Skip to content

@tabula-css/core

Tabula의 코드형 계약(contract-as-code) 계층: 다른 모든 Tabula 패키지가 합의하는 고정 테이블, 순수 함수, 오류 코드, JSON 스키마. 런타임 의존성 없음.

설치

대부분의 프로젝트는 @tabula-css/core를 직접 설치하지 않습니다 — 이는 @tabula-css/tokens, @tabula-css/registry, @tabula-css/merge, @tabula-css/preset의 전이 의존성(transitive dependency)이며, 이들 모두 여기서 불변식(invariant)을 가져옵니다. 나머지 파이프라인을 끌어들이지 않고 진단 카탈로그, 고정 테이블, JSON 스키마만 필요한 커스텀 도구를 작성하는 경우에만 직접 설치하십시오.

bash
npm install @tabula-css/core

개요

@tabula-css/core는 프로파일의 어휘와 그 진단이 정의되는 단 하나의 장소이며, 이 덕분에 CLI, 레지스트리 생성기, 린터, MCP 서버가 서로 어긋나지 않습니다. I/O도 Tailwind 의존성도 없습니다: 이 패키지가 내보내는 모든 것은 고정 데이터 테이블(정규 CSS 슬롯, 네임스페이스 → 유틸리티 패밀리 매핑, 변형 테이블, 금지 목록), 순수 함수(rank(), checkLaminarity(), computeSpecificity()), JSON 스키마(tabula.config.json, 토큰 파일, registry.json, manifest.json용), 또는 안정된 TAB-Exxx/TAB-Wxxx 오류 카탈로그 중 하나입니다. 하위의 모든 것 — @tabula-css/tokens의 검증기, @tabula-css/registry의 생성기, @tabula-css/merge의 런타임 — 은 이 테이블들을 다시 유도하는 대신 그대로 읽습니다.

내보내기

진단

시스템 안의 모든 TAB-Exxx/TAB-Wxxx 코드가 끌어오는 안정된 진단 카탈로그입니다 — 코드가 실제 맥락에서 쓰이는 예시는 핵심 개념 § 레지스트리는 근거 있는 사실이다시작하기를 참고하십시오.

ts
export type Severity = 'error' | 'warning';

export interface Diagnostic {
  readonly code: string;
  readonly severity: Severity;
  readonly message: string;
  readonly subject?: string;
  readonly hint?: string;
}

export type ErrorCode = keyof typeof ERROR_CATALOG; // e.g. 'TAB-E109' | 'TAB-E300' | …
export const ERROR_CATALOG: Readonly<Record<ErrorCode, { severity: Severity; summary: string; teach: string }>>;
export const ERROR_CODES: readonly ErrorCode[];

export function formatMessage(
  template: string,
  params?: Readonly<Record<string, string | number>>,
): string;

export function makeDiagnostic(
  code: ErrorCode,
  params?: Readonly<Record<string, string | number>>,
  opts?: { readonly subject?: string; readonly hint?: string },
): Diagnostic;

ERROR_CATALOG는 모든 코드를 그 심각도(severity), {name} 템플릿이 적용된 summary, 그리고 (tabula explain <code>가 출력하는) 한 줄짜리 teach 문자열에 매핑합니다. makeDiagnostic()은 시스템의 모든 패키지가 Diagnostic을 만들 때 사용하는 단일 생성자입니다: 코드의 템플릿을 조회하고, formatMessage()를 통해 params를 채운 뒤, 선택적인 subject(진단이 다루는 토큰 경로 또는 클래스 이름)와 hint(실행 가능한 다음 단계 하나)를 붙입니다.

ts
import { makeDiagnostic } from '@tabula-css/core';

makeDiagnostic('TAB-E109', { path: 'color.surface' });
// → { code: 'TAB-E109', severity: 'error',
//     message: "Token 'color.surface' requires a $description ≥ 20 chars, not byte-equal to its value.", … }

