dispersa 0.4.2 → 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 +73 -39
- package/dist/android-CRDfSB3_.d.cts +126 -0
- package/dist/android-DANJjjPO.d.ts +126 -0
- package/dist/builders.cjs +220 -64
- package/dist/builders.cjs.map +1 -1
- package/dist/builders.d.cts +15 -13
- package/dist/builders.d.ts +15 -13
- package/dist/builders.js +220 -64
- 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 +813 -355
- 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 +807 -355
- 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.cjs +0 -12
- package/dist/transforms.cjs.map +1 -1
- package/dist/transforms.d.cts +3 -7
- package/dist/transforms.d.ts +3 -7
- package/dist/transforms.js +1 -12
- package/dist/transforms.js.map +1 -1
- 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,7 +3,12 @@ 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';
|
|
11
|
+
import { kebabCase } from 'change-case';
|
|
7
12
|
import { converter, formatHex8, formatHex } from 'culori';
|
|
8
13
|
import prettier from 'prettier';
|
|
9
14
|
|
|
@@ -18,7 +23,7 @@ var __export = (target, all) => {
|
|
|
18
23
|
};
|
|
19
24
|
|
|
20
25
|
// src/shared/errors/index.ts
|
|
21
|
-
var DispersaError, TokenReferenceError, CircularReferenceError, ValidationError, FileOperationError, ConfigurationError, BasePermutationError, ModifierError;
|
|
26
|
+
var DispersaError, TokenReferenceError, CircularReferenceError, ValidationError, FileOperationError, ConfigurationError, BasePermutationError, ModifierError, LintError;
|
|
22
27
|
var init_errors = __esm({
|
|
23
28
|
"src/shared/errors/index.ts"() {
|
|
24
29
|
DispersaError = class extends Error {
|
|
@@ -101,23 +106,19 @@ var init_errors = __esm({
|
|
|
101
106
|
this.name = "ModifierError";
|
|
102
107
|
}
|
|
103
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
|
+
};
|
|
104
118
|
}
|
|
105
119
|
});
|
|
106
120
|
|
|
107
121
|
// src/shared/utils/token-utils.ts
|
|
108
|
-
function formatDeprecationMessage(token, description = "", format = "bracket") {
|
|
109
|
-
if (token.$deprecated == null || token.$deprecated === false) {
|
|
110
|
-
return description;
|
|
111
|
-
}
|
|
112
|
-
const deprecationMsg = typeof token.$deprecated === "string" ? token.$deprecated : "";
|
|
113
|
-
if (format === "comment") {
|
|
114
|
-
const msg2 = deprecationMsg ? ` ${deprecationMsg}` : "";
|
|
115
|
-
return `DEPRECATED${msg2}`;
|
|
116
|
-
}
|
|
117
|
-
const msg = deprecationMsg ? `: ${deprecationMsg}` : "";
|
|
118
|
-
const prefix = `[DEPRECATED${msg}]`;
|
|
119
|
-
return description ? `${prefix} ${description}` : prefix;
|
|
120
|
-
}
|
|
121
122
|
function stripInternalTokenMetadata(tokens) {
|
|
122
123
|
const cleaned = {};
|
|
123
124
|
for (const [name, token] of Object.entries(tokens)) {
|
|
@@ -2471,7 +2472,7 @@ var init_schemas = __esm({
|
|
|
2471
2472
|
});
|
|
2472
2473
|
|
|
2473
2474
|
// src/validation/config-schemas.ts
|
|
2474
|
-
var resolverSchemaRef, basePluginProperties, commonRendererOptionsProperties, transformPluginSchema, rendererPluginSchema, filterPluginSchema, preprocessorPluginSchema, outputConfigSchema, dispersaOptionsSchema, buildConfigSchema;
|
|
2475
|
+
var resolverSchemaRef, basePluginProperties, commonRendererOptionsProperties, transformPluginSchema, rendererPluginSchema, filterPluginSchema, preprocessorPluginSchema, lintConfigSchema, outputConfigSchema, dispersaOptionsSchema, buildConfigSchema;
|
|
2475
2476
|
var init_config_schemas = __esm({
|
|
2476
2477
|
"src/validation/config-schemas.ts"() {
|
|
2477
2478
|
init_schemas();
|
|
@@ -2622,6 +2623,42 @@ var init_config_schemas = __esm({
|
|
|
2622
2623
|
}
|
|
2623
2624
|
}
|
|
2624
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
|
+
};
|
|
2625
2662
|
outputConfigSchema = {
|
|
2626
2663
|
$schema: "http://json-schema.org/draft-07/schema#",
|
|
2627
2664
|
type: "object",
|
|
@@ -2739,10 +2776,20 @@ var init_config_schemas = __esm({
|
|
|
2739
2776
|
description: "Resolver configuration - file path or ResolverDocument object"
|
|
2740
2777
|
},
|
|
2741
2778
|
buildPath: { type: "string" },
|
|
2779
|
+
validation: {
|
|
2780
|
+
type: "object",
|
|
2781
|
+
properties: {
|
|
2782
|
+
mode: { type: "string", enum: ["error", "warn", "off"] }
|
|
2783
|
+
}
|
|
2784
|
+
},
|
|
2742
2785
|
hooks: {
|
|
2743
2786
|
type: "object",
|
|
2744
2787
|
description: "Global build lifecycle hooks (functions, validated at runtime)",
|
|
2745
2788
|
additionalProperties: true
|
|
2789
|
+
},
|
|
2790
|
+
lint: {
|
|
2791
|
+
...lintConfigSchema,
|
|
2792
|
+
description: "Linting configuration"
|
|
2746
2793
|
}
|
|
2747
2794
|
},
|
|
2748
2795
|
additionalProperties: false
|
|
@@ -3290,7 +3337,7 @@ function indentStr(width, level) {
|
|
|
3290
3337
|
function buildGeneratedFileHeader() {
|
|
3291
3338
|
return [
|
|
3292
3339
|
"// Generated by Dispersa - do not edit manually",
|
|
3293
|
-
"// https://github.com/
|
|
3340
|
+
"// https://github.com/dispersa-core/dispersa"
|
|
3294
3341
|
].join("\n");
|
|
3295
3342
|
}
|
|
3296
3343
|
function toSafeIdentifier(name, keywords, capitalize) {
|
|
@@ -3502,6 +3549,94 @@ var init_utils = __esm({
|
|
|
3502
3549
|
}
|
|
3503
3550
|
});
|
|
3504
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
|
+
|
|
3505
3640
|
// src/renderers/bundlers/js.ts
|
|
3506
3641
|
var js_exports = {};
|
|
3507
3642
|
__export(js_exports, {
|
|
@@ -3606,7 +3741,7 @@ async function bundleAsJsModule(bundleData, resolver, options, formatTokens) {
|
|
|
3606
3741
|
}
|
|
3607
3742
|
const metadata = buildMetadata(resolver);
|
|
3608
3743
|
const jsBlocks = [];
|
|
3609
|
-
for (const { tokens, modifierInputs } of bundleData) {
|
|
3744
|
+
for (const { tokens, modifierInputs, isBase } of bundleData) {
|
|
3610
3745
|
const cleanTokens = stripInternalMetadata(tokens);
|
|
3611
3746
|
const key = buildStableDashKey({
|
|
3612
3747
|
modifierInputs,
|
|
@@ -3614,10 +3749,30 @@ async function bundleAsJsModule(bundleData, resolver, options, formatTokens) {
|
|
|
3614
3749
|
defaults: metadata.defaults
|
|
3615
3750
|
});
|
|
3616
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
|
+
}
|
|
3617
3760
|
const formattedJs = await formatTokens(cleanTokens);
|
|
3618
3761
|
const tokenObject = extractObjectFromJsModule(formattedJs);
|
|
3619
3762
|
const indentedObject = tokenObject.replace(/\n/g, "\n ");
|
|
3620
|
-
|
|
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}
|
|
3621
3776
|
${JSON.stringify(camelKey)}: ${indentedObject}`);
|
|
3622
3777
|
}
|
|
3623
3778
|
return assembleJsBundle(metadata, jsBlocks, options?.generateHelper ?? false);
|
|
@@ -3625,6 +3780,7 @@ async function bundleAsJsModule(bundleData, resolver, options, formatTokens) {
|
|
|
3625
3780
|
var init_js = __esm({
|
|
3626
3781
|
"src/renderers/bundlers/js.ts"() {
|
|
3627
3782
|
init_errors();
|
|
3783
|
+
init_metadata();
|
|
3628
3784
|
init_utils();
|
|
3629
3785
|
}
|
|
3630
3786
|
});
|
|
@@ -3994,7 +4150,8 @@ var BuildOrchestrator = class {
|
|
|
3994
4150
|
resolver,
|
|
3995
4151
|
config.transforms,
|
|
3996
4152
|
config.preprocessors,
|
|
3997
|
-
config.filters
|
|
4153
|
+
config.filters,
|
|
4154
|
+
config.lint
|
|
3998
4155
|
);
|
|
3999
4156
|
return this.executeBuild(buildPath, config, permutations2, resolver);
|
|
4000
4157
|
}
|
|
@@ -4005,7 +4162,8 @@ var BuildOrchestrator = class {
|
|
|
4005
4162
|
modifierInputs,
|
|
4006
4163
|
config.transforms,
|
|
4007
4164
|
config.preprocessors,
|
|
4008
|
-
config.filters
|
|
4165
|
+
config.filters,
|
|
4166
|
+
config.lint
|
|
4009
4167
|
);
|
|
4010
4168
|
return { tokens, modifierInputs: resolvedInputs };
|
|
4011
4169
|
})
|
|
@@ -4266,7 +4424,358 @@ var OutputProcessor = class {
|
|
|
4266
4424
|
|
|
4267
4425
|
// src/build/pipeline/token-pipeline.ts
|
|
4268
4426
|
init_resolver_loader();
|
|
4269
|
-
|
|
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
|
+
};
|
|
4270
4779
|
|
|
4271
4780
|
// src/shared/constants.ts
|
|
4272
4781
|
var DEFAULT_MAX_ALIAS_DEPTH = 10;
|
|
@@ -5461,6 +5970,10 @@ var ResolutionEngine = class {
|
|
|
5461
5970
|
return typeof obj === "object" && obj !== null && "contexts" in obj && typeof obj.contexts === "object";
|
|
5462
5971
|
}
|
|
5463
5972
|
};
|
|
5973
|
+
|
|
5974
|
+
// src/build/pipeline/token-pipeline.ts
|
|
5975
|
+
init_errors();
|
|
5976
|
+
init_validation_handler();
|
|
5464
5977
|
init_errors();
|
|
5465
5978
|
|
|
5466
5979
|
// src/shared/utils/path-utils.ts
|
|
@@ -5953,6 +6466,8 @@ var TokenPipeline = class {
|
|
|
5953
6466
|
resolverLoader;
|
|
5954
6467
|
tokenParser;
|
|
5955
6468
|
aliasResolver;
|
|
6469
|
+
lintRunner = null;
|
|
6470
|
+
lintConfigCache = null;
|
|
5956
6471
|
constructor(options = {}) {
|
|
5957
6472
|
this.options = options;
|
|
5958
6473
|
this.validationHandler = new ValidationHandler(options.validation);
|
|
@@ -5972,8 +6487,9 @@ var TokenPipeline = class {
|
|
|
5972
6487
|
* 6. Parse and flatten token structure
|
|
5973
6488
|
* 7. Resolve alias references
|
|
5974
6489
|
* 8. Strip $root from token names/paths (DTCG structural mechanism, transparent in output)
|
|
5975
|
-
* 9.
|
|
5976
|
-
* 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
|
|
5977
6493
|
*
|
|
5978
6494
|
* Each stage is explicitly typed to ensure correct order and prevent temporal coupling.
|
|
5979
6495
|
*
|
|
@@ -5982,9 +6498,11 @@ var TokenPipeline = class {
|
|
|
5982
6498
|
* @param transformList - Optional transforms to apply
|
|
5983
6499
|
* @param preprocessorList - Optional preprocessors to apply
|
|
5984
6500
|
* @param filterList - Optional filters to apply before transforms
|
|
5985
|
-
* @
|
|
6501
|
+
* @param lintConfig - Optional lint configuration for this run
|
|
6502
|
+
* @returns Final tokens, resolution engine, and lint result
|
|
5986
6503
|
*/
|
|
5987
|
-
async resolve(resolver, modifierInputs, transformList, preprocessorList, filterList) {
|
|
6504
|
+
async resolve(resolver, modifierInputs, transformList, preprocessorList, filterList, lintConfig) {
|
|
6505
|
+
const effectiveLintConfig = lintConfig ?? this.options.lint;
|
|
5988
6506
|
const stage1 = await this.loadResolver(resolver);
|
|
5989
6507
|
const engine = this.createEngine(stage1);
|
|
5990
6508
|
const result = await this.runPipelineStages(
|
|
@@ -5992,29 +6510,32 @@ var TokenPipeline = class {
|
|
|
5992
6510
|
modifierInputs,
|
|
5993
6511
|
preprocessorList,
|
|
5994
6512
|
filterList,
|
|
5995
|
-
transformList
|
|
6513
|
+
transformList,
|
|
6514
|
+
effectiveLintConfig
|
|
5996
6515
|
);
|
|
5997
6516
|
return {
|
|
5998
6517
|
tokens: result.tokens,
|
|
5999
6518
|
resolutionEngine: result.resolutionEngine,
|
|
6000
|
-
modifierInputs: result.modifierInputs
|
|
6519
|
+
modifierInputs: result.modifierInputs,
|
|
6520
|
+
lintResult: result.lintResult
|
|
6001
6521
|
};
|
|
6002
6522
|
}
|
|
6003
6523
|
/**
|
|
6004
|
-
* Run pipeline stages 3-
|
|
6524
|
+
* Run pipeline stages 3-11 on a pre-created engine
|
|
6005
6525
|
*
|
|
6006
6526
|
* Shared by both `resolve()` (single permutation) and
|
|
6007
6527
|
* `resolveAllPermutations()` (parallel permutations) to keep the
|
|
6008
6528
|
* stage sequence defined in exactly one place.
|
|
6009
6529
|
*/
|
|
6010
|
-
async runPipelineStages(engine, modifierInputs, preprocessorList, filterList, transformList) {
|
|
6530
|
+
async runPipelineStages(engine, modifierInputs, preprocessorList, filterList, transformList, lintConfig) {
|
|
6011
6531
|
const rawTokens = await this.resolveTokens(engine, modifierInputs);
|
|
6012
6532
|
const preprocessed = await this.preprocessTokens(rawTokens, preprocessorList);
|
|
6013
6533
|
const refResolved = await this.resolveReferences(preprocessed);
|
|
6014
6534
|
const flattened = this.flattenTokens(refResolved);
|
|
6015
6535
|
const aliasResolved = this.resolveAliases(flattened);
|
|
6016
6536
|
const rootStripped = this.stripRootTokenNames(aliasResolved);
|
|
6017
|
-
const
|
|
6537
|
+
const linted = await this.runLintStage(rootStripped, lintConfig);
|
|
6538
|
+
const filtered = this.applyFilterStage(linted, filterList);
|
|
6018
6539
|
return this.applyTransformStage(filtered, transformList);
|
|
6019
6540
|
}
|
|
6020
6541
|
/**
|
|
@@ -6127,6 +6648,47 @@ var TokenPipeline = class {
|
|
|
6127
6648
|
}
|
|
6128
6649
|
return { ...stage, aliasResolvedTokens: result };
|
|
6129
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
|
+
*/
|
|
6130
6692
|
applyFilterStage(stage, filterList) {
|
|
6131
6693
|
let tokens = stage.aliasResolvedTokens;
|
|
6132
6694
|
if (filterList !== void 0 && filterList.length > 0) {
|
|
@@ -6135,7 +6697,7 @@ var TokenPipeline = class {
|
|
|
6135
6697
|
return { ...stage, aliasResolvedTokens: tokens };
|
|
6136
6698
|
}
|
|
6137
6699
|
/**
|
|
6138
|
-
* Stage
|
|
6700
|
+
* Stage 11: Apply transforms to the filtered token set
|
|
6139
6701
|
*/
|
|
6140
6702
|
applyTransformStage(stage, transformList) {
|
|
6141
6703
|
let tokens = stage.aliasResolvedTokens;
|
|
@@ -6169,8 +6731,10 @@ var TokenPipeline = class {
|
|
|
6169
6731
|
* @param transformList - Optional transforms to apply
|
|
6170
6732
|
* @param preprocessorList - Optional preprocessors to apply
|
|
6171
6733
|
* @param filterList - Optional filters to apply before transforms
|
|
6734
|
+
* @param lintConfig - Optional lint configuration for this run
|
|
6172
6735
|
*/
|
|
6173
|
-
async resolveAllPermutations(resolver, transformList, preprocessorList, filterList) {
|
|
6736
|
+
async resolveAllPermutations(resolver, transformList, preprocessorList, filterList, lintConfig) {
|
|
6737
|
+
const effectiveLintConfig = lintConfig ?? this.options.lint;
|
|
6174
6738
|
const stage1 = await this.loadResolver(resolver);
|
|
6175
6739
|
const discoveryEngine = this.createEngine(stage1);
|
|
6176
6740
|
const permutationInputs = discoveryEngine.resolutionEngine.generatePermutations();
|
|
@@ -6183,11 +6747,13 @@ var TokenPipeline = class {
|
|
|
6183
6747
|
modifierInputs,
|
|
6184
6748
|
preprocessorList,
|
|
6185
6749
|
filterList,
|
|
6186
|
-
transformList
|
|
6750
|
+
transformList,
|
|
6751
|
+
effectiveLintConfig
|
|
6187
6752
|
);
|
|
6188
6753
|
return {
|
|
6189
6754
|
tokens: result.tokens,
|
|
6190
|
-
modifierInputs: result.modifierInputs
|
|
6755
|
+
modifierInputs: result.modifierInputs,
|
|
6756
|
+
lintResult: result.lintResult
|
|
6191
6757
|
};
|
|
6192
6758
|
})
|
|
6193
6759
|
);
|
|
@@ -6208,286 +6774,106 @@ var TokenPipeline = class {
|
|
|
6208
6774
|
init_errors();
|
|
6209
6775
|
init_token_utils();
|
|
6210
6776
|
init_validator();
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
const errors = this.validator.validateDispersaOptions(options);
|
|
6229
|
-
if (errors.length > 0) {
|
|
6230
|
-
throw new ConfigurationError(
|
|
6231
|
-
`Invalid Dispersa options: ${this.validator.getErrorMessage(errors)}`
|
|
6232
|
-
);
|
|
6233
|
-
}
|
|
6234
|
-
this.pipeline = new TokenPipeline({ validation: options.validation });
|
|
6235
|
-
this.outputProcessor = new OutputProcessor();
|
|
6236
|
-
this.orchestrator = new BuildOrchestrator(this.pipeline, this.outputProcessor);
|
|
6237
|
-
}
|
|
6238
|
-
/**
|
|
6239
|
-
* Builds design tokens from a resolver configuration
|
|
6240
|
-
*
|
|
6241
|
-
* Processes tokens through the resolution pipeline, applies preprocessors,
|
|
6242
|
-
* transforms, and filters, then generates output files in multiple formats
|
|
6243
|
-
* for specified outputs.
|
|
6244
|
-
*
|
|
6245
|
-
* **Runtime Validation:**
|
|
6246
|
-
* This method validates the build configuration
|
|
6247
|
-
* and all output configurations before processing, throwing helpful errors for
|
|
6248
|
-
* invalid inputs.
|
|
6249
|
-
*
|
|
6250
|
-
* **Permutation Handling:**
|
|
6251
|
-
* - If `config.permutations` is provided and non-empty, builds those specific permutations
|
|
6252
|
-
* - If `config.permutations` is undefined or empty, auto-discovers all permutations from resolver
|
|
6253
|
-
*
|
|
6254
|
-
* @param config - Build configuration
|
|
6255
|
-
* @param config.resolver - Resolver configuration (file path or inline object, optional if set in constructor)
|
|
6256
|
-
* @param config.outputs - Array of output configurations (renderers, transforms, filters)
|
|
6257
|
-
* @param config.buildPath - Output directory for generated files (omit for in-memory mode, optional if set in constructor)
|
|
6258
|
-
* @param config.transforms - Global transforms to apply to all tokens
|
|
6259
|
-
* @param config.preprocessors - Global preprocessors to apply before parsing
|
|
6260
|
-
* @param config.permutations - Array of modifier inputs for generating variations
|
|
6261
|
-
* @returns Build result with success status and generated output files
|
|
6262
|
-
* @throws {ConfigurationError} If configuration is invalid
|
|
6263
|
-
* @throws {FileOperationError} If file operations fail
|
|
6264
|
-
*
|
|
6265
|
-
* @example Basic build
|
|
6266
|
-
* ```typescript
|
|
6267
|
-
* const dispersa = new Dispersa({
|
|
6268
|
-
* resolver: './tokens.resolver.json',
|
|
6269
|
-
* buildPath: './output'
|
|
6270
|
-
* })
|
|
6271
|
-
*
|
|
6272
|
-
* const result = await dispersa.build({
|
|
6273
|
-
* outputs: [
|
|
6274
|
-
* css({
|
|
6275
|
-
* name: 'css',
|
|
6276
|
-
* file: 'tokens.css',
|
|
6277
|
-
* preset: 'bundle',
|
|
6278
|
-
* selector: ':root',
|
|
6279
|
-
* transforms: [nameKebabCase()]
|
|
6280
|
-
* })
|
|
6281
|
-
* ]
|
|
6282
|
-
* })
|
|
6283
|
-
* ```
|
|
6284
|
-
*
|
|
6285
|
-
* @example With filters and multiple presets
|
|
6286
|
-
* ```typescript
|
|
6287
|
-
* const result = await dispersa.build({
|
|
6288
|
-
* resolver: './tokens.resolver.json',
|
|
6289
|
-
* outputs: [
|
|
6290
|
-
* css({
|
|
6291
|
-
* name: 'css',
|
|
6292
|
-
* file: 'tokens.css',
|
|
6293
|
-
* preset: 'bundle',
|
|
6294
|
-
* selector: ':root', // All themes in one file
|
|
6295
|
-
* transforms: [nameKebabCase()]
|
|
6296
|
-
* }),
|
|
6297
|
-
* json({
|
|
6298
|
-
* name: 'json',
|
|
6299
|
-
* file: 'tokens-{theme}.json', // Separate file per theme
|
|
6300
|
-
* preset: 'standalone',
|
|
6301
|
-
* structure: 'flat'
|
|
6302
|
-
* })
|
|
6303
|
-
* ],
|
|
6304
|
-
* buildPath: './output',
|
|
6305
|
-
* permutations: [
|
|
6306
|
-
* { theme: 'light' },
|
|
6307
|
-
* { theme: 'dark' }
|
|
6308
|
-
* ]
|
|
6309
|
-
* })
|
|
6310
|
-
* ```
|
|
6311
|
-
*/
|
|
6312
|
-
async build(config) {
|
|
6313
|
-
try {
|
|
6314
|
-
return await this.buildOrThrow(config);
|
|
6315
|
-
} catch (error) {
|
|
6316
|
-
return {
|
|
6317
|
-
success: false,
|
|
6318
|
-
outputs: [],
|
|
6319
|
-
errors: [toBuildError(error)]
|
|
6320
|
-
};
|
|
6321
|
-
}
|
|
6322
|
-
}
|
|
6323
|
-
/**
|
|
6324
|
-
* Builds design tokens and throws on any failure.
|
|
6325
|
-
*
|
|
6326
|
-
* Unlike {@link build}, which catches errors and returns them inside
|
|
6327
|
-
* `BuildResult.errors`, this method propagates the first error as an
|
|
6328
|
-
* exception. Use it when you want fail-fast behavior in CLI or CI workflows.
|
|
6329
|
-
*
|
|
6330
|
-
* @param config - Build configuration specifying resolver, outputs, transforms, etc.
|
|
6331
|
-
* @returns A successful `BuildResult` (never contains errors)
|
|
6332
|
-
* @throws {ConfigurationError} When the build config or resolver is invalid
|
|
6333
|
-
* @throws {DispersaError} When token resolution, transforms, or rendering fails
|
|
6334
|
-
*
|
|
6335
|
-
* @example
|
|
6336
|
-
* ```typescript
|
|
6337
|
-
* try {
|
|
6338
|
-
* const result = await dispersa.buildOrThrow({
|
|
6339
|
-
* resolver: './tokens.resolver.json',
|
|
6340
|
-
* outputs: [css({ name: 'css', file: 'tokens.css' })],
|
|
6341
|
-
* buildPath: './output',
|
|
6342
|
-
* })
|
|
6343
|
-
* } catch (error) {
|
|
6344
|
-
* process.exit(1)
|
|
6345
|
-
* }
|
|
6346
|
-
* ```
|
|
6347
|
-
*/
|
|
6348
|
-
async buildOrThrow(config) {
|
|
6349
|
-
const configErrors = this.validator.validateBuildConfig(config);
|
|
6350
|
-
if (configErrors.length > 0) {
|
|
6351
|
-
throw new ConfigurationError(
|
|
6352
|
-
`Invalid build configuration: ${this.validator.getErrorMessage(configErrors)}`
|
|
6353
|
-
);
|
|
6354
|
-
}
|
|
6355
|
-
for (const output of config.outputs) {
|
|
6356
|
-
const outputErrors = this.validator.validateOutputConfig(output);
|
|
6357
|
-
if (outputErrors.length > 0) {
|
|
6358
|
-
throw new ConfigurationError(
|
|
6359
|
-
`Invalid output '${output.name}': ${this.validator.getErrorMessage(outputErrors)}`
|
|
6360
|
-
);
|
|
6361
|
-
}
|
|
6362
|
-
}
|
|
6363
|
-
const { resolver, buildPath } = this.resolveConfig(config);
|
|
6364
|
-
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");
|
|
6365
6794
|
}
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
* @param config - Build configuration
|
|
6375
|
-
* @param modifierInputs - Modifier values (e.g., `{ theme: 'dark' }`)
|
|
6376
|
-
* @returns Build result (success, outputs, optional errors)
|
|
6377
|
-
*/
|
|
6378
|
-
async buildPermutation(config, modifierInputs = {}) {
|
|
6379
|
-
return await this.build({
|
|
6380
|
-
...config,
|
|
6381
|
-
permutations: [modifierInputs]
|
|
6382
|
-
});
|
|
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
|
+
);
|
|
6383
6803
|
}
|
|
6384
|
-
|
|
6385
|
-
|
|
6386
|
-
|
|
6387
|
-
resolveConfig(config) {
|
|
6388
|
-
const resolver = config.resolver ?? this.options.resolver;
|
|
6389
|
-
const buildPath = config.buildPath ?? this.options.buildPath ?? "";
|
|
6390
|
-
if (!resolver) {
|
|
6804
|
+
for (const output of config.outputs) {
|
|
6805
|
+
const outputErrors = validator.validateOutputConfig(output);
|
|
6806
|
+
if (outputErrors.length > 0) {
|
|
6391
6807
|
throw new ConfigurationError(
|
|
6392
|
-
|
|
6808
|
+
`Invalid output '${output.name}': ${validator.getErrorMessage(outputErrors)}`
|
|
6393
6809
|
);
|
|
6394
6810
|
}
|
|
6395
|
-
return { resolver, buildPath };
|
|
6396
6811
|
}
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
|
|
6411
|
-
* ```typescript
|
|
6412
|
-
* const tokens = await dispersa.resolveTokens(
|
|
6413
|
-
* './tokens.resolver.json',
|
|
6414
|
-
* { theme: 'dark' }
|
|
6415
|
-
* )
|
|
6416
|
-
*
|
|
6417
|
-
* console.log(tokens['color.background'].$value) // '#1a1a1a'
|
|
6418
|
-
* ```
|
|
6419
|
-
*/
|
|
6420
|
-
async resolveTokens(resolver, modifierInputs = {}) {
|
|
6421
|
-
const { tokens } = await this.pipeline.resolve(resolver, modifierInputs);
|
|
6422
|
-
return stripInternalTokenMetadata(tokens);
|
|
6423
|
-
}
|
|
6424
|
-
/**
|
|
6425
|
-
* Resolves tokens for all permutations defined in the resolver
|
|
6426
|
-
*
|
|
6427
|
-
* Auto-discovers all possible permutations from the resolver's modifier
|
|
6428
|
-
* definitions and resolves tokens for each one. Useful for generating
|
|
6429
|
-
* comprehensive token sets or validating all theme variations.
|
|
6430
|
-
*
|
|
6431
|
-
* @param resolver - Resolver configuration (file path or inline object)
|
|
6432
|
-
* @returns Array of resolved token sets with their modifier inputs
|
|
6433
|
-
* @throws {FileOperationError} If resolver file cannot be read
|
|
6434
|
-
* @throws {TokenReferenceError} If token references cannot be resolved (when validate is enabled)
|
|
6435
|
-
*
|
|
6436
|
-
* @example
|
|
6437
|
-
* ```typescript
|
|
6438
|
-
* const permutations = await dispersa.resolveAllPermutations(
|
|
6439
|
-
* './tokens.resolver.json'
|
|
6440
|
-
* )
|
|
6441
|
-
*
|
|
6442
|
-
* permutations.forEach(({ tokens, modifierInputs }) => {
|
|
6443
|
-
* console.log(`Theme: ${modifierInputs.theme}`)
|
|
6444
|
-
* console.log(`Tokens: ${Object.keys(tokens).length}`)
|
|
6445
|
-
* })
|
|
6446
|
-
* ```
|
|
6447
|
-
*/
|
|
6448
|
-
async resolveAllPermutations(resolver) {
|
|
6449
|
-
const permutations = await this.pipeline.resolveAllPermutations(resolver);
|
|
6450
|
-
return permutations.map(({ tokens, modifierInputs }) => ({
|
|
6451
|
-
tokens: stripInternalTokenMetadata(tokens),
|
|
6452
|
-
modifierInputs
|
|
6453
|
-
}));
|
|
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
|
+
};
|
|
6454
6826
|
}
|
|
6455
|
-
|
|
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
|
-
moduleName: options?.moduleName ?? "Tokens",
|
|
6487
|
-
includeValues: true
|
|
6488
|
-
});
|
|
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);
|
|
6489
6858
|
}
|
|
6490
|
-
|
|
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
|
+
}
|
|
6491
6877
|
|
|
6492
6878
|
// src/tokens/types.ts
|
|
6493
6879
|
function isColorToken(token) {
|
|
@@ -6514,6 +6900,17 @@ function isTransitionToken(token) {
|
|
|
6514
6900
|
function isGradientToken(token) {
|
|
6515
6901
|
return token.$type === "gradient";
|
|
6516
6902
|
}
|
|
6903
|
+
function nameKebabCase() {
|
|
6904
|
+
return {
|
|
6905
|
+
transform: (token) => {
|
|
6906
|
+
const name = kebabCase(token.path.join(" "));
|
|
6907
|
+
return {
|
|
6908
|
+
...token,
|
|
6909
|
+
name
|
|
6910
|
+
};
|
|
6911
|
+
}
|
|
6912
|
+
};
|
|
6913
|
+
}
|
|
6517
6914
|
function isColorObject(value) {
|
|
6518
6915
|
return typeof value === "object" && value !== null && "colorSpace" in value && "components" in value;
|
|
6519
6916
|
}
|
|
@@ -6591,6 +6988,7 @@ function durationObjectToString(duration) {
|
|
|
6591
6988
|
init_errors();
|
|
6592
6989
|
init_token_utils();
|
|
6593
6990
|
init_utils();
|
|
6991
|
+
init_metadata();
|
|
6594
6992
|
var toSRGB = converter("rgb");
|
|
6595
6993
|
var toP3 = converter("p3");
|
|
6596
6994
|
var KOTLIN_KEYWORDS = /* @__PURE__ */ new Set([
|
|
@@ -6641,9 +7039,6 @@ function resolveColorFormat(format) {
|
|
|
6641
7039
|
function escapeKotlinString(str) {
|
|
6642
7040
|
return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\$/g, "\\$");
|
|
6643
7041
|
}
|
|
6644
|
-
function escapeKDoc(str) {
|
|
6645
|
-
return str.replace(/\*\//g, "* /").replace(/\r?\n/g, " ").trim();
|
|
6646
|
-
}
|
|
6647
7042
|
function formatKotlinNumber(value) {
|
|
6648
7043
|
return Number.isInteger(value) ? `${value}.0` : String(value);
|
|
6649
7044
|
}
|
|
@@ -6775,8 +7170,13 @@ var AndroidRenderer = class {
|
|
|
6775
7170
|
const kotlinName = this.buildFlatKotlinName(token);
|
|
6776
7171
|
const kotlinValue = this.formatKotlinValue(token, options, baseDepth + 1);
|
|
6777
7172
|
const annotation = this.typeAnnotationSuffix(token);
|
|
6778
|
-
|
|
6779
|
-
|
|
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}`);
|
|
6780
7180
|
}
|
|
6781
7181
|
lines.push(
|
|
6782
7182
|
`${valIndent}${options.visPrefix}val ${kotlinName}${annotation} = ${kotlinValue}`
|
|
@@ -6812,8 +7212,13 @@ var AndroidRenderer = class {
|
|
|
6812
7212
|
const kotlinName = toSafeIdentifier(key, KOTLIN_KEYWORDS, false);
|
|
6813
7213
|
const kotlinValue = this.formatKotlinValue(token, options, depth);
|
|
6814
7214
|
const annotation = this.typeAnnotationSuffix(token);
|
|
6815
|
-
|
|
6816
|
-
|
|
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}`);
|
|
6817
7222
|
}
|
|
6818
7223
|
lines.push(`${pad}${options.visPrefix}val ${kotlinName}${annotation} = ${kotlinValue}`);
|
|
6819
7224
|
}
|
|
@@ -7590,10 +7995,8 @@ function stableInputsKey(modifierInputs) {
|
|
|
7590
7995
|
|
|
7591
7996
|
// src/renderers/css.ts
|
|
7592
7997
|
init_utils();
|
|
7998
|
+
init_metadata();
|
|
7593
7999
|
var CssRenderer = class _CssRenderer {
|
|
7594
|
-
sanitizeCssCommentText(text) {
|
|
7595
|
-
return text.replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ").trim();
|
|
7596
|
-
}
|
|
7597
8000
|
async format(context, options) {
|
|
7598
8001
|
const opts = {
|
|
7599
8002
|
preset: options?.preset ?? "bundle",
|
|
@@ -7673,12 +8076,13 @@ var CssRenderer = class _CssRenderer {
|
|
|
7673
8076
|
}
|
|
7674
8077
|
pushTokenLines(lines, token, tokens, referenceTokens, preserveReferences, indent, newline, space) {
|
|
7675
8078
|
const entries = this.buildCssEntries(token, tokens, referenceTokens, preserveReferences);
|
|
7676
|
-
|
|
7677
|
-
|
|
7678
|
-
lines.push(`${indent}
|
|
8079
|
+
const deprecationComment = buildTokenDeprecationComment(token, "css");
|
|
8080
|
+
if (deprecationComment) {
|
|
8081
|
+
lines.push(`${indent}${deprecationComment}${newline}`);
|
|
7679
8082
|
}
|
|
7680
|
-
|
|
7681
|
-
|
|
8083
|
+
const descriptionComment = buildTokenDescriptionComment(token, "css");
|
|
8084
|
+
if (descriptionComment) {
|
|
8085
|
+
lines.push(`${indent}${descriptionComment}${newline}`);
|
|
7682
8086
|
}
|
|
7683
8087
|
for (const entry of entries) {
|
|
7684
8088
|
lines.push(`${indent}--${entry.name}:${space}${entry.value};${newline}`);
|
|
@@ -8318,6 +8722,7 @@ function cssRenderer() {
|
|
|
8318
8722
|
|
|
8319
8723
|
// src/renderers/ios.ts
|
|
8320
8724
|
init_utils();
|
|
8725
|
+
init_metadata();
|
|
8321
8726
|
var toSRGB2 = converter("rgb");
|
|
8322
8727
|
var toP32 = converter("p3");
|
|
8323
8728
|
var SWIFT_TYPE_GROUP_MAP = {
|
|
@@ -8461,9 +8866,13 @@ var IosRenderer = class {
|
|
|
8461
8866
|
const swiftValue = this.formatSwiftValue(token, options);
|
|
8462
8867
|
const typeAnnotation = this.getTypeAnnotation(token);
|
|
8463
8868
|
const annotation = typeAnnotation ? `: ${typeAnnotation}` : "";
|
|
8464
|
-
const docComment =
|
|
8869
|
+
const docComment = buildTokenDescriptionComment(token, "swift");
|
|
8465
8870
|
if (docComment) {
|
|
8466
|
-
lines.push(docComment);
|
|
8871
|
+
lines.push(`${indent}${docComment}`);
|
|
8872
|
+
}
|
|
8873
|
+
const deprecationAttr = buildSwiftDeprecationAttribute(token);
|
|
8874
|
+
if (deprecationAttr) {
|
|
8875
|
+
lines.push(`${indent}${deprecationAttr}`);
|
|
8467
8876
|
}
|
|
8468
8877
|
lines.push(`${indent}${access3} ${staticPrefix}${swiftName}${annotation} = ${swiftValue}`);
|
|
8469
8878
|
}
|
|
@@ -8478,15 +8887,6 @@ var IosRenderer = class {
|
|
|
8478
8887
|
}
|
|
8479
8888
|
return Array.from(imports).sort();
|
|
8480
8889
|
}
|
|
8481
|
-
/**
|
|
8482
|
-
* Builds a `///` doc comment from a token's `$description`, if present.
|
|
8483
|
-
*/
|
|
8484
|
-
buildDocComment(token, indent) {
|
|
8485
|
-
if (!token.$description) {
|
|
8486
|
-
return void 0;
|
|
8487
|
-
}
|
|
8488
|
-
return `${indent}/// ${token.$description}`;
|
|
8489
|
-
}
|
|
8490
8890
|
/**
|
|
8491
8891
|
* Builds a qualified Swift name from a token's path, preserving parent
|
|
8492
8892
|
* hierarchy segments to avoid duplicate identifiers.
|
|
@@ -8877,6 +9277,7 @@ function iosRenderer() {
|
|
|
8877
9277
|
// src/renderers/js-module.ts
|
|
8878
9278
|
init_utils();
|
|
8879
9279
|
init_token_utils();
|
|
9280
|
+
init_metadata();
|
|
8880
9281
|
var JsModuleRenderer = class {
|
|
8881
9282
|
async format(context, options) {
|
|
8882
9283
|
const opts = {
|
|
@@ -8914,17 +9315,10 @@ var JsModuleRenderer = class {
|
|
|
8914
9315
|
return outputTree(files);
|
|
8915
9316
|
}
|
|
8916
9317
|
async formatTokens(tokens, options) {
|
|
8917
|
-
const opts = {
|
|
8918
|
-
preset: options.preset ?? "standalone",
|
|
8919
|
-
structure: options.structure ?? "nested",
|
|
8920
|
-
minify: options.minify ?? false,
|
|
8921
|
-
moduleName: options.moduleName ?? "tokens",
|
|
8922
|
-
generateHelper: options.generateHelper ?? false
|
|
8923
|
-
};
|
|
8924
9318
|
const lines = [];
|
|
8925
|
-
lines.push(...this.formatAsObject(tokens,
|
|
9319
|
+
lines.push(...this.formatAsObject(tokens, options));
|
|
8926
9320
|
const code = lines.join("\n");
|
|
8927
|
-
if (
|
|
9321
|
+
if (options.minify) {
|
|
8928
9322
|
return code;
|
|
8929
9323
|
}
|
|
8930
9324
|
return await prettier.format(code, {
|
|
@@ -8937,20 +9331,53 @@ var JsModuleRenderer = class {
|
|
|
8937
9331
|
trailingComma: "es5"
|
|
8938
9332
|
});
|
|
8939
9333
|
}
|
|
8940
|
-
/**
|
|
8941
|
-
* Format as default export object
|
|
8942
|
-
*/
|
|
8943
9334
|
formatAsObject(tokens, options) {
|
|
8944
9335
|
const lines = [];
|
|
8945
|
-
const
|
|
9336
|
+
const tokenMap = this.buildTokenMap(tokens);
|
|
8946
9337
|
const varName = options.moduleName !== "" ? options.moduleName : "tokens";
|
|
8947
|
-
|
|
8948
|
-
|
|
8949
|
-
|
|
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
|
+
}
|
|
8950
9348
|
lines.push("");
|
|
8951
9349
|
lines.push(`export default ${varName}`);
|
|
8952
9350
|
return lines;
|
|
8953
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
|
+
}
|
|
8954
9381
|
tokensToPlainObject(tokens, structure) {
|
|
8955
9382
|
if (structure === "nested") {
|
|
8956
9383
|
return buildNestedTokenObject(tokens, (token) => token.$value);
|
|
@@ -8961,7 +9388,7 @@ var JsModuleRenderer = class {
|
|
|
8961
9388
|
}
|
|
8962
9389
|
return result;
|
|
8963
9390
|
}
|
|
8964
|
-
|
|
9391
|
+
addNestedProperties(lines, obj, tokenMap, indent) {
|
|
8965
9392
|
const indentStr2 = " ".repeat(indent);
|
|
8966
9393
|
const entries = Object.entries(obj).sort(([keyA], [keyB]) => keyA.localeCompare(keyB));
|
|
8967
9394
|
for (let i = 0; i < entries.length; i++) {
|
|
@@ -8973,19 +9400,20 @@ var JsModuleRenderer = class {
|
|
|
8973
9400
|
const isLast = i === entries.length - 1;
|
|
8974
9401
|
const isNestedObject = typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8975
9402
|
if (!isNestedObject) {
|
|
9403
|
+
const token = tokenMap.get(key);
|
|
9404
|
+
if (token) {
|
|
9405
|
+
this.pushTokenComments(lines, token, indentStr2);
|
|
9406
|
+
}
|
|
8976
9407
|
lines.push(
|
|
8977
9408
|
`${indentStr2}${this.quoteKey(key)}: ${JSON.stringify(value)}${isLast ? "" : ","}`
|
|
8978
9409
|
);
|
|
8979
9410
|
continue;
|
|
8980
9411
|
}
|
|
8981
9412
|
lines.push(`${indentStr2}${this.quoteKey(key)}: {`);
|
|
8982
|
-
this.
|
|
9413
|
+
this.addNestedProperties(lines, value, tokenMap, indent + 1);
|
|
8983
9414
|
lines.push(`${indentStr2}}${isLast ? "" : ","}`);
|
|
8984
9415
|
}
|
|
8985
9416
|
}
|
|
8986
|
-
/**
|
|
8987
|
-
* Quote key if necessary
|
|
8988
|
-
*/
|
|
8989
9417
|
quoteKey(key) {
|
|
8990
9418
|
if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key)) {
|
|
8991
9419
|
return key;
|
|
@@ -9221,6 +9649,7 @@ function resolveOptions(options) {
|
|
|
9221
9649
|
|
|
9222
9650
|
// src/renderers/tailwind.ts
|
|
9223
9651
|
init_utils();
|
|
9652
|
+
init_metadata();
|
|
9224
9653
|
var TAILWIND_NAMESPACE_MAP = {
|
|
9225
9654
|
color: "color",
|
|
9226
9655
|
dimension: "spacing",
|
|
@@ -9274,6 +9703,14 @@ var TailwindRenderer = class {
|
|
|
9274
9703
|
for (const [, token] of getSortedTokenEntries(tokens)) {
|
|
9275
9704
|
const varName = this.buildVariableName(token);
|
|
9276
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
|
+
}
|
|
9277
9714
|
lines.push(`${indent}--${varName}:${space}${varValue};${newline}`);
|
|
9278
9715
|
}
|
|
9279
9716
|
lines.push(`}${newline}`);
|
|
@@ -9300,6 +9737,14 @@ var TailwindRenderer = class {
|
|
|
9300
9737
|
for (const [, token] of getSortedTokenEntries(tokens)) {
|
|
9301
9738
|
const varName = this.buildVariableName(token);
|
|
9302
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
|
+
}
|
|
9303
9748
|
lines.push(`${tokenIndent}--${varName}:${space}${varValue};${newline}`);
|
|
9304
9749
|
}
|
|
9305
9750
|
if (hasMediaQuery) {
|
|
@@ -9460,7 +9905,7 @@ function css(config) {
|
|
|
9460
9905
|
file,
|
|
9461
9906
|
renderer: cssRenderer(),
|
|
9462
9907
|
options: { preset, ...rendererOptions },
|
|
9463
|
-
transforms,
|
|
9908
|
+
transforms: [nameKebabCase(), ...transforms ?? []],
|
|
9464
9909
|
filters,
|
|
9465
9910
|
hooks
|
|
9466
9911
|
};
|
|
@@ -9572,12 +10017,19 @@ init_errors();
|
|
|
9572
10017
|
* This source code is licensed under the MIT license found in the
|
|
9573
10018
|
* LICENSE file in the root directory of this source tree.
|
|
9574
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
|
+
*/
|
|
9575
10027
|
/**
|
|
9576
10028
|
* @license
|
|
9577
10029
|
* Copyright (c) 2025 Dispersa Contributors
|
|
9578
10030
|
* SPDX-License-Identifier: MIT
|
|
9579
10031
|
*/
|
|
9580
10032
|
|
|
9581
|
-
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 };
|
|
9582
10034
|
//# sourceMappingURL=index.js.map
|
|
9583
10035
|
//# sourceMappingURL=index.js.map
|