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.
- package/README.md +65 -30
- package/dist/android-CRDfSB3_.d.cts +126 -0
- package/dist/android-DANJjjPO.d.ts +126 -0
- package/dist/builders.cjs +206 -62
- package/dist/builders.cjs.map +1 -1
- package/dist/builders.d.cts +12 -11
- package/dist/builders.d.ts +12 -11
- package/dist/builders.js +206 -62
- package/dist/builders.js.map +1 -1
- package/dist/cli/cli.js +120 -7
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/config.d.ts +321 -0
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/index.js +119 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/dispersa-BC1kDF5u.d.ts +118 -0
- package/dist/dispersa-DL3J_Pmz.d.cts +118 -0
- package/dist/errors-qT4sJgSA.d.cts +104 -0
- package/dist/errors-qT4sJgSA.d.ts +104 -0
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +1 -83
- package/dist/errors.d.ts +1 -83
- package/dist/errors.js.map +1 -1
- package/dist/filters.cjs.map +1 -1
- package/dist/filters.d.cts +2 -2
- package/dist/filters.d.ts +2 -2
- package/dist/filters.js.map +1 -1
- package/dist/{index-CNT2Meyf.d.cts → index-Dajm5rvM.d.ts} +311 -132
- package/dist/{index-CqdaN3X0.d.ts → index-De6SjZYH.d.cts} +311 -132
- package/dist/index.cjs +799 -353
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -329
- package/dist/index.d.ts +8 -329
- package/dist/index.js +793 -353
- package/dist/index.js.map +1 -1
- package/dist/lint.cjs +1017 -0
- package/dist/lint.cjs.map +1 -0
- package/dist/lint.d.cts +463 -0
- package/dist/lint.d.ts +463 -0
- package/dist/lint.js +997 -0
- package/dist/lint.js.map +1 -0
- package/dist/preprocessors.d.cts +2 -2
- package/dist/preprocessors.d.ts +2 -2
- package/dist/renderers.cjs.map +1 -1
- package/dist/renderers.d.cts +7 -6
- package/dist/renderers.d.ts +7 -6
- package/dist/renderers.js.map +1 -1
- package/dist/transforms.d.cts +2 -2
- package/dist/transforms.d.ts +2 -2
- package/dist/{types-CZb19kiq.d.ts → types-8MLtztK3.d.ts} +56 -1
- package/dist/{types-CussyWwe.d.cts → types-BHBHRm0a.d.cts} +56 -1
- package/dist/{types-BAv39mum.d.cts → types-BltzwVYK.d.cts} +1 -1
- package/dist/{types-DWKq-eJj.d.cts → types-CAdUV-fa.d.cts} +1 -1
- package/dist/{types-CzHa7YkW.d.ts → types-DztXKlka.d.ts} +1 -1
- package/dist/{types-Bc0kA7De.d.ts → types-TQHV1MrY.d.cts} +19 -1
- package/dist/{types-Bc0kA7De.d.cts → types-TQHV1MrY.d.ts} +19 -1
- package/dist/{types-BzNcG-rI.d.ts → types-ebxDimRz.d.ts} +1 -1
- 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 {
|
|
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
|
|
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
|
|
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>
|
|
204
|
-
io.stdout(" --
|
|
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
|
package/dist/cli/cli.js.map
CHANGED
|
@@ -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"]}
|
package/dist/cli/config.d.ts
CHANGED
|
@@ -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
|
|
package/dist/cli/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/config.ts"],"names":[],"mappings":";
|
|
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"]}
|