@theme-registry/refract 0.1.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.
Files changed (135) hide show
  1. package/LICENSE +21 -0
  2. package/dist/_createTheme-255ff48e.esm.js +2 -0
  3. package/dist/_createTheme-255ff48e.esm.js.map +1 -0
  4. package/dist/_createTheme-41c01033.cjs.js +2 -0
  5. package/dist/_createTheme-41c01033.cjs.js.map +1 -0
  6. package/dist/_errors-be768b25.cjs.js +2 -0
  7. package/dist/_errors-be768b25.cjs.js.map +1 -0
  8. package/dist/_errors-d75a5c74.esm.js +2 -0
  9. package/dist/_errors-d75a5c74.esm.js.map +1 -0
  10. package/dist/adapter-kit.cjs.js +2 -0
  11. package/dist/adapter-kit.cjs.js.map +1 -0
  12. package/dist/adapter-kit.d.ts +88 -0
  13. package/dist/adapter-kit.esm.js +2 -0
  14. package/dist/adapter-kit.esm.js.map +1 -0
  15. package/dist/build/auditCommand.d.ts +19 -0
  16. package/dist/build/buildCommand.d.ts +23 -0
  17. package/dist/build/cli.d.ts +2 -0
  18. package/dist/build/config.d.ts +58 -0
  19. package/dist/build/diff.d.ts +56 -0
  20. package/dist/build/diffCommand.d.ts +29 -0
  21. package/dist/build/emit.d.ts +20 -0
  22. package/dist/build/emitTheme.d.ts +39 -0
  23. package/dist/build/guide.d.ts +34 -0
  24. package/dist/build/importCommand.d.ts +42 -0
  25. package/dist/build/index.d.ts +33 -0
  26. package/dist/build/init.d.ts +32 -0
  27. package/dist/build/paths.d.ts +42 -0
  28. package/dist/build/skillsCommand.d.ts +53 -0
  29. package/dist/build/tokensCommand.d.ts +17 -0
  30. package/dist/build/vendor.d.ts +39 -0
  31. package/dist/build.cjs.js +2 -0
  32. package/dist/build.cjs.js.map +1 -0
  33. package/dist/build.esm.js +2 -0
  34. package/dist/build.esm.js.map +1 -0
  35. package/dist/cli.js +8250 -0
  36. package/dist/cli.js.map +1 -0
  37. package/dist/color-math.cjs.js +2 -0
  38. package/dist/color-math.cjs.js.map +1 -0
  39. package/dist/color-math.esm.js +2 -0
  40. package/dist/color-math.esm.js.map +1 -0
  41. package/dist/core/ThemeAdapter.d.ts +234 -0
  42. package/dist/core/createTheme.d.ts +96 -0
  43. package/dist/core/cssProperties.d.ts +8 -0
  44. package/dist/core/defineAdapter.d.ts +25 -0
  45. package/dist/core/derive/crossProperty.d.ts +31 -0
  46. package/dist/core/derive/index.d.ts +11 -0
  47. package/dist/core/derive/resolveTokens.d.ts +27 -0
  48. package/dist/core/errors.d.ts +24 -0
  49. package/dist/core/index.d.ts +16 -0
  50. package/dist/core/media/containers.d.ts +20 -0
  51. package/dist/core/media/defaults.d.ts +3 -0
  52. package/dist/core/media/descriptors.d.ts +12 -0
  53. package/dist/core/media/index.d.ts +11 -0
  54. package/dist/core/media/queries.d.ts +20 -0
  55. package/dist/core/model/buildModel.d.ts +116 -0
  56. package/dist/core/model/index.d.ts +14 -0
  57. package/dist/core/model/interpreted.d.ts +37 -0
  58. package/dist/core/model/mergeRuleSet.d.ts +68 -0
  59. package/dist/core/model/model.d.ts +260 -0
  60. package/dist/core/noopAdapter.d.ts +26 -0
  61. package/dist/core/normalize/index.d.ts +15 -0
  62. package/dist/core/normalize/properties.d.ts +20 -0
  63. package/dist/core/normalize/recipeResolver.d.ts +19 -0
  64. package/dist/core/normalize/recipes.d.ts +38 -0
  65. package/dist/core/normalize/responsive.d.ts +40 -0
  66. package/dist/core/normalize/types.d.ts +261 -0
  67. package/dist/core/rawTheme.d.ts +53 -0
  68. package/dist/core/ref.d.ts +13 -0
  69. package/dist/core/subsystem.d.ts +115 -0
  70. package/dist/core/types.d.ts +31 -0
  71. package/dist/core/units.d.ts +93 -0
  72. package/dist/dtcg/export.d.ts +48 -0
  73. package/dist/dtcg/import.d.ts +43 -0
  74. package/dist/dtcg/index.d.ts +21 -0
  75. package/dist/dtcg/parse.d.ts +6 -0
  76. package/dist/dtcg/types.d.ts +69 -0
  77. package/dist/dtcg.cjs.js +2 -0
  78. package/dist/dtcg.cjs.js.map +1 -0
  79. package/dist/dtcg.esm.js +2 -0
  80. package/dist/dtcg.esm.js.map +1 -0
  81. package/dist/index.cjs.js +2 -0
  82. package/dist/index.cjs.js.map +1 -0
  83. package/dist/index.d.ts +27 -0
  84. package/dist/index.esm.js +2 -0
  85. package/dist/index.esm.js.map +1 -0
  86. package/dist/subsystems/animation/index.d.ts +13 -0
  87. package/dist/subsystems/animation/recipes.d.ts +20 -0
  88. package/dist/subsystems/animation/types.d.ts +52 -0
  89. package/dist/subsystems/borders/index.d.ts +10 -0
  90. package/dist/subsystems/borders/recipes.d.ts +29 -0
  91. package/dist/subsystems/borders/types.d.ts +50 -0
  92. package/dist/subsystems/colors/audit.d.ts +67 -0
  93. package/dist/subsystems/colors/colorInput.d.ts +17 -0
  94. package/dist/subsystems/colors/index.d.ts +12 -0
  95. package/dist/subsystems/colors/keywords.d.ts +9 -0
  96. package/dist/subsystems/colors/normalize.d.ts +26 -0
  97. package/dist/subsystems/colors/recipes.d.ts +21 -0
  98. package/dist/subsystems/colors/types.d.ts +98 -0
  99. package/dist/subsystems/colors/utils.d.ts +104 -0
  100. package/dist/subsystems/components/index.d.ts +13 -0
  101. package/dist/subsystems/components/recipes.d.ts +22 -0
  102. package/dist/subsystems/components/types.d.ts +46 -0
  103. package/dist/subsystems/effects/index.d.ts +9 -0
  104. package/dist/subsystems/effects/recipes.d.ts +24 -0
  105. package/dist/subsystems/effects/types.d.ts +63 -0
  106. package/dist/subsystems/effects/utils.d.ts +57 -0
  107. package/dist/subsystems/globals/index.d.ts +21 -0
  108. package/dist/subsystems/globals/presets.d.ts +33 -0
  109. package/dist/subsystems/globals/types.d.ts +48 -0
  110. package/dist/subsystems/index.d.ts +21 -0
  111. package/dist/subsystems/layout/index.d.ts +14 -0
  112. package/dist/subsystems/layout/normalize.d.ts +35 -0
  113. package/dist/subsystems/layout/recipes.d.ts +16 -0
  114. package/dist/subsystems/layout/structural.d.ts +37 -0
  115. package/dist/subsystems/layout/types.d.ts +154 -0
  116. package/dist/subsystems/typography/index.d.ts +9 -0
  117. package/dist/subsystems/typography/normalize.d.ts +17 -0
  118. package/dist/subsystems/typography/recipes.d.ts +21 -0
  119. package/dist/subsystems/typography/types.d.ts +49 -0
  120. package/package.json +83 -0
  121. package/skills/adapter-scaffold/SKILL.md +85 -0
  122. package/skills/adapter-usage/SKILL.md +75 -0
  123. package/skills/build-config/SKILL.md +77 -0
  124. package/skills/colors/SKILL.md +134 -0
  125. package/skills/consuming-the-output/SKILL.md +62 -0
  126. package/skills/dtcg-import/SKILL.md +76 -0
  127. package/skills/layout/SKILL.md +65 -0
  128. package/skills/overrides-and-child-themes/SKILL.md +70 -0
  129. package/skills/recipes-and-composition/SKILL.md +110 -0
  130. package/skills/theme-authoring/SKILL.md +107 -0
  131. package/skills/theme-foundations/SKILL.md +127 -0
  132. package/skills/troubleshooting/SKILL.md +97 -0
  133. package/skills/typography/SKILL.md +66 -0
  134. package/skills/visual-effects/SKILL.md +96 -0
  135. package/src/subsystems/colors/utils.ts +299 -0
@@ -0,0 +1,2 @@
1
+ "use strict";class r extends Error{constructor(t,e,s){super(e),this.name="RefractError",this.code=t,s&&(this.failures=s),Object.setPrototypeOf(this,r.prototype)}}exports.RefractError=r;
2
+ //# sourceMappingURL=_errors-be768b25.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_errors-be768b25.cjs.js","sources":["../src/core/errors.ts"],"sourcesContent":["/**\n * Stable, machine-readable error codes (§P2-3). Every error refract throws for a theme authoring /\n * build problem — everything reachable from {@link createTheme} (subsystem normalization, token\n * derivation, DTCG parsing) — is a {@link RefractError} carrying a `code` from {@link RefractErrorCode}:\n * a stable identifier an agent (or a catch block) can branch on without string-matching the human\n * message. The message text stays human-first and unchanged; the code is additive.\n *\n * Scope: authoring/build errors. Pure CLI-tooling failures in `src/build/*` (bad arguments, a missing\n * file, an unknown command) stay plain `Error`s — they're usage errors from `refract <cmd>`, not a\n * problem with the theme an agent is editing.\n *\n * Dependency-free leaf on purpose, so any module (including the standalone `adapter-kit`) can throw one\n * without pulling in the core graph.\n */\nexport type RefractErrorCode =\n | \"REFRACT_E_COLOR_INPUT\" // a colour value wasn't a derivable colour\n | \"REFRACT_E_COLOR_TUPLE\" // an [r,g,b] tuple was malformed\n | \"REFRACT_E_STEPS\" // colors.<name>.steps out of range / non-numeric\n | \"REFRACT_E_VARIANT\" // a derivation-spec variant / modifier chain was malformed\n | \"REFRACT_E_VARIANT_REF\" // a variant referenced an unknown source\n | \"REFRACT_E_CYCLE\" // a cyclic reference (colour variant, token, recipe, DTCG alias)\n | \"REFRACT_E_ADJUST\" // an adjust dial was out of range\n | \"REFRACT_E_HARMONY\" // an invalid harmony scheme\n | \"REFRACT_E_VALIDATION\" // aggregate: one or more post-build ref-validation failures (see `failures`)\n | \"REFRACT_E_RECIPE_PROPERTY\" // a recipe declaration key is neither a known CSS property nor a reserved key\n | \"REFRACT_E_TOKEN_PATH\" // a token path is unknown / malformed / uses an unknown derivation fn\n | \"REFRACT_E_BREAKPOINT\" // a responsive entry omitted or named an unknown breakpoint\n | \"REFRACT_E_STATE\" // a recipe state entry named a state the adapter doesn't know\n | \"REFRACT_E_CONTAINER\" // a container-query entry named an unknown container / size / unsupported axis\n | \"REFRACT_E_RESPONSIVE\" // a responsive/mode override was malformed (variant+target conflict, unknown ref)\n | \"REFRACT_E_MEDIA\" // an invalid media / container query range (min > max)\n | \"REFRACT_E_MODE\" // an appearance-mode override with no base to override\n | \"REFRACT_E_PRESET\" // an unknown globals preset name\n | \"REFRACT_E_EFFECTS\" // a malformed effects value (shadow / transition layer)\n | \"REFRACT_E_LAYOUT\" // a malformed layout scale (ratio+step, bad rung)\n | \"REFRACT_E_UNITS\" // a malformed units config\n | \"REFRACT_E_PROPERTY\" // a property couldn't be normalized (no resolvable base value)\n | \"REFRACT_E_REFERENCE\" // a composition / rule-set reference didn't resolve\n | \"REFRACT_E_NAMING\" // a naming override / default path produced a collision\n | \"REFRACT_E_DTCG_VERSION\" // an unreadable DTCG refract-extension version\n | \"REFRACT_E_AUDIT\"; // a strict contrast audit failed\n\n/**\n * An authoring / build error with a stable {@link RefractErrorCode}. For an aggregate (collect-all)\n * error, `failures` lists each individual message so a caller can report them all at once.\n */\nexport class RefractError extends Error {\n readonly code: RefractErrorCode;\n readonly failures?: readonly string[];\n\n constructor(code: RefractErrorCode, message: string, failures?: readonly string[]) {\n super(message);\n this.name = \"RefractError\";\n this.code = code;\n if (failures) this.failures = failures;\n // Keep `instanceof RefractError` working after transpilation to ES5-ish targets.\n Object.setPrototypeOf(this, RefractError.prototype);\n }\n}\n"],"names":["RefractError","Error","constructor","code","message","failures","super","this","name","Object","setPrototypeOf","prototype"],"mappings":"aA8CM,MAAOA,UAAqBC,MAIhC,WAAAC,CAAYC,EAAwBC,EAAiBC,GACnDC,MAAMF,GACNG,KAAKC,KAAO,eACZD,KAAKJ,KAAOA,EACRE,IAAUE,KAAKF,SAAWA,GAE9BI,OAAOC,eAAeH,KAAMP,EAAaW,UAC1C"}
@@ -0,0 +1,2 @@
1
+ class t extends Error{constructor(r,e,s){super(e),this.name="RefractError",this.code=r,s&&(this.failures=s),Object.setPrototypeOf(this,t.prototype)}}export{t as R};
2
+ //# sourceMappingURL=_errors-d75a5c74.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_errors-d75a5c74.esm.js","sources":["../src/core/errors.ts"],"sourcesContent":["/**\n * Stable, machine-readable error codes (§P2-3). Every error refract throws for a theme authoring /\n * build problem — everything reachable from {@link createTheme} (subsystem normalization, token\n * derivation, DTCG parsing) — is a {@link RefractError} carrying a `code` from {@link RefractErrorCode}:\n * a stable identifier an agent (or a catch block) can branch on without string-matching the human\n * message. The message text stays human-first and unchanged; the code is additive.\n *\n * Scope: authoring/build errors. Pure CLI-tooling failures in `src/build/*` (bad arguments, a missing\n * file, an unknown command) stay plain `Error`s — they're usage errors from `refract <cmd>`, not a\n * problem with the theme an agent is editing.\n *\n * Dependency-free leaf on purpose, so any module (including the standalone `adapter-kit`) can throw one\n * without pulling in the core graph.\n */\nexport type RefractErrorCode =\n | \"REFRACT_E_COLOR_INPUT\" // a colour value wasn't a derivable colour\n | \"REFRACT_E_COLOR_TUPLE\" // an [r,g,b] tuple was malformed\n | \"REFRACT_E_STEPS\" // colors.<name>.steps out of range / non-numeric\n | \"REFRACT_E_VARIANT\" // a derivation-spec variant / modifier chain was malformed\n | \"REFRACT_E_VARIANT_REF\" // a variant referenced an unknown source\n | \"REFRACT_E_CYCLE\" // a cyclic reference (colour variant, token, recipe, DTCG alias)\n | \"REFRACT_E_ADJUST\" // an adjust dial was out of range\n | \"REFRACT_E_HARMONY\" // an invalid harmony scheme\n | \"REFRACT_E_VALIDATION\" // aggregate: one or more post-build ref-validation failures (see `failures`)\n | \"REFRACT_E_RECIPE_PROPERTY\" // a recipe declaration key is neither a known CSS property nor a reserved key\n | \"REFRACT_E_TOKEN_PATH\" // a token path is unknown / malformed / uses an unknown derivation fn\n | \"REFRACT_E_BREAKPOINT\" // a responsive entry omitted or named an unknown breakpoint\n | \"REFRACT_E_STATE\" // a recipe state entry named a state the adapter doesn't know\n | \"REFRACT_E_CONTAINER\" // a container-query entry named an unknown container / size / unsupported axis\n | \"REFRACT_E_RESPONSIVE\" // a responsive/mode override was malformed (variant+target conflict, unknown ref)\n | \"REFRACT_E_MEDIA\" // an invalid media / container query range (min > max)\n | \"REFRACT_E_MODE\" // an appearance-mode override with no base to override\n | \"REFRACT_E_PRESET\" // an unknown globals preset name\n | \"REFRACT_E_EFFECTS\" // a malformed effects value (shadow / transition layer)\n | \"REFRACT_E_LAYOUT\" // a malformed layout scale (ratio+step, bad rung)\n | \"REFRACT_E_UNITS\" // a malformed units config\n | \"REFRACT_E_PROPERTY\" // a property couldn't be normalized (no resolvable base value)\n | \"REFRACT_E_REFERENCE\" // a composition / rule-set reference didn't resolve\n | \"REFRACT_E_NAMING\" // a naming override / default path produced a collision\n | \"REFRACT_E_DTCG_VERSION\" // an unreadable DTCG refract-extension version\n | \"REFRACT_E_AUDIT\"; // a strict contrast audit failed\n\n/**\n * An authoring / build error with a stable {@link RefractErrorCode}. For an aggregate (collect-all)\n * error, `failures` lists each individual message so a caller can report them all at once.\n */\nexport class RefractError extends Error {\n readonly code: RefractErrorCode;\n readonly failures?: readonly string[];\n\n constructor(code: RefractErrorCode, message: string, failures?: readonly string[]) {\n super(message);\n this.name = \"RefractError\";\n this.code = code;\n if (failures) this.failures = failures;\n // Keep `instanceof RefractError` working after transpilation to ES5-ish targets.\n Object.setPrototypeOf(this, RefractError.prototype);\n }\n}\n"],"names":["RefractError","Error","constructor","code","message","failures","super","this","name","Object","setPrototypeOf","prototype"],"mappings":"AA8CM,MAAOA,UAAqBC,MAIhC,WAAAC,CAAYC,EAAwBC,EAAiBC,GACnDC,MAAMF,GACNG,KAAKC,KAAO,eACZD,KAAKJ,KAAOA,EACRE,IAAUE,KAAKF,SAAWA,GAE9BI,OAAOC,eAAeH,KAAMP,EAAaW,UAC1C"}
@@ -0,0 +1,2 @@
1
+ "use strict";var e=require("./_errors-be768b25.cjs.js");const a=e=>e.trim().replace(/\s+/g,"-").replace(/[^a-zA-Z0-9-_]/g,"-").replace(/-+/g,"-").replace(/^-+/,"").replace(/-+$/,"").toLowerCase(),n=(e,n)=>`--${e}-${n.split(".").map(a).filter(Boolean).join("-")}`,r=(e,n,r,s)=>[e.classToken,n,r,s].map(a).filter(Boolean).join("-");exports.createNamer=(s,t)=>{const o=new Map,i=new Map,l=!!(null==t?void 0:t.variableName),c=!!(null==t?void 0:t.className),m=(a,n)=>{const r=o.get(a);if(void 0!==r&&r!==n)throw new e.RefractError("REFRACT_E_NAMING",l?`naming override: variable name "${a}" is produced by both "${r}" and "${n}" — variableName must map distinct token paths to distinct names`:`naming collision: token paths "${r}" and "${n}" both produce the variable name "${a}" — segment sanitization collapses spaces / punctuation to "-", so rename one so their sanitized names differ`);o.set(a,n)},d=(a,n)=>{const r=i.get(a);if(void 0!==r&&r!==n)throw new e.RefractError("REFRACT_E_NAMING",c?`naming override: class name "${a}" is produced by both "${r}" and "${n}" — className must map distinct rule-sets to distinct names`:`naming collision: rule-sets "${r}" and "${n}" both produce the class name "${a}" — segment sanitization collapses spaces / punctuation to "-", so rename one so they differ`);i.set(a,n)};return{naming:s,variableName:r=>{const o=n(s.varToken,r);if(!(null==t?void 0:t.variableName))return m(o,r),o;const i=(n=>{const r=a(n.replace(/^-+/,""));if(!r)throw new e.RefractError("REFRACT_E_NAMING",`naming override: variableName returned an empty/invalid name ("${n}")`);return`--${r}`})(t.variableName({path:r,segments:r.split(".")},{varToken:s.varToken,name:o}));return m(i,r),i},className:(n,o,i,l)=>{const c="container"===n?`${s.classToken}-cq-${a(l)}`:r(s,o,i,l),m=`${n}:${o}.${i}.${l}`;if(!(null==t?void 0:t.className))return d(c,m),c;const p=t.className({kind:n,subsystem:o,group:i,variant:l},{classToken:s.classToken,name:c}),u=a(p);if(!u)throw new e.RefractError("REFRACT_E_NAMING",`naming override: className returned an empty/invalid name for "${n}:${o}.${i}.${l}"`);return d(u,m),u}}},exports.recipeClassName=r,exports.resolveNaming=e=>{var n,r,s;return{varToken:a(null!==(n=e.prefix)&&void 0!==n?n:"dt")||"dt",classToken:a(null!==(s=null!==(r=e.classPrefix)&&void 0!==r?r:e.prefix)&&void 0!==s?s:"dt")||"dt"}},exports.sanitizeSegment=a,exports.varNameFromPath=n;
2
+ //# sourceMappingURL=adapter-kit.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-kit.cjs.js","sources":["../src/adapter-kit.ts"],"sourcesContent":["/**\n * Uniform text-adapter naming (§17) — a single adapter-wide `prefix` (+ optional `classPrefix`\n * defaulting to it) drives every CSS variable and class name. Shared by the CSS and SC adapters so\n * the two text formats emit the SAME names from a token path — no per-subsystem infixes, no\n * per-subsystem defaults, single-dash separators. Lives at the adapters root (like `length.ts`) so\n * neither adapter depends on its sibling.\n *\n * variable: `varNameFromPath(token, \"colors.primary.dark\")` → `--<token>-colors-primary-dark`\n * class: `recipeClassName(naming, \"colors\", \"solid\", \"primary\")` → `<classToken>-colors-solid-primary`\n */\n\nimport { RefractError } from \"./core/errors\";\n\n/** Kebab/underscore-safe identifier segment. */\nexport const sanitizeSegment = (segment: string): string =>\n segment\n .trim()\n .replace(/\\s+/g, \"-\")\n .replace(/[^a-zA-Z0-9-_]/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-+/, \"\")\n .replace(/-+$/, \"\")\n .toLowerCase();\n\n/** Resolved naming tokens for one bound theme. */\nexport type AdapterNaming = {\n /** Leading segment of every CSS variable name (`app` → `--app-colors-primary`). */\n varToken: string;\n /** Leading segment of every class name (`app` → `app-colors-solid-primary`). */\n classToken: string;\n};\n\n/** Resolve the adapter-wide tokens: `classPrefix` falls back to `prefix`, both default to `dt`. */\nexport const resolveNaming = (options: { prefix?: string; classPrefix?: string }): AdapterNaming => {\n const varToken = sanitizeSegment(options.prefix ?? \"dt\") || \"dt\";\n const classToken = sanitizeSegment(options.classPrefix ?? options.prefix ?? \"dt\") || \"dt\";\n return { varToken, classToken };\n};\n\n/** A token path → its CSS variable name: `colors.primary.dark` → `--<token>-colors-primary-dark`. */\nexport const varNameFromPath = (varToken: string, path: string): string =>\n `--${varToken}-${path.split(\".\").map(sanitizeSegment).filter(Boolean).join(\"-\")}`;\n\n/** The recipe/rule-set identity: `<classToken>-<sub>-<group>-<variant>` (sanitized). */\nexport const recipeClassName = (\n naming: AdapterNaming,\n subsystem: string,\n group: string,\n variant: string,\n): string =>\n [naming.classToken, subsystem, group, variant].map(sanitizeSegment).filter(Boolean).join(\"-\");\n\n// ---------------------------------------------------------------------------\n// §7B — adapter naming-override hook\n// ---------------------------------------------------------------------------\n\n/**\n * A token path → its (possibly overridden) CSS variable name. The resolver the CSS + SC lowering\n * thread in place of a raw `varToken`, so a variable's `:root` definition and every `var(--…)`\n * usage funnel through the same (optionally overridden) name.\n */\nexport type VarNamer = (path: string) => string;\n\n/**\n * Optional per-adapter formatters that swap how class + variable names are generated. Each receives\n * the structured address plus the computed built-in `name` (decorate it or replace it). Shared by\n * the two text adapters (CSS + SC); JSON keys its own way and stays out. The adapter enforces a\n * three-part contract on every result: **deterministic** (a pure fn of the address), **collision-free**\n * (distinct addresses must yield distinct names — a duplicate throws), and a **valid identifier**\n * (the result is run through {@link sanitizeSegment}).\n */\nexport type NamingOverrides = {\n /**\n * Remap a recipe class (`kind: \"recipe\"`) or a container-context utility (`kind: \"container\"`,\n * the `-cq-<name>` class). `address.variant` is the recipe variant, or — for a container — its\n * name. Return `defaults.name` to keep the built-in name for the kinds you don't care about.\n */\n className?(\n address: { kind: \"recipe\" | \"container\"; subsystem: string; group: string; variant: string },\n defaults: { classToken: string; name: string },\n ): string;\n /**\n * Remap a CSS variable, addressed by its dotted token `path` (and its `segments`). The returned\n * name is normalized to a valid custom property (`--` + sanitized body).\n */\n variableName?(\n address: { path: string; segments: string[] },\n defaults: { varToken: string; name: string },\n ): string;\n};\n\n/** Normalize an overridden variable name to a valid custom property: `--` + sanitized body. */\nconst sanitizeVarName = (name: string): string => {\n const body = sanitizeSegment(name.replace(/^-+/, \"\"));\n if (!body) throw new RefractError(\"REFRACT_E_NAMING\", `naming override: variableName returned an empty/invalid name (\"${name}\")`);\n return `--${body}`;\n};\n\n/** The bound naming surface for one theme: the resolved tokens + the two override-aware namers. */\nexport interface AdapterNamer {\n readonly naming: AdapterNaming;\n /** A token path → its (possibly overridden) CSS variable name. */\n variableName: VarNamer;\n /** A recipe or container-context class → its (possibly overridden) class name. */\n className(\n kind: \"recipe\" | \"container\",\n subsystem: string,\n group: string,\n variant: string,\n ): string;\n}\n\n/**\n * Bind the resolved {@link AdapterNaming} + optional {@link NamingOverrides} into an {@link AdapterNamer}.\n * Every emitted name is collision-checked on **both** the default and the override path: two distinct\n * addresses (token paths / rule-sets) that resolve to the same output name throw a path-labelled error,\n * so a silent merge — e.g. palettes `\"brand accent\"` and `\"brand-accent\"` both sanitizing to\n * `--dt-colors-brand-accent` — fails loud instead. The SAME address re-resolving to the same name is\n * fine (definitions + usages call repeatedly). With no overrides the namer returns the built-in name\n * verbatim (byte-identical); the bookkeeping is checked but never rewrites the name.\n * The container-context class keeps its own `<classToken>-cq-<name>` default, distinct from the recipe formula.\n */\nexport const createNamer = (naming: AdapterNaming, overrides?: NamingOverrides): AdapterNamer => {\n const varSeen = new Map<string, string>(); // output var name → source path\n const classSeen = new Map<string, string>(); // output class name → source address key\n const hasVarOverride = !!overrides?.variableName;\n const hasClassOverride = !!overrides?.className;\n\n const trackVar = (name: string, path: string): void => {\n const prev = varSeen.get(name);\n if (prev !== undefined && prev !== path) {\n throw new RefractError(\n \"REFRACT_E_NAMING\",\n hasVarOverride\n ? `naming override: variable name \"${name}\" is produced by both \"${prev}\" and \"${path}\" — ` +\n `variableName must map distinct token paths to distinct names`\n : `naming collision: token paths \"${prev}\" and \"${path}\" both produce the variable name ` +\n `\"${name}\" — segment sanitization collapses spaces / punctuation to \"-\", so rename one ` +\n `so their sanitized names differ`,\n );\n }\n varSeen.set(name, path);\n };\n\n const trackClass = (name: string, key: string): void => {\n const prev = classSeen.get(name);\n if (prev !== undefined && prev !== key) {\n throw new RefractError(\n \"REFRACT_E_NAMING\",\n hasClassOverride\n ? `naming override: class name \"${name}\" is produced by both \"${prev}\" and \"${key}\" — ` +\n `className must map distinct rule-sets to distinct names`\n : `naming collision: rule-sets \"${prev}\" and \"${key}\" both produce the class name \"${name}\" — ` +\n `segment sanitization collapses spaces / punctuation to \"-\", so rename one so they differ`,\n );\n }\n classSeen.set(name, key);\n };\n\n return {\n naming,\n variableName: (path) => {\n const def = varNameFromPath(naming.varToken, path);\n if (!overrides?.variableName) {\n trackVar(def, path);\n return def;\n }\n const raw = overrides.variableName(\n { path, segments: path.split(\".\") },\n { varToken: naming.varToken, name: def },\n );\n const name = sanitizeVarName(raw);\n trackVar(name, path);\n return name;\n },\n className: (kind, subsystem, group, variant) => {\n const def =\n kind === \"container\"\n ? `${naming.classToken}-cq-${sanitizeSegment(variant)}`\n : recipeClassName(naming, subsystem, group, variant);\n const key = `${kind}:${subsystem}.${group}.${variant}`;\n if (!overrides?.className) {\n trackClass(def, key);\n return def;\n }\n const raw = overrides.className(\n { kind, subsystem, group, variant },\n { classToken: naming.classToken, name: def },\n );\n const name = sanitizeSegment(raw);\n if (!name) {\n throw new RefractError(\n \"REFRACT_E_NAMING\",\n `naming override: className returned an empty/invalid name for ` +\n `\"${kind}:${subsystem}.${group}.${variant}\"`,\n );\n }\n trackClass(name, key);\n return name;\n },\n };\n};\n"],"names":["sanitizeSegment","segment","trim","replace","toLowerCase","varNameFromPath","varToken","path","split","map","filter","Boolean","join","recipeClassName","naming","subsystem","group","variant","classToken","overrides","varSeen","Map","classSeen","hasVarOverride","variableName","hasClassOverride","className","trackVar","name","prev","get","undefined","RefractError","set","trackClass","key","def","body","sanitizeVarName","segments","kind","raw","options","_a","prefix","_c","_b","classPrefix"],"mappings":"8DAcaA,EAAmBC,GAC9BA,EACGC,OACAC,QAAQ,OAAQ,KAChBA,QAAQ,kBAAmB,KAC3BA,QAAQ,MAAO,KACfA,QAAQ,MAAO,IACfA,QAAQ,MAAO,IACfC,cAkBQC,EAAkB,CAACC,EAAkBC,IAChD,KAAKD,KAAYC,EAAKC,MAAM,KAAKC,IAAIT,GAAiBU,OAAOC,SAASC,KAAK,OAGhEC,EAAkB,CAC7BC,EACAC,EACAC,EACAC,IAEA,CAACH,EAAOI,WAAYH,EAAWC,EAAOC,GAASR,IAAIT,GAAiBU,OAAOC,SAASC,KAAK,yBAwEhE,CAACE,EAAuBK,KACjD,MAAMC,EAAU,IAAIC,IACdC,EAAY,IAAID,IAChBE,KAAmBJ,aAAA,EAAAA,EAAWK,cAC9BC,KAAqBN,aAAA,EAAAA,EAAWO,WAEhCC,EAAW,CAACC,EAAcrB,KAC9B,MAAMsB,EAAOT,EAAQU,IAAIF,GACzB,QAAaG,IAATF,GAAsBA,IAAStB,EACjC,MAAM,IAAIyB,EAAAA,aACR,mBACAT,EACI,mCAAmCK,2BAA8BC,WAActB,oEAE/E,kCAAkCsB,WAActB,sCAC1CqB,kHAIdR,EAAQa,IAAIL,EAAMrB,IAGd2B,EAAa,CAACN,EAAcO,KAChC,MAAMN,EAAOP,EAAUQ,IAAIF,GAC3B,QAAaG,IAATF,GAAsBA,IAASM,EACjC,MAAM,IAAIH,EAAAA,aACR,mBACAP,EACI,gCAAgCG,2BAA8BC,WAAcM,+DAE5E,gCAAgCN,WAAcM,mCAAqCP,iGAI3FN,EAAUW,IAAIL,EAAMO,IAGtB,MAAO,CACLrB,SACAU,aAAejB,IACb,MAAM6B,EAAM/B,EAAgBS,EAAOR,SAAUC,GAC7C,KAAKY,aAAA,EAAAA,EAAWK,cAEd,OADAG,EAASS,EAAK7B,GACP6B,EAET,MAIMR,EA/EY,CAACA,IACvB,MAAMS,EAAOrC,EAAgB4B,EAAKzB,QAAQ,MAAO,KACjD,IAAKkC,EAAM,MAAM,IAAIL,EAAYA,aAAC,mBAAoB,kEAAkEJ,OACxH,MAAO,KAAKS,KA4EKC,CAJDnB,EAAUK,aACpB,CAAEjB,OAAMgC,SAAUhC,EAAKC,MAAM,MAC7B,CAAEF,SAAUQ,EAAOR,SAAUsB,KAAMQ,KAIrC,OADAT,EAASC,EAAMrB,GACRqB,GAETF,UAAW,CAACc,EAAMzB,EAAWC,EAAOC,KAClC,MAAMmB,EACK,cAATI,EACI,GAAG1B,EAAOI,iBAAiBlB,EAAgBiB,KAC3CJ,EAAgBC,EAAQC,EAAWC,EAAOC,GAC1CkB,EAAM,GAAGK,KAAQzB,KAAaC,KAASC,IAC7C,KAAKE,aAAA,EAAAA,EAAWO,WAEd,OADAQ,EAAWE,EAAKD,GACTC,EAET,MAAMK,EAAMtB,EAAUO,UACpB,CAAEc,OAAMzB,YAAWC,QAAOC,WAC1B,CAAEC,WAAYJ,EAAOI,WAAYU,KAAMQ,IAEnCR,EAAO5B,EAAgByC,GAC7B,IAAKb,EACH,MAAM,IAAII,EAAYA,aACpB,mBAEE,kEAAIQ,KAAQzB,KAAaC,KAASC,MAIxC,OADAiB,EAAWN,EAAMO,GACVP,qDArKiBc,cAG5B,MAAO,CAAEpC,SAFQN,EAAkC,QAAlB2C,EAAAD,EAAQE,cAAU,IAAAD,EAAAA,EAAA,OAAS,KAEzCzB,WADAlB,EAAqD,QAArC6C,EAAuB,QAAvBC,EAAAJ,EAAQK,mBAAe,IAAAD,EAAAA,EAAAJ,EAAQE,cAAM,IAAAC,EAAAA,EAAI,OAAS"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Uniform text-adapter naming (§17) — a single adapter-wide `prefix` (+ optional `classPrefix`
3
+ * defaulting to it) drives every CSS variable and class name. Shared by the CSS and SC adapters so
4
+ * the two text formats emit the SAME names from a token path — no per-subsystem infixes, no
5
+ * per-subsystem defaults, single-dash separators. Lives at the adapters root (like `length.ts`) so
6
+ * neither adapter depends on its sibling.
7
+ *
8
+ * variable: `varNameFromPath(token, "colors.primary.dark")` → `--<token>-colors-primary-dark`
9
+ * class: `recipeClassName(naming, "colors", "solid", "primary")` → `<classToken>-colors-solid-primary`
10
+ */
11
+ /** Kebab/underscore-safe identifier segment. */
12
+ export declare const sanitizeSegment: (segment: string) => string;
13
+ /** Resolved naming tokens for one bound theme. */
14
+ export type AdapterNaming = {
15
+ /** Leading segment of every CSS variable name (`app` → `--app-colors-primary`). */
16
+ varToken: string;
17
+ /** Leading segment of every class name (`app` → `app-colors-solid-primary`). */
18
+ classToken: string;
19
+ };
20
+ /** Resolve the adapter-wide tokens: `classPrefix` falls back to `prefix`, both default to `dt`. */
21
+ export declare const resolveNaming: (options: {
22
+ prefix?: string;
23
+ classPrefix?: string;
24
+ }) => AdapterNaming;
25
+ /** A token path → its CSS variable name: `colors.primary.dark` → `--<token>-colors-primary-dark`. */
26
+ export declare const varNameFromPath: (varToken: string, path: string) => string;
27
+ /** The recipe/rule-set identity: `<classToken>-<sub>-<group>-<variant>` (sanitized). */
28
+ export declare const recipeClassName: (naming: AdapterNaming, subsystem: string, group: string, variant: string) => string;
29
+ /**
30
+ * A token path → its (possibly overridden) CSS variable name. The resolver the CSS + SC lowering
31
+ * thread in place of a raw `varToken`, so a variable's `:root` definition and every `var(--…)`
32
+ * usage funnel through the same (optionally overridden) name.
33
+ */
34
+ export type VarNamer = (path: string) => string;
35
+ /**
36
+ * Optional per-adapter formatters that swap how class + variable names are generated. Each receives
37
+ * the structured address plus the computed built-in `name` (decorate it or replace it). Shared by
38
+ * the two text adapters (CSS + SC); JSON keys its own way and stays out. The adapter enforces a
39
+ * three-part contract on every result: **deterministic** (a pure fn of the address), **collision-free**
40
+ * (distinct addresses must yield distinct names — a duplicate throws), and a **valid identifier**
41
+ * (the result is run through {@link sanitizeSegment}).
42
+ */
43
+ export type NamingOverrides = {
44
+ /**
45
+ * Remap a recipe class (`kind: "recipe"`) or a container-context utility (`kind: "container"`,
46
+ * the `-cq-<name>` class). `address.variant` is the recipe variant, or — for a container — its
47
+ * name. Return `defaults.name` to keep the built-in name for the kinds you don't care about.
48
+ */
49
+ className?(address: {
50
+ kind: "recipe" | "container";
51
+ subsystem: string;
52
+ group: string;
53
+ variant: string;
54
+ }, defaults: {
55
+ classToken: string;
56
+ name: string;
57
+ }): string;
58
+ /**
59
+ * Remap a CSS variable, addressed by its dotted token `path` (and its `segments`). The returned
60
+ * name is normalized to a valid custom property (`--` + sanitized body).
61
+ */
62
+ variableName?(address: {
63
+ path: string;
64
+ segments: string[];
65
+ }, defaults: {
66
+ varToken: string;
67
+ name: string;
68
+ }): string;
69
+ };
70
+ /** The bound naming surface for one theme: the resolved tokens + the two override-aware namers. */
71
+ export interface AdapterNamer {
72
+ readonly naming: AdapterNaming;
73
+ /** A token path → its (possibly overridden) CSS variable name. */
74
+ variableName: VarNamer;
75
+ /** A recipe or container-context class → its (possibly overridden) class name. */
76
+ className(kind: "recipe" | "container", subsystem: string, group: string, variant: string): string;
77
+ }
78
+ /**
79
+ * Bind the resolved {@link AdapterNaming} + optional {@link NamingOverrides} into an {@link AdapterNamer}.
80
+ * Every emitted name is collision-checked on **both** the default and the override path: two distinct
81
+ * addresses (token paths / rule-sets) that resolve to the same output name throw a path-labelled error,
82
+ * so a silent merge — e.g. palettes `"brand accent"` and `"brand-accent"` both sanitizing to
83
+ * `--dt-colors-brand-accent` — fails loud instead. The SAME address re-resolving to the same name is
84
+ * fine (definitions + usages call repeatedly). With no overrides the namer returns the built-in name
85
+ * verbatim (byte-identical); the bookkeeping is checked but never rewrites the name.
86
+ * The container-context class keeps its own `<classToken>-cq-<name>` default, distinct from the recipe formula.
87
+ */
88
+ export declare const createNamer: (naming: AdapterNaming, overrides?: NamingOverrides) => AdapterNamer;
@@ -0,0 +1,2 @@
1
+ import{R as e}from"./_errors-d75a5c74.esm.js";const a=e=>e.trim().replace(/\s+/g,"-").replace(/[^a-zA-Z0-9-_]/g,"-").replace(/-+/g,"-").replace(/^-+/,"").replace(/-+$/,"").toLowerCase(),n=e=>{var n,s,t;return{varToken:a(null!==(n=e.prefix)&&void 0!==n?n:"dt")||"dt",classToken:a(null!==(t=null!==(s=e.classPrefix)&&void 0!==s?s:e.prefix)&&void 0!==t?t:"dt")||"dt"}},s=(e,n)=>`--${e}-${n.split(".").map(a).filter(Boolean).join("-")}`,t=(e,n,s,t)=>[e.classToken,n,s,t].map(a).filter(Boolean).join("-"),o=(n,o)=>{const i=new Map,r=new Map,l=!!(null==o?void 0:o.variableName),m=!!(null==o?void 0:o.className),c=(a,n)=>{const s=i.get(a);if(void 0!==s&&s!==n)throw new e("REFRACT_E_NAMING",l?`naming override: variable name "${a}" is produced by both "${s}" and "${n}" — variableName must map distinct token paths to distinct names`:`naming collision: token paths "${s}" and "${n}" both produce the variable name "${a}" — segment sanitization collapses spaces / punctuation to "-", so rename one so their sanitized names differ`);i.set(a,n)},d=(a,n)=>{const s=r.get(a);if(void 0!==s&&s!==n)throw new e("REFRACT_E_NAMING",m?`naming override: class name "${a}" is produced by both "${s}" and "${n}" — className must map distinct rule-sets to distinct names`:`naming collision: rule-sets "${s}" and "${n}" both produce the class name "${a}" — segment sanitization collapses spaces / punctuation to "-", so rename one so they differ`);r.set(a,n)};return{naming:n,variableName:t=>{const i=s(n.varToken,t);if(!(null==o?void 0:o.variableName))return c(i,t),i;const r=(n=>{const s=a(n.replace(/^-+/,""));if(!s)throw new e("REFRACT_E_NAMING",`naming override: variableName returned an empty/invalid name ("${n}")`);return`--${s}`})(o.variableName({path:t,segments:t.split(".")},{varToken:n.varToken,name:i}));return c(r,t),r},className:(s,i,r,l)=>{const m="container"===s?`${n.classToken}-cq-${a(l)}`:t(n,i,r,l),c=`${s}:${i}.${r}.${l}`;if(!(null==o?void 0:o.className))return d(m,c),m;const p=o.className({kind:s,subsystem:i,group:r,variant:l},{classToken:n.classToken,name:m}),u=a(p);if(!u)throw new e("REFRACT_E_NAMING",`naming override: className returned an empty/invalid name for "${s}:${i}.${r}.${l}"`);return d(u,c),u}}};export{o as createNamer,t as recipeClassName,n as resolveNaming,a as sanitizeSegment,s as varNameFromPath};
2
+ //# sourceMappingURL=adapter-kit.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter-kit.esm.js","sources":["../src/adapter-kit.ts"],"sourcesContent":["/**\n * Uniform text-adapter naming (§17) — a single adapter-wide `prefix` (+ optional `classPrefix`\n * defaulting to it) drives every CSS variable and class name. Shared by the CSS and SC adapters so\n * the two text formats emit the SAME names from a token path — no per-subsystem infixes, no\n * per-subsystem defaults, single-dash separators. Lives at the adapters root (like `length.ts`) so\n * neither adapter depends on its sibling.\n *\n * variable: `varNameFromPath(token, \"colors.primary.dark\")` → `--<token>-colors-primary-dark`\n * class: `recipeClassName(naming, \"colors\", \"solid\", \"primary\")` → `<classToken>-colors-solid-primary`\n */\n\nimport { RefractError } from \"./core/errors\";\n\n/** Kebab/underscore-safe identifier segment. */\nexport const sanitizeSegment = (segment: string): string =>\n segment\n .trim()\n .replace(/\\s+/g, \"-\")\n .replace(/[^a-zA-Z0-9-_]/g, \"-\")\n .replace(/-+/g, \"-\")\n .replace(/^-+/, \"\")\n .replace(/-+$/, \"\")\n .toLowerCase();\n\n/** Resolved naming tokens for one bound theme. */\nexport type AdapterNaming = {\n /** Leading segment of every CSS variable name (`app` → `--app-colors-primary`). */\n varToken: string;\n /** Leading segment of every class name (`app` → `app-colors-solid-primary`). */\n classToken: string;\n};\n\n/** Resolve the adapter-wide tokens: `classPrefix` falls back to `prefix`, both default to `dt`. */\nexport const resolveNaming = (options: { prefix?: string; classPrefix?: string }): AdapterNaming => {\n const varToken = sanitizeSegment(options.prefix ?? \"dt\") || \"dt\";\n const classToken = sanitizeSegment(options.classPrefix ?? options.prefix ?? \"dt\") || \"dt\";\n return { varToken, classToken };\n};\n\n/** A token path → its CSS variable name: `colors.primary.dark` → `--<token>-colors-primary-dark`. */\nexport const varNameFromPath = (varToken: string, path: string): string =>\n `--${varToken}-${path.split(\".\").map(sanitizeSegment).filter(Boolean).join(\"-\")}`;\n\n/** The recipe/rule-set identity: `<classToken>-<sub>-<group>-<variant>` (sanitized). */\nexport const recipeClassName = (\n naming: AdapterNaming,\n subsystem: string,\n group: string,\n variant: string,\n): string =>\n [naming.classToken, subsystem, group, variant].map(sanitizeSegment).filter(Boolean).join(\"-\");\n\n// ---------------------------------------------------------------------------\n// §7B — adapter naming-override hook\n// ---------------------------------------------------------------------------\n\n/**\n * A token path → its (possibly overridden) CSS variable name. The resolver the CSS + SC lowering\n * thread in place of a raw `varToken`, so a variable's `:root` definition and every `var(--…)`\n * usage funnel through the same (optionally overridden) name.\n */\nexport type VarNamer = (path: string) => string;\n\n/**\n * Optional per-adapter formatters that swap how class + variable names are generated. Each receives\n * the structured address plus the computed built-in `name` (decorate it or replace it). Shared by\n * the two text adapters (CSS + SC); JSON keys its own way and stays out. The adapter enforces a\n * three-part contract on every result: **deterministic** (a pure fn of the address), **collision-free**\n * (distinct addresses must yield distinct names — a duplicate throws), and a **valid identifier**\n * (the result is run through {@link sanitizeSegment}).\n */\nexport type NamingOverrides = {\n /**\n * Remap a recipe class (`kind: \"recipe\"`) or a container-context utility (`kind: \"container\"`,\n * the `-cq-<name>` class). `address.variant` is the recipe variant, or — for a container — its\n * name. Return `defaults.name` to keep the built-in name for the kinds you don't care about.\n */\n className?(\n address: { kind: \"recipe\" | \"container\"; subsystem: string; group: string; variant: string },\n defaults: { classToken: string; name: string },\n ): string;\n /**\n * Remap a CSS variable, addressed by its dotted token `path` (and its `segments`). The returned\n * name is normalized to a valid custom property (`--` + sanitized body).\n */\n variableName?(\n address: { path: string; segments: string[] },\n defaults: { varToken: string; name: string },\n ): string;\n};\n\n/** Normalize an overridden variable name to a valid custom property: `--` + sanitized body. */\nconst sanitizeVarName = (name: string): string => {\n const body = sanitizeSegment(name.replace(/^-+/, \"\"));\n if (!body) throw new RefractError(\"REFRACT_E_NAMING\", `naming override: variableName returned an empty/invalid name (\"${name}\")`);\n return `--${body}`;\n};\n\n/** The bound naming surface for one theme: the resolved tokens + the two override-aware namers. */\nexport interface AdapterNamer {\n readonly naming: AdapterNaming;\n /** A token path → its (possibly overridden) CSS variable name. */\n variableName: VarNamer;\n /** A recipe or container-context class → its (possibly overridden) class name. */\n className(\n kind: \"recipe\" | \"container\",\n subsystem: string,\n group: string,\n variant: string,\n ): string;\n}\n\n/**\n * Bind the resolved {@link AdapterNaming} + optional {@link NamingOverrides} into an {@link AdapterNamer}.\n * Every emitted name is collision-checked on **both** the default and the override path: two distinct\n * addresses (token paths / rule-sets) that resolve to the same output name throw a path-labelled error,\n * so a silent merge — e.g. palettes `\"brand accent\"` and `\"brand-accent\"` both sanitizing to\n * `--dt-colors-brand-accent` — fails loud instead. The SAME address re-resolving to the same name is\n * fine (definitions + usages call repeatedly). With no overrides the namer returns the built-in name\n * verbatim (byte-identical); the bookkeeping is checked but never rewrites the name.\n * The container-context class keeps its own `<classToken>-cq-<name>` default, distinct from the recipe formula.\n */\nexport const createNamer = (naming: AdapterNaming, overrides?: NamingOverrides): AdapterNamer => {\n const varSeen = new Map<string, string>(); // output var name → source path\n const classSeen = new Map<string, string>(); // output class name → source address key\n const hasVarOverride = !!overrides?.variableName;\n const hasClassOverride = !!overrides?.className;\n\n const trackVar = (name: string, path: string): void => {\n const prev = varSeen.get(name);\n if (prev !== undefined && prev !== path) {\n throw new RefractError(\n \"REFRACT_E_NAMING\",\n hasVarOverride\n ? `naming override: variable name \"${name}\" is produced by both \"${prev}\" and \"${path}\" — ` +\n `variableName must map distinct token paths to distinct names`\n : `naming collision: token paths \"${prev}\" and \"${path}\" both produce the variable name ` +\n `\"${name}\" — segment sanitization collapses spaces / punctuation to \"-\", so rename one ` +\n `so their sanitized names differ`,\n );\n }\n varSeen.set(name, path);\n };\n\n const trackClass = (name: string, key: string): void => {\n const prev = classSeen.get(name);\n if (prev !== undefined && prev !== key) {\n throw new RefractError(\n \"REFRACT_E_NAMING\",\n hasClassOverride\n ? `naming override: class name \"${name}\" is produced by both \"${prev}\" and \"${key}\" — ` +\n `className must map distinct rule-sets to distinct names`\n : `naming collision: rule-sets \"${prev}\" and \"${key}\" both produce the class name \"${name}\" — ` +\n `segment sanitization collapses spaces / punctuation to \"-\", so rename one so they differ`,\n );\n }\n classSeen.set(name, key);\n };\n\n return {\n naming,\n variableName: (path) => {\n const def = varNameFromPath(naming.varToken, path);\n if (!overrides?.variableName) {\n trackVar(def, path);\n return def;\n }\n const raw = overrides.variableName(\n { path, segments: path.split(\".\") },\n { varToken: naming.varToken, name: def },\n );\n const name = sanitizeVarName(raw);\n trackVar(name, path);\n return name;\n },\n className: (kind, subsystem, group, variant) => {\n const def =\n kind === \"container\"\n ? `${naming.classToken}-cq-${sanitizeSegment(variant)}`\n : recipeClassName(naming, subsystem, group, variant);\n const key = `${kind}:${subsystem}.${group}.${variant}`;\n if (!overrides?.className) {\n trackClass(def, key);\n return def;\n }\n const raw = overrides.className(\n { kind, subsystem, group, variant },\n { classToken: naming.classToken, name: def },\n );\n const name = sanitizeSegment(raw);\n if (!name) {\n throw new RefractError(\n \"REFRACT_E_NAMING\",\n `naming override: className returned an empty/invalid name for ` +\n `\"${kind}:${subsystem}.${group}.${variant}\"`,\n );\n }\n trackClass(name, key);\n return name;\n },\n };\n};\n"],"names":["sanitizeSegment","segment","trim","replace","toLowerCase","resolveNaming","options","varToken","_a","prefix","classToken","_c","_b","classPrefix","varNameFromPath","path","split","map","filter","Boolean","join","recipeClassName","naming","subsystem","group","variant","createNamer","overrides","varSeen","Map","classSeen","hasVarOverride","variableName","hasClassOverride","className","trackVar","name","prev","get","undefined","RefractError","set","trackClass","key","def","body","sanitizeVarName","segments","kind","raw"],"mappings":"oDAcaA,EAAmBC,GAC9BA,EACGC,OACAC,QAAQ,OAAQ,KAChBA,QAAQ,kBAAmB,KAC3BA,QAAQ,MAAO,KACfA,QAAQ,MAAO,IACfA,QAAQ,MAAO,IACfC,cAWQC,EAAiBC,cAG5B,MAAO,CAAEC,SAFQP,EAAkC,QAAlBQ,EAAAF,EAAQG,cAAU,IAAAD,EAAAA,EAAA,OAAS,KAEzCE,WADAV,EAAqD,QAArCW,EAAuB,QAAvBC,EAAAN,EAAQO,mBAAe,IAAAD,EAAAA,EAAAN,EAAQG,cAAM,IAAAE,EAAAA,EAAI,OAAS,OAK1EG,EAAkB,CAACP,EAAkBQ,IAChD,KAAKR,KAAYQ,EAAKC,MAAM,KAAKC,IAAIjB,GAAiBkB,OAAOC,SAASC,KAAK,OAGhEC,EAAkB,CAC7BC,EACAC,EACAC,EACAC,IAEA,CAACH,EAAOZ,WAAYa,EAAWC,EAAOC,GAASR,IAAIjB,GAAiBkB,OAAOC,SAASC,KAAK,KAwE9EM,EAAc,CAACJ,EAAuBK,KACjD,MAAMC,EAAU,IAAIC,IACdC,EAAY,IAAID,IAChBE,KAAmBJ,aAAA,EAAAA,EAAWK,cAC9BC,KAAqBN,aAAA,EAAAA,EAAWO,WAEhCC,EAAW,CAACC,EAAcrB,KAC9B,MAAMsB,EAAOT,EAAQU,IAAIF,GACzB,QAAaG,IAATF,GAAsBA,IAAStB,EACjC,MAAM,IAAIyB,EACR,mBACAT,EACI,mCAAmCK,2BAA8BC,WAActB,oEAE/E,kCAAkCsB,WAActB,sCAC1CqB,kHAIdR,EAAQa,IAAIL,EAAMrB,IAGd2B,EAAa,CAACN,EAAcO,KAChC,MAAMN,EAAOP,EAAUQ,IAAIF,GAC3B,QAAaG,IAATF,GAAsBA,IAASM,EACjC,MAAM,IAAIH,EACR,mBACAP,EACI,gCAAgCG,2BAA8BC,WAAcM,+DAE5E,gCAAgCN,WAAcM,mCAAqCP,iGAI3FN,EAAUW,IAAIL,EAAMO,IAGtB,MAAO,CACLrB,SACAU,aAAejB,IACb,MAAM6B,EAAM9B,EAAgBQ,EAAOf,SAAUQ,GAC7C,KAAKY,aAAA,EAAAA,EAAWK,cAEd,OADAG,EAASS,EAAK7B,GACP6B,EAET,MAIMR,EA/EY,CAACA,IACvB,MAAMS,EAAO7C,EAAgBoC,EAAKjC,QAAQ,MAAO,KACjD,IAAK0C,EAAM,MAAM,IAAIL,EAAa,mBAAoB,kEAAkEJ,OACxH,MAAO,KAAKS,KA4EKC,CAJDnB,EAAUK,aACpB,CAAEjB,OAAMgC,SAAUhC,EAAKC,MAAM,MAC7B,CAAET,SAAUe,EAAOf,SAAU6B,KAAMQ,KAIrC,OADAT,EAASC,EAAMrB,GACRqB,GAETF,UAAW,CAACc,EAAMzB,EAAWC,EAAOC,KAClC,MAAMmB,EACK,cAATI,EACI,GAAG1B,EAAOZ,iBAAiBV,EAAgByB,KAC3CJ,EAAgBC,EAAQC,EAAWC,EAAOC,GAC1CkB,EAAM,GAAGK,KAAQzB,KAAaC,KAASC,IAC7C,KAAKE,aAAA,EAAAA,EAAWO,WAEd,OADAQ,EAAWE,EAAKD,GACTC,EAET,MAAMK,EAAMtB,EAAUO,UACpB,CAAEc,OAAMzB,YAAWC,QAAOC,WAC1B,CAAEf,WAAYY,EAAOZ,WAAY0B,KAAMQ,IAEnCR,EAAOpC,EAAgBiD,GAC7B,IAAKb,EACH,MAAM,IAAII,EACR,mBAEE,kEAAIQ,KAAQzB,KAAaC,KAASC,MAIxC,OADAiB,EAAWN,EAAMO,GACVP"}
@@ -0,0 +1,19 @@
1
+ import { type AuditResult, type WcagLevel } from "../subsystems/colors/audit";
2
+ export interface AuditCommandOptions {
3
+ readonly cwd?: string;
4
+ /** `--config` override — a path to the config file. */
5
+ readonly configPath?: string;
6
+ /** `--strict` — throw (non-zero exit) when any pairing fails. */
7
+ readonly strict?: boolean;
8
+ /** `--min-wcag` — pass bar (`"AA"` default). */
9
+ readonly minWcag?: WcagLevel;
10
+ /** `--large` — score against large-text thresholds. */
11
+ readonly largeText?: boolean;
12
+ }
13
+ export interface AuditCommandResult {
14
+ /** Absolute path the config was loaded from. */
15
+ readonly configPath: string;
16
+ readonly result: AuditResult;
17
+ }
18
+ /** Load the config, build the theme (adapter-free), and audit its colour pairings. */
19
+ export declare function runAudit(options?: AuditCommandOptions): Promise<AuditCommandResult>;
@@ -0,0 +1,23 @@
1
+ export interface BuildOptions {
2
+ readonly cwd?: string;
3
+ /** `--config` override — a path to the config file. */
4
+ readonly configPath?: string;
5
+ /** `--target` override — a target name, numeric index, or outDir to build in isolation. */
6
+ readonly target?: string;
7
+ /** `--out` override — replaces the selected target's outDir. */
8
+ readonly out?: string;
9
+ }
10
+ export interface BuildTargetSummary {
11
+ readonly name?: string;
12
+ readonly adapter: string;
13
+ /** Absolute outDir the target was written to. */
14
+ readonly outDir: string;
15
+ /** Absolute paths of every file written for this target. */
16
+ readonly files: string[];
17
+ }
18
+ export interface BuildResult {
19
+ readonly configPath: string;
20
+ readonly targets: BuildTargetSummary[];
21
+ }
22
+ /** Load the config and emit every (selected) target to disk. */
23
+ export declare function runBuild(options?: BuildOptions): Promise<BuildResult>;
@@ -0,0 +1,2 @@
1
+ /** Dispatch a parsed argv (without the node/script prefix). Returns a process exit code. */
2
+ export declare function main(argv: string[]): Promise<number>;
@@ -0,0 +1,58 @@
1
+ import type { ThemeAdapter, Emit } from "../core/ThemeAdapter";
2
+ import type { RawTheme } from "../core/rawTheme";
3
+ import type { MediaConfig } from "../core/media";
4
+ import type { UnitsConfig } from "../core/units";
5
+ import type { GuideConfig } from "./emitTheme";
6
+ /** One emit target: an adapter + where to write it, plus which shared vendored helpers it wants. */
7
+ export interface EmitTarget {
8
+ readonly adapter: ThemeAdapter;
9
+ readonly outDir: string;
10
+ readonly helpers?: readonly string[];
11
+ /** Optional label — lets `refract build --target <name>` select this target (else index/outDir). */
12
+ readonly name?: string;
13
+ /** Optional output-shape directive (§9): single / split / subsystem / components. Default = single. */
14
+ readonly emit?: Emit;
15
+ /**
16
+ * §C — emit a self-documenting `llms.txt` + `manifest.json` into this target's `outDir`, so a
17
+ * published/zipped theme carries its own AI consumption guide (real class names / token paths) for
18
+ * a downstream dev who has neither refract nor its skills. `true` uses defaults; an object tunes the
19
+ * file names or adds a `packageName` for a by-specifier import overlay. Off by default.
20
+ */
21
+ readonly guide?: boolean | GuideConfig;
22
+ }
23
+ /** The `theme.config` shape: the raw theme + one or more emit targets. */
24
+ export interface ThemeConfig {
25
+ readonly raw: RawTheme;
26
+ readonly targets: readonly EmitTarget[];
27
+ /**
28
+ * Media-query output config (§10.5) — `{ unit: "px" | "em" | "rem"; baseFontSize }`. Applies to
29
+ * both the viewport `@media` and container `@container` widths (breakpoints/container thresholds are
30
+ * authored as px numbers; `unit` controls the emitted unit). Defaults to px.
31
+ */
32
+ readonly media?: MediaConfig;
33
+ /**
34
+ * Declaration-value length units (§21) — a token-path role map (`units.default`, `units["<subsystem>"]`,
35
+ * `units["<subsystem>.<property>"]`), most-specific wins over the built-in seed. Resolved once, format-
36
+ * neutrally, so every target emits the same unit. The build-time twin of `createTheme`'s `units` option.
37
+ */
38
+ readonly units?: UnitsConfig;
39
+ /** Divisor when a deferred length resolves to `rem` (§21). Defaults to 16. */
40
+ readonly baseFontSize?: number;
41
+ }
42
+ /** Identity fn — types the config authored in `theme.config.(ts|js|mjs)`. */
43
+ export declare const defineConfig: (config: ThemeConfig) => ThemeConfig;
44
+ /** Find `theme.config.{ts,mjs,js}` in `fromDir`, honoring the ts→mjs→js resolution order. */
45
+ export declare const findConfigFile: (fromDir?: string) => string | undefined;
46
+ export interface LoadedConfig {
47
+ readonly config: ThemeConfig;
48
+ /** Absolute path the config was loaded from. */
49
+ readonly path: string;
50
+ }
51
+ /**
52
+ * Resolve + load a `theme.config`. `configPath` (a CLI `--config` override) wins; otherwise the
53
+ * ts→mjs→js search in `cwd`. Returns the `defineConfig(...)` object (default or named `config` export).
54
+ */
55
+ export declare function loadConfig(options?: {
56
+ cwd?: string;
57
+ configPath?: string;
58
+ }): Promise<LoadedConfig>;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * `diffThemes` — the blast radius of a candidate theme edit, computed against a base (§5 agent-native).
3
+ *
4
+ * refract stores every synthesized rung/variant as a `{ ref, fn, arg }` graph, not a frozen literal, so
5
+ * a candidate theme can be *built and compared* before it's applied — the claim no token file can make:
6
+ * see what a change does before you make it. This is the shared engine behind `refract diff <candidate>`
7
+ * (a human CLI + a CI gate) and the MCP `diffTheme` tool (an agent's plan-then-apply guardrail).
8
+ *
9
+ * Three axes, each adapter-independent except `classes`:
10
+ * - `tokens` — which resolved token values moved (added / removed / changed).
11
+ * - `classes` — which emitted recipe classes changed CSS (only when the themes emit classes, e.g. the
12
+ * CSS adapter — read via the duck-typed `renderRecipe` / `getClass`).
13
+ * - `contrast` — which WCAG pairings crossed a pass/level threshold (via {@link audit}).
14
+ */
15
+ import type { Theme } from "../core";
16
+ export type ChangeKind = "added" | "removed" | "changed";
17
+ export interface TokenChange {
18
+ path: string;
19
+ before: string | null;
20
+ after: string | null;
21
+ kind: ChangeKind;
22
+ }
23
+ export interface ClassChange {
24
+ /** The emitted class name (or the `subsystem.group.variant` id when no adapter names it). */
25
+ name: string;
26
+ kind: ChangeKind;
27
+ }
28
+ export interface ContrastScore {
29
+ ratio?: number;
30
+ level?: string;
31
+ pass?: boolean;
32
+ }
33
+ export interface ContrastChange {
34
+ label: string;
35
+ before: ContrastScore | null;
36
+ after: ContrastScore | null;
37
+ /** True when the pass verdict or the WCAG level changed — the threshold-crossing an agent cares about. */
38
+ crossed: boolean;
39
+ }
40
+ export interface ThemeDiff {
41
+ tokens: TokenChange[];
42
+ classes: ClassChange[];
43
+ contrast: ContrastChange[];
44
+ summary: {
45
+ tokensChanged: number;
46
+ classesChanged: number;
47
+ /** Pairings whose pass verdict or level crossed a threshold. */
48
+ pairingsCrossed: number;
49
+ };
50
+ }
51
+ /**
52
+ * Diff a candidate theme against a base. Both should be built with the same adapter; pass a
53
+ * class-emitting adapter (e.g. CSS) on both sides to populate `classes`, or any adapter for the
54
+ * adapter-independent `tokens` / `contrast` axes.
55
+ */
56
+ export declare function diffThemes(base: Theme, candidate: Theme): ThemeDiff;
@@ -0,0 +1,29 @@
1
+ import { type ThemeDiff } from "./diff";
2
+ export interface DiffCommandOptions {
3
+ cwd?: string;
4
+ configPath?: string;
5
+ /** Path to the candidate theme (`.ts` / `.mjs` / `.js` default-export, or `.json`). */
6
+ candidatePath: string;
7
+ /** CI gate: fail if more than this many classes changed. */
8
+ maxClassChanges?: number;
9
+ /** CI gate: fail if more than this many tokens changed. */
10
+ maxTokenChanges?: number;
11
+ /** CI gate: fail if any pairing's `after` level drops below this WCAG bar. */
12
+ failBelow?: string;
13
+ }
14
+ export interface TargetStatus {
15
+ name: string;
16
+ ok: boolean;
17
+ errors: string[];
18
+ }
19
+ export interface DiffCommandResult {
20
+ configPath: string;
21
+ candidatePath: string;
22
+ diff: ThemeDiff;
23
+ /** Per configured target: does the candidate still build? */
24
+ targets: TargetStatus[];
25
+ /** CI-gate verdict: false when any threshold was breached (or a target stopped building). */
26
+ ok: boolean;
27
+ violations: string[];
28
+ }
29
+ export declare function runDiff(options: DiffCommandOptions): Promise<DiffCommandResult>;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * `resolveEmitPlan` — normalize the authored `Emit` directive into a discriminated `NormalizedEmit`
3
+ * with every default filled (§9, 9a). This is the build layer's light normalization; the *vocabulary*
4
+ * (`Emit`/`NormalizedEmit`) lives in core (`src/core/ThemeAdapter.ts`), and each adapter decides which
5
+ * modes it actually honors — `resolveEmitPlan` never renders anything.
6
+ *
7
+ * Discriminator inference (only `single`/`split` may omit `type`):
8
+ * - `undefined` / `{}` / `{ file }` → `single` (`file` renames the one file; default theme.css)
9
+ * - the `variables` key present → `split` (that key is what tips `{ file, variables }` in)
10
+ * - `subsystem` / `components` → require an explicit `type` (or the string shorthand)
11
+ *
12
+ * Per-type filename/name defaults:
13
+ * - single → `theme.css`
14
+ * - split → `styles.css` + `variables.css`
15
+ * - subsystem → `<sub>.css` / `<sub>.variables.css`
16
+ * - components→ `${group}-${variant}.css`, `inline: true`, `variables` on (a filename)
17
+ */
18
+ import type { Emit, NormalizedEmit } from "../core/ThemeAdapter";
19
+ /** Normalize an authored {@link Emit} directive into a fully-defaulted {@link NormalizedEmit}. */
20
+ export declare function resolveEmitPlan(emit: Emit): NormalizedEmit;
@@ -0,0 +1,39 @@
1
+ import type { ThemeAdapter, Emit } from "../core/ThemeAdapter";
2
+ import type { RawTheme } from "../core/rawTheme";
3
+ import type { MediaConfig } from "../core/media";
4
+ import type { UnitsConfig } from "../core/units";
5
+ /** Opt-in self-documenting output config (§C). `true` uses defaults; the object tunes names/overlay. */
6
+ export type GuideConfig = {
7
+ /** Published package specifier — adds a by-specifier import overlay to the guide (else relative-only). */
8
+ readonly packageName?: string;
9
+ /** Narrative guide filename (default `"llms.txt"`). */
10
+ readonly llmsFile?: string;
11
+ /** Machine index filename (default `"manifest.json"`); `false` suppresses it. */
12
+ readonly manifestFile?: string | false;
13
+ };
14
+ export interface EmitThemeOptions {
15
+ /** The raw theme config (same shape `createTheme` consumes). */
16
+ readonly raw: RawTheme;
17
+ /** The fully-constructed adapter object (`createCssAdapter(...)`, an SC adapter, …). */
18
+ readonly adapter: ThemeAdapter;
19
+ /** Directory to write the emitted files into (created recursively). */
20
+ readonly outDir: string;
21
+ /** Shared vendorable helper ids to materialize from `VENDOR_HELPERS` (e.g. `["color-math"]`). */
22
+ readonly helpers?: readonly string[];
23
+ /** Output-shape directive (§9); normalized to a plan and passed to the adapter's `emit(plan)`. */
24
+ readonly emit?: Emit;
25
+ /** Media unit config (§10.5) — threaded into `createTheme` + the emit rebind so em/rem reaches disk. */
26
+ readonly media?: MediaConfig;
27
+ /** Declaration-value length units (§21) — threaded into `createTheme` so built output honors the role map. */
28
+ readonly units?: UnitsConfig;
29
+ /** Divisor when a deferred length resolves to `rem` (§21). Defaults to 16. */
30
+ readonly baseFontSize?: number;
31
+ /** §C — emit a self-documenting `llms.txt` + `manifest.json` into `outDir`. Off by default. */
32
+ readonly guide?: boolean | GuideConfig;
33
+ }
34
+ export interface EmitThemeResult {
35
+ readonly outDir: string;
36
+ /** Absolute paths of every file written, in write order. */
37
+ readonly files: string[];
38
+ }
39
+ export declare function emitTheme(options: EmitThemeOptions): Promise<EmitThemeResult>;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Self-documenting theme output (Node-only) — render an `llms.txt` consumption guide + a
3
+ * `manifest.json` index from an adapter's {@link UsageDescriptor} and a DTCG token export.
4
+ *
5
+ * The point: a theme built by refract is often shipped onward as a published package, a zip / CI
6
+ * artifact, or a vendored folder to developers who have **neither refract nor its skills** (and may
7
+ * not know refract exists). These two files travel *inside* `outDir`, so they accompany any
8
+ * distribution form, and they name the theme's REAL class names / export ids / token paths — a
9
+ * downstream agent consumes the theme from the folder alone, never guessing an identifier.
10
+ *
11
+ * Distribution-agnostic by construction: references are **relative** by default (`./theme.css`); the
12
+ * `@scope/name` import form is added only as an overlay when a package name is configured (a zip has
13
+ * no package specifier, so it must not be assumed).
14
+ */
15
+ import type { UsageDescriptor } from "../core/ThemeAdapter";
16
+ export interface GuideOptions {
17
+ /** The static file names emitted for this target (relative), so the guide points at real artifacts. */
18
+ readonly files: readonly string[];
19
+ /** The published package specifier, if any — adds an import-by-specifier overlay to the prose. */
20
+ readonly packageName?: string;
21
+ /** Output name for the narrative guide (default `"llms.txt"`). */
22
+ readonly llmsFile?: string;
23
+ /** Output name for the machine index (default `"manifest.json"`); `false` suppresses it. */
24
+ readonly manifestFile?: string | false;
25
+ }
26
+ export interface GuideOutput {
27
+ /** filename → contents, ready for the build layer to write into `outDir`. */
28
+ readonly files: Record<string, string>;
29
+ }
30
+ /**
31
+ * Build the guide artifacts. `tokens` is a DTCG document (from `toDTCG`) embedded verbatim into the
32
+ * manifest so the machine index carries every token path + value beside the recipe identities.
33
+ */
34
+ export declare function buildGuide(descriptor: UsageDescriptor, tokens: unknown, options: GuideOptions): GuideOutput;
@@ -0,0 +1,42 @@
1
+ export interface ImportOptions {
2
+ /** Project dir to scaffold into (default `process.cwd()`). */
3
+ readonly cwd?: string;
4
+ /** Path to the DTCG `tokens.json` to import (relative to cwd or absolute). Required. */
5
+ readonly input: string;
6
+ /** `--out` — the raw-theme file to write (default `theme.raw.ts`, resolved against cwd). */
7
+ readonly out?: string;
8
+ /** `--raw-only` — write only `theme.raw.ts`, skip the companion `theme.config.ts` (default false). */
9
+ readonly rawOnly?: boolean;
10
+ /** `--force` — overwrite existing files instead of refusing (default false). */
11
+ readonly force?: boolean;
12
+ /** `--breakpoint-group` — DTCG group whose dimension tokens seed the breakpoints. */
13
+ readonly breakpointGroup?: string;
14
+ /** `--breakpoints` — explicit `{ name: px }` fallback when the doc carries no breakpoint group. */
15
+ readonly breakpoints?: Record<string, number>;
16
+ /** Package name the generated files import from (default: this package's own `name`). */
17
+ readonly packageName?: string;
18
+ }
19
+ export interface ImportResult {
20
+ /** Absolute path of the DTCG document read. */
21
+ readonly inputFile: string;
22
+ /** Absolute path of the written `theme.raw.ts`. */
23
+ readonly rawFile: string;
24
+ /** Absolute path of the written `theme.config.ts`, or `undefined` when `--raw-only`. */
25
+ readonly configFile?: string;
26
+ /** Top-level raw keys produced (e.g. `["breakpoints", "colors", "typography"]`). */
27
+ readonly sections: readonly string[];
28
+ /** Per-subsystem property count seeded from the document (excludes `breakpoints`). */
29
+ readonly counts: Readonly<Record<string, number>>;
30
+ }
31
+ /** Parse a `--breakpoints "sm:576,md:768"` flag into `{ sm: 576, md: 768 }`. Ignores malformed pairs. */
32
+ export declare function parseBreakpointsFlag(spec: string): Record<string, number>;
33
+ /** The generated `theme.raw.ts` body — a typed `RawTheme` the user then owns and extends. */
34
+ export declare function scaffoldRaw(packageName: string, raw: unknown, sourceLabel: string): string;
35
+ /** The generated companion `theme.config.ts` — a runnable build config importing the seeded raw. */
36
+ export declare function scaffoldImportConfig(packageName: string, rawImportSpec: string): string;
37
+ /**
38
+ * Read the DTCG document at `input`, convert it via `fromDTCG`, and write a `theme.raw.ts` (plus, unless
39
+ * `rawOnly`, a companion `theme.config.ts`) into `cwd`. Returns a summary of what was seeded. Throws on a
40
+ * missing/unparseable input or when an output file exists and `force` is not set (never clobbers).
41
+ */
42
+ export declare function runImport(options: ImportOptions): ImportResult;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Build-time layer barrel (Node-only) — `emitTheme` + config plumbing + the vendor registry.
3
+ *
4
+ * Deliberately NOT re-exported from the runtime `.` barrel (`src/index.ts`): it imports `node:fs`
5
+ * + `typescript` and belongs to the build/CLI surface (surfaced via a `./build` subpath + `bin` in
6
+ * Step 10e). Nothing here is on the runtime graph.
7
+ */
8
+ export * from "./vendor";
9
+ export * from "./paths";
10
+ export * from "./guide";
11
+ export * from "./emitTheme";
12
+ export * from "./emit";
13
+ export * from "./config";
14
+ export * from "./init";
15
+ export * from "./importCommand";
16
+ export * from "./buildCommand";
17
+ export * from "./tokensCommand";
18
+ export * from "./auditCommand";
19
+ export * from "./diff";
20
+ export * from "./diffCommand";
21
+ export * from "./skillsCommand";
22
+ /** The `refract` bin's `main(argv)` dispatch — exposed so the CLI is testable without spawning a process
23
+ * (the module's entry-guard means importing it here never triggers a run). */
24
+ export { main } from "./cli";
25
+ /**
26
+ * Re-export the authoring types (§8c) so a config author gets `defineConfig` + `RawTheme` from ONE
27
+ * `/build` import — `import { defineConfig, type RawTheme } from "…/build"` — to type a separate
28
+ * `theme.raw.ts` the graph loader now compiles (§8b). Type-only: no runtime edge, boundary-safe.
29
+ */
30
+ export type { RawTheme } from "../core";
31
+ /** The output-shape vocabulary (§9) — config authors use it in `defineConfig` target `emit` fields. */
32
+ export type { Emit } from "../core";
33
+ export type { ColorsRaw, TypographyRaw, EffectsRaw, LayoutRaw, ComponentsRaw, } from "../subsystems";
@@ -0,0 +1,32 @@
1
+ export type ConfigVariant = "ts" | "js" | "mjs";
2
+ /**
3
+ * The sibling package the CSS adapter ships from post monorepo split. `defineConfig`/`RawTheme` still
4
+ * come from core (`${packageName}/build`); only the adapter itself moved to its own package.
5
+ */
6
+ export declare const CSS_ADAPTER_PACKAGE = "@theme-registry/refract-css";
7
+ export interface InitOptions {
8
+ /** Project dir to scaffold into (default `process.cwd()`). */
9
+ readonly cwd?: string;
10
+ /** Which config flavor to write (default `"ts"`). */
11
+ readonly variant?: ConfigVariant;
12
+ /** Overwrite an existing config instead of refusing (default `false`). */
13
+ readonly force?: boolean;
14
+ /** Package name to import from in the scaffold (default: this package's own `name`). */
15
+ readonly packageName?: string;
16
+ }
17
+ export interface InitResult {
18
+ /** Absolute path of the written config. */
19
+ readonly path: string;
20
+ readonly variant: ConfigVariant;
21
+ /** The package name the scaffold imports from. */
22
+ readonly packageName: string;
23
+ }
24
+ /** Read this package's own `name` (so the scaffold imports the currently-installed package name). */
25
+ export declare function readOwnPackageName(): string;
26
+ /** The scaffolded config body — one shared ESM template across ts/js/mjs. */
27
+ export declare function scaffoldConfig(packageName: string): string;
28
+ /**
29
+ * Scaffold `theme.config.<variant>` into `cwd`. Throws if the file exists and `force` is not set
30
+ * (never silently clobbers a user's config).
31
+ */
32
+ export declare function runInit(options?: InitOptions): InitResult;