@theme-registry/refract-json 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Petyo Stoyanov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ "use strict";var e=require("@theme-registry/refract");const t=e=>e.endsWith(".json")?e:`${e.replace(/\.[^./]+$/,"")}.json`;exports.createJsonAdapter=(s={})=>{var r,n;const o=null!==(r=s.refs)&&void 0!==r?r:"both",i=null!==(n=s.indent)&&void 0!==n?n:2,a={name:"json",version:1,bind(s,r){const{media:n,resolve:a}=r,c=e.buildTokenMap(s),l=e=>JSON.stringify(e,null,i),u=e=>{try{return a(e)}catch{return}},d=(e,t,s)=>{const r={},n=void 0!==e.ref;return"value"!==s&&n&&(r.ref=e.ref,void 0!==e.fn&&(r.fn=e.fn),void 0!==e.arg&&(r.arg=e.arg)),"value"!==s&&void 0!==e.wrap&&(r.wrap=e.wrap),void 0!==e.external&&(r.external=e.external),"path"===s&&n||void 0===t||(r.value=t),void 0!==e.struct&&(r.struct=e.struct),r},f=(e,t,s)=>{var r;return d(t,null!==(r=u(e))&&void 0!==r?r:t.value,s)},v=(e,t)=>{var s;const r=void 0!==e.ref&&null!==(s=u(e.ref))&&void 0!==s?s:e.value,n=d(e,r,t);if(void 0===n.ref&&void 0===n.value&&void 0===n.struct&&void 0!==e.ref){const t=c[e.ref];void 0!==(null==t?void 0:t.struct)&&(n.struct=t.struct)}return n},b=(e,t)=>{const s={};for(const[r,n]of Object.entries(e))s[r]=v(n,t);return s},k=(e,t)=>{void 0!==e.state&&(t.state=e.state),void 0!==e.breakpoint&&(t.breakpoint=e.breakpoint),void 0!==e.query&&(t.query=e.query),void 0!==e.orientation&&(t.orientation=e.orientation),void 0!==e.container&&(t.container=e.container),void 0!==e.size&&(t.size=e.size),void 0!==e.variant&&(t.variant=e.variant),void 0!==e.target&&(t.target=e.target)},p=(e,t)=>{const s=[];for(const r of e){const e={};k(r,e),e.declarations=r.declarations?b(r.declarations,t):{},s.push(e)}return s},y=(e,t)=>{const s=((e,t,s)=>{const r={};return e.kind&&(r.kind=e.kind),void 0!==e.selector&&(r.selector=e.selector),e.references&&e.references.length&&(r.references=e.references),r.declarations=t,r.overrides=s,r})({kind:e.kind,selector:e.selector,references:e.references?[...e.references]:void 0},b(e.declarations,t),p(e.overrides,t));return e.variants&&Object.keys(e.variants).length&&(s.variants=Object.fromEntries(Object.entries(e.variants).map(([e,s])=>[e,{declarations:b(s.declarations,t),overrides:p(s.overrides,t)}]))),s},m=(e,t)=>({steps:e.steps.map(e=>({stop:e.stop,declarations:b(e.declarations,t)}))}),h=(e,t)=>{const s={kind:"recipe",declarations:b(e.base,t),overrides:[]};for(const[r,n]of Object.entries(e.states))s.overrides.push({state:r,declarations:b(n,t)});for(const r of e.responsive){const e={};k(r,e),e.declarations=b(r.declarations,t),s.overrides.push(e)}return s},j=e=>{const t=void 0!==e?`${e}.`:"",s={};for(const[r,n]of Object.entries(c))(void 0===e||r.startsWith(t))&&(s[r]=f(r,n,o));return s},g=e=>{var t;const r={};for(const[n,i]of Object.entries(s.subsystems))if(void 0===e||n===e)for(const[e,s]of Object.entries(null!==(t=i.ruleSets)&&void 0!==t?t:{}))for(const[t,i]of Object.entries(s))r[`${n}.${e}.${t}`]=y(i,o);return r},O=e=>{var t;const r={};for(const[n,i]of Object.entries(s.subsystems))if(void 0===e||n===e)for(const[e,s]of Object.entries(null!==(t=i.keyframes)&&void 0!==t?t:{}))r[`${n}.${e}`]=m(s,o);return r},S=()=>{if(!s.containers||!Object.keys(s.containers).length)return;const e={};for(const[t,r]of Object.entries(s.containers))e[t]={type:r.type,sizes:{...r.sizes}};return e},$=()=>{const e={breakpoints:{...s.breakpoints}},t=S();t&&(e.containers=t);const r=j();Object.keys(r).length&&(e.tokens=r);const n=g();Object.keys(n).length&&(e.ruleSets=n);const o=O();return Object.keys(o).length&&(e.keyframes=o),e},w=e=>Object.keys(e).length>0;return{recipeName:(e,t,s)=>`${e}.${t}.${s}`,describeUsage(){var e;const t=[];for(const[r,n]of Object.entries(s.subsystems))for(const[s,o]of Object.entries(null!==(e=n.ruleSets)&&void 0!==e?e:{}))for(const e of Object.keys(o))t.push({subsystem:r,group:s,variant:e,name:`${r}.${s}.${e}`});return{format:"json",summary:["This theme is emitted as a JSON document: a `tokens` bucket (the theme's values) plus a `ruleSets` map (the recipes), each keyed by `subsystem.group.variant`.",'Load it in any language or tool: `import theme from "./theme.json"` (or `require`). It carries no framework binding — read the token values and recipe declarations directly.',"Each recipe below is addressed by its dotted key under `ruleSets`; token paths follow the same `subsystem.group.variant` convention."],recipes:t}},renderRecipe(e,t,r){var n,i,a;const c=null===(a=null===(i=null===(n=s.subsystems[e])||void 0===n?void 0:n.ruleSets)||void 0===i?void 0:i[t])||void 0===a?void 0:a[r];return c?{ruleSets:{[`${e}.${t}.${r}`]:y(c,o)}}:{}},renderVariables(e){const t=j(e);return Object.keys(t).length?{tokens:t}:{}},join:e=>{const t={};for(const s of e)s.breakpoints&&(t.breakpoints={...t.breakpoints,...s.breakpoints}),s.containers&&(t.containers={...t.containers,...s.containers}),s.tokens&&(t.tokens={...t.tokens,...s.tokens}),s.ruleSets&&(t.ruleSets={...t.ruleSets,...s.ruleSets}),s.keyframes&&(t.keyframes={...t.keyframes,...s.keyframes});return t},renderAllVariables(){const e={breakpoints:{...s.breakpoints}},t=S();t&&(e.containers=t);const r=j();return Object.keys(r).length&&(e.tokens=r),e},renderAllRecipes(){const e={},t=g();Object.keys(t).length&&(e.ruleSets=t);const s=O();return Object.keys(s).length&&(e.keyframes=s),e},renderAll:$,extend:()=>({media:n,get json(){return $()},get jsonString(){return l($())}}),emit(r){var n,o,i,a;const u=null!==(n=null==r?void 0:r.type)&&void 0!==n?n:"single";if("single"===u){const e="single"===(null==r?void 0:r.type)?r.file:"theme.json";return{files:{[t(e)]:l($())}}}if("split"===(null==r?void 0:r.type)){const e=$(),s={};e.ruleSets&&(s.ruleSets=e.ruleSets),e.keyframes&&(s.keyframes=e.keyframes);const n={};return e.breakpoints&&(n.breakpoints=e.breakpoints),e.containers&&(n.containers=e.containers),e.tokens&&(n.tokens=e.tokens),{files:{[t(r.file)]:l(s),[t(r.variables)]:l(n)}}}if("subsystem"===(null==r?void 0:r.type)){const e={};for(const n of Object.keys(s.subsystems)){const s=j(n);Object.keys(s).length&&(e[t(r.filename(n,"variables"))]=l({tokens:s}));const o={},i=g(n);Object.keys(i).length&&(o.ruleSets=i);const a=O(n);Object.keys(a).length&&(o.keyframes=a),w(o)&&(e[t(r.filename(n,"styles"))]=l(o))}return{files:e}}if("components"===(null==r?void 0:r.type)){const n=null!==(i=null===(o=s.subsystems.components)||void 0===o?void 0:o.ruleSets)&&void 0!==i?i:{},u=r.inline?"value":"both",d={},v=[],b=new Set;for(const[o,i]of Object.entries(n))for(const n of Object.keys(i)){const i=e.mergeComponentRuleSet(s,o,n),c=t(r.filename({group:o,variant:n}));if((null!==(a=d[c])&&void 0!==a?a:d[c]={})[`components.${o}.${n}`]=h(i,u),!r.inline)for(const e of i.referencedPaths)b.has(e)||(b.add(e),v.push(e))}const k={};for(const[e,t]of Object.entries(d))k[e]=l({ruleSets:t});if(!r.inline&&!1!==r.variables){const e={};for(const t of v){const s=c[t];s&&(e[t]=f(t,s,"both"))}Object.keys(e).length&&(k[t(r.variables)]=l({tokens:e}))}return{files:k}}throw new Error(`json adapter: emit mode '${u}' not yet implemented`)}}}};return e.defineAdapter(a)};
2
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * The JSON adapter — lowers the format-neutral {@link ThemeModel} to structured JSON.\n *\n * The second shipping adapter, and the proof that \"one Model, many formats\" is real: where the\n * CSS adapter's output unit is `string`, this adapter's is a {@link JsonDoc} object and `join`\n * is a bucket merge — the same four primitives + `defineAdapter` aggregators, a different `TUnit`.\n *\n * What it adds over the adapter-free `./dtcg` export (which is tokens-only): it lowers the FULL\n * Model — not just tokens, but rule-sets/recipes, states, responsive/container overrides,\n * composition-by-reference, and keyframes — keeping each `ref` as data alongside its resolved\n * value (exactly what CSS collapses into opaque `var(--…)` strings). That is recipes-as-data,\n * and it doubles as the Model + build-time emit path.\n *\n * Worked reference: `src/adapters/css/`. Core stays format-agnostic; all addressing, the doc IR,\n * and value resolution live here.\n */\nimport type { Literal, Ref, RuleSet, ThemeModel } from \"@theme-registry/refract\";\nimport { buildTokenMap, mergeComponentRuleSet } from \"@theme-registry/refract\";\nimport type { MergedRuleSet } from \"@theme-registry/refract\";\nimport type { AdapterSpec, RenderContext, ThemeAdapter, UsageDescriptor, UsageRecipe } from \"@theme-registry/refract\";\nimport { defineAdapter } from \"@theme-registry/refract\";\nimport type {\n JsonAdapterOptions,\n JsonDoc,\n JsonKeyframe,\n JsonLeaf,\n JsonOverride,\n JsonRuleSet,\n RefsMode,\n} from \"./types\";\n\nexport type {\n JsonAdapterOptions,\n JsonContainer,\n JsonDoc,\n JsonKeyframe,\n JsonKeyframeStep,\n JsonLeaf,\n JsonOverride,\n JsonRuleSet,\n RefsMode,\n} from \"./types\";\n\n/** The JSON adapter's output unit — a document fragment (see {@link JsonDoc}). */\nexport type JsonUnit = JsonDoc;\n\n/** Normalize an emitted filename's extension to `.json` (plan defaults are CSS-centric: `theme.css`,\n * `variables.css`, …). Any existing extension is swapped; a bare name gains `.json`. */\nconst jsonName = (name: string): string =>\n name.endsWith(\".json\") ? name : `${name.replace(/\\.[^./]+$/, \"\")}.json`;\n\nexport const createJsonAdapter = (options: JsonAdapterOptions = {}): ThemeAdapter<JsonUnit> => {\n const refsMode: RefsMode = options.refs ?? \"both\";\n const indent = options.indent ?? 2;\n\n const spec: AdapterSpec<JsonUnit> = {\n name: \"json\",\n version: 1,\n // No `allowedStates`: JSON renders any state name as a data key — it owns no selector knowledge\n // (contrast the CSS adapter's CSS_KNOWN_STATES). Core then does no state validation for this adapter.\n bind(model: ThemeModel, ctx: RenderContext) {\n const { media, resolve } = ctx;\n // The flat `path -> Ref` token map (base + variants + extras), shared by the tokens bucket,\n // renderVariables, and the components tree-shake — the same map that backs `theme.tokens`.\n const tokenMap = buildTokenMap(model);\n\n const stringify = (doc: JsonDoc): string => JSON.stringify(doc, null, indent);\n\n /** Resolve a token path to its literal, swallowing a resolver throw (defensive — a well-formed\n * Model resolves everything; falls back to the Ref's cached `value`). */\n const safeResolve = (path: string): Literal | undefined => {\n try {\n return resolve(path);\n } catch {\n return undefined;\n }\n };\n\n /** Build a leaf from a `Ref` + its already-resolved literal, honoring the ref mode. */\n const buildLeaf = (ref: Ref, value: Literal | undefined, mode: RefsMode): JsonLeaf => {\n const leaf: JsonLeaf = {};\n const hasRef = ref.ref !== undefined;\n if (mode !== \"value\" && hasRef) {\n leaf.ref = ref.ref;\n if (ref.fn !== undefined) leaf.fn = ref.fn;\n if (ref.arg !== undefined) leaf.arg = ref.arg;\n }\n if (mode !== \"value\" && ref.wrap !== undefined) leaf.wrap = ref.wrap;\n if (ref.external !== undefined) leaf.external = ref.external; // §W6b — parent-var passthrough\n // `value` in both/value modes; in path mode only for a literal (no ref to stand in for it).\n if ((mode !== \"path\" || !hasRef) && value !== undefined) leaf.value = value;\n // §15: a structured (shadow/transition) value carries as data — the format-neutral shape a\n // future RN adapter lowers; its per-layer `color` stays a `colors.*` ref for the consumer.\n if (ref.struct !== undefined) leaf.struct = ref.struct;\n return leaf;\n };\n\n /** A token leaf — resolved by the token's OWN address (its `Ref.ref`, if any, is a derivation source). */\n const tokenLeaf = (path: string, ref: Ref, mode: RefsMode): JsonLeaf =>\n buildLeaf(ref, safeResolve(path) ?? ref.value, mode);\n\n /** A declaration leaf — resolved by the path its `Ref.ref` points at (literal ⇒ its `value`).\n * §15: when the ref points at a STRUCTURED (shadow/transition) token — which has no single\n * literal to bake — the leaf carries that token's `struct` (its per-layer `color` stays a\n * `colors.*` ref for the consumer), so an inline declaration isn't left value-less. */\n const declLeaf = (ref: Ref, mode: RefsMode): JsonLeaf => {\n const value = ref.ref !== undefined ? safeResolve(ref.ref) ?? ref.value : ref.value;\n const leaf = buildLeaf(ref, value, mode);\n // Only when the `ref` was baked away (inline `value` mode) and no literal resulted — otherwise\n // the retained `ref` already leads the consumer to the token that carries the struct.\n if (leaf.ref === undefined && leaf.value === undefined && leaf.struct === undefined && ref.ref !== undefined) {\n const target = tokenMap[ref.ref];\n if (target?.struct !== undefined) leaf.struct = target.struct;\n }\n return leaf;\n };\n\n const mapDecls = (decls: Record<string, Ref>, mode: RefsMode): Record<string, JsonLeaf> => {\n const out: Record<string, JsonLeaf> = {};\n for (const [prop, ref] of Object.entries(decls)) out[prop] = declLeaf(ref, mode);\n return out;\n };\n\n /** Copy the present condition axes off a Model override/entry onto a JSON override. */\n const copyCondition = (\n src: {\n state?: string;\n breakpoint?: string;\n query?: JsonOverride[\"query\"];\n orientation?: JsonOverride[\"orientation\"];\n container?: string;\n size?: string;\n variant?: string;\n target?: string;\n },\n dst: JsonOverride,\n ): void => {\n if (src.state !== undefined) dst.state = src.state;\n if (src.breakpoint !== undefined) dst.breakpoint = src.breakpoint;\n if (src.query !== undefined) dst.query = src.query;\n if (src.orientation !== undefined) dst.orientation = src.orientation;\n if (src.container !== undefined) dst.container = src.container;\n if (src.size !== undefined) dst.size = src.size;\n if (src.variant !== undefined) dst.variant = src.variant;\n if (src.target !== undefined) dst.target = src.target;\n };\n\n // Assemble a rule-set with a readable key order: kind / selector / references first, then\n // declarations / overrides (independent of the Model's property insertion order).\n const assembleRuleSet = (\n head: Pick<JsonRuleSet, \"kind\" | \"selector\" | \"references\">,\n declarations: Record<string, JsonLeaf>,\n overrides: JsonOverride[],\n ): JsonRuleSet => {\n const out = {} as JsonRuleSet;\n if (head.kind) out.kind = head.kind;\n if (head.selector !== undefined) out.selector = head.selector;\n if (head.references && head.references.length) out.references = head.references;\n out.declarations = declarations;\n out.overrides = overrides;\n return out;\n };\n\n const overridesToJson = (list: RuleSet[\"overrides\"], mode: RefsMode): JsonOverride[] => {\n const overrides: JsonOverride[] = [];\n for (const ov of list) {\n const jo = {} as JsonOverride; // condition axes first, then declarations (readability)\n copyCondition(ov, jo);\n jo.declarations = ov.declarations ? mapDecls(ov.declarations, mode) : {};\n overrides.push(jo);\n }\n return overrides;\n };\n\n const ruleSetToJson = (rs: RuleSet, mode: RefsMode): JsonRuleSet => {\n const out = assembleRuleSet(\n { kind: rs.kind, selector: rs.selector, references: rs.references ? [...rs.references] : undefined },\n mapDecls(rs.declarations, mode),\n overridesToJson(rs.overrides, mode),\n );\n // §9: globals element variants (delta-only modifiers) survive as data.\n if (rs.variants && Object.keys(rs.variants).length) {\n out.variants = Object.fromEntries(\n Object.entries(rs.variants).map(([name, v]) => [\n name,\n { declarations: mapDecls(v.declarations, mode), overrides: overridesToJson(v.overrides, mode) },\n ]),\n );\n }\n return out;\n };\n\n const keyframeToJson = (kf: { steps: { stop: string; declarations: Record<string, Ref> }[] }, mode: RefsMode): JsonKeyframe => ({\n steps: kf.steps.map(s => ({ stop: s.stop, declarations: mapDecls(s.declarations, mode) })),\n });\n\n /** A merged component variant (`mergeComponentRuleSet`) → one self-contained JSON rule-set. */\n const mergedToJson = (merged: MergedRuleSet, mode: RefsMode): JsonRuleSet => {\n const out: JsonRuleSet = { kind: \"recipe\", declarations: mapDecls(merged.base, mode), overrides: [] };\n for (const [state, decls] of Object.entries(merged.states)) {\n out.overrides.push({ state, declarations: mapDecls(decls, mode) });\n }\n for (const entry of merged.responsive) {\n const jo = {} as JsonOverride;\n copyCondition(entry, jo);\n jo.declarations = mapDecls(entry.declarations, mode);\n out.overrides.push(jo);\n }\n return out;\n };\n\n // ── Bucket builders (each a flat address-keyed map; every full-doc consumer composes these) ──\n const buildTokensBucket = (subsystem?: string): Record<string, JsonLeaf> => {\n const prefix = subsystem !== undefined ? `${subsystem}.` : \"\";\n const tokens: Record<string, JsonLeaf> = {};\n for (const [path, ref] of Object.entries(tokenMap)) {\n if (subsystem !== undefined && !path.startsWith(prefix)) continue;\n tokens[path] = tokenLeaf(path, ref, refsMode);\n }\n return tokens;\n };\n\n const buildRuleSetsBucket = (subsystem?: string): Record<string, JsonRuleSet> => {\n const ruleSets: Record<string, JsonRuleSet> = {};\n for (const [sub, subModel] of Object.entries(model.subsystems)) {\n if (subsystem !== undefined && sub !== subsystem) continue;\n for (const [group, rsGroup] of Object.entries(subModel.ruleSets ?? {})) {\n for (const [variant, rs] of Object.entries(rsGroup)) {\n ruleSets[`${sub}.${group}.${variant}`] = ruleSetToJson(rs, refsMode);\n }\n }\n }\n return ruleSets;\n };\n\n const buildKeyframesBucket = (subsystem?: string): Record<string, JsonKeyframe> => {\n const keyframes: Record<string, JsonKeyframe> = {};\n for (const [sub, subModel] of Object.entries(model.subsystems)) {\n if (subsystem !== undefined && sub !== subsystem) continue;\n for (const [name, kf] of Object.entries(subModel.keyframes ?? {})) {\n keyframes[`${sub}.${name}`] = keyframeToJson(kf, refsMode);\n }\n }\n return keyframes;\n };\n\n const buildContainersBucket = (): JsonDoc[\"containers\"] => {\n if (!model.containers || !Object.keys(model.containers).length) return undefined;\n const out: NonNullable<JsonDoc[\"containers\"]> = {};\n for (const [name, c] of Object.entries(model.containers)) out[name] = { type: c.type, sizes: { ...c.sizes } };\n return out;\n };\n\n /** The whole theme as one document — the JSON analogue of the CSS adapter's `collectNodes()`. */\n const buildDoc = (): JsonDoc => {\n const doc: JsonDoc = { breakpoints: { ...model.breakpoints } };\n const containers = buildContainersBucket();\n if (containers) doc.containers = containers;\n const tokens = buildTokensBucket();\n if (Object.keys(tokens).length) doc.tokens = tokens;\n const ruleSets = buildRuleSetsBucket();\n if (Object.keys(ruleSets).length) doc.ruleSets = ruleSets;\n const keyframes = buildKeyframesBucket();\n if (Object.keys(keyframes).length) doc.keyframes = keyframes;\n return doc;\n };\n\n const hasContent = (doc: JsonDoc): boolean => Object.keys(doc).length > 0;\n\n const join = (parts: JsonDoc[]): JsonDoc => {\n const out: JsonDoc = {};\n for (const p of parts) {\n if (p.breakpoints) out.breakpoints = { ...out.breakpoints, ...p.breakpoints };\n if (p.containers) out.containers = { ...out.containers, ...p.containers };\n if (p.tokens) out.tokens = { ...out.tokens, ...p.tokens };\n if (p.ruleSets) out.ruleSets = { ...out.ruleSets, ...p.ruleSets };\n if (p.keyframes) out.keyframes = { ...out.keyframes, ...p.keyframes };\n }\n return out;\n };\n\n return {\n recipeName(subsystem, group, variant) {\n return `${subsystem}.${group}.${variant}`;\n },\n\n // Self-documentation: every recipe's dotted key under `ruleSets`, plus framework-neutral\n // \"read the data\" prose for the emitted guide (llms.txt).\n describeUsage(): UsageDescriptor {\n const recipes: UsageRecipe[] = [];\n for (const [subsystem, sub] of Object.entries(model.subsystems)) {\n for (const [group, ruleSetGroup] of Object.entries(sub.ruleSets ?? {})) {\n for (const variant of Object.keys(ruleSetGroup)) {\n recipes.push({ subsystem, group, variant, name: `${subsystem}.${group}.${variant}` });\n }\n }\n }\n return {\n format: \"json\",\n summary: [\n \"This theme is emitted as a JSON document: a `tokens` bucket (the theme's values) plus a `ruleSets` map (the recipes), each keyed by `subsystem.group.variant`.\",\n 'Load it in any language or tool: `import theme from \"./theme.json\"` (or `require`). It carries no framework binding — read the token values and recipe declarations directly.',\n \"Each recipe below is addressed by its dotted key under `ruleSets`; token paths follow the same `subsystem.group.variant` convention.\",\n ],\n recipes,\n };\n },\n renderRecipe(subsystem, group, variant) {\n const rs = model.subsystems[subsystem]?.ruleSets?.[group]?.[variant];\n if (!rs) return {};\n return { ruleSets: { [`${subsystem}.${group}.${variant}`]: ruleSetToJson(rs, refsMode) } };\n },\n renderVariables(subsystem) {\n const tokens = buildTokensBucket(subsystem);\n return Object.keys(tokens).length ? { tokens } : {};\n },\n join,\n\n // Aggregators overridden (like the CSS adapter): the full doc is not a flat concat of the\n // primitives — the theme-global breakpoints/containers + keyframes land here.\n renderAllVariables(): JsonDoc {\n const doc: JsonDoc = { breakpoints: { ...model.breakpoints } };\n const containers = buildContainersBucket();\n if (containers) doc.containers = containers;\n const tokens = buildTokensBucket();\n if (Object.keys(tokens).length) doc.tokens = tokens;\n return doc;\n },\n renderAllRecipes(): JsonDoc {\n const doc: JsonDoc = {};\n const ruleSets = buildRuleSetsBucket();\n if (Object.keys(ruleSets).length) doc.ruleSets = ruleSets;\n const keyframes = buildKeyframesBucket();\n if (Object.keys(keyframes).length) doc.keyframes = keyframes;\n return doc;\n },\n renderAll: buildDoc,\n\n // Runtime surface: the doc object + its pretty string, plus the plain media descriptor\n // pass-through (mirrors how the CSS adapter surfaces `theme.css` + `theme.media`).\n extend() {\n return {\n media,\n get json(): JsonDoc {\n return buildDoc();\n },\n get jsonString(): string {\n return stringify(buildDoc());\n },\n };\n },\n\n // Build-time emit — the §9 output-shape vocabulary mapped onto the doc's buckets. Plan filenames\n // are normalized to a `.json` extension (the shared plan defaults name `.css` files).\n emit(plan) {\n const type = plan?.type ?? \"single\";\n\n if (type === \"single\") {\n const file = plan?.type === \"single\" ? plan.file : \"theme.json\";\n return { files: { [jsonName(file)]: stringify(buildDoc()) } };\n }\n\n if (plan?.type === \"split\") {\n // Two docs under a load-order-free contract: rule-sets/keyframes vs tokens/config.\n const doc = buildDoc();\n const stylesDoc: JsonDoc = {};\n if (doc.ruleSets) stylesDoc.ruleSets = doc.ruleSets;\n if (doc.keyframes) stylesDoc.keyframes = doc.keyframes;\n const varsDoc: JsonDoc = {};\n if (doc.breakpoints) varsDoc.breakpoints = doc.breakpoints;\n if (doc.containers) varsDoc.containers = doc.containers;\n if (doc.tokens) varsDoc.tokens = doc.tokens;\n return {\n files: { [jsonName(plan.file)]: stringify(stylesDoc), [jsonName(plan.variables)]: stringify(varsDoc) },\n };\n }\n\n if (plan?.type === \"subsystem\") {\n // One pair of docs per subsystem — its tokens (variables side) + its rule-sets/keyframes\n // (styles side). Global breakpoints/containers are theme-level, not per-subsystem, so they\n // don't appear here (like CSS `@media` breakpoints, they only surface inside overrides).\n // Skip empties — the components subsystem owns no tokens → styles file only.\n const files: Record<string, string> = {};\n for (const sub of Object.keys(model.subsystems)) {\n const tokens = buildTokensBucket(sub);\n if (Object.keys(tokens).length) files[jsonName(plan.filename(sub, \"variables\"))] = stringify({ tokens });\n\n const stylesDoc: JsonDoc = {};\n const ruleSets = buildRuleSetsBucket(sub);\n if (Object.keys(ruleSets).length) stylesDoc.ruleSets = ruleSets;\n const keyframes = buildKeyframesBucket(sub);\n if (Object.keys(keyframes).length) stylesDoc.keyframes = keyframes;\n if (hasContent(stylesDoc)) files[jsonName(plan.filename(sub, \"styles\"))] = stringify(stylesDoc);\n }\n return { files };\n }\n\n if (plan?.type === \"components\") {\n // The flattened/merged export: each component variant → one self-contained rule-set\n // (`mergeComponentRuleSet`). `inline` (default true) resolves values and drops refs;\n // `inline: false` keeps refs + a tree-shaken tokens file of only the referenced paths.\n const componentRuleSets = model.subsystems.components?.ruleSets ?? {};\n const leafMode: RefsMode = plan.inline ? \"value\" : \"both\";\n\n const filesByName: Record<string, Record<string, JsonRuleSet>> = {};\n const referencedPaths: string[] = [];\n const seen = new Set<string>();\n\n for (const [group, ruleSetGroup] of Object.entries(componentRuleSets)) {\n for (const variant of Object.keys(ruleSetGroup)) {\n const merged = mergeComponentRuleSet(model, group, variant);\n const filename = jsonName(plan.filename({ group, variant }));\n (filesByName[filename] ??= {})[`components.${group}.${variant}`] = mergedToJson(merged, leafMode);\n\n if (!plan.inline) {\n for (const path of merged.referencedPaths) {\n if (!seen.has(path)) {\n seen.add(path);\n referencedPaths.push(path);\n }\n }\n }\n }\n }\n\n const files: Record<string, string> = {};\n for (const [name, ruleSets] of Object.entries(filesByName)) files[name] = stringify({ ruleSets });\n\n // Tree-shaken tokens file — only the referenced paths — unless `variables: false`.\n if (!plan.inline && plan.variables !== false) {\n const tokens: Record<string, JsonLeaf> = {};\n for (const path of referencedPaths) {\n const ref = tokenMap[path];\n if (ref) tokens[path] = tokenLeaf(path, ref, \"both\");\n }\n if (Object.keys(tokens).length) files[jsonName(plan.variables)] = stringify({ tokens });\n }\n\n return { files };\n }\n\n throw new Error(`json adapter: emit mode '${type}' not yet implemented`);\n },\n };\n },\n };\n\n return defineAdapter(spec);\n};\n"],"names":["jsonName","name","endsWith","replace","options","refsMode","_a","refs","indent","_b","spec","version","bind","model","ctx","media","resolve","tokenMap","buildTokenMap","stringify","doc","JSON","safeResolve","path","buildLeaf","ref","value","mode","leaf","hasRef","undefined","fn","arg","wrap","external","struct","tokenLeaf","declLeaf","target","mapDecls","decls","out","prop","Object","entries","copyCondition","src","dst","state","breakpoint","query","orientation","container","size","variant","overridesToJson","list","overrides","ov","jo","declarations","push","ruleSetToJson","rs","head","kind","selector","references","length","assembleRuleSet","variants","keys","fromEntries","map","v","keyframeToJson","kf","steps","s","stop","mergedToJson","merged","base","states","entry","responsive","buildTokensBucket","subsystem","prefix","tokens","startsWith","buildRuleSetsBucket","ruleSets","sub","subModel","subsystems","group","rsGroup","buildKeyframesBucket","keyframes","buildContainersBucket","containers","c","type","sizes","buildDoc","breakpoints","hasContent","recipeName","describeUsage","recipes","ruleSetGroup","format","summary","renderRecipe","_c","renderVariables","join","parts","p","renderAllVariables","renderAllRecipes","renderAll","extend","json","jsonString","emit","plan","file","files","stylesDoc","varsDoc","variables","filename","componentRuleSets","components","leafMode","inline","filesByName","referencedPaths","seen","Set","mergeComponentRuleSet","_d","has","add","Error","defineAdapter"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { ThemeAdapter } from "@theme-registry/refract";
2
+ import type { JsonAdapterOptions, JsonDoc } from "./types";
3
+ export type { JsonAdapterOptions, JsonContainer, JsonDoc, JsonKeyframe, JsonKeyframeStep, JsonLeaf, JsonOverride, JsonRuleSet, RefsMode, } from "./types";
4
+ /** The JSON adapter's output unit — a document fragment (see {@link JsonDoc}). */
5
+ export type JsonUnit = JsonDoc;
6
+ export declare const createJsonAdapter: (options?: JsonAdapterOptions) => ThemeAdapter<JsonUnit>;
@@ -0,0 +1,2 @@
1
+ import{defineAdapter as e,buildTokenMap as t,mergeComponentRuleSet as s}from"@theme-registry/refract";const r=e=>e.endsWith(".json")?e:`${e.replace(/\.[^./]+$/,"")}.json`,n=(n={})=>{var o,i;const a=null!==(o=n.refs)&&void 0!==o?o:"both",c=null!==(i=n.indent)&&void 0!==i?i:2,l={name:"json",version:1,bind(e,n){const{media:o,resolve:i}=n,l=t(e),u=e=>JSON.stringify(e,null,c),d=e=>{try{return i(e)}catch{return}},f=(e,t,s)=>{const r={},n=void 0!==e.ref;return"value"!==s&&n&&(r.ref=e.ref,void 0!==e.fn&&(r.fn=e.fn),void 0!==e.arg&&(r.arg=e.arg)),"value"!==s&&void 0!==e.wrap&&(r.wrap=e.wrap),void 0!==e.external&&(r.external=e.external),"path"===s&&n||void 0===t||(r.value=t),void 0!==e.struct&&(r.struct=e.struct),r},v=(e,t,s)=>{var r;return f(t,null!==(r=d(e))&&void 0!==r?r:t.value,s)},b=(e,t)=>{var s;const r=void 0!==e.ref&&null!==(s=d(e.ref))&&void 0!==s?s:e.value,n=f(e,r,t);if(void 0===n.ref&&void 0===n.value&&void 0===n.struct&&void 0!==e.ref){const t=l[e.ref];void 0!==(null==t?void 0:t.struct)&&(n.struct=t.struct)}return n},k=(e,t)=>{const s={};for(const[r,n]of Object.entries(e))s[r]=b(n,t);return s},p=(e,t)=>{void 0!==e.state&&(t.state=e.state),void 0!==e.breakpoint&&(t.breakpoint=e.breakpoint),void 0!==e.query&&(t.query=e.query),void 0!==e.orientation&&(t.orientation=e.orientation),void 0!==e.container&&(t.container=e.container),void 0!==e.size&&(t.size=e.size),void 0!==e.variant&&(t.variant=e.variant),void 0!==e.target&&(t.target=e.target)},y=(e,t)=>{const s=[];for(const r of e){const e={};p(r,e),e.declarations=r.declarations?k(r.declarations,t):{},s.push(e)}return s},m=(e,t)=>{const s=((e,t,s)=>{const r={};return e.kind&&(r.kind=e.kind),void 0!==e.selector&&(r.selector=e.selector),e.references&&e.references.length&&(r.references=e.references),r.declarations=t,r.overrides=s,r})({kind:e.kind,selector:e.selector,references:e.references?[...e.references]:void 0},k(e.declarations,t),y(e.overrides,t));return e.variants&&Object.keys(e.variants).length&&(s.variants=Object.fromEntries(Object.entries(e.variants).map(([e,s])=>[e,{declarations:k(s.declarations,t),overrides:y(s.overrides,t)}]))),s},h=(e,t)=>({steps:e.steps.map(e=>({stop:e.stop,declarations:k(e.declarations,t)}))}),j=(e,t)=>{const s={kind:"recipe",declarations:k(e.base,t),overrides:[]};for(const[r,n]of Object.entries(e.states))s.overrides.push({state:r,declarations:k(n,t)});for(const r of e.responsive){const e={};p(r,e),e.declarations=k(r.declarations,t),s.overrides.push(e)}return s},g=e=>{const t=void 0!==e?`${e}.`:"",s={};for(const[r,n]of Object.entries(l))(void 0===e||r.startsWith(t))&&(s[r]=v(r,n,a));return s},O=t=>{var s;const r={};for(const[n,o]of Object.entries(e.subsystems))if(void 0===t||n===t)for(const[e,t]of Object.entries(null!==(s=o.ruleSets)&&void 0!==s?s:{}))for(const[s,o]of Object.entries(t))r[`${n}.${e}.${s}`]=m(o,a);return r},S=t=>{var s;const r={};for(const[n,o]of Object.entries(e.subsystems))if(void 0===t||n===t)for(const[e,t]of Object.entries(null!==(s=o.keyframes)&&void 0!==s?s:{}))r[`${n}.${e}`]=h(t,a);return r},$=()=>{if(!e.containers||!Object.keys(e.containers).length)return;const t={};for(const[s,r]of Object.entries(e.containers))t[s]={type:r.type,sizes:{...r.sizes}};return t},w=()=>{const t={breakpoints:{...e.breakpoints}},s=$();s&&(t.containers=s);const r=g();Object.keys(r).length&&(t.tokens=r);const n=O();Object.keys(n).length&&(t.ruleSets=n);const o=S();return Object.keys(o).length&&(t.keyframes=o),t},x=e=>Object.keys(e).length>0;return{recipeName:(e,t,s)=>`${e}.${t}.${s}`,describeUsage(){var t;const s=[];for(const[r,n]of Object.entries(e.subsystems))for(const[e,o]of Object.entries(null!==(t=n.ruleSets)&&void 0!==t?t:{}))for(const t of Object.keys(o))s.push({subsystem:r,group:e,variant:t,name:`${r}.${e}.${t}`});return{format:"json",summary:["This theme is emitted as a JSON document: a `tokens` bucket (the theme's values) plus a `ruleSets` map (the recipes), each keyed by `subsystem.group.variant`.",'Load it in any language or tool: `import theme from "./theme.json"` (or `require`). It carries no framework binding — read the token values and recipe declarations directly.',"Each recipe below is addressed by its dotted key under `ruleSets`; token paths follow the same `subsystem.group.variant` convention."],recipes:s}},renderRecipe(t,s,r){var n,o,i;const c=null===(i=null===(o=null===(n=e.subsystems[t])||void 0===n?void 0:n.ruleSets)||void 0===o?void 0:o[s])||void 0===i?void 0:i[r];return c?{ruleSets:{[`${t}.${s}.${r}`]:m(c,a)}}:{}},renderVariables(e){const t=g(e);return Object.keys(t).length?{tokens:t}:{}},join:e=>{const t={};for(const s of e)s.breakpoints&&(t.breakpoints={...t.breakpoints,...s.breakpoints}),s.containers&&(t.containers={...t.containers,...s.containers}),s.tokens&&(t.tokens={...t.tokens,...s.tokens}),s.ruleSets&&(t.ruleSets={...t.ruleSets,...s.ruleSets}),s.keyframes&&(t.keyframes={...t.keyframes,...s.keyframes});return t},renderAllVariables(){const t={breakpoints:{...e.breakpoints}},s=$();s&&(t.containers=s);const r=g();return Object.keys(r).length&&(t.tokens=r),t},renderAllRecipes(){const e={},t=O();Object.keys(t).length&&(e.ruleSets=t);const s=S();return Object.keys(s).length&&(e.keyframes=s),e},renderAll:w,extend:()=>({media:o,get json(){return w()},get jsonString(){return u(w())}}),emit(t){var n,o,i,a;const c=null!==(n=null==t?void 0:t.type)&&void 0!==n?n:"single";if("single"===c){const e="single"===(null==t?void 0:t.type)?t.file:"theme.json";return{files:{[r(e)]:u(w())}}}if("split"===(null==t?void 0:t.type)){const e=w(),s={};e.ruleSets&&(s.ruleSets=e.ruleSets),e.keyframes&&(s.keyframes=e.keyframes);const n={};return e.breakpoints&&(n.breakpoints=e.breakpoints),e.containers&&(n.containers=e.containers),e.tokens&&(n.tokens=e.tokens),{files:{[r(t.file)]:u(s),[r(t.variables)]:u(n)}}}if("subsystem"===(null==t?void 0:t.type)){const s={};for(const n of Object.keys(e.subsystems)){const e=g(n);Object.keys(e).length&&(s[r(t.filename(n,"variables"))]=u({tokens:e}));const o={},i=O(n);Object.keys(i).length&&(o.ruleSets=i);const a=S(n);Object.keys(a).length&&(o.keyframes=a),x(o)&&(s[r(t.filename(n,"styles"))]=u(o))}return{files:s}}if("components"===(null==t?void 0:t.type)){const n=null!==(i=null===(o=e.subsystems.components)||void 0===o?void 0:o.ruleSets)&&void 0!==i?i:{},c=t.inline?"value":"both",d={},f=[],b=new Set;for(const[o,i]of Object.entries(n))for(const n of Object.keys(i)){const i=s(e,o,n),l=r(t.filename({group:o,variant:n}));if((null!==(a=d[l])&&void 0!==a?a:d[l]={})[`components.${o}.${n}`]=j(i,c),!t.inline)for(const e of i.referencedPaths)b.has(e)||(b.add(e),f.push(e))}const k={};for(const[e,t]of Object.entries(d))k[e]=u({ruleSets:t});if(!t.inline&&!1!==t.variables){const e={};for(const t of f){const s=l[t];s&&(e[t]=v(t,s,"both"))}Object.keys(e).length&&(k[r(t.variables)]=u({tokens:e}))}return{files:k}}throw new Error(`json adapter: emit mode '${c}' not yet implemented`)}}}};return e(l)};export{n as createJsonAdapter};
2
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../src/index.ts"],"sourcesContent":["/**\n * The JSON adapter — lowers the format-neutral {@link ThemeModel} to structured JSON.\n *\n * The second shipping adapter, and the proof that \"one Model, many formats\" is real: where the\n * CSS adapter's output unit is `string`, this adapter's is a {@link JsonDoc} object and `join`\n * is a bucket merge — the same four primitives + `defineAdapter` aggregators, a different `TUnit`.\n *\n * What it adds over the adapter-free `./dtcg` export (which is tokens-only): it lowers the FULL\n * Model — not just tokens, but rule-sets/recipes, states, responsive/container overrides,\n * composition-by-reference, and keyframes — keeping each `ref` as data alongside its resolved\n * value (exactly what CSS collapses into opaque `var(--…)` strings). That is recipes-as-data,\n * and it doubles as the Model + build-time emit path.\n *\n * Worked reference: `src/adapters/css/`. Core stays format-agnostic; all addressing, the doc IR,\n * and value resolution live here.\n */\nimport type { Literal, Ref, RuleSet, ThemeModel } from \"@theme-registry/refract\";\nimport { buildTokenMap, mergeComponentRuleSet } from \"@theme-registry/refract\";\nimport type { MergedRuleSet } from \"@theme-registry/refract\";\nimport type { AdapterSpec, RenderContext, ThemeAdapter, UsageDescriptor, UsageRecipe } from \"@theme-registry/refract\";\nimport { defineAdapter } from \"@theme-registry/refract\";\nimport type {\n JsonAdapterOptions,\n JsonDoc,\n JsonKeyframe,\n JsonLeaf,\n JsonOverride,\n JsonRuleSet,\n RefsMode,\n} from \"./types\";\n\nexport type {\n JsonAdapterOptions,\n JsonContainer,\n JsonDoc,\n JsonKeyframe,\n JsonKeyframeStep,\n JsonLeaf,\n JsonOverride,\n JsonRuleSet,\n RefsMode,\n} from \"./types\";\n\n/** The JSON adapter's output unit — a document fragment (see {@link JsonDoc}). */\nexport type JsonUnit = JsonDoc;\n\n/** Normalize an emitted filename's extension to `.json` (plan defaults are CSS-centric: `theme.css`,\n * `variables.css`, …). Any existing extension is swapped; a bare name gains `.json`. */\nconst jsonName = (name: string): string =>\n name.endsWith(\".json\") ? name : `${name.replace(/\\.[^./]+$/, \"\")}.json`;\n\nexport const createJsonAdapter = (options: JsonAdapterOptions = {}): ThemeAdapter<JsonUnit> => {\n const refsMode: RefsMode = options.refs ?? \"both\";\n const indent = options.indent ?? 2;\n\n const spec: AdapterSpec<JsonUnit> = {\n name: \"json\",\n version: 1,\n // No `allowedStates`: JSON renders any state name as a data key — it owns no selector knowledge\n // (contrast the CSS adapter's CSS_KNOWN_STATES). Core then does no state validation for this adapter.\n bind(model: ThemeModel, ctx: RenderContext) {\n const { media, resolve } = ctx;\n // The flat `path -> Ref` token map (base + variants + extras), shared by the tokens bucket,\n // renderVariables, and the components tree-shake — the same map that backs `theme.tokens`.\n const tokenMap = buildTokenMap(model);\n\n const stringify = (doc: JsonDoc): string => JSON.stringify(doc, null, indent);\n\n /** Resolve a token path to its literal, swallowing a resolver throw (defensive — a well-formed\n * Model resolves everything; falls back to the Ref's cached `value`). */\n const safeResolve = (path: string): Literal | undefined => {\n try {\n return resolve(path);\n } catch {\n return undefined;\n }\n };\n\n /** Build a leaf from a `Ref` + its already-resolved literal, honoring the ref mode. */\n const buildLeaf = (ref: Ref, value: Literal | undefined, mode: RefsMode): JsonLeaf => {\n const leaf: JsonLeaf = {};\n const hasRef = ref.ref !== undefined;\n if (mode !== \"value\" && hasRef) {\n leaf.ref = ref.ref;\n if (ref.fn !== undefined) leaf.fn = ref.fn;\n if (ref.arg !== undefined) leaf.arg = ref.arg;\n }\n if (mode !== \"value\" && ref.wrap !== undefined) leaf.wrap = ref.wrap;\n if (ref.external !== undefined) leaf.external = ref.external; // §W6b — parent-var passthrough\n // `value` in both/value modes; in path mode only for a literal (no ref to stand in for it).\n if ((mode !== \"path\" || !hasRef) && value !== undefined) leaf.value = value;\n // §15: a structured (shadow/transition) value carries as data — the format-neutral shape a\n // future RN adapter lowers; its per-layer `color` stays a `colors.*` ref for the consumer.\n if (ref.struct !== undefined) leaf.struct = ref.struct;\n return leaf;\n };\n\n /** A token leaf — resolved by the token's OWN address (its `Ref.ref`, if any, is a derivation source). */\n const tokenLeaf = (path: string, ref: Ref, mode: RefsMode): JsonLeaf =>\n buildLeaf(ref, safeResolve(path) ?? ref.value, mode);\n\n /** A declaration leaf — resolved by the path its `Ref.ref` points at (literal ⇒ its `value`).\n * §15: when the ref points at a STRUCTURED (shadow/transition) token — which has no single\n * literal to bake — the leaf carries that token's `struct` (its per-layer `color` stays a\n * `colors.*` ref for the consumer), so an inline declaration isn't left value-less. */\n const declLeaf = (ref: Ref, mode: RefsMode): JsonLeaf => {\n const value = ref.ref !== undefined ? safeResolve(ref.ref) ?? ref.value : ref.value;\n const leaf = buildLeaf(ref, value, mode);\n // Only when the `ref` was baked away (inline `value` mode) and no literal resulted — otherwise\n // the retained `ref` already leads the consumer to the token that carries the struct.\n if (leaf.ref === undefined && leaf.value === undefined && leaf.struct === undefined && ref.ref !== undefined) {\n const target = tokenMap[ref.ref];\n if (target?.struct !== undefined) leaf.struct = target.struct;\n }\n return leaf;\n };\n\n const mapDecls = (decls: Record<string, Ref>, mode: RefsMode): Record<string, JsonLeaf> => {\n const out: Record<string, JsonLeaf> = {};\n for (const [prop, ref] of Object.entries(decls)) out[prop] = declLeaf(ref, mode);\n return out;\n };\n\n /** Copy the present condition axes off a Model override/entry onto a JSON override. */\n const copyCondition = (\n src: {\n state?: string;\n breakpoint?: string;\n query?: JsonOverride[\"query\"];\n orientation?: JsonOverride[\"orientation\"];\n container?: string;\n size?: string;\n variant?: string;\n target?: string;\n },\n dst: JsonOverride,\n ): void => {\n if (src.state !== undefined) dst.state = src.state;\n if (src.breakpoint !== undefined) dst.breakpoint = src.breakpoint;\n if (src.query !== undefined) dst.query = src.query;\n if (src.orientation !== undefined) dst.orientation = src.orientation;\n if (src.container !== undefined) dst.container = src.container;\n if (src.size !== undefined) dst.size = src.size;\n if (src.variant !== undefined) dst.variant = src.variant;\n if (src.target !== undefined) dst.target = src.target;\n };\n\n // Assemble a rule-set with a readable key order: kind / selector / references first, then\n // declarations / overrides (independent of the Model's property insertion order).\n const assembleRuleSet = (\n head: Pick<JsonRuleSet, \"kind\" | \"selector\" | \"references\">,\n declarations: Record<string, JsonLeaf>,\n overrides: JsonOverride[],\n ): JsonRuleSet => {\n const out = {} as JsonRuleSet;\n if (head.kind) out.kind = head.kind;\n if (head.selector !== undefined) out.selector = head.selector;\n if (head.references && head.references.length) out.references = head.references;\n out.declarations = declarations;\n out.overrides = overrides;\n return out;\n };\n\n const overridesToJson = (list: RuleSet[\"overrides\"], mode: RefsMode): JsonOverride[] => {\n const overrides: JsonOverride[] = [];\n for (const ov of list) {\n const jo = {} as JsonOverride; // condition axes first, then declarations (readability)\n copyCondition(ov, jo);\n jo.declarations = ov.declarations ? mapDecls(ov.declarations, mode) : {};\n overrides.push(jo);\n }\n return overrides;\n };\n\n const ruleSetToJson = (rs: RuleSet, mode: RefsMode): JsonRuleSet => {\n const out = assembleRuleSet(\n { kind: rs.kind, selector: rs.selector, references: rs.references ? [...rs.references] : undefined },\n mapDecls(rs.declarations, mode),\n overridesToJson(rs.overrides, mode),\n );\n // §9: globals element variants (delta-only modifiers) survive as data.\n if (rs.variants && Object.keys(rs.variants).length) {\n out.variants = Object.fromEntries(\n Object.entries(rs.variants).map(([name, v]) => [\n name,\n { declarations: mapDecls(v.declarations, mode), overrides: overridesToJson(v.overrides, mode) },\n ]),\n );\n }\n return out;\n };\n\n const keyframeToJson = (kf: { steps: { stop: string; declarations: Record<string, Ref> }[] }, mode: RefsMode): JsonKeyframe => ({\n steps: kf.steps.map(s => ({ stop: s.stop, declarations: mapDecls(s.declarations, mode) })),\n });\n\n /** A merged component variant (`mergeComponentRuleSet`) → one self-contained JSON rule-set. */\n const mergedToJson = (merged: MergedRuleSet, mode: RefsMode): JsonRuleSet => {\n const out: JsonRuleSet = { kind: \"recipe\", declarations: mapDecls(merged.base, mode), overrides: [] };\n for (const [state, decls] of Object.entries(merged.states)) {\n out.overrides.push({ state, declarations: mapDecls(decls, mode) });\n }\n for (const entry of merged.responsive) {\n const jo = {} as JsonOverride;\n copyCondition(entry, jo);\n jo.declarations = mapDecls(entry.declarations, mode);\n out.overrides.push(jo);\n }\n return out;\n };\n\n // ── Bucket builders (each a flat address-keyed map; every full-doc consumer composes these) ──\n const buildTokensBucket = (subsystem?: string): Record<string, JsonLeaf> => {\n const prefix = subsystem !== undefined ? `${subsystem}.` : \"\";\n const tokens: Record<string, JsonLeaf> = {};\n for (const [path, ref] of Object.entries(tokenMap)) {\n if (subsystem !== undefined && !path.startsWith(prefix)) continue;\n tokens[path] = tokenLeaf(path, ref, refsMode);\n }\n return tokens;\n };\n\n const buildRuleSetsBucket = (subsystem?: string): Record<string, JsonRuleSet> => {\n const ruleSets: Record<string, JsonRuleSet> = {};\n for (const [sub, subModel] of Object.entries(model.subsystems)) {\n if (subsystem !== undefined && sub !== subsystem) continue;\n for (const [group, rsGroup] of Object.entries(subModel.ruleSets ?? {})) {\n for (const [variant, rs] of Object.entries(rsGroup)) {\n ruleSets[`${sub}.${group}.${variant}`] = ruleSetToJson(rs, refsMode);\n }\n }\n }\n return ruleSets;\n };\n\n const buildKeyframesBucket = (subsystem?: string): Record<string, JsonKeyframe> => {\n const keyframes: Record<string, JsonKeyframe> = {};\n for (const [sub, subModel] of Object.entries(model.subsystems)) {\n if (subsystem !== undefined && sub !== subsystem) continue;\n for (const [name, kf] of Object.entries(subModel.keyframes ?? {})) {\n keyframes[`${sub}.${name}`] = keyframeToJson(kf, refsMode);\n }\n }\n return keyframes;\n };\n\n const buildContainersBucket = (): JsonDoc[\"containers\"] => {\n if (!model.containers || !Object.keys(model.containers).length) return undefined;\n const out: NonNullable<JsonDoc[\"containers\"]> = {};\n for (const [name, c] of Object.entries(model.containers)) out[name] = { type: c.type, sizes: { ...c.sizes } };\n return out;\n };\n\n /** The whole theme as one document — the JSON analogue of the CSS adapter's `collectNodes()`. */\n const buildDoc = (): JsonDoc => {\n const doc: JsonDoc = { breakpoints: { ...model.breakpoints } };\n const containers = buildContainersBucket();\n if (containers) doc.containers = containers;\n const tokens = buildTokensBucket();\n if (Object.keys(tokens).length) doc.tokens = tokens;\n const ruleSets = buildRuleSetsBucket();\n if (Object.keys(ruleSets).length) doc.ruleSets = ruleSets;\n const keyframes = buildKeyframesBucket();\n if (Object.keys(keyframes).length) doc.keyframes = keyframes;\n return doc;\n };\n\n const hasContent = (doc: JsonDoc): boolean => Object.keys(doc).length > 0;\n\n const join = (parts: JsonDoc[]): JsonDoc => {\n const out: JsonDoc = {};\n for (const p of parts) {\n if (p.breakpoints) out.breakpoints = { ...out.breakpoints, ...p.breakpoints };\n if (p.containers) out.containers = { ...out.containers, ...p.containers };\n if (p.tokens) out.tokens = { ...out.tokens, ...p.tokens };\n if (p.ruleSets) out.ruleSets = { ...out.ruleSets, ...p.ruleSets };\n if (p.keyframes) out.keyframes = { ...out.keyframes, ...p.keyframes };\n }\n return out;\n };\n\n return {\n recipeName(subsystem, group, variant) {\n return `${subsystem}.${group}.${variant}`;\n },\n\n // Self-documentation: every recipe's dotted key under `ruleSets`, plus framework-neutral\n // \"read the data\" prose for the emitted guide (llms.txt).\n describeUsage(): UsageDescriptor {\n const recipes: UsageRecipe[] = [];\n for (const [subsystem, sub] of Object.entries(model.subsystems)) {\n for (const [group, ruleSetGroup] of Object.entries(sub.ruleSets ?? {})) {\n for (const variant of Object.keys(ruleSetGroup)) {\n recipes.push({ subsystem, group, variant, name: `${subsystem}.${group}.${variant}` });\n }\n }\n }\n return {\n format: \"json\",\n summary: [\n \"This theme is emitted as a JSON document: a `tokens` bucket (the theme's values) plus a `ruleSets` map (the recipes), each keyed by `subsystem.group.variant`.\",\n 'Load it in any language or tool: `import theme from \"./theme.json\"` (or `require`). It carries no framework binding — read the token values and recipe declarations directly.',\n \"Each recipe below is addressed by its dotted key under `ruleSets`; token paths follow the same `subsystem.group.variant` convention.\",\n ],\n recipes,\n };\n },\n renderRecipe(subsystem, group, variant) {\n const rs = model.subsystems[subsystem]?.ruleSets?.[group]?.[variant];\n if (!rs) return {};\n return { ruleSets: { [`${subsystem}.${group}.${variant}`]: ruleSetToJson(rs, refsMode) } };\n },\n renderVariables(subsystem) {\n const tokens = buildTokensBucket(subsystem);\n return Object.keys(tokens).length ? { tokens } : {};\n },\n join,\n\n // Aggregators overridden (like the CSS adapter): the full doc is not a flat concat of the\n // primitives — the theme-global breakpoints/containers + keyframes land here.\n renderAllVariables(): JsonDoc {\n const doc: JsonDoc = { breakpoints: { ...model.breakpoints } };\n const containers = buildContainersBucket();\n if (containers) doc.containers = containers;\n const tokens = buildTokensBucket();\n if (Object.keys(tokens).length) doc.tokens = tokens;\n return doc;\n },\n renderAllRecipes(): JsonDoc {\n const doc: JsonDoc = {};\n const ruleSets = buildRuleSetsBucket();\n if (Object.keys(ruleSets).length) doc.ruleSets = ruleSets;\n const keyframes = buildKeyframesBucket();\n if (Object.keys(keyframes).length) doc.keyframes = keyframes;\n return doc;\n },\n renderAll: buildDoc,\n\n // Runtime surface: the doc object + its pretty string, plus the plain media descriptor\n // pass-through (mirrors how the CSS adapter surfaces `theme.css` + `theme.media`).\n extend() {\n return {\n media,\n get json(): JsonDoc {\n return buildDoc();\n },\n get jsonString(): string {\n return stringify(buildDoc());\n },\n };\n },\n\n // Build-time emit — the §9 output-shape vocabulary mapped onto the doc's buckets. Plan filenames\n // are normalized to a `.json` extension (the shared plan defaults name `.css` files).\n emit(plan) {\n const type = plan?.type ?? \"single\";\n\n if (type === \"single\") {\n const file = plan?.type === \"single\" ? plan.file : \"theme.json\";\n return { files: { [jsonName(file)]: stringify(buildDoc()) } };\n }\n\n if (plan?.type === \"split\") {\n // Two docs under a load-order-free contract: rule-sets/keyframes vs tokens/config.\n const doc = buildDoc();\n const stylesDoc: JsonDoc = {};\n if (doc.ruleSets) stylesDoc.ruleSets = doc.ruleSets;\n if (doc.keyframes) stylesDoc.keyframes = doc.keyframes;\n const varsDoc: JsonDoc = {};\n if (doc.breakpoints) varsDoc.breakpoints = doc.breakpoints;\n if (doc.containers) varsDoc.containers = doc.containers;\n if (doc.tokens) varsDoc.tokens = doc.tokens;\n return {\n files: { [jsonName(plan.file)]: stringify(stylesDoc), [jsonName(plan.variables)]: stringify(varsDoc) },\n };\n }\n\n if (plan?.type === \"subsystem\") {\n // One pair of docs per subsystem — its tokens (variables side) + its rule-sets/keyframes\n // (styles side). Global breakpoints/containers are theme-level, not per-subsystem, so they\n // don't appear here (like CSS `@media` breakpoints, they only surface inside overrides).\n // Skip empties — the components subsystem owns no tokens → styles file only.\n const files: Record<string, string> = {};\n for (const sub of Object.keys(model.subsystems)) {\n const tokens = buildTokensBucket(sub);\n if (Object.keys(tokens).length) files[jsonName(plan.filename(sub, \"variables\"))] = stringify({ tokens });\n\n const stylesDoc: JsonDoc = {};\n const ruleSets = buildRuleSetsBucket(sub);\n if (Object.keys(ruleSets).length) stylesDoc.ruleSets = ruleSets;\n const keyframes = buildKeyframesBucket(sub);\n if (Object.keys(keyframes).length) stylesDoc.keyframes = keyframes;\n if (hasContent(stylesDoc)) files[jsonName(plan.filename(sub, \"styles\"))] = stringify(stylesDoc);\n }\n return { files };\n }\n\n if (plan?.type === \"components\") {\n // The flattened/merged export: each component variant → one self-contained rule-set\n // (`mergeComponentRuleSet`). `inline` (default true) resolves values and drops refs;\n // `inline: false` keeps refs + a tree-shaken tokens file of only the referenced paths.\n const componentRuleSets = model.subsystems.components?.ruleSets ?? {};\n const leafMode: RefsMode = plan.inline ? \"value\" : \"both\";\n\n const filesByName: Record<string, Record<string, JsonRuleSet>> = {};\n const referencedPaths: string[] = [];\n const seen = new Set<string>();\n\n for (const [group, ruleSetGroup] of Object.entries(componentRuleSets)) {\n for (const variant of Object.keys(ruleSetGroup)) {\n const merged = mergeComponentRuleSet(model, group, variant);\n const filename = jsonName(plan.filename({ group, variant }));\n (filesByName[filename] ??= {})[`components.${group}.${variant}`] = mergedToJson(merged, leafMode);\n\n if (!plan.inline) {\n for (const path of merged.referencedPaths) {\n if (!seen.has(path)) {\n seen.add(path);\n referencedPaths.push(path);\n }\n }\n }\n }\n }\n\n const files: Record<string, string> = {};\n for (const [name, ruleSets] of Object.entries(filesByName)) files[name] = stringify({ ruleSets });\n\n // Tree-shaken tokens file — only the referenced paths — unless `variables: false`.\n if (!plan.inline && plan.variables !== false) {\n const tokens: Record<string, JsonLeaf> = {};\n for (const path of referencedPaths) {\n const ref = tokenMap[path];\n if (ref) tokens[path] = tokenLeaf(path, ref, \"both\");\n }\n if (Object.keys(tokens).length) files[jsonName(plan.variables)] = stringify({ tokens });\n }\n\n return { files };\n }\n\n throw new Error(`json adapter: emit mode '${type}' not yet implemented`);\n },\n };\n },\n };\n\n return defineAdapter(spec);\n};\n"],"names":["jsonName","name","endsWith","replace","createJsonAdapter","options","refsMode","_a","refs","indent","_b","spec","version","bind","model","ctx","media","resolve","tokenMap","buildTokenMap","stringify","doc","JSON","safeResolve","path","buildLeaf","ref","value","mode","leaf","hasRef","undefined","fn","arg","wrap","external","struct","tokenLeaf","declLeaf","target","mapDecls","decls","out","prop","Object","entries","copyCondition","src","dst","state","breakpoint","query","orientation","container","size","variant","overridesToJson","list","overrides","ov","jo","declarations","push","ruleSetToJson","rs","head","kind","selector","references","length","assembleRuleSet","variants","keys","fromEntries","map","v","keyframeToJson","kf","steps","s","stop","mergedToJson","merged","base","states","entry","responsive","buildTokensBucket","subsystem","prefix","tokens","startsWith","buildRuleSetsBucket","ruleSets","sub","subModel","subsystems","group","rsGroup","buildKeyframesBucket","keyframes","buildContainersBucket","containers","c","type","sizes","buildDoc","breakpoints","hasContent","recipeName","describeUsage","recipes","ruleSetGroup","format","summary","renderRecipe","_c","renderVariables","join","parts","p","renderAllVariables","renderAllRecipes","renderAll","extend","json","jsonString","emit","plan","file","files","stylesDoc","varsDoc","variables","filename","componentRuleSets","components","leafMode","inline","filesByName","referencedPaths","seen","Set","mergeComponentRuleSet","_d","has","add","Error","defineAdapter"],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * The JSON adapter's output IR — a format-neutral **document fragment**.
3
+ *
4
+ * A JSON-specific lowering artifact, derived inside the adapter from the format-neutral
5
+ * {@link ThemeModel}. Where the CSS adapter's `TUnit` is `string`, the JSON adapter's is
6
+ * this {@link JsonDoc} object; `join` shallow-merges fragments per bucket (the buckets are
7
+ * flat, full-address-keyed maps, so keys never collide across fragments).
8
+ *
9
+ * The doc mirrors the Model's two kinds of thing plus its config: **tokens** (property
10
+ * leaves), **ruleSets** (recipes / layout presets / composition / reset), **keyframes**,
11
+ * and the theme-global `breakpoints` / `containers`. Each leaf is the JSON mirror of the
12
+ * Model's `Ref` — carrying the token `ref` path AND the resolved `value` (the parts a
13
+ * tokens-only DTCG export cannot represent: recipes, states, responsive rule overrides,
14
+ * and composition-by-reference all survive as data here).
15
+ */
16
+ import type { Literal, Orientation, ResponsiveQueryKind, StructuredValue } from "@theme-registry/refract";
17
+ /**
18
+ * A rendered leaf — the JSON mirror of the Model's `Ref`.
19
+ *
20
+ * - `value` — the resolved literal (present in `both` / `value` ref modes; and in `path`
21
+ * mode only for a pure literal that has no `ref`).
22
+ * - `ref` — the token path this leaf references (`"colors.primary.dark"`), or — on a
23
+ * derived token leaf — its derivation source. Present in `both` / `path` modes.
24
+ * - `fn` / `arg` — the derivation carried on a derived token (`darken(colors.primary, 20)`).
25
+ * - `wrap` — an adapter output-wrap hint (e.g. `blur`) kept as data.
26
+ * - `struct`— a structured compound value (§15) for shadow / transition tokens — an array of
27
+ * layers/parts kept as data; each layer's `color` is a `colors.*` token-path ref (the RN/JSON
28
+ * consumer resolves it). Present whenever the Model `Ref` carries structure, in any ref mode.
29
+ */
30
+ export type JsonLeaf = {
31
+ ref?: string;
32
+ fn?: string;
33
+ arg?: unknown;
34
+ wrap?: string;
35
+ value?: Literal;
36
+ struct?: StructuredValue;
37
+ /** §W6b — set (to the parent var name) when this token is an external passthrough; `value` is the `var(…)`. */
38
+ external?: string;
39
+ };
40
+ /** One conditioned override on a rule-set — the Model's condition axes + its declarations. */
41
+ export type JsonOverride = {
42
+ state?: string;
43
+ breakpoint?: string;
44
+ query?: ResponsiveQueryKind;
45
+ orientation?: Orientation;
46
+ container?: string;
47
+ size?: string;
48
+ variant?: string;
49
+ target?: string;
50
+ declarations: Record<string, JsonLeaf>;
51
+ };
52
+ /** One globals element variant (§9) as data — a delta-only modifier's declarations + overrides. */
53
+ export type JsonGlobalsVariant = {
54
+ declarations: Record<string, JsonLeaf>;
55
+ overrides: JsonOverride[];
56
+ };
57
+ /**
58
+ * A rule-set as data — recipes / layout presets / composition (`references`) / globals
59
+ * (`selector` + `kind:"reset"` preset layer or `kind:"globals"` themed element with `variants`).
60
+ */
61
+ export type JsonRuleSet = {
62
+ kind?: "recipe" | "utility" | "reset" | "globals";
63
+ selector?: string;
64
+ references?: string[];
65
+ declarations: Record<string, JsonLeaf>;
66
+ overrides: JsonOverride[];
67
+ /** `kind:"globals"` only (§9): named delta-only element variants, kept as data. */
68
+ variants?: Record<string, JsonGlobalsVariant>;
69
+ };
70
+ /** One keyframe step — its verbatim stop + the declarations at that stop. */
71
+ export type JsonKeyframeStep = {
72
+ stop: string;
73
+ declarations: Record<string, JsonLeaf>;
74
+ };
75
+ /** A named keyframe definition — an ordered list of steps. */
76
+ export type JsonKeyframe = {
77
+ steps: JsonKeyframeStep[];
78
+ };
79
+ /** One named query container (§10.5) as data. */
80
+ export type JsonContainer = {
81
+ type: "inline-size" | "size";
82
+ sizes: Record<string, number>;
83
+ };
84
+ /**
85
+ * The JSON adapter's output unit — a document fragment. Every bucket is a flat map keyed by
86
+ * a full Model address (`"colors.primary.dark"`, `"colors.solid.primary"`), so `join` is a
87
+ * shallow per-bucket merge. A whole theme is one {@link JsonDoc} with every bucket populated.
88
+ */
89
+ export type JsonDoc = {
90
+ breakpoints?: Record<string, number>;
91
+ containers?: Record<string, JsonContainer>;
92
+ tokens?: Record<string, JsonLeaf>;
93
+ ruleSets?: Record<string, JsonRuleSet>;
94
+ keyframes?: Record<string, JsonKeyframe>;
95
+ };
96
+ /**
97
+ * How a leaf renders its reference:
98
+ * - `both` — `ref` (+ `fn`/`arg`/`wrap`) AND the resolved `value` (default; strongest proof + most useful).
99
+ * - `path` — the `ref` only (a literal with no ref still emits its `value`).
100
+ * - `value` — the resolved `value` only (DTCG-like literals, but with recipes/states/composition).
101
+ */
102
+ export type RefsMode = "both" | "path" | "value";
103
+ /** Per-adapter knobs. JSON keys are Model addresses, so there are no CSS-style prefix options. */
104
+ export type JsonAdapterOptions = {
105
+ /** How referenced leaves render (default `both`). */
106
+ refs?: RefsMode;
107
+ /** Pretty-print indent (spaces) for emitted files. Default `2`; `0` = minified. */
108
+ indent?: number;
109
+ };
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@theme-registry/refract-json",
3
+ "version": "0.1.0",
4
+ "description": "The JSON output adapter for @theme-registry/refract — lowers a ThemeModel to a structured JSON document.",
5
+ "author": {
6
+ "name": "Petyo Stoyanov",
7
+ "email": "petyosv@gmail.com"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/theme-registry/refract.git",
12
+ "directory": "packages/refract-json"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/theme-registry/refract/issues"
16
+ },
17
+ "homepage": "https://github.com/theme-registry/refract#readme",
18
+ "license": "MIT",
19
+ "main": "./dist/index.cjs.js",
20
+ "module": "./dist/index.esm.js",
21
+ "types": "./dist/index.d.ts",
22
+ "files": [
23
+ "/dist"
24
+ ],
25
+ "sideEffects": false,
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.esm.js",
30
+ "require": "./dist/index.cjs.js"
31
+ },
32
+ "./package.json": "./package.json"
33
+ },
34
+ "peerDependencies": {
35
+ "@theme-registry/refract": "^0.1.0"
36
+ },
37
+ "devDependencies": {
38
+ "@rollup/plugin-terser": "^0.4.4",
39
+ "@rollup/plugin-typescript": "^11.1.6",
40
+ "rimraf": "^5.0.5",
41
+ "rollup": "^3.29.4",
42
+ "rollup-plugin-peer-deps-external": "^2.2.4",
43
+ "typescript": "^5.4.2",
44
+ "vitest": "^4.1.10",
45
+ "@theme-registry/refract": "^0.1.0",
46
+ "@theme-registry/theme-fixtures": "^0.0.0"
47
+ },
48
+ "scripts": {
49
+ "build": "rollup -c",
50
+ "typecheck": "tsc -p tsconfig.typecheck.json",
51
+ "clean": "rimraf dist",
52
+ "test": "vitest run"
53
+ }
54
+ }