@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.
Files changed (196) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/LICENSE +21 -0
  3. package/README.md +72 -0
  4. package/cli/Cli.d.ts +10 -0
  5. package/cli/Cli.d.ts.map +1 -0
  6. package/cli/Cli.js +32 -0
  7. package/cli/Cli.js.map +1 -0
  8. package/cli/CliArgs.d.ts +2 -0
  9. package/cli/CliArgs.d.ts.map +1 -0
  10. package/cli/CliArgs.js +88 -0
  11. package/cli/CliArgs.js.map +1 -0
  12. package/cli/CliArgsConfig.d.ts +2 -0
  13. package/cli/CliArgsConfig.d.ts.map +1 -0
  14. package/cli/CliArgsConfig.js +12 -0
  15. package/cli/CliArgsConfig.js.map +1 -0
  16. package/cli/CliRun.d.ts +2 -0
  17. package/cli/CliRun.d.ts.map +1 -0
  18. package/cli/CliRun.js +34 -0
  19. package/cli/CliRun.js.map +1 -0
  20. package/cli/commands/LintCommand.d.ts +2 -0
  21. package/cli/commands/LintCommand.d.ts.map +1 -0
  22. package/cli/commands/LintCommand.js +66 -0
  23. package/cli/commands/LintCommand.js.map +1 -0
  24. package/cli/commands/LintCommandArgsConfig.d.ts +2 -0
  25. package/cli/commands/LintCommandArgsConfig.d.ts.map +1 -0
  26. package/cli/commands/LintCommandArgsConfig.js +46 -0
  27. package/cli/commands/LintCommandArgsConfig.js.map +1 -0
  28. package/cli/lint.d.ts +3 -0
  29. package/cli/lint.d.ts.map +1 -0
  30. package/cli/lint.js +55 -0
  31. package/cli/lint.js.map +1 -0
  32. package/config/TokenLinterConfigDiscovery.d.ts +16 -0
  33. package/config/TokenLinterConfigDiscovery.d.ts.map +1 -0
  34. package/config/TokenLinterConfigDiscovery.js +44 -0
  35. package/config/TokenLinterConfigDiscovery.js.map +1 -0
  36. package/config/defineConfig.d.ts +41 -0
  37. package/config/defineConfig.d.ts.map +1 -0
  38. package/config/defineConfig.js +37 -0
  39. package/config/defineConfig.js.map +1 -0
  40. package/core/interaction.d.ts +25 -0
  41. package/core/interaction.d.ts.map +1 -0
  42. package/core/interaction.js +45 -0
  43. package/core/interaction.js.map +1 -0
  44. package/core/loader.d.ts +21 -0
  45. package/core/loader.d.ts.map +1 -0
  46. package/core/loader.js +84 -0
  47. package/core/loader.js.map +1 -0
  48. package/core/rule-registry.d.ts +46 -0
  49. package/core/rule-registry.d.ts.map +1 -0
  50. package/core/rule-registry.js +73 -0
  51. package/core/rule-registry.js.map +1 -0
  52. package/core/rule.d.ts +46 -0
  53. package/core/rule.d.ts.map +1 -0
  54. package/core/rule.js +3 -0
  55. package/core/rule.js.map +1 -0
  56. package/core/runner.d.ts +23 -0
  57. package/core/runner.d.ts.map +1 -0
  58. package/core/runner.js +103 -0
  59. package/core/runner.js.map +1 -0
  60. package/index.d.ts +46 -0
  61. package/index.d.ts.map +1 -0
  62. package/index.js +47 -0
  63. package/index.js.map +1 -0
  64. package/models/lint-result.d.ts +14 -0
  65. package/models/lint-result.d.ts.map +1 -0
  66. package/models/lint-result.js +3 -0
  67. package/models/lint-result.js.map +1 -0
  68. package/models/rule-context.d.ts +18 -0
  69. package/models/rule-context.d.ts.map +1 -0
  70. package/models/rule-context.js +3 -0
  71. package/models/rule-context.js.map +1 -0
  72. package/models/rule-finding.d.ts +15 -0
  73. package/models/rule-finding.d.ts.map +1 -0
  74. package/models/rule-finding.js +3 -0
  75. package/models/rule-finding.js.map +1 -0
  76. package/models/rule-result.d.ts +11 -0
  77. package/models/rule-result.d.ts.map +1 -0
  78. package/models/rule-result.js +3 -0
  79. package/models/rule-result.js.map +1 -0
  80. package/models/rule-severity.d.ts +14 -0
  81. package/models/rule-severity.d.ts.map +1 -0
  82. package/models/rule-severity.js +10 -0
  83. package/models/rule-severity.js.map +1 -0
  84. package/models/token-entry.d.ts +11 -0
  85. package/models/token-entry.d.ts.map +1 -0
  86. package/models/token-entry.js +2 -0
  87. package/models/token-entry.js.map +1 -0
  88. package/models/token-linter-config.d.ts +30 -0
  89. package/models/token-linter-config.d.ts.map +1 -0
  90. package/models/token-linter-config.js +3 -0
  91. package/models/token-linter-config.js.map +1 -0
  92. package/orchestration/TokenLinterOrchestrator.d.ts +29 -0
  93. package/orchestration/TokenLinterOrchestrator.d.ts.map +1 -0
  94. package/orchestration/TokenLinterOrchestrator.js +98 -0
  95. package/orchestration/TokenLinterOrchestrator.js.map +1 -0
  96. package/package.json +20 -0
  97. package/presets/index.d.ts +2 -0
  98. package/presets/index.d.ts.map +1 -0
  99. package/presets/index.js +2 -0
  100. package/presets/index.js.map +1 -0
  101. package/presets/recommended.d.ts +23 -0
  102. package/presets/recommended.d.ts.map +1 -0
  103. package/presets/recommended.js +41 -0
  104. package/presets/recommended.js.map +1 -0
  105. package/reporters/console.reporter.d.ts +15 -0
  106. package/reporters/console.reporter.d.ts.map +1 -0
  107. package/reporters/console.reporter.js +75 -0
  108. package/reporters/console.reporter.js.map +1 -0
  109. package/reporters/json.reporter.d.ts +11 -0
  110. package/reporters/json.reporter.d.ts.map +1 -0
  111. package/reporters/json.reporter.js +37 -0
  112. package/reporters/json.reporter.js.map +1 -0
  113. package/reporters/reporter.d.ts +16 -0
  114. package/reporters/reporter.d.ts.map +1 -0
  115. package/reporters/reporter.js +3 -0
  116. package/reporters/reporter.js.map +1 -0
  117. package/reporters/summary.reporter.d.ts +12 -0
  118. package/reporters/summary.reporter.d.ts.map +1 -0
  119. package/reporters/summary.reporter.js +48 -0
  120. package/reporters/summary.reporter.js.map +1 -0
  121. package/rules/alphabetical-sort.rule.d.ts +19 -0
  122. package/rules/alphabetical-sort.rule.d.ts.map +1 -0
  123. package/rules/alphabetical-sort.rule.js +72 -0
  124. package/rules/alphabetical-sort.rule.js.map +1 -0
  125. package/rules/component-presence.rule.d.ts +29 -0
  126. package/rules/component-presence.rule.d.ts.map +1 -0
  127. package/rules/component-presence.rule.js +102 -0
  128. package/rules/component-presence.rule.js.map +1 -0
  129. package/rules/duplicate-value.rule.d.ts +17 -0
  130. package/rules/duplicate-value.rule.d.ts.map +1 -0
  131. package/rules/duplicate-value.rule.js +49 -0
  132. package/rules/duplicate-value.rule.js.map +1 -0
  133. package/rules/empty-json.rule.d.ts +52 -0
  134. package/rules/empty-json.rule.d.ts.map +1 -0
  135. package/rules/empty-json.rule.js +100 -0
  136. package/rules/empty-json.rule.js.map +1 -0
  137. package/rules/forbidden-key.rule.d.ts +57 -0
  138. package/rules/forbidden-key.rule.d.ts.map +1 -0
  139. package/rules/forbidden-key.rule.js +118 -0
  140. package/rules/forbidden-key.rule.js.map +1 -0
  141. package/rules/forbidden-value.rule.d.ts +53 -0
  142. package/rules/forbidden-value.rule.d.ts.map +1 -0
  143. package/rules/forbidden-value.rule.js +130 -0
  144. package/rules/forbidden-value.rule.js.map +1 -0
  145. package/rules/includes-consistency.rule.d.ts +30 -0
  146. package/rules/includes-consistency.rule.d.ts.map +1 -0
  147. package/rules/includes-consistency.rule.js +153 -0
  148. package/rules/includes-consistency.rule.js.map +1 -0
  149. package/rules/index.d.ts +7 -0
  150. package/rules/index.d.ts.map +1 -0
  151. package/rules/index.js +47 -0
  152. package/rules/index.js.map +1 -0
  153. package/rules/key-consistency.rule.d.ts +38 -0
  154. package/rules/key-consistency.rule.d.ts.map +1 -0
  155. package/rules/key-consistency.rule.js +161 -0
  156. package/rules/key-consistency.rule.js.map +1 -0
  157. package/rules/missing-includes.rule.d.ts +19 -0
  158. package/rules/missing-includes.rule.d.ts.map +1 -0
  159. package/rules/missing-includes.rule.js +51 -0
  160. package/rules/missing-includes.rule.js.map +1 -0
  161. package/rules/mixin-reference.rule.d.ts +28 -0
  162. package/rules/mixin-reference.rule.d.ts.map +1 -0
  163. package/rules/mixin-reference.rule.js +104 -0
  164. package/rules/mixin-reference.rule.js.map +1 -0
  165. package/rules/naming-convention.rule.d.ts +29 -0
  166. package/rules/naming-convention.rule.d.ts.map +1 -0
  167. package/rules/naming-convention.rule.js +112 -0
  168. package/rules/naming-convention.rule.js.map +1 -0
  169. package/rules/nested-depth.rule.d.ts +42 -0
  170. package/rules/nested-depth.rule.d.ts.map +1 -0
  171. package/rules/nested-depth.rule.js +72 -0
  172. package/rules/nested-depth.rule.js.map +1 -0
  173. package/rules/required-includes.rule.d.ts +60 -0
  174. package/rules/required-includes.rule.d.ts.map +1 -0
  175. package/rules/required-includes.rule.js +118 -0
  176. package/rules/required-includes.rule.js.map +1 -0
  177. package/rules/rule-options.d.ts +158 -0
  178. package/rules/rule-options.d.ts.map +1 -0
  179. package/rules/rule-options.js +89 -0
  180. package/rules/rule-options.js.map +1 -0
  181. package/rules/value-consistency.rule.d.ts +17 -0
  182. package/rules/value-consistency.rule.d.ts.map +1 -0
  183. package/rules/value-consistency.rule.js +69 -0
  184. package/rules/value-consistency.rule.js.map +1 -0
  185. package/rules/value-schema.rule.d.ts +18 -0
  186. package/rules/value-schema.rule.d.ts.map +1 -0
  187. package/rules/value-schema.rule.js +108 -0
  188. package/rules/value-schema.rule.js.map +1 -0
  189. package/rules/value-type.rule.d.ts +71 -0
  190. package/rules/value-type.rule.d.ts.map +1 -0
  191. package/rules/value-type.rule.js +176 -0
  192. package/rules/value-type.rule.js.map +1 -0
  193. package/utils.d.ts +55 -0
  194. package/utils.d.ts.map +1 -0
  195. package/utils.js +125 -0
  196. package/utils.js.map +1 -0
