@bezel-labs/bezel-kit 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,36 +1,56 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- generateVariablesCss
4
- } from "./chunk-WLGTZBXW.js";
5
- import "./chunk-5EW7EW3R.js";
3
+ generateVariablesCss,
4
+ initConfig,
5
+ readPackageScripts
6
+ } from "./chunk-FGX7KW2Z.js";
7
+ import {
8
+ DEFAULT_CONFIG_FILE,
9
+ DEFAULT_VARIABLES_OUTPUT
10
+ } from "./chunk-T6DKROBI.js";
6
11
 
7
12
  // src/cli.ts
8
13
  import { existsSync } from "fs";
9
14
  import { readFile } from "fs/promises";
10
15
  import { pathToFileURL } from "url";
11
16
  import { parseArgs } from "util";
12
- import { resolve } from "path";
17
+ import { relative, resolve } from "path";
13
18
  var USAGE = `bezel \u2014 convert a W3C Design Tokens (DTCG) file into a scoped variables.css
14
19
 
15
20
  Usage:
16
- bezel build [options]
21
+ bezel init [options] Create a bezel.json for this project
22
+ bezel build [options] Generate the outputs (default command)
17
23
 
18
24
  Reads design-tokens.json from the project root (the working directory).
19
25
 
20
- Options:
26
+ init options:
27
+ --dir <path> Directory for all outputs
28
+ (default: src/bezel, or bezel with no src/)
29
+ --variables-output <path> Override just the CSS path
30
+ --contexts-output <path> Override just the contexts module path
31
+ --fonts-output <path> Override just the fonts module path
32
+ --no-contexts Skip the generated CONTEXTS module
33
+ --no-fonts Skip the generated FONTS module
34
+ --color <format> Color output: oklch | hex (default: oklch)
35
+ --unit <mode> Dimension unit: preserve | rem (default: preserve)
36
+ -f, --force Overwrite an existing bezel.json
37
+
38
+ build options:
21
39
  -c, --config <path> Config file (.json or .js exporting BezelOptions)
22
- --variables-output <path> Output CSS file (default: variables.css)
40
+ --variables-output <path> Output CSS file (default: ${DEFAULT_VARIABLES_OUTPUT})
23
41
  --contexts-output <path> Also write a generated TS module exporting CONTEXTS
24
42
  --fonts-output <path> Also write a generated TS module exporting FONTS
25
43
  --color <format> Color output: oklch | hex (default: oklch)
26
44
  --unit <mode> Dimension unit: preserve | rem (default: preserve)
27
45
  --stdout Print CSS to stdout instead of writing the file
28
46
  --no-gitignore Don't create/update .gitignore for generated files
47
+
29
48
  -h, --help Show this help
30
49
 
31
- A bezel.json file in the working directory is loaded automatically when -c is omitted.
50
+ A ${DEFAULT_CONFIG_FILE} file in the working directory is loaded automatically when -c is omitted.
51
+ The contexts/fonts modules are TypeScript, so init only scaffolds them for a
52
+ TypeScript project unless you pass the paths explicitly.
32
53
  `;
