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/index.js
CHANGED
|
@@ -3,6 +3,10 @@ import addFormats from 'ajv-formats';
|
|
|
3
3
|
import { constants } from 'fs';
|
|
4
4
|
import { mkdir, writeFile, access, readFile } from 'fs/promises';
|
|
5
5
|
import * as path from 'path';
|
|
6
|
+
import { isAbsolute, resolve } from 'path';
|
|
7
|
+
import { createRequire } from 'module';
|
|
8
|
+
import process2 from 'process';
|
|
9
|
+
import { createJiti } from 'jiti';
|
|
6
10
|
import { JsonPointer } from 'json-ptr';
|
|
7
11
|
import { kebabCase } from 'change-case';
|
|
8
12
|
import { converter, formatHex8, formatHex } from 'culori';
|
|
@@ -19,7 +23,7 @@ var __export = (target, all) => {
|
|
|
19
23
|
};
|
|
20
24
|
|
|
21
25
|
// src/shared/errors/index.ts
|
|
22
|
-
var DispersaError, TokenReferenceError, CircularReferenceError, ValidationError, FileOperationError, ConfigurationError, BasePermutationError, ModifierError;
|
|
26
|
+
var DispersaError, TokenReferenceError, CircularReferenceError, ValidationError, FileOperationError, ConfigurationError, BasePermutationError, ModifierError, LintError;
|
|
23
27
|
var init_errors = __esm({
|
|
24
28
|
"src/shared/errors/index.ts"() {
|
|
25
29
|
DispersaError = class extends Error {
|
|
@@ -102,23 +106,19 @@ var init_errors = __esm({
|
|
|
102
106
|
this.name = "ModifierError";
|
|
103
107
|
}
|
|
104
108
|
};
|
|
109
|
+
LintError = class extends DispersaError {
|
|
110
|
+
constructor(issues) {
|
|
111
|
+
const errorCount = issues.filter((i) => i.severity === "error").length;
|
|
112
|
+
const warningCount = issues.filter((i) => i.severity === "warn").length;
|
|
113
|
+
super(`Lint failed with ${errorCount} error(s) and ${warningCount} warning(s).`);
|
|
114
|
+
this.issues = issues;
|
|
115
|
+
this.name = "LintError";
|
|
116
|
+
}
|
|
117
|
+
};
|
|
105
118
|
}
|
|
106
119
|
});
|
|
107
120
|
|
|
108
121
|
// src/shared/utils/token-utils.ts
|
|
109
|
-
function formatDeprecationMessage(token, description = "", format = "bracket") {
|
|
110
|
-
if (token.$deprecated == null || token.$deprecated === false) {
|
|
111
|
-
return description;
|
|
112
|
-
}
|
|
113
|
-
const deprecationMsg = typeof token.$deprecated === "string" ? token.$deprecated : "";
|
|
114
|
-
if (format === "comment") {
|
|
115
|
-
const msg2 = deprecationMsg ? ` ${deprecationMsg}` : "";
|
|
116
|
-
return `DEPRECATED${msg2}`;
|
|
117
|
-
}
|
|
118
|
-
const msg = deprecationMsg ? `: ${deprecationMsg}` : "";
|
|
119
|
-
const prefix = `[DEPRECATED${msg}]`;
|
|
120
|
-
return description ? `${prefix} ${description}` : prefix;
|
|
121
|
-
}
|
|
122
122
|
function stripInternalTokenMetadata(tokens) {
|
|
123
123
|
const cleaned = {};
|
|
124
124
|
for (const [name, token] of Object.entries(tokens)) {
|
|
@@ -2472,7 +2472,7 @@ var init_schemas = __esm({
|
|
|
2472
2472
|
});
|
|
2473
2473
|
|
|
2474
2474
|
// src/validation/config-schemas.ts
|
|
2475
|
-
var resolverSchemaRef, basePluginProperties, commonRendererOptionsProperties, transformPluginSchema, rendererPluginSchema, filterPluginSchema, preprocessorPluginSchema, outputConfigSchema, dispersaOptionsSchema, buildConfigSchema;
|
|
2475
|
+
var resolverSchemaRef, basePluginProperties, commonRendererOptionsProperties, transformPluginSchema, rendererPluginSchema, filterPluginSchema, preprocessorPluginSchema, lintConfigSchema, outputConfigSchema, dispersaOptionsSchema, buildConfigSchema;
|
|
2476
2476
|
var init_config_schemas = __esm({
|
|
2477
2477
|
"src/validation/config-schemas.ts"() {
|
|
2478
2478
|
init_schemas();
|
|
@@ -2623,6 +2623,42 @@ var init_config_schemas = __esm({
|
|
|
2623
2623
|
}
|
|
2624
2624
|
}
|
|
2625
2625
|
};
|
|
2626
|
+
lintConfigSchema = {
|
|
2627
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
2628
|
+
type: "object",
|
|
2629
|
+
properties: {
|
|
2630
|
+
enabled: {
|
|
2631
|
+
type: "boolean",
|
|
2632
|
+
description: "Enable linting (default: false, opt-in)"
|
|
2633
|
+
},
|
|
2634
|
+
failOnError: {
|
|
2635
|
+
type: "boolean",
|
|
2636
|
+
description: "Fail build on lint errors (default: true)"
|
|
2637
|
+
},
|
|
2638
|
+
plugins: {
|
|
2639
|
+
type: "object",
|
|
2640
|
+
description: "Plugins to load (by object or module path string)",
|
|
2641
|
+
additionalProperties: {
|
|
2642
|
+
oneOf: [{ type: "string" }, { type: "object" }]
|
|
2643
|
+
}
|
|
2644
|
+
},
|
|
2645
|
+
rules: {
|
|
2646
|
+
type: "object",
|
|
2647
|
+
description: "Rule configurations",
|
|
2648
|
+
additionalProperties: {
|
|
2649
|
+
oneOf: [
|
|
2650
|
+
{ type: "string", enum: ["off", "warn", "error"] },
|
|
2651
|
+
{
|
|
2652
|
+
type: "array",
|
|
2653
|
+
minItems: 2,
|
|
2654
|
+
items: [{ type: "string", enum: ["off", "warn", "error"] }, { type: "object" }]
|
|
2655
|
+
}
|
|
2656
|
+
]
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
},
|
|
2660
|
+
additionalProperties: false
|
|
2661
|
+
};
|
|
2626
2662
|
outputConfigSchema = {
|
|
2627
2663
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
2628
2664
|
type: "object",
|
|
@@ -2740,10 +2776,20 @@ var init_config_schemas = __esm({
|
|
|
2740
2776
|
description: "Resolver configuration - file path or ResolverDocument object"
|
|
2741
2777
|
},
|
|
2742
2778
|
buildPath: { type: "string" },
|
|
2779
|
+
validation: {
|
|
2780
|
+
type: "object",
|
|
2781
|
+
properties: {
|
|
2782
|
+
mode: { type: "string", enum: ["error", "warn", "off"] }
|
|
2783
|
+
}
|
|
2784
|
+
},
|
|
2743
2785
|
hooks: {
|
|
2744
2786
|
type: "object",
|
|
2745
2787
|
description: "Global build lifecycle hooks (functions, validated at runtime)",
|
|
2746
2788
|
additionalProperties: true
|
|
2789
|
+
},
|
|
2790
|
+
lint: {
|
|
2791
|
+
...lintConfigSchema,
|
|
2792
|
+
description: "Linting configuration"
|
|
2747
2793
|
}
|
|
2748
2794
|
},
|
|
2749
2795
|
additionalProperties: false
|
|
@@ -3503,6 +3549,94 @@ var init_utils = __esm({
|
|
|
3503
3549
|
}
|
|
3504
3550
|
});
|
|
3505
3551
|
|
|
3552
|
+
// src/renderers/metadata.ts
|
|
3553
|
+
function sanitizeText(text, format) {
|
|
3554
|
+
switch (format) {
|
|
3555
|
+
case "css":
|
|
3556
|
+
case "tailwind":
|
|
3557
|
+
return text.replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ").trim();
|
|
3558
|
+
case "kotlin":
|
|
3559
|
+
return text.replace(/\*\//g, "* /").replace(/\r?\n/g, " ").trim();
|
|
3560
|
+
case "js":
|
|
3561
|
+
case "swift":
|
|
3562
|
+
return text.replace(/\r?\n/g, " ").trim();
|
|
3563
|
+
default:
|
|
3564
|
+
return text.trim();
|
|
3565
|
+
}
|
|
3566
|
+
}
|
|
3567
|
+
function buildDeprecationText(token) {
|
|
3568
|
+
if (token.$deprecated == null || token.$deprecated === false) {
|
|
3569
|
+
return "";
|
|
3570
|
+
}
|
|
3571
|
+
const msg = typeof token.$deprecated === "string" ? token.$deprecated : "";
|
|
3572
|
+
return msg ? `DEPRECATED: ${msg}` : "DEPRECATED";
|
|
3573
|
+
}
|
|
3574
|
+
function buildTokenDescriptionComment(token, format) {
|
|
3575
|
+
if (!token.$description || token.$description === "") {
|
|
3576
|
+
return void 0;
|
|
3577
|
+
}
|
|
3578
|
+
const text = sanitizeText(token.$description, format);
|
|
3579
|
+
switch (format) {
|
|
3580
|
+
case "css":
|
|
3581
|
+
case "tailwind":
|
|
3582
|
+
return `/* ${text} */`;
|
|
3583
|
+
case "js":
|
|
3584
|
+
return `// ${text}`;
|
|
3585
|
+
case "swift":
|
|
3586
|
+
return `/// ${text}`;
|
|
3587
|
+
case "kotlin":
|
|
3588
|
+
return `/** ${text} */`;
|
|
3589
|
+
default:
|
|
3590
|
+
return void 0;
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
function buildTokenDeprecationComment(token, format) {
|
|
3594
|
+
const text = buildDeprecationText(token);
|
|
3595
|
+
if (!text) {
|
|
3596
|
+
return void 0;
|
|
3597
|
+
}
|
|
3598
|
+
switch (format) {
|
|
3599
|
+
case "css":
|
|
3600
|
+
case "tailwind":
|
|
3601
|
+
return `/* ${text} */`;
|
|
3602
|
+
case "js":
|
|
3603
|
+
return `// ${text}`;
|
|
3604
|
+
case "swift":
|
|
3605
|
+
return `/// ${text}`;
|
|
3606
|
+
case "kotlin":
|
|
3607
|
+
return `/** ${text} */`;
|
|
3608
|
+
default:
|
|
3609
|
+
return void 0;
|
|
3610
|
+
}
|
|
3611
|
+
}
|
|
3612
|
+
function buildModifierComment(modifier, context) {
|
|
3613
|
+
return `/* Modifier: ${modifier}=${context} */`;
|
|
3614
|
+
}
|
|
3615
|
+
function buildSwiftDeprecationAttribute(token) {
|
|
3616
|
+
if (token.$deprecated == null || token.$deprecated === false) {
|
|
3617
|
+
return void 0;
|
|
3618
|
+
}
|
|
3619
|
+
const msg = typeof token.$deprecated === "string" ? token.$deprecated : "";
|
|
3620
|
+
if (msg) {
|
|
3621
|
+
return `@available(*, deprecated, message: "${sanitizeText(msg, "swift")}")`;
|
|
3622
|
+
}
|
|
3623
|
+
return "@available(*, deprecated)";
|
|
3624
|
+
}
|
|
3625
|
+
function buildKotlinDeprecationAnnotation(token) {
|
|
3626
|
+
if (token.$deprecated == null || token.$deprecated === false) {
|
|
3627
|
+
return void 0;
|
|
3628
|
+
}
|
|
3629
|
+
const msg = typeof token.$deprecated === "string" ? token.$deprecated : "";
|
|
3630
|
+
if (msg) {
|
|
3631
|
+
return `@Deprecated(message = "${sanitizeText(msg, "kotlin")}")`;
|
|
3632
|
+
}
|
|
3633
|
+
return "@Deprecated";
|
|
3634
|
+
}
|
|
3635
|
+
var init_metadata = __esm({
|
|
3636
|
+
"src/renderers/metadata.ts"() {
|
|
3637
|
+
}
|
|
3638
|
+
});
|
|
3639
|
+
|
|
3506
3640
|
// src/renderers/bundlers/js.ts
|
|
3507
3641
|
var js_exports = {};
|
|
3508
3642
|
__export(js_exports, {
|
|
@@ -3607,7 +3741,7 @@ async function bundleAsJsModule(bundleData, resolver, options, formatTokens) {
|
|
|
3607
3741
|
}
|
|
3608
3742
|
const metadata = buildMetadata(resolver);
|
|
3609
3743
|
const jsBlocks = [];
|
|
3610
|
-
for (const { tokens, modifierInputs } of bundleData) {
|
|
3744
|
+
for (const { tokens, modifierInputs, isBase } of bundleData) {
|
|
3611
3745
|
const cleanTokens = stripInternalMetadata(tokens);
|
|
3612
3746
|
const key = buildStableDashKey({
|
|
3613
3747
|
modifierInputs,
|
|
@@ -3615,10 +3749,30 @@ async function bundleAsJsModule(bundleData, resolver, options, formatTokens) {
|
|
|
3615
3749
|
defaults: metadata.defaults
|
|
3616
3750
|
});
|
|
3617
3751
|
const camelKey = toCamelKey(key);
|
|
3752
|
+
const normalizedInputs = normalizeModifierInputs(modifierInputs);
|
|
3753
|
+
const modifierParts = [];
|
|
3754
|
+
for (const dim of metadata.dimensions) {
|
|
3755
|
+
const value = normalizedInputs[dim.toLowerCase()];
|
|
3756
|
+
if (value) {
|
|
3757
|
+
modifierParts.push(`${dim}=${value}`);
|
|
3758
|
+
}
|
|
3759
|
+
}
|
|
3618
3760
|
const formattedJs = await formatTokens(cleanTokens);
|
|
3619
3761
|
const tokenObject = extractObjectFromJsModule(formattedJs);
|
|
3620
3762
|
const indentedObject = tokenObject.replace(/\n/g, "\n ");
|
|
3621
|
-
|
|
3763
|
+
let comment;
|
|
3764
|
+
if (modifierParts.length > 0) {
|
|
3765
|
+
const modifierPart = modifierParts[0];
|
|
3766
|
+
const eqIndex = modifierPart.indexOf("=");
|
|
3767
|
+
const modifier = modifierPart.slice(0, eqIndex);
|
|
3768
|
+
const context = modifierPart.slice(eqIndex + 1);
|
|
3769
|
+
comment = buildModifierComment(modifier, context);
|
|
3770
|
+
} else if (isBase) {
|
|
3771
|
+
comment = "// Base permutation";
|
|
3772
|
+
} else {
|
|
3773
|
+
comment = `// ${key}`;
|
|
3774
|
+
}
|
|
3775
|
+
jsBlocks.push(` ${comment}
|
|
3622
3776
|
${JSON.stringify(camelKey)}: ${indentedObject}`);
|
|
3623
3777
|
}
|
|
3624
3778
|
return assembleJsBundle(metadata, jsBlocks, options?.generateHelper ?? false);
|
|
@@ -3626,6 +3780,7 @@ async function bundleAsJsModule(bundleData, resolver, options, formatTokens) {
|
|
|
3626
3780
|
var init_js = __esm({
|
|
3627
3781
|
"src/renderers/bundlers/js.ts"() {
|
|
3628
3782
|
init_errors();
|
|
3783
|
+
init_metadata();
|
|
3629
3784
|
init_utils();
|
|
3630
3785
|
}
|
|
3631
3786
|
});
|
|
@@ -3995,7 +4150,8 @@ var BuildOrchestrator = class {
|
|
|
3995
4150
|
resolver,
|
|
3996
4151
|
config.transforms,
|
|
3997
4152
|
config.preprocessors,
|
|
3998
|
-
config.filters
|
|
4153
|
+
config.filters,
|
|
4154
|
+
config.lint
|
|
3999
4155
|
);
|
|
4000
4156
|
return this.executeBuild(buildPath, config, permutations2, resolver);
|
|
4001
4157
|
}
|
|
@@ -4006,7 +4162,8 @@ var BuildOrchestrator = class {
|
|
|
4006
4162
|
modifierInputs,
|
|
4007
4163
|
config.transforms,
|
|
4008
4164
|
config.preprocessors,
|
|
4009
|
-
config.filters
|
|
4165
|
+
config.filters,
|
|
4166
|
+
config.lint
|
|
4010
4167
|
);
|
|
4011
4168
|
return { tokens, modifierInputs: resolvedInputs };
|
|
4012
4169
|
})
|
|
@@ -4267,7 +4424,358 @@ var OutputProcessor = class {
|
|
|
4267
4424
|
|
|
4268
4425
|
// src/build/pipeline/token-pipeline.ts
|
|
4269
4426
|
init_resolver_loader();
|
|
4270
|
-
|
|
4427
|
+
|
|
4428
|
+
// src/lint/plugin-loader.ts
|
|
4429
|
+
init_errors();
|
|
4430
|
+
var PluginLoader = class {
|
|
4431
|
+
cwd;
|
|
4432
|
+
jiti = null;
|
|
4433
|
+
cache = /* @__PURE__ */ new Map();
|
|
4434
|
+
constructor(options = {}) {
|
|
4435
|
+
this.cwd = options.cwd ?? process2.cwd();
|
|
4436
|
+
}
|
|
4437
|
+
/**
|
|
4438
|
+
* Load a plugin from an inline object or module path
|
|
4439
|
+
*
|
|
4440
|
+
* @param source - Plugin object or module path string
|
|
4441
|
+
* @returns Loaded plugin
|
|
4442
|
+
* @throws {ConfigurationError} If plugin cannot be loaded or is invalid
|
|
4443
|
+
*/
|
|
4444
|
+
async load(source) {
|
|
4445
|
+
if (this.isPluginObject(source)) {
|
|
4446
|
+
this.validatePlugin(source);
|
|
4447
|
+
return source;
|
|
4448
|
+
}
|
|
4449
|
+
const modulePath = source;
|
|
4450
|
+
const cached = this.cache.get(modulePath);
|
|
4451
|
+
if (cached) {
|
|
4452
|
+
return cached;
|
|
4453
|
+
}
|
|
4454
|
+
const plugin = await this.loadFromModule(modulePath);
|
|
4455
|
+
this.validatePlugin(plugin);
|
|
4456
|
+
this.cache.set(modulePath, plugin);
|
|
4457
|
+
return plugin;
|
|
4458
|
+
}
|
|
4459
|
+
/**
|
|
4460
|
+
* Load multiple plugins
|
|
4461
|
+
*
|
|
4462
|
+
* @param plugins - Record of namespace to plugin source
|
|
4463
|
+
* @returns Record of namespace to loaded plugin
|
|
4464
|
+
*/
|
|
4465
|
+
async loadAll(plugins) {
|
|
4466
|
+
const entries = Object.entries(plugins);
|
|
4467
|
+
const loaded = await Promise.all(
|
|
4468
|
+
entries.map(async ([namespace, source]) => [namespace, await this.load(source)])
|
|
4469
|
+
);
|
|
4470
|
+
return Object.fromEntries(loaded);
|
|
4471
|
+
}
|
|
4472
|
+
/**
|
|
4473
|
+
* Check if source is an inline plugin object
|
|
4474
|
+
*/
|
|
4475
|
+
isPluginObject(source) {
|
|
4476
|
+
return typeof source !== "string";
|
|
4477
|
+
}
|
|
4478
|
+
/**
|
|
4479
|
+
* Load a plugin from a module path
|
|
4480
|
+
*/
|
|
4481
|
+
async loadFromModule(modulePath) {
|
|
4482
|
+
const resolvedPath = isAbsolute(modulePath) ? modulePath : resolve(this.cwd, modulePath);
|
|
4483
|
+
const isFilePath = modulePath.startsWith("./") || modulePath.startsWith("../") || isAbsolute(modulePath);
|
|
4484
|
+
try {
|
|
4485
|
+
if (isFilePath) {
|
|
4486
|
+
return await this.loadFromFile(resolvedPath);
|
|
4487
|
+
}
|
|
4488
|
+
return await this.loadFromPackage(modulePath);
|
|
4489
|
+
} catch (error) {
|
|
4490
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4491
|
+
throw new ConfigurationError(`Failed to load lint plugin '${modulePath}': ${message}`);
|
|
4492
|
+
}
|
|
4493
|
+
}
|
|
4494
|
+
/**
|
|
4495
|
+
* Load a plugin from a file path using jiti (supports TypeScript)
|
|
4496
|
+
*/
|
|
4497
|
+
async loadFromFile(filePath) {
|
|
4498
|
+
this.jiti ??= createJiti(this.cwd, {
|
|
4499
|
+
interopDefault: true
|
|
4500
|
+
});
|
|
4501
|
+
const loaded = await this.jiti(filePath);
|
|
4502
|
+
const plugin = this.extractPlugin(loaded);
|
|
4503
|
+
if (!plugin) {
|
|
4504
|
+
throw new ConfigurationError(`Plugin file '${filePath}' does not export a valid LintPlugin`);
|
|
4505
|
+
}
|
|
4506
|
+
return plugin;
|
|
4507
|
+
}
|
|
4508
|
+
/**
|
|
4509
|
+
* Load a plugin from a package name
|
|
4510
|
+
*/
|
|
4511
|
+
async loadFromPackage(packageName) {
|
|
4512
|
+
const require2 = createRequire(this.cwd);
|
|
4513
|
+
let resolvedPath;
|
|
4514
|
+
try {
|
|
4515
|
+
resolvedPath = require2.resolve(packageName, { paths: [this.cwd] });
|
|
4516
|
+
} catch {
|
|
4517
|
+
try {
|
|
4518
|
+
resolvedPath = require2.resolve(packageName);
|
|
4519
|
+
} catch {
|
|
4520
|
+
throw new ConfigurationError(
|
|
4521
|
+
`Cannot find package '${packageName}'. Make sure it is installed.`
|
|
4522
|
+
);
|
|
4523
|
+
}
|
|
4524
|
+
}
|
|
4525
|
+
this.jiti ??= createJiti(this.cwd, {
|
|
4526
|
+
interopDefault: true
|
|
4527
|
+
});
|
|
4528
|
+
const loaded = await this.jiti(resolvedPath);
|
|
4529
|
+
const plugin = this.extractPlugin(loaded);
|
|
4530
|
+
if (!plugin) {
|
|
4531
|
+
throw new ConfigurationError(`Package '${packageName}' does not export a valid LintPlugin`);
|
|
4532
|
+
}
|
|
4533
|
+
return plugin;
|
|
4534
|
+
}
|
|
4535
|
+
/**
|
|
4536
|
+
* Extract plugin from loaded module
|
|
4537
|
+
*
|
|
4538
|
+
* Supports multiple export patterns:
|
|
4539
|
+
* - export default plugin
|
|
4540
|
+
* - export const plugin = {...}
|
|
4541
|
+
* - module.exports = plugin (CJS)
|
|
4542
|
+
*/
|
|
4543
|
+
extractPlugin(loaded) {
|
|
4544
|
+
if (!loaded || typeof loaded !== "object") {
|
|
4545
|
+
return null;
|
|
4546
|
+
}
|
|
4547
|
+
const module = loaded;
|
|
4548
|
+
if (module.default && this.isValidPluginStructure(module.default)) {
|
|
4549
|
+
return module.default;
|
|
4550
|
+
}
|
|
4551
|
+
if (module.plugin && this.isValidPluginStructure(module.plugin)) {
|
|
4552
|
+
return module.plugin;
|
|
4553
|
+
}
|
|
4554
|
+
if (this.isValidPluginStructure(loaded)) {
|
|
4555
|
+
return loaded;
|
|
4556
|
+
}
|
|
4557
|
+
return null;
|
|
4558
|
+
}
|
|
4559
|
+
/**
|
|
4560
|
+
* Check if object has required plugin structure
|
|
4561
|
+
*/
|
|
4562
|
+
isValidPluginStructure(obj) {
|
|
4563
|
+
if (!obj || typeof obj !== "object") {
|
|
4564
|
+
return false;
|
|
4565
|
+
}
|
|
4566
|
+
const plugin = obj;
|
|
4567
|
+
const rules = plugin.rules;
|
|
4568
|
+
if (plugin.meta === void 0 || typeof plugin.meta !== "object" || !plugin.meta.name || rules === void 0 || Object.keys(rules).length === 0) {
|
|
4569
|
+
return false;
|
|
4570
|
+
}
|
|
4571
|
+
return true;
|
|
4572
|
+
}
|
|
4573
|
+
/**
|
|
4574
|
+
* Validate a loaded plugin
|
|
4575
|
+
*/
|
|
4576
|
+
validatePlugin(plugin) {
|
|
4577
|
+
if (!plugin.meta) {
|
|
4578
|
+
throw new ConfigurationError("Lint plugin must have a meta property with name");
|
|
4579
|
+
}
|
|
4580
|
+
if (!plugin.meta.name) {
|
|
4581
|
+
throw new ConfigurationError("Lint plugin meta.name is required");
|
|
4582
|
+
}
|
|
4583
|
+
if (!plugin.rules || typeof plugin.rules !== "object" || Object.keys(plugin.rules).length === 0) {
|
|
4584
|
+
throw new ConfigurationError(
|
|
4585
|
+
`Lint plugin '${plugin.meta.name}' must have a non-empty rules object`
|
|
4586
|
+
);
|
|
4587
|
+
}
|
|
4588
|
+
for (const [ruleName, rule] of Object.entries(plugin.rules)) {
|
|
4589
|
+
if (!rule.meta) {
|
|
4590
|
+
throw new ConfigurationError(
|
|
4591
|
+
`Rule '${ruleName}' in plugin '${plugin.meta.name}' is missing meta property`
|
|
4592
|
+
);
|
|
4593
|
+
}
|
|
4594
|
+
if (!rule.meta.messages || typeof rule.meta.messages !== "object") {
|
|
4595
|
+
throw new ConfigurationError(
|
|
4596
|
+
`Rule '${ruleName}' in plugin '${plugin.meta.name}' is missing meta.messages`
|
|
4597
|
+
);
|
|
4598
|
+
}
|
|
4599
|
+
if (typeof rule.create !== "function") {
|
|
4600
|
+
throw new ConfigurationError(
|
|
4601
|
+
`Rule '${ruleName}' in plugin '${plugin.meta.name}' is missing create function`
|
|
4602
|
+
);
|
|
4603
|
+
}
|
|
4604
|
+
}
|
|
4605
|
+
}
|
|
4606
|
+
/**
|
|
4607
|
+
* Clear the plugin cache
|
|
4608
|
+
*/
|
|
4609
|
+
clearCache() {
|
|
4610
|
+
this.cache.clear();
|
|
4611
|
+
}
|
|
4612
|
+
};
|
|
4613
|
+
|
|
4614
|
+
// src/lint/lint-runner.ts
|
|
4615
|
+
var LintRunner = class {
|
|
4616
|
+
config;
|
|
4617
|
+
pluginLoader;
|
|
4618
|
+
resolvedConfig = null;
|
|
4619
|
+
warn;
|
|
4620
|
+
constructor(config) {
|
|
4621
|
+
this.config = config;
|
|
4622
|
+
this.pluginLoader = new PluginLoader();
|
|
4623
|
+
this.warn = config.onWarn ?? console.warn;
|
|
4624
|
+
}
|
|
4625
|
+
/**
|
|
4626
|
+
* Run all configured rules against the provided tokens
|
|
4627
|
+
*
|
|
4628
|
+
* Rules are executed in parallel for performance. Issues are collected
|
|
4629
|
+
* and returned with counts by severity.
|
|
4630
|
+
*
|
|
4631
|
+
* @param tokens - Resolved tokens to lint
|
|
4632
|
+
* @returns Lint result with issues and counts
|
|
4633
|
+
*/
|
|
4634
|
+
async run(tokens) {
|
|
4635
|
+
this.resolvedConfig ??= await this.resolveConfig();
|
|
4636
|
+
const { rules, plugins } = this.resolvedConfig;
|
|
4637
|
+
const issues = [];
|
|
4638
|
+
if (Object.keys(rules).length === 0) {
|
|
4639
|
+
return { issues: [], errorCount: 0, warningCount: 0 };
|
|
4640
|
+
}
|
|
4641
|
+
const rulePromises = Object.entries(rules).map(async ([ruleId, ruleConfig]) => {
|
|
4642
|
+
const { severity, options } = ruleConfig;
|
|
4643
|
+
const rule = this.resolveRule(ruleId, plugins);
|
|
4644
|
+
if (!rule) {
|
|
4645
|
+
this.warn(`[lint] Unknown rule '${ruleId}' - no plugin provides this rule`);
|
|
4646
|
+
return [];
|
|
4647
|
+
}
|
|
4648
|
+
const reports = [];
|
|
4649
|
+
const applicableTokens = this.filterTokensByAppliesTo(tokens, rule.meta.appliesTo);
|
|
4650
|
+
const mergedOptions = rule.defaultOptions ? { ...rule.defaultOptions, ...options } : options;
|
|
4651
|
+
const context = {
|
|
4652
|
+
id: ruleId,
|
|
4653
|
+
options: mergedOptions,
|
|
4654
|
+
tokens: applicableTokens,
|
|
4655
|
+
report: (descriptor) => {
|
|
4656
|
+
reports.push(descriptor);
|
|
4657
|
+
}
|
|
4658
|
+
};
|
|
4659
|
+
try {
|
|
4660
|
+
await rule.create(context);
|
|
4661
|
+
} catch (error) {
|
|
4662
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4663
|
+
return [
|
|
4664
|
+
{
|
|
4665
|
+
ruleId: "lint/rule-error",
|
|
4666
|
+
severity: "error",
|
|
4667
|
+
message: `Rule '${ruleId}' failed: ${message}`,
|
|
4668
|
+
tokenName: "(rule execution)",
|
|
4669
|
+
tokenPath: []
|
|
4670
|
+
}
|
|
4671
|
+
];
|
|
4672
|
+
}
|
|
4673
|
+
return reports.map((report) => {
|
|
4674
|
+
const messageTemplate = rule.meta.messages[report.messageId];
|
|
4675
|
+
const message = messageTemplate ? this.interpolateMessage(messageTemplate, report.data) : report.messageId;
|
|
4676
|
+
return {
|
|
4677
|
+
ruleId,
|
|
4678
|
+
severity,
|
|
4679
|
+
message,
|
|
4680
|
+
tokenName: report.token.name,
|
|
4681
|
+
tokenPath: report.token.path
|
|
4682
|
+
};
|
|
4683
|
+
});
|
|
4684
|
+
});
|
|
4685
|
+
const allIssues = await Promise.all(rulePromises);
|
|
4686
|
+
issues.push(...allIssues.flat());
|
|
4687
|
+
const errorCount = issues.filter((i) => i.severity === "error").length;
|
|
4688
|
+
const warningCount = issues.filter((i) => i.severity === "warn").length;
|
|
4689
|
+
return { issues, errorCount, warningCount };
|
|
4690
|
+
}
|
|
4691
|
+
/**
|
|
4692
|
+
* Resolve configuration: load plugins, parse rule configs
|
|
4693
|
+
*/
|
|
4694
|
+
async resolveConfig() {
|
|
4695
|
+
const { plugins: pluginSources = {}, rules: ruleConfigs = {} } = this.config;
|
|
4696
|
+
const plugins = await this.pluginLoader.loadAll(pluginSources);
|
|
4697
|
+
const rules = {};
|
|
4698
|
+
for (const [ruleId, config] of Object.entries(ruleConfigs)) {
|
|
4699
|
+
const resolved = this.resolveRuleConfig(config);
|
|
4700
|
+
if (resolved) {
|
|
4701
|
+
rules[ruleId] = resolved;
|
|
4702
|
+
}
|
|
4703
|
+
}
|
|
4704
|
+
return {
|
|
4705
|
+
enabled: true,
|
|
4706
|
+
failOnError: this.config.failOnError ?? true,
|
|
4707
|
+
plugins,
|
|
4708
|
+
rules
|
|
4709
|
+
};
|
|
4710
|
+
}
|
|
4711
|
+
filterTokensByAppliesTo(tokens, appliesTo) {
|
|
4712
|
+
if (!appliesTo || appliesTo === "all") {
|
|
4713
|
+
return tokens;
|
|
4714
|
+
}
|
|
4715
|
+
const filtered = {};
|
|
4716
|
+
for (const [name, token] of Object.entries(tokens)) {
|
|
4717
|
+
if (token.$type && appliesTo.includes(token.$type)) {
|
|
4718
|
+
filtered[name] = token;
|
|
4719
|
+
}
|
|
4720
|
+
}
|
|
4721
|
+
return filtered;
|
|
4722
|
+
}
|
|
4723
|
+
/**
|
|
4724
|
+
* Parse rule configuration into resolved format
|
|
4725
|
+
*/
|
|
4726
|
+
resolveRuleConfig(config) {
|
|
4727
|
+
if (typeof config === "string") {
|
|
4728
|
+
if (config === "off") {
|
|
4729
|
+
return null;
|
|
4730
|
+
}
|
|
4731
|
+
return { severity: config, options: {} };
|
|
4732
|
+
}
|
|
4733
|
+
const [severity, options = {}] = config;
|
|
4734
|
+
if (severity === "off") {
|
|
4735
|
+
return null;
|
|
4736
|
+
}
|
|
4737
|
+
return { severity, options };
|
|
4738
|
+
}
|
|
4739
|
+
/**
|
|
4740
|
+
* Resolve a rule from plugins by rule ID
|
|
4741
|
+
*
|
|
4742
|
+
* Rule IDs are formatted as 'namespace/rule-name'
|
|
4743
|
+
*/
|
|
4744
|
+
resolveRule(ruleId, plugins) {
|
|
4745
|
+
const separatorIndex = ruleId.indexOf("/");
|
|
4746
|
+
if (separatorIndex === -1) {
|
|
4747
|
+
return null;
|
|
4748
|
+
}
|
|
4749
|
+
const namespace = ruleId.slice(0, separatorIndex);
|
|
4750
|
+
const ruleName = ruleId.slice(separatorIndex + 1);
|
|
4751
|
+
const plugin = plugins[namespace];
|
|
4752
|
+
if (!plugin) {
|
|
4753
|
+
return null;
|
|
4754
|
+
}
|
|
4755
|
+
return plugin.rules[ruleName] ?? null;
|
|
4756
|
+
}
|
|
4757
|
+
/**
|
|
4758
|
+
* Interpolate message template with data
|
|
4759
|
+
*
|
|
4760
|
+
* Replaces {{key}} placeholders with values from data
|
|
4761
|
+
*/
|
|
4762
|
+
interpolateMessage(template, data) {
|
|
4763
|
+
if (!data) {
|
|
4764
|
+
return template;
|
|
4765
|
+
}
|
|
4766
|
+
return template.replace(/\{\{(\w+)\}\}/g, (_, key) => {
|
|
4767
|
+
const value = data[key];
|
|
4768
|
+
return value !== void 0 ? String(value) : `{{${key}}}`;
|
|
4769
|
+
});
|
|
4770
|
+
}
|
|
4771
|
+
/**
|
|
4772
|
+
* Clear the plugin cache
|
|
4773
|
+
*/
|
|
4774
|
+
clearCache() {
|
|
4775
|
+
this.pluginLoader.clearCache();
|
|
4776
|
+
this.resolvedConfig = null;
|
|
4777
|
+
}
|
|
4778
|
+
};
|
|
4271
4779
|
|
|
4272
4780
|
// src/shared/constants.ts
|
|
4273
4781
|
var DEFAULT_MAX_ALIAS_DEPTH = 10;
|
|
@@ -5462,6 +5970,10 @@ var ResolutionEngine = class {
|
|
|
5462
5970
|
return typeof obj === "object" && obj !== null && "contexts" in obj && typeof obj.contexts === "object";
|
|
5463
5971
|
}
|
|
5464
5972
|
};
|
|
5973
|
+
|
|
5974
|
+
// src/build/pipeline/token-pipeline.ts
|
|
5975
|
+
init_errors();
|
|
5976
|
+
init_validation_handler();
|
|
5465
5977
|
init_errors();
|
|
5466
5978
|
|
|
5467
5979
|
// src/shared/utils/path-utils.ts
|
|
@@ -5954,6 +6466,8 @@ var TokenPipeline = class {
|
|
|
5954
6466
|
resolverLoader;
|
|
5955
6467
|
tokenParser;
|
|
5956
6468
|
aliasResolver;
|
|
6469
|
+
lintRunner = null;
|
|
6470
|
+
lintConfigCache = null;
|
|
5957
6471
|
constructor(options = {}) {
|
|
5958
6472
|
this.options = options;
|
|
5959
6473
|
this.validationHandler = new ValidationHandler(options.validation);
|
|
@@ -5973,8 +6487,9 @@ var TokenPipeline = class {
|
|
|
5973
6487
|
* 6. Parse and flatten token structure
|
|
5974
6488
|
* 7. Resolve alias references
|
|
5975
6489
|
* 8. Strip $root from token names/paths (DTCG structural mechanism, transparent in output)
|
|
5976
|
-
* 9.
|
|
5977
|
-
* 10. Apply
|
|
6490
|
+
* 9. Run lint rules (if enabled)
|
|
6491
|
+
* 10. Apply filters (if provided) — runs first to remove tokens before transforms
|
|
6492
|
+
* 11. Apply transforms (if provided) — runs on the already-filtered token set
|
|
5978
6493
|
*
|
|
5979
6494
|
* Each stage is explicitly typed to ensure correct order and prevent temporal coupling.
|
|
5980
6495
|
*
|
|
@@ -5983,9 +6498,11 @@ var TokenPipeline = class {
|
|
|
5983
6498
|
* @param transformList - Optional transforms to apply
|
|
5984
6499
|
* @param preprocessorList - Optional preprocessors to apply
|
|
5985
6500
|
* @param filterList - Optional filters to apply before transforms
|
|
5986
|
-
* @
|
|
6501
|
+
* @param lintConfig - Optional lint configuration for this run
|
|
6502
|
+
* @returns Final tokens, resolution engine, and lint result
|
|
5987
6503
|
*/
|
|
5988
|
-
async resolve(resolver, modifierInputs, transformList, preprocessorList, filterList) {
|
|
6504
|
+
async resolve(resolver, modifierInputs, transformList, preprocessorList, filterList, lintConfig) {
|
|
6505
|
+
const effectiveLintConfig = lintConfig ?? this.options.lint;
|
|
5989
6506
|
const stage1 = await this.loadResolver(resolver);
|
|
5990
6507
|
const engine = this.createEngine(stage1);
|
|
5991
6508
|
const result = await this.runPipelineStages(
|
|
@@ -5993,29 +6510,32 @@ var TokenPipeline = class {
|
|
|
5993
6510
|
modifierInputs,
|
|
5994
6511
|
preprocessorList,
|
|
5995
6512
|
filterList,
|
|
5996
|
-
transformList
|
|
6513
|
+
transformList,
|
|
6514
|
+
effectiveLintConfig
|
|
5997
6515
|
);
|
|
5998
6516
|
return {
|
|
5999
6517
|
tokens: result.tokens,
|
|
6000
6518
|
resolutionEngine: result.resolutionEngine,
|
|
6001
|
-
modifierInputs: result.modifierInputs
|
|
6519
|
+
modifierInputs: result.modifierInputs,
|
|
6520
|
+
lintResult: result.lintResult
|
|
6002
6521
|
};
|
|
6003
6522
|
}
|
|
6004
6523
|
/**
|
|
6005
|
-
* Run pipeline stages 3-
|
|
6524
|
+
* Run pipeline stages 3-11 on a pre-created engine
|
|
6006
6525
|
*
|
|
6007
6526
|
* Shared by both `resolve()` (single permutation) and
|
|
6008
6527
|
* `resolveAllPermutations()` (parallel permutations) to keep the
|
|
6009
6528
|
* stage sequence defined in exactly one place.
|
|
6010
6529
|
*/
|
|
6011
|
-
async runPipelineStages(engine, modifierInputs, preprocessorList, filterList, transformList) {
|
|
6530
|
+
async runPipelineStages(engine, modifierInputs, preprocessorList, filterList, transformList, lintConfig) {
|
|
6012
6531
|
const rawTokens = await this.resolveTokens(engine, modifierInputs);
|
|
6013
6532
|
const preprocessed = await this.preprocessTokens(rawTokens, preprocessorList);
|
|
6014
6533
|
const refResolved = await this.resolveReferences(preprocessed);
|
|
6015
6534
|
const flattened = this.flattenTokens(refResolved);
|
|
6016
6535
|
const aliasResolved = this.resolveAliases(flattened);
|
|
6017
6536
|
const rootStripped = this.stripRootTokenNames(aliasResolved);
|
|
6018
|
-
const
|
|
6537
|
+
const linted = await this.runLintStage(rootStripped, lintConfig);
|
|
6538
|
+
const filtered = this.applyFilterStage(linted, filterList);
|
|
6019
6539
|
return this.applyTransformStage(filtered, transformList);
|
|
6020
6540
|
}
|
|
6021
6541
|
/**
|
|
@@ -6128,6 +6648,47 @@ var TokenPipeline = class {
|
|
|
6128
6648
|
}
|
|
6129
6649
|
return { ...stage, aliasResolvedTokens: result };
|
|
6130
6650
|
}
|
|
6651
|
+
/**
|
|
6652
|
+
* Stage 9: Run lint rules against tokens
|
|
6653
|
+
*
|
|
6654
|
+
* Linting runs after alias resolution and $root stripping but before
|
|
6655
|
+
* filters and transforms. This ensures rules see the full token set
|
|
6656
|
+
* with resolved values.
|
|
6657
|
+
*/
|
|
6658
|
+
async runLintStage(stage, lintConfig) {
|
|
6659
|
+
if (!lintConfig?.enabled) {
|
|
6660
|
+
return stage;
|
|
6661
|
+
}
|
|
6662
|
+
if (!this.lintRunner || !this.isLintConfigEqual(this.lintConfigCache, lintConfig)) {
|
|
6663
|
+
this.lintRunner = new LintRunner({
|
|
6664
|
+
plugins: lintConfig.plugins,
|
|
6665
|
+
rules: lintConfig.rules,
|
|
6666
|
+
onWarn: (msg) => this.validationHandler.warn(msg)
|
|
6667
|
+
});
|
|
6668
|
+
this.lintConfigCache = lintConfig;
|
|
6669
|
+
}
|
|
6670
|
+
const lintResult = await this.lintRunner.run(stage.aliasResolvedTokens);
|
|
6671
|
+
if (lintResult.errorCount > 0 && lintConfig.failOnError !== false) {
|
|
6672
|
+
throw new LintError(lintResult.issues);
|
|
6673
|
+
}
|
|
6674
|
+
for (const issue of lintResult.issues.filter((i) => i.severity === "warn")) {
|
|
6675
|
+
this.validationHandler.warn(
|
|
6676
|
+
`[${issue.ruleId}] ${issue.message} (token: ${issue.tokenName})`
|
|
6677
|
+
);
|
|
6678
|
+
}
|
|
6679
|
+
return { ...stage, lintResult };
|
|
6680
|
+
}
|
|
6681
|
+
isLintConfigEqual(a, b) {
|
|
6682
|
+
if (!a || !b) return false;
|
|
6683
|
+
if (a.enabled !== b.enabled) return false;
|
|
6684
|
+
if (a.failOnError !== b.failOnError) return false;
|
|
6685
|
+
if (a.plugins !== b.plugins) return false;
|
|
6686
|
+
if (a.rules !== b.rules) return false;
|
|
6687
|
+
return true;
|
|
6688
|
+
}
|
|
6689
|
+
/**
|
|
6690
|
+
* Stage 10: Apply filters to the linted token set
|
|
6691
|
+
*/
|
|
6131
6692
|
applyFilterStage(stage, filterList) {
|
|
6132
6693
|
let tokens = stage.aliasResolvedTokens;
|
|
6133
6694
|
if (filterList !== void 0 && filterList.length > 0) {
|
|
@@ -6136,7 +6697,7 @@ var TokenPipeline = class {
|
|
|
6136
6697
|
return { ...stage, aliasResolvedTokens: tokens };
|
|
6137
6698
|
}
|
|
6138
6699
|
/**
|
|
6139
|
-
* Stage
|
|
6700
|
+
* Stage 11: Apply transforms to the filtered token set
|
|
6140
6701
|
*/
|
|
6141
6702
|
applyTransformStage(stage, transformList) {
|
|
6142
6703
|
let tokens = stage.aliasResolvedTokens;
|
|
@@ -6170,8 +6731,10 @@ var TokenPipeline = class {
|
|
|
6170
6731
|
* @param transformList - Optional transforms to apply
|
|
6171
6732
|
* @param preprocessorList - Optional preprocessors to apply
|
|
6172
6733
|
* @param filterList - Optional filters to apply before transforms
|
|
6734
|
+
* @param lintConfig - Optional lint configuration for this run
|
|
6173
6735
|
*/
|
|
6174
|
-
async resolveAllPermutations(resolver, transformList, preprocessorList, filterList) {
|
|
6736
|
+
async resolveAllPermutations(resolver, transformList, preprocessorList, filterList, lintConfig) {
|
|
6737
|
+
const effectiveLintConfig = lintConfig ?? this.options.lint;
|
|
6175
6738
|
const stage1 = await this.loadResolver(resolver);
|
|
6176
6739
|
const discoveryEngine = this.createEngine(stage1);
|
|
6177
6740
|
const permutationInputs = discoveryEngine.resolutionEngine.generatePermutations();
|
|
@@ -6184,11 +6747,13 @@ var TokenPipeline = class {
|
|
|
6184
6747
|
modifierInputs,
|
|
6185
6748
|
preprocessorList,
|
|
6186
6749
|
filterList,
|
|
6187
|
-
transformList
|
|
6750
|
+
transformList,
|
|
6751
|
+
effectiveLintConfig
|
|
6188
6752
|
);
|
|
6189
6753
|
return {
|
|
6190
6754
|
tokens: result.tokens,
|
|
6191
|
-
modifierInputs: result.modifierInputs
|
|
6755
|
+
modifierInputs: result.modifierInputs,
|
|
6756
|
+
lintResult: result.lintResult
|
|
6192
6757
|
};
|
|
6193
6758
|
})
|
|
6194
6759
|
);
|
|
@@ -6209,286 +6774,106 @@ var TokenPipeline = class {
|
|
|
6209
6774
|
init_errors();
|
|
6210
6775
|
init_token_utils();
|
|
6211
6776
|
init_validator();
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
const errors = this.validator.validateDispersaOptions(options);
|
|
6230
|
-
if (errors.length > 0) {
|
|
6231
|
-
throw new ConfigurationError(
|
|
6232
|
-
`Invalid Dispersa options: ${this.validator.getErrorMessage(errors)}`
|
|
6233
|
-
);
|
|
6234
|
-
}
|
|
6235
|
-
this.pipeline = new TokenPipeline({ validation: options.validation });
|
|
6236
|
-
this.outputProcessor = new OutputProcessor();
|
|
6237
|
-
this.orchestrator = new BuildOrchestrator(this.pipeline, this.outputProcessor);
|
|
6238
|
-
}
|
|
6239
|
-
/**
|
|
6240
|
-
* Builds design tokens from a resolver configuration
|
|
6241
|
-
*
|
|
6242
|
-
* Processes tokens through the resolution pipeline, applies preprocessors,
|
|
6243
|
-
* transforms, and filters, then generates output files in multiple formats
|
|
6244
|
-
* for specified outputs.
|
|
6245
|
-
*
|
|
6246
|
-
* **Runtime Validation:**
|
|
6247
|
-
* This method validates the build configuration
|
|
6248
|
-
* and all output configurations before processing, throwing helpful errors for
|
|
6249
|
-
* invalid inputs.
|
|
6250
|
-
*
|
|
6251
|
-
* **Permutation Handling:**
|
|
6252
|
-
* - If `config.permutations` is provided and non-empty, builds those specific permutations
|
|
6253
|
-
* - If `config.permutations` is undefined or empty, auto-discovers all permutations from resolver
|
|
6254
|
-
*
|
|
6255
|
-
* @param config - Build configuration
|
|
6256
|
-
* @param config.resolver - Resolver configuration (file path or inline object, optional if set in constructor)
|
|
6257
|
-
* @param config.outputs - Array of output configurations (renderers, transforms, filters)
|
|
6258
|
-
* @param config.buildPath - Output directory for generated files (omit for in-memory mode, optional if set in constructor)
|
|
6259
|
-
* @param config.transforms - Global transforms to apply to all tokens
|
|
6260
|
-
* @param config.preprocessors - Global preprocessors to apply before parsing
|
|
6261
|
-
* @param config.permutations - Array of modifier inputs for generating variations
|
|
6262
|
-
* @returns Build result with success status and generated output files
|
|
6263
|
-
* @throws {ConfigurationError} If configuration is invalid
|
|
6264
|
-
* @throws {FileOperationError} If file operations fail
|
|
6265
|
-
*
|
|
6266
|
-
* @example Basic build
|
|
6267
|
-
* ```typescript
|
|
6268
|
-
* const dispersa = new Dispersa({
|
|
6269
|
-
* resolver: './tokens.resolver.json',
|
|
6270
|
-
* buildPath: './output'
|
|
6271
|
-
* })
|
|
6272
|
-
*
|
|
6273
|
-
* const result = await dispersa.build({
|
|
6274
|
-
* outputs: [
|
|
6275
|
-
* css({
|
|
6276
|
-
* name: 'css',
|
|
6277
|
-
* file: 'tokens.css',
|
|
6278
|
-
* preset: 'bundle',
|
|
6279
|
-
* selector: ':root',
|
|
6280
|
-
* transforms: [nameKebabCase()]
|
|
6281
|
-
* })
|
|
6282
|
-
* ]
|
|
6283
|
-
* })
|
|
6284
|
-
* ```
|
|
6285
|
-
*
|
|
6286
|
-
* @example With filters and multiple presets
|
|
6287
|
-
* ```typescript
|
|
6288
|
-
* const result = await dispersa.build({
|
|
6289
|
-
* resolver: './tokens.resolver.json',
|
|
6290
|
-
* outputs: [
|
|
6291
|
-
* css({
|
|
6292
|
-
* name: 'css',
|
|
6293
|
-
* file: 'tokens.css',
|
|
6294
|
-
* preset: 'bundle',
|
|
6295
|
-
* selector: ':root', // All themes in one file
|
|
6296
|
-
* transforms: [nameKebabCase()]
|
|
6297
|
-
* }),
|
|
6298
|
-
* json({
|
|
6299
|
-
* name: 'json',
|
|
6300
|
-
* file: 'tokens-{theme}.json', // Separate file per theme
|
|
6301
|
-
* preset: 'standalone',
|
|
6302
|
-
* structure: 'flat'
|
|
6303
|
-
* })
|
|
6304
|
-
* ],
|
|
6305
|
-
* buildPath: './output',
|
|
6306
|
-
* permutations: [
|
|
6307
|
-
* { theme: 'light' },
|
|
6308
|
-
* { theme: 'dark' }
|
|
6309
|
-
* ]
|
|
6310
|
-
* })
|
|
6311
|
-
* ```
|
|
6312
|
-
*/
|
|
6313
|
-
async build(config) {
|
|
6314
|
-
try {
|
|
6315
|
-
return await this.buildOrThrow(config);
|
|
6316
|
-
} catch (error) {
|
|
6317
|
-
return {
|
|
6318
|
-
success: false,
|
|
6319
|
-
outputs: [],
|
|
6320
|
-
errors: [toBuildError(error)]
|
|
6321
|
-
};
|
|
6322
|
-
}
|
|
6323
|
-
}
|
|
6324
|
-
/**
|
|
6325
|
-
* Builds design tokens and throws on any failure.
|
|
6326
|
-
*
|
|
6327
|
-
* Unlike {@link build}, which catches errors and returns them inside
|
|
6328
|
-
* `BuildResult.errors`, this method propagates the first error as an
|
|
6329
|
-
* exception. Use it when you want fail-fast behavior in CLI or CI workflows.
|
|
6330
|
-
*
|
|
6331
|
-
* @param config - Build configuration specifying resolver, outputs, transforms, etc.
|
|
6332
|
-
* @returns A successful `BuildResult` (never contains errors)
|
|
6333
|
-
* @throws {ConfigurationError} When the build config or resolver is invalid
|
|
6334
|
-
* @throws {DispersaError} When token resolution, transforms, or rendering fails
|
|
6335
|
-
*
|
|
6336
|
-
* @example
|
|
6337
|
-
* ```typescript
|
|
6338
|
-
* try {
|
|
6339
|
-
* const result = await dispersa.buildOrThrow({
|
|
6340
|
-
* resolver: './tokens.resolver.json',
|
|
6341
|
-
* outputs: [css({ name: 'css', file: 'tokens.css' })],
|
|
6342
|
-
* buildPath: './output',
|
|
6343
|
-
* })
|
|
6344
|
-
* } catch (error) {
|
|
6345
|
-
* process.exit(1)
|
|
6346
|
-
* }
|
|
6347
|
-
* ```
|
|
6348
|
-
*/
|
|
6349
|
-
async buildOrThrow(config) {
|
|
6350
|
-
const configErrors = this.validator.validateBuildConfig(config);
|
|
6351
|
-
if (configErrors.length > 0) {
|
|
6352
|
-
throw new ConfigurationError(
|
|
6353
|
-
`Invalid build configuration: ${this.validator.getErrorMessage(configErrors)}`
|
|
6354
|
-
);
|
|
6355
|
-
}
|
|
6356
|
-
for (const output of config.outputs) {
|
|
6357
|
-
const outputErrors = this.validator.validateOutputConfig(output);
|
|
6358
|
-
if (outputErrors.length > 0) {
|
|
6359
|
-
throw new ConfigurationError(
|
|
6360
|
-
`Invalid output '${output.name}': ${this.validator.getErrorMessage(outputErrors)}`
|
|
6361
|
-
);
|
|
6362
|
-
}
|
|
6363
|
-
}
|
|
6364
|
-
const { resolver, buildPath } = this.resolveConfig(config);
|
|
6365
|
-
return this.orchestrator.build(resolver, buildPath, config);
|
|
6777
|
+
function createValidator() {
|
|
6778
|
+
return new SchemaValidator();
|
|
6779
|
+
}
|
|
6780
|
+
function createPipeline(options) {
|
|
6781
|
+
return new TokenPipeline({ validation: options?.validation });
|
|
6782
|
+
}
|
|
6783
|
+
function createOutputProcessor() {
|
|
6784
|
+
return new OutputProcessor();
|
|
6785
|
+
}
|
|
6786
|
+
function createOrchestrator(pipeline, outputProcessor) {
|
|
6787
|
+
return new BuildOrchestrator(pipeline, outputProcessor);
|
|
6788
|
+
}
|
|
6789
|
+
function resolveConfig(config, options) {
|
|
6790
|
+
const resolver = config.resolver ?? options?.resolver;
|
|
6791
|
+
const buildPath = config.buildPath ?? options?.buildPath ?? "";
|
|
6792
|
+
if (!resolver) {
|
|
6793
|
+
throw new ConfigurationError("resolver is required in build config");
|
|
6366
6794
|
}
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
* @param config - Build configuration
|
|
6376
|
-
* @param modifierInputs - Modifier values (e.g., `{ theme: 'dark' }`)
|
|
6377
|
-
* @returns Build result (success, outputs, optional errors)
|
|
6378
|
-
*/
|
|
6379
|
-
async buildPermutation(config, modifierInputs = {}) {
|
|
6380
|
-
return await this.build({
|
|
6381
|
-
...config,
|
|
6382
|
-
permutations: [modifierInputs]
|
|
6383
|
-
});
|
|
6795
|
+
return { resolver, buildPath };
|
|
6796
|
+
}
|
|
6797
|
+
function validateBuildConfig(validator, config) {
|
|
6798
|
+
const configErrors = validator.validateBuildConfig(config);
|
|
6799
|
+
if (configErrors.length > 0) {
|
|
6800
|
+
throw new ConfigurationError(
|
|
6801
|
+
`Invalid build configuration: ${validator.getErrorMessage(configErrors)}`
|
|
6802
|
+
);
|
|
6384
6803
|
}
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
resolveConfig(config) {
|
|
6389
|
-
const resolver = config.resolver ?? this.options.resolver;
|
|
6390
|
-
const buildPath = config.buildPath ?? this.options.buildPath ?? "";
|
|
6391
|
-
if (!resolver) {
|
|
6804
|
+
for (const output of config.outputs) {
|
|
6805
|
+
const outputErrors = validator.validateOutputConfig(output);
|
|
6806
|
+
if (outputErrors.length > 0) {
|
|
6392
6807
|
throw new ConfigurationError(
|
|
6393
|
-
|
|
6808
|
+
`Invalid output '${output.name}': ${validator.getErrorMessage(outputErrors)}`
|
|
6394
6809
|
);
|
|
6395
6810
|
}
|
|
6396
|
-
return { resolver, buildPath };
|
|
6397
6811
|
}
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
|
|
6412
|
-
* ```typescript
|
|
6413
|
-
* const tokens = await dispersa.resolveTokens(
|
|
6414
|
-
* './tokens.resolver.json',
|
|
6415
|
-
* { theme: 'dark' }
|
|
6416
|
-
* )
|
|
6417
|
-
*
|
|
6418
|
-
* console.log(tokens['color.background'].$value) // '#1a1a1a'
|
|
6419
|
-
* ```
|
|
6420
|
-
*/
|
|
6421
|
-
async resolveTokens(resolver, modifierInputs = {}) {
|
|
6422
|
-
const { tokens } = await this.pipeline.resolve(resolver, modifierInputs);
|
|
6423
|
-
return stripInternalTokenMetadata(tokens);
|
|
6424
|
-
}
|
|
6425
|
-
/**
|
|
6426
|
-
* Resolves tokens for all permutations defined in the resolver
|
|
6427
|
-
*
|
|
6428
|
-
* Auto-discovers all possible permutations from the resolver's modifier
|
|
6429
|
-
* definitions and resolves tokens for each one. Useful for generating
|
|
6430
|
-
* comprehensive token sets or validating all theme variations.
|
|
6431
|
-
*
|
|
6432
|
-
* @param resolver - Resolver configuration (file path or inline object)
|
|
6433
|
-
* @returns Array of resolved token sets with their modifier inputs
|
|
6434
|
-
* @throws {FileOperationError} If resolver file cannot be read
|
|
6435
|
-
* @throws {TokenReferenceError} If token references cannot be resolved (when validate is enabled)
|
|
6436
|
-
*
|
|
6437
|
-
* @example
|
|
6438
|
-
* ```typescript
|
|
6439
|
-
* const permutations = await dispersa.resolveAllPermutations(
|
|
6440
|
-
* './tokens.resolver.json'
|
|
6441
|
-
* )
|
|
6442
|
-
*
|
|
6443
|
-
* permutations.forEach(({ tokens, modifierInputs }) => {
|
|
6444
|
-
* console.log(`Theme: ${modifierInputs.theme}`)
|
|
6445
|
-
* console.log(`Tokens: ${Object.keys(tokens).length}`)
|
|
6446
|
-
* })
|
|
6447
|
-
* ```
|
|
6448
|
-
*/
|
|
6449
|
-
async resolveAllPermutations(resolver) {
|
|
6450
|
-
const permutations = await this.pipeline.resolveAllPermutations(resolver);
|
|
6451
|
-
return permutations.map(({ tokens, modifierInputs }) => ({
|
|
6452
|
-
tokens: stripInternalTokenMetadata(tokens),
|
|
6453
|
-
modifierInputs
|
|
6454
|
-
}));
|
|
6812
|
+
}
|
|
6813
|
+
async function resolvePipeline(pipeline, resolver, modifierInputs) {
|
|
6814
|
+
const { tokens } = await pipeline.resolve(resolver, modifierInputs);
|
|
6815
|
+
return stripInternalTokenMetadata(tokens);
|
|
6816
|
+
}
|
|
6817
|
+
async function build(config) {
|
|
6818
|
+
try {
|
|
6819
|
+
return await buildOrThrow(config);
|
|
6820
|
+
} catch (error) {
|
|
6821
|
+
return {
|
|
6822
|
+
success: false,
|
|
6823
|
+
outputs: [],
|
|
6824
|
+
errors: [toBuildError(error)]
|
|
6825
|
+
};
|
|
6455
6826
|
}
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
moduleName: options?.moduleName ?? "Tokens",
|
|
6488
|
-
includeValues: true
|
|
6489
|
-
});
|
|
6827
|
+
}
|
|
6828
|
+
async function buildOrThrow(config) {
|
|
6829
|
+
const validator = createValidator();
|
|
6830
|
+
validateBuildConfig(validator, config);
|
|
6831
|
+
const { resolver, buildPath } = resolveConfig(config);
|
|
6832
|
+
const pipeline = createPipeline({ validation: config.validation });
|
|
6833
|
+
const outputProcessor = createOutputProcessor();
|
|
6834
|
+
const orchestrator = createOrchestrator(pipeline, outputProcessor);
|
|
6835
|
+
return orchestrator.build(resolver, buildPath, config);
|
|
6836
|
+
}
|
|
6837
|
+
async function buildPermutation(config, modifierInputs = {}) {
|
|
6838
|
+
return build({
|
|
6839
|
+
...config,
|
|
6840
|
+
permutations: [modifierInputs]
|
|
6841
|
+
});
|
|
6842
|
+
}
|
|
6843
|
+
async function resolveTokens(resolver, modifierInputs = {}, validation) {
|
|
6844
|
+
const pipeline = createPipeline({ validation });
|
|
6845
|
+
return resolvePipeline(pipeline, resolver, modifierInputs);
|
|
6846
|
+
}
|
|
6847
|
+
async function lint(options) {
|
|
6848
|
+
const { resolver, modifierInputs = {}, validation, ...lintConfig } = options;
|
|
6849
|
+
const pipeline = createPipeline({ validation });
|
|
6850
|
+
const tokens = await resolvePipeline(pipeline, resolver, modifierInputs);
|
|
6851
|
+
const runner = new LintRunner({
|
|
6852
|
+
...lintConfig,
|
|
6853
|
+
failOnError: lintConfig.failOnError ?? true
|
|
6854
|
+
});
|
|
6855
|
+
const result = await runner.run(tokens);
|
|
6856
|
+
if (result.errorCount > 0 && lintConfig.failOnError !== false) {
|
|
6857
|
+
throw new LintError(result.issues);
|
|
6490
6858
|
}
|
|
6491
|
-
|
|
6859
|
+
return result;
|
|
6860
|
+
}
|
|
6861
|
+
async function resolveAllPermutations(resolver) {
|
|
6862
|
+
const pipeline = createPipeline();
|
|
6863
|
+
const permutations = await pipeline.resolveAllPermutations(resolver);
|
|
6864
|
+
return permutations.map(({ tokens, modifierInputs }) => ({
|
|
6865
|
+
tokens: stripInternalTokenMetadata(tokens),
|
|
6866
|
+
modifierInputs
|
|
6867
|
+
}));
|
|
6868
|
+
}
|
|
6869
|
+
async function generateTypes(tokens, fileName, options) {
|
|
6870
|
+
const typeWriter = new TypeWriter();
|
|
6871
|
+
await typeWriter.write(tokens, {
|
|
6872
|
+
fileName,
|
|
6873
|
+
moduleName: options?.moduleName ?? "Tokens",
|
|
6874
|
+
includeValues: true
|
|
6875
|
+
});
|
|
6876
|
+
}
|
|
6492
6877
|
|
|
6493
6878
|
// src/tokens/types.ts
|
|
6494
6879
|
function isColorToken(token) {
|
|
@@ -6603,6 +6988,7 @@ function durationObjectToString(duration) {
|
|
|
6603
6988
|
init_errors();
|
|
6604
6989
|
init_token_utils();
|
|
6605
6990
|
init_utils();
|
|
6991
|
+
init_metadata();
|
|
6606
6992
|
var toSRGB = converter("rgb");
|
|
6607
6993
|
var toP3 = converter("p3");
|
|
6608
6994
|
var KOTLIN_KEYWORDS = /* @__PURE__ */ new Set([
|
|
@@ -6653,9 +7039,6 @@ function resolveColorFormat(format) {
|
|
|
6653
7039
|
function escapeKotlinString(str) {
|
|
6654
7040
|
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\$/g, "\\$");
|
|
6655
7041
|
}
|
|
6656
|
-
function escapeKDoc(str) {
|
|
6657
|
-
return str.replace(/\*\//g, "* /").replace(/\r?\n/g, " ").trim();
|
|
6658
|
-
}
|
|
6659
7042
|
function formatKotlinNumber(value) {
|
|
6660
7043
|
return Number.isInteger(value) ? `${value}.0` : String(value);
|
|
6661
7044
|
}
|
|
@@ -6787,8 +7170,13 @@ var AndroidRenderer = class {
|
|
|
6787
7170
|
const kotlinName = this.buildFlatKotlinName(token);
|
|
6788
7171
|
const kotlinValue = this.formatKotlinValue(token, options, baseDepth + 1);
|
|
6789
7172
|
const annotation = this.typeAnnotationSuffix(token);
|
|
6790
|
-
|
|
6791
|
-
|
|
7173
|
+
const descriptionComment = buildTokenDescriptionComment(token, "kotlin");
|
|
7174
|
+
if (descriptionComment) {
|
|
7175
|
+
lines.push(`${valIndent}${descriptionComment}`);
|
|
7176
|
+
}
|
|
7177
|
+
const deprecation = buildKotlinDeprecationAnnotation(token);
|
|
7178
|
+
if (deprecation) {
|
|
7179
|
+
lines.push(`${valIndent}${deprecation}`);
|
|
6792
7180
|
}
|
|
6793
7181
|
lines.push(
|
|
6794
7182
|
`${valIndent}${options.visPrefix}val ${kotlinName}${annotation} = ${kotlinValue}`
|
|
@@ -6824,8 +7212,13 @@ var AndroidRenderer = class {
|
|
|
6824
7212
|
const kotlinName = toSafeIdentifier(key, KOTLIN_KEYWORDS, false);
|
|
6825
7213
|
const kotlinValue = this.formatKotlinValue(token, options, depth);
|
|
6826
7214
|
const annotation = this.typeAnnotationSuffix(token);
|
|
6827
|
-
|
|
6828
|
-
|
|
7215
|
+
const descriptionComment = buildTokenDescriptionComment(token, "kotlin");
|
|
7216
|
+
if (descriptionComment) {
|
|
7217
|
+
lines.push(`${pad}${descriptionComment}`);
|
|
7218
|
+
}
|
|
7219
|
+
const deprecation = buildKotlinDeprecationAnnotation(token);
|
|
7220
|
+
if (deprecation) {
|
|
7221
|
+
lines.push(`${pad}${deprecation}`);
|
|
6829
7222
|
}
|
|
6830
7223
|
lines.push(`${pad}${options.visPrefix}val ${kotlinName}${annotation} = ${kotlinValue}`);
|
|
6831
7224
|
}
|
|
@@ -7602,10 +7995,8 @@ function stableInputsKey(modifierInputs) {
|
|
|
7602
7995
|
|
|
7603
7996
|
// src/renderers/css.ts
|
|
7604
7997
|
init_utils();
|
|
7998
|
+
init_metadata();
|
|
7605
7999
|
var CssRenderer = class _CssRenderer {
|
|
7606
|
-
sanitizeCssCommentText(text) {
|
|
7607
|
-
return text.replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ").trim();
|
|
7608
|
-
}
|
|
7609
8000
|
async format(context, options) {
|
|
7610
8001
|
const opts = {
|
|
7611
8002
|
preset: options?.preset ?? "bundle",
|
|
@@ -7685,12 +8076,13 @@ var CssRenderer = class _CssRenderer {
|
|
|
7685
8076
|
}
|
|
7686
8077
|
pushTokenLines(lines, token, tokens, referenceTokens, preserveReferences, indent, newline, space) {
|
|
7687
8078
|
const entries = this.buildCssEntries(token, tokens, referenceTokens, preserveReferences);
|
|
7688
|
-
|
|
7689
|
-
|
|
7690
|
-
lines.push(`${indent}
|
|
8079
|
+
const deprecationComment = buildTokenDeprecationComment(token, "css");
|
|
8080
|
+
if (deprecationComment) {
|
|
8081
|
+
lines.push(`${indent}${deprecationComment}${newline}`);
|
|
7691
8082
|
}
|
|
7692
|
-
|
|
7693
|
-
|
|
8083
|
+
const descriptionComment = buildTokenDescriptionComment(token, "css");
|
|
8084
|
+
if (descriptionComment) {
|
|
8085
|
+
lines.push(`${indent}${descriptionComment}${newline}`);
|
|
7694
8086
|
}
|
|
7695
8087
|
for (const entry of entries) {
|
|
7696
8088
|
lines.push(`${indent}--${entry.name}:${space}${entry.value};${newline}`);
|
|
@@ -8330,6 +8722,7 @@ function cssRenderer() {
|
|
|
8330
8722
|
|
|
8331
8723
|
// src/renderers/ios.ts
|
|
8332
8724
|
init_utils();
|
|
8725
|
+
init_metadata();
|
|
8333
8726
|
var toSRGB2 = converter("rgb");
|
|
8334
8727
|
var toP32 = converter("p3");
|
|
8335
8728
|
var SWIFT_TYPE_GROUP_MAP = {
|
|
@@ -8473,9 +8866,13 @@ var IosRenderer = class {
|
|
|
8473
8866
|
const swiftValue = this.formatSwiftValue(token, options);
|
|
8474
8867
|
const typeAnnotation = this.getTypeAnnotation(token);
|
|
8475
8868
|
const annotation = typeAnnotation ? `: ${typeAnnotation}` : "";
|
|
8476
|
-
const docComment =
|
|
8869
|
+
const docComment = buildTokenDescriptionComment(token, "swift");
|
|
8477
8870
|
if (docComment) {
|
|
8478
|
-
lines.push(docComment);
|
|
8871
|
+
lines.push(`${indent}${docComment}`);
|
|
8872
|
+
}
|
|
8873
|
+
const deprecationAttr = buildSwiftDeprecationAttribute(token);
|
|
8874
|
+
if (deprecationAttr) {
|
|
8875
|
+
lines.push(`${indent}${deprecationAttr}`);
|
|
8479
8876
|
}
|
|
8480
8877
|
lines.push(`${indent}${access3} ${staticPrefix}${swiftName}${annotation} = ${swiftValue}`);
|
|
8481
8878
|
}
|
|
@@ -8490,15 +8887,6 @@ var IosRenderer = class {
|
|
|
8490
8887
|
}
|
|
8491
8888
|
return Array.from(imports).sort();
|
|
8492
8889
|
}
|
|
8493
|
-
/**
|
|
8494
|
-
* Builds a `///` doc comment from a token's `$description`, if present.
|
|
8495
|
-
*/
|
|
8496
|
-
buildDocComment(token, indent) {
|
|
8497
|
-
if (!token.$description) {
|
|
8498
|
-
return void 0;
|
|
8499
|
-
}
|
|
8500
|
-
return `${indent}/// ${token.$description}`;
|
|
8501
|
-
}
|
|
8502
8890
|
/**
|
|
8503
8891
|
* Builds a qualified Swift name from a token's path, preserving parent
|
|
8504
8892
|
* hierarchy segments to avoid duplicate identifiers.
|
|
@@ -8889,6 +9277,7 @@ function iosRenderer() {
|
|
|
8889
9277
|
// src/renderers/js-module.ts
|
|
8890
9278
|
init_utils();
|
|
8891
9279
|
init_token_utils();
|
|
9280
|
+
init_metadata();
|
|
8892
9281
|
var JsModuleRenderer = class {
|
|
8893
9282
|
async format(context, options) {
|
|
8894
9283
|
const opts = {
|
|
@@ -8926,17 +9315,10 @@ var JsModuleRenderer = class {
|
|
|
8926
9315
|
return outputTree(files);
|
|
8927
9316
|
}
|
|
8928
9317
|
async formatTokens(tokens, options) {
|
|
8929
|
-
const opts = {
|
|
8930
|
-
preset: options.preset ?? "standalone",
|
|
8931
|
-
structure: options.structure ?? "nested",
|
|
8932
|
-
minify: options.minify ?? false,
|
|
8933
|
-
moduleName: options.moduleName ?? "tokens",
|
|
8934
|
-
generateHelper: options.generateHelper ?? false
|
|
8935
|
-
};
|
|
8936
9318
|
const lines = [];
|
|
8937
|
-
lines.push(...this.formatAsObject(tokens,
|
|
9319
|
+
lines.push(...this.formatAsObject(tokens, options));
|
|
8938
9320
|
const code = lines.join("\n");
|
|
8939
|
-
if (
|
|
9321
|
+
if (options.minify) {
|
|
8940
9322
|
return code;
|
|
8941
9323
|
}
|
|
8942
9324
|
return await prettier.format(code, {
|
|
@@ -8949,20 +9331,53 @@ var JsModuleRenderer = class {
|
|
|
8949
9331
|
trailingComma: "es5"
|
|
8950
9332
|
});
|
|
8951
9333
|
}
|
|
8952
|
-
/**
|
|
8953
|
-
* Format as default export object
|
|
8954
|
-
*/
|
|
8955
9334
|
formatAsObject(tokens, options) {
|
|
8956
9335
|
const lines = [];
|
|
8957
|
-
const
|
|
9336
|
+
const tokenMap = this.buildTokenMap(tokens);
|
|
8958
9337
|
const varName = options.moduleName !== "" ? options.moduleName : "tokens";
|
|
8959
|
-
|
|
8960
|
-
|
|
8961
|
-
|
|
9338
|
+
if (options.structure === "flat") {
|
|
9339
|
+
lines.push(`const ${varName} = {`);
|
|
9340
|
+
this.addFlatProperties(lines, tokens, 1);
|
|
9341
|
+
lines.push("}");
|
|
9342
|
+
} else {
|
|
9343
|
+
lines.push(`const ${varName} = {`);
|
|
9344
|
+
const tokenObj = this.tokensToPlainObject(tokens, "nested");
|
|
9345
|
+
this.addNestedProperties(lines, tokenObj, tokenMap, 1);
|
|
9346
|
+
lines.push("}");
|
|
9347
|
+
}
|
|
8962
9348
|
lines.push("");
|
|
8963
9349
|
lines.push(`export default ${varName}`);
|
|
8964
9350
|
return lines;
|
|
8965
9351
|
}
|
|
9352
|
+
buildTokenMap(tokens) {
|
|
9353
|
+
const map = /* @__PURE__ */ new Map();
|
|
9354
|
+
for (const [name, token] of Object.entries(tokens)) {
|
|
9355
|
+
map.set(name, token);
|
|
9356
|
+
}
|
|
9357
|
+
return map;
|
|
9358
|
+
}
|
|
9359
|
+
addFlatProperties(lines, tokens, indent) {
|
|
9360
|
+
const indentStr2 = " ".repeat(indent);
|
|
9361
|
+
const sortedEntries = getSortedTokenEntries(tokens);
|
|
9362
|
+
for (let i = 0; i < sortedEntries.length; i++) {
|
|
9363
|
+
const [name, token] = sortedEntries[i];
|
|
9364
|
+
const isLast = i === sortedEntries.length - 1;
|
|
9365
|
+
this.pushTokenComments(lines, token, indentStr2);
|
|
9366
|
+
lines.push(
|
|
9367
|
+
`${indentStr2}${this.quoteKey(name)}: ${JSON.stringify(token.$value)}${isLast ? "" : ","}`
|
|
9368
|
+
);
|
|
9369
|
+
}
|
|
9370
|
+
}
|
|
9371
|
+
pushTokenComments(lines, token, indent) {
|
|
9372
|
+
const deprecationComment = buildTokenDeprecationComment(token, "js");
|
|
9373
|
+
if (deprecationComment) {
|
|
9374
|
+
lines.push(`${indent}${deprecationComment}`);
|
|
9375
|
+
}
|
|
9376
|
+
const descriptionComment = buildTokenDescriptionComment(token, "js");
|
|
9377
|
+
if (descriptionComment) {
|
|
9378
|
+
lines.push(`${indent}${descriptionComment}`);
|
|
9379
|
+
}
|
|
9380
|
+
}
|
|
8966
9381
|
tokensToPlainObject(tokens, structure) {
|
|
8967
9382
|
if (structure === "nested") {
|
|
8968
9383
|
return buildNestedTokenObject(tokens, (token) => token.$value);
|
|
@@ -8973,7 +9388,7 @@ var JsModuleRenderer = class {
|
|
|
8973
9388
|
}
|
|
8974
9389
|
return result;
|
|
8975
9390
|
}
|
|
8976
|
-
|
|
9391
|
+
addNestedProperties(lines, obj, tokenMap, indent) {
|
|
8977
9392
|
const indentStr2 = " ".repeat(indent);
|
|
8978
9393
|
const entries = Object.entries(obj).sort(([keyA], [keyB]) => keyA.localeCompare(keyB));
|
|
8979
9394
|
for (let i = 0; i < entries.length; i++) {
|
|
@@ -8985,19 +9400,20 @@ var JsModuleRenderer = class {
|
|
|
8985
9400
|
const isLast = i === entries.length - 1;
|
|
8986
9401
|
const isNestedObject = typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8987
9402
|
if (!isNestedObject) {
|
|
9403
|
+
const token = tokenMap.get(key);
|
|
9404
|
+
if (token) {
|
|
9405
|
+
this.pushTokenComments(lines, token, indentStr2);
|
|
9406
|
+
}
|
|
8988
9407
|
lines.push(
|
|
8989
9408
|
`${indentStr2}${this.quoteKey(key)}: ${JSON.stringify(value)}${isLast ? "" : ","}`
|
|
8990
9409
|
);
|
|
8991
9410
|
continue;
|
|
8992
9411
|
}
|
|
8993
9412
|
lines.push(`${indentStr2}${this.quoteKey(key)}: {`);
|
|
8994
|
-
this.
|
|
9413
|
+
this.addNestedProperties(lines, value, tokenMap, indent + 1);
|
|
8995
9414
|
lines.push(`${indentStr2}}${isLast ? "" : ","}`);
|
|
8996
9415
|
}
|
|
8997
9416
|
}
|
|
8998
|
-
/**
|
|
8999
|
-
* Quote key if necessary
|
|
9000
|
-
*/
|
|
9001
9417
|
quoteKey(key) {
|
|
9002
9418
|
if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key)) {
|
|
9003
9419
|
return key;
|
|
@@ -9233,6 +9649,7 @@ function resolveOptions(options) {
|
|
|
9233
9649
|
|
|
9234
9650
|
// src/renderers/tailwind.ts
|
|
9235
9651
|
init_utils();
|
|
9652
|
+
init_metadata();
|
|
9236
9653
|
var TAILWIND_NAMESPACE_MAP = {
|
|
9237
9654
|
color: "color",
|
|
9238
9655
|
dimension: "spacing",
|
|
@@ -9286,6 +9703,14 @@ var TailwindRenderer = class {
|
|
|
9286
9703
|
for (const [, token] of getSortedTokenEntries(tokens)) {
|
|
9287
9704
|
const varName = this.buildVariableName(token);
|
|
9288
9705
|
const varValue = this.formatValue(token);
|
|
9706
|
+
const deprecationComment = buildTokenDeprecationComment(token, "tailwind");
|
|
9707
|
+
if (deprecationComment) {
|
|
9708
|
+
lines.push(`${indent}${deprecationComment}${newline}`);
|
|
9709
|
+
}
|
|
9710
|
+
const descriptionComment = buildTokenDescriptionComment(token, "tailwind");
|
|
9711
|
+
if (descriptionComment) {
|
|
9712
|
+
lines.push(`${indent}${descriptionComment}${newline}`);
|
|
9713
|
+
}
|
|
9289
9714
|
lines.push(`${indent}--${varName}:${space}${varValue};${newline}`);
|
|
9290
9715
|
}
|
|
9291
9716
|
lines.push(`}${newline}`);
|
|
@@ -9312,6 +9737,14 @@ var TailwindRenderer = class {
|
|
|
9312
9737
|
for (const [, token] of getSortedTokenEntries(tokens)) {
|
|
9313
9738
|
const varName = this.buildVariableName(token);
|
|
9314
9739
|
const varValue = this.formatValue(token);
|
|
9740
|
+
const deprecationComment = buildTokenDeprecationComment(token, "tailwind");
|
|
9741
|
+
if (deprecationComment) {
|
|
9742
|
+
lines.push(`${tokenIndent}${deprecationComment}${newline}`);
|
|
9743
|
+
}
|
|
9744
|
+
const descriptionComment = buildTokenDescriptionComment(token, "tailwind");
|
|
9745
|
+
if (descriptionComment) {
|
|
9746
|
+
lines.push(`${tokenIndent}${descriptionComment}${newline}`);
|
|
9747
|
+
}
|
|
9315
9748
|
lines.push(`${tokenIndent}--${varName}:${space}${varValue};${newline}`);
|
|
9316
9749
|
}
|
|
9317
9750
|
if (hasMediaQuery) {
|
|
@@ -9584,12 +10017,19 @@ init_errors();
|
|
|
9584
10017
|
* This source code is licensed under the MIT license found in the
|
|
9585
10018
|
* LICENSE file in the root directory of this source tree.
|
|
9586
10019
|
*/
|
|
10020
|
+
/**
|
|
10021
|
+
* @license MIT
|
|
10022
|
+
* Copyright (c) 2025-present Dispersa
|
|
10023
|
+
*
|
|
10024
|
+
* This source code is licensed under the MIT license found in the
|
|
10025
|
+
* LICENSE file in the root directory of this source tree.
|
|
10026
|
+
*/
|
|
9587
10027
|
/**
|
|
9588
10028
|
* @license
|
|
9589
10029
|
* Copyright (c) 2025 Dispersa Contributors
|
|
9590
10030
|
* SPDX-License-Identifier: MIT
|
|
9591
10031
|
*/
|
|
9592
10032
|
|
|
9593
|
-
export { BasePermutationError, CircularReferenceError, ConfigurationError,
|
|
10033
|
+
export { BasePermutationError, CircularReferenceError, ConfigurationError, DispersaError, FileOperationError, LintError, ModifierError, TokenReferenceError, ValidationError, android, build, buildOrThrow, buildPermutation, css, defineRenderer, generateTypes, ios, isBorderToken, isColorToken, isDimensionToken, isDurationToken, isGradientToken, isOutputTree, isShadowToken, isTransitionToken, isTypographyToken, js, json, lint, outputTree, resolveAllPermutations, resolveTokens, tailwind };
|
|
9594
10034
|
//# sourceMappingURL=index.js.map
|
|
9595
10035
|
//# sourceMappingURL=index.js.map
|