@mildastudio/milda 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -3044,6 +3044,78 @@ const preludeV0 = {
3044
3044
  const atomsByName = Object.fromEntries(atoms.map((a) => [a.name, a]));
3045
3045
  const compositesByName = Object.fromEntries(composites.map((c) => [c.name, c]));
3046
3046
  const archetypesByName = Object.fromEntries(archetypes.map((a) => [a.name, a]));
3047
+ // prelude/required.ts
3048
+ function archetypeDef(archetype) {
3049
+ return typeof archetype === "string" ? archetypesByName[archetype] : archetype ?? void 0;
3050
+ }
3051
+ function anatomyIndex(archetype) {
3052
+ const out = /* @__PURE__ */ new Map();
3053
+ const parts = archetypeDef(archetype)?.anatomy;
3054
+ if (!parts) return out;
3055
+ const walk = (part, parentName) => {
3056
+ const seen = out.get(part.name);
3057
+ if (seen) seen.repeated = true;
3058
+ else out.set(part.name, {
3059
+ name: part.name,
3060
+ parentName,
3061
+ role: part.role,
3062
+ optional: part.optional === true,
3063
+ repeated: false
3064
+ });
3065
+ for (const child of part.children ?? []) walk(child, part.name);
3066
+ };
3067
+ for (const part of parts) walk(part, null);
3068
+ return out;
3069
+ }
3070
+ const LOWERED_ANATOMY = { BooleanInput: ["control", "indicator"] };
3071
+ function loweredAnatomy(archetype) {
3072
+ const name = typeof archetype === "string" ? archetype : archetype?.name;
3073
+ return name && LOWERED_ANATOMY[name] || [];
3074
+ }
3075
+ function findDeclaredPart(name, parentPath, rootPath, paths, repeated) {
3076
+ let best;
3077
+ for (const path of paths) {
3078
+ if ((path.split(".").pop() || path) !== name) continue;
3079
+ const under = parentPath === rootPath || path.startsWith(`${parentPath}.`);
3080
+ if (repeated && !under) continue;
3081
+ if (!best || path.split(".").length < best.split(".").length) best = path;
3082
+ }
3083
+ return best;
3084
+ }
3085
+ function missingRequiredParts(archetype, anatomy) {
3086
+ const parts = archetypeDef(archetype)?.anatomy;
3087
+ const paths = Object.keys(anatomy);
3088
+ const rootPath = paths[0];
3089
+ if (!parts || rootPath === void 0) return [];
3090
+ const known = anatomyIndex(archetype);
3091
+ const lowered = new Set(loweredAnatomy(archetype));
3092
+ const parentOf = (path) => path.includes(".") ? path.slice(0, path.lastIndexOf(".")) : rootPath;
3093
+ const standIns = /* @__PURE__ */ new Set();
3094
+ for (const path of paths.slice(1)) {
3095
+ const leaf = path.split(".").pop() || path;
3096
+ if (anatomy[path]?.kind === "input" && !known.has(leaf)) standIns.add(parentOf(path));
3097
+ }
3098
+ const out = [];
3099
+ const walk = (part, parentPath, parentMissing) => {
3100
+ const repeated = known.get(part.name)?.repeated ?? false;
3101
+ const declared = findDeclaredPart(part.name, parentPath, rootPath, paths, repeated);
3102
+ if (declared) {
3103
+ for (const child of part.children ?? []) walk(child, declared, false);
3104
+ return;
3105
+ }
3106
+ if (part.optional) return;
3107
+ if (!parentMissing && part.role === "input" && standIns.has(parentPath)) return;
3108
+ const path = parentPath === rootPath ? part.name : `${parentPath}.${part.name}`;
3109
+ out.push({
3110
+ path,
3111
+ kind: part.role,
3112
+ implied: parentMissing
3113
+ });
3114
+ for (const child of part.children ?? []) walk(child, path, true);
3115
+ };
3116
+ for (const part of parts) if (!lowered.has(part.name)) walk(part, rootPath, false);
3117
+ return out;
3118
+ }
3047
3119
  // engine/resolveToken.ts
3048
3120
  function resolveToken(tokenId, contextIds, layers, _depth = 0) {
3049
3121
  if (_depth > 20) return null;
@@ -3641,6 +3713,17 @@ const LOGICAL_EDGES = [
3641
3713
  "inline",
3642
3714
  "all"
3643
3715
  ];
3716
+ /** The edges an inset can be stated on, besides all four at once (proposal 0057). A dotted facet
3717
+ * name each - `inset.inline`, `inset.block-start` - the way `border` takes `.<edge>`. The bare
3718
+ * `inset` already means all four, so `all` is not one of them. */
3719
+ const INSET_EDGES = [
3720
+ "block",
3721
+ "inline",
3722
+ "block-start",
3723
+ "block-end",
3724
+ "inline-start",
3725
+ "inline-end"
3726
+ ];
3644
3727
  /** The physical edge words the parser used to take, read as the logical edge each names in a
3645
3728
  * horizontal left-to-right system. Read, never offered, never written - the `rgba` treatment. */
3646
3729
  const PHYSICAL_EDGE_ALIASES = {
@@ -3675,7 +3758,7 @@ function kebab(s) {
3675
3758
  function camelField(s) {
3676
3759
  return s.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
3677
3760
  }
3678
- const MILDA_SURFACE_VERSION = "0.8";
3761
+ const MILDA_SURFACE_VERSION = "0.10";
3679
3762
  const PRELUDE_VERSION = "0.0.2";
3680
3763
  // dsl/literal.ts
3681
3764
  const NUMBER_RE = /^-?\d+(\.\d+)?$/;
@@ -3792,6 +3875,17 @@ function validate(doc, prelude) {
3792
3875
  where,
3793
3876
  id: comp.id
3794
3877
  });
3878
+ const archetype = prelude.archetypes.find((a) => a.name === comp.archetype);
3879
+ for (const gap of missingRequiredParts(archetype, comp.anatomy)) {
3880
+ if (gap.implied) continue;
3881
+ issues.push({
3882
+ severity: "error",
3883
+ code: "part.required",
3884
+ message: `a ${comp.archetype} requires the part "${gap.path}" (${gap.kind})`,
3885
+ where,
3886
+ id: comp.id
3887
+ });
3888
+ }
3795
3889
  const propIds = new Set(comp.contract.props.map((p) => p.id));
3796
3890
  for (const [param, binding] of Object.entries(comp.contract.params)) if ("prop" in binding && !propIds.has(binding.prop)) issues.push({
3797
3891
  severity: "error",
@@ -4074,6 +4168,7 @@ const FACET_MAP = {
4074
4168
  "border.block-end": "border.block-end",
4075
4169
  corner: "corner",
4076
4170
  inset: "inset",
4171
+ ...Object.fromEntries(INSET_EDGES.map((e) => [`inset.${e}`, `inset.${e}`])),
4077
4172
  gap: "gap",
4078
4173
  text: "text",
4079
4174
  "text.clamp": "textClamp",
@@ -4210,7 +4305,6 @@ const SLOT_ARITIES = [
4210
4305
  const PART_KEYWORDS = [
4211
4306
  "kind",
4212
4307
  "origin",
4213
- "locked",
4214
4308
  "present",
4215
4309
  "slot",
4216
4310
  "content",
@@ -5970,7 +6064,13 @@ var Parser = class Parser {
5970
6064
  return spec;
5971
6065
  }
5972
6066
  parseFacetStmt() {
5973
- const raw = this.expectWord("facet-name");
6067
+ let raw = this.expectWord("facet-name");
6068
+ const physical = /^inset\.(top|right|bottom|left)$/.exec(raw);
6069
+ if (physical) {
6070
+ const logical = `inset.${PHYSICAL_EDGE_ALIASES[physical[1]]}`;
6071
+ this.issue("warning", "inset-physical", `'${raw}' is read as '${logical}' - write the logical edge`);
6072
+ raw = logical;
6073
+ }
5974
6074
  const mapped = FACET_MAP[raw];
5975
6075
  if (mapped === void 0) {
5976
6076
  this.issue("warning", "facet-unknown", `unknown facet "${raw}" skipped`);
@@ -5986,6 +6086,19 @@ var Parser = class Parser {
5986
6086
  name: "inset",
5987
6087
  value: { inset: this.parseInsetArgs() }
5988
6088
  };
6089
+ if (mapped.startsWith("inset.")) {
6090
+ const w = this.at("word") ? this.next().value : void 0;
6091
+ if (w === void 0) {
6092
+ this.issue("error", "facet-value", `"${raw}" needs a value`);
6093
+ this.skipToTerminator();
6094
+ return null;
6095
+ }
6096
+ if (!this.at("semi") && !this.at("newline") && !this.at("rbrace")) this.skipToTerminator();
6097
+ return {
6098
+ name: mapped,
6099
+ value: { token: tokId(w) }
6100
+ };
6101
+ }
5989
6102
  if (mapped === "border" || mapped.startsWith("border.")) {
5990
6103
  const border = {};
5991
6104
  while (this.at("word")) {
@@ -6466,13 +6579,30 @@ var Parser = class Parser {
6466
6579
  }
6467
6580
  return out;
6468
6581
  }
6582
+ parsePartHeader(part) {
6583
+ const said = {};
6584
+ if (this.at("colon")) {
6585
+ this.next();
6586
+ if (!this.at("word")) this.issue("error", "part-header-kind", "expected the part's kind after ':'");
6587
+ else {
6588
+ said.kind = this.next().value;
6589
+ part.kind = said.kind;
6590
+ }
6591
+ }
6592
+ while (!this.at("lbrace") && !this.atValueEnd()) {
6593
+ const tok = this.next();
6594
+ this.issue("error", "part-header-word", `unexpected ${JSON.stringify(tok.value)} in a part header - expected '{'`, tok);
6595
+ }
6596
+ return said;
6597
+ }
6469
6598
  parsePart() {
6470
6599
  const kw = this.next();
6471
6600
  const nameTok = this.peek();
6472
6601
  const name = this.expectWord("part-name");
6473
6602
  if (!name) return null;
6474
- this.expect("lbrace", "part-lbrace");
6475
6603
  const part = {};
6604
+ const header = this.parsePartHeader(part);
6605
+ this.expect("lbrace", "part-lbrace");
6476
6606
  const facets = {};
6477
6607
  const variants = [];
6478
6608
  while (!this.at("rbrace") && !this.at("eof")) {
@@ -6502,16 +6632,17 @@ var Parser = class Parser {
6502
6632
  this.next();
6503
6633
  part.slot = this.parseSlot();
6504
6634
  } else if (this.atWord("kind")) {
6505
- this.next();
6506
- part.kind = this.expectWord("part-kind");
6635
+ const tok = this.next();
6636
+ const stated = this.expectWord("part-kind");
6637
+ if (header.kind === void 0) part.kind = stated;
6638
+ else if (stated === header.kind) this.issue("warning", "part-kind-twice", `kind '${stated}' is stated twice`, tok);
6639
+ else if (stated) this.issue("error", "part-kind-conflict", `kind '${stated}' contradicts the header's '${header.kind}' - the header wins`, tok);
6507
6640
  } else if (this.atWord("origin")) {
6508
6641
  this.next();
6509
6642
  const o = this.expectWord("part-origin");
6510
6643
  if (o === "root" || o === "archetype" || o === "author") part.origin = o;
6511
- } else if (this.atWord("locked")) {
6512
- this.next();
6513
- part.locked = true;
6514
- } else if (this.atWord("content")) {
6644
+ } else if (this.atWord("locked")) this.next();
6645
+ else if (this.atWord("content")) {
6515
6646
  this.next();
6516
6647
  part.content = this.parsePartContent();
6517
6648
  } else if (this.atWord("a11y")) {
@@ -7630,7 +7761,7 @@ var Parser = class Parser {
7630
7761
  let docs;
7631
7762
  let assets;
7632
7763
  let icons;
7633
- let mildaVer = opts.milda ?? "0.8";
7764
+ let mildaVer = opts.milda ?? "0.10";
7634
7765
  let preludeVer = opts.prelude ?? "0.0.2";
7635
7766
  let docName = opts.name ?? "Design system";
7636
7767
  let docVersion = "0.0.0";
@@ -7759,7 +7890,7 @@ function parseMildaDocument(src, opts = {}) {
7759
7890
  }
7760
7891
  function emptyDocument(opts) {
7761
7892
  return {
7762
- milda: opts.milda ?? "0.8",
7893
+ milda: opts.milda ?? "0.10",
7763
7894
  kind: "design-system",
7764
7895
  prelude: opts.prelude ?? "0.0.2",
7765
7896
  meta: {
@@ -7801,6 +7932,7 @@ exports.DOC_TRANSCLUSIONS = DOC_TRANSCLUSIONS;
7801
7932
  exports.EXAMPLE_KEYWORDS = EXAMPLE_KEYWORDS;
7802
7933
  exports.FACET_NAMES = FACET_NAMES;
7803
7934
  exports.GROUP_REALIZATIONS = GROUP_REALIZATIONS;
7935
+ exports.INSET_EDGES = INSET_EDGES;
7804
7936
  exports.INTERACTION_KINDS = INTERACTION_KINDS;
7805
7937
  exports.LAYOUT_ALIGNS = LAYOUT_ALIGNS;
7806
7938
  exports.LAYOUT_DIRECTIONS = LAYOUT_DIRECTIONS;
@@ -7834,14 +7966,18 @@ exports.TOKEN_VALUE_KIND = TOKEN_VALUE_KIND;
7834
7966
  exports.TOKEN_VALUE_KINDS = TOKEN_VALUE_KINDS;
7835
7967
  exports.VALUE_LITERAL_FNS = VALUE_LITERAL_FNS;
7836
7968
  exports.allTokensOfType = allTokensOfType;
7969
+ exports.anatomyIndex = anatomyIndex;
7837
7970
  exports.archetypesByName = archetypesByName;
7838
7971
  exports.atomsByName = atomsByName;
7839
7972
  exports.camelField = camelField;
7840
7973
  exports.compositesByName = compositesByName;
7841
7974
  exports.conformance = conformance;
7975
+ exports.findDeclaredPart = findDeclaredPart;
7842
7976
  exports.findToken = findToken;
7843
7977
  exports.kebabField = kebab;
7844
7978
  exports.lex = lex;
7979
+ exports.loweredAnatomy = loweredAnatomy;
7980
+ exports.missingRequiredParts = missingRequiredParts;
7845
7981
  exports.parseMildaDocument = parseMildaDocument;
7846
7982
  exports.preludeV0 = preludeV0;
7847
7983
  exports.resolveToken = resolveToken;
package/dist/index.d.cts CHANGED
@@ -427,6 +427,11 @@ type PositionKind = (typeof POSITION_KINDS)[number];
427
427
  /** Logical edges, so a design system reads the same in a right-to-left locale. */
428
428
  declare const LOGICAL_EDGES: readonly ['block-start', 'block-end', 'inline-start', 'inline-end', 'block', 'inline', 'all'];
429
429
  type LogicalEdge = (typeof LOGICAL_EDGES)[number];
430
+ /** The edges an inset can be stated on, besides all four at once (proposal 0057). A dotted facet
431
+ * name each - `inset.inline`, `inset.block-start` - the way `border` takes `.<edge>`. The bare
432
+ * `inset` already means all four, so `all` is not one of them. */
433
+ declare const INSET_EDGES: readonly ["block", "inline", "block-start", "block-end", "inline-start", "inline-end"];
434
+ type InsetEdge = (typeof INSET_EDGES)[number];
430
435
  /** The physical edge words the parser used to take, read as the logical edge each names in a
431
436
  * horizontal left-to-right system. Read, never offered, never written - the `rgba` treatment. */
432
437
  declare const PHYSICAL_EDGE_ALIASES: Readonly<Record<string, LogicalEdge>>;
@@ -441,17 +446,12 @@ declare const DEMO_ACTION_OPS: readonly string[];
441
446
  declare function kebab(s: string): string;
442
447
  /** A surface kebab key → the IR's camelCase field (`week-starts-on` → `weekStartsOn`). */
443
448
  declare function camelField(s: string): string;
444
- declare const MILDA_SURFACE_VERSION = "0.8";
449
+ declare const MILDA_SURFACE_VERSION = "0.10";
445
450
  declare const PRELUDE_VERSION = "0.0.2";
446
- type FacetName = 'fill' | 'ink' | 'border' | 'border.top' | 'border.right' | 'border.bottom' | 'border.left' | 'border.inline-start' | 'border.inline-end' | 'border.block-start' | 'border.block-end' | 'corner' | 'inset' | 'gap' | 'text' | 'textClamp' | 'textWrap' | 'weight' | 'font' | 'slant' | 'elevation' | 'overlay' | 'opacity' | 'ring' | 'backdrop';
451
+ type FacetName = 'fill' | 'ink' | 'border' | 'border.top' | 'border.right' | 'border.bottom' | 'border.left' | 'border.inline-start' | 'border.inline-end' | 'border.block-start' | 'border.block-end' | 'corner' | 'inset' | `inset.${InsetEdge}` | 'gap' | 'text' | 'textClamp' | 'textWrap' | 'weight' | 'font' | 'slant' | 'elevation' | 'overlay' | 'opacity' | 'ring' | 'backdrop';
447
452
  type InsetValue = {
448
453
  block?: Id;
449
454
  inline?: Id;
450
- } | {
451
- top?: Id;
452
- right?: Id;
453
- bottom?: Id;
454
- left?: Id;
455
455
  } | {
456
456
  all: Id;
457
457
  };
@@ -923,7 +923,6 @@ interface Part {
923
923
  facets?: FacetMap;
924
924
  kind?: string;
925
925
  origin?: 'root' | 'archetype' | 'author';
926
- locked?: boolean;
927
926
  content?: PartContent;
928
927
  a11y?: PartA11y;
929
928
  emits?: PartEmit[];
@@ -1302,6 +1301,23 @@ declare const preludeV0: PreludeDocument;
1302
1301
  declare const atomsByName: Record<string, Atom>;
1303
1302
  declare const compositesByName: Record<string, CompositeBehavior>;
1304
1303
  declare const archetypesByName: Record<string, ArchetypeDef>;
1304
+ type ArchetypeRef = ArchetypeDef | string | null | undefined;
1305
+ interface AnatomyEntry {
1306
+ name: string;
1307
+ parentName: string | null;
1308
+ role: PartRole;
1309
+ optional: boolean;
1310
+ repeated: boolean;
1311
+ }
1312
+ declare function anatomyIndex(archetype: ArchetypeRef): Map<string, AnatomyEntry>;
1313
+ declare function loweredAnatomy(archetype: ArchetypeRef): readonly string[];
1314
+ declare function findDeclaredPart(name: string, parentPath: string, rootPath: string, paths: Iterable<string>, repeated: boolean): string | undefined;
1315
+ interface MissingPart {
1316
+ path: string;
1317
+ kind: PartRole;
1318
+ implied: boolean;
1319
+ }
1320
+ declare function missingRequiredParts(archetype: ArchetypeRef, anatomy: Anatomy): MissingPart[];
1305
1321
  type ResolvedToken = {
1306
1322
  kind: 'value';
1307
1323
  type: TokenType;
@@ -1482,4 +1498,4 @@ interface SkippedChar {
1482
1498
  col: number;
1483
1499
  }
1484
1500
  declare function lex(src: string, skipped?: SkippedChar[]): Token[];
1485
- export { ASSET_BASE_KEYS, ASSET_FIELDS, ASSET_FIELD_KEYS, ASSET_KINDS, AXIS_CLAMPS, AXIS_INTENTS, type AliasTokenValue, type Align, type Anatomy, type AnatomyPart, type AnimationAsset, type AnimationFormat, type AnyTokenValue, type ArchetypeDef, type ArchetypeGroup, type ArchetypeRealize, type Asset, type AssetByKind, type AssetDecl, type AssetFolder, type AssetFolderDecl, type AssetKind, type AssetRegistry, type AssetsDecl, type Assignment, type Atom, type AtomContextVar, type AtomEvent, type AtomParam, type AtomStateNode, type AxisIntent, type AxisIntentKind, type AxisSize, type AxisSizeValue, BEHAVIOR_FIELDS, BEHAVIOR_KINDS, type BlurValue, type BorderFacetStyle, type BorderFacetValue, type BorderStyle, type BorderValue, type BorderWidth, type BrowseRealize, CELL_MODIFIERS, COLOR_KEYWORDS, COLOR_LITERAL_ALIASES, COLOR_LITERAL_FNS, COLOR_LITERAL_SPELLINGS, COLOR_TOKEN_TYPE_NAMES, CONTROL_REALIZATIONS, type Capability, type CapabilityDef, type ColorOrRef, type ColorSpace, type ColorValue, type CommitRealize, type CompareOp, type Component, type ComponentGroupDecl, type CompositeBehavior, type Composition, type ComputeOp, type ComputeSpace, type ComputeTokenValue, type ConfigFieldSpec, type ConfigSurface, type ConformanceOptions, type ConformanceReport, type ContentCategory, type Context, type ContextGroup, type Contract, type CoordEntry, DEMO_ACTION_OPS, DOCS_FOOTER_KEYWORDS, DOCS_KEYWORDS, DOCS_SITE_KEYS, DOC_BLOCK_KEYWORDS, DOC_PROSE_KINDS, DOC_TRANSCLUSIONS, type DemoVariable, type DesignSystemDocument, type DimensionOrRef, type DimensionUnit, type DimensionValue, type Distribute, type DocBlockDecl, type DocPageDecl, type DocsDecl, type DocsFooterDecl, type DocsFooterLinkDecl, type DocsSiteDecl, type DocumentKind, type DocumentMeta, type DocumentMeta as ProjectMeta, type Token as DslToken, type DurationValue, EXAMPLE_KEYWORDS, type Emit, type EscapeTokenValue, type EventDef, type Example, type Expose, FACET_NAMES, type FacetDef, type FacetMap, type FacetName, type FacetTokenType, type FacetValue, type FieldType, type FontAsset, type FontCategory, type FontFamilyValue, type FontProvenance, type FontWeightValue, type Foundations, GROUP_REALIZATIONS, type GlobalProp, type Hole, INTERACTION_KINDS, type IconDecl, type IconSetDecl, type IconsDecl, type Id, type ImageAsset, type InsetValue, LAYOUT_ALIGNS, LAYOUT_DIRECTIONS, LAYOUT_DISTRIBUTES, LAYOUT_KEYS, LAYOUT_RECORD_KEYS, LAYOUT_VALUES, LAYOUT_WRAPS, LENGTH_LITERAL_FNS, LENGTH_TOKEN_TYPE_NAMES, LOGICAL_EDGES, type Layer, type LayoutAlign, type LayoutDirection, type LayoutDistribute, type LayoutRecordKey, type LayoutSpec, type LayoutWrap, type LengthKeyword, type LengthKeywordValue, type LengthValue, LexError, type LiteralChannel, type LiteralFnSpec, type LogicalEdge, MEDIA_TYPES, MILDA_SURFACE_VERSION, type Metadata, type MildaDocumentBase, NODE_KINDS, NODE_ORIGINS, type NodeSpan, type NoneValue, type ObjectField, type OpacityValue, PART_CONFIGS, PART_CONFIG_NAMES, PART_CONFIG_WORDS, PART_KEYWORDS, PHYSICAL_EDGE_ALIASES, POSITION_KINDS, PRELUDE_VERSION, PRESENTATION_KINDS, type ParamBinding, type ParseIssue, type ParseOptions, type ParseResult, type Part, type PartA11y, type PartAction, type PartBehavior, type PartCell, type PartConfigs, type PartContent, type PartContentRule, type PartEmit, type PartForeign, type PartInstance, type PartMediaSample, type PartMediaSource, type PartMotionTransition, type PartRepeat, type PartRepeatSource, type PartRole, type PartSlot, type PartSlotAccepts, type PartSlotArity, type PartSlotSample, type PartState, type PartStateBinding, type PartValue, type PartVariant, type Position, type PositionKind, type Predicate, type PredicateRef, type PreludeDocument, type PresentationRealize, type PrimitiveTokenType, type Project, type ProjectMetadataEntry, type PropConstraint, type PropDef, type PropValue, type RawTokenValue, type Realization, type RealizeCond, type RequiresClause, type ResolvedToken, type RuleSubject, SLOT_ARITIES, SLOT_MODIFIERS, SLOT_ROLES, type ShadowLayer, type ShadowValue, type SharedType, type SkippedChar, type SourcePosition, type SourceRange, type SpanKind, type StackAxis, type StateDef, type StateName, type Substitution, type SvgAsset, TOKEN_TYPES_BY_NAME, TOKEN_TYPE_NAMES, TOKEN_VALUE_KIND, TOKEN_VALUE_KINDS, type TaxonomyNote, type Token$1 as Token, type TokenRef, type TokenType, type TokenValue, type TokenValueSchemaByType, type TonalValue, type Transition, type TransitionTarget, type TypeExpr, type TypeRef, type TypographyValue, type UsageRule, type UsesClause, VALUE_LITERAL_FNS, type ValidationIssue, type VideoAsset, type Wire, allTokensOfType, archetypesByName, atomsByName, camelField, compositesByName, conformance, findToken, kebab as kebabField, lex, parseMildaDocument, preludeV0, resolveToken, tokenTypeFamily, validate };
1501
+ export { ASSET_BASE_KEYS, ASSET_FIELDS, ASSET_FIELD_KEYS, ASSET_KINDS, AXIS_CLAMPS, AXIS_INTENTS, type AliasTokenValue, type Align, type Anatomy, type AnatomyEntry, type AnatomyPart, type AnimationAsset, type AnimationFormat, type AnyTokenValue, type ArchetypeDef, type ArchetypeGroup, type ArchetypeRealize, type ArchetypeRef, type Asset, type AssetByKind, type AssetDecl, type AssetFolder, type AssetFolderDecl, type AssetKind, type AssetRegistry, type AssetsDecl, type Assignment, type Atom, type AtomContextVar, type AtomEvent, type AtomParam, type AtomStateNode, type AxisIntent, type AxisIntentKind, type AxisSize, type AxisSizeValue, BEHAVIOR_FIELDS, BEHAVIOR_KINDS, type BlurValue, type BorderFacetStyle, type BorderFacetValue, type BorderStyle, type BorderValue, type BorderWidth, type BrowseRealize, CELL_MODIFIERS, COLOR_KEYWORDS, COLOR_LITERAL_ALIASES, COLOR_LITERAL_FNS, COLOR_LITERAL_SPELLINGS, COLOR_TOKEN_TYPE_NAMES, CONTROL_REALIZATIONS, type Capability, type CapabilityDef, type ColorOrRef, type ColorSpace, type ColorValue, type CommitRealize, type CompareOp, type Component, type ComponentGroupDecl, type CompositeBehavior, type Composition, type ComputeOp, type ComputeSpace, type ComputeTokenValue, type ConfigFieldSpec, type ConfigSurface, type ConformanceOptions, type ConformanceReport, type ContentCategory, type Context, type ContextGroup, type Contract, type CoordEntry, DEMO_ACTION_OPS, DOCS_FOOTER_KEYWORDS, DOCS_KEYWORDS, DOCS_SITE_KEYS, DOC_BLOCK_KEYWORDS, DOC_PROSE_KINDS, DOC_TRANSCLUSIONS, type DemoVariable, type DesignSystemDocument, type DimensionOrRef, type DimensionUnit, type DimensionValue, type Distribute, type DocBlockDecl, type DocPageDecl, type DocsDecl, type DocsFooterDecl, type DocsFooterLinkDecl, type DocsSiteDecl, type DocumentKind, type DocumentMeta, type DocumentMeta as ProjectMeta, type Token as DslToken, type DurationValue, EXAMPLE_KEYWORDS, type Emit, type EscapeTokenValue, type EventDef, type Example, type Expose, FACET_NAMES, type FacetDef, type FacetMap, type FacetName, type FacetTokenType, type FacetValue, type FieldType, type FontAsset, type FontCategory, type FontFamilyValue, type FontProvenance, type FontWeightValue, type Foundations, GROUP_REALIZATIONS, type GlobalProp, type Hole, INSET_EDGES, INTERACTION_KINDS, type IconDecl, type IconSetDecl, type IconsDecl, type Id, type ImageAsset, type InsetEdge, type InsetValue, LAYOUT_ALIGNS, LAYOUT_DIRECTIONS, LAYOUT_DISTRIBUTES, LAYOUT_KEYS, LAYOUT_RECORD_KEYS, LAYOUT_VALUES, LAYOUT_WRAPS, LENGTH_LITERAL_FNS, LENGTH_TOKEN_TYPE_NAMES, LOGICAL_EDGES, type Layer, type LayoutAlign, type LayoutDirection, type LayoutDistribute, type LayoutRecordKey, type LayoutSpec, type LayoutWrap, type LengthKeyword, type LengthKeywordValue, type LengthValue, LexError, type LiteralChannel, type LiteralFnSpec, type LogicalEdge, MEDIA_TYPES, MILDA_SURFACE_VERSION, type Metadata, type MildaDocumentBase, type MissingPart, NODE_KINDS, NODE_ORIGINS, type NodeSpan, type NoneValue, type ObjectField, type OpacityValue, PART_CONFIGS, PART_CONFIG_NAMES, PART_CONFIG_WORDS, PART_KEYWORDS, PHYSICAL_EDGE_ALIASES, POSITION_KINDS, PRELUDE_VERSION, PRESENTATION_KINDS, type ParamBinding, type ParseIssue, type ParseOptions, type ParseResult, type Part, type PartA11y, type PartAction, type PartBehavior, type PartCell, type PartConfigs, type PartContent, type PartContentRule, type PartEmit, type PartForeign, type PartInstance, type PartMediaSample, type PartMediaSource, type PartMotionTransition, type PartRepeat, type PartRepeatSource, type PartRole, type PartSlot, type PartSlotAccepts, type PartSlotArity, type PartSlotSample, type PartState, type PartStateBinding, type PartValue, type PartVariant, type Position, type PositionKind, type Predicate, type PredicateRef, type PreludeDocument, type PresentationRealize, type PrimitiveTokenType, type Project, type ProjectMetadataEntry, type PropConstraint, type PropDef, type PropValue, type RawTokenValue, type Realization, type RealizeCond, type RequiresClause, type ResolvedToken, type RuleSubject, SLOT_ARITIES, SLOT_MODIFIERS, SLOT_ROLES, type ShadowLayer, type ShadowValue, type SharedType, type SkippedChar, type SourcePosition, type SourceRange, type SpanKind, type StackAxis, type StateDef, type StateName, type Substitution, type SvgAsset, TOKEN_TYPES_BY_NAME, TOKEN_TYPE_NAMES, TOKEN_VALUE_KIND, TOKEN_VALUE_KINDS, type TaxonomyNote, type Token$1 as Token, type TokenRef, type TokenType, type TokenValue, type TokenValueSchemaByType, type TonalValue, type Transition, type TransitionTarget, type TypeExpr, type TypeRef, type TypographyValue, type UsageRule, type UsesClause, VALUE_LITERAL_FNS, type ValidationIssue, type VideoAsset, type Wire, allTokensOfType, anatomyIndex, archetypesByName, atomsByName, camelField, compositesByName, conformance, findDeclaredPart, findToken, kebab as kebabField, lex, loweredAnatomy, missingRequiredParts, parseMildaDocument, preludeV0, resolveToken, tokenTypeFamily, validate };
package/dist/index.d.mts CHANGED
@@ -427,6 +427,11 @@ type PositionKind = (typeof POSITION_KINDS)[number];
427
427
  /** Logical edges, so a design system reads the same in a right-to-left locale. */
428
428
  declare const LOGICAL_EDGES: readonly ['block-start', 'block-end', 'inline-start', 'inline-end', 'block', 'inline', 'all'];
429
429
  type LogicalEdge = (typeof LOGICAL_EDGES)[number];
430
+ /** The edges an inset can be stated on, besides all four at once (proposal 0057). A dotted facet
431
+ * name each - `inset.inline`, `inset.block-start` - the way `border` takes `.<edge>`. The bare
432
+ * `inset` already means all four, so `all` is not one of them. */
433
+ declare const INSET_EDGES: readonly ["block", "inline", "block-start", "block-end", "inline-start", "inline-end"];
434
+ type InsetEdge = (typeof INSET_EDGES)[number];
430
435
  /** The physical edge words the parser used to take, read as the logical edge each names in a
431
436
  * horizontal left-to-right system. Read, never offered, never written - the `rgba` treatment. */
432
437
  declare const PHYSICAL_EDGE_ALIASES: Readonly<Record<string, LogicalEdge>>;
@@ -441,17 +446,12 @@ declare const DEMO_ACTION_OPS: readonly string[];
441
446
  declare function kebab(s: string): string;
442
447
  /** A surface kebab key → the IR's camelCase field (`week-starts-on` → `weekStartsOn`). */
443
448
  declare function camelField(s: string): string;
444
- declare const MILDA_SURFACE_VERSION = "0.8";
449
+ declare const MILDA_SURFACE_VERSION = "0.10";
445
450
  declare const PRELUDE_VERSION = "0.0.2";
446
- type FacetName = 'fill' | 'ink' | 'border' | 'border.top' | 'border.right' | 'border.bottom' | 'border.left' | 'border.inline-start' | 'border.inline-end' | 'border.block-start' | 'border.block-end' | 'corner' | 'inset' | 'gap' | 'text' | 'textClamp' | 'textWrap' | 'weight' | 'font' | 'slant' | 'elevation' | 'overlay' | 'opacity' | 'ring' | 'backdrop';
451
+ type FacetName = 'fill' | 'ink' | 'border' | 'border.top' | 'border.right' | 'border.bottom' | 'border.left' | 'border.inline-start' | 'border.inline-end' | 'border.block-start' | 'border.block-end' | 'corner' | 'inset' | `inset.${InsetEdge}` | 'gap' | 'text' | 'textClamp' | 'textWrap' | 'weight' | 'font' | 'slant' | 'elevation' | 'overlay' | 'opacity' | 'ring' | 'backdrop';
447
452
  type InsetValue = {
448
453
  block?: Id;
449
454
  inline?: Id;
450
- } | {
451
- top?: Id;
452
- right?: Id;
453
- bottom?: Id;
454
- left?: Id;
455
455
  } | {
456
456
  all: Id;
457
457
  };
@@ -923,7 +923,6 @@ interface Part {
923
923
  facets?: FacetMap;
924
924
  kind?: string;
925
925
  origin?: 'root' | 'archetype' | 'author';
926
- locked?: boolean;
927
926
  content?: PartContent;
928
927
  a11y?: PartA11y;
929
928
  emits?: PartEmit[];
@@ -1302,6 +1301,23 @@ declare const preludeV0: PreludeDocument;
1302
1301
  declare const atomsByName: Record<string, Atom>;
1303
1302
  declare const compositesByName: Record<string, CompositeBehavior>;
1304
1303
  declare const archetypesByName: Record<string, ArchetypeDef>;
1304
+ type ArchetypeRef = ArchetypeDef | string | null | undefined;
1305
+ interface AnatomyEntry {
1306
+ name: string;
1307
+ parentName: string | null;
1308
+ role: PartRole;
1309
+ optional: boolean;
1310
+ repeated: boolean;
1311
+ }
1312
+ declare function anatomyIndex(archetype: ArchetypeRef): Map<string, AnatomyEntry>;
1313
+ declare function loweredAnatomy(archetype: ArchetypeRef): readonly string[];
1314
+ declare function findDeclaredPart(name: string, parentPath: string, rootPath: string, paths: Iterable<string>, repeated: boolean): string | undefined;
1315
+ interface MissingPart {
1316
+ path: string;
1317
+ kind: PartRole;
1318
+ implied: boolean;
1319
+ }
1320
+ declare function missingRequiredParts(archetype: ArchetypeRef, anatomy: Anatomy): MissingPart[];
1305
1321
  type ResolvedToken = {
1306
1322
  kind: 'value';
1307
1323
  type: TokenType;
@@ -1482,4 +1498,4 @@ interface SkippedChar {
1482
1498
  col: number;
1483
1499
  }
1484
1500
  declare function lex(src: string, skipped?: SkippedChar[]): Token[];
1485
- export { ASSET_BASE_KEYS, ASSET_FIELDS, ASSET_FIELD_KEYS, ASSET_KINDS, AXIS_CLAMPS, AXIS_INTENTS, type AliasTokenValue, type Align, type Anatomy, type AnatomyPart, type AnimationAsset, type AnimationFormat, type AnyTokenValue, type ArchetypeDef, type ArchetypeGroup, type ArchetypeRealize, type Asset, type AssetByKind, type AssetDecl, type AssetFolder, type AssetFolderDecl, type AssetKind, type AssetRegistry, type AssetsDecl, type Assignment, type Atom, type AtomContextVar, type AtomEvent, type AtomParam, type AtomStateNode, type AxisIntent, type AxisIntentKind, type AxisSize, type AxisSizeValue, BEHAVIOR_FIELDS, BEHAVIOR_KINDS, type BlurValue, type BorderFacetStyle, type BorderFacetValue, type BorderStyle, type BorderValue, type BorderWidth, type BrowseRealize, CELL_MODIFIERS, COLOR_KEYWORDS, COLOR_LITERAL_ALIASES, COLOR_LITERAL_FNS, COLOR_LITERAL_SPELLINGS, COLOR_TOKEN_TYPE_NAMES, CONTROL_REALIZATIONS, type Capability, type CapabilityDef, type ColorOrRef, type ColorSpace, type ColorValue, type CommitRealize, type CompareOp, type Component, type ComponentGroupDecl, type CompositeBehavior, type Composition, type ComputeOp, type ComputeSpace, type ComputeTokenValue, type ConfigFieldSpec, type ConfigSurface, type ConformanceOptions, type ConformanceReport, type ContentCategory, type Context, type ContextGroup, type Contract, type CoordEntry, DEMO_ACTION_OPS, DOCS_FOOTER_KEYWORDS, DOCS_KEYWORDS, DOCS_SITE_KEYS, DOC_BLOCK_KEYWORDS, DOC_PROSE_KINDS, DOC_TRANSCLUSIONS, type DemoVariable, type DesignSystemDocument, type DimensionOrRef, type DimensionUnit, type DimensionValue, type Distribute, type DocBlockDecl, type DocPageDecl, type DocsDecl, type DocsFooterDecl, type DocsFooterLinkDecl, type DocsSiteDecl, type DocumentKind, type DocumentMeta, type DocumentMeta as ProjectMeta, type Token as DslToken, type DurationValue, EXAMPLE_KEYWORDS, type Emit, type EscapeTokenValue, type EventDef, type Example, type Expose, FACET_NAMES, type FacetDef, type FacetMap, type FacetName, type FacetTokenType, type FacetValue, type FieldType, type FontAsset, type FontCategory, type FontFamilyValue, type FontProvenance, type FontWeightValue, type Foundations, GROUP_REALIZATIONS, type GlobalProp, type Hole, INTERACTION_KINDS, type IconDecl, type IconSetDecl, type IconsDecl, type Id, type ImageAsset, type InsetValue, LAYOUT_ALIGNS, LAYOUT_DIRECTIONS, LAYOUT_DISTRIBUTES, LAYOUT_KEYS, LAYOUT_RECORD_KEYS, LAYOUT_VALUES, LAYOUT_WRAPS, LENGTH_LITERAL_FNS, LENGTH_TOKEN_TYPE_NAMES, LOGICAL_EDGES, type Layer, type LayoutAlign, type LayoutDirection, type LayoutDistribute, type LayoutRecordKey, type LayoutSpec, type LayoutWrap, type LengthKeyword, type LengthKeywordValue, type LengthValue, LexError, type LiteralChannel, type LiteralFnSpec, type LogicalEdge, MEDIA_TYPES, MILDA_SURFACE_VERSION, type Metadata, type MildaDocumentBase, NODE_KINDS, NODE_ORIGINS, type NodeSpan, type NoneValue, type ObjectField, type OpacityValue, PART_CONFIGS, PART_CONFIG_NAMES, PART_CONFIG_WORDS, PART_KEYWORDS, PHYSICAL_EDGE_ALIASES, POSITION_KINDS, PRELUDE_VERSION, PRESENTATION_KINDS, type ParamBinding, type ParseIssue, type ParseOptions, type ParseResult, type Part, type PartA11y, type PartAction, type PartBehavior, type PartCell, type PartConfigs, type PartContent, type PartContentRule, type PartEmit, type PartForeign, type PartInstance, type PartMediaSample, type PartMediaSource, type PartMotionTransition, type PartRepeat, type PartRepeatSource, type PartRole, type PartSlot, type PartSlotAccepts, type PartSlotArity, type PartSlotSample, type PartState, type PartStateBinding, type PartValue, type PartVariant, type Position, type PositionKind, type Predicate, type PredicateRef, type PreludeDocument, type PresentationRealize, type PrimitiveTokenType, type Project, type ProjectMetadataEntry, type PropConstraint, type PropDef, type PropValue, type RawTokenValue, type Realization, type RealizeCond, type RequiresClause, type ResolvedToken, type RuleSubject, SLOT_ARITIES, SLOT_MODIFIERS, SLOT_ROLES, type ShadowLayer, type ShadowValue, type SharedType, type SkippedChar, type SourcePosition, type SourceRange, type SpanKind, type StackAxis, type StateDef, type StateName, type Substitution, type SvgAsset, TOKEN_TYPES_BY_NAME, TOKEN_TYPE_NAMES, TOKEN_VALUE_KIND, TOKEN_VALUE_KINDS, type TaxonomyNote, type Token$1 as Token, type TokenRef, type TokenType, type TokenValue, type TokenValueSchemaByType, type TonalValue, type Transition, type TransitionTarget, type TypeExpr, type TypeRef, type TypographyValue, type UsageRule, type UsesClause, VALUE_LITERAL_FNS, type ValidationIssue, type VideoAsset, type Wire, allTokensOfType, archetypesByName, atomsByName, camelField, compositesByName, conformance, findToken, kebab as kebabField, lex, parseMildaDocument, preludeV0, resolveToken, tokenTypeFamily, validate };
1501
+ export { ASSET_BASE_KEYS, ASSET_FIELDS, ASSET_FIELD_KEYS, ASSET_KINDS, AXIS_CLAMPS, AXIS_INTENTS, type AliasTokenValue, type Align, type Anatomy, type AnatomyEntry, type AnatomyPart, type AnimationAsset, type AnimationFormat, type AnyTokenValue, type ArchetypeDef, type ArchetypeGroup, type ArchetypeRealize, type ArchetypeRef, type Asset, type AssetByKind, type AssetDecl, type AssetFolder, type AssetFolderDecl, type AssetKind, type AssetRegistry, type AssetsDecl, type Assignment, type Atom, type AtomContextVar, type AtomEvent, type AtomParam, type AtomStateNode, type AxisIntent, type AxisIntentKind, type AxisSize, type AxisSizeValue, BEHAVIOR_FIELDS, BEHAVIOR_KINDS, type BlurValue, type BorderFacetStyle, type BorderFacetValue, type BorderStyle, type BorderValue, type BorderWidth, type BrowseRealize, CELL_MODIFIERS, COLOR_KEYWORDS, COLOR_LITERAL_ALIASES, COLOR_LITERAL_FNS, COLOR_LITERAL_SPELLINGS, COLOR_TOKEN_TYPE_NAMES, CONTROL_REALIZATIONS, type Capability, type CapabilityDef, type ColorOrRef, type ColorSpace, type ColorValue, type CommitRealize, type CompareOp, type Component, type ComponentGroupDecl, type CompositeBehavior, type Composition, type ComputeOp, type ComputeSpace, type ComputeTokenValue, type ConfigFieldSpec, type ConfigSurface, type ConformanceOptions, type ConformanceReport, type ContentCategory, type Context, type ContextGroup, type Contract, type CoordEntry, DEMO_ACTION_OPS, DOCS_FOOTER_KEYWORDS, DOCS_KEYWORDS, DOCS_SITE_KEYS, DOC_BLOCK_KEYWORDS, DOC_PROSE_KINDS, DOC_TRANSCLUSIONS, type DemoVariable, type DesignSystemDocument, type DimensionOrRef, type DimensionUnit, type DimensionValue, type Distribute, type DocBlockDecl, type DocPageDecl, type DocsDecl, type DocsFooterDecl, type DocsFooterLinkDecl, type DocsSiteDecl, type DocumentKind, type DocumentMeta, type DocumentMeta as ProjectMeta, type Token as DslToken, type DurationValue, EXAMPLE_KEYWORDS, type Emit, type EscapeTokenValue, type EventDef, type Example, type Expose, FACET_NAMES, type FacetDef, type FacetMap, type FacetName, type FacetTokenType, type FacetValue, type FieldType, type FontAsset, type FontCategory, type FontFamilyValue, type FontProvenance, type FontWeightValue, type Foundations, GROUP_REALIZATIONS, type GlobalProp, type Hole, INSET_EDGES, INTERACTION_KINDS, type IconDecl, type IconSetDecl, type IconsDecl, type Id, type ImageAsset, type InsetEdge, type InsetValue, LAYOUT_ALIGNS, LAYOUT_DIRECTIONS, LAYOUT_DISTRIBUTES, LAYOUT_KEYS, LAYOUT_RECORD_KEYS, LAYOUT_VALUES, LAYOUT_WRAPS, LENGTH_LITERAL_FNS, LENGTH_TOKEN_TYPE_NAMES, LOGICAL_EDGES, type Layer, type LayoutAlign, type LayoutDirection, type LayoutDistribute, type LayoutRecordKey, type LayoutSpec, type LayoutWrap, type LengthKeyword, type LengthKeywordValue, type LengthValue, LexError, type LiteralChannel, type LiteralFnSpec, type LogicalEdge, MEDIA_TYPES, MILDA_SURFACE_VERSION, type Metadata, type MildaDocumentBase, type MissingPart, NODE_KINDS, NODE_ORIGINS, type NodeSpan, type NoneValue, type ObjectField, type OpacityValue, PART_CONFIGS, PART_CONFIG_NAMES, PART_CONFIG_WORDS, PART_KEYWORDS, PHYSICAL_EDGE_ALIASES, POSITION_KINDS, PRELUDE_VERSION, PRESENTATION_KINDS, type ParamBinding, type ParseIssue, type ParseOptions, type ParseResult, type Part, type PartA11y, type PartAction, type PartBehavior, type PartCell, type PartConfigs, type PartContent, type PartContentRule, type PartEmit, type PartForeign, type PartInstance, type PartMediaSample, type PartMediaSource, type PartMotionTransition, type PartRepeat, type PartRepeatSource, type PartRole, type PartSlot, type PartSlotAccepts, type PartSlotArity, type PartSlotSample, type PartState, type PartStateBinding, type PartValue, type PartVariant, type Position, type PositionKind, type Predicate, type PredicateRef, type PreludeDocument, type PresentationRealize, type PrimitiveTokenType, type Project, type ProjectMetadataEntry, type PropConstraint, type PropDef, type PropValue, type RawTokenValue, type Realization, type RealizeCond, type RequiresClause, type ResolvedToken, type RuleSubject, SLOT_ARITIES, SLOT_MODIFIERS, SLOT_ROLES, type ShadowLayer, type ShadowValue, type SharedType, type SkippedChar, type SourcePosition, type SourceRange, type SpanKind, type StackAxis, type StateDef, type StateName, type Substitution, type SvgAsset, TOKEN_TYPES_BY_NAME, TOKEN_TYPE_NAMES, TOKEN_VALUE_KIND, TOKEN_VALUE_KINDS, type TaxonomyNote, type Token$1 as Token, type TokenRef, type TokenType, type TokenValue, type TokenValueSchemaByType, type TonalValue, type Transition, type TransitionTarget, type TypeExpr, type TypeRef, type TypographyValue, type UsageRule, type UsesClause, VALUE_LITERAL_FNS, type ValidationIssue, type VideoAsset, type Wire, allTokensOfType, anatomyIndex, archetypesByName, atomsByName, camelField, compositesByName, conformance, findDeclaredPart, findToken, kebab as kebabField, lex, loweredAnatomy, missingRequiredParts, parseMildaDocument, preludeV0, resolveToken, tokenTypeFamily, validate };
package/dist/index.mjs CHANGED
@@ -3043,6 +3043,78 @@ const preludeV0 = {
3043
3043
  const atomsByName = Object.fromEntries(atoms.map((a) => [a.name, a]));
3044
3044
  const compositesByName = Object.fromEntries(composites.map((c) => [c.name, c]));
3045
3045
  const archetypesByName = Object.fromEntries(archetypes.map((a) => [a.name, a]));
3046
+ // prelude/required.ts
3047
+ function archetypeDef(archetype) {
3048
+ return typeof archetype === "string" ? archetypesByName[archetype] : archetype ?? void 0;
3049
+ }
3050
+ function anatomyIndex(archetype) {
3051
+ const out = /* @__PURE__ */ new Map();
3052
+ const parts = archetypeDef(archetype)?.anatomy;
3053
+ if (!parts) return out;
3054
+ const walk = (part, parentName) => {
3055
+ const seen = out.get(part.name);
3056
+ if (seen) seen.repeated = true;
3057
+ else out.set(part.name, {
3058
+ name: part.name,
3059
+ parentName,
3060
+ role: part.role,
3061
+ optional: part.optional === true,
3062
+ repeated: false
3063
+ });
3064
+ for (const child of part.children ?? []) walk(child, part.name);
3065
+ };
3066
+ for (const part of parts) walk(part, null);
3067
+ return out;
3068
+ }
3069
+ const LOWERED_ANATOMY = { BooleanInput: ["control", "indicator"] };
3070
+ function loweredAnatomy(archetype) {
3071
+ const name = typeof archetype === "string" ? archetype : archetype?.name;
3072
+ return name && LOWERED_ANATOMY[name] || [];
3073
+ }
3074
+ function findDeclaredPart(name, parentPath, rootPath, paths, repeated) {
3075
+ let best;
3076
+ for (const path of paths) {
3077
+ if ((path.split(".").pop() || path) !== name) continue;
3078
+ const under = parentPath === rootPath || path.startsWith(`${parentPath}.`);
3079
+ if (repeated && !under) continue;
3080
+ if (!best || path.split(".").length < best.split(".").length) best = path;
3081
+ }
3082
+ return best;
3083
+ }
3084
+ function missingRequiredParts(archetype, anatomy) {
3085
+ const parts = archetypeDef(archetype)?.anatomy;
3086
+ const paths = Object.keys(anatomy);
3087
+ const rootPath = paths[0];
3088
+ if (!parts || rootPath === void 0) return [];
3089
+ const known = anatomyIndex(archetype);
3090
+ const lowered = new Set(loweredAnatomy(archetype));
3091
+ const parentOf = (path) => path.includes(".") ? path.slice(0, path.lastIndexOf(".")) : rootPath;
3092
+ const standIns = /* @__PURE__ */ new Set();
3093
+ for (const path of paths.slice(1)) {
3094
+ const leaf = path.split(".").pop() || path;
3095
+ if (anatomy[path]?.kind === "input" && !known.has(leaf)) standIns.add(parentOf(path));
3096
+ }
3097
+ const out = [];
3098
+ const walk = (part, parentPath, parentMissing) => {
3099
+ const repeated = known.get(part.name)?.repeated ?? false;
3100
+ const declared = findDeclaredPart(part.name, parentPath, rootPath, paths, repeated);
3101
+ if (declared) {
3102
+ for (const child of part.children ?? []) walk(child, declared, false);
3103
+ return;
3104
+ }
3105
+ if (part.optional) return;
3106
+ if (!parentMissing && part.role === "input" && standIns.has(parentPath)) return;
3107
+ const path = parentPath === rootPath ? part.name : `${parentPath}.${part.name}`;
3108
+ out.push({
3109
+ path,
3110
+ kind: part.role,
3111
+ implied: parentMissing
3112
+ });
3113
+ for (const child of part.children ?? []) walk(child, path, true);
3114
+ };
3115
+ for (const part of parts) if (!lowered.has(part.name)) walk(part, rootPath, false);
3116
+ return out;
3117
+ }
3046
3118
  // engine/resolveToken.ts
3047
3119
  function resolveToken(tokenId, contextIds, layers, _depth = 0) {
3048
3120
  if (_depth > 20) return null;
@@ -3640,6 +3712,17 @@ const LOGICAL_EDGES = [
3640
3712
  "inline",
3641
3713
  "all"
3642
3714
  ];
3715
+ /** The edges an inset can be stated on, besides all four at once (proposal 0057). A dotted facet
3716
+ * name each - `inset.inline`, `inset.block-start` - the way `border` takes `.<edge>`. The bare
3717
+ * `inset` already means all four, so `all` is not one of them. */
3718
+ const INSET_EDGES = [
3719
+ "block",
3720
+ "inline",
3721
+ "block-start",
3722
+ "block-end",
3723
+ "inline-start",
3724
+ "inline-end"
3725
+ ];
3643
3726
  /** The physical edge words the parser used to take, read as the logical edge each names in a
3644
3727
  * horizontal left-to-right system. Read, never offered, never written - the `rgba` treatment. */
3645
3728
  const PHYSICAL_EDGE_ALIASES = {
@@ -3674,7 +3757,7 @@ function kebab(s) {
3674
3757
  function camelField(s) {
3675
3758
  return s.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
3676
3759
  }
3677
- const MILDA_SURFACE_VERSION = "0.8";
3760
+ const MILDA_SURFACE_VERSION = "0.10";
3678
3761
  const PRELUDE_VERSION = "0.0.2";
3679
3762
  // dsl/literal.ts
3680
3763
  const NUMBER_RE = /^-?\d+(\.\d+)?$/;
@@ -3791,6 +3874,17 @@ function validate(doc, prelude) {
3791
3874
  where,
3792
3875
  id: comp.id
3793
3876
  });
3877
+ const archetype = prelude.archetypes.find((a) => a.name === comp.archetype);
3878
+ for (const gap of missingRequiredParts(archetype, comp.anatomy)) {
3879
+ if (gap.implied) continue;
3880
+ issues.push({
3881
+ severity: "error",
3882
+ code: "part.required",
3883
+ message: `a ${comp.archetype} requires the part "${gap.path}" (${gap.kind})`,
3884
+ where,
3885
+ id: comp.id
3886
+ });
3887
+ }
3794
3888
  const propIds = new Set(comp.contract.props.map((p) => p.id));
3795
3889
  for (const [param, binding] of Object.entries(comp.contract.params)) if ("prop" in binding && !propIds.has(binding.prop)) issues.push({
3796
3890
  severity: "error",
@@ -4073,6 +4167,7 @@ const FACET_MAP = {
4073
4167
  "border.block-end": "border.block-end",
4074
4168
  corner: "corner",
4075
4169
  inset: "inset",
4170
+ ...Object.fromEntries(INSET_EDGES.map((e) => [`inset.${e}`, `inset.${e}`])),
4076
4171
  gap: "gap",
4077
4172
  text: "text",
4078
4173
  "text.clamp": "textClamp",
@@ -4209,7 +4304,6 @@ const SLOT_ARITIES = [
4209
4304
  const PART_KEYWORDS = [
4210
4305
  "kind",
4211
4306
  "origin",
4212
- "locked",
4213
4307
  "present",
4214
4308
  "slot",
4215
4309
  "content",
@@ -5969,7 +6063,13 @@ var Parser = class Parser {
5969
6063
  return spec;
5970
6064
  }
5971
6065
  parseFacetStmt() {
5972
- const raw = this.expectWord("facet-name");
6066
+ let raw = this.expectWord("facet-name");
6067
+ const physical = /^inset\.(top|right|bottom|left)$/.exec(raw);
6068
+ if (physical) {
6069
+ const logical = `inset.${PHYSICAL_EDGE_ALIASES[physical[1]]}`;
6070
+ this.issue("warning", "inset-physical", `'${raw}' is read as '${logical}' - write the logical edge`);
6071
+ raw = logical;
6072
+ }
5973
6073
  const mapped = FACET_MAP[raw];
5974
6074
  if (mapped === void 0) {
5975
6075
  this.issue("warning", "facet-unknown", `unknown facet "${raw}" skipped`);
@@ -5985,6 +6085,19 @@ var Parser = class Parser {
5985
6085
  name: "inset",
5986
6086
  value: { inset: this.parseInsetArgs() }
5987
6087
  };
6088
+ if (mapped.startsWith("inset.")) {
6089
+ const w = this.at("word") ? this.next().value : void 0;
6090
+ if (w === void 0) {
6091
+ this.issue("error", "facet-value", `"${raw}" needs a value`);
6092
+ this.skipToTerminator();
6093
+ return null;
6094
+ }
6095
+ if (!this.at("semi") && !this.at("newline") && !this.at("rbrace")) this.skipToTerminator();
6096
+ return {
6097
+ name: mapped,
6098
+ value: { token: tokId(w) }
6099
+ };
6100
+ }
5988
6101
  if (mapped === "border" || mapped.startsWith("border.")) {
5989
6102
  const border = {};
5990
6103
  while (this.at("word")) {
@@ -6465,13 +6578,30 @@ var Parser = class Parser {
6465
6578
  }
6466
6579
  return out;
6467
6580
  }
6581
+ parsePartHeader(part) {
6582
+ const said = {};
6583
+ if (this.at("colon")) {
6584
+ this.next();
6585
+ if (!this.at("word")) this.issue("error", "part-header-kind", "expected the part's kind after ':'");
6586
+ else {
6587
+ said.kind = this.next().value;
6588
+ part.kind = said.kind;
6589
+ }
6590
+ }
6591
+ while (!this.at("lbrace") && !this.atValueEnd()) {
6592
+ const tok = this.next();
6593
+ this.issue("error", "part-header-word", `unexpected ${JSON.stringify(tok.value)} in a part header - expected '{'`, tok);
6594
+ }
6595
+ return said;
6596
+ }
6468
6597
  parsePart() {
6469
6598
  const kw = this.next();
6470
6599
  const nameTok = this.peek();
6471
6600
  const name = this.expectWord("part-name");
6472
6601
  if (!name) return null;
6473
- this.expect("lbrace", "part-lbrace");
6474
6602
  const part = {};
6603
+ const header = this.parsePartHeader(part);
6604
+ this.expect("lbrace", "part-lbrace");
6475
6605
  const facets = {};
6476
6606
  const variants = [];
6477
6607
  while (!this.at("rbrace") && !this.at("eof")) {
@@ -6501,16 +6631,17 @@ var Parser = class Parser {
6501
6631
  this.next();
6502
6632
  part.slot = this.parseSlot();
6503
6633
  } else if (this.atWord("kind")) {
6504
- this.next();
6505
- part.kind = this.expectWord("part-kind");
6634
+ const tok = this.next();
6635
+ const stated = this.expectWord("part-kind");
6636
+ if (header.kind === void 0) part.kind = stated;
6637
+ else if (stated === header.kind) this.issue("warning", "part-kind-twice", `kind '${stated}' is stated twice`, tok);
6638
+ else if (stated) this.issue("error", "part-kind-conflict", `kind '${stated}' contradicts the header's '${header.kind}' - the header wins`, tok);
6506
6639
  } else if (this.atWord("origin")) {
6507
6640
  this.next();
6508
6641
  const o = this.expectWord("part-origin");
6509
6642
  if (o === "root" || o === "archetype" || o === "author") part.origin = o;
6510
- } else if (this.atWord("locked")) {
6511
- this.next();
6512
- part.locked = true;
6513
- } else if (this.atWord("content")) {
6643
+ } else if (this.atWord("locked")) this.next();
6644
+ else if (this.atWord("content")) {
6514
6645
  this.next();
6515
6646
  part.content = this.parsePartContent();
6516
6647
  } else if (this.atWord("a11y")) {
@@ -7629,7 +7760,7 @@ var Parser = class Parser {
7629
7760
  let docs;
7630
7761
  let assets;
7631
7762
  let icons;
7632
- let mildaVer = opts.milda ?? "0.8";
7763
+ let mildaVer = opts.milda ?? "0.10";
7633
7764
  let preludeVer = opts.prelude ?? "0.0.2";
7634
7765
  let docName = opts.name ?? "Design system";
7635
7766
  let docVersion = "0.0.0";
@@ -7758,7 +7889,7 @@ function parseMildaDocument(src, opts = {}) {
7758
7889
  }
7759
7890
  function emptyDocument(opts) {
7760
7891
  return {
7761
- milda: opts.milda ?? "0.8",
7892
+ milda: opts.milda ?? "0.10",
7762
7893
  kind: "design-system",
7763
7894
  prelude: opts.prelude ?? "0.0.2",
7764
7895
  meta: {
@@ -7775,4 +7906,4 @@ function emptyDocument(opts) {
7775
7906
  components: []
7776
7907
  };
7777
7908
  }
7778
- export { ASSET_BASE_KEYS, ASSET_FIELDS, ASSET_FIELD_KEYS, ASSET_KINDS, AXIS_CLAMPS, AXIS_INTENTS, BEHAVIOR_FIELDS, BEHAVIOR_KINDS, CELL_MODIFIERS, COLOR_KEYWORDS, COLOR_LITERAL_ALIASES, COLOR_LITERAL_FNS, COLOR_LITERAL_SPELLINGS, COLOR_TOKEN_TYPE_NAMES, CONTROL_REALIZATIONS, DEMO_ACTION_OPS, DOCS_FOOTER_KEYWORDS, DOCS_KEYWORDS, DOCS_SITE_KEYS, DOC_BLOCK_KEYWORDS, DOC_PROSE_KINDS, DOC_TRANSCLUSIONS, EXAMPLE_KEYWORDS, FACET_NAMES, GROUP_REALIZATIONS, INTERACTION_KINDS, LAYOUT_ALIGNS, LAYOUT_DIRECTIONS, LAYOUT_DISTRIBUTES, LAYOUT_KEYS, LAYOUT_RECORD_KEYS, LAYOUT_VALUES, LAYOUT_WRAPS, LENGTH_LITERAL_FNS, LENGTH_TOKEN_TYPE_NAMES, LOGICAL_EDGES, LexError, MEDIA_TYPES, MILDA_SURFACE_VERSION, NODE_KINDS, NODE_ORIGINS, PART_CONFIGS, PART_CONFIG_NAMES, PART_CONFIG_WORDS, PART_KEYWORDS, PHYSICAL_EDGE_ALIASES, POSITION_KINDS, PRELUDE_VERSION, PRESENTATION_KINDS, SLOT_ARITIES, SLOT_MODIFIERS, SLOT_ROLES, TOKEN_TYPES_BY_NAME, TOKEN_TYPE_NAMES, TOKEN_VALUE_KIND, TOKEN_VALUE_KINDS, VALUE_LITERAL_FNS, allTokensOfType, archetypesByName, atomsByName, camelField, compositesByName, conformance, findToken, kebab as kebabField, lex, parseMildaDocument, preludeV0, resolveToken, tokenTypeFamily, validate };
7909
+ export { ASSET_BASE_KEYS, ASSET_FIELDS, ASSET_FIELD_KEYS, ASSET_KINDS, AXIS_CLAMPS, AXIS_INTENTS, BEHAVIOR_FIELDS, BEHAVIOR_KINDS, CELL_MODIFIERS, COLOR_KEYWORDS, COLOR_LITERAL_ALIASES, COLOR_LITERAL_FNS, COLOR_LITERAL_SPELLINGS, COLOR_TOKEN_TYPE_NAMES, CONTROL_REALIZATIONS, DEMO_ACTION_OPS, DOCS_FOOTER_KEYWORDS, DOCS_KEYWORDS, DOCS_SITE_KEYS, DOC_BLOCK_KEYWORDS, DOC_PROSE_KINDS, DOC_TRANSCLUSIONS, EXAMPLE_KEYWORDS, FACET_NAMES, GROUP_REALIZATIONS, INSET_EDGES, INTERACTION_KINDS, LAYOUT_ALIGNS, LAYOUT_DIRECTIONS, LAYOUT_DISTRIBUTES, LAYOUT_KEYS, LAYOUT_RECORD_KEYS, LAYOUT_VALUES, LAYOUT_WRAPS, LENGTH_LITERAL_FNS, LENGTH_TOKEN_TYPE_NAMES, LOGICAL_EDGES, LexError, MEDIA_TYPES, MILDA_SURFACE_VERSION, NODE_KINDS, NODE_ORIGINS, PART_CONFIGS, PART_CONFIG_NAMES, PART_CONFIG_WORDS, PART_KEYWORDS, PHYSICAL_EDGE_ALIASES, POSITION_KINDS, PRELUDE_VERSION, PRESENTATION_KINDS, SLOT_ARITIES, SLOT_MODIFIERS, SLOT_ROLES, TOKEN_TYPES_BY_NAME, TOKEN_TYPE_NAMES, TOKEN_VALUE_KIND, TOKEN_VALUE_KINDS, VALUE_LITERAL_FNS, allTokensOfType, anatomyIndex, archetypesByName, atomsByName, camelField, compositesByName, conformance, findDeclaredPart, findToken, kebab as kebabField, lex, loweredAnatomy, missingRequiredParts, parseMildaDocument, preludeV0, resolveToken, tokenTypeFamily, validate };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mildastudio/milda",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "license": "MIT",
5
5
  "description": "The Milda language - a platform-neutral design language and canonical AST for design systems.",
6
6
  "repository": {