bdsg-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,63 @@
1
+ import { adjustColorForContrast, calculateContrast, meetsWCAG } from "bdsg";
2
+ import chalk from "chalk";
3
+ import { Command } from "commander";
4
+ export const validateCommand = new Command("validate")
5
+ .description("Validate WCAG contrast between colors")
6
+ .argument("<foreground>", "Foreground color in hex format")
7
+ .argument("<background>", "Background color in hex format")
8
+ .option("-l, --level <level>", "Target WCAG level (AA, AAA)", "AA")
9
+ .option("-s, --size <size>", "Text size (normal, large)", "normal")
10
+ .action((foreground, background, options) => {
11
+ console.log(chalk.bold("\n Contrast Analysis\n"));
12
+ // Calculate contrast
13
+ const ratio = calculateContrast(foreground, background);
14
+ // Check each combination
15
+ const AANormal = meetsWCAG(ratio, "AA", "normal");
16
+ const AALarge = meetsWCAG(ratio, "AA", "large");
17
+ const AAANormal = meetsWCAG(ratio, "AAA", "normal");
18
+ const AAALarge = meetsWCAG(ratio, "AAA", "large");
19
+ // Display colors
20
+ console.log(chalk.dim("Colors"));
21
+ console.log(chalk.dim("──────────────────"));
22
+ console.log(` Foreground: ${chalk.hex(foreground)(foreground)}`);
23
+ console.log(` Background: ${chalk.hex(background)("████")} ${background}`);
24
+ console.log(` Ratio: ${chalk.bold(ratio.toFixed(2))}:1`);
25
+ console.log();
26
+ // WCAG Results
27
+ console.log(chalk.dim("WCAG Results"));
28
+ console.log(chalk.dim("──────────────────"));
29
+ const passSymbol = chalk.green("✓ Pass");
30
+ const failSymbol = chalk.red("✗ Fail");
31
+ console.log(` AA Normal Text: ${AANormal ? passSymbol : failSymbol} (needs 4.5:1)`);
32
+ console.log(` AA Large Text: ${AALarge ? passSymbol : failSymbol} (needs 3.0:1)`);
33
+ console.log(` AAA Normal Text: ${AAANormal ? passSymbol : failSymbol} (needs 7.0:1)`);
34
+ console.log(` AAA Large Text: ${AAALarge ? passSymbol : failSymbol} (needs 4.5:1)`);
35
+ console.log();
36
+ // Suggest fix if failing target level
37
+ const targetLevel = options.level;
38
+ const textSize = options.size;
39
+ const targetMet = meetsWCAG(ratio, targetLevel, textSize);
40
+ if (!targetMet) {
41
+ console.log(chalk.dim("Suggestion"));
42
+ console.log(chalk.dim("──────────────────"));
43
+ try {
44
+ const adjusted = adjustColorForContrast(foreground, background, targetLevel, textSize);
45
+ if (adjusted.adjusted !== foreground) {
46
+ console.log(` For ${targetLevel} ${textSize} text compliance:`);
47
+ console.log(` Try: ${chalk.hex(adjusted.adjusted)(adjusted.adjusted)} (ratio: ${adjusted.ratio.toFixed(2)}:1)`);
48
+ console.log(` Strategy: ${adjusted.strategy}`);
49
+ }
50
+ else {
51
+ console.log(chalk.yellow(" Could not find a suitable adjustment."));
52
+ }
53
+ }
54
+ catch {
55
+ console.log(chalk.yellow(" Could not calculate adjustment."));
56
+ }
57
+ console.log();
58
+ }
59
+ else {
60
+ console.log(chalk.green(`✓ Colors meet ${targetLevel} ${textSize} text requirements!\n`));
61
+ }
62
+ });
63
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { generateCommand } from "./commands/generate.js";
4
+ import { initCommand } from "./commands/init.js";
5
+ import { validateCommand } from "./commands/validate.js";
6
+ const program = new Command();
7
+ program
8
+ .name("bdsg")
9
+ .description("Design system generation CLI")
10
+ .version("0.1.0");
11
+ program.addCommand(initCommand);
12
+ program.addCommand(generateCommand);
13
+ program.addCommand(validateCommand);
14
+ program.parse();
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACL,IAAI,CAAC,MAAM,CAAC;KACZ,WAAW,CAAC,8BAA8B,CAAC;KAC3C,OAAO,CAAC,OAAO,CAAC,CAAC;AAEnB,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;AAEpC,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ColorPalette, ShadowScale, SpacingScale, TypographyScale } from "bdsg";
2
+ interface TokensToWrite {
3
+ palette: ColorPalette;
4
+ typography: TypographyScale;
5
+ spacing: SpacingScale;
6
+ shadows: ShadowScale;
7
+ format: "css" | "json" | "tailwind-v4" | "shadcn";
8
+ outputDir: string;
9
+ }
10
+ export declare function writeTokensToFile(tokens: TokensToWrite): Promise<void>;
11
+ export {};
12
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/utils/files.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,eAAe,EACf,MAAM,MAAM,CAAC;AAEd,UAAU,aAAa;IACtB,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,eAAe,CAAC;IAC5B,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,aAAa,GAAG,QAAQ,CAAC;IAClD,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAY5E"}
@@ -0,0 +1,190 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ export async function writeTokensToFile(tokens) {
4
+ await mkdir(tokens.outputDir, { recursive: true });
5
+ if (tokens.format === "json") {
6
+ await writeJsonTokens(tokens);
7
+ }
8
+ else if (tokens.format === "tailwind-v4") {
9
+ await writeTailwindV4Tokens(tokens);
10
+ }
11
+ else if (tokens.format === "shadcn") {
12
+ await writeShadcnTokens(tokens);
13
+ }
14
+ else {
15
+ await writeCssTokens(tokens);
16
+ }
17
+ }
18
+ async function writeCssTokens(tokens) {
19
+ // Colors CSS
20
+ const colorsContent = generateColorsCss(tokens.palette);
21
+ await writeFile(join(tokens.outputDir, "colors.css"), colorsContent);
22
+ // Typography CSS
23
+ await writeFile(join(tokens.outputDir, "typography.css"), tokens.typography.cssVariables);
24
+ // Spacing CSS
25
+ await writeFile(join(tokens.outputDir, "spacing.css"), tokens.spacing.cssVariables);
26
+ // Shadows CSS
27
+ await writeFile(join(tokens.outputDir, "shadows.css"), tokens.shadows.cssVariables);
28
+ }
29
+ async function writeJsonTokens(tokens) {
30
+ // Colors JSON
31
+ const colors = {};
32
+ for (const [shade, data] of Object.entries(tokens.palette.shades)) {
33
+ colors[`primary-${shade}`] = data.value;
34
+ }
35
+ await writeFile(join(tokens.outputDir, "colors.json"), JSON.stringify({ colors }, null, 2));
36
+ // Typography JSON
37
+ const typography = {};
38
+ for (const token of tokens.typography.tokens) {
39
+ typography[token.name] = {
40
+ fontSize: token.fontSize,
41
+ lineHeight: token.lineHeight,
42
+ letterSpacing: token.letterSpacing,
43
+ };
44
+ }
45
+ await writeFile(join(tokens.outputDir, "typography.json"), JSON.stringify({ typography }, null, 2));
46
+ // Spacing JSON
47
+ const spacing = {};
48
+ for (const token of tokens.spacing.tokens) {
49
+ spacing[token.name] = {
50
+ value: token.formatted,
51
+ px: token.value,
52
+ };
53
+ }
54
+ await writeFile(join(tokens.outputDir, "spacing.json"), JSON.stringify({ spacing }, null, 2));
55
+ // Shadows JSON
56
+ const shadows = {};
57
+ for (const token of tokens.shadows.tokens) {
58
+ shadows[token.name] = token.value;
59
+ }
60
+ await writeFile(join(tokens.outputDir, "shadows.json"), JSON.stringify({ shadows }, null, 2));
61
+ }
62
+ async function writeTailwindV4Tokens(tokens) {
63
+ let content = '@import "tailwindcss";\n\n@theme {\n';
64
+ // Colors
65
+ for (const [shade, data] of Object.entries(tokens.palette.shades)) {
66
+ content += ` --color-primary-${shade}: ${data.value};\n`;
67
+ }
68
+ content += "\n";
69
+ // Typography
70
+ for (const token of tokens.typography.tokens) {
71
+ const remValue = token.fontSize / 16;
72
+ content += ` --font-size-${token.name}: ${remValue}rem;\n`;
73
+ }
74
+ content += "\n";
75
+ // Spacing
76
+ for (const token of tokens.spacing.tokens) {
77
+ content += ` --spacing-${token.name}: ${token.formatted};\n`;
78
+ }
79
+ content += "\n";
80
+ // Shadows
81
+ for (const token of tokens.shadows.tokens) {
82
+ content += ` --shadow-${token.name}: ${token.value};\n`;
83
+ }
84
+ content += "}\n";
85
+ await writeFile(join(tokens.outputDir, "theme.css"), content);
86
+ }
87
+ function generateColorsCss(palette) {
88
+ let css = ":root {\n";
89
+ for (const [shade, data] of Object.entries(palette.shades)) {
90
+ css += ` --color-primary-${shade}: ${data.value};\n`;
91
+ }
92
+ css += "}\n";
93
+ return css;
94
+ }
95
+ async function writeShadcnTokens(tokens) {
96
+ const shades = tokens.palette.shades;
97
+ // Light mode tokens (using palette shades)
98
+ const lightTokens = {
99
+ background: "#ffffff",
100
+ foreground: shades[900].value,
101
+ card: "#ffffff",
102
+ "card-foreground": shades[900].value,
103
+ popover: "#ffffff",
104
+ "popover-foreground": shades[900].value,
105
+ primary: shades[500].value,
106
+ "primary-foreground": shades[50].value,
107
+ secondary: shades[100].value,
108
+ "secondary-foreground": shades[900].value,
109
+ muted: shades[100].value,
110
+ "muted-foreground": shades[500].value,
111
+ accent: shades[100].value,
112
+ "accent-foreground": shades[900].value,
113
+ destructive: "#ef4444",
114
+ border: shades[200].value,
115
+ input: shades[200].value,
116
+ ring: shades[500].value,
117
+ };
118
+ // Dark mode tokens (inverted)
119
+ const darkTokens = {
120
+ background: shades[900].value,
121
+ foreground: shades[50].value,
122
+ card: shades[800].value,
123
+ "card-foreground": shades[50].value,
124
+ popover: shades[800].value,
125
+ "popover-foreground": shades[50].value,
126
+ primary: shades[400].value,
127
+ "primary-foreground": shades[900].value,
128
+ secondary: shades[700].value,
129
+ "secondary-foreground": shades[50].value,
130
+ muted: shades[700].value,
131
+ "muted-foreground": shades[400].value,
132
+ accent: shades[700].value,
133
+ "accent-foreground": shades[50].value,
134
+ destructive: "#dc2626",
135
+ border: shades[700].value,
136
+ input: shades[700].value,
137
+ ring: shades[400].value,
138
+ };
139
+ let content = '@import "tailwindcss";\n\n';
140
+ // @theme block for Tailwind v4 mapping
141
+ content += "@custom-variant dark (&:is(.dark *));\n\n";
142
+ content += "@theme inline {\n";
143
+ content += " --color-background: var(--background);\n";
144
+ content += " --color-foreground: var(--foreground);\n";
145
+ content += " --color-card: var(--card);\n";
146
+ content += " --color-card-foreground: var(--card-foreground);\n";
147
+ content += " --color-popover: var(--popover);\n";
148
+ content += " --color-popover-foreground: var(--popover-foreground);\n";
149
+ content += " --color-primary: var(--primary);\n";
150
+ content += " --color-primary-foreground: var(--primary-foreground);\n";
151
+ content += " --color-secondary: var(--secondary);\n";
152
+ content += " --color-secondary-foreground: var(--secondary-foreground);\n";
153
+ content += " --color-muted: var(--muted);\n";
154
+ content += " --color-muted-foreground: var(--muted-foreground);\n";
155
+ content += " --color-accent: var(--accent);\n";
156
+ content += " --color-accent-foreground: var(--accent-foreground);\n";
157
+ content += " --color-destructive: var(--destructive);\n";
158
+ content += " --color-border: var(--border);\n";
159
+ content += " --color-input: var(--input);\n";
160
+ content += " --color-ring: var(--ring);\n";
161
+ content += " --radius-sm: calc(var(--radius) - 4px);\n";
162
+ content += " --radius-md: calc(var(--radius) - 2px);\n";
163
+ content += " --radius-lg: var(--radius);\n";
164
+ content += " --radius-xl: calc(var(--radius) + 4px);\n";
165
+ content += "}\n\n";
166
+ // :root with light mode tokens
167
+ content += ":root {\n";
168
+ content += " --radius: 0.625rem;\n";
169
+ for (const [name, value] of Object.entries(lightTokens)) {
170
+ content += ` --${name}: ${value};\n`;
171
+ }
172
+ content += "}\n\n";
173
+ // .dark with dark mode tokens
174
+ content += ".dark {\n";
175
+ for (const [name, value] of Object.entries(darkTokens)) {
176
+ content += ` --${name}: ${value};\n`;
177
+ }
178
+ content += "}\n\n";
179
+ // Base layer
180
+ content += "@layer base {\n";
181
+ content += " * {\n";
182
+ content += " @apply border-border outline-ring/50;\n";
183
+ content += " }\n";
184
+ content += " body {\n";
185
+ content += " @apply bg-background text-foreground;\n";
186
+ content += " }\n";
187
+ content += "}\n";
188
+ await writeFile(join(tokens.outputDir, "globals.css"), content);
189
+ }
190
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/utils/files.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "bdsg-cli",
3
+ "version": "0.1.0",
4
+ "description": "CLI for design system generation",
5
+ "type": "module",
6
+ "bin": {
7
+ "bdsg": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "dev": "tsc --watch"
12
+ },
13
+ "dependencies": {
14
+ "bdsg": "workspace:*",
15
+ "commander": "^12.0.0",
16
+ "inquirer": "^9.2.0",
17
+ "chalk": "^5.3.0",
18
+ "ora": "^8.0.0"
19
+ },
20
+ "devDependencies": {
21
+ "@bdsg/config": "workspace:*",
22
+ "@types/inquirer": "^9.0.9",
23
+ "@types/node": "^25.0.6"
24
+ }
25
+ }
@@ -0,0 +1,236 @@
1
+ import { mkdir, writeFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import {
4
+ generatePalette,
5
+ generateShadows,
6
+ generateSpacingScale,
7
+ generateTypographyScale,
8
+ } from "bdsg";
9
+ import chalk from "chalk";
10
+ import { Command } from "commander";
11
+ import ora from "ora";
12
+
13
+ export const generateCommand = new Command("generate")
14
+ .description("Generate specific design tokens")
15
+ .addCommand(
16
+ new Command("palette")
17
+ .description("Generate a color palette from a base color")
18
+ .argument("<color>", "Base color in hex format (e.g., #3B82F6)")
19
+ .option("-n, --name <name>", "Palette name", "primary")
20
+ .option("-o, --output <dir>", "Output directory", "./tokens")
21
+ .option("-f, --format <format>", "Output format (css, json)", "css")
22
+ .action(async (color, options) => {
23
+ const spinner = ora("Generating palette...").start();
24
+
25
+ try {
26
+ const palette = generatePalette(color, options.name);
27
+ await mkdir(options.output, { recursive: true });
28
+
29
+ if (options.format === "json") {
30
+ const colors: Record<string, string> = {};
31
+ for (const [shade, data] of Object.entries(palette.shades)) {
32
+ colors[`${options.name}-${shade}`] = data.value;
33
+ }
34
+ await writeFile(
35
+ join(options.output, `${options.name}.json`),
36
+ JSON.stringify({ colors }, null, 2),
37
+ );
38
+ } else {
39
+ let css = ":root {\n";
40
+ for (const [shade, data] of Object.entries(palette.shades)) {
41
+ css += ` --color-${options.name}-${shade}: ${data.value};\n`;
42
+ }
43
+ css += "}\n";
44
+ await writeFile(join(options.output, `${options.name}.css`), css);
45
+ }
46
+
47
+ spinner.succeed(chalk.green("Palette generated!"));
48
+ console.log(
49
+ chalk.dim(
50
+ `\nFile: ${options.output}/${options.name}.${options.format}`,
51
+ ),
52
+ );
53
+ console.log();
54
+
55
+ // Show preview
56
+ console.log(chalk.bold("Color shades:"));
57
+ for (const [shade, data] of Object.entries(palette.shades)) {
58
+ console.log(` ${shade}: ${data.value}`);
59
+ }
60
+ console.log();
61
+ } catch (error) {
62
+ spinner.fail(chalk.red("Failed to generate palette"));
63
+ console.error(error);
64
+ process.exit(1);
65
+ }
66
+ }),
67
+ )
68
+ .addCommand(
69
+ new Command("typography")
70
+ .description("Generate a typography scale")
71
+ .option("-r, --ratio <ratio>", "Scale ratio", "perfect-fourth")
72
+ .option("-b, --base <size>", "Base font size in px", "16")
73
+ .option("-o, --output <dir>", "Output directory", "./tokens")
74
+ .option("-f, --format <format>", "Output format (css, json)", "css")
75
+ .action(async (options) => {
76
+ const spinner = ora("Generating typography scale...").start();
77
+
78
+ try {
79
+ const typography = generateTypographyScale({
80
+ ratio: options.ratio,
81
+ base: Number.parseInt(options.base, 10),
82
+ });
83
+ await mkdir(options.output, { recursive: true });
84
+
85
+ if (options.format === "json") {
86
+ const tokens: Record<string, unknown> = {};
87
+ for (const token of typography.tokens) {
88
+ tokens[token.name] = {
89
+ fontSize: token.fontSize,
90
+ lineHeight: token.lineHeight,
91
+ letterSpacing: token.letterSpacing,
92
+ };
93
+ }
94
+ await writeFile(
95
+ join(options.output, "typography.json"),
96
+ JSON.stringify({ typography: tokens }, null, 2),
97
+ );
98
+ } else {
99
+ await writeFile(
100
+ join(options.output, "typography.css"),
101
+ typography.cssVariables,
102
+ );
103
+ }
104
+
105
+ spinner.succeed(chalk.green("Typography scale generated!"));
106
+ console.log(
107
+ chalk.dim(`\nFile: ${options.output}/typography.${options.format}`),
108
+ );
109
+ console.log();
110
+
111
+ // Show preview
112
+ console.log(chalk.bold("Font sizes:"));
113
+ for (const token of typography.tokens) {
114
+ console.log(` ${token.name}: ${token.fontSize}px`);
115
+ }
116
+ console.log();
117
+ } catch (error) {
118
+ spinner.fail(chalk.red("Failed to generate typography"));
119
+ console.error(error);
120
+ process.exit(1);
121
+ }
122
+ }),
123
+ )
124
+ .addCommand(
125
+ new Command("spacing")
126
+ .description("Generate a spacing scale")
127
+ .option(
128
+ "-m, --method <method>",
129
+ "Spacing method (fibonacci, linear, t-shirt)",
130
+ "fibonacci",
131
+ )
132
+ .option("-b, --base <size>", "Base spacing in px", "8")
133
+ .option("-o, --output <dir>", "Output directory", "./tokens")
134
+ .option("-f, --format <format>", "Output format (css, json)", "css")
135
+ .action(async (options) => {
136
+ const spinner = ora("Generating spacing scale...").start();
137
+
138
+ try {
139
+ const spacing = generateSpacingScale({
140
+ method: options.method,
141
+ base: Number.parseInt(options.base, 10),
142
+ });
143
+ await mkdir(options.output, { recursive: true });
144
+
145
+ if (options.format === "json") {
146
+ const tokens: Record<string, unknown> = {};
147
+ for (const token of spacing.tokens) {
148
+ tokens[token.name] = {
149
+ value: token.formatted,
150
+ px: token.value,
151
+ };
152
+ }
153
+ await writeFile(
154
+ join(options.output, "spacing.json"),
155
+ JSON.stringify({ spacing: tokens }, null, 2),
156
+ );
157
+ } else {
158
+ await writeFile(
159
+ join(options.output, "spacing.css"),
160
+ spacing.cssVariables,
161
+ );
162
+ }
163
+
164
+ spinner.succeed(chalk.green("Spacing scale generated!"));
165
+ console.log(
166
+ chalk.dim(`\nFile: ${options.output}/spacing.${options.format}`),
167
+ );
168
+ console.log();
169
+
170
+ // Show preview
171
+ console.log(chalk.bold("Spacing values:"));
172
+ for (const token of spacing.tokens) {
173
+ console.log(` ${token.name}: ${token.formatted}`);
174
+ }
175
+ console.log();
176
+ } catch (error) {
177
+ spinner.fail(chalk.red("Failed to generate spacing"));
178
+ console.error(error);
179
+ process.exit(1);
180
+ }
181
+ }),
182
+ )
183
+ .addCommand(
184
+ new Command("shadows")
185
+ .description("Generate shadow tokens")
186
+ .option(
187
+ "-s, --style <style>",
188
+ "Shadow style (material, soft, hard)",
189
+ "material",
190
+ )
191
+ .option("-o, --output <dir>", "Output directory", "./tokens")
192
+ .option("-f, --format <format>", "Output format (css, json)", "css")
193
+ .action(async (options) => {
194
+ const spinner = ora("Generating shadows...").start();
195
+
196
+ try {
197
+ const shadows = generateShadows({
198
+ style: options.style,
199
+ });
200
+ await mkdir(options.output, { recursive: true });
201
+
202
+ if (options.format === "json") {
203
+ const tokens: Record<string, string> = {};
204
+ for (const token of shadows.tokens) {
205
+ tokens[token.name] = token.value;
206
+ }
207
+ await writeFile(
208
+ join(options.output, "shadows.json"),
209
+ JSON.stringify({ shadows: tokens }, null, 2),
210
+ );
211
+ } else {
212
+ await writeFile(
213
+ join(options.output, "shadows.css"),
214
+ shadows.cssVariables,
215
+ );
216
+ }
217
+
218
+ spinner.succeed(chalk.green("Shadows generated!"));
219
+ console.log(
220
+ chalk.dim(`\nFile: ${options.output}/shadows.${options.format}`),
221
+ );
222
+ console.log();
223
+
224
+ // Show preview
225
+ console.log(chalk.bold("Shadow levels:"));
226
+ for (const token of shadows.tokens) {
227
+ console.log(` ${token.name}: elevation ${token.elevation}`);
228
+ }
229
+ console.log();
230
+ } catch (error) {
231
+ spinner.fail(chalk.red("Failed to generate shadows"));
232
+ console.error(error);
233
+ process.exit(1);
234
+ }
235
+ }),
236
+ );