@bezel-labs/bezel-kit 0.4.0 → 0.6.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/README.md +43 -2
- package/dist/{chunk-RLMGV52B.js → chunk-KCAFXZVO.js} +3 -2
- package/dist/chunk-KCAFXZVO.js.map +1 -0
- package/dist/{chunk-T6DKROBI.js → chunk-Z7IFWPRA.js} +20 -3
- package/dist/chunk-Z7IFWPRA.js.map +1 -0
- package/dist/cli.cjs +176 -8
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +159 -7
- package/dist/cli.js.map +1 -1
- package/dist/{index-GGPx58oG.d.cts → index-CxeyVs4k.d.cts} +9 -0
- package/dist/{index-GGPx58oG.d.ts → index-CxeyVs4k.d.ts} +9 -0
- package/dist/index.cjs +19 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/node.cjs +20 -2
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +5 -2
- package/dist/node.d.ts +5 -2
- package/dist/node.js +2 -2
- package/package.json +3 -3
- package/dist/chunk-RLMGV52B.js.map +0 -1
- package/dist/chunk-T6DKROBI.js.map +0 -1
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 { 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 --project <uuid> Link this repo to a Bezel project (writes projectId)\n --tokens-version <v> Tokens version the Bezel MCP fetches: latest | semver (default: latest)\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--project and --tokens-version update only their own key in an existing bezel.json; no --force needed.\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 project: { type: \"string\" },\n \"tokens-version\": { 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\nconst TOKENS_FILE_HINT =\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/** `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 projectId: values.project,\n version: values[\"tokens-version\"],\n })\n\n const configName = relative(cwd, result.configPath) || DEFAULT_CONFIG_FILE\n\n if (result.updated) {\n if (values.project) {\n const changed = result.previousProjectId && result.previousProjectId !== values.project\n process.stderr.write(\n changed\n ? `bezel: updated projectId in ${configName} (was ${result.previousProjectId})\\n`\n : `bezel: set projectId in ${configName}\\n`,\n )\n }\n if (result.config.version !== result.previousVersion) {\n process.stderr.write(`bezel: set version to ${result.config.version} in ${configName}\\n`)\n }\n if (!result.hasTokensFile) {\n process.stderr.write(`\\n${TOKENS_FILE_HINT}\\n`)\n }\n return\n }\n\n if (!result.written) {\n process.stderr.write(\n `bezel: ${configName} already exists — leaving it alone. Re-run with --force to overwrite, or pass --project <uuid> / --tokens-version <v> to just update the project link.\\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(TOKENS_FILE_HINT)\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":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/install-mcp.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 { installMcp } from \"./install-mcp\"\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 install-mcp [--client <name>] Connect claude-code, codex, cursor, vscode, or other\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 --include-all Also emit variables for tokens without an exportName\n (kebab-cased full path, e.g. --base-color-primary-500)\n --project <uuid> Link this repo to a Bezel project (writes projectId)\n --tokens-version <v> Tokens version the Bezel MCP fetches: latest | semver (default: latest)\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 --include-all Also emit variables for tokens without an exportName\n (kebab-cased full path, e.g. --base-color-primary-500)\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--project and --tokens-version update only their own key in an existing bezel.json; no --force needed.\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 client: { type: \"string\" },\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 \"include-all\": { type: \"boolean\" },\n project: { type: \"string\" },\n \"tokens-version\": { 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\nconst TOKENS_FILE_HINT =\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/** `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 includeAll: values[\"include-all\"],\n force: values.force,\n projectId: values.project,\n version: values[\"tokens-version\"],\n })\n\n const configName = relative(cwd, result.configPath) || DEFAULT_CONFIG_FILE\n\n if (result.updated) {\n if (values.project) {\n const changed = result.previousProjectId && result.previousProjectId !== values.project\n process.stderr.write(\n changed\n ? `bezel: updated projectId in ${configName} (was ${result.previousProjectId})\\n`\n : `bezel: set projectId in ${configName}\\n`,\n )\n }\n if (result.config.version !== result.previousVersion) {\n process.stderr.write(`bezel: set version to ${result.config.version} in ${configName}\\n`)\n }\n if (!result.hasTokensFile) {\n process.stderr.write(`\\n${TOKENS_FILE_HINT}\\n`)\n }\n return\n }\n\n if (!result.written) {\n process.stderr.write(\n `bezel: ${configName} already exists — leaving it alone. Re-run with --force to overwrite, or pass --project <uuid> / --tokens-version <v> to just update the project link.\\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(TOKENS_FILE_HINT)\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[\"include-all\"]) options.includeAll = true\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 === \"install-mcp\") {\n await installMcp(values.client)\n return\n }\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","import { spawnSync } from \"node:child_process\"\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\"\nimport { dirname, resolve } from \"node:path\"\nimport { createInterface } from \"node:readline/promises\"\n\nexport const MCP_URL = \"https://mcp.bezel.new/mcp\"\nexport const CLIENTS = [\"claude-code\", \"codex\", \"cursor\", \"vscode\", \"other\"] as const\nexport type McpClient = (typeof CLIENTS)[number]\n\nexport function clientCommand(client: McpClient): { command: string; args: string[] } | undefined {\n if (client === \"claude-code\") {\n return {\n command: \"claude\",\n args: [\"mcp\", \"add\", \"--transport\", \"http\", \"--scope\", \"project\", \"bezel\", MCP_URL],\n }\n }\n if (client === \"codex\") {\n return { command: \"codex\", args: [\"mcp\", \"add\", \"bezel\", \"--url\", MCP_URL] }\n }\n return undefined\n}\n\nfunction object(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nexport function codexAlreadyConfigured(raw: string): boolean {\n const servers: unknown = JSON.parse(raw)\n if (\n !Array.isArray(servers) ||\n !servers.every((server) => object(server) && typeof server[\"name\"] === \"string\")\n ) {\n throw new Error(\"Could not inspect Codex MCP configuration; no changes made.\")\n }\n const existing = servers.find((server) => server[\"name\"] === \"bezel\")\n if (!existing) return false\n if (\n !object(existing[\"transport\"]) ||\n existing[\"transport\"][\"url\"] !== MCP_URL ||\n existing[\"enabled\"] === false\n ) {\n throw new Error(\n \"An existing or disabled Bezel entry needs attention in Codex; no changes made.\",\n )\n }\n return true\n}\n\n/** Preserve unrelated settings; reject conflicting or malformed configuration. */\nexport function mergeMcpConfig(raw: string, client: \"cursor\" | \"vscode\"): string {\n const config: unknown = JSON.parse(raw)\n if (!object(config)) throw new Error(\"MCP config must be a JSON object; no changes made.\")\n const key = client === \"cursor\" ? \"mcpServers\" : \"servers\"\n const servers = config[key] ?? {}\n if (!object(servers)) throw new Error(`${key} must be a JSON object; no changes made.`)\n const entry = client === \"cursor\" ? { url: MCP_URL } : { type: \"http\", url: MCP_URL }\n if (servers[\"bezel\"] !== undefined) {\n const existing = servers[\"bezel\"]\n if (\n !object(existing) ||\n existing[\"url\"] !== MCP_URL ||\n (existing[\"type\"] !== undefined && existing[\"type\"] !== \"http\") ||\n existing[\"command\"] !== undefined\n ) {\n throw new Error(\"A different bezel server is already configured; no changes made.\")\n }\n return raw\n }\n return `${JSON.stringify({ ...config, [key]: { ...servers, bezel: entry } }, null, 2)}\\n`\n}\n\nexport async function installMcp(clientName?: string): Promise<void> {\n let choice = clientName\n if (!choice) {\n if (!process.stdin.isTTY) {\n throw new Error(`Choose a client with --client ${CLIENTS.join(\"|\")}.`)\n }\n const prompt = createInterface({ input: process.stdin, output: process.stdout })\n try {\n console.log(\n \"Connect Bezel to your coding tool:\\n1. Claude Code (this project)\\n2. Codex (your user configuration)\\n3. Cursor (this project)\\n4. VS Code (this project)\\n5. Other / hosted tool\",\n )\n const answer = (await prompt.question(\"Choose 1–5: \")).trim()\n choice = CLIENTS[Number(answer) - 1] ?? answer\n } finally {\n prompt.close()\n }\n }\n if (!CLIENTS.includes(choice as McpClient))\n throw new Error(`Unknown client: ${choice}. Choose ${CLIENTS.join(\", \")}.`)\n const client = choice as McpClient\n const invocation = clientCommand(client)\n if (invocation) {\n console.log(\n client === \"codex\"\n ? \"Adding Bezel to Codex user configuration.\"\n : \"Adding Bezel to this project's Claude Code configuration.\",\n )\n let alreadyConfigured = false\n if (client === \"codex\") {\n const current = spawnSync(\"codex\", [\"mcp\", \"list\", \"--json\"], {\n encoding: \"utf8\",\n shell: false,\n })\n if (current.error || current.status !== 0)\n throw new Error(\n \"Could not inspect Codex MCP configuration. Ensure the Codex CLI is installed; no changes made.\",\n )\n alreadyConfigured = codexAlreadyConfigured(current.stdout)\n }\n const result = alreadyConfigured\n ? { status: 0, error: undefined }\n : spawnSync(invocation.command, invocation.args, {\n stdio: \"inherit\",\n shell: false,\n })\n if (result.error || result.status !== 0) {\n throw new Error(\n `Could not configure ${client}. Ensure its CLI is installed and review any existing bezel entry. No existing server was removed. Manual setup: https://docs.bezel.new/docs/mcp-server/setup`,\n )\n }\n } else if (client === \"cursor\" || client === \"vscode\") {\n const path = resolve(client === \"cursor\" ? \".cursor/mcp.json\" : \".vscode/mcp.json\")\n let raw = \"{}\"\n let exists = false\n try {\n raw = await readFile(path, \"utf8\")\n exists = true\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error\n }\n // JSONC is deliberately not rewritten: preserve comments by requesting manual setup.\n let merged: string\n try {\n merged = mergeMcpConfig(raw, client)\n } catch (error) {\n throw new Error(\n `${path}: ${error instanceof Error ? error.message : String(error)} For JSON with comments, add Bezel manually: https://docs.bezel.new/docs/mcp-server/setup`,\n )\n }\n if (merged !== raw) {\n await mkdir(dirname(path), { recursive: true })\n if (exists) await writeFile(`${path}.bezel-backup`, raw, { flag: \"wx\", mode: 0o600 })\n await writeFile(path, merged, { flag: exists ? \"w\" : \"wx\" })\n }\n console.log(`Bezel configured in ${path}`)\n } else {\n console.log(\n `In your tool's MCP/connector settings, add Bezel with URL ${MCP_URL}, Streamable HTTP transport, and OAuth authentication.\\nClient instructions: https://docs.bezel.new/docs/mcp-server/setup`,\n )\n }\n console.log(\n client === \"codex\"\n ? \"Next: run `codex mcp login bezel` and complete browser sign-in.\"\n : client === \"claude-code\"\n ? \"Next: open Claude Code, run /mcp, select bezel, and sign in.\"\n : \"Next: open or reload your coding tool and sign in to Bezel when prompted.\",\n )\n console.log(\n '\\nThen open your current project in the assistant and ask:\\n\"Set up Bezel in this project. Help me choose my Bezel project, generate my token files, and offer the recommended live preview setup.\"\\n\\nThe assistant will install Bezel Kit, configure your output folder, and ask before adding Crystal for live preview. A host with file and terminal access can perform setup; other hosts provide manual steps.',\n )\n}\n"],"mappings":"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","names":["readFile","resolve","resolve","readFile"]}
|
|
@@ -16,6 +16,14 @@ interface CssOptions {
|
|
|
16
16
|
dimensionUnit?: "preserve" | "rem";
|
|
17
17
|
/** `$extensions` key holding the `exportName` array. Default: `"com.bezel.app"`. */
|
|
18
18
|
nameExtension?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Also emit a variable for every token that has no `exportName`, named by kebab-casing its
|
|
21
|
+
* full path (e.g. `base.color.primary.500` → `--base-color-primary-500`). Tokens with an
|
|
22
|
+
* `exportName` still emit only their export names. Has no effect when no token declares an
|
|
23
|
+
* `exportName`, since every token is then emitted with a path-derived name already.
|
|
24
|
+
* Default: `false`.
|
|
25
|
+
*/
|
|
26
|
+
includeAll?: boolean;
|
|
19
27
|
}
|
|
20
28
|
/** Fully-resolved CSS-transform options (no `undefined`). */
|
|
21
29
|
interface ResolvedCssOptions {
|
|
@@ -23,6 +31,7 @@ interface ResolvedCssOptions {
|
|
|
23
31
|
colorFormat: "oklch" | "hex";
|
|
24
32
|
dimensionUnit: "preserve" | "rem";
|
|
25
33
|
nameExtension: string;
|
|
34
|
+
includeAll: boolean;
|
|
26
35
|
}
|
|
27
36
|
/** Apply defaults to {@link CssOptions}. Pure — no path resolution, no `node:*`. */
|
|
28
37
|
declare function resolveCssOptions(options?: CssOptions): ResolvedCssOptions;
|
|
@@ -16,6 +16,14 @@ interface CssOptions {
|
|
|
16
16
|
dimensionUnit?: "preserve" | "rem";
|
|
17
17
|
/** `$extensions` key holding the `exportName` array. Default: `"com.bezel.app"`. */
|
|
18
18
|
nameExtension?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Also emit a variable for every token that has no `exportName`, named by kebab-casing its
|
|
21
|
+
* full path (e.g. `base.color.primary.500` → `--base-color-primary-500`). Tokens with an
|
|
22
|
+
* `exportName` still emit only their export names. Has no effect when no token declares an
|
|
23
|
+
* `exportName`, since every token is then emitted with a path-derived name already.
|
|
24
|
+
* Default: `false`.
|
|
25
|
+
*/
|
|
26
|
+
includeAll?: boolean;
|
|
19
27
|
}
|
|
20
28
|
/** Fully-resolved CSS-transform options (no `undefined`). */
|
|
21
29
|
interface ResolvedCssOptions {
|
|
@@ -23,6 +31,7 @@ interface ResolvedCssOptions {
|
|
|
23
31
|
colorFormat: "oklch" | "hex";
|
|
24
32
|
dimensionUnit: "preserve" | "rem";
|
|
25
33
|
nameExtension: string;
|
|
34
|
+
includeAll: boolean;
|
|
26
35
|
}
|
|
27
36
|
/** Apply defaults to {@link CssOptions}. Pure — no path resolution, no `node:*`. */
|
|
28
37
|
declare function resolveCssOptions(options?: CssOptions): ResolvedCssOptions;
|
package/dist/index.cjs
CHANGED
|
@@ -105,6 +105,11 @@ function nameFromPath(path) {
|
|
|
105
105
|
}
|
|
106
106
|
return segments.join("-");
|
|
107
107
|
}
|
|
108
|
+
function pathToKebabName(path) {
|
|
109
|
+
return path.split(".").map(
|
|
110
|
+
(segment) => segment.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "")
|
|
111
|
+
).filter((segment) => segment.length > 0).join("-");
|
|
112
|
+
}
|
|
108
113
|
function cssNames(token, nameExtension, useExportName) {
|
|
109
114
|
if (useExportName) {
|
|
110
115
|
const names = exportNames(token, nameExtension);
|
|
@@ -201,9 +206,20 @@ function serializeValue(value, options) {
|
|
|
201
206
|
// src/emit.ts
|
|
202
207
|
function buildContextVars(tokens, context, useExportName, options) {
|
|
203
208
|
const flat = resolveReferences(flattenForContext(tokens, context));
|
|
209
|
+
const includeUnnamed = useExportName && options.includeAll;
|
|
210
|
+
const exportNames2 = /* @__PURE__ */ new Set();
|
|
211
|
+
if (includeUnnamed) {
|
|
212
|
+
for (const token of flat.values()) {
|
|
213
|
+
for (const name of cssNames(token, options.nameExtension, true)) exportNames2.add(name);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
204
216
|
const vars = /* @__PURE__ */ new Map();
|
|
205
217
|
for (const token of flat.values()) {
|
|
206
|
-
|
|
218
|
+
let names = cssNames(token, options.nameExtension, useExportName);
|
|
219
|
+
if (names.length === 0 && includeUnnamed) {
|
|
220
|
+
const generated = pathToKebabName(token.path);
|
|
221
|
+
if (generated && !exportNames2.has(generated) && !vars.has(generated)) names = [generated];
|
|
222
|
+
}
|
|
207
223
|
if (names.length === 0) continue;
|
|
208
224
|
const value = serializeValue(token.value, options);
|
|
209
225
|
for (const name of names) vars.set(name, value);
|
|
@@ -259,7 +275,8 @@ function resolveCssOptions(options = {}) {
|
|
|
259
275
|
contexts,
|
|
260
276
|
colorFormat: options.colorFormat ?? "oklch",
|
|
261
277
|
dimensionUnit: options.dimensionUnit ?? "preserve",
|
|
262
|
-
nameExtension: options.nameExtension ?? DEFAULT_NAME_EXTENSION
|
|
278
|
+
nameExtension: options.nameExtension ?? DEFAULT_NAME_EXTENSION,
|
|
279
|
+
includeAll: options.includeAll ?? false
|
|
263
280
|
};
|
|
264
281
|
}
|
|
265
282
|
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/collapse.ts","../src/name.ts","../src/resolve.ts","../src/serialize.ts","../src/emit.ts","../src/defaults.ts","../src/options.ts","../src/contexts.ts","../src/fonts.ts"],"sourcesContent":["/**\n * bezel — isomorphic entry.\n *\n * The pure transform core: convert an in-memory W3C Design Tokens (DTCG) object\n * into a scoped `variables.css` string. Imports no `node:*`, so it runs anywhere\n * — browser, edge, Node. For the filesystem/CLI conveniences (reading a tokens\n * file, writing outputs), import from `bezel/node`.\n */\nimport { emitCss } from \"./emit\"\nimport { resolveCssOptions, type CssOptions } from \"./options\"\nimport type { DtcgNode } from \"./types\"\n\nexport type { CssOptions, ResolvedCssOptions } from \"./options\"\nexport type { DtcgNode, FlatToken, TokenValue, ColorValue, DimensionValue } from \"./types\"\nexport { DEFAULT_CONTEXTS, DEFAULT_NAME_EXTENSION } from \"./defaults\"\nexport { emitCss } from \"./emit\"\nexport { resolveCssOptions } from \"./options\"\nexport { getContexts, formatContextsModule, DEFAULT_CONTEXT_NAME } from \"./contexts\"\nexport { getFonts, formatFontsModule } from \"./fonts\"\nexport type { FontDef } from \"./fonts\"\n\n/**\n * Convert a DTCG token object into a scoped `variables.css` string.\n *\n * Resolves each configured context (with `$root` fallback and reference\n * resolution) and emits one CSS scope per context — the base context in full,\n * others as override-only blocks. Pure: no filesystem access.\n *\n * @example\n * const css = tokensToCss(tokens)\n *\n * @example\n * const css = tokensToCss(tokens, { colorFormat: \"hex\", contexts: { $root: \":root\" } })\n */\nexport function tokensToCss(tokens: DtcgNode, options: CssOptions = {}): string {\n return emitCss(tokens, resolveCssOptions(options))\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","/**\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 * so any repo/app the platform connects to resolves its tokens at the same name\n * and location.\n */\nexport const DEFAULT_INPUT = \"design-tokens.json\";\n\n/**\n * Directory generated outputs are written to, relative to the project root.\n *\n * Everything Bezel emits is generated and gitignored, and `bezel build` overwrites\n * without asking — so outputs live in their own directory rather than alongside\n * hand-written files, where a generic name like `variables.css` or `fonts.ts` could\n * silently clobber something the user wrote. {@link FALLBACK_OUTPUT_DIR} is used by\n * `bezel init` for projects with no `src/`.\n */\nexport const DEFAULT_OUTPUT_DIR = \"src/bezel\";\n/** Output directory `bezel init` picks when the project has no `src/`. */\nexport const FALLBACK_OUTPUT_DIR = \"bezel\";\n\n/** Generated output filenames, joined onto the output directory. */\nexport const VARIABLES_FILE = \"variables.css\";\nexport const CONTEXTS_FILE = \"contexts.ts\";\nexport const FONTS_FILE = \"fonts.ts\";\n\nexport const DEFAULT_VARIABLES_OUTPUT = `${DEFAULT_OUTPUT_DIR}/${VARIABLES_FILE}`;\nexport const DEFAULT_NAME_EXTENSION = \"com.bezel.app\";\n\n/** The config file `bezel init` writes and `bezel build` auto-loads from the project root. */\nexport const DEFAULT_CONFIG_FILE = \"bezel.json\";\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.bezel.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 { 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"],"mappings":"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","names":["isObject","isObject","isContextWrapper"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/collapse.ts","../src/name.ts","../src/resolve.ts","../src/serialize.ts","../src/emit.ts","../src/defaults.ts","../src/options.ts","../src/contexts.ts","../src/fonts.ts"],"sourcesContent":["/**\n * bezel — isomorphic entry.\n *\n * The pure transform core: convert an in-memory W3C Design Tokens (DTCG) object\n * into a scoped `variables.css` string. Imports no `node:*`, so it runs anywhere\n * — browser, edge, Node. For the filesystem/CLI conveniences (reading a tokens\n * file, writing outputs), import from `bezel/node`.\n */\nimport { emitCss } from \"./emit\"\nimport { resolveCssOptions, type CssOptions } from \"./options\"\nimport type { DtcgNode } from \"./types\"\n\nexport type { CssOptions, ResolvedCssOptions } from \"./options\"\nexport type { DtcgNode, FlatToken, TokenValue, ColorValue, DimensionValue } from \"./types\"\nexport { DEFAULT_CONTEXTS, DEFAULT_NAME_EXTENSION } from \"./defaults\"\nexport { emitCss } from \"./emit\"\nexport { resolveCssOptions } from \"./options\"\nexport { getContexts, formatContextsModule, DEFAULT_CONTEXT_NAME } from \"./contexts\"\nexport { getFonts, formatFontsModule } from \"./fonts\"\nexport type { FontDef } from \"./fonts\"\n\n/**\n * Convert a DTCG token object into a scoped `variables.css` string.\n *\n * Resolves each configured context (with `$root` fallback and reference\n * resolution) and emits one CSS scope per context — the base context in full,\n * others as override-only blocks. Pure: no filesystem access.\n *\n * @example\n * const css = tokensToCss(tokens)\n *\n * @example\n * const css = tokensToCss(tokens, { colorFormat: \"hex\", contexts: { $root: \":root\" } })\n */\nexport function tokensToCss(tokens: DtcgNode, options: CssOptions = {}): string {\n return emitCss(tokens, resolveCssOptions(options))\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 * Derive a CSS variable name from the full dot-path, kebab-cased (e.g.\n * `base.color.primary.500` → `base-color-primary-500`). Unlike {@link nameFromPath} it keeps\n * every segment, so the name identifies one token unambiguously.\n */\nexport function pathToKebabName(path: string): string {\n return path\n .split(\".\")\n .map((segment) =>\n segment\n .replace(/([a-z0-9])([A-Z])/g, \"$1-$2\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\"),\n )\n .filter((segment) => segment.length > 0)\n .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, pathToKebabName, 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 includeUnnamed = useExportName && options.includeAll\n\n // Export names always win over a generated path name, so collect them up front.\n const exportNames = new Set<string>()\n if (includeUnnamed) {\n for (const token of flat.values()) {\n for (const name of cssNames(token, options.nameExtension, true)) exportNames.add(name)\n }\n }\n\n const vars: VarMap = new Map()\n for (const token of flat.values()) {\n let names = cssNames(token, options.nameExtension, useExportName)\n if (names.length === 0 && includeUnnamed) {\n const generated = pathToKebabName(token.path)\n // First token wins among generated names; never shadow an export name.\n if (generated && !exportNames.has(generated) && !vars.has(generated)) names = [generated]\n }\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","/**\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 * so any repo/app the platform connects to resolves its tokens at the same name\n * and location.\n */\nexport const DEFAULT_INPUT = \"design-tokens.json\";\n\n/**\n * Directory generated outputs are written to, relative to the project root.\n *\n * Everything Bezel emits is generated and gitignored, and `bezel build` overwrites\n * without asking — so outputs live in their own directory rather than alongside\n * hand-written files, where a generic name like `variables.css` or `fonts.ts` could\n * silently clobber something the user wrote. {@link FALLBACK_OUTPUT_DIR} is used by\n * `bezel init` for projects with no `src/`.\n */\nexport const DEFAULT_OUTPUT_DIR = \"src/bezel\";\n/** Output directory `bezel init` picks when the project has no `src/`. */\nexport const FALLBACK_OUTPUT_DIR = \"bezel\";\n\n/** Generated output filenames, joined onto the output directory. */\nexport const VARIABLES_FILE = \"variables.css\";\nexport const CONTEXTS_FILE = \"contexts.ts\";\nexport const FONTS_FILE = \"fonts.ts\";\n\nexport const DEFAULT_VARIABLES_OUTPUT = `${DEFAULT_OUTPUT_DIR}/${VARIABLES_FILE}`;\nexport const DEFAULT_NAME_EXTENSION = \"com.bezel.app\";\n\n/** The config file `bezel init` writes and `bezel build` auto-loads from the project root. */\nexport const DEFAULT_CONFIG_FILE = \"bezel.json\";\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.bezel.app\"`. */\n nameExtension?: string\n /**\n * Also emit a variable for every token that has no `exportName`, named by kebab-casing its\n * full path (e.g. `base.color.primary.500` → `--base-color-primary-500`). Tokens with an\n * `exportName` still emit only their export names. Has no effect when no token declares an\n * `exportName`, since every token is then emitted with a path-derived name already.\n * Default: `false`.\n */\n includeAll?: boolean\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 includeAll: boolean\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 includeAll: options.includeAll ?? false,\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"],"mappings":"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","names":["isObject","exportNames","isObject","isContextWrapper"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { a as ColorValue, C as CssOptions, b as DEFAULT_CONTEXTS, c as DEFAULT_CONTEXT_NAME, d as DEFAULT_NAME_EXTENSION, f as DimensionValue, g as DtcgNode, h as FlatToken, i as FontDef, R as ResolvedCssOptions, T as TokenValue, j as emitCss, k as formatContextsModule, l as formatFontsModule, m as getContexts, n as getFonts, r as resolveCssOptions, t as tokensToCss } from './index-
|
|
1
|
+
export { a as ColorValue, C as CssOptions, b as DEFAULT_CONTEXTS, c as DEFAULT_CONTEXT_NAME, d as DEFAULT_NAME_EXTENSION, f as DimensionValue, g as DtcgNode, h as FlatToken, i as FontDef, R as ResolvedCssOptions, T as TokenValue, j as emitCss, k as formatContextsModule, l as formatFontsModule, m as getContexts, n as getFonts, r as resolveCssOptions, t as tokensToCss } from './index-CxeyVs4k.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { a as ColorValue, C as CssOptions, b as DEFAULT_CONTEXTS, c as DEFAULT_CONTEXT_NAME, d as DEFAULT_NAME_EXTENSION, f as DimensionValue, g as DtcgNode, h as FlatToken, i as FontDef, R as ResolvedCssOptions, T as TokenValue, j as emitCss, k as formatContextsModule, l as formatFontsModule, m as getContexts, n as getFonts, r as resolveCssOptions, t as tokensToCss } from './index-
|
|
1
|
+
export { a as ColorValue, C as CssOptions, b as DEFAULT_CONTEXTS, c as DEFAULT_CONTEXT_NAME, d as DEFAULT_NAME_EXTENSION, f as DimensionValue, g as DtcgNode, h as FlatToken, i as FontDef, R as ResolvedCssOptions, T as TokenValue, j as emitCss, k as formatContextsModule, l as formatFontsModule, m as getContexts, n as getFonts, r as resolveCssOptions, t as tokensToCss } from './index-CxeyVs4k.js';
|
package/dist/index.js
CHANGED
package/dist/node.cjs
CHANGED
|
@@ -71,7 +71,8 @@ function resolveCssOptions(options = {}) {
|
|
|
71
71
|
contexts,
|
|
72
72
|
colorFormat: options.colorFormat ?? "oklch",
|
|
73
73
|
dimensionUnit: options.dimensionUnit ?? "preserve",
|
|
74
|
-
nameExtension: options.nameExtension ?? DEFAULT_NAME_EXTENSION
|
|
74
|
+
nameExtension: options.nameExtension ?? DEFAULT_NAME_EXTENSION,
|
|
75
|
+
includeAll: options.includeAll ?? false
|
|
75
76
|
};
|
|
76
77
|
}
|
|
77
78
|
|
|
@@ -165,6 +166,11 @@ function nameFromPath(path) {
|
|
|
165
166
|
}
|
|
166
167
|
return segments.join("-");
|
|
167
168
|
}
|
|
169
|
+
function pathToKebabName(path) {
|
|
170
|
+
return path.split(".").map(
|
|
171
|
+
(segment) => segment.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "")
|
|
172
|
+
).filter((segment) => segment.length > 0).join("-");
|
|
173
|
+
}
|
|
168
174
|
function cssNames(token, nameExtension, useExportName) {
|
|
169
175
|
if (useExportName) {
|
|
170
176
|
const names = exportNames(token, nameExtension);
|
|
@@ -261,9 +267,20 @@ function serializeValue(value, options) {
|
|
|
261
267
|
// src/emit.ts
|
|
262
268
|
function buildContextVars(tokens, context, useExportName, options) {
|
|
263
269
|
const flat = resolveReferences(flattenForContext(tokens, context));
|
|
270
|
+
const includeUnnamed = useExportName && options.includeAll;
|
|
271
|
+
const exportNames2 = /* @__PURE__ */ new Set();
|
|
272
|
+
if (includeUnnamed) {
|
|
273
|
+
for (const token of flat.values()) {
|
|
274
|
+
for (const name of cssNames(token, options.nameExtension, true)) exportNames2.add(name);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
264
277
|
const vars = /* @__PURE__ */ new Map();
|
|
265
278
|
for (const token of flat.values()) {
|
|
266
|
-
|
|
279
|
+
let names = cssNames(token, options.nameExtension, useExportName);
|
|
280
|
+
if (names.length === 0 && includeUnnamed) {
|
|
281
|
+
const generated = pathToKebabName(token.path);
|
|
282
|
+
if (generated && !exportNames2.has(generated) && !vars.has(generated)) names = [generated];
|
|
283
|
+
}
|
|
267
284
|
if (names.length === 0) continue;
|
|
268
285
|
const value = serializeValue(token.value, options);
|
|
269
286
|
for (const name of names) vars.set(name, value);
|
|
@@ -490,6 +507,7 @@ async function initConfig(options = {}) {
|
|
|
490
507
|
}
|
|
491
508
|
if (options.colorFormat) config.colorFormat = options.colorFormat;
|
|
492
509
|
if (options.dimensionUnit) config.dimensionUnit = options.dimensionUnit;
|
|
510
|
+
if (options.includeAll) config.includeAll = true;
|
|
493
511
|
if ((0, import_node_fs.existsSync)(configPath) && !options.force) {
|
|
494
512
|
const wantsLinkUpdate = options.projectId !== void 0 || options.version !== void 0;
|
|
495
513
|
if (!wantsLinkUpdate) {
|