이 카탈로그는 구조적인 토큰 파일 오류(TAB-E1xx), 값 의미론(TAB-E15xE16x), 변형 폐쇄성(TAB-E170E172 설정, TAB-E230 스캔), 빌드 불변식(TAB-E21x), CSS 거버넌스(TAB-E22x), eject 전제 조건(TAB-E240/TAB-W402), 병합 런타임(TAB-E3xx), 생성된 아티팩트의 무결성(TAB-E601), CLI 사용(TAB-E9xx)에 걸쳐 있습니다 — 특히 E22x 계열은 CSS 거버넌스를 참고하십시오.

고정 테이블

@tabula-css/core는 프로파일의 불변식이 대조되는 모든 테이블의 정본(canonical copy)을 고정(freeze)합니다. 주제별로 묶으면 다음과 같습니다.

내보내기타입목적
CANONICAL_SLOT_PROPERTIESreadonly string[]정규 롱핸드(longhand) CSS 속성의 순서 목록; 슬롯의 id는 그 인덱스입니다.
CANONICAL_SLOTSReadonly<Record<string, string>>slotId → property, registry.jsonslots 맵과 일치합니다.
SLOT_ALIASESReadonly<Record<string, string>>블록-논리(block-logical) → 물리-블록(physical-block) 정규화(padding-block-start → padding-top).
PHYSICAL_INLINE_TWINSReadonly<Record<string, string>>논리-인라인 속성 → (등록되지 않은) 그 물리-인라인 짝, "둘 다는 안 됨" 단위 테스트용.
slotIdOf(property)(string) => SlotId | undefined정규 속성에 대한 슬롯 id, 없으면 undefined.
SHORTHAND_EXPANSIONSReadonly<Record<string, readonly string[]>>CSS 숏핸드(shorthand) → 롱핸드-리프(leaf) 전개(padding → 네 방향), 한 단계만.
INHERITED_PROPERTIES{ tier1, tier2 }2단계 상속 속성 테이블: Tier 1(폐쇄성 요구 — type-*/ink-*만) 대 Tier 2(주변적, 유계).
INHERITABLE_PROPERTIESreadonly string[]Tier 1 ∪ Tier 2, 안정된 순서로 — base 레벨의 주변 기준선(ambient baseline)이 :root에서 한 번 설정해야 하는 정확한 집합.
AMBIENT_BASELINE_DEFAULTSReadonly<Record<string, string>>모든 Tier-2 속성에 대한 고정된 리터럴 :root 기본값.
TYPE_COMPOSITE_FIELDS8개 문자열 튜플type 합성 값의 필드 이름들(fontFamily, fontSize 등).
TYPE_FIELD_TO_PROPERTYReadonly<Record<string, string>>type 필드를 그것이 기록하는 CSS 속성에 매핑합니다.
inheritanceTier(property)(string) => 0 | 1 | 2속성의 상속 계층, 상속하지 않으면 0.
NAMESPACE_FAMILY_TABLEReadonly<Record<string, NamespaceEntry>>네임스페이스 → 그것이 합성하는 유틸리티 패밀리, 네임스페이스(color, spacing, size, radius 등)로 키가 지정됩니다.
ALL_FAMILIESreadonly FamilyDef[]familyIndex 순서로, 모든 네임스페이스에 걸친 모든 패밀리.
NAMESPACESreadonly string[]합법적인 네임스페이스 이름의 집합.
isKnownNamespace(ns)(string) => boolean네임스페이스 이름이 합법적인지 여부.
familyInLevel(family, level) / familiesForLevel(entry, level)profileLevel(basestrict)로 패밀리/네임스페이스의 항목을 필터링합니다.
familyBreadth(family)(FamilyDef) => number비합성 슬롯 개수 + 기록된 커스텀 속성 개수 — rank()의 주요 키.
STATIC_UTILITIESReadonly<Record<string, StaticUtility>>프로파일이 허용하는 값 없는 유틸리티(flex, sr-only, cursor-pointer 등), 클래스 이름으로 키가 지정됩니다.
STATIC_UTILITY_NAMESreadonly string[]모든 정적 유틸리티의 클래스 이름.
staticUtilityNamesForLevel(level)(ProfileLevel) => readonly string[]특정 프로파일 레벨 아래 등록된 정적 유틸리티 이름.
VARIANT_TABLEReadonly<Record<string, VariantDef>>이름 있는 모든 변형(hover, md, group-hover/* 등)과 그 선택자/조건, 순위 대역(rank band).
CONDITION_RANK_SCALEnumber (1_000_000)조건이 외부 대역을 형성하도록 합산된 조건 순위에 곱해지는 승수.
BANLISTreadonly BanPattern[]레지스트리와 무관한 금지 하한선(space-*, divide-*, *:, in-*, rtl:/ltr: 등).
matchBan(token)(string) => string | undefined클래스 토큰을 금지 하한선에 대조하고, 위반된 금지 id를 반환합니다.
betterTailwindcssBanlist()() => { restrict: … }eslint-plugin-better-tailwindcssno-restricted-classes 옵션에 맞게 정형화된 금지 하한선.
QUARANTINE_ATTRIBUTE, QUARANTINE_KIND, QUARANTINE_FENCE_CLASS, QUARANTINE_SAFE_FAMILIES, QUARANTINE_SELECTOR, QUARANTINE_CSSstrings / readonly string[]프로즈 격리(prose-quarantine) 경계 마커, 펜스 클래스, 안전한 유틸리티 패밀리, 생성된 제외 CSS — 핵심 개념을 참고하십시오.
isQuarantineSafe(className)(string) => boolean격리 경계 요소에서 클래스가 합법적인지 여부.

순수 함수

ts
export function expandShorthand(property: string): readonly string[];
export function canonicalizeProperty(property: string): string;
export function isComposedValue(value: string): boolean;

export interface ClassMeta {
  readonly breadth: number;
  readonly familyIndex: number;
  readonly valueIndex: number;
}
export function rank(meta: ClassMeta): number; // throws RankError out of range
export class RankError extends Error {}
export const MAX_BREADTH: number; // 32
export const VALUE_SPAN: number; // 100_000
export const FAMILY_SPAN: number; // 10_000

export interface SlotBearing {
  readonly class: string;
  readonly slots: Iterable<number>;
  readonly atomic?: boolean;
}
export interface LaminarityViolation {
  readonly a: string;
  readonly b: string;
  readonly shared: readonly number[];
  readonly onlyA: readonly number[];
  readonly onlyB: readonly number[];
}
export function checkLaminarity(classes: readonly SlotBearing[]): LaminarityViolation[];

export type Specificity = readonly [number, number, number];
export function computeSpecificity(selector: string): Specificity;
export function compareSpecificity(a: Specificity, b: Specificity): number;
export function formatSpecificity(s: Specificity): string; // "(0,1,0)"
export function hasPseudoElement(selector: string): boolean;

rank()는 클래스의 (breadth, familyIndex, valueIndex) 트리플을 어휘 전체를 완전히 정렬하는 단일 정수로 축약합니다(Draft A §5.2: lex(−breadth, familyIndex, valueIndex)) — 핵심 개념 § 병합: 캐스케이드 시뮬레이션이 아닌 전순서를 참고하십시오. 어느 성분이든 지원 범위를 벗어나면 RankError를 던지는데, 조용한 오버플로가 순서를 망가뜨릴 것이기 때문입니다.

ts
import { rank } from '@tabula-css/core';

rank({ breadth: 4, familyIndex: 1, valueIndex: 0 }); // a p-* class: writes 4 slots

checkLaminarity()는 불변식 I2(Draft A §5.3)입니다: 조건을 공유하는 클래스들의 슬롯 집합은 서로 내포되거나(nest) 서로소(disjoint)여야 하며, 부분적으로 겹쳐서는 안 됩니다. 위반하는 모든 쌍을 반환하며(비어 있으면 라미나(laminar) 조건 충족), 원자적 리셋 유틸리티(sr-only)는 예외로 건너뜁니다.

computeSpecificity()는 런타임 의존성 없이 CSS Selectors Level 4의 명시도(specificity)를 구현하며, :where()(항상 (0,0,0)), :is()/:not()/:has()(가장 명시도가 높은 인자의 명시도), 의사 요소(pseudo-element)를 이해합니다. 이는 불변식 I4를 뒷받침합니다 — 모든 유틸리티 규칙은 (0,1,0)(의사 요소의 경우 (0,1,1))으로 정규화되어야 합니다.

설정 스키마와 타입

tabula.config.json 스키마와 그에 대응하는 TypeScript 타입입니다 — 시작하기 § 3. 축을 선언하기를 참고하십시오.

ts
export type ProfileLevel = 'base' | 'strict';
export const PROFILE_LEVELS: readonly ProfileLevel[];
export const DEFAULT_PROFILE_LEVEL: ProfileLevel; // 'base'

export interface AxisConfig {
  readonly values: readonly string[];
  readonly default: string;
  readonly attribute?: string;
  readonly media?: Readonly<Record<string, string>>;
}
export interface TabulaConfig {
  readonly profileId: string;
  readonly profileLevel?: ProfileLevel;
  readonly axes: Readonly<Record<string, AxisConfig>>;
  readonly baseline?: BaselineConfig;
  readonly groups?: readonly string[];
  readonly variantChainMaxLength?: number;
  readonly dynamicProperties?: Readonly<Record<string, DynamicPropertyConfig>>;
  readonly foreignClasses?: readonly string[];
  readonly textLeafComponents?: readonly string[];
  readonly gamut?: 'srgb' | 'p3' | 'rec2020';
  readonly budgets?: BudgetsConfig;
  readonly scan?: ScanConfig;
  readonly variants?: VariantsConfig; // declared variant products (contract J22)
}

export const configSchema: JsonSchemaObject; // JSON Schema (2020-12) for tabula.config.json

variants 섹션은 어떤 변형 체인이 CSS를 내는지 선언합니다 — v0.2에서 나온 폐쇄성 수정입니다:

ts
export type VariantPreset = 'interaction' | 'all-len1' | 'none';
export const VARIANT_PRESETS: readonly VariantPreset[];

export interface VariantsConfig {
  /** Seeds the product map before `products` are merged over it. Absent ⇒ `interaction`. */
  readonly preset?: VariantPreset;
  /** Canonical chain prefix → the families it may prefix (`"*"` = every non-atomic family). */
  readonly products?: Readonly<Record<string, '*' | readonly string[]>>;
  /** Hard cap on materialized chain candidates. Absent ⇒ DEFAULT_MAX_CHAIN_CANDIDATES. */
  readonly maxChainCandidates?: number;
}