33
- var DEFAULT_CONFIG_FILE = "bezel.json";
34
54
  async function loadConfig(path) {
35
55
  const abs = resolve(process.cwd(), path);
36
56
  if (/\.json$/.test(abs)) {
@@ -39,34 +59,71 @@ async function loadConfig(path) {
39
59
  const mod = await import(pathToFileURL(abs).href);
40
60
  return mod.default ?? mod;
41
61
  }
42
- async function main(argv) {
43
- const { values, positionals } = parseArgs({
44
- args: argv,
45
- allowPositionals: true,
46
- options: {
47
- config: { type: "string", short: "c" },
48
- "variables-output": { type: "string" },
49
- "contexts-output": { type: "string" },
50
- "fonts-output": { type: "string" },
51
- color: { type: "string" },
52
- unit: { type: "string" },
53
- stdout: { type: "boolean" },
54
- "no-gitignore": { type: "boolean" },
55
- help: { type: "boolean", short: "h" }
56
- }
62
+ var OPTIONS = {
63
+ config: { type: "string", short: "c" },
64
+ dir: { type: "string" },
65
+ "variables-output": { type: "string" },
66
+ "contexts-output": { type: "string" },
67
+ "fonts-output": { type: "string" },
68
+ color: { type: "string" },
69
+ unit: { type: "string" },
70
+ stdout: { type: "boolean" },
71
+ "no-gitignore": { type: "boolean" },
72
+ "no-contexts": { type: "boolean" },
73
+ "no-fonts": { type: "boolean" },
74
+ force: { type: "boolean", short: "f" },
75
+ help: { type: "boolean", short: "h" }
76
+ };
77
+ async function runInit(values) {
78
+ const cwd = process.cwd();
79
+ const result = await initConfig({
80
+ cwd,
81
+ outputDir: values.dir,
82
+ variablesOutput: values["variables-output"],
83
+ contextsOutput: values["contexts-output"],
84
+ fontsOutput: values["fonts-output"],
85
+ contexts: values["no-contexts"] ? false : void 0,
86
+ fonts: values["no-fonts"] ? false : void 0,
87
+ colorFormat: values.color,
88
+ dimensionUnit: values.unit,
89
+ force: values.force
57
90
  });
58
- if (values.help || positionals[0] === "help") {
59
- process.stdout.write(USAGE);
60
- return;
61
- }
62
- const command = positionals[0] ?? "build";
63
- if (command !== "build") {
64
- process.stderr.write(`bezel: unknown command "${command}".
65
-
66
- ${USAGE}`);
91
+ const configName = relative(cwd, result.configPath) || DEFAULT_CONFIG_FILE;
92
+ if (!result.written) {
93
+ process.stderr.write(
94
+ `bezel: ${configName} already exists \u2014 leaving it alone. Re-run with --force to overwrite.
95
+ `
96
+ );
67
97
  process.exitCode = 1;
68
98
  return;
69
99
  }
100
+ const outputs = [
101
+ result.config.variablesOutput,
102
+ result.config.contextsOutput,
103
+ result.config.fontsOutput
104
+ ].filter((p) => p !== void 0);
105
+ process.stderr.write(`bezel: wrote ${configName}
106
+ `);
107
+ for (const output of outputs) {
108
+ process.stderr.write(`bezel: ${output}
109
+ `);
110
+ }
111
+ const scripts = await readPackageScripts(cwd);
112
+ const steps = [];
113
+ if (!result.hasTokensFile) {
114
+ steps.push(
115
+ "Add design-tokens.json to the project root \u2014 ask your AI agent for it via the\n Bezel MCP, or download it from your project."
116
+ );
117
+ }
118
+ if (!scripts["tokens"]) {
119
+ steps.push('Add "tokens": "bezel build" to your package.json scripts.');
120
+ }
121
+ steps.push(`Run the build, then import ${result.config.variablesOutput} in your entry file.`);
122
+ process.stderr.write("\nNext:\n");
123
+ steps.forEach((step, i) => process.stderr.write(` ${i + 1}. ${step}
124
+ `));
125
+ }
126
+ async function runBuild(values) {
70
127
  const configPath = values.config ?? (existsSync(resolve(process.cwd(), DEFAULT_CONFIG_FILE)) ? DEFAULT_CONFIG_FILE : void 0);
71
128
  const fileConfig = configPath ? await loadConfig(configPath) : {};
72
129
  const options = { ...fileConfig };
@@ -81,10 +138,34 @@ ${USAGE}`);
81
138
  if (values.stdout) {
82
139
  process.stdout.write(css);
83
140
  } else {
84
- process.stderr.write(`bezel: wrote ${options.variablesOutput ?? "variables.css"}
141
+ process.stderr.write(`bezel: wrote ${options.variablesOutput ?? DEFAULT_VARIABLES_OUTPUT}
85
142
  `);
86
143
  }
87
144
  }
145
+ async function main(argv) {
146
+ const { values, positionals } = parseArgs({
147
+ args: argv,
148
+ allowPositionals: true,
149
+ options: OPTIONS
150
+ });
151
+ if (values.help || positionals[0] === "help") {
152
+ process.stdout.write(USAGE);
153
+ return;
154
+ }
155
+ const command = positionals[0] ?? "build";
156
+ if (command === "init") {
157
+ await runInit(values);
158
+ return;
159
+ }
160
+ if (command !== "build") {
161
+ process.stderr.write(`bezel: unknown command "${command}".
162
+
163
+ ${USAGE}`);
164
+ process.exitCode = 1;
165
+ return;
166
+ }
167
+ await runBuild(values);
168
+ }
88
169
  main(process.argv.slice(2)).catch((err) => {
89
170
  process.stderr.write(`${err instanceof Error ? err.message : String(err)}
90
171
  `);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.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"],"mappings":";;;;;;;AACA,SAAS,kBAAkB;AAC3B,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AAC9B,SAAS,iBAAiB;AAC1B,SAAS,eAAe;AAIxB,IAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsBd,IAAM,sBAAsB;AAG5B,eAAe,WAAW,MAAqC;AAC7D,QAAM,MAAM,QAAQ,QAAQ,IAAI,GAAG,IAAI;AACvC,MAAI,UAAU,KAAK,GAAG,GAAG;AACvB,WAAO,KAAK,MAAM,MAAM,SAAS,KAAK,MAAM,CAAC;AAAA,EAC/C;AACA,QAAM,MAAO,MAAM,OAAO,cAAc,GAAG,EAAE;AAG7C,SAAQ,IAAI,WAAW;AACzB;AAEA,eAAe,KAAK,MAA+B;AACjD,QAAM,EAAE,QAAQ,YAAY,IAAI,UAAU;AAAA,IACxC,MAAM;AAAA,IACN,kBAAkB;AAAA,IAClB,SAAS;AAAA,MACP,QAAQ,EAAE,MAAM,UAAU,OAAO,IAAI;AAAA,MACrC,oBAAoB,EAAE,MAAM,SAAS;AAAA,MACrC,mBAAmB,EAAE,MAAM,SAAS;AAAA,MACpC,gBAAgB,EAAE,MAAM,SAAS;AAAA,MACjC,OAAO,EAAE,MAAM,SAAS;AAAA,MACxB,MAAM,EAAE,MAAM,SAAS;AAAA,MACvB,QAAQ,EAAE,MAAM,UAAU;AAAA,MAC1B,gBAAgB,EAAE,MAAM,UAAU;AAAA,MAClC,MAAM,EAAE,MAAM,WAAW,OAAO,IAAI;AAAA,IACtC;AAAA,EACF,CAAC;AAED,MAAI,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ;AAC5C,YAAQ,OAAO,MAAM,KAAK;AAC1B;AAAA,EACF;AAEA,QAAM,UAAU,YAAY,CAAC,KAAK;AAClC,MAAI,YAAY,SAAS;AACvB,YAAQ,OAAO,MAAM,2BAA2B,OAAO;AAAA;AAAA,EAAS,KAAK,EAAE;AACvE,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,QAAM,aACJ,OAAO,WACN,WAAW,QAAQ,QAAQ,IAAI,GAAG,mBAAmB,CAAC,IACnD,sBACA;AACN,QAAM,aAAa,aAAa,MAAM,WAAW,UAAU,IAAI,CAAC;AAEhE,QAAM,UAAwB,EAAE,GAAG,WAAW;AAC9C,MAAI,OAAO,kBAAkB,EAAG,SAAQ,kBAAkB,OAAO,kBAAkB;AACnF,MAAI,OAAO,iBAAiB,EAAG,SAAQ,iBAAiB,OAAO,iBAAiB;AAChF,MAAI,OAAO,cAAc,EAAG,SAAQ,cAAc,OAAO,cAAc;AACvE,MAAI,OAAO,MAAO,SAAQ,cAAc,OAAO;AAC/C,MAAI,OAAO,KAAM,SAAQ,gBAAgB,OAAO;AAChD,MAAI,OAAO,OAAQ,SAAQ,QAAQ;AACnC,MAAI,OAAO,cAAc,EAAG,SAAQ,YAAY;AAEhD,QAAM,MAAM,MAAM,qBAAqB,OAAO;AAE9C,MAAI,OAAO,QAAQ;AACjB,YAAQ,OAAO,MAAM,GAAG;AAAA,EAC1B,OAAO;AACL,YAAQ,OAAO,MAAM,gBAAgB,QAAQ,mBAAmB,eAAe;AAAA,CAAI;AAAA,EACrF;AACF;AAEA,KAAK,QAAQ,KAAK,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,QAAiB;AAClD,UAAQ,OAAO,MAAM,GAAG,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,CAAI;AAC5E,UAAQ,WAAW;AACrB,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/cli.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 { relative, resolve } from \"node:path\"\nimport { generateVariablesCss } from \"./node\"\nimport { initConfig, readPackageScripts } from \"./init\"\nimport type { BezelOptions } from \"./config\"\nimport { DEFAULT_CONFIG_FILE, DEFAULT_VARIABLES_OUTPUT } from \"./defaults\"\n\nconst USAGE = `bezel — convert a W3C Design Tokens (DTCG) file into a scoped variables.css\n\nUsage:\n bezel init [options] Create a bezel.json for this project\n bezel build [options] Generate the outputs (default command)\n\nReads design-tokens.json from the project root (the working directory).\n\ninit options:\n --dir <path> Directory for all outputs\n (default: src/bezel, or bezel with no src/)\n --variables-output <path> Override just the CSS path\n --contexts-output <path> Override just the contexts module path\n --fonts-output <path> Override just the fonts module path\n --no-contexts Skip the generated CONTEXTS module\n --no-fonts Skip the generated FONTS module\n --color <format> Color output: oklch | hex (default: oklch)\n --unit <mode> Dimension unit: preserve | rem (default: preserve)\n -f, --force Overwrite an existing bezel.json\n\nbuild options:\n -c, --config <path> Config file (.json or .js exporting BezelOptions)\n --variables-output <path> Output CSS file (default: ${DEFAULT_VARIABLES_OUTPUT})\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\n -h, --help Show this help\n\nA ${DEFAULT_CONFIG_FILE} file in the working directory is loaded automatically when -c is omitted.\nThe contexts/fonts modules are TypeScript, so init only scaffolds them for a\nTypeScript project unless you pass the paths explicitly.\n`\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\ntype Values = ReturnType<typeof parseArgs<{ options: typeof OPTIONS }>>[\"values\"]\n\nconst OPTIONS = {\n config: { type: \"string\", short: \"c\" },\n dir: { type: \"string\" },\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 \"no-contexts\": { type: \"boolean\" },\n \"no-fonts\": { type: \"boolean\" },\n force: { type: \"boolean\", short: \"f\" },\n help: { type: \"boolean\", short: \"h\" },\n} as const\n\n/** `bezel init` — scaffold a bezel.json, then print what to do next. */\nasync function runInit(values: Values): Promise<void> {\n const cwd = process.cwd()\n const result = await initConfig({\n cwd,\n outputDir: values.dir,\n variablesOutput: values[\"variables-output\"],\n contextsOutput: values[\"contexts-output\"],\n fontsOutput: values[\"fonts-output\"],\n contexts: values[\"no-contexts\"] ? false : undefined,\n fonts: values[\"no-fonts\"] ? false : undefined,\n colorFormat: values.color as BezelOptions[\"colorFormat\"],\n dimensionUnit: values.unit as BezelOptions[\"dimensionUnit\"],\n force: values.force,\n })\n\n const configName = relative(cwd, result.configPath) || DEFAULT_CONFIG_FILE\n\n if (!result.written) {\n process.stderr.write(\n `bezel: ${configName} already exists — leaving it alone. Re-run with --force to overwrite.\\n`,\n )\n process.exitCode = 1\n return\n }\n\n const outputs = [\n result.config.variablesOutput,\n result.config.contextsOutput,\n result.config.fontsOutput,\n ].filter((p): p is string => p !== undefined)\n\n process.stderr.write(`bezel: wrote ${configName}\\n`)\n for (const output of outputs) {\n process.stderr.write(`bezel: ${output}\\n`)\n }\n\n const scripts = await readPackageScripts(cwd)\n const steps: string[] = []\n\n if (!result.hasTokensFile) {\n steps.push(\n \"Add design-tokens.json to the project root — ask your AI agent for it via the\\n Bezel MCP, or download it from your project.\",\n )\n }\n if (!scripts[\"tokens\"]) {\n steps.push('Add \"tokens\": \"bezel build\" to your package.json scripts.')\n }\n steps.push(`Run the build, then import ${result.config.variablesOutput} in your entry file.`)\n\n process.stderr.write(\"\\nNext:\\n\")\n steps.forEach((step, i) => process.stderr.write(` ${i + 1}. ${step}\\n`))\n}\n\n/** `bezel build` — generate the outputs. */\nasync function runBuild(values: Values): Promise<void> {\n const configPath =\n values.config ??\n (existsSync(resolve(process.cwd(), DEFAULT_CONFIG_FILE)) ? DEFAULT_CONFIG_FILE : 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 ?? DEFAULT_VARIABLES_OUTPUT}\\n`)\n }\n}\n\nasync function main(argv: string[]): Promise<void> {\n const { values, positionals } = parseArgs({\n args: argv,\n allowPositionals: true,\n options: OPTIONS,\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\n if (command === \"init\") {\n await runInit(values)\n return\n }\n\n if (command !== \"build\") {\n process.stderr.write(`bezel: unknown command \"${command}\".\\n\\n${USAGE}`)\n process.exitCode = 1\n return\n }\n\n await runBuild(values)\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"],"mappings":"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","names":[]}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Options for the pure CSS transform ({@link tokensToCss}/{@link emitCss}),
3
+ * decoupled from any filesystem concern so they work in any environment.
4
+ * All optional; defaults make the zero-config case work.
5
+ */
6
+ interface CssOptions {
7
+ /**
8
+ * Map of context name → CSS selector. The first entry is the base context (full
9
+ * output); every other context emits only the variables that differ from the base.
10
+ * Default: `{ "$root": ":root", "dark": ".dark", "light": ".light" }`.
11
+ */
12
+ contexts?: Record<string, string>;
13
+ /** Color serialization. Default: `"oklch"`. */
14
+ colorFormat?: "oklch" | "hex";
15
+ /** Dimension handling: keep the authored unit, or convert `px` → `rem`. Default: `"preserve"`. */
16
+ dimensionUnit?: "preserve" | "rem";
17
+ /** `$extensions` key holding the `exportName` array. Default: `"com.bezel.app"`. */
18
+ nameExtension?: string;
19
+ }
20
+ /** Fully-resolved CSS-transform options (no `undefined`). */
21
+ interface ResolvedCssOptions {
22
+ contexts: Record<string, string>;
23
+ colorFormat: "oklch" | "hex";
24
+ dimensionUnit: "preserve" | "rem";
25
+ nameExtension: string;
26
+ }
27
+ /** Apply defaults to {@link CssOptions}. Pure — no path resolution, no `node:*`. */
28
+ declare function resolveCssOptions(options?: CssOptions): ResolvedCssOptions;
29
+
30
+ /**
31
+ * Minimal type surface for the W3C Design Tokens (DTCG) 2025.10 format, plus
32
+ * the internal shapes the generator passes between stages.
33
+ *
34
+ * @see https://www.designtokens.org/tr/2025.10/format/
35
+ */
36
+ /** A DTCG color value (e.g. `{ colorSpace: "oklch", components: [...], hex, alpha }`). */
37
+ interface ColorValue {
38
+ colorSpace: string;
39
+ components: number[];
40
+ hex?: string;
41
+ alpha?: number;
42
+ }
43
+ /** A DTCG dimension value (e.g. `{ value: 12, unit: "px" }`). */
44
+ interface DimensionValue {
45
+ value: number;
46
+ unit: string;
47
+ }
48
+ /** Any DTCG token value: a literal, a reference string `"{a.b.c}"`, or a typed object. */
49
+ type TokenValue = string | number | ColorValue | DimensionValue | (string | number)[] | Record<string, unknown>;
50
+ /**
51
+ * An arbitrary DTCG node — either a group (nested nodes) or a token (`$value`).
52
+ * Indexed loosely because we walk it structurally rather than by a fixed schema.
53
+ */
54
+ interface DtcgNode {
55
+ $value?: TokenValue;
56
+ $type?: string;
57
+ $description?: string;
58
+ $extensions?: Record<string, unknown>;
59
+ [key: string]: unknown;
60
+ }
61
+ /** A single logical token after the tree has been collapsed + flattened for one context. */
62
+ interface FlatToken {
63
+ /** Dot-path of the token in the source tree (contexts already stripped). */
64
+ path: string;
65
+ /** The token's value for the active context (may still be a `"{ref}"`). */
66
+ value: TokenValue;
67
+ /** Resolved/inherited `$type`, if known. */
68
+ type?: string;
69
+ /** Vendor extensions carried through from the source token. */
70
+ extensions?: Record<string, unknown>;
71
+ }
72
+
73
+ /**
74
+ * Pure default constants shared by the isomorphic core and the Node layer.
75
+ * Kept free of `node:*` imports so the browser/edge entry can use them.
76
+ */
77
+ /** Default context → selector mapping. The first key is the base context. */
78
+ declare const DEFAULT_CONTEXTS: Record<string, string>;
79
+ /**
80
+ * Directory generated outputs are written to, relative to the project root.
81
+ *
82
+ * Everything Bezel emits is generated and gitignored, and `bezel build` overwrites
83
+ * without asking — so outputs live in their own directory rather than alongside
84
+ * hand-written files, where a generic name like `variables.css` or `fonts.ts` could
85
+ * silently clobber something the user wrote. {@link FALLBACK_OUTPUT_DIR} is used by
86
+ * `bezel init` for projects with no `src/`.
87
+ */
88
+ declare const DEFAULT_OUTPUT_DIR = "src/bezel";
89
+ /** Output directory `bezel init` picks when the project has no `src/`. */
90
+ declare const FALLBACK_OUTPUT_DIR = "bezel";
91
+ declare const DEFAULT_NAME_EXTENSION = "com.bezel.app";
92
+ /** The config file `bezel init` writes and `bezel build` auto-loads from the project root. */
93
+ declare const DEFAULT_CONFIG_FILE = "bezel.json";
94
+
95
+ /**
96
+ * Convert a DTCG token tree into a scoped CSS string. The first context in
97
+ * `options.contexts` is the base (emitted in full); every other context emits
98
+ * only the variables whose value differs from the base.
99
+ */
100
+ declare function emitCss(tokens: DtcgNode, options: ResolvedCssOptions): string;
101
+
102
+ /** Name the `$root` context maps to in generated output (matches the `:root` CSS scope). */
103
+ declare const DEFAULT_CONTEXT_NAME = "default";
104
+ /**
105
+ * Extract the distinct context names declared anywhere in a DTCG token tree.
106
+ *
107
+ * Walks to each logical token (a node with a `$root` context wrapper) and collects the
108
+ * context keys it declares (`$root`, `dark`, `light`, …). `$root` is mapped to
109
+ * `"default"` and placed first; the rest follow in first-seen order, deduped.
110
+ */
111
+ declare function getContexts(tokens: DtcgNode, rootName?: string): string[];
112
+ /** Render the generated `contexts.ts` module emitted alongside `variables.css`. */
113
+ declare function formatContextsModule(contexts: string[]): string;
114
+
115
+ /** A web font to load: a family name and the weights it is used at. */
116
+ interface FontDef {
117
+ family: string;
118
+ weights: number[];
119
+ }
120
+ /**
121
+ * Extract the web fonts referenced by a DTCG token tree.
122
+ *
123
+ * Collects every distinct `fontFamily` value (references resolved), then derives each
124
+ * family's weights from the semantic typography composites — a group whose `font-family`
125
+ * resolves to that family contributes its sibling `font-weight`. Families used without an
126
+ * accompanying weight default to `[400]`. Result is sorted by family for determinism.
127
+ */
128
+ declare function getFonts(tokens: DtcgNode): FontDef[];
129
+ /** Render the generated `fonts.ts` module emitted alongside `variables.css`. */
130
+ declare function formatFontsModule(fonts: FontDef[]): string;
131
+
132
+ /**
133
+ * Convert a DTCG token object into a scoped `variables.css` string.
134
+ *
135
+ * Resolves each configured context (with `$root` fallback and reference
136
+ * resolution) and emits one CSS scope per context — the base context in full,
137
+ * others as override-only blocks. Pure: no filesystem access.
138
+ *
139
+ * @example
140
+ * const css = tokensToCss(tokens)
141
+ *
142
+ * @example
143
+ * const css = tokensToCss(tokens, { colorFormat: "hex", contexts: { $root: ":root" } })
144
+ */
145
+ declare function tokensToCss(tokens: DtcgNode, options?: CssOptions): string;
146
+
147
+ export { type CssOptions as C, DEFAULT_CONFIG_FILE as D, FALLBACK_OUTPUT_DIR as F, type ResolvedCssOptions as R, type TokenValue as T, type ColorValue as a, DEFAULT_CONTEXTS as b, DEFAULT_CONTEXT_NAME as c, DEFAULT_NAME_EXTENSION as d, DEFAULT_OUTPUT_DIR as e, type DimensionValue as f, type DtcgNode as g, type FlatToken as h, type FontDef as i, emitCss as j, formatContextsModule as k, formatFontsModule as l, getContexts as m, getFonts as n, resolveCssOptions as r, tokensToCss as t };
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Options for the pure CSS transform ({@link tokensToCss}/{@link emitCss}),
3
+ * decoupled from any filesystem concern so they work in any environment.
4
+ * All optional; defaults make the zero-config case work.
5
+ */
6
+ interface CssOptions {
7
+ /**
8
+ * Map of context name → CSS selector. The first entry is the base context (full
9
+ * output); every other context emits only the variables that differ from the base.
10
+ * Default: `{ "$root": ":root", "dark": ".dark", "light": ".light" }`.
11
+ */
12
+ contexts?: Record<string, string>;
13
+ /** Color serialization. Default: `"oklch"`. */
14
+ colorFormat?: "oklch" | "hex";
15
+ /** Dimension handling: keep the authored unit, or convert `px` → `rem`. Default: `"preserve"`. */
16
+ dimensionUnit?: "preserve" | "rem";
17
+ /** `$extensions` key holding the `exportName` array. Default: `"com.bezel.app"`. */
18
+ nameExtension?: string;
19
+ }
20
+ /** Fully-resolved CSS-transform options (no `undefined`). */
21
+ interface ResolvedCssOptions {
22
+ contexts: Record<string, string>;
23
+ colorFormat: "oklch" | "hex";
24
+ dimensionUnit: "preserve" | "rem";
25
+ nameExtension: string;
26
+ }
27
+ /** Apply defaults to {@link CssOptions}. Pure — no path resolution, no `node:*`. */
28
+ declare function resolveCssOptions(options?: CssOptions): ResolvedCssOptions;
29
+
30
+ /**
31
+ * Minimal type surface for the W3C Design Tokens (DTCG) 2025.10 format, plus
32
+ * the internal shapes the generator passes between stages.
33
+ *
34
+ * @see https://www.designtokens.org/tr/2025.10/format/
35
+ */
36
+ /** A DTCG color value (e.g. `{ colorSpace: "oklch", components: [...], hex, alpha }`). */
37
+ interface ColorValue {
38
+ colorSpace: string;
39
+ components: number[];
40
+ hex?: string;
41
+ alpha?: number;
42
+ }
43
+ /** A DTCG dimension value (e.g. `{ value: 12, unit: "px" }`). */
44
+ interface DimensionValue {
45
+ value: number;
46
+ unit: string;
47
+ }
48
+ /** Any DTCG token value: a literal, a reference string `"{a.b.c}"`, or a typed object. */
49
+ type TokenValue = string | number | ColorValue | DimensionValue | (string | number)[] | Record<string, unknown>;
50
+ /**
51
+ * An arbitrary DTCG node — either a group (nested nodes) or a token (`$value`).
52
+ * Indexed loosely because we walk it structurally rather than by a fixed schema.
53
+ */
54
+ interface DtcgNode {
55
+ $value?: TokenValue;
56
+ $type?: string;
57
+ $description?: string;
58
+ $extensions?: Record<string, unknown>;
59
+ [key: string]: unknown;
60
+ }
61
+ /** A single logical token after the tree has been collapsed + flattened for one context. */
62
+ interface FlatToken {
63
+ /** Dot-path of the token in the source tree (contexts already stripped). */
64
+ path: string;
65
+ /** The token's value for the active context (may still be a `"{ref}"`). */
66
+ value: TokenValue;
67
+ /** Resolved/inherited `$type`, if known. */
68
+ type?: string;
69
+ /** Vendor extensions carried through from the source token. */
70
+ extensions?: Record<string, unknown>;
71
+ }
72
+
73
+ /**
74
+ * Pure default constants shared by the isomorphic core and the Node layer.
75
+ * Kept free of `node:*` imports so the browser/edge entry can use them.
76
+ */
77
+ /** Default context → selector mapping. The first key is the base context. */
78
+ declare const DEFAULT_CONTEXTS: Record<string, string>;
79
+ /**
80
+ * Directory generated outputs are written to, relative to the project root.
81
+ *
82
+ * Everything Bezel emits is generated and gitignored, and `bezel build` overwrites
83
+ * without asking — so outputs live in their own directory rather than alongside
84
+ * hand-written files, where a generic name like `variables.css` or `fonts.ts` could
85
+ * silently clobber something the user wrote. {@link FALLBACK_OUTPUT_DIR} is used by
86
+ * `bezel init` for projects with no `src/`.
87
+ */
88
+ declare const DEFAULT_OUTPUT_DIR = "src/bezel";
89
+ /** Output directory `bezel init` picks when the project has no `src/`. */
90
+ declare const FALLBACK_OUTPUT_DIR = "bezel";
91
+ declare const DEFAULT_NAME_EXTENSION = "com.bezel.app";
92
+ /** The config file `bezel init` writes and `bezel build` auto-loads from the project root. */
93
+ declare const DEFAULT_CONFIG_FILE = "bezel.json";
94
+
95
+ /**
96
+ * Convert a DTCG token tree into a scoped CSS string. The first context in
97
+ * `options.contexts` is the base (emitted in full); every other context emits
98
+ * only the variables whose value differs from the base.
99
+ */
100
+ declare function emitCss(tokens: DtcgNode, options: ResolvedCssOptions): string;
101
+
102
+ /** Name the `$root` context maps to in generated output (matches the `:root` CSS scope). */
103
+ declare const DEFAULT_CONTEXT_NAME = "default";
104
+ /**
105
+ * Extract the distinct context names declared anywhere in a DTCG token tree.
106
+ *
107
+ * Walks to each logical token (a node with a `$root` context wrapper) and collects the
108
+ * context keys it declares (`$root`, `dark`, `light`, …). `$root` is mapped to
109
+ * `"default"` and placed first; the rest follow in first-seen order, deduped.
110
+ */
111
+ declare function getContexts(tokens: DtcgNode, rootName?: string): string[];
112
+ /** Render the generated `contexts.ts` module emitted alongside `variables.css`. */
113
+ declare function formatContextsModule(contexts: string[]): string;
114
+
115
+ /** A web font to load: a family name and the weights it is used at. */
116
+ interface FontDef {
117
+ family: string;
118
+ weights: number[];
119
+ }
120
+ /**
121
+ * Extract the web fonts referenced by a DTCG token tree.
122
+ *
123
+ * Collects every distinct `fontFamily` value (references resolved), then derives each
124
+ * family's weights from the semantic typography composites — a group whose `font-family`
125
+ * resolves to that family contributes its sibling `font-weight`. Families used without an
126
+ * accompanying weight default to `[400]`. Result is sorted by family for determinism.
127
+ */
128
+ declare function getFonts(tokens: DtcgNode): FontDef[];
129
+ /** Render the generated `fonts.ts` module emitted alongside `variables.css`. */
130
+ declare function formatFontsModule(fonts: FontDef[]): string;
131
+
132
+ /**
133
+ * Convert a DTCG token object into a scoped `variables.css` string.
134
+ *
135
+ * Resolves each configured context (with `$root` fallback and reference
136
+ * resolution) and emits one CSS scope per context — the base context in full,
137
+ * others as override-only blocks. Pure: no filesystem access.
138
+ *
139
+ * @example
140
+ * const css = tokensToCss(tokens)
141
+ *
142
+ * @example
143
+ * const css = tokensToCss(tokens, { colorFormat: "hex", contexts: { $root: ":root" } })
144
+ */
145
+ declare function tokensToCss(tokens: DtcgNode, options?: CssOptions): string;
146
+
147
+ export { type CssOptions as C, DEFAULT_CONFIG_FILE as D, FALLBACK_OUTPUT_DIR as F, type ResolvedCssOptions as R, type TokenValue as T, type ColorValue as a, DEFAULT_CONTEXTS as b, DEFAULT_CONTEXT_NAME as c, DEFAULT_NAME_EXTENSION as d, DEFAULT_OUTPUT_DIR as e, type DimensionValue as f, type DtcgNode as g, type FlatToken as h, type FontDef as i, emitCss as j, formatContextsModule as k, formatFontsModule as l, getContexts as m, getFonts as n, resolveCssOptions as r, tokensToCss as t };
package/dist/index.cjs CHANGED
@@ -244,7 +244,10 @@ var DEFAULT_CONTEXTS = {
244
244
  dark: ".dark",
245
245
  light: ".light"
246
246
  };
247
- var DEFAULT_NAME_EXTENSION = "com.tokendesigner.app";
247
+ var DEFAULT_OUTPUT_DIR = "src/bezel";
248
+ var VARIABLES_FILE = "variables.css";
249
+ var DEFAULT_VARIABLES_OUTPUT = `${DEFAULT_OUTPUT_DIR}/${VARIABLES_FILE}`;
250
+ var DEFAULT_NAME_EXTENSION = "com.bezel.app";
248
251
 
249
252
  // src/options.ts
250
253
  function resolveCssOptions(options = {}) {