dispersa 0.4.3 → 1.0.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.
Files changed (58) hide show
  1. package/README.md +65 -30
  2. package/dist/android-CRDfSB3_.d.cts +126 -0
  3. package/dist/android-DANJjjPO.d.ts +126 -0
  4. package/dist/builders.cjs +206 -62
  5. package/dist/builders.cjs.map +1 -1
  6. package/dist/builders.d.cts +12 -11
  7. package/dist/builders.d.ts +12 -11
  8. package/dist/builders.js +206 -62
  9. package/dist/builders.js.map +1 -1
  10. package/dist/cli/cli.js +120 -7
  11. package/dist/cli/cli.js.map +1 -1
  12. package/dist/cli/config.d.ts +321 -0
  13. package/dist/cli/config.js.map +1 -1
  14. package/dist/cli/index.js +119 -7
  15. package/dist/cli/index.js.map +1 -1
  16. package/dist/dispersa-BC1kDF5u.d.ts +118 -0
  17. package/dist/dispersa-DL3J_Pmz.d.cts +118 -0
  18. package/dist/errors-qT4sJgSA.d.cts +104 -0
  19. package/dist/errors-qT4sJgSA.d.ts +104 -0
  20. package/dist/errors.cjs.map +1 -1
  21. package/dist/errors.d.cts +1 -83
  22. package/dist/errors.d.ts +1 -83
  23. package/dist/errors.js.map +1 -1
  24. package/dist/filters.cjs.map +1 -1
  25. package/dist/filters.d.cts +2 -2
  26. package/dist/filters.d.ts +2 -2
  27. package/dist/filters.js.map +1 -1
  28. package/dist/{index-CNT2Meyf.d.cts → index-Dajm5rvM.d.ts} +311 -132
  29. package/dist/{index-CqdaN3X0.d.ts → index-De6SjZYH.d.cts} +311 -132
  30. package/dist/index.cjs +799 -353
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +8 -329
  33. package/dist/index.d.ts +8 -329
  34. package/dist/index.js +793 -353
  35. package/dist/index.js.map +1 -1
  36. package/dist/lint.cjs +1017 -0
  37. package/dist/lint.cjs.map +1 -0
  38. package/dist/lint.d.cts +463 -0
  39. package/dist/lint.d.ts +463 -0
  40. package/dist/lint.js +997 -0
  41. package/dist/lint.js.map +1 -0
  42. package/dist/preprocessors.d.cts +2 -2
  43. package/dist/preprocessors.d.ts +2 -2
  44. package/dist/renderers.cjs.map +1 -1
  45. package/dist/renderers.d.cts +7 -6
  46. package/dist/renderers.d.ts +7 -6
  47. package/dist/renderers.js.map +1 -1
  48. package/dist/transforms.d.cts +2 -2
  49. package/dist/transforms.d.ts +2 -2
  50. package/dist/{types-CZb19kiq.d.ts → types-8MLtztK3.d.ts} +56 -1
  51. package/dist/{types-CussyWwe.d.cts → types-BHBHRm0a.d.cts} +56 -1
  52. package/dist/{types-BAv39mum.d.cts → types-BltzwVYK.d.cts} +1 -1
  53. package/dist/{types-DWKq-eJj.d.cts → types-CAdUV-fa.d.cts} +1 -1
  54. package/dist/{types-CzHa7YkW.d.ts → types-DztXKlka.d.ts} +1 -1
  55. package/dist/{types-Bc0kA7De.d.ts → types-TQHV1MrY.d.cts} +19 -1
  56. package/dist/{types-Bc0kA7De.d.cts → types-TQHV1MrY.d.ts} +19 -1
  57. package/dist/{types-BzNcG-rI.d.ts → types-ebxDimRz.d.ts} +1 -1
  58. package/package.json +11 -1
package/dist/cli/cli.js CHANGED
@@ -2,9 +2,60 @@ import { access } from 'fs/promises';
2
2
  import { createRequire } from 'module';
3
3
  import { dirname, resolve, isAbsolute } from 'path';
4
4
  import process from 'process';
5
- import { Dispersa } from 'dispersa';
5
+ import { build, lint } from 'dispersa';
6
6
  import { createJiti } from 'jiti';
7
7
 
8
+ // src/cli/cli.ts
9
+
10
+ // src/cli/formatters/lint-formatter.ts
11
+ var formatLintJson = (result) => {
12
+ return JSON.stringify(result, null, 2);
13
+ };
14
+ var formatLintStylish = (result) => {
15
+ const lines = [];
16
+ if (result.issues.length === 0) {
17
+ return "\u2713 No lint issues found";
18
+ }
19
+ const byToken = /* @__PURE__ */ new Map();
20
+ for (const issue of result.issues) {
21
+ const existing = byToken.get(issue.tokenName) ?? [];
22
+ existing.push(issue);
23
+ byToken.set(issue.tokenName, existing);
24
+ }
25
+ for (const [tokenName, issues] of byToken) {
26
+ lines.push(``);
27
+ lines.push(` ${tokenName}`);
28
+ for (const issue of issues) {
29
+ const severity = issue.severity === "error" ? "\u2716" : "\u26A0";
30
+ const label = issue.severity === "error" ? "error" : "warning";
31
+ lines.push(` ${severity} ${label}: ${issue.message} [${issue.ruleId}]`);
32
+ }
33
+ }
34
+ lines.push(``);
35
+ if (result.errorCount > 0 || result.warningCount > 0) {
36
+ const parts = [];
37
+ if (result.errorCount > 0) {
38
+ parts.push(`${result.errorCount} error${result.errorCount === 1 ? "" : "s"}`);
39
+ }
40
+ if (result.warningCount > 0) {
41
+ parts.push(`${result.warningCount} warning${result.warningCount === 1 ? "" : "s"}`);
42
+ }
43
+ lines.push(`\u2716 ${parts.join(", ")}`);
44
+ }
45
+ return lines.join("\n");
46
+ };
47
+ var formatLintCompact = (result) => {
48
+ const lines = [];
49
+ for (const issue of result.issues) {
50
+ const severity = issue.severity.toUpperCase();
51
+ lines.push(`${severity}: ${issue.ruleId} - ${issue.message} (token: ${issue.tokenName})`);
52
+ }
53
+ if (result.errorCount > 0 || result.warningCount > 0) {
54
+ lines.push(`SUMMARY: ${result.errorCount} errors, ${result.warningCount} warnings`);
55
+ }
56
+ return lines.join("\n");
57
+ };
58
+
8
59
  // src/cli/cli.ts
9
60
  var defaultConfigNames = [
10
61
  "dispersa.config.ts",
@@ -27,6 +78,9 @@ async function runCli(args, options = {}) {
27
78
  printHelp(io);
28
79
  return 0;
29
80
  }
81
+ if (command === "lint") {
82
+ return runLintCommand(args.slice(1), cwd, io);
83
+ }
30
84
  if (command !== "build") {
31
85
  io.stderr(`Unknown command: ${command}`);
32
86
  printHelp(io);
@@ -47,8 +101,7 @@ async function runCli(args, options = {}) {
47
101
  }
48
102
  }
49
103
  const startTime = Date.now();
50
- const dispersa = new Dispersa({ resolver, buildPath, validation });
51
- const result = await dispersa.build(buildConfig);
104
+ const result = await build({ resolver, buildPath, validation, ...buildConfig });
52
105
  const elapsed = Date.now() - startTime;
53
106
  return reportBuildResult(result, verbose, elapsed, io);
54
107
  }
@@ -103,6 +156,50 @@ function reportBuildResult(result, verbose, elapsed, io) {
103
156
  }
104
157
  return 0;
105
158
  }
159
+ async function runLintCommand(args, cwd, io) {
160
+ const verbose = hasFlag(args, "--verbose") || hasFlag(args, "-v");
161
+ const formatArg = getArgValue(args, "--format");
162
+ const format = formatArg === "json" || formatArg === "compact" ? formatArg : "stylish";
163
+ const loaded = await resolveAndLoadConfig(args, cwd, io, verbose);
164
+ if (!loaded) {
165
+ return 1;
166
+ }
167
+ const normalizedConfig = normalizeConfigPaths(loaded.config, loaded.configDir);
168
+ const { lint: lintConfig, validation, resolver } = normalizedConfig;
169
+ if (!lintConfig) {
170
+ io.stderr("No lint configuration found in config file.");
171
+ io.stderr('Add a "lint" property to your dispersa.config.ts');
172
+ return 1;
173
+ }
174
+ if (!resolver) {
175
+ io.stderr("No resolver configuration found in config file.");
176
+ io.stderr('Add a "resolver" property to your dispersa.config.ts');
177
+ return 1;
178
+ }
179
+ if (verbose) {
180
+ io.stdout(`Resolver: ${typeof resolver === "string" ? resolver : "(inline)"}`);
181
+ io.stdout(`Format: ${format}`);
182
+ }
183
+ const startTime = Date.now();
184
+ try {
185
+ const result = await lint({ resolver, ...lintConfig, validation });
186
+ const elapsed = Date.now() - startTime;
187
+ const formatter = format === "json" ? formatLintJson : format === "compact" ? formatLintCompact : formatLintStylish;
188
+ const output = formatter(result);
189
+ io.stdout(output);
190
+ if (verbose) {
191
+ io.stdout(`Duration: ${elapsed}ms`);
192
+ }
193
+ return result.errorCount > 0 ? 1 : 0;
194
+ } catch (error) {
195
+ io.stderr("Lint failed.");
196
+ io.stderr(`- ${error instanceof Error ? error.message : String(error)}`);
197
+ if (verbose) {
198
+ io.stderr(`Duration: ${Date.now() - startTime}ms`);
199
+ }
200
+ return 1;
201
+ }
202
+ }
106
203
  function getArgValue(args, flag) {
107
204
  const index = args.indexOf(flag);
108
205
  if (index === -1 || index === args.length - 1) {
@@ -197,12 +294,28 @@ function isPackageResolvable(name, cwd) {
197
294
  }
198
295
  }
199
296
  function printHelp(io) {
200
- io.stdout("dispersa build [options]");
297
+ io.stdout("dispersa <command> [options]");
298
+ io.stdout("");
299
+ io.stdout("Commands:");
300
+ io.stdout(" build Build design tokens");
301
+ io.stdout(" lint Lint design tokens without building");
302
+ io.stdout("");
303
+ io.stdout("Build Options:");
304
+ io.stdout(" --config <path> Path to dispersa.config.(ts|js|mts|mjs|cts|cjs)");
305
+ io.stdout(" --verbose, -v Show detailed build output (timing, error context)");
201
306
  io.stdout("");
202
- io.stdout("Options:");
203
- io.stdout(" --config <path> Path to dispersa.config.(ts|js|mts|mjs|cts|cjs)");
204
- io.stdout(" --verbose, -v Show detailed build output (timing, error context)");
307
+ io.stdout("Lint Options:");
308
+ io.stdout(" --config <path> Path to dispersa.config.(ts|js|mts|mjs|cts|cjs)");
309
+ io.stdout(" --format <format> Output format: stylish (default), json, compact");
310
+ io.stdout(" --verbose, -v Show detailed lint output");
205
311
  }
312
+ /**
313
+ * @license MIT
314
+ * Copyright (c) 2025-present Dispersa
315
+ *
316
+ * This source code is licensed under the MIT license found in the
317
+ * LICENSE file in the root directory of this source tree.
318
+ */
206
319
 
207
320
  export { runCli };
208
321
  //# sourceMappingURL=cli.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/cli.ts"],"names":["require"],"mappings":"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","file":"cli.js","sourcesContent":["import { access } from 'node:fs/promises'\nimport { createRequire } from 'node:module'\nimport { dirname, isAbsolute, resolve } from 'node:path'\nimport process from 'node:process'\n\nimport { Dispersa, type BuildConfig } from 'dispersa'\nimport { createJiti } from 'jiti'\n\nimport type { CliConfig } from './config'\n\ntype CliIO = {\n stdout: (message: string) => void\n stderr: (message: string) => void\n}\n\ntype RunOptions = {\n cwd?: string\n io?: CliIO\n}\n\nconst defaultConfigNames = [\n 'dispersa.config.ts',\n 'dispersa.config.js',\n 'dispersa.config.mts',\n 'dispersa.config.mjs',\n 'dispersa.config.cts',\n 'dispersa.config.cjs',\n]\n\nexport async function runCli(args: string[], options: RunOptions = {}): Promise<number> {\n const cwd = options.cwd ?? process.cwd()\n const io: CliIO = options.io ?? {\n stdout: (message) => process.stdout.write(`${message}\\n`),\n stderr: (message) => process.stderr.write(`${message}\\n`),\n }\n\n const command = args[0] ?? 'build'\n if (command === '--help' || command === '-h' || command === 'help') {\n printHelp(io)\n return 0\n }\n\n if (command !== 'build') {\n io.stderr(`Unknown command: ${command}`)\n printHelp(io)\n return 1\n }\n\n const verbose = hasFlag(args, '--verbose') || hasFlag(args, '-v')\n const loaded = await resolveAndLoadConfig(args, cwd, io, verbose)\n if (!loaded) {\n return 1\n }\n\n const normalizedConfig = normalizeConfigPaths(loaded.config, loaded.configDir)\n const { validation, resolver, buildPath, ...buildConfig } = normalizedConfig\n\n if (verbose) {\n const outputCount = buildConfig.outputs?.length ?? 0\n io.stdout(`Outputs: ${outputCount} configured`)\n if (buildPath) {\n io.stdout(`Build path: ${buildPath}`)\n }\n }\n\n const startTime = Date.now()\n const dispersa = new Dispersa({ resolver, buildPath, validation })\n const result = await dispersa.build(buildConfig as BuildConfig)\n const elapsed = Date.now() - startTime\n\n return reportBuildResult(result, verbose, elapsed, io)\n}\n\nasync function resolveAndLoadConfig(\n args: string[],\n cwd: string,\n io: CliIO,\n verbose: boolean,\n): Promise<{ config: CliConfig; configDir: string } | undefined> {\n const configPath = getArgValue(args, '--config')\n const resolvedPath = await resolveConfigPath(configPath, cwd)\n if (resolvedPath === undefined) {\n io.stderr(\n `No config found. Expected one of: ${defaultConfigNames.join(', ')} ` +\n 'or pass --config <path>.',\n )\n return undefined\n }\n\n if (verbose) {\n io.stdout(`Config: ${resolvedPath}`)\n }\n\n try {\n const config = await loadConfig(resolvedPath, cwd)\n return { config, configDir: dirname(resolvedPath) }\n } catch (error) {\n io.stderr(`Failed to load config: ${resolvedPath}`)\n io.stderr(`- ${error instanceof Error ? error.message : String(error)}`)\n return undefined\n }\n}\n\nfunction reportBuildResult(\n result: Awaited<ReturnType<Dispersa['build']>>,\n verbose: boolean,\n elapsed: number,\n io: CliIO,\n): number {\n if (!result.success) {\n io.stderr('Build failed.')\n for (const error of result.errors ?? []) {\n io.stderr(`- [${error.code}] ${error.message}`)\n if (verbose && error.tokenPath) {\n io.stderr(` Token: ${error.tokenPath}`)\n }\n if (verbose && error.path) {\n io.stderr(` File: ${error.path}`)\n }\n if (verbose && error.suggestions && error.suggestions.length > 0) {\n io.stderr(` Suggestions: ${error.suggestions.join(', ')}`)\n }\n }\n if (verbose) {\n io.stderr(`Duration: ${elapsed}ms`)\n }\n return 1\n }\n\n io.stdout('Build succeeded.')\n for (const output of result.outputs) {\n const location = output.path ?? '(in-memory)'\n io.stdout(`- ${output.name}: ${location}`)\n }\n\n if (verbose) {\n io.stdout(`Duration: ${elapsed}ms`)\n }\n\n return 0\n}\n\nfunction getArgValue(args: string[], flag: string): string | undefined {\n const index = args.indexOf(flag)\n if (index === -1 || index === args.length - 1) {\n return undefined\n }\n const value = args[index + 1]\n if (value == null || value.startsWith('-')) {\n return undefined\n }\n return value\n}\n\nfunction hasFlag(args: string[], flag: string): boolean {\n return args.includes(flag)\n}\n\nasync function resolveConfigPath(\n configPath: string | undefined,\n cwd: string,\n): Promise<string | undefined> {\n if (configPath) {\n const fullPath = resolve(cwd, configPath)\n if (!(await fileExists(fullPath))) {\n return undefined\n }\n return fullPath\n }\n\n for (const name of defaultConfigNames) {\n const fullPath = resolve(cwd, name)\n if (await fileExists(fullPath)) {\n return fullPath\n }\n }\n\n return undefined\n}\n\nasync function loadConfig(configPath: string, cwd: string): Promise<CliConfig> {\n const alias = await buildAliasMap(cwd)\n const loader = createJiti(cwd, {\n interopDefault: true,\n alias,\n })\n const loaded = await loader(configPath)\n const config = (loaded as { default?: CliConfig }).default ?? (loaded as CliConfig)\n\n if (config == null || typeof config !== 'object') {\n throw new Error(`Invalid config: ${configPath} did not export an object`)\n }\n\n return config\n}\n\nfunction normalizeConfigPaths(config: CliConfig, configDir: string): CliConfig {\n const resolver =\n typeof config.resolver === 'string'\n ? resolveIfRelative(config.resolver, configDir)\n : config.resolver\n const buildPath = resolveIfRelative(config.buildPath, configDir)\n const outputs = config.outputs ?? []\n\n return {\n ...config,\n resolver,\n buildPath,\n outputs,\n }\n}\n\nfunction resolveIfRelative(value: string | undefined, baseDir: string): string | undefined {\n if (!value) {\n return value\n }\n return isAbsolute(value) ? value : resolve(baseDir, value)\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path)\n return true\n } catch {\n return false\n }\n}\n\nasync function buildAliasMap(cwd: string): Promise<Record<string, string>> {\n const alias: Record<string, string> = {}\n\n // Dev monorepo: point to source files for hot-reload\n const coreSourcePath = resolve(cwd, 'packages/core/src/index.ts')\n if (await fileExists(coreSourcePath)) {\n alias['dispersa'] = coreSourcePath\n return alias\n }\n\n // Not resolvable from cwd — try from the CLI module's own location\n // (handles workspace symlinks and global installs)\n if (!isPackageResolvable('dispersa', cwd)) {\n const require = createRequire(import.meta.url)\n try {\n alias['dispersa'] = require.resolve('dispersa')\n } catch {\n // Not resolvable at all; config loading will fail with a clear error\n }\n }\n\n return alias\n}\n\nfunction isPackageResolvable(name: string, cwd: string): boolean {\n const require = createRequire(import.meta.url)\n try {\n require.resolve(name, { paths: [cwd] })\n return true\n } catch {\n return false\n }\n}\n\nfunction printHelp(io: CliIO): void {\n io.stdout('dispersa build [options]')\n io.stdout('')\n io.stdout('Options:')\n io.stdout(' --config <path> Path to dispersa.config.(ts|js|mts|mjs|cts|cjs)')\n io.stdout(' --verbose, -v Show detailed build output (timing, error context)')\n}\n"]}
1
+ {"version":3,"sources":["../../src/cli/formatters/lint-formatter.ts","../../src/cli/cli.ts"],"names":["require"],"mappings":"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","file":"cli.js","sourcesContent":["/**\n * @license MIT\n * Copyright (c) 2025-present Dispersa\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n/**\n * @fileoverview Lint output formatter interface and utilities\n */\n\nimport type { LintIssue, LintResult, LintFormatter } from '@lint/types'\n\n/**\n * Format lint results as JSON\n */\nexport const formatLintJson: LintFormatter = (result: LintResult): string => {\n return JSON.stringify(result, null, 2)\n}\n\n/**\n * Format lint results in a human-readable stylish format\n */\nexport const formatLintStylish: LintFormatter = (result: LintResult): string => {\n const lines: string[] = []\n\n if (result.issues.length === 0) {\n return '✓ No lint issues found'\n }\n\n // Group issues by token\n const byToken = new Map<string, LintIssue[]>()\n for (const issue of result.issues) {\n const existing = byToken.get(issue.tokenName) ?? []\n existing.push(issue)\n byToken.set(issue.tokenName, existing)\n }\n\n // Output issues\n for (const [tokenName, issues] of byToken) {\n lines.push(``)\n lines.push(` ${tokenName}`)\n for (const issue of issues) {\n const severity = issue.severity === 'error' ? '✖' : '⚠'\n const label = issue.severity === 'error' ? 'error' : 'warning'\n lines.push(` ${severity} ${label}: ${issue.message} [${issue.ruleId}]`)\n }\n }\n\n // Summary\n lines.push(``)\n if (result.errorCount > 0 || result.warningCount > 0) {\n const parts: string[] = []\n if (result.errorCount > 0) {\n parts.push(`${result.errorCount} error${result.errorCount === 1 ? '' : 's'}`)\n }\n if (result.warningCount > 0) {\n parts.push(`${result.warningCount} warning${result.warningCount === 1 ? '' : 's'}`)\n }\n lines.push(`✖ ${parts.join(', ')}`)\n }\n\n return lines.join('\\n')\n}\n\n/**\n * Format lint results for CI output (compact, parseable)\n */\nexport const formatLintCompact: LintFormatter = (result: LintResult): string => {\n const lines: string[] = []\n\n for (const issue of result.issues) {\n const severity = issue.severity.toUpperCase()\n lines.push(`${severity}: ${issue.ruleId} - ${issue.message} (token: ${issue.tokenName})`)\n }\n\n if (result.errorCount > 0 || result.warningCount > 0) {\n lines.push(`SUMMARY: ${result.errorCount} errors, ${result.warningCount} warnings`)\n }\n\n return lines.join('\\n')\n}\n","import { access } from 'node:fs/promises'\nimport { createRequire } from 'node:module'\nimport { dirname, isAbsolute, resolve } from 'node:path'\nimport process from 'node:process'\n\nimport type { LintOutputFormat } from '@lint/types'\nimport { build, lint, type BuildConfig } from 'dispersa'\nimport { createJiti } from 'jiti'\n\nimport type { CliConfig } from './config'\nimport { formatLintCompact, formatLintJson, formatLintStylish } from './formatters/lint-formatter'\n\ntype CliIO = {\n stdout: (message: string) => void\n stderr: (message: string) => void\n}\n\ntype RunOptions = {\n cwd?: string\n io?: CliIO\n}\n\nconst defaultConfigNames = [\n 'dispersa.config.ts',\n 'dispersa.config.js',\n 'dispersa.config.mts',\n 'dispersa.config.mjs',\n 'dispersa.config.cts',\n 'dispersa.config.cjs',\n]\n\nexport async function runCli(args: string[], options: RunOptions = {}): Promise<number> {\n const cwd = options.cwd ?? process.cwd()\n const io: CliIO = options.io ?? {\n stdout: (message) => process.stdout.write(`${message}\\n`),\n stderr: (message) => process.stderr.write(`${message}\\n`),\n }\n\n const command = args[0] ?? 'build'\n if (command === '--help' || command === '-h' || command === 'help') {\n printHelp(io)\n return 0\n }\n\n if (command === 'lint') {\n return runLintCommand(args.slice(1), cwd, io)\n }\n\n if (command !== 'build') {\n io.stderr(`Unknown command: ${command}`)\n printHelp(io)\n return 1\n }\n\n const verbose = hasFlag(args, '--verbose') || hasFlag(args, '-v')\n const loaded = await resolveAndLoadConfig(args, cwd, io, verbose)\n if (!loaded) {\n return 1\n }\n\n const normalizedConfig = normalizeConfigPaths(loaded.config, loaded.configDir)\n const { validation, resolver, buildPath, ...buildConfig } = normalizedConfig\n\n if (verbose) {\n const outputCount = buildConfig.outputs?.length ?? 0\n io.stdout(`Outputs: ${outputCount} configured`)\n if (buildPath) {\n io.stdout(`Build path: ${buildPath}`)\n }\n }\n\n const startTime = Date.now()\n const result = await build({ resolver, buildPath, validation, ...buildConfig } as BuildConfig)\n const elapsed = Date.now() - startTime\n\n return reportBuildResult(result, verbose, elapsed, io)\n}\n\nasync function resolveAndLoadConfig(\n args: string[],\n cwd: string,\n io: CliIO,\n verbose: boolean,\n): Promise<{ config: CliConfig; configDir: string } | undefined> {\n const configPath = getArgValue(args, '--config')\n const resolvedPath = await resolveConfigPath(configPath, cwd)\n if (resolvedPath === undefined) {\n io.stderr(\n `No config found. Expected one of: ${defaultConfigNames.join(', ')} ` +\n 'or pass --config <path>.',\n )\n return undefined\n }\n\n if (verbose) {\n io.stdout(`Config: ${resolvedPath}`)\n }\n\n try {\n const config = await loadConfig(resolvedPath, cwd)\n return { config, configDir: dirname(resolvedPath) }\n } catch (error) {\n io.stderr(`Failed to load config: ${resolvedPath}`)\n io.stderr(`- ${error instanceof Error ? error.message : String(error)}`)\n return undefined\n }\n}\n\nfunction reportBuildResult(\n result: Awaited<ReturnType<typeof build>>,\n verbose: boolean,\n elapsed: number,\n io: CliIO,\n): number {\n if (!result.success) {\n io.stderr('Build failed.')\n for (const error of result.errors ?? []) {\n io.stderr(`- [${error.code}] ${error.message}`)\n if (verbose && error.tokenPath) {\n io.stderr(` Token: ${error.tokenPath}`)\n }\n if (verbose && error.path) {\n io.stderr(` File: ${error.path}`)\n }\n if (verbose && error.suggestions && error.suggestions.length > 0) {\n io.stderr(` Suggestions: ${error.suggestions.join(', ')}`)\n }\n }\n if (verbose) {\n io.stderr(`Duration: ${elapsed}ms`)\n }\n return 1\n }\n\n io.stdout('Build succeeded.')\n for (const output of result.outputs) {\n const location = output.path ?? '(in-memory)'\n io.stdout(`- ${output.name}: ${location}`)\n }\n\n if (verbose) {\n io.stdout(`Duration: ${elapsed}ms`)\n }\n\n return 0\n}\n\nasync function runLintCommand(args: string[], cwd: string, io: CliIO): Promise<number> {\n const verbose = hasFlag(args, '--verbose') || hasFlag(args, '-v')\n const formatArg = getArgValue(args, '--format')\n const format: LintOutputFormat =\n formatArg === 'json' || formatArg === 'compact' ? formatArg : 'stylish'\n\n const loaded = await resolveAndLoadConfig(args, cwd, io, verbose)\n if (!loaded) {\n return 1\n }\n\n const normalizedConfig = normalizeConfigPaths(loaded.config, loaded.configDir)\n const { lint: lintConfig, validation, resolver } = normalizedConfig\n\n if (!lintConfig) {\n io.stderr('No lint configuration found in config file.')\n io.stderr('Add a \"lint\" property to your dispersa.config.ts')\n return 1\n }\n\n if (!resolver) {\n io.stderr('No resolver configuration found in config file.')\n io.stderr('Add a \"resolver\" property to your dispersa.config.ts')\n return 1\n }\n\n if (verbose) {\n io.stdout(`Resolver: ${typeof resolver === 'string' ? resolver : '(inline)'}`)\n io.stdout(`Format: ${format}`)\n }\n\n const startTime = Date.now()\n\n try {\n const result = await lint({ resolver, ...lintConfig, validation })\n const elapsed = Date.now() - startTime\n\n const formatter =\n format === 'json'\n ? formatLintJson\n : format === 'compact'\n ? formatLintCompact\n : formatLintStylish\n\n const output = formatter(result)\n io.stdout(output)\n\n if (verbose) {\n io.stdout(`Duration: ${elapsed}ms`)\n }\n\n return result.errorCount > 0 ? 1 : 0\n } catch (error) {\n io.stderr('Lint failed.')\n io.stderr(`- ${error instanceof Error ? error.message : String(error)}`)\n if (verbose) {\n io.stderr(`Duration: ${Date.now() - startTime}ms`)\n }\n return 1\n }\n}\n\nfunction getArgValue(args: string[], flag: string): string | undefined {\n const index = args.indexOf(flag)\n if (index === -1 || index === args.length - 1) {\n return undefined\n }\n const value = args[index + 1]\n if (value == null || value.startsWith('-')) {\n return undefined\n }\n return value\n}\n\nfunction hasFlag(args: string[], flag: string): boolean {\n return args.includes(flag)\n}\n\nasync function resolveConfigPath(\n configPath: string | undefined,\n cwd: string,\n): Promise<string | undefined> {\n if (configPath) {\n const fullPath = resolve(cwd, configPath)\n if (!(await fileExists(fullPath))) {\n return undefined\n }\n return fullPath\n }\n\n for (const name of defaultConfigNames) {\n const fullPath = resolve(cwd, name)\n if (await fileExists(fullPath)) {\n return fullPath\n }\n }\n\n return undefined\n}\n\nasync function loadConfig(configPath: string, cwd: string): Promise<CliConfig> {\n const alias = await buildAliasMap(cwd)\n const loader = createJiti(cwd, {\n interopDefault: true,\n alias,\n })\n const loaded = await loader(configPath)\n const config = (loaded as { default?: CliConfig }).default ?? (loaded as CliConfig)\n\n if (config == null || typeof config !== 'object') {\n throw new Error(`Invalid config: ${configPath} did not export an object`)\n }\n\n return config\n}\n\nfunction normalizeConfigPaths(config: CliConfig, configDir: string): CliConfig {\n const resolver =\n typeof config.resolver === 'string'\n ? resolveIfRelative(config.resolver, configDir)\n : config.resolver\n const buildPath = resolveIfRelative(config.buildPath, configDir)\n const outputs = config.outputs ?? []\n\n return {\n ...config,\n resolver,\n buildPath,\n outputs,\n }\n}\n\nfunction resolveIfRelative(value: string | undefined, baseDir: string): string | undefined {\n if (!value) {\n return value\n }\n return isAbsolute(value) ? value : resolve(baseDir, value)\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await access(path)\n return true\n } catch {\n return false\n }\n}\n\nasync function buildAliasMap(cwd: string): Promise<Record<string, string>> {\n const alias: Record<string, string> = {}\n\n // Dev monorepo: point to source files for hot-reload\n const coreSourcePath = resolve(cwd, 'packages/core/src/index.ts')\n if (await fileExists(coreSourcePath)) {\n alias['dispersa'] = coreSourcePath\n return alias\n }\n\n // Not resolvable from cwd — try from the CLI module's own location\n // (handles workspace symlinks and global installs)\n if (!isPackageResolvable('dispersa', cwd)) {\n const require = createRequire(import.meta.url)\n try {\n alias['dispersa'] = require.resolve('dispersa')\n } catch {\n // Not resolvable at all; config loading will fail with a clear error\n }\n }\n\n return alias\n}\n\nfunction isPackageResolvable(name: string, cwd: string): boolean {\n const require = createRequire(import.meta.url)\n try {\n require.resolve(name, { paths: [cwd] })\n return true\n } catch {\n return false\n }\n}\n\nfunction printHelp(io: CliIO): void {\n io.stdout('dispersa <command> [options]')\n io.stdout('')\n io.stdout('Commands:')\n io.stdout(' build Build design tokens')\n io.stdout(' lint Lint design tokens without building')\n io.stdout('')\n io.stdout('Build Options:')\n io.stdout(' --config <path> Path to dispersa.config.(ts|js|mts|mjs|cts|cjs)')\n io.stdout(' --verbose, -v Show detailed build output (timing, error context)')\n io.stdout('')\n io.stdout('Lint Options:')\n io.stdout(' --config <path> Path to dispersa.config.(ts|js|mts|mjs|cts|cjs)')\n io.stdout(' --format <format> Output format: stylish (default), json, compact')\n io.stdout(' --verbose, -v Show detailed lint output')\n}\n"]}
@@ -1,7 +1,328 @@
1
1
  import { BuildConfig, ValidationOptions } from 'dispersa';
2
2
 
3
+ /**
4
+ * @fileoverview Token types - extended from schema-generated types
5
+ *
6
+ * Base token types are defined manually to match DTCG 2025.10.
7
+ * This keeps TypeScript types stable while runtime validation relies on
8
+ * the vendored DTCG JSON Schemas.
9
+ */
10
+ type JsonPointerReferenceObject = {
11
+ $ref: string;
12
+ };
13
+ type TokenValueReference = string | JsonPointerReferenceObject;
14
+ type Token = {
15
+ $value?: TokenValue | TokenValueReference;
16
+ $ref?: string;
17
+ $type?: TokenType;
18
+ $description?: string;
19
+ $deprecated?: boolean | string;
20
+ $extensions?: Record<string, unknown>;
21
+ };
22
+ /**
23
+ * Token type discriminator - union of all valid token type strings
24
+ *
25
+ * Represents the possible values for the $type property in DTCG tokens.
26
+ */
27
+ type TokenType = 'color' | 'dimension' | 'fontFamily' | 'fontWeight' | 'duration' | 'cubicBezier' | 'number' | 'shadow' | 'typography' | 'border' | 'strokeStyle' | 'transition' | 'gradient';
28
+ /**
29
+ * Token value types - any valid value that can appear in a token
30
+ *
31
+ * Represents the possible types for the $value property in tokens.
32
+ * Can be primitives, objects, or arrays depending on the token type.
33
+ */
34
+ type TokenValue = string | number | boolean | Record<string, unknown> | unknown[];
35
+ /**
36
+ * Fully resolved token with computed metadata
37
+ *
38
+ * After resolution, tokens include additional metadata like their
39
+ * full path in the token hierarchy and the original value before
40
+ * any alias or reference resolution.
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * {
45
+ * $value: "#ff0000",
46
+ * $type: "color",
47
+ * path: ["color", "brand", "primary"],
48
+ * name: "color.brand.primary",
49
+ * originalValue: "{color.red.500}" // Before alias resolution
50
+ * }
51
+ * ```
52
+ */
53
+ type ResolvedToken = Token & {
54
+ /** Hierarchical path segments (e.g., ['color', 'brand', 'primary']) */
55
+ path: string[];
56
+ /** Fully qualified token name (e.g., 'color.brand.primary') */
57
+ name: string;
58
+ /**
59
+ * The raw value before any alias or reference resolution.
60
+ *
61
+ * For alias tokens this contains the alias reference string
62
+ * (e.g., `"{color.primary}"`) or a composite value with embedded
63
+ * alias references. For non-alias tokens this equals `$value`.
64
+ *
65
+ * Use the built-in `isAlias()` / `isBase()` filters or inspect
66
+ * this value with `getPureAliasReferenceName()` to determine
67
+ * whether the token was originally an alias.
68
+ */
69
+ originalValue: TokenValue;
70
+ };
71
+ /**
72
+ * Internal resolved token with metadata used by the pipeline and bundlers
73
+ *
74
+ * These fields are not part of the DTCG spec and should be stripped before
75
+ * returning tokens to public callers or rendering output.
76
+ */
77
+ type InternalResolvedToken = ResolvedToken & {
78
+ /** Internal: Whether this token was originally an alias (not part of DTCG spec) */
79
+ _isAlias?: boolean;
80
+ /** Internal: Source modifier tag for bundle outputs (not part of DTCG spec) */
81
+ _sourceModifier?: string;
82
+ /** Internal: Source set name for bundle outputs (not part of DTCG spec) */
83
+ _sourceSet?: string;
84
+ };
85
+ /**
86
+ * Internal collection of resolved tokens (with internal metadata)
87
+ */
88
+ type InternalResolvedTokens = Record<string, InternalResolvedToken>;
89
+
90
+ /**
91
+ * @license MIT
92
+ * Copyright (c) 2025-present Dispersa
93
+ *
94
+ * This source code is licensed under the MIT license found in the
95
+ * LICENSE file in the root directory of this source tree.
96
+ */
97
+ /**
98
+ * @fileoverview Core type definitions for the Dispersa linting system
99
+ *
100
+ * Inspired by ESLint and Terrazzo, this system provides a plugin-based
101
+ * architecture for validating design tokens against semantic rules.
102
+ */
103
+
104
+ /**
105
+ * Lint rule severity levels
106
+ *
107
+ * - `'off'` - Rule is disabled
108
+ * - `'warn'` - Rule issues warnings but doesn't fail the build
109
+ * - `'error'` - Rule issues errors and fails the build (if failOnError is true)
110
+ */
111
+ type Severity = 'off' | 'warn' | 'error';
112
+ /**
113
+ * Metadata describing a lint rule
114
+ *
115
+ * @template MessageIds - Union type of message IDs this rule can produce
116
+ */
117
+ type LintRuleMeta<MessageIds extends string = string> = {
118
+ /** Short name of the rule (e.g., 'require-description') */
119
+ name: string;
120
+ /** Human-readable description of what the rule checks */
121
+ description: string;
122
+ /** Optional URL to documentation for this rule */
123
+ url?: string;
124
+ /** Map of message IDs to message templates (supports {{placeholder}} interpolation) */
125
+ messages: Record<MessageIds, string>;
126
+ /** Token types this rule applies to. Default: 'all' */
127
+ appliesTo?: TokenType[] | 'all';
128
+ };
129
+ /**
130
+ * Context object passed to rule's create() function
131
+ *
132
+ * Provides access to tokens, configuration, and the report function.
133
+ *
134
+ * @template MessageIds - Union type of message IDs this rule can produce
135
+ * @template Options - Rule-specific options type
136
+ */
137
+ type LintRuleContext<MessageIds extends string = string, Options extends Record<string, unknown> = Record<string, never>> = {
138
+ /** Fully qualified rule ID (e.g., 'dispersa/require-description') */
139
+ id: string;
140
+ /** Merged options (defaultOptions + user config) */
141
+ options: Options;
142
+ /** All resolved tokens to validate */
143
+ tokens: InternalResolvedTokens;
144
+ /**
145
+ * Report a lint issue
146
+ *
147
+ * @param descriptor - Issue descriptor with token, message ID, and optional data
148
+ */
149
+ report(descriptor: LintReportDescriptor<MessageIds>): void;
150
+ };
151
+ /**
152
+ * Descriptor for reporting a lint issue
153
+ *
154
+ * @template MessageIds - Union type of message IDs this rule can produce
155
+ */
156
+ type LintReportDescriptor<MessageIds extends string = string> = {
157
+ /** The token that has the issue */
158
+ token: ResolvedToken;
159
+ /** ID of the message to use from rule's meta.messages */
160
+ messageId: MessageIds;
161
+ /** Data to interpolate into the message (replaces {{key}} placeholders) */
162
+ data?: Record<string, string | number>;
163
+ };
164
+ /**
165
+ * A lint rule definition
166
+ *
167
+ * Rules are created using the `createRule()` factory function for type safety.
168
+ *
169
+ * @template MessageIds - Union type of message IDs this rule can produce
170
+ * @template Options - Rule-specific options type
171
+ *
172
+ * @example
173
+ * ```typescript
174
+ * const myRule: LintRule<'MISSING_VALUE', { required: boolean }> = {
175
+ * meta: {
176
+ * name: 'require-value',
177
+ * description: 'Require tokens to have values',
178
+ * messages: {
179
+ * MISSING_VALUE: "Token '{{name}}' is missing a value",
180
+ * },
181
+ * },
182
+ * defaultOptions: { required: true },
183
+ * create({ tokens, report, options }) {
184
+ * for (const token of Object.values(tokens)) {
185
+ * if (options.required && !token.$value) {
186
+ * report({ token, messageId: 'MISSING_VALUE', data: { name: token.name } })
187
+ * }
188
+ * }
189
+ * },
190
+ * }
191
+ * ```
192
+ */
193
+ type LintRule<MessageIds extends string = string, Options extends Record<string, unknown> = Record<string, never>> = {
194
+ /** Rule metadata */
195
+ meta: LintRuleMeta<MessageIds>;
196
+ /** Default options merged with user config */
197
+ defaultOptions?: Options;
198
+ /**
199
+ * Factory function that creates the rule's validation logic
200
+ *
201
+ * Called once per lint run with the context object.
202
+ *
203
+ * @param context - Rule context with tokens, options, and report function
204
+ */
205
+ create(context: LintRuleContext<MessageIds, Options>): void | Promise<void>;
206
+ };
207
+ /**
208
+ * Base rule type without generic parameters for use in plugin definitions
209
+ */
210
+ type AnyLintRule = LintRule<string, Record<string, unknown>>;
211
+ /**
212
+ * A lint plugin that provides rules and configurations
213
+ *
214
+ * @example
215
+ * ```typescript
216
+ * const myPlugin: LintPlugin = {
217
+ * meta: {
218
+ * name: 'my-lint-plugin',
219
+ * version: '1.0.0',
220
+ * },
221
+ * rules: {
222
+ * 'my-rule': myRule,
223
+ * },
224
+ * configs: {
225
+ * recommended: {
226
+ * plugins: { my: myPlugin },
227
+ * rules: {
228
+ * 'my/my-rule': 'warn',
229
+ * },
230
+ * },
231
+ * },
232
+ * }
233
+ * ```
234
+ */
235
+ type LintPlugin = {
236
+ /** Plugin metadata */
237
+ meta: {
238
+ /** Package name (e.g., '@dispersa/lint-plugin-a11y') */
239
+ name: string;
240
+ /** Semantic version (optional, for debugging/metadata) */
241
+ version?: string;
242
+ };
243
+ /** Rules provided by this plugin */
244
+ rules: Record<string, AnyLintRule>;
245
+ /** Predefined configurations */
246
+ configs?: Record<string, LintConfig>;
247
+ };
248
+ /**
249
+ * Rule configuration - either severity only or severity with options
250
+ *
251
+ * @example
252
+ * ```typescript
253
+ * // Severity only
254
+ * 'error'
255
+ *
256
+ * // Severity with options
257
+ * ['error', { format: 'kebab-case' }]
258
+ * ```
259
+ */
260
+ type RuleConfig = Severity | [Severity, Record<string, unknown>];
261
+ /**
262
+ * Registry for lint rule options types.
263
+ *
264
+ * Built-in dispersa rules are registered via declaration merging in `./rules/index.ts`.
265
+ * Plugin authors can augment this interface to add their own rule types:
266
+ *
267
+ * @example
268
+ * ```typescript
269
+ * // In your plugin file
270
+ * declare module 'dispersa/lint' {
271
+ * interface RulesRegistry {
272
+ * 'my-plugin/my-rule': MyRuleOptions
273
+ * }
274
+ * }
275
+ * ```
276
+ */
277
+ interface RulesRegistry {
278
+ }
279
+ /**
280
+ * Type-safe configuration for a single rule from the registry.
281
+ *
282
+ * @template K - The rule ID key from RulesRegistry
283
+ */
284
+ type RuleConfigFor<K extends keyof RulesRegistry> = Severity | [Severity, RulesRegistry[K]];
285
+ /**
286
+ * Typed rules configuration with intellisense for all registered rules.
287
+ *
288
+ * Provides autocomplete for rule IDs and their option types.
289
+ * Also allows arbitrary string keys for unregistered rules.
290
+ */
291
+ type TypedRulesConfig = {
292
+ [K in keyof RulesRegistry]?: RuleConfigFor<K>;
293
+ } & Record<string, RuleConfig>;
294
+ /**
295
+ * Lint configuration
296
+ *
297
+ * @template Rules - Rules configuration type (defaults to TypedRulesConfig for intellisense)
298
+ *
299
+ * @example
300
+ * ```typescript
301
+ * const config: LintConfig = {
302
+ * plugins: {
303
+ * dispersa: dispersaPlugin,
304
+ * a11y: '@dispersa/lint-plugin-a11y', // Load by string
305
+ * },
306
+ * rules: {
307
+ * 'dispersa/require-description': 'warn',
308
+ * 'dispersa/naming-convention': ['error', { format: 'kebab-case' }],
309
+ * 'a11y/min-contrast': ['error', { level: 'AA' }],
310
+ * },
311
+ * }
312
+ * ```
313
+ */
314
+ type LintConfig<Rules extends Record<string, RuleConfig> = TypedRulesConfig> = {
315
+ /** Plugins to load (by object or module path string) */
316
+ plugins?: Record<string, LintPlugin | string>;
317
+ /** Rule configurations */
318
+ rules?: Rules;
319
+ /** Fail build on lint errors (default: true) */
320
+ failOnError?: boolean;
321
+ };
322
+
3
323
  type CliConfig = BuildConfig & {
4
324
  validation?: ValidationOptions;
325
+ lint?: LintConfig;
5
326
  };
6
327
  declare function defineConfig(config: CliConfig): CliConfig;
7
328
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/config.ts"],"names":[],"mappings":";AAMO,SAAS,aAAa,MAAA,EAA8B;AACzD,EAAA,OAAO,MAAA;AACT","file":"config.js","sourcesContent":["import type { BuildConfig, ValidationOptions } from 'dispersa'\n\nexport type CliConfig = BuildConfig & {\n validation?: ValidationOptions\n}\n\nexport function defineConfig(config: CliConfig): CliConfig {\n return config\n}\n"]}
1
+ {"version":3,"sources":["../../src/cli/config.ts"],"names":[],"mappings":";AAQO,SAAS,aAAa,MAAA,EAA8B;AACzD,EAAA,OAAO,MAAA;AACT","file":"config.js","sourcesContent":["import type { LintConfig } from '@lint/types'\nimport type { BuildConfig, ValidationOptions } from 'dispersa'\n\nexport type CliConfig = BuildConfig & {\n validation?: ValidationOptions\n lint?: LintConfig\n}\n\nexport function defineConfig(config: CliConfig): CliConfig {\n return config\n}\n"]}