@@ -0,0 +1,100 @@
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 } from '../utils.js';
6
+ // #endregion
7
+ // #region Functions
8
+ /**
9
+ * @description Creates typed rule options for the `empty-json` rule.
10
+ * @public
11
+ *
12
+ * @example
13
+ * ```js
14
+ * ruleOptions: {
15
+ * ...emptyJsonRuleOptions({ allowIncludes: true }),
16
+ * }
17
+ * ```
18
+ */
19
+ export function emptyJsonRuleOptions(options) {
20
+ return { 'empty-json': options };
21
+ }
22
+ // #endregion
23
+ /**
24
+ * @description Detects component token files with no token definitions.
25
+ *
26
+ * @example Interactive prompt
27
+ * ```
28
+ * ? Component 'divider' in theme 'joy' has no token definitions.
29
+ * > Delete file
30
+ * Skip
31
+ * Skip all remaining
32
+ * ```
33
+ *
34
+ * @public
35
+ */
36
+ export class EmptyJsonRule {
37
+ // #region Fields
38
+ name = 'empty-json';
39
+ description = 'Detects component token files with no token definitions.';
40
+ defaultSeverity = RuleSeverity.Warning;
41
+ fixable = false;
42
+ interactive = true;
43
+ // #endregion
44
+ // #region Methods
45
+ run(context) {
46
+ const findings = [];
47
+ const options = context.config.ruleOptions[this.name];
48
+ const allowIncludes = options?.allowIncludes ?? false;
49
+ for (const entry of context.entries) {
50
+ const tokenKeys = getTokenKeys(entry.content);
51
+ if (tokenKeys.length === 0) {
52
+ if (allowIncludes && Array.isArray(entry.content['$includes']) && entry.content['$includes'].length > 0) {
53
+ continue;
54
+ }
55
+ findings.push({
56
+ component: entry.component,
57
+ theme: entry.theme,
58
+ message: `Component '${entry.component}' in theme '${entry.theme}' has no token definitions.`,
59
+ severity: this.defaultSeverity,
60
+ filePath: entry.filePath,
61
+ fixed: false,
62
+ });
63
+ }
64
+ }
65
+ return { ruleName: this.name, findings, duration: 0 };
66
+ }
67
+ async interact(_context, findings) {
68
+ const result = [];
69
+ let skipAll = false;
70
+ for (const finding of findings) {
71
+ if (skipAll) {
72
+ result.push(finding);
73
+ continue;
74
+ }
75
+ if (!finding.filePath) {
76
+ result.push(finding);
77
+ continue;
78
+ }
79
+ const action = await promptSelect(finding.message, ['Delete file']);
80
+ if (action === SKIP_ALL) {
81
+ skipAll = true;
82
+ result.push(finding);
83
+ continue;
84
+ }
85
+ if (action === SKIP) {
86
+ result.push(finding);
87
+ continue;
88
+ }
89
+ if (fs.existsSync(finding.filePath)) {
90
+ fs.unlinkSync(finding.filePath);
91
+ result.push({ ...finding, fixed: true });
92
+ }
93
+ else {
94
+ result.push(finding);
95
+ }
96
+ }
97
+ return result;
98
+ }
99
+ }
100
+ //# sourceMappingURL=empty-json.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty-json.rule.js","sourceRoot":"","sources":["../../src/rules/empty-json.rule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
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
+ import type { IRuleOptionsEntry, IRuleOptionValues } from '../models/token-linter-config.js';
7
+ /**
8
+ * @description Options for the `forbidden-key` rule.
9
+ * @public
10
+ */
11
+ export interface IForbiddenKeyRuleOptions extends IRuleOptionValues {
12
+ /**
13
+ * @description Keys that are forbidden in component token files. Overrides the built-in default list.
14
+ * @default ['transition', 'shadow']
15
+ */
16
+ readonly keys?: ReadonlyArray<string>;
17
+ /**
18
+ * @description If set, only these themes are checked for forbidden keys.
19
+ * @default undefined (all themes)
20
+ */
21
+ readonly themes?: ReadonlyArray<string>;
22
+ }
23
+ /**
24
+ * @description Creates typed rule options for the `forbidden-key` rule.
25
+ * @public
26
+ *
27
+ * @example
28
+ * ```js
29
+ * ruleOptions: {
30
+ * ...forbiddenKeyRuleOptions({ keys: ['transition', 'shadow'], themes: ['joy'] }),
31
+ * }
32
+ * ```
33
+ */
34
+ export declare function forbiddenKeyRuleOptions(options: IForbiddenKeyRuleOptions): IRuleOptionsEntry;
35
+ /**
36
+ * @description Detects forbidden keys in component token files.
37
+ *
38
+ * @example Interactive prompt
39
+ * ```
40
+ * ? Forbidden key 'transition' found in 'button' (joy).
41
+ * > Remove key 'transition'
42
+ * Skip
43
+ * Skip all remaining
44
+ * ```
45
+ *
46
+ * @public
47
+ */
48
+ export declare class ForbiddenKeyRule implements IRule {
49
+ readonly name = "forbidden-key";
50
+ readonly description = "Detects forbidden keys in component token files.";
51
+ readonly defaultSeverity: RuleSeverity;
52
+ readonly fixable = false;
53
+ readonly interactive = true;
54
+ run(context: IRuleContext): IRuleResult;
55
+ interact(context: IRuleContext, findings: ReadonlyArray<IRuleFinding>): Promise<IRuleFinding[]>;
56
+ }
57
+ //# sourceMappingURL=forbidden-key.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forbidden-key.rule.d.ts","sourceRoot":"","sources":["../../src/rules/forbidden-key.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;AAE1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAa7F;;;GAGG;AACH,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IAE/D;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAEtC;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC3C;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,wBAAwB,GAAG,iBAAiB,CAE5F;AAID;;;;;;;;;;;;GAYG;AACH,qBAAa,gBAAiB,YAAW,KAAK;IAI1C,SAAgB,IAAI,mBAAmB;IACvC,SAAgB,WAAW,sDAAsD;IACjF,SAAgB,eAAe,EAAE,YAAY,CAAwB;IACrE,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;CA6D/G"}
@@ -0,0 +1,118 @@
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 } from '../utils.js';
6
+ // #endregion
7
+ // #region Constants
8
+ const DEFAULT_FORBIDDEN_KEYS = ['transition', 'shadow'];
9
+ // #endregion
10
+ // #region Functions
11
+ /**
12
+ * @description Creates typed rule options for the `forbidden-key` rule.
13
+ * @public
14
+ *
15
+ * @example
16
+ * ```js
17
+ * ruleOptions: {
18
+ * ...forbiddenKeyRuleOptions({ keys: ['transition', 'shadow'], themes: ['joy'] }),
19
+ * }
20
+ * ```
21
+ */
22
+ export function forbiddenKeyRuleOptions(options) {
23
+ return { 'forbidden-key': options };
24
+ }
25
+ // #endregion
26
+ /**
27
+ * @description Detects forbidden keys in component token files.
28
+ *
29
+ * @example Interactive prompt
30
+ * ```
31
+ * ? Forbidden key 'transition' found in 'button' (joy).
32
+ * > Remove key 'transition'
33
+ * Skip
34
+ * Skip all remaining
35
+ * ```
36
+ *
37
+ * @public
38
+ */
39
+ export class ForbiddenKeyRule {
40
+ // #region Fields
41
+ name = 'forbidden-key';
42
+ description = 'Detects forbidden keys in component token files.';
43
+ defaultSeverity = RuleSeverity.Warning;
44
+ fixable = false;
45
+ interactive = true;
46
+ // #endregion
47
+ // #region Methods
48
+ run(context) {
49
+ const findings = [];
50
+ const options = context.config.ruleOptions[this.name];
51
+ const forbiddenKeys = options?.keys ?? DEFAULT_FORBIDDEN_KEYS;
52
+ const restrictedThemes = options?.themes;
53
+ for (const entry of context.entries) {
54
+ if (restrictedThemes && !restrictedThemes.includes(entry.theme)) {
55
+ continue;
56
+ }
57
+ const keys = getTokenKeys(entry.content);
58
+ for (const key of keys) {
59
+ if (forbiddenKeys.includes(key)) {
60
+ findings.push({
61
+ component: entry.component,
62
+ theme: entry.theme,
63
+ key,
64
+ message: `Forbidden key '${key}' found in '${entry.component}' (${entry.theme}).`,
65
+ severity: this.defaultSeverity,
66
+ filePath: entry.filePath,
67
+ fixed: false,
68
+ });
69
+ }
70
+ }
71
+ }
72
+ return { ruleName: this.name, findings, duration: 0 };
73
+ }
74
+ async interact(context, findings) {
75
+ const entryMap = new Map(context.entries.map((e) => [`${e.theme}:${e.component}`, e]));
76
+ const pendingWrites = new Map();
77
+ const result = [];
78
+ let skipAll = false;
79
+ for (const finding of findings) {
80
+ if (skipAll) {
81
+ result.push(finding);
82
+ continue;
83
+ }
84
+ if (!finding.key || !finding.filePath) {
85
+ result.push(finding);
86
+ continue;
87
+ }
88
+ const entry = entryMap.get(`${finding.theme}:${finding.component}`);
89
+ if (!entry) {
90
+ result.push(finding);
91
+ continue;
92
+ }
93
+ const action = await promptSelect(finding.message, [`Remove key '${finding.key}'`]);
94
+ if (action === SKIP_ALL) {
95
+ skipAll = true;
96
+ result.push(finding);
97
+ continue;
98
+ }
99
+ if (action === SKIP) {
100
+ result.push(finding);
101
+ continue;
102
+ }
103
+ if (Object.prototype.hasOwnProperty.call(entry.content, finding.key)) {
104
+ delete entry.content[finding.key];
105
+ pendingWrites.set(entry.filePath, entry);
106
+ result.push({ ...finding, fixed: true });
107
+ }
108
+ else {
109
+ result.push(finding);
110
+ }
111
+ }
112
+ for (const entry of pendingWrites.values()) {
113
+ fs.writeFileSync(entry.filePath, JSON.stringify(entry.content, null, 2) + '\n', 'utf-8');
114
+ }
115
+ return result;
116
+ }
117
+ }
118
+ //# sourceMappingURL=forbidden-key.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forbidden-key.rule.js","sourceRoot":"","sources":["../../src/rules/forbidden-key.rule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
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
+ import type { IRuleOptionsEntry, IRuleOptionValues } from '../models/token-linter-config.js';
7
+ /**
8
+ * @description Options for the `forbidden-value` rule.
9
+ * @public
10
+ */
11
+ export interface IForbiddenValueRuleOptions extends IRuleOptionValues {
12
+ /**
13
+ * @description Values that are forbidden in token definitions. Overrides the built-in default list.
14
+ * @default ['unset', '0px', 'all']
15
+ */
16
+ readonly values?: ReadonlyArray<string>;
17
+ }
18
+ /**
19
+ * @description Creates typed rule options for the `forbidden-value` rule.
20
+ * @public
21
+ *
22
+ * @example
23
+ * ```js
24
+ * ruleOptions: {
25
+ * ...forbiddenValueRuleOptions({ values: ['unset', '0px', 'none'] }),
26
+ * }
27
+ * ```
28
+ */
29
+ export declare function forbiddenValueRuleOptions(options: IForbiddenValueRuleOptions): IRuleOptionsEntry;
30
+ /**
31
+ * @description Detects forbidden token values such as unset, 0px, all.
32
+ *
33
+ * @example Interactive prompt
34
+ * ```
35
+ * ? Forbidden value 'unset' found for key 'borderColor' in 'button' (joy).
36
+ * > Remove key 'borderColor'
37
+ * Skip
38
+ * Skip all remaining
39
+ * ```
40
+ *
41
+ * @public
42
+ */
43
+ export declare class ForbiddenValueRule implements IRule {
44
+ readonly name = "forbidden-value";
45
+ readonly description = "Detects forbidden token values like unset, 0px, all.";
46
+ readonly defaultSeverity: RuleSeverity;
47
+ readonly fixable = false;
48
+ readonly interactive = true;
49
+ run(context: IRuleContext): IRuleResult;
50
+ interact(context: IRuleContext, findings: ReadonlyArray<IRuleFinding>): Promise<IRuleFinding[]>;
51
+ private _deleteNestedKey;
52
+ }
53
+ //# sourceMappingURL=forbidden-value.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forbidden-value.rule.d.ts","sourceRoot":"","sources":["../../src/rules/forbidden-value.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;AAE1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAa7F;;;GAGG;AACH,MAAM,WAAW,0BAA2B,SAAQ,iBAAiB;IAEjE;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC3C;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,0BAA0B,GAAG,iBAAiB,CAEhG;AAID;;;;;;;;;;;;GAYG;AACH,qBAAa,kBAAmB,YAAW,KAAK;IAI5C,SAAgB,IAAI,qBAAqB;IACzC,SAAgB,WAAW,0DAA0D;IACrF,SAAgB,eAAe,EAAE,YAAY,CAAwB;IACrE,SAAgB,OAAO,SAAS;IAChC,SAAgB,WAAW,QAAQ;IAM5B,GAAG,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW;IA0BjC,QAAQ,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IA2D5G,OAAO,CAAC,gBAAgB;CA0B3B"}
@@ -0,0 +1,130 @@
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 { flattenTokenEntries } from '../utils.js';
6
+ // #endregion
7
+ // #region Constants
8
+ const DEFAULT_FORBIDDEN_VALUES = ['unset', '0px', 'all'];
9
+ // #endregion
10
+ // #region Functions
11
+ /**
12
+ * @description Creates typed rule options for the `forbidden-value` rule.
13
+ * @public
14
+ *
15
+ * @example
16
+ * ```js
17
+ * ruleOptions: {
18
+ * ...forbiddenValueRuleOptions({ values: ['unset', '0px', 'none'] }),
19
+ * }
20
+ * ```
21
+ */
22
+ export function forbiddenValueRuleOptions(options) {
23
+ return { 'forbidden-value': options };
24
+ }
25
+ // #endregion
26
+ /**
27
+ * @description Detects forbidden token values such as unset, 0px, all.
28
+ *
29
+ * @example Interactive prompt
30
+ * ```
31
+ * ? Forbidden value 'unset' found for key 'borderColor' in 'button' (joy).
32
+ * > Remove key 'borderColor'
33
+ * Skip
34
+ * Skip all remaining
35
+ * ```
36
+ *
37
+ * @public
38
+ */
39
+ export class ForbiddenValueRule {
40
+ // #region Fields
41
+ name = 'forbidden-value';
42
+ description = 'Detects forbidden token values like unset, 0px, all.';
43
+ defaultSeverity = RuleSeverity.Warning;
44
+ fixable = false;
45
+ interactive = true;
46
+ // #endregion
47
+ // #region Methods
48
+ run(context) {
49
+ const findings = [];
50
+ const options = context.config.ruleOptions[this.name];
51
+ const forbiddenValues = options?.values ?? DEFAULT_FORBIDDEN_VALUES;
52
+ for (const entry of context.entries) {
53
+ const flatEntries = flattenTokenEntries(entry.content);
54
+ for (const { key, value } of flatEntries) {
55
+ if (typeof value === 'string' && forbiddenValues.includes(value.trim())) {
56
+ findings.push({
57
+ component: entry.component,
58
+ theme: entry.theme,
59
+ key,
60
+ message: `Forbidden value '${value}' found for key '${key}' in '${entry.component}' (${entry.theme}).`,
61
+ severity: this.defaultSeverity,
62
+ filePath: entry.filePath,
63
+ fixed: false,
64
+ });
65
+ }
66
+ }
67
+ }
68
+ return { ruleName: this.name, findings, duration: 0 };
69
+ }
70
+ async interact(context, findings) {
71
+ const entryMap = new Map(context.entries.map((e) => [`${e.theme}:${e.component}`, e]));
72
+ const pendingWrites = new Map();
73
+ const result = [];
74
+ let skipAll = false;
75
+ for (const finding of findings) {
76
+ if (skipAll) {
77
+ result.push(finding);
78
+ continue;
79
+ }
80
+ if (!finding.key || !finding.filePath) {
81
+ result.push(finding);
82
+ continue;
83
+ }
84
+ const entry = entryMap.get(`${finding.theme}:${finding.component}`);
85
+ if (!entry) {
86
+ result.push(finding);
87
+ continue;
88
+ }
89
+ const action = await promptSelect(finding.message, [`Remove key '${finding.key}'`]);
90
+ if (action === SKIP_ALL) {
91
+ skipAll = true;
92
+ result.push(finding);
93
+ continue;
94
+ }
95
+ if (action === SKIP) {
96
+ result.push(finding);
97
+ continue;
98
+ }
99
+ if (this._deleteNestedKey(entry.content, finding.key)) {
100
+ pendingWrites.set(entry.filePath, entry);
101
+ result.push({ ...finding, fixed: true });
102
+ }
103
+ else {
104
+ result.push(finding);
105
+ }
106
+ }
107
+ for (const entry of pendingWrites.values()) {
108
+ fs.writeFileSync(entry.filePath, JSON.stringify(entry.content, null, 2) + '\n', 'utf-8');
109
+ }
110
+ return result;
111
+ }
112
+ _deleteNestedKey(obj, dotPath) {
113
+ const parts = dotPath.split('.');
114
+ let current = obj;
115
+ for (let i = 0; i < parts.length - 1; i++) {
116
+ const next = current[parts[i]];
117
+ if (typeof next !== 'object' || next === null) {
118
+ return false;
119
+ }
120
+ current = next;
121
+ }
122
+ const lastKey = parts[parts.length - 1];
123
+ if (Object.prototype.hasOwnProperty.call(current, lastKey)) {
124
+ delete current[lastKey];
125
+ return true;
126
+ }
127
+ return false;
128
+ }
129
+ }
130
+ //# sourceMappingURL=forbidden-value.rule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forbidden-value.rule.js","sourceRoot":"","sources":["../../src/rules/forbidden-value.rule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
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 $includes arrays are consistent across themes for the same component.
8
+ *
9
+ * @example Interactive prompt
10
+ * ```
11
+ * ? $includes differs from 'memphis' for 'button': missing: [ripple]; extra: [shadow].
12
+ * > Use memphis's includes: [focusRing, ripple]
13
+ * Use cosmopolitan's includes: [focusRing, ripple]
14
+ * Union all: [focusRing, ripple, shadow]
15
+ * Skip
16
+ * Skip all remaining
17
+ * ```
18
+ *
19
+ * @public
20
+ */
21
+ export declare class IncludesConsistencyRule implements IRule {
22
+ readonly name = "includes-consistency";
23
+ readonly description = "Ensures $includes arrays are consistent across themes for the same component.";
24
+ readonly defaultSeverity: RuleSeverity;
25
+ readonly fixable = false;
26
+ readonly interactive = true;
27
+ run(context: IRuleContext): IRuleResult;
28
+ interact(context: IRuleContext, findings: ReadonlyArray<IRuleFinding>): Promise<IRuleFinding[]>;
29
+ }
30
+ //# sourceMappingURL=includes-consistency.rule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"includes-consistency.rule.d.ts","sourceRoot":"","sources":["../../src/rules/includes-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;;;;;;;;;;;;;;GAcG;AACH,qBAAa,uBAAwB,YAAW,KAAK;IAIjD,SAAgB,IAAI,0BAA0B;IAC9C,SAAgB,WAAW,mFAAmF;IAC9G,SAAgB,eAAe,EAAE,YAAY,CAAwB;IACrE,SAAgB,OAAO,SAAS;IAChC,SAAgB,WAAW,QAAQ;IAM5B,GAAG,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW;IA4DjC,QAAQ,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;CAuG/G"}