@breadstone-infrastructure/token-linter 0.0.231
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/CHANGELOG.md +10 -0
- package/LICENSE +21 -0
- package/README.md +72 -0
- package/cli/Cli.d.ts +10 -0
- package/cli/Cli.d.ts.map +1 -0
- package/cli/Cli.js +32 -0
- package/cli/Cli.js.map +1 -0
- package/cli/CliArgs.d.ts +2 -0
- package/cli/CliArgs.d.ts.map +1 -0
- package/cli/CliArgs.js +88 -0
- package/cli/CliArgs.js.map +1 -0
- package/cli/CliArgsConfig.d.ts +2 -0
- package/cli/CliArgsConfig.d.ts.map +1 -0
- package/cli/CliArgsConfig.js +12 -0
- package/cli/CliArgsConfig.js.map +1 -0
- package/cli/CliRun.d.ts +2 -0
- package/cli/CliRun.d.ts.map +1 -0
- package/cli/CliRun.js +34 -0
- package/cli/CliRun.js.map +1 -0
- package/cli/commands/LintCommand.d.ts +2 -0
- package/cli/commands/LintCommand.d.ts.map +1 -0
- package/cli/commands/LintCommand.js +66 -0
- package/cli/commands/LintCommand.js.map +1 -0
- package/cli/commands/LintCommandArgsConfig.d.ts +2 -0
- package/cli/commands/LintCommandArgsConfig.d.ts.map +1 -0
- package/cli/commands/LintCommandArgsConfig.js +46 -0
- package/cli/commands/LintCommandArgsConfig.js.map +1 -0
- package/cli/lint.d.ts +3 -0
- package/cli/lint.d.ts.map +1 -0
- package/cli/lint.js +55 -0
- package/cli/lint.js.map +1 -0
- package/config/TokenLinterConfigDiscovery.d.ts +16 -0
- package/config/TokenLinterConfigDiscovery.d.ts.map +1 -0
- package/config/TokenLinterConfigDiscovery.js +44 -0
- package/config/TokenLinterConfigDiscovery.js.map +1 -0
- package/config/defineConfig.d.ts +41 -0
- package/config/defineConfig.d.ts.map +1 -0
- package/config/defineConfig.js +37 -0
- package/config/defineConfig.js.map +1 -0
- package/core/interaction.d.ts +25 -0
- package/core/interaction.d.ts.map +1 -0
- package/core/interaction.js +45 -0
- package/core/interaction.js.map +1 -0
- package/core/loader.d.ts +21 -0
- package/core/loader.d.ts.map +1 -0
- package/core/loader.js +84 -0
- package/core/loader.js.map +1 -0
- package/core/rule-registry.d.ts +46 -0
- package/core/rule-registry.d.ts.map +1 -0
- package/core/rule-registry.js +73 -0
- package/core/rule-registry.js.map +1 -0
- package/core/rule.d.ts +46 -0
- package/core/rule.d.ts.map +1 -0
- package/core/rule.js +3 -0
- package/core/rule.js.map +1 -0
- package/core/runner.d.ts +23 -0
- package/core/runner.d.ts.map +1 -0
- package/core/runner.js +103 -0
- package/core/runner.js.map +1 -0
- package/index.d.ts +46 -0
- package/index.d.ts.map +1 -0
- package/index.js +47 -0
- package/index.js.map +1 -0
- package/models/lint-result.d.ts +14 -0
- package/models/lint-result.d.ts.map +1 -0
- package/models/lint-result.js +3 -0
- package/models/lint-result.js.map +1 -0
- package/models/rule-context.d.ts +18 -0
- package/models/rule-context.d.ts.map +1 -0
- package/models/rule-context.js +3 -0
- package/models/rule-context.js.map +1 -0
- package/models/rule-finding.d.ts +15 -0
- package/models/rule-finding.d.ts.map +1 -0
- package/models/rule-finding.js +3 -0
- package/models/rule-finding.js.map +1 -0
- package/models/rule-result.d.ts +11 -0
- package/models/rule-result.d.ts.map +1 -0
- package/models/rule-result.js +3 -0
- package/models/rule-result.js.map +1 -0
- package/models/rule-severity.d.ts +14 -0
- package/models/rule-severity.d.ts.map +1 -0
- package/models/rule-severity.js +10 -0
- package/models/rule-severity.js.map +1 -0
- package/models/token-entry.d.ts +11 -0
- package/models/token-entry.d.ts.map +1 -0
- package/models/token-entry.js +2 -0
- package/models/token-entry.js.map +1 -0
- package/models/token-linter-config.d.ts +30 -0
- package/models/token-linter-config.d.ts.map +1 -0
- package/models/token-linter-config.js +3 -0
- package/models/token-linter-config.js.map +1 -0
- package/orchestration/TokenLinterOrchestrator.d.ts +29 -0
- package/orchestration/TokenLinterOrchestrator.d.ts.map +1 -0
- package/orchestration/TokenLinterOrchestrator.js +98 -0
- package/orchestration/TokenLinterOrchestrator.js.map +1 -0
- package/package.json +20 -0
- package/presets/index.d.ts +2 -0
- package/presets/index.d.ts.map +1 -0
- package/presets/index.js +2 -0
- package/presets/index.js.map +1 -0
- package/presets/recommended.d.ts +23 -0
- package/presets/recommended.d.ts.map +1 -0
- package/presets/recommended.js +41 -0
- package/presets/recommended.js.map +1 -0
- package/reporters/console.reporter.d.ts +15 -0
- package/reporters/console.reporter.d.ts.map +1 -0
- package/reporters/console.reporter.js +75 -0
- package/reporters/console.reporter.js.map +1 -0
- package/reporters/json.reporter.d.ts +11 -0
- package/reporters/json.reporter.d.ts.map +1 -0
- package/reporters/json.reporter.js +37 -0
- package/reporters/json.reporter.js.map +1 -0
- package/reporters/reporter.d.ts +16 -0
- package/reporters/reporter.d.ts.map +1 -0
- package/reporters/reporter.js +3 -0
- package/reporters/reporter.js.map +1 -0
- package/reporters/summary.reporter.d.ts +12 -0
- package/reporters/summary.reporter.d.ts.map +1 -0
- package/reporters/summary.reporter.js +48 -0
- package/reporters/summary.reporter.js.map +1 -0
- package/rules/alphabetical-sort.rule.d.ts +19 -0
- package/rules/alphabetical-sort.rule.d.ts.map +1 -0
- package/rules/alphabetical-sort.rule.js +72 -0
- package/rules/alphabetical-sort.rule.js.map +1 -0
- package/rules/component-presence.rule.d.ts +29 -0
- package/rules/component-presence.rule.d.ts.map +1 -0
- package/rules/component-presence.rule.js +102 -0
- package/rules/component-presence.rule.js.map +1 -0
- package/rules/duplicate-value.rule.d.ts +17 -0
- package/rules/duplicate-value.rule.d.ts.map +1 -0
- package/rules/duplicate-value.rule.js +49 -0
- package/rules/duplicate-value.rule.js.map +1 -0
- package/rules/empty-json.rule.d.ts +52 -0
- package/rules/empty-json.rule.d.ts.map +1 -0
- package/rules/empty-json.rule.js +100 -0
- package/rules/empty-json.rule.js.map +1 -0
- package/rules/forbidden-key.rule.d.ts +57 -0
- package/rules/forbidden-key.rule.d.ts.map +1 -0
- package/rules/forbidden-key.rule.js +118 -0
- package/rules/forbidden-key.rule.js.map +1 -0
- package/rules/forbidden-value.rule.d.ts +53 -0
- package/rules/forbidden-value.rule.d.ts.map +1 -0
- package/rules/forbidden-value.rule.js +130 -0
- package/rules/forbidden-value.rule.js.map +1 -0
- package/rules/includes-consistency.rule.d.ts +30 -0
- package/rules/includes-consistency.rule.d.ts.map +1 -0
- package/rules/includes-consistency.rule.js +153 -0
- package/rules/includes-consistency.rule.js.map +1 -0
- package/rules/index.d.ts +7 -0
- package/rules/index.d.ts.map +1 -0
- package/rules/index.js +47 -0
- package/rules/index.js.map +1 -0
- package/rules/key-consistency.rule.d.ts +38 -0
- package/rules/key-consistency.rule.d.ts.map +1 -0
- package/rules/key-consistency.rule.js +161 -0
- package/rules/key-consistency.rule.js.map +1 -0
- package/rules/missing-includes.rule.d.ts +19 -0
- package/rules/missing-includes.rule.d.ts.map +1 -0
- package/rules/missing-includes.rule.js +51 -0
- package/rules/missing-includes.rule.js.map +1 -0
- package/rules/mixin-reference.rule.d.ts +28 -0
- package/rules/mixin-reference.rule.d.ts.map +1 -0
- package/rules/mixin-reference.rule.js +104 -0
- package/rules/mixin-reference.rule.js.map +1 -0
- package/rules/naming-convention.rule.d.ts +29 -0
- package/rules/naming-convention.rule.d.ts.map +1 -0
- package/rules/naming-convention.rule.js +112 -0
- package/rules/naming-convention.rule.js.map +1 -0
- package/rules/nested-depth.rule.d.ts +42 -0
- package/rules/nested-depth.rule.d.ts.map +1 -0
- package/rules/nested-depth.rule.js +72 -0
- package/rules/nested-depth.rule.js.map +1 -0
- package/rules/required-includes.rule.d.ts +60 -0
- package/rules/required-includes.rule.d.ts.map +1 -0
- package/rules/required-includes.rule.js +118 -0
- package/rules/required-includes.rule.js.map +1 -0
- package/rules/rule-options.d.ts +158 -0
- package/rules/rule-options.d.ts.map +1 -0
- package/rules/rule-options.js +89 -0
- package/rules/rule-options.js.map +1 -0
- package/rules/value-consistency.rule.d.ts +17 -0
- package/rules/value-consistency.rule.d.ts.map +1 -0
- package/rules/value-consistency.rule.js +69 -0
- package/rules/value-consistency.rule.js.map +1 -0
- package/rules/value-schema.rule.d.ts +18 -0
- package/rules/value-schema.rule.d.ts.map +1 -0
- package/rules/value-schema.rule.js +108 -0
- package/rules/value-schema.rule.js.map +1 -0
- package/rules/value-type.rule.d.ts +71 -0
- package/rules/value-type.rule.d.ts.map +1 -0
- package/rules/value-type.rule.js +176 -0
- package/rules/value-type.rule.js.map +1 -0
- package/utils.d.ts +55 -0
- package/utils.d.ts.map +1 -0
- package/utils.js +125 -0
- package/utils.js.map +1 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// #region Imports
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import { promptSelect, SKIP, SKIP_ALL } from '../core/interaction.js';
|
|
4
|
+
import { RuleSeverity } from '../models/rule-severity.js';
|
|
5
|
+
import { groupByComponent } from '../utils.js';
|
|
6
|
+
// #endregion
|
|
7
|
+
/**
|
|
8
|
+
* @description Ensures $includes arrays are consistent across themes for the same component.
|
|
9
|
+
*
|
|
10
|
+
* @example Interactive prompt
|
|
11
|
+
* ```
|
|
12
|
+
* ? $includes differs from 'memphis' for 'button': missing: [ripple]; extra: [shadow].
|
|
13
|
+
* > Use memphis's includes: [focusRing, ripple]
|
|
14
|
+
* Use cosmopolitan's includes: [focusRing, ripple]
|
|
15
|
+
* Union all: [focusRing, ripple, shadow]
|
|
16
|
+
* Skip
|
|
17
|
+
* Skip all remaining
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @public
|
|
21
|
+
*/
|
|
22
|
+
export class IncludesConsistencyRule {
|
|
23
|
+
// #region Fields
|
|
24
|
+
name = 'includes-consistency';
|
|
25
|
+
description = 'Ensures $includes arrays are consistent across themes for the same component.';
|
|
26
|
+
defaultSeverity = RuleSeverity.Warning;
|
|
27
|
+
fixable = false;
|
|
28
|
+
interactive = true;
|
|
29
|
+
// #endregion
|
|
30
|
+
// #region Methods
|
|
31
|
+
run(context) {
|
|
32
|
+
const findings = [];
|
|
33
|
+
const grouped = groupByComponent(context.entries);
|
|
34
|
+
for (const [component, entries] of grouped.entries()) {
|
|
35
|
+
const includesMap = new Map();
|
|
36
|
+
for (const entry of entries) {
|
|
37
|
+
const includes = entry.content['$includes'];
|
|
38
|
+
const normalized = Array.isArray(includes) ? includes : [];
|
|
39
|
+
includesMap.set(entry.theme, normalized);
|
|
40
|
+
}
|
|
41
|
+
const signatures = new Set(Array.from(includesMap.values()).map(arr => [...arr].sort().join(',')));
|
|
42
|
+
if (signatures.size <= 1) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const referenceEntry = entries[0];
|
|
46
|
+
const referenceIncludes = includesMap.get(referenceEntry.theme) ?? [];
|
|
47
|
+
const referenceSet = new Set(referenceIncludes);
|
|
48
|
+
for (const entry of entries.slice(1)) {
|
|
49
|
+
const entryIncludes = includesMap.get(entry.theme) ?? [];
|
|
50
|
+
const entrySet = new Set(entryIncludes);
|
|
51
|
+
const missingInEntry = referenceIncludes.filter(i => !entrySet.has(i));
|
|
52
|
+
const extraInEntry = entryIncludes.filter(i => !referenceSet.has(i));
|
|
53
|
+
if (missingInEntry.length > 0 || extraInEntry.length > 0) {
|
|
54
|
+
const parts = [];
|
|
55
|
+
if (missingInEntry.length > 0) {
|
|
56
|
+
parts.push(`missing: [${missingInEntry.join(', ')}]`);
|
|
57
|
+
}
|
|
58
|
+
if (extraInEntry.length > 0) {
|
|
59
|
+
parts.push(`extra: [${extraInEntry.join(', ')}]`);
|
|
60
|
+
}
|
|
61
|
+
findings.push({
|
|
62
|
+
component,
|
|
63
|
+
theme: entry.theme,
|
|
64
|
+
key: '$includes',
|
|
65
|
+
message: `$includes differs from '${referenceEntry.theme}' for '${component}': ${parts.join('; ')}.`,
|
|
66
|
+
severity: this.defaultSeverity,
|
|
67
|
+
filePath: entry.filePath,
|
|
68
|
+
fixed: false,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { ruleName: this.name, findings, duration: 0 };
|
|
74
|
+
}
|
|
75
|
+
async interact(context, findings) {
|
|
76
|
+
const grouped = groupByComponent(context.entries);
|
|
77
|
+
const pendingWrites = new Map();
|
|
78
|
+
const result = [];
|
|
79
|
+
let skipAll = false;
|
|
80
|
+
for (const finding of findings) {
|
|
81
|
+
if (skipAll) {
|
|
82
|
+
result.push(finding);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const entries = grouped.get(finding.component);
|
|
86
|
+
if (!entries || !finding.filePath) {
|
|
87
|
+
result.push(finding);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const targetEntry = entries.find(e => e.theme === finding.theme);
|
|
91
|
+
if (!targetEntry) {
|
|
92
|
+
result.push(finding);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
const otherEntries = entries.filter(e => e.theme !== finding.theme);
|
|
96
|
+
const choices = [];
|
|
97
|
+
for (const other of otherEntries) {
|
|
98
|
+
const includes = Array.isArray(other.content['$includes']) ? other.content['$includes'] : [];
|
|
99
|
+
choices.push({
|
|
100
|
+
name: `use-${other.theme}`,
|
|
101
|
+
message: `Use ${other.theme}'s includes: [${includes.join(', ')}]`,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
const allIncludes = new Set();
|
|
105
|
+
for (const entry of entries) {
|
|
106
|
+
const includes = Array.isArray(entry.content['$includes']) ? entry.content['$includes'] : [];
|
|
107
|
+
for (const inc of includes) {
|
|
108
|
+
allIncludes.add(inc);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
choices.push({
|
|
112
|
+
name: 'union',
|
|
113
|
+
message: `Union all: [${[...allIncludes].sort().join(', ')}]`,
|
|
114
|
+
});
|
|
115
|
+
const action = await promptSelect(finding.message, choices);
|
|
116
|
+
if (action === SKIP_ALL) {
|
|
117
|
+
skipAll = true;
|
|
118
|
+
result.push(finding);
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (action === SKIP) {
|
|
122
|
+
result.push(finding);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
let newIncludes;
|
|
126
|
+
if (action === 'union') {
|
|
127
|
+
newIncludes = [...allIncludes].sort();
|
|
128
|
+
}
|
|
129
|
+
else if (action.startsWith('use-')) {
|
|
130
|
+
const sourceTheme = action.substring(4);
|
|
131
|
+
const sourceEntry = entries.find(e => e.theme === sourceTheme);
|
|
132
|
+
if (sourceEntry) {
|
|
133
|
+
newIncludes = Array.isArray(sourceEntry.content['$includes'])
|
|
134
|
+
? [...sourceEntry.content['$includes']]
|
|
135
|
+
: [];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (newIncludes !== undefined) {
|
|
139
|
+
targetEntry.content['$includes'] = newIncludes;
|
|
140
|
+
pendingWrites.set(targetEntry.filePath, targetEntry);
|
|
141
|
+
result.push({ ...finding, fixed: true });
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
result.push(finding);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
for (const entry of pendingWrites.values()) {
|
|
148
|
+
fs.writeFileSync(entry.filePath, JSON.stringify(entry.content, null, 2) + '\n', 'utf-8');
|
|
149
|
+
}
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=includes-consistency.rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"includes-consistency.rule.js","sourceRoot":"","sources":["../../src/rules/includes-consistency.rule.ts"],"names":[],"mappings":"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"}
|
package/rules/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAoB7C;;;GAGG;AACH,wBAAgB,YAAY,IAAI,KAAK,EAAE,CA0BtC"}
|
package/rules/index.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// #region Imports
|
|
2
|
+
import { AlphabeticalSortRule } from './alphabetical-sort.rule.js';
|
|
3
|
+
import { ComponentPresenceRule } from './component-presence.rule.js';
|
|
4
|
+
import { DuplicateValueRule } from './duplicate-value.rule.js';
|
|
5
|
+
import { EmptyJsonRule } from './empty-json.rule.js';
|
|
6
|
+
import { ForbiddenKeyRule } from './forbidden-key.rule.js';
|
|
7
|
+
import { ForbiddenValueRule } from './forbidden-value.rule.js';
|
|
8
|
+
import { IncludesConsistencyRule } from './includes-consistency.rule.js';
|
|
9
|
+
import { KeyConsistencyRule } from './key-consistency.rule.js';
|
|
10
|
+
import { MissingIncludesRule } from './missing-includes.rule.js';
|
|
11
|
+
import { MixinReferenceRule } from './mixin-reference.rule.js';
|
|
12
|
+
import { NamingConventionRule } from './naming-convention.rule.js';
|
|
13
|
+
import { NestedDepthRule } from './nested-depth.rule.js';
|
|
14
|
+
import { RequiredIncludesRule } from './required-includes.rule.js';
|
|
15
|
+
import { ValueConsistencyRule } from './value-consistency.rule.js';
|
|
16
|
+
import { ValueSchemaRule } from './value-schema.rule.js';
|
|
17
|
+
import { ValueTypeRule } from './value-type.rule.js';
|
|
18
|
+
// #endregion
|
|
19
|
+
/**
|
|
20
|
+
* @description Creates and returns all built-in token linter rules.
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
export function builtInRules() {
|
|
24
|
+
return [
|
|
25
|
+
// Core structural rules
|
|
26
|
+
new ComponentPresenceRule(),
|
|
27
|
+
new KeyConsistencyRule(),
|
|
28
|
+
new IncludesConsistencyRule(),
|
|
29
|
+
new MissingIncludesRule(),
|
|
30
|
+
new RequiredIncludesRule(),
|
|
31
|
+
new EmptyJsonRule(),
|
|
32
|
+
// Quality rules
|
|
33
|
+
new ForbiddenValueRule(),
|
|
34
|
+
new ForbiddenKeyRule(),
|
|
35
|
+
new NamingConventionRule(),
|
|
36
|
+
new ValueSchemaRule(),
|
|
37
|
+
new ValueTypeRule(),
|
|
38
|
+
new ValueConsistencyRule(),
|
|
39
|
+
new DuplicateValueRule(),
|
|
40
|
+
// Structural depth
|
|
41
|
+
new NestedDepthRule(),
|
|
42
|
+
new MixinReferenceRule(),
|
|
43
|
+
// Formatting
|
|
44
|
+
new AlphabeticalSortRule(),
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAAA,kBAAkB;AAGlB,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,aAAa;AAEb;;;GAGG;AACH,MAAM,UAAU,YAAY;IACxB,OAAO;QACH,wBAAwB;QACxB,IAAI,qBAAqB,EAAE;QAC3B,IAAI,kBAAkB,EAAE;QACxB,IAAI,uBAAuB,EAAE;QAC7B,IAAI,mBAAmB,EAAE;QACzB,IAAI,oBAAoB,EAAE;QAC1B,IAAI,aAAa,EAAE;QAEnB,gBAAgB;QAChB,IAAI,kBAAkB,EAAE;QACxB,IAAI,gBAAgB,EAAE;QACtB,IAAI,oBAAoB,EAAE;QAC1B,IAAI,eAAe,EAAE;QACrB,IAAI,aAAa,EAAE;QACnB,IAAI,oBAAoB,EAAE;QAC1B,IAAI,kBAAkB,EAAE;QAExB,mBAAmB;QACnB,IAAI,eAAe,EAAE;QACrB,IAAI,kBAAkB,EAAE;QAExB,aAAa;QACb,IAAI,oBAAoB,EAAE;KAC7B,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { IRule } from '../core/rule.js';
|
|
2
|
+
import type { IRuleContext } from '../models/rule-context.js';
|
|
3
|
+
import type { IRuleFinding } from '../models/rule-finding.js';
|
|
4
|
+
import type { IRuleResult } from '../models/rule-result.js';
|
|
5
|
+
import { RuleSeverity } from '../models/rule-severity.js';
|
|
6
|
+
/**
|
|
7
|
+
* @description Ensures all themes use the same set of keys for each component.
|
|
8
|
+
* Keys that are provided by `$includes` mixins are excluded from the consistency check.
|
|
9
|
+
* When auto-fix is enabled, missing keys are copied from the first theme that defines them,
|
|
10
|
+
* with theme-specific CSS variable prefixes automatically replaced.
|
|
11
|
+
*
|
|
12
|
+
* @example Interactive prompt
|
|
13
|
+
* ```
|
|
14
|
+
* ? Key 'borderRadius' is missing in component 'button' for theme 'joy'.
|
|
15
|
+
* > Copy from 'memphis'
|
|
16
|
+
* Copy from 'cosmopolitan'
|
|
17
|
+
* Skip
|
|
18
|
+
* Skip all remaining
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
export declare class KeyConsistencyRule implements IRule {
|
|
24
|
+
readonly name = "key-consistency";
|
|
25
|
+
readonly description = "Ensures all themes use the same keys for each component.";
|
|
26
|
+
readonly defaultSeverity: RuleSeverity;
|
|
27
|
+
readonly fixable = true;
|
|
28
|
+
readonly interactive = true;
|
|
29
|
+
run(context: IRuleContext): IRuleResult;
|
|
30
|
+
fix(context: IRuleContext, findings: ReadonlyArray<IRuleFinding>): IRuleFinding[];
|
|
31
|
+
interact(context: IRuleContext, findings: ReadonlyArray<IRuleFinding>): Promise<IRuleFinding[]>;
|
|
32
|
+
/**
|
|
33
|
+
* @description Deep-clones a value and replaces occurrences of the source theme prefix with the target theme prefix
|
|
34
|
+
* in all CSS variable references (e.g. `--memphis-` → `--joy-`).
|
|
35
|
+
*/
|
|
36
|
+
private _replaceThemePrefix;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=key-consistency.rule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-consistency.rule.d.ts","sourceRoot":"","sources":["../../src/rules/key-consistency.rule.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAM1D;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,kBAAmB,YAAW,KAAK;IAI5C,SAAgB,IAAI,qBAAqB;IACzC,SAAgB,WAAW,8DAA8D;IACzF,SAAgB,eAAe,EAAE,YAAY,CAAsB;IACnE,SAAgB,OAAO,QAAQ;IAC/B,SAAgB,WAAW,QAAQ;IAM5B,GAAG,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW;IAiDvC,GAAG,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,YAAY,EAAE;IAqC3E,QAAQ,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAyE5G;;;OAGG;IACH,OAAO,CAAC,mBAAmB;CAK9B"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// #region Imports
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import { promptSelect, SKIP, SKIP_ALL } from '../core/interaction.js';
|
|
4
|
+
import { RuleSeverity } from '../models/rule-severity.js';
|
|
5
|
+
import { getTokenKeys, groupByComponent, replaceThemePrefix, resolveMixinKeys } from '../utils.js';
|
|
6
|
+
// #endregion
|
|
7
|
+
/**
|
|
8
|
+
* @description Ensures all themes use the same set of keys for each component.
|
|
9
|
+
* Keys that are provided by `$includes` mixins are excluded from the consistency check.
|
|
10
|
+
* When auto-fix is enabled, missing keys are copied from the first theme that defines them,
|
|
11
|
+
* with theme-specific CSS variable prefixes automatically replaced.
|
|
12
|
+
*
|
|
13
|
+
* @example Interactive prompt
|
|
14
|
+
* ```
|
|
15
|
+
* ? Key 'borderRadius' is missing in component 'button' for theme 'joy'.
|
|
16
|
+
* > Copy from 'memphis'
|
|
17
|
+
* Copy from 'cosmopolitan'
|
|
18
|
+
* Skip
|
|
19
|
+
* Skip all remaining
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
export class KeyConsistencyRule {
|
|
25
|
+
// #region Fields
|
|
26
|
+
name = 'key-consistency';
|
|
27
|
+
description = 'Ensures all themes use the same keys for each component.';
|
|
28
|
+
defaultSeverity = RuleSeverity.Error;
|
|
29
|
+
fixable = true;
|
|
30
|
+
interactive = true;
|
|
31
|
+
// #endregion
|
|
32
|
+
// #region Methods
|
|
33
|
+
run(context) {
|
|
34
|
+
const findings = [];
|
|
35
|
+
const grouped = groupByComponent(context.entries);
|
|
36
|
+
for (const [component, entries] of grouped.entries()) {
|
|
37
|
+
const themeEntryMap = new Map(entries.map(e => [e.theme, e]));
|
|
38
|
+
const allKeys = new Set();
|
|
39
|
+
for (const entry of entries) {
|
|
40
|
+
for (const key of getTokenKeys(entry.content)) {
|
|
41
|
+
allKeys.add(key);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
for (const key of allKeys) {
|
|
45
|
+
for (const theme of context.themes) {
|
|
46
|
+
const entry = themeEntryMap.get(theme);
|
|
47
|
+
if (!entry || Object.prototype.hasOwnProperty.call(entry.content, key)) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
// Check if the key is provided by one of the entry's $includes mixins
|
|
51
|
+
const includes = entry.content['$includes'];
|
|
52
|
+
if (Array.isArray(includes)) {
|
|
53
|
+
const mixinProvidedKeys = resolveMixinKeys(includes, context.mixinKeys);
|
|
54
|
+
if (mixinProvidedKeys.has(key)) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
findings.push({
|
|
59
|
+
component,
|
|
60
|
+
theme,
|
|
61
|
+
key,
|
|
62
|
+
message: `Key '${key}' is missing in component '${component}' for theme '${theme}'.`,
|
|
63
|
+
severity: this.defaultSeverity,
|
|
64
|
+
filePath: entry.filePath,
|
|
65
|
+
fixed: false,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { ruleName: this.name, findings, duration: 0 };
|
|
71
|
+
}
|
|
72
|
+
fix(context, findings) {
|
|
73
|
+
const grouped = groupByComponent(context.entries);
|
|
74
|
+
const pendingWrites = new Map();
|
|
75
|
+
const result = [];
|
|
76
|
+
for (const finding of findings) {
|
|
77
|
+
const entries = grouped.get(finding.component);
|
|
78
|
+
if (!entries || !finding.key || !finding.filePath) {
|
|
79
|
+
result.push(finding);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const targetEntry = entries.find(e => e.theme === finding.theme);
|
|
83
|
+
const sourceEntry = entries.find(e => e.theme !== finding.theme && Object.prototype.hasOwnProperty.call(e.content, finding.key));
|
|
84
|
+
if (targetEntry && sourceEntry) {
|
|
85
|
+
const sourceValue = sourceEntry.content[finding.key];
|
|
86
|
+
targetEntry.content[finding.key] = replaceThemePrefix(sourceValue, sourceEntry.theme, finding.theme);
|
|
87
|
+
pendingWrites.set(targetEntry.filePath, targetEntry);
|
|
88
|
+
result.push({ ...finding, fixed: true });
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
result.push(finding);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
for (const entry of pendingWrites.values()) {
|
|
95
|
+
fs.writeFileSync(entry.filePath, JSON.stringify(entry.content, null, 2) + '\n', 'utf-8');
|
|
96
|
+
}
|
|
97
|
+
return result;
|
|
98
|
+
}
|
|
99
|
+
async interact(context, findings) {
|
|
100
|
+
const grouped = groupByComponent(context.entries);
|
|
101
|
+
const pendingWrites = new Map();
|
|
102
|
+
const result = [];
|
|
103
|
+
let skipAll = false;
|
|
104
|
+
for (const finding of findings) {
|
|
105
|
+
if (skipAll) {
|
|
106
|
+
result.push(finding);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const entries = grouped.get(finding.component);
|
|
110
|
+
if (!entries || !finding.key || !finding.filePath) {
|
|
111
|
+
result.push(finding);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
const targetEntry = entries.find(e => e.theme === finding.theme);
|
|
115
|
+
const sourceThemes = entries
|
|
116
|
+
.filter(e => e.theme !== finding.theme && Object.prototype.hasOwnProperty.call(e.content, finding.key))
|
|
117
|
+
.map(e => e.theme);
|
|
118
|
+
if (!targetEntry || sourceThemes.length === 0) {
|
|
119
|
+
result.push(finding);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const choices = sourceThemes.map(theme => ({
|
|
123
|
+
name: `copy-${theme}`,
|
|
124
|
+
message: `Copy from '${theme}'`,
|
|
125
|
+
}));
|
|
126
|
+
const action = await promptSelect(finding.message, choices);
|
|
127
|
+
if (action === SKIP_ALL) {
|
|
128
|
+
skipAll = true;
|
|
129
|
+
result.push(finding);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (action === SKIP) {
|
|
133
|
+
result.push(finding);
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const sourceTheme = action.startsWith('copy-') ? action.substring(5) : undefined;
|
|
137
|
+
const sourceEntry = sourceTheme ? entries.find(e => e.theme === sourceTheme) : undefined;
|
|
138
|
+
if (sourceEntry && Object.prototype.hasOwnProperty.call(sourceEntry.content, finding.key)) {
|
|
139
|
+
const sourceValue = sourceEntry.content[finding.key];
|
|
140
|
+
targetEntry.content[finding.key] = replaceThemePrefix(sourceValue, sourceEntry.theme, finding.theme);
|
|
141
|
+
pendingWrites.set(targetEntry.filePath, targetEntry);
|
|
142
|
+
result.push({ ...finding, fixed: true });
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
result.push(finding);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
for (const entry of pendingWrites.values()) {
|
|
149
|
+
fs.writeFileSync(entry.filePath, JSON.stringify(entry.content, null, 2) + '\n', 'utf-8');
|
|
150
|
+
}
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* @description Deep-clones a value and replaces occurrences of the source theme prefix with the target theme prefix
|
|
155
|
+
* in all CSS variable references (e.g. `--memphis-` → `--joy-`).
|
|
156
|
+
*/
|
|
157
|
+
_replaceThemePrefix(value, sourceTheme, targetTheme) {
|
|
158
|
+
return replaceThemePrefix(value, sourceTheme, targetTheme);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=key-consistency.rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-consistency.rule.js","sourceRoot":"","sources":["../../src/rules/key-consistency.rule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { IRule } from '../core/rule.js';
|
|
2
|
+
import type { IRuleContext } from '../models/rule-context.js';
|
|
3
|
+
import type { IRuleFinding } from '../models/rule-finding.js';
|
|
4
|
+
import type { IRuleResult } from '../models/rule-result.js';
|
|
5
|
+
import { RuleSeverity } from '../models/rule-severity.js';
|
|
6
|
+
/**
|
|
7
|
+
* @description Ensures all component token files have a `$includes` field. Auto-fixable.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export declare class MissingIncludesRule implements IRule {
|
|
11
|
+
readonly name = "missing-includes";
|
|
12
|
+
readonly description = "Ensures all component token files have a $includes field. Auto-fixable.";
|
|
13
|
+
readonly defaultSeverity: RuleSeverity;
|
|
14
|
+
readonly fixable = true;
|
|
15
|
+
readonly interactive = false;
|
|
16
|
+
run(context: IRuleContext): IRuleResult;
|
|
17
|
+
fix(context: IRuleContext, findings: ReadonlyArray<IRuleFinding>): IRuleFinding[];
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=missing-includes.rule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"missing-includes.rule.d.ts","sourceRoot":"","sources":["../../src/rules/missing-includes.rule.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAI1D;;;GAGG;AACH,qBAAa,mBAAoB,YAAW,KAAK;IAI7C,SAAgB,IAAI,sBAAsB;IAC1C,SAAgB,WAAW,6EAA6E;IACxG,SAAgB,eAAe,EAAE,YAAY,CAAwB;IACrE,SAAgB,OAAO,QAAQ;IAC/B,SAAgB,WAAW,SAAS;IAM7B,GAAG,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW;IAqBvC,GAAG,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,YAAY,EAAE;CAuB3F"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// #region Imports
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import { RuleSeverity } from '../models/rule-severity.js';
|
|
4
|
+
// #endregion
|
|
5
|
+
/**
|
|
6
|
+
* @description Ensures all component token files have a `$includes` field. Auto-fixable.
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
export class MissingIncludesRule {
|
|
10
|
+
// #region Fields
|
|
11
|
+
name = 'missing-includes';
|
|
12
|
+
description = 'Ensures all component token files have a $includes field. Auto-fixable.';
|
|
13
|
+
defaultSeverity = RuleSeverity.Warning;
|
|
14
|
+
fixable = true;
|
|
15
|
+
interactive = false;
|
|
16
|
+
// #endregion
|
|
17
|
+
// #region Methods
|
|
18
|
+
run(context) {
|
|
19
|
+
const findings = [];
|
|
20
|
+
for (const entry of context.entries) {
|
|
21
|
+
if (Array.isArray(entry.content['$includes'])) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
findings.push({
|
|
25
|
+
component: entry.component,
|
|
26
|
+
theme: entry.theme,
|
|
27
|
+
message: `Component '${entry.component}' in theme '${entry.theme}' is missing '$includes'.`,
|
|
28
|
+
severity: this.defaultSeverity,
|
|
29
|
+
filePath: entry.filePath,
|
|
30
|
+
fixed: false,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return { ruleName: this.name, findings, duration: 0 };
|
|
34
|
+
}
|
|
35
|
+
fix(context, findings) {
|
|
36
|
+
const entryMap = new Map(context.entries.map(e => [e.filePath, e]));
|
|
37
|
+
const result = [];
|
|
38
|
+
for (const finding of findings) {
|
|
39
|
+
const entry = finding.filePath ? entryMap.get(finding.filePath) : undefined;
|
|
40
|
+
if (!entry) {
|
|
41
|
+
result.push(finding);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const updated = { '$includes': [], ...entry.content };
|
|
45
|
+
fs.writeFileSync(entry.filePath, JSON.stringify(updated, null, 2) + '\n', 'utf-8');
|
|
46
|
+
result.push({ ...finding, fixed: true });
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=missing-includes.rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"missing-includes.rule.js","sourceRoot":"","sources":["../../src/rules/missing-includes.rule.ts"],"names":[],"mappings":"AAAA,kBAAkB;AAElB,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAKzB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,aAAa;AAEb;;;GAGG;AACH,MAAM,OAAO,mBAAmB;IAE5B,iBAAiB;IAED,IAAI,GAAG,kBAAkB,CAAC;IAC1B,WAAW,GAAG,yEAAyE,CAAC;IACxF,eAAe,GAAiB,YAAY,CAAC,OAAO,CAAC;IACrD,OAAO,GAAG,IAAI,CAAC;IACf,WAAW,GAAG,KAAK,CAAC;IAEpC,aAAa;IAEb,kBAAkB;IAEX,GAAG,CAAC,OAAqB;QAC5B,MAAM,QAAQ,GAAmB,EAAE,CAAC;QAEpC,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YAClC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC;gBAC5C,SAAS;YACb,CAAC;YAED,QAAQ,CAAC,IAAI,CAAC;gBACV,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,OAAO,EAAE,cAAc,KAAK,CAAC,SAAS,eAAe,KAAK,CAAC,KAAK,2BAA2B;gBAC3F,QAAQ,EAAE,IAAI,CAAC,eAAe;gBAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,KAAK,EAAE,KAAK;aACf,CAAC,CAAC;QACP,CAAC;QAED,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IAC1D,CAAC;IAEM,GAAG,CAAC,OAAqB,EAAE,QAAqC;QACnE,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,MAAM,MAAM,GAAmB,EAAE,CAAC;QAElC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YAE5E,IAAI,CAAC,KAAK,EAAE,CAAC;gBACT,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAErB,SAAS;YACb,CAAC;YAED,MAAM,OAAO,GAA4B,EAAE,WAAW,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;YAE/E,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;YACnF,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,CAAC;QAED,OAAO,MAAM,CAAC;IAClB,CAAC;CAGJ"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { IRule } from '../core/rule.js';
|
|
2
|
+
import type { IRuleContext } from '../models/rule-context.js';
|
|
3
|
+
import type { IRuleFinding } from '../models/rule-finding.js';
|
|
4
|
+
import type { IRuleResult } from '../models/rule-result.js';
|
|
5
|
+
import { RuleSeverity } from '../models/rule-severity.js';
|
|
6
|
+
/**
|
|
7
|
+
* @description Validates that $includes references point to existing mixin files.
|
|
8
|
+
*
|
|
9
|
+
* @example Interactive prompt
|
|
10
|
+
* ```
|
|
11
|
+
* ? Mixin 'glow' (base: 'glow') referenced in '$includes' does not exist as a mixin file.
|
|
12
|
+
* > Remove 'glow' from $includes
|
|
13
|
+
* Skip
|
|
14
|
+
* Skip all remaining
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
export declare class MixinReferenceRule implements IRule {
|
|
20
|
+
readonly name = "mixin-reference";
|
|
21
|
+
readonly description = "Validates that $includes references point to existing mixin files.";
|
|
22
|
+
readonly defaultSeverity: RuleSeverity;
|
|
23
|
+
readonly fixable = false;
|
|
24
|
+
readonly interactive = true;
|
|
25
|
+
run(context: IRuleContext): IRuleResult;
|
|
26
|
+
interact(context: IRuleContext, findings: ReadonlyArray<IRuleFinding>): Promise<IRuleFinding[]>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=mixin-reference.rule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mixin-reference.rule.d.ts","sourceRoot":"","sources":["../../src/rules/mixin-reference.rule.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAK1D;;;;;;;;;;;;GAYG;AACH,qBAAa,kBAAmB,YAAW,KAAK;IAI5C,SAAgB,IAAI,qBAAqB;IACzC,SAAgB,WAAW,wEAAwE;IACnG,SAAgB,eAAe,EAAE,YAAY,CAAsB;IACnE,SAAgB,OAAO,SAAS;IAChC,SAAgB,WAAW,QAAQ;IAM5B,GAAG,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW;IA+BjC,QAAQ,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;CAwE/G"}
|