선언된 변형 프로덕트는 등록된 집합(기본 어휘 ∪ 프로덕트)을 넓혀서, 방출되는 스타일시트가 여전히 프로파일의 순수 함수로 남는 채로 변형이 접두된 클래스가 CSS를 내게 합니다 — 핵심 개념 § 변형을 참고하십시오. 구조적 형태는 configSchema가 검사합니다; 값-의미론 게이트(체인 문법, 패밀리 이름, 미디어→브레이크포인트 요구 사항 TAB-E170, 잘못된 프로덕트 검사 TAB-E171, 그리고 maxChainCandidates 예산 TAB-E172)는 @tabula-css/tokensvalidateConfig에 있습니다.

DynamicPropertyConfig.syntax는 결코 리터럴 '*'가 될 수 없습니다 — 보편적인 @property 구문을 가진 --d-* 동적 커스텀 속성(dyn()을 통해 기록됨)은 시스템 어디에서도 아무것도 검증하지 못하게 되므로, 이 스키마와 @tabula-css/tokensvalidateConfig 모두 이를 거부합니다(TAB-E127).

스키마와 함께 내보내지는 그 밖의 기본값과 상한: DEFAULT_VARIANT_CHAIN_MAX_LENGTH(2, 이미터가 실제로 만들어내는 길이에 맞추어 v0.2에서 3으로부터 낮아짐), DEFAULT_VARIANT_PRESET('interaction'), DEFAULT_MAX_CHAIN_CANDIDATES(20,000 — variants.maxChainCandidates 예산), DEFAULT_GAMUT('srgb'), DEFAULT_MAX_ESCAPES(25), DEFAULT_MAX_SUPPRESSIONS(0), DEFAULT_SCAN_SOURCES/DEFAULT_SCAN_IGNORE(tabula scan의 글롭 기본값), MAX_AXIS_CROSS_PRODUCT(16).

토큰, 레지스트리, 매니페스트 스키마

ts
export const TOKEN_TYPES: readonly string[]; // 'color' | 'dimension' | 'number' | … | 'type' | 'shadow'
export const tokensSchema: JsonSchemaObject; // JSON Schema for a flat-DTCG token file
export interface Token {
  readonly $type: string;
  readonly $value: TokenValue;
  readonly $description: string;
  readonly $deprecated?: Deprecation;
  readonly $extensions?: TokenExtensions;
}
export type TokensFile = Readonly<Record<string, TokenNamespace>>;
export function isLiteralEscape(meta: ExceptionMeta): boolean;

export const registrySchema: JsonSchemaObject; // JSON Schema for registry.json (schema version 3)
export interface RegistryFile { /* registrySchemaVersion (3), classes, variants, exceptions, variantProducts, chainCount, chainExceptions, … */ }
export interface RegistryClass { /* family, slots, rank, declarations, … */ }

export const manifestSchema: JsonSchemaObject; // JSON Schema for manifest.json
export const MANIFEST_FORMAT_VERSION: number; // 1
export interface ManifestFile { /* formatVersion, sourceHash, inputsHash, artifacts, … */ }

tokensSchema는 토큰 파일 계약의 구조적인 부분(깊이-2 중첩, 닫힌 $type 열거형, 필수 $description, 케밥 표기 토큰 이름)을 다룹니다. JSON 스키마가 표현할 수 없는 값 의미론(축의 완전성, 대비, 차원 도메인)은 @tabula-css/tokens의 커스텀 검사 단계입니다. registrySchemamanifestSchema@tabula-css/registry의 리더가 registry.jsonmanifest.json의 내용을 신뢰하기 전에 검증하는 데 사용됩니다. 레지스트리 스키마는 버전 3입니다(v0.2): 선언된-변형-프로덕트 필드인 variantProducts(체인 접두사 → 정렬된 패밀리 목록)와 chainCount, 그리고 선택적인 chainExceptions(정확한 단일 클래스 체인 허가)를 추가합니다. 더 이전 스키마 버전으로 작성된 레지스트리는 리더에 의해 TAB-E302로 거부됩니다.

모든 JSON 스키마는 core가 함께 내보내는 최소한의 JsonSchema/JsonSchemaObject 형태로 타입이 지정됩니다(이 네 스키마를 표현하기에 충분한 JSON Schema draft 2020-12의 부분집합이며, any 대신 unknown 타입의 인덱스 시그니처를 사용합니다).

함께 보기

  • @tabula-css/tokens — core의 테이블과 스키마를 사용하는 검증기와 리졸버.
  • @tabula-css/registry — core의 스키마에 대해 registry.json/manifest.json을 검증하는 리더.
  • @tabula-css/merge — core의 TAB-E3xx 진단을 던지는 런타임.
  • 핵심 개념 — 이 테이블들이 부호화하는 지역성, 레지스트리, 병합 알고리즘, 금지된 메커니즘 카탈로그.

Released under the MIT License.