@bezel-labs/bezel-kit 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/dist/cli.cjs ADDED
@@ -0,0 +1,567 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ // src/cli.ts
5
+ var import_node_fs = require("fs");
6
+ var import_promises2 = require("fs/promises");
7
+ var import_node_url = require("url");
8
+ var import_node_util = require("util");
9
+ var import_node_path3 = require("path");
10
+
11
+ // src/node.ts
12
+ var import_promises = require("fs/promises");
13
+ var import_node_path2 = require("path");
14
+
15
+ // src/config.ts
16
+ var import_node_path = require("path");
17
+
18
+ // src/defaults.ts
19
+ var DEFAULT_CONTEXTS = {
20
+ $root: ":root",
21
+ dark: ".dark",
22
+ light: ".light"
23
+ };
24
+ var DEFAULT_INPUT = "design-tokens.json";
25
+ var DEFAULT_VARIABLES_OUTPUT = "variables.css";
26
+ var DEFAULT_NAME_EXTENSION = "com.tokendesigner.app";
27
+
28
+ // src/options.ts
29
+ function resolveCssOptions(options = {}) {
30
+ const contexts = options.contexts ?? DEFAULT_CONTEXTS;
31
+ if (Object.keys(contexts).length === 0) {
32
+ throw new Error("bezel: `contexts` must define at least one context.");
33
+ }
34
+ return {
35
+ contexts,
36
+ colorFormat: options.colorFormat ?? "oklch",
37
+ dimensionUnit: options.dimensionUnit ?? "preserve",
38
+ nameExtension: options.nameExtension ?? DEFAULT_NAME_EXTENSION
39
+ };
40
+ }
41
+
42
+ // src/config.ts
43
+ function resolveOptions(options = {}) {
44
+ const cwd = options.cwd ?? process.cwd();
45
+ const toAbs = (p) => (0, import_node_path.isAbsolute)(p) ? p : (0, import_node_path.resolve)(cwd, p);
46
+ const css = resolveCssOptions(options);
47
+ return {
48
+ // The tokens file is always `design-tokens.json` at the project root — not configurable.
49
+ inputPath: toAbs(DEFAULT_INPUT),
50
+ variablesOutputPath: toAbs(options.variablesOutput ?? DEFAULT_VARIABLES_OUTPUT),
51
+ ...css,
52
+ contextsOutput: options.contextsOutput ? toAbs(options.contextsOutput) : null,
53
+ fontsOutput: options.fontsOutput ? toAbs(options.fontsOutput) : null,
54
+ write: options.write ?? true,
55
+ gitignore: options.gitignore ?? true,
56
+ gitignorePath: toAbs(options.gitignorePath ?? ".gitignore")
57
+ };
58
+ }
59
+
60
+ // src/collapse.ts
61
+ var ROOT_CONTEXT = "$root";
62
+ function isObject(v) {
63
+ return typeof v === "object" && v !== null && !Array.isArray(v);
64
+ }
65
+ function isContextWrapper(v) {
66
+ return isObject(v) && "$value" in v;
67
+ }
68
+ function isMetaKey(key) {
69
+ return key === "$type" || key === "$description" || key === "$extensions" || key === "$value";
70
+ }
71
+ function flattenForContext(tokens, context) {
72
+ const out = /* @__PURE__ */ new Map();
73
+ const walk = (node, path, inheritedType) => {
74
+ const type = typeof node.$type === "string" ? node.$type : inheritedType;
75
+ if ("$value" in node) {
76
+ out.set(path, {
77
+ path,
78
+ value: node.$value,
79
+ type,
80
+ extensions: node.$extensions
81
+ });
82
+ return;
83
+ }
84
+ const wrapperKeys = Object.keys(node).filter((k) => !isMetaKey(k) && isContextWrapper(node[k]));
85
+ if (wrapperKeys.length > 0) {
86
+ const chosen = node[context] ?? node[ROOT_CONTEXT] ?? node[wrapperKeys[0]];
87
+ out.set(path, {
88
+ path,
89
+ value: chosen.$value,
90
+ type,
91
+ extensions: node.$extensions
92
+ });
93
+ return;
94
+ }
95
+ for (const key of Object.keys(node)) {
96
+ if (isMetaKey(key)) continue;
97
+ const child = node[key];
98
+ if (isObject(child)) {
99
+ walk(child, path ? `${path}.${key}` : key, type);
100
+ }
101
+ }
102
+ };
103
+ walk(tokens, "", void 0);
104
+ return out;
105
+ }
106
+
107
+ // src/name.ts
108
+ var DROPPED_PREFIXES = /* @__PURE__ */ new Set(["base", "semantic"]);
109
+ var DROPPED_SUFFIXES = /* @__PURE__ */ new Set(["default", "$root"]);
110
+ function exportNames(token, nameExtension) {
111
+ const ext = token.extensions?.[nameExtension];
112
+ if (ext && typeof ext === "object" && "exportName" in ext) {
113
+ const names = ext.exportName;
114
+ if (Array.isArray(names)) return names.filter((n) => typeof n === "string");
115
+ }
116
+ return void 0;
117
+ }
118
+ function usesExportNames(tokens, nameExtension) {
119
+ for (const token of tokens) {
120
+ if (exportNames(token, nameExtension) !== void 0) return true;
121
+ }
122
+ return false;
123
+ }
124
+ function nameFromPath(path) {
125
+ const segments = path.split(".");
126
+ while (segments.length > 1 && DROPPED_PREFIXES.has(segments[0])) segments.shift();
127
+ while (segments.length > 1 && DROPPED_SUFFIXES.has(segments[segments.length - 1])) {
128
+ segments.pop();
129
+ }
130
+ return segments.join("-");
131
+ }
132
+ function cssNames(token, nameExtension, useExportName) {
133
+ if (useExportName) {
134
+ const names = exportNames(token, nameExtension);
135
+ if (!names) return [];
136
+ return names.filter((n) => n.length > 0);
137
+ }
138
+ return [nameFromPath(token.path)];
139
+ }
140
+
141
+ // src/resolve.ts
142
+ var REFERENCE_RE = /^\{([^{}]+)\}$/;
143
+ function aliasTarget(value) {
144
+ if (typeof value !== "string") return null;
145
+ const match = REFERENCE_RE.exec(value.trim());
146
+ return match ? match[1].trim() : null;
147
+ }
148
+ function resolveReferences(tokens) {
149
+ const resolved = /* @__PURE__ */ new Map();
150
+ const resolveValue = (value, seen) => {
151
+ const target = aliasTarget(value);
152
+ if (target === null) return value;
153
+ if (resolved.has(target)) return resolved.get(target);
154
+ if (seen.has(target)) {
155
+ throw new Error(`bezel: circular token reference detected at "{${target}}".`);
156
+ }
157
+ const token = tokens.get(target);
158
+ if (!token) {
159
+ throw new Error(`bezel: unresolved token reference "{${target}}".`);
160
+ }
161
+ seen.add(target);
162
+ const value2 = resolveValue(token.value, seen);
163
+ seen.delete(target);
164
+ resolved.set(target, value2);
165
+ return value2;
166
+ };
167
+ for (const token of tokens.values()) {
168
+ token.value = resolveValue(token.value, /* @__PURE__ */ new Set());
169
+ }
170
+ return tokens;
171
+ }
172
+
173
+ // src/serialize.ts
174
+ function isObject2(v) {
175
+ return typeof v === "object" && v !== null && !Array.isArray(v);
176
+ }
177
+ function isColor(v) {
178
+ return isObject2(v) && "colorSpace" in v && Array.isArray(v["components"]);
179
+ }
180
+ function isDimension(v) {
181
+ return isObject2(v) && typeof v["value"] === "number" && "unit" in v;
182
+ }
183
+ function round(n, dp) {
184
+ const f = 10 ** dp;
185
+ return Math.round(n * f) / f;
186
+ }
187
+ function serializeColor(color, format) {
188
+ if (format === "hex" && color.hex) return color.hex.toLowerCase();
189
+ if (color.colorSpace === "oklch") {
190
+ const [l = 0, c = 0, h = 0] = color.components;
191
+ const base = `oklch(${round(l, 4)} ${round(c, 4)} ${round(h, 3)})`;
192
+ if (color.alpha !== void 0 && color.alpha < 1) {
193
+ return `oklch(${round(l, 4)} ${round(c, 4)} ${round(h, 3)} / ${round(color.alpha, 4)})`;
194
+ }
195
+ return base;
196
+ }
197
+ if (color.hex) return color.hex.toLowerCase();
198
+ return `color(${color.colorSpace} ${color.components.map((n) => round(n, 4)).join(" ")})`;
199
+ }
200
+ function serializeDimension(dim, unit) {
201
+ if (unit === "rem" && dim.unit === "px") {
202
+ return `${round(dim.value / 16, 4)}rem`;
203
+ }
204
+ return `${dim.value}${dim.unit}`;
205
+ }
206
+ function quoteFamily(name) {
207
+ const trimmed = name.trim();
208
+ if (/^['"].*['"]$/.test(trimmed)) return trimmed;
209
+ return /\s/.test(trimmed) ? `"${trimmed}"` : trimmed;
210
+ }
211
+ function serializeValue(value, options) {
212
+ if (isColor(value)) return serializeColor(value, options.colorFormat);
213
+ if (isDimension(value)) return serializeDimension(value, options.dimensionUnit);
214
+ if (Array.isArray(value)) {
215
+ return value.map((v) => quoteFamily(String(v))).join(", ");
216
+ }
217
+ if (typeof value === "number") return String(value);
218
+ const str = String(value);
219
+ if (/\s/.test(str) && !str.includes(",") && !/[()]/.test(str)) {
220
+ return quoteFamily(str);
221
+ }
222
+ return str;
223
+ }
224
+
225
+ // src/emit.ts
226
+ function buildContextVars(tokens, context, useExportName, options) {
227
+ const flat = resolveReferences(flattenForContext(tokens, context));
228
+ const vars = /* @__PURE__ */ new Map();
229
+ for (const token of flat.values()) {
230
+ const names = cssNames(token, options.nameExtension, useExportName);
231
+ if (names.length === 0) continue;
232
+ const value = serializeValue(token.value, options);
233
+ for (const name of names) vars.set(name, value);
234
+ }
235
+ return vars;
236
+ }
237
+ function renderBlock(selector, vars) {
238
+ const lines = [...vars].map(([name, value]) => ` --${name}: ${value};`);
239
+ if (lines.length === 0) return "";
240
+ return `${selector} {
241
+ ${lines.join("\n")}
242
+ }`;
243
+ }
244
+ function emitCss(tokens, options) {
245
+ const contextNames = Object.keys(options.contexts);
246
+ const useExportName = usesExportNames(
247
+ flattenForContext(tokens, contextNames[0]).values(),
248
+ options.nameExtension
249
+ );
250
+ const [baseContext, ...overrideContexts] = contextNames;
251
+ const baseVars = buildContextVars(tokens, baseContext, useExportName, options);
252
+ const blocks = [renderBlock(options.contexts[baseContext], baseVars)];
253
+ for (const context of overrideContexts) {
254
+ const vars = buildContextVars(tokens, context, useExportName, options);
255
+ const overrides = [...vars].filter(([name, value]) => baseVars.get(name) !== value);
256
+ const block = renderBlock(options.contexts[context], overrides);
257
+ if (block) blocks.push(block);
258
+ }
259
+ const header = "/* Generated by bezel \u2014 do not edit by hand. */\n/* Run `npm run tokens` (or `bezel build`) to regenerate. */\n";
260
+ return `${header}
261
+ ${blocks.filter(Boolean).join("\n\n")}
262
+ `;
263
+ }
264
+
265
+ // src/contexts.ts
266
+ var DEFAULT_CONTEXT_NAME = "default";
267
+ function isObject3(v) {
268
+ return typeof v === "object" && v !== null && !Array.isArray(v);
269
+ }
270
+ function isContextWrapper2(v) {
271
+ return isObject3(v) && "$value" in v;
272
+ }
273
+ function getContexts(tokens, rootName = DEFAULT_CONTEXT_NAME) {
274
+ const order = [];
275
+ const seen = /* @__PURE__ */ new Set();
276
+ const walk = (node) => {
277
+ if (ROOT_CONTEXT in node && isContextWrapper2(node[ROOT_CONTEXT])) {
278
+ for (const key of Object.keys(node)) {
279
+ if (key.startsWith("$") && key !== ROOT_CONTEXT) continue;
280
+ if (isContextWrapper2(node[key]) && !seen.has(key)) {
281
+ seen.add(key);
282
+ order.push(key);
283
+ }
284
+ }
285
+ return;
286
+ }
287
+ for (const key of Object.keys(node)) {
288
+ if (key.startsWith("$")) continue;
289
+ const child = node[key];
290
+ if (isObject3(child)) walk(child);
291
+ }
292
+ };
293
+ walk(tokens);
294
+ const mapped = order.map((k) => k === ROOT_CONTEXT ? rootName : k);
295
+ return [.../* @__PURE__ */ new Set([rootName, ...mapped])];
296
+ }
297
+ function formatContextsModule(contexts) {
298
+ const list = contexts.map((c) => JSON.stringify(c)).join(", ");
299
+ return `/* Generated by bezel \u2014 do not edit by hand. */
300
+ /* Run \`npm run tokens\` (or \`bezel build\`) to regenerate. */
301
+
302
+ export const CONTEXTS = [${list}] as const
303
+
304
+ export type Context = (typeof CONTEXTS)[number]
305
+ `;
306
+ }
307
+
308
+ // src/fonts.ts
309
+ var GENERIC_FAMILIES = /* @__PURE__ */ new Set([
310
+ "serif",
311
+ "sans-serif",
312
+ "monospace",
313
+ "cursive",
314
+ "fantasy",
315
+ "system-ui",
316
+ "ui-serif",
317
+ "ui-sans-serif",
318
+ "ui-monospace",
319
+ "ui-rounded",
320
+ "math",
321
+ "emoji",
322
+ "fangsong",
323
+ "inherit",
324
+ "initial",
325
+ "unset"
326
+ ]);
327
+ var DEFAULT_WEIGHT = 400;
328
+ function primaryFamily(value) {
329
+ const candidates = Array.isArray(value) ? value : [value];
330
+ for (const candidate of candidates) {
331
+ if (typeof candidate !== "string") continue;
332
+ const name = candidate.trim().replace(/^['"]|['"]$/g, "");
333
+ if (name && !GENERIC_FAMILIES.has(name.toLowerCase())) return name;
334
+ }
335
+ return null;
336
+ }
337
+ function parentPath(path) {
338
+ const i = path.lastIndexOf(".");
339
+ return i === -1 ? "" : path.slice(0, i);
340
+ }
341
+ function getFonts(tokens) {
342
+ const flat = resolveReferences(flattenForContext(tokens, ROOT_CONTEXT));
343
+ const families = /* @__PURE__ */ new Set();
344
+ const familyByParent = /* @__PURE__ */ new Map();
345
+ const weightByParent = /* @__PURE__ */ new Map();
346
+ for (const token of flat.values()) {
347
+ if (token.type === "fontFamily") {
348
+ const family = primaryFamily(token.value);
349
+ if (family) {
350
+ families.add(family);
351
+ familyByParent.set(parentPath(token.path), family);
352
+ }
353
+ } else if (token.type === "fontWeight" && typeof token.value === "number") {
354
+ weightByParent.set(parentPath(token.path), token.value);
355
+ }
356
+ }
357
+ const weightsByFamily = /* @__PURE__ */ new Map();
358
+ for (const [parent, family] of familyByParent) {
359
+ const weight = weightByParent.get(parent);
360
+ if (weight === void 0) continue;
361
+ const set = weightsByFamily.get(family) ?? /* @__PURE__ */ new Set();
362
+ set.add(weight);
363
+ weightsByFamily.set(family, set);
364
+ }
365
+ return [...families].sort().map((family) => {
366
+ const weights = weightsByFamily.get(family);
367
+ return {
368
+ family,
369
+ weights: weights ? [...weights].sort((a, b) => a - b) : [DEFAULT_WEIGHT]
370
+ };
371
+ });
372
+ }
373
+ function formatFontsModule(fonts) {
374
+ const entries = fonts.map((f) => ` { family: ${JSON.stringify(f.family)}, weights: [${f.weights.join(", ")}] },`).join("\n");
375
+ return `/* Generated by bezel \u2014 do not edit by hand. */
376
+ /* Run \`npm run tokens\` (or \`bezel build\`) to regenerate. */
377
+
378
+ export const FONTS = [
379
+ ${entries}
380
+ ] as const
381
+
382
+ export type FontDef = { family: string; weights: number[] }
383
+ `;
384
+ }
385
+
386
+ // src/gitignore.ts
387
+ var START = "# bezel:start (generated \u2014 do not edit)";
388
+ var END = "# bezel:end";
389
+ function mergeGitignore(existing, entries) {
390
+ const block = [START, ...entries, END].join("\n");
391
+ if (existing.trim() === "") return `${block}
392
+ `;
393
+ const start = existing.indexOf(START);
394
+ if (start !== -1) {
395
+ const endMarker = existing.indexOf(END, start);
396
+ if (endMarker !== -1) {
397
+ const before = existing.slice(0, start).replace(/\n+$/, "");
398
+ const after = existing.slice(endMarker + END.length).replace(/^\n+/, "");
399
+ const head = before === "" ? "" : `${before}
400
+
401
+ `;
402
+ const tail = after === "" ? "" : `
403
+
404
+ ${after.replace(/\n+$/, "")}`;
405
+ return `${head}${block}${tail}
406
+ `;
407
+ }
408
+ }
409
+ return `${existing.replace(/\n+$/, "")}
410
+
411
+ ${block}
412
+ `;
413
+ }
414
+
415
+ // src/node.ts
416
+ async function generateVariablesCss(options = {}) {
417
+ const resolved = resolveOptions(options);
418
+ let raw;
419
+ try {
420
+ raw = await (0, import_promises.readFile)(resolved.inputPath, "utf8");
421
+ } catch (err) {
422
+ throw new Error(
423
+ `bezel: could not read tokens file at "${resolved.inputPath}". A "design-tokens.json" file must exist at the project root.
424
+ ${err.message}`
425
+ );
426
+ }
427
+ let tokens;
428
+ try {
429
+ tokens = JSON.parse(raw);
430
+ } catch (err) {
431
+ throw new Error(`bezel: "${resolved.inputPath}" is not valid JSON.
432
+ ${err.message}`);
433
+ }
434
+ const css = emitCss(tokens, resolved);
435
+ if (resolved.write) {
436
+ await (0, import_promises.mkdir)((0, import_node_path2.dirname)(resolved.variablesOutputPath), { recursive: true });
437
+ await (0, import_promises.writeFile)(resolved.variablesOutputPath, css, "utf8");
438
+ if (resolved.contextsOutput) {
439
+ const contextsModule = formatContextsModule(getContexts(tokens));
440
+ await (0, import_promises.mkdir)((0, import_node_path2.dirname)(resolved.contextsOutput), { recursive: true });
441
+ await (0, import_promises.writeFile)(resolved.contextsOutput, contextsModule, "utf8");
442
+ }
443
+ if (resolved.fontsOutput) {
444
+ const fontsModule = formatFontsModule(getFonts(tokens));
445
+ await (0, import_promises.mkdir)((0, import_node_path2.dirname)(resolved.fontsOutput), { recursive: true });
446
+ await (0, import_promises.writeFile)(resolved.fontsOutput, fontsModule, "utf8");
447
+ }
448
+ if (resolved.gitignore) {
449
+ await updateGitignore(resolved);
450
+ }
451
+ }
452
+ return css;
453
+ }
454
+ async function updateGitignore(resolved) {
455
+ const dir = (0, import_node_path2.dirname)(resolved.gitignorePath);
456
+ const outputs = [
457
+ resolved.variablesOutputPath,
458
+ resolved.contextsOutput,
459
+ resolved.fontsOutput
460
+ ].filter((p) => p !== null);
461
+ const entries = [];
462
+ for (const output of outputs) {
463
+ const rel = (0, import_node_path2.relative)(dir, output);
464
+ if (rel === "" || rel.startsWith("..")) {
465
+ process.stderr.write(
466
+ `bezel: skipping .gitignore entry for "${output}" \u2014 outside ${resolved.gitignorePath}
467
+ `
468
+ );
469
+ continue;
470
+ }
471
+ entries.push(`/${rel.split(import_node_path2.sep).join("/")}`);
472
+ }
473
+ if (entries.length === 0) return;
474
+ let existing = "";
475
+ try {
476
+ existing = await (0, import_promises.readFile)(resolved.gitignorePath, "utf8");
477
+ } catch {
478
+ }
479
+ const next = mergeGitignore(existing, entries);
480
+ if (next !== existing) {
481
+ await (0, import_promises.mkdir)(dir, { recursive: true });
482
+ await (0, import_promises.writeFile)(resolved.gitignorePath, next, "utf8");
483
+ }
484
+ }
485
+
486
+ // src/cli.ts
487
+ var USAGE = `bezel \u2014 convert a W3C Design Tokens (DTCG) file into a scoped variables.css
488
+
489
+ Usage:
490
+ bezel build [options]
491
+
492
+ Reads design-tokens.json from the project root (the working directory).
493
+
494
+ Options:
495
+ -c, --config <path> Config file (.json or .js exporting BezelOptions)
496
+ --variables-output <path> Output CSS file (default: variables.css)
497
+ --contexts-output <path> Also write a generated TS module exporting CONTEXTS
498
+ --fonts-output <path> Also write a generated TS module exporting FONTS
499
+ --color <format> Color output: oklch | hex (default: oklch)
500
+ --unit <mode> Dimension unit: preserve | rem (default: preserve)
501
+ --stdout Print CSS to stdout instead of writing the file
502
+ --no-gitignore Don't create/update .gitignore for generated files
503
+ -h, --help Show this help
504
+
505
+ A bezel.json file in the working directory is loaded automatically when -c is omitted.
506
+ `;
507
+ var DEFAULT_CONFIG_FILE = "bezel.json";
508
+ async function loadConfig(path) {
509
+ const abs = (0, import_node_path3.resolve)(process.cwd(), path);
510
+ if (/\.json$/.test(abs)) {
511
+ return JSON.parse(await (0, import_promises2.readFile)(abs, "utf8"));
512
+ }
513
+ const mod = await import((0, import_node_url.pathToFileURL)(abs).href);
514
+ return mod.default ?? mod;
515
+ }
516
+ async function main(argv) {
517
+ const { values, positionals } = (0, import_node_util.parseArgs)({
518
+ args: argv,
519
+ allowPositionals: true,
520
+ options: {
521
+ config: { type: "string", short: "c" },
522
+ "variables-output": { type: "string" },
523
+ "contexts-output": { type: "string" },
524
+ "fonts-output": { type: "string" },
525
+ color: { type: "string" },
526
+ unit: { type: "string" },
527
+ stdout: { type: "boolean" },
528
+ "no-gitignore": { type: "boolean" },
529
+ help: { type: "boolean", short: "h" }
530
+ }
531
+ });
532
+ if (values.help || positionals[0] === "help") {
533
+ process.stdout.write(USAGE);
534
+ return;
535
+ }
536
+ const command = positionals[0] ?? "build";
537
+ if (command !== "build") {
538
+ process.stderr.write(`bezel: unknown command "${command}".
539
+
540
+ ${USAGE}`);
541
+ process.exitCode = 1;
542
+ return;
543
+ }
544
+ const configPath = values.config ?? ((0, import_node_fs.existsSync)((0, import_node_path3.resolve)(process.cwd(), DEFAULT_CONFIG_FILE)) ? DEFAULT_CONFIG_FILE : void 0);
545
+ const fileConfig = configPath ? await loadConfig(configPath) : {};
546
+ const options = { ...fileConfig };
547
+ if (values["variables-output"]) options.variablesOutput = values["variables-output"];
548
+ if (values["contexts-output"]) options.contextsOutput = values["contexts-output"];
549
+ if (values["fonts-output"]) options.fontsOutput = values["fonts-output"];
550
+ if (values.color) options.colorFormat = values.color;
551
+ if (values.unit) options.dimensionUnit = values.unit;
552
+ if (values.stdout) options.write = false;
553
+ if (values["no-gitignore"]) options.gitignore = false;
554
+ const css = await generateVariablesCss(options);
555
+ if (values.stdout) {
556
+ process.stdout.write(css);
557
+ } else {
558
+ process.stderr.write(`bezel: wrote ${options.variablesOutput ?? "variables.css"}
559
+ `);
560
+ }
561
+ }
562
+ main(process.argv.slice(2)).catch((err) => {
563
+ process.stderr.write(`${err instanceof Error ? err.message : String(err)}
564
+ `);
565
+ process.exitCode = 1;
566
+ });
567
+ //# sourceMappingURL=cli.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../src/node.ts","../src/config.ts","../src/defaults.ts","../src/options.ts","../src/collapse.ts","../src/name.ts","../src/resolve.ts","../src/serialize.ts","../src/emit.ts","../src/contexts.ts","../src/fonts.ts","../src/gitignore.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { existsSync } from \"node:fs\"\nimport { readFile } from \"node:fs/promises\"\nimport { pathToFileURL } from \"node:url\"\nimport { parseArgs } from \"node:util\"\nimport { resolve } from \"node:path\"\nimport { generateVariablesCss } from \"./node\"\nimport type { BezelOptions } from \"./config\"\n\nconst USAGE = `bezel — convert a W3C Design Tokens (DTCG) file into a scoped variables.css\n\nUsage:\n bezel build [options]\n\nReads design-tokens.json from the project root (the working directory).\n\nOptions:\n -c, --config <path> Config file (.json or .js exporting BezelOptions)\n --variables-output <path> Output CSS file (default: variables.css)\n --contexts-output <path> Also write a generated TS module exporting CONTEXTS\n --fonts-output <path> Also write a generated TS module exporting FONTS\n --color <format> Color output: oklch | hex (default: oklch)\n --unit <mode> Dimension unit: preserve | rem (default: preserve)\n --stdout Print CSS to stdout instead of writing the file\n --no-gitignore Don't create/update .gitignore for generated files\n -h, --help Show this help\n\nA bezel.json file in the working directory is loaded automatically when -c is omitted.\n`\n\n/** Default config file auto-loaded from the working directory when no -c is given. */\nconst DEFAULT_CONFIG_FILE = \"bezel.json\"\n\n/** Load options from a `.json` or `.js`/`.mjs` config file. */\nasync function loadConfig(path: string): Promise<BezelOptions> {\n const abs = resolve(process.cwd(), path)\n if (/\\.json$/.test(abs)) {\n return JSON.parse(await readFile(abs, \"utf8\")) as BezelOptions\n }\n const mod = (await import(pathToFileURL(abs).href)) as {\n default?: BezelOptions\n } & BezelOptions\n return (mod.default ?? mod) as BezelOptions\n}\n\nasync function main(argv: string[]): Promise<void> {\n const { values, positionals } = parseArgs({\n args: argv,\n allowPositionals: true,\n options: {\n config: { type: \"string\", short: \"c\" },\n \"variables-output\": { type: \"string\" },\n \"contexts-output\": { type: \"string\" },\n \"fonts-output\": { type: \"string\" },\n color: { type: \"string\" },\n unit: { type: \"string\" },\n stdout: { type: \"boolean\" },\n \"no-gitignore\": { type: \"boolean\" },\n help: { type: \"boolean\", short: \"h\" },\n },\n })\n\n if (values.help || positionals[0] === \"help\") {\n process.stdout.write(USAGE)\n return\n }\n\n const command = positionals[0] ?? \"build\"\n if (command !== \"build\") {\n process.stderr.write(`bezel: unknown command \"${command}\".\\n\\n${USAGE}`)\n process.exitCode = 1\n return\n }\n\n const configPath =\n values.config ??\n (existsSync(resolve(process.cwd(), DEFAULT_CONFIG_FILE))\n ? DEFAULT_CONFIG_FILE\n : undefined)\n const fileConfig = configPath ? await loadConfig(configPath) : {}\n\n const options: BezelOptions = { ...fileConfig }\n if (values[\"variables-output\"]) options.variablesOutput = values[\"variables-output\"]\n if (values[\"contexts-output\"]) options.contextsOutput = values[\"contexts-output\"]\n if (values[\"fonts-output\"]) options.fontsOutput = values[\"fonts-output\"]\n if (values.color) options.colorFormat = values.color as BezelOptions[\"colorFormat\"]\n if (values.unit) options.dimensionUnit = values.unit as BezelOptions[\"dimensionUnit\"]\n if (values.stdout) options.write = false\n if (values[\"no-gitignore\"]) options.gitignore = false\n\n const css = await generateVariablesCss(options)\n\n if (values.stdout) {\n process.stdout.write(css)\n } else {\n process.stderr.write(`bezel: wrote ${options.variablesOutput ?? \"variables.css\"}\\n`)\n }\n}\n\nmain(process.argv.slice(2)).catch((err: unknown) => {\n process.stderr.write(`${err instanceof Error ? err.message : String(err)}\\n`)\n process.exitCode = 1\n})\n","/**\n * bezel/node — Node entry.\n *\n * Re-exports the full isomorphic core, plus the filesystem conveniences:\n * read a DTCG tokens file and write the generated `variables.css` (and optional\n * `contexts.ts`/`fonts.ts`) to disk. This module imports `node:*` and is not\n * browser-safe; for the pure transform use `bezel`.\n */\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\"\nimport { dirname, relative, sep } from \"node:path\"\nimport { resolveOptions, type BezelOptions, type ResolvedOptions } from \"./config\"\nimport { emitCss } from \"./emit\"\nimport { formatContextsModule, getContexts } from \"./contexts\"\nimport { formatFontsModule, getFonts } from \"./fonts\"\nimport { mergeGitignore } from \"./gitignore\"\nimport type { DtcgNode } from \"./types\"\n\nexport * from \"./index\"\nexport { resolveOptions } from \"./config\"\nexport type { BezelOptions, ResolvedOptions } from \"./config\"\n\n/**\n * Generate a scoped `variables.css` from a W3C DTCG tokens file.\n *\n * Reads the tokens file, resolves each configured context (with `$root` fallback\n * and reference resolution), and writes one CSS scope per context — the base\n * context in full, others as override-only blocks. Returns the generated CSS.\n *\n * The tokens file is always read from `design-tokens.json` at the project root\n * (resolved against `cwd`); the name and location are fixed and not configurable.\n *\n * @example\n * // zero-config: ./design-tokens.json → ./variables.css\n * await generateVariablesCss()\n *\n * @example\n * await generateVariablesCss({\n * variablesOutput: \"packages/ui/src/styles/variables.css\",\n * })\n */\nexport async function generateVariablesCss(options: BezelOptions = {}): Promise<string> {\n const resolved = resolveOptions(options)\n\n let raw: string\n try {\n raw = await readFile(resolved.inputPath, \"utf8\")\n } catch (err) {\n throw new Error(\n `bezel: could not read tokens file at \"${resolved.inputPath}\". ` +\n `A \"design-tokens.json\" file must exist at the project root.\\n${(err as Error).message}`,\n )\n }\n\n let tokens: DtcgNode\n try {\n tokens = JSON.parse(raw) as DtcgNode\n } catch (err) {\n throw new Error(`bezel: \"${resolved.inputPath}\" is not valid JSON.\\n${(err as Error).message}`)\n }\n\n const css = emitCss(tokens, resolved)\n\n if (resolved.write) {\n await mkdir(dirname(resolved.variablesOutputPath), { recursive: true })\n await writeFile(resolved.variablesOutputPath, css, \"utf8\")\n\n if (resolved.contextsOutput) {\n const contextsModule = formatContextsModule(getContexts(tokens))\n await mkdir(dirname(resolved.contextsOutput), { recursive: true })\n await writeFile(resolved.contextsOutput, contextsModule, \"utf8\")\n }\n\n if (resolved.fontsOutput) {\n const fontsModule = formatFontsModule(getFonts(tokens))\n await mkdir(dirname(resolved.fontsOutput), { recursive: true })\n await writeFile(resolved.fontsOutput, fontsModule, \"utf8\")\n }\n\n if (resolved.gitignore) {\n await updateGitignore(resolved)\n }\n }\n\n return css\n}\n\n/**\n * Create or update the project `.gitignore` so the generated outputs are ignored.\n * Outputs are written as paths relative to the `.gitignore`, anchored with a leading\n * `/`. Outputs outside the `.gitignore`'s directory can't be anchored from it and are\n * skipped with a warning. The file is only rewritten when its contents actually change.\n */\nasync function updateGitignore(resolved: ResolvedOptions): Promise<void> {\n const dir = dirname(resolved.gitignorePath)\n const outputs = [\n resolved.variablesOutputPath,\n resolved.contextsOutput,\n resolved.fontsOutput,\n ].filter((p): p is string => p !== null)\n\n const entries: string[] = []\n for (const output of outputs) {\n const rel = relative(dir, output)\n if (rel === \"\" || rel.startsWith(\"..\")) {\n process.stderr.write(\n `bezel: skipping .gitignore entry for \"${output}\" — outside ${resolved.gitignorePath}\\n`,\n )\n continue\n }\n entries.push(`/${rel.split(sep).join(\"/\")}`)\n }\n\n if (entries.length === 0) return\n\n let existing = \"\"\n try {\n existing = await readFile(resolved.gitignorePath, \"utf8\")\n } catch {\n // No existing .gitignore — create one.\n }\n\n const next = mergeGitignore(existing, entries)\n if (next !== existing) {\n await mkdir(dir, { recursive: true })\n await writeFile(resolved.gitignorePath, next, \"utf8\")\n }\n}\n","import { isAbsolute, resolve } from \"node:path\"\nimport { DEFAULT_INPUT, DEFAULT_VARIABLES_OUTPUT } from \"./defaults\"\nimport { resolveCssOptions, type CssOptions } from \"./options\"\n\nexport { DEFAULT_CONTEXTS, DEFAULT_INPUT, DEFAULT_VARIABLES_OUTPUT, DEFAULT_NAME_EXTENSION } from \"./defaults\"\n\n/**\n * Options for {@link generateVariablesCss} — the Node, file-oriented surface.\n * Extends the pure {@link CssOptions} with input/output paths. All optional;\n * defaults make the zero-config case work.\n */\nexport interface BezelOptions extends CssOptions {\n /** Path to write the generated CSS. Default: `\"variables.css\"` (resolved from `cwd`). */\n variablesOutput?: string\n /** Base directory paths are resolved against. Default: `process.cwd()`. */\n cwd?: string\n /**\n * When set, also write a generated TypeScript module exporting `CONTEXTS` (the list of\n * context names derived from the tokens). Path resolved against `cwd`. Default: none.\n */\n contextsOutput?: string\n /**\n * When set, also write a generated TypeScript module exporting `FONTS` (the web fonts\n * derived from the tokens). Path resolved against `cwd`. Default: none.\n */\n fontsOutput?: string\n /** When `false`, return the CSS string without touching the filesystem. Default: `true`. */\n write?: boolean\n /**\n * Create/update a project `.gitignore` so the generated outputs are ignored. The\n * entries live in a marked block, rewritten on each run so renamed outputs are\n * cleaned up. Default: `true`.\n */\n gitignore?: boolean\n /** Path to the `.gitignore` to manage. Default: `\".gitignore\"` (resolved from `cwd`). */\n gitignorePath?: string\n}\n\n/** Fully-resolved options (no `undefined`), produced by {@link resolveOptions}. */\nexport interface ResolvedOptions {\n inputPath: string\n variablesOutputPath: string\n contexts: Record<string, string>\n colorFormat: \"oklch\" | \"hex\"\n dimensionUnit: \"preserve\" | \"rem\"\n nameExtension: string\n contextsOutput: string | null\n fontsOutput: string | null\n write: boolean\n gitignore: boolean\n gitignorePath: string\n}\n\n/** Apply defaults and resolve input/output paths against `cwd`. */\nexport function resolveOptions(options: BezelOptions = {}): ResolvedOptions {\n const cwd = options.cwd ?? process.cwd()\n const toAbs = (p: string) => (isAbsolute(p) ? p : resolve(cwd, p))\n\n const css = resolveCssOptions(options)\n\n return {\n // The tokens file is always `design-tokens.json` at the project root — not configurable.\n inputPath: toAbs(DEFAULT_INPUT),\n variablesOutputPath: toAbs(options.variablesOutput ?? DEFAULT_VARIABLES_OUTPUT),\n ...css,\n contextsOutput: options.contextsOutput ? toAbs(options.contextsOutput) : null,\n fontsOutput: options.fontsOutput ? toAbs(options.fontsOutput) : null,\n write: options.write ?? true,\n gitignore: options.gitignore ?? true,\n gitignorePath: toAbs(options.gitignorePath ?? \".gitignore\"),\n }\n}\n","/**\n * Pure default constants shared by the isomorphic core and the Node layer.\n * Kept free of `node:*` imports so the browser/edge entry can use them.\n */\n\n/** Default context → selector mapping. The first key is the base context. */\nexport const DEFAULT_CONTEXTS: Record<string, string> = {\n $root: \":root\",\n dark: \".dark\",\n light: \".light\",\n}\n\n/**\n * The DTCG input file the CLI reads from the project root. This is a cross-system\n * contract: it MUST stay in sync with the platform's `TOKENS_FILE_NAME` constant\n * (gundam: libs/keypuncher/data/constants/src/lib/tokens-file.ts) so any repo/app\n * the platform connects to resolves its tokens at the same name + location.\n */\nexport const DEFAULT_INPUT = \"design-tokens.json\"\nexport const DEFAULT_VARIABLES_OUTPUT = \"variables.css\"\nexport const DEFAULT_NAME_EXTENSION = \"com.tokendesigner.app\"\n","import { DEFAULT_CONTEXTS, DEFAULT_NAME_EXTENSION } from \"./defaults\"\n\n/**\n * Options for the pure CSS transform ({@link tokensToCss}/{@link emitCss}),\n * decoupled from any filesystem concern so they work in any environment.\n * All optional; defaults make the zero-config case work.\n */\nexport interface CssOptions {\n /**\n * Map of context name → CSS selector. The first entry is the base context (full\n * output); every other context emits only the variables that differ from the base.\n * Default: `{ \"$root\": \":root\", \"dark\": \".dark\", \"light\": \".light\" }`.\n */\n contexts?: Record<string, string>\n /** Color serialization. Default: `\"oklch\"`. */\n colorFormat?: \"oklch\" | \"hex\"\n /** Dimension handling: keep the authored unit, or convert `px` → `rem`. Default: `\"preserve\"`. */\n dimensionUnit?: \"preserve\" | \"rem\"\n /** `$extensions` key holding the `exportName` array. Default: `\"com.tokendesigner.app\"`. */\n nameExtension?: string\n}\n\n/** Fully-resolved CSS-transform options (no `undefined`). */\nexport interface ResolvedCssOptions {\n contexts: Record<string, string>\n colorFormat: \"oklch\" | \"hex\"\n dimensionUnit: \"preserve\" | \"rem\"\n nameExtension: string\n}\n\n/** Apply defaults to {@link CssOptions}. Pure — no path resolution, no `node:*`. */\nexport function resolveCssOptions(options: CssOptions = {}): ResolvedCssOptions {\n const contexts = options.contexts ?? DEFAULT_CONTEXTS\n if (Object.keys(contexts).length === 0) {\n throw new Error(\"bezel: `contexts` must define at least one context.\")\n }\n\n return {\n contexts,\n colorFormat: options.colorFormat ?? \"oklch\",\n dimensionUnit: options.dimensionUnit ?? \"preserve\",\n nameExtension: options.nameExtension ?? DEFAULT_NAME_EXTENSION,\n }\n}\n","import type { DtcgNode, FlatToken, TokenValue } from \"./types\"\n\n/** The W3C \"root token\" key — the base value of a group / logical token. */\nexport const ROOT_CONTEXT = \"$root\"\n\nfunction isObject(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v)\n}\n\n/** A \"context wrapper\" is a child object that directly holds a `$value` (e.g. `dark`, `light`, `$root`). */\nfunction isContextWrapper(v: unknown): v is DtcgNode {\n return isObject(v) && \"$value\" in v\n}\n\n/** Keys that are DTCG metadata, never traversed as child tokens/contexts. */\nfunction isMetaKey(key: string): boolean {\n return key === \"$type\" || key === \"$description\" || key === \"$extensions\" || key === \"$value\"\n}\n\n/**\n * Collapse a DTCG token tree to the single value that applies for `context`, and\n * flatten it to a map of dot-path → {@link FlatToken}.\n *\n * Handles three node shapes:\n * - **Simple token** — a node with a direct `$value` (context-invariant).\n * - **Logical token** — a node whose children include context wrappers (one of\n * which is `$root`). The value for `context` is picked, falling back to `$root`.\n * - **Group** — anything else; recursed into.\n *\n * `$type` is inherited from the nearest ancestor that declares one.\n */\nexport function flattenForContext(tokens: DtcgNode, context: string): Map<string, FlatToken> {\n const out = new Map<string, FlatToken>()\n\n const walk = (node: DtcgNode, path: string, inheritedType: string | undefined): void => {\n const type = typeof node.$type === \"string\" ? node.$type : inheritedType\n\n // Simple token: direct $value.\n if (\"$value\" in node) {\n out.set(path, {\n path,\n value: node.$value as TokenValue,\n type,\n extensions: node.$extensions,\n })\n return\n }\n\n // Logical token: has context-wrapper children (dark/light/$root).\n const wrapperKeys = Object.keys(node).filter((k) => !isMetaKey(k) && isContextWrapper(node[k]))\n if (wrapperKeys.length > 0) {\n const chosen =\n (node[context] as DtcgNode | undefined) ??\n (node[ROOT_CONTEXT] as DtcgNode | undefined) ??\n (node[wrapperKeys[0]!] as DtcgNode)\n out.set(path, {\n path,\n value: chosen.$value as TokenValue,\n type,\n extensions: node.$extensions,\n })\n return\n }\n\n // Group: recurse into non-meta children.\n for (const key of Object.keys(node)) {\n if (isMetaKey(key)) continue\n const child = node[key]\n if (isObject(child)) {\n walk(child as DtcgNode, path ? `${path}.${key}` : key, type)\n }\n }\n }\n\n walk(tokens, \"\", undefined)\n return out\n}\n","import type { FlatToken } from \"./types\"\n\n/** Leading path segments dropped when deriving a CSS name from a token path. */\nconst DROPPED_PREFIXES = new Set([\"base\", \"semantic\"])\n/** Trailing path segments dropped (a group's \"default\"/root token maps to the bare group name). */\nconst DROPPED_SUFFIXES = new Set([\"default\", \"$root\"])\n\nfunction exportNames(token: FlatToken, nameExtension: string): string[] | undefined {\n const ext = token.extensions?.[nameExtension]\n if (ext && typeof ext === \"object\" && \"exportName\" in ext) {\n const names = (ext as { exportName: unknown }).exportName\n if (Array.isArray(names)) return names.filter((n): n is string => typeof n === \"string\")\n }\n return undefined\n}\n\n/** True if any token in the map declares an `exportName` under `nameExtension`. */\nexport function usesExportNames(\n tokens: Iterable<FlatToken>,\n nameExtension: string,\n): boolean {\n for (const token of tokens) {\n if (exportNames(token, nameExtension) !== undefined) return true\n }\n return false\n}\n\n/** Derive a CSS variable name from a dot-path (fallback when no `exportName` exists). */\nexport function nameFromPath(path: string): string {\n const segments = path.split(\".\")\n while (segments.length > 1 && DROPPED_PREFIXES.has(segments[0]!)) segments.shift()\n while (segments.length > 1 && DROPPED_SUFFIXES.has(segments[segments.length - 1]!)) {\n segments.pop()\n }\n return segments.join(\"-\")\n}\n\n/**\n * Resolve the CSS variable name(s) a token emits (without the leading `--`).\n *\n * - In **exportName mode** (`useExportName`), names come solely from the token's\n * `exportName` array. A token without one — or with only empty strings — emits\n * nothing (it exists purely as a reference target). One token may emit many names.\n * - Otherwise (generic DTCG), the name is derived from the token's path.\n */\nexport function cssNames(\n token: FlatToken,\n nameExtension: string,\n useExportName: boolean,\n): string[] {\n if (useExportName) {\n const names = exportNames(token, nameExtension)\n if (!names) return []\n return names.filter((n) => n.length > 0)\n }\n return [nameFromPath(token.path)]\n}\n","import type { FlatToken, TokenValue } from \"./types\"\n\nconst REFERENCE_RE = /^\\{([^{}]+)\\}$/\n\n/** Returns the referenced path if `value` is a whole-value DTCG alias `\"{a.b.c}\"`, else `null`. */\nexport function aliasTarget(value: TokenValue): string | null {\n if (typeof value !== \"string\") return null\n const match = REFERENCE_RE.exec(value.trim())\n return match ? match[1]!.trim() : null\n}\n\n/**\n * Resolve whole-value references (`\"{a.b.c}\"`) in a flattened, single-context token\n * map, in place. Because the map was collapsed for one context, following an alias\n * yields that context's value (with `$root` fallback already applied during collapse).\n *\n * Multi-hop aliases are followed, results memoized, and cycles guarded against.\n */\nexport function resolveReferences(tokens: Map<string, FlatToken>): Map<string, FlatToken> {\n const resolved = new Map<string, TokenValue>()\n\n const resolveValue = (value: TokenValue, seen: Set<string>): TokenValue => {\n const target = aliasTarget(value)\n if (target === null) return value\n\n if (resolved.has(target)) return resolved.get(target)!\n if (seen.has(target)) {\n throw new Error(`bezel: circular token reference detected at \"{${target}}\".`)\n }\n\n const token = tokens.get(target)\n if (!token) {\n throw new Error(`bezel: unresolved token reference \"{${target}}\".`)\n }\n\n seen.add(target)\n const value2 = resolveValue(token.value, seen)\n seen.delete(target)\n resolved.set(target, value2)\n return value2\n }\n\n for (const token of tokens.values()) {\n token.value = resolveValue(token.value, new Set())\n }\n return tokens\n}\n","import type { ResolvedCssOptions } from \"./options\"\nimport type {\n ColorValue,\n DimensionValue,\n TokenValue,\n} from \"./types\"\n\nfunction isObject(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v)\n}\n\nfunction isColor(v: unknown): v is ColorValue {\n return isObject(v) && \"colorSpace\" in v && Array.isArray(v[\"components\"])\n}\n\nfunction isDimension(v: unknown): v is DimensionValue {\n return isObject(v) && typeof v[\"value\"] === \"number\" && \"unit\" in v\n}\n\n/** Round to at most `dp` decimals without trailing zeros. */\nfunction round(n: number, dp: number): number {\n const f = 10 ** dp\n return Math.round(n * f) / f\n}\n\nfunction serializeColor(color: ColorValue, format: ResolvedCssOptions[\"colorFormat\"]): string {\n if (format === \"hex\" && color.hex) return color.hex.toLowerCase()\n\n if (color.colorSpace === \"oklch\") {\n const [l = 0, c = 0, h = 0] = color.components\n const base = `oklch(${round(l, 4)} ${round(c, 4)} ${round(h, 3)})`\n if (color.alpha !== undefined && color.alpha < 1) {\n return `oklch(${round(l, 4)} ${round(c, 4)} ${round(h, 3)} / ${round(color.alpha, 4)})`\n }\n return base\n }\n\n // Unknown color space: prefer hex fallback, else CSS color() function.\n if (color.hex) return color.hex.toLowerCase()\n return `color(${color.colorSpace} ${color.components.map((n) => round(n, 4)).join(\" \")})`\n}\n\nfunction serializeDimension(dim: DimensionValue, unit: ResolvedCssOptions[\"dimensionUnit\"]): string {\n if (unit === \"rem\" && dim.unit === \"px\") {\n return `${round(dim.value / 16, 4)}rem`\n }\n return `${dim.value}${dim.unit}`\n}\n\n/** Quote a font-family name if it contains whitespace and isn't already quoted. */\nfunction quoteFamily(name: string): string {\n const trimmed = name.trim()\n if (/^['\"].*['\"]$/.test(trimmed)) return trimmed\n return /\\s/.test(trimmed) ? `\"${trimmed}\"` : trimmed\n}\n\n/** Serialize a resolved token value to a CSS declaration value. */\nexport function serializeValue(value: TokenValue, options: ResolvedCssOptions): string {\n if (isColor(value)) return serializeColor(value, options.colorFormat)\n if (isDimension(value)) return serializeDimension(value, options.dimensionUnit)\n\n // fontFamily as an array of names.\n if (Array.isArray(value)) {\n return value.map((v) => quoteFamily(String(v))).join(\", \")\n }\n\n if (typeof value === \"number\") return String(value)\n\n // Strings: could be a single font-family name or an already-formatted value.\n // Quote multi-word family names; leave comma-lists and plain values untouched.\n const str = String(value)\n if (/\\s/.test(str) && !str.includes(\",\") && !/[()]/.test(str)) {\n return quoteFamily(str)\n }\n return str\n}\n","import { flattenForContext } from \"./collapse\"\nimport { cssNames, usesExportNames } from \"./name\"\nimport { resolveReferences } from \"./resolve\"\nimport { serializeValue } from \"./serialize\"\nimport type { ResolvedCssOptions } from \"./options\"\nimport type { DtcgNode } from \"./types\"\n\n/** An ordered map of CSS variable name → serialized value for one context. */\ntype VarMap = Map<string, string>\n\n/** Build the `name → cssValue` map for a single context. */\nfunction buildContextVars(\n tokens: DtcgNode,\n context: string,\n useExportName: boolean,\n options: ResolvedCssOptions,\n): VarMap {\n const flat = resolveReferences(flattenForContext(tokens, context))\n const vars: VarMap = new Map()\n for (const token of flat.values()) {\n const names = cssNames(token, options.nameExtension, useExportName)\n if (names.length === 0) continue\n const value = serializeValue(token.value, options)\n for (const name of names) vars.set(name, value)\n }\n return vars\n}\n\nfunction renderBlock(selector: string, vars: Iterable<[string, string]>): string {\n const lines = [...vars].map(([name, value]) => ` --${name}: ${value};`)\n if (lines.length === 0) return \"\"\n return `${selector} {\\n${lines.join(\"\\n\")}\\n}`\n}\n\n/**\n * Convert a DTCG token tree into a scoped CSS string. The first context in\n * `options.contexts` is the base (emitted in full); every other context emits\n * only the variables whose value differs from the base.\n */\nexport function emitCss(tokens: DtcgNode, options: ResolvedCssOptions): string {\n const contextNames = Object.keys(options.contexts)\n const useExportName = usesExportNames(\n flattenForContext(tokens, contextNames[0]!).values(),\n options.nameExtension,\n )\n\n const [baseContext, ...overrideContexts] = contextNames\n const baseVars = buildContextVars(tokens, baseContext!, useExportName, options)\n\n const blocks: string[] = [renderBlock(options.contexts[baseContext!]!, baseVars)]\n\n for (const context of overrideContexts) {\n const vars = buildContextVars(tokens, context, useExportName, options)\n const overrides = [...vars].filter(([name, value]) => baseVars.get(name) !== value)\n const block = renderBlock(options.contexts[context]!, overrides)\n if (block) blocks.push(block)\n }\n\n const header =\n \"/* Generated by bezel — do not edit by hand. */\\n\" +\n \"/* Run `npm run tokens` (or `bezel build`) to regenerate. */\\n\"\n return `${header}\\n${blocks.filter(Boolean).join(\"\\n\\n\")}\\n`\n}\n","import { ROOT_CONTEXT } from \"./collapse\"\nimport type { DtcgNode } from \"./types\"\n\n/** Name the `$root` context maps to in generated output (matches the `:root` CSS scope). */\nexport const DEFAULT_CONTEXT_NAME = \"default\"\n\nfunction isObject(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v)\n}\n\nfunction isContextWrapper(v: unknown): boolean {\n return isObject(v) && \"$value\" in v\n}\n\n/**\n * Extract the distinct context names declared anywhere in a DTCG token tree.\n *\n * Walks to each logical token (a node with a `$root` context wrapper) and collects the\n * context keys it declares (`$root`, `dark`, `light`, …). `$root` is mapped to\n * `\"default\"` and placed first; the rest follow in first-seen order, deduped.\n */\nexport function getContexts(tokens: DtcgNode, rootName: string = DEFAULT_CONTEXT_NAME): string[] {\n const order: string[] = []\n const seen = new Set<string>()\n\n const walk = (node: DtcgNode): void => {\n if (ROOT_CONTEXT in node && isContextWrapper(node[ROOT_CONTEXT])) {\n for (const key of Object.keys(node)) {\n if (key.startsWith(\"$\") && key !== ROOT_CONTEXT) continue\n if (isContextWrapper(node[key]) && !seen.has(key)) {\n seen.add(key)\n order.push(key)\n }\n }\n return\n }\n for (const key of Object.keys(node)) {\n if (key.startsWith(\"$\")) continue\n const child = node[key]\n if (isObject(child)) walk(child as DtcgNode)\n }\n }\n\n walk(tokens)\n\n const mapped = order.map((k) => (k === ROOT_CONTEXT ? rootName : k))\n return [...new Set([rootName, ...mapped])]\n}\n\n/** Render the generated `contexts.ts` module emitted alongside `variables.css`. */\nexport function formatContextsModule(contexts: string[]): string {\n const list = contexts.map((c) => JSON.stringify(c)).join(\", \")\n return (\n \"/* Generated by bezel — do not edit by hand. */\\n\" +\n \"/* Run `npm run tokens` (or `bezel build`) to regenerate. */\\n\\n\" +\n `export const CONTEXTS = [${list}] as const\\n\\n` +\n \"export type Context = (typeof CONTEXTS)[number]\\n\"\n )\n}\n","import { flattenForContext, ROOT_CONTEXT } from \"./collapse\"\nimport { resolveReferences } from \"./resolve\"\nimport type { DtcgNode, TokenValue } from \"./types\"\n\n/** A web font to load: a family name and the weights it is used at. */\nexport interface FontDef {\n family: string\n weights: number[]\n}\n\n/** Generic CSS family keywords that are never loaded as web fonts. */\nconst GENERIC_FAMILIES = new Set([\n \"serif\",\n \"sans-serif\",\n \"monospace\",\n \"cursive\",\n \"fantasy\",\n \"system-ui\",\n \"ui-serif\",\n \"ui-sans-serif\",\n \"ui-monospace\",\n \"ui-rounded\",\n \"math\",\n \"emoji\",\n \"fangsong\",\n \"inherit\",\n \"initial\",\n \"unset\",\n])\n\nconst DEFAULT_WEIGHT = 400\n\n/** Resolve a fontFamily token value to a primary family name (first non-generic), or null. */\nfunction primaryFamily(value: TokenValue): string | null {\n const candidates = Array.isArray(value) ? value : [value]\n for (const candidate of candidates) {\n if (typeof candidate !== \"string\") continue\n const name = candidate.trim().replace(/^['\"]|['\"]$/g, \"\")\n if (name && !GENERIC_FAMILIES.has(name.toLowerCase())) return name\n }\n return null\n}\n\nfunction parentPath(path: string): string {\n const i = path.lastIndexOf(\".\")\n return i === -1 ? \"\" : path.slice(0, i)\n}\n\n/**\n * Extract the web fonts referenced by a DTCG token tree.\n *\n * Collects every distinct `fontFamily` value (references resolved), then derives each\n * family's weights from the semantic typography composites — a group whose `font-family`\n * resolves to that family contributes its sibling `font-weight`. Families used without an\n * accompanying weight default to `[400]`. Result is sorted by family for determinism.\n */\nexport function getFonts(tokens: DtcgNode): FontDef[] {\n const flat = resolveReferences(flattenForContext(tokens, ROOT_CONTEXT))\n\n const families = new Set<string>()\n const familyByParent = new Map<string, string>()\n const weightByParent = new Map<string, number>()\n\n for (const token of flat.values()) {\n if (token.type === \"fontFamily\") {\n const family = primaryFamily(token.value)\n if (family) {\n families.add(family)\n familyByParent.set(parentPath(token.path), family)\n }\n } else if (token.type === \"fontWeight\" && typeof token.value === \"number\") {\n weightByParent.set(parentPath(token.path), token.value)\n }\n }\n\n const weightsByFamily = new Map<string, Set<number>>()\n for (const [parent, family] of familyByParent) {\n const weight = weightByParent.get(parent)\n if (weight === undefined) continue\n const set = weightsByFamily.get(family) ?? new Set<number>()\n set.add(weight)\n weightsByFamily.set(family, set)\n }\n\n return [...families].sort().map((family) => {\n const weights = weightsByFamily.get(family)\n return {\n family,\n weights: weights ? [...weights].sort((a, b) => a - b) : [DEFAULT_WEIGHT],\n }\n })\n}\n\n/** Render the generated `fonts.ts` module emitted alongside `variables.css`. */\nexport function formatFontsModule(fonts: FontDef[]): string {\n const entries = fonts\n .map((f) => ` { family: ${JSON.stringify(f.family)}, weights: [${f.weights.join(\", \")}] },`)\n .join(\"\\n\")\n return (\n \"/* Generated by bezel — do not edit by hand. */\\n\" +\n \"/* Run `npm run tokens` (or `bezel build`) to regenerate. */\\n\\n\" +\n `export const FONTS = [\\n${entries}\\n] as const\\n\\n` +\n \"export type FontDef = { family: string; weights: number[] }\\n\"\n )\n}\n","/**\n * bezel — `.gitignore` managed-block merging.\n *\n * Pure string transforms (no `node:fs`): given the existing `.gitignore` contents\n * and the list of generated outputs to ignore, produce the new contents. Bezel's\n * entries live inside a marked block so repeated runs rewrite just that span —\n * renamed/removed outputs drop out automatically and entries never duplicate, while\n * the user's own rules outside the markers are preserved.\n */\n\n/** Opening marker for the Bezel-managed block. */\nexport const START = \"# bezel:start (generated — do not edit)\"\n/** Closing marker for the Bezel-managed block. */\nexport const END = \"# bezel:end\"\n\n/**\n * Merge Bezel's managed block into existing `.gitignore` contents.\n *\n * - Empty `existing` → just the block.\n * - An existing block (delimited by {@link START}…{@link END}) → replaced in place,\n * preserving everything before and after.\n * - No block → appended after the existing content, separated by a blank line.\n *\n * The result always ends with a single trailing newline.\n */\nexport function mergeGitignore(existing: string, entries: string[]): string {\n const block = [START, ...entries, END].join(\"\\n\")\n\n if (existing.trim() === \"\") return `${block}\\n`\n\n const start = existing.indexOf(START)\n if (start !== -1) {\n const endMarker = existing.indexOf(END, start)\n if (endMarker !== -1) {\n const before = existing.slice(0, start).replace(/\\n+$/, \"\")\n const after = existing.slice(endMarker + END.length).replace(/^\\n+/, \"\")\n const head = before === \"\" ? \"\" : `${before}\\n\\n`\n const tail = after === \"\" ? \"\" : `\\n\\n${after.replace(/\\n+$/, \"\")}`\n return `${head}${block}${tail}\\n`\n }\n }\n\n return `${existing.replace(/\\n+$/, \"\")}\\n\\n${block}\\n`\n}\n"],"mappings":"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","names":["import_promises","import_node_path","import_node_path","isObject","isObject","isContextWrapper"]}