@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,41 @@
|
|
|
1
|
+
import type { RuleSeverity } from '../models/rule-severity.js';
|
|
2
|
+
import type { ITokenLinterConfig } from '../models/token-linter-config.js';
|
|
3
|
+
/**
|
|
4
|
+
* @description Input type for defining a token linter configuration via `tokenlinter.config.mjs`.
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export interface ITokenLinterConfigInput {
|
|
8
|
+
readonly tokensDir: string;
|
|
9
|
+
readonly themes: ReadonlyArray<string>;
|
|
10
|
+
readonly mixinsDir?: string;
|
|
11
|
+
readonly fix?: boolean;
|
|
12
|
+
readonly interactive?: boolean;
|
|
13
|
+
readonly verbose?: boolean;
|
|
14
|
+
readonly reporter?: 'console' | 'json' | 'summary';
|
|
15
|
+
readonly rules?: Readonly<Record<string, RuleSeverity | 'off'>>;
|
|
16
|
+
readonly ruleOptions?: Readonly<Record<string, Readonly<Record<string, unknown>>>>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* @description Define a token linter configuration. Place this in a `tokenlinter.config.mjs` file.
|
|
20
|
+
* @public
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```js
|
|
24
|
+
* // tokenlinter.config.mjs
|
|
25
|
+
* import { defineConfig } from '@breadstone-infrastructure/token-linter';
|
|
26
|
+
*
|
|
27
|
+
* export default defineConfig({
|
|
28
|
+
* tokensDir: 'tokens/themes',
|
|
29
|
+
* themes: ['joy', 'memphis', 'cosmopolitan'],
|
|
30
|
+
* mixinsDir: 'tokens/mixins',
|
|
31
|
+
* reporter: 'console',
|
|
32
|
+
* rules: {
|
|
33
|
+
* 'component-presence': 'error',
|
|
34
|
+
* 'key-consistency': 'error',
|
|
35
|
+
* 'alphabetical-sort': 'warning',
|
|
36
|
+
* },
|
|
37
|
+
* });
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function defineConfig(config: ITokenLinterConfigInput): ITokenLinterConfig;
|
|
41
|
+
//# sourceMappingURL=defineConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defineConfig.d.ts","sourceRoot":"","sources":["../../src/config/defineConfig.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAI3E;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;IACnD,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,KAAK,CAAC,CAAC,CAAC;IAChE,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;CACtF;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,uBAAuB,GAAG,kBAAkB,CAYhF"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// #region Imports
|
|
2
|
+
/**
|
|
3
|
+
* @description Define a token linter configuration. Place this in a `tokenlinter.config.mjs` file.
|
|
4
|
+
* @public
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```js
|
|
8
|
+
* // tokenlinter.config.mjs
|
|
9
|
+
* import { defineConfig } from '@breadstone-infrastructure/token-linter';
|
|
10
|
+
*
|
|
11
|
+
* export default defineConfig({
|
|
12
|
+
* tokensDir: 'tokens/themes',
|
|
13
|
+
* themes: ['joy', 'memphis', 'cosmopolitan'],
|
|
14
|
+
* mixinsDir: 'tokens/mixins',
|
|
15
|
+
* reporter: 'console',
|
|
16
|
+
* rules: {
|
|
17
|
+
* 'component-presence': 'error',
|
|
18
|
+
* 'key-consistency': 'error',
|
|
19
|
+
* 'alphabetical-sort': 'warning',
|
|
20
|
+
* },
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export function defineConfig(config) {
|
|
25
|
+
return {
|
|
26
|
+
tokensDir: config.tokensDir,
|
|
27
|
+
mixinsDir: config.mixinsDir ?? 'tokens/mixins',
|
|
28
|
+
themes: config.themes,
|
|
29
|
+
fix: config.fix ?? false,
|
|
30
|
+
interactive: config.interactive ?? false,
|
|
31
|
+
verbose: config.verbose ?? false,
|
|
32
|
+
reporter: config.reporter ?? 'console',
|
|
33
|
+
rules: config.rules ?? {},
|
|
34
|
+
ruleOptions: config.ruleOptions ?? {},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=defineConfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defineConfig.js","sourceRoot":"","sources":["../../src/config/defineConfig.ts"],"names":[],"mappings":"AAAA,kBAAkB;AAuBlB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,YAAY,CAAC,MAA+B;IACxD,OAAO;QACH,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,eAAe;QAC9C,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,KAAK;QACxB,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,KAAK;QACxC,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,KAAK;QAChC,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,SAAS;QACtC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE;QACzB,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,EAAE;KACxC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description Sentinel value indicating the user chose to skip a finding.
|
|
3
|
+
* @public
|
|
4
|
+
*/
|
|
5
|
+
export declare const SKIP: "__skip__";
|
|
6
|
+
/**
|
|
7
|
+
* @description Sentinel value indicating the user chose to skip all remaining findings.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export declare const SKIP_ALL: "__skip_all__";
|
|
11
|
+
/**
|
|
12
|
+
* @description A choice for an interactive select prompt with separate machine-readable name and display message.
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
export interface IPromptChoice {
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly message: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* @description Presents a select prompt to the user with the given choices plus Skip / Skip all remaining.
|
|
21
|
+
* Returns the selected choice name string, or one of the sentinel values (SKIP / SKIP_ALL).
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
export declare function promptSelect(message: string, choices: ReadonlyArray<string | IPromptChoice>): Promise<string>;
|
|
25
|
+
//# sourceMappingURL=interaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interaction.d.ts","sourceRoot":"","sources":["../../src/core/interaction.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,eAAO,MAAM,IAAI,EAAG,UAAmB,CAAC;AAExC;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAG,cAAuB,CAAC;AAMhD;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC5B;AAMD;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,CAAC,MAAM,GAAG,aAAa,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBnH"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// #region Imports
|
|
2
|
+
import enquirer from 'enquirer';
|
|
3
|
+
const { prompt } = enquirer;
|
|
4
|
+
// #endregion
|
|
5
|
+
// #region Constants
|
|
6
|
+
/**
|
|
7
|
+
* @description Sentinel value indicating the user chose to skip a finding.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export const SKIP = '__skip__';
|
|
11
|
+
/**
|
|
12
|
+
* @description Sentinel value indicating the user chose to skip all remaining findings.
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
export const SKIP_ALL = '__skip_all__';
|
|
16
|
+
// #endregion
|
|
17
|
+
// #region Functions
|
|
18
|
+
/**
|
|
19
|
+
* @description Presents a select prompt to the user with the given choices plus Skip / Skip all remaining.
|
|
20
|
+
* Returns the selected choice name string, or one of the sentinel values (SKIP / SKIP_ALL).
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
export async function promptSelect(message, choices) {
|
|
24
|
+
const normalizedChoices = choices.map(choice => {
|
|
25
|
+
if (typeof choice === 'string') {
|
|
26
|
+
return { name: choice, message: choice };
|
|
27
|
+
}
|
|
28
|
+
return choice;
|
|
29
|
+
});
|
|
30
|
+
const allChoices = [
|
|
31
|
+
...normalizedChoices,
|
|
32
|
+
{ name: SKIP, message: 'Skip' },
|
|
33
|
+
{ name: SKIP_ALL, message: 'Skip all remaining' },
|
|
34
|
+
];
|
|
35
|
+
const options = {
|
|
36
|
+
type: 'select',
|
|
37
|
+
name: 'action',
|
|
38
|
+
message,
|
|
39
|
+
choices: allChoices,
|
|
40
|
+
};
|
|
41
|
+
const result = await prompt(options);
|
|
42
|
+
return result.action;
|
|
43
|
+
}
|
|
44
|
+
// #endregion
|
|
45
|
+
//# sourceMappingURL=interaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interaction.js","sourceRoot":"","sources":["../../src/core/interaction.ts"],"names":[],"mappings":"AAAA,kBAAkB;AAElB,OAAO,QAAQ,MAAM,UAAU,CAAC;AAEhC,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC;AAE5B,aAAa;AAEb,oBAAoB;AAEpB;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,UAAmB,CAAC;AAExC;;;GAGG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,cAAuB,CAAC;AAehD,aAAa;AAEb,oBAAoB;AAEpB;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAe,EAAE,OAA8C;IAC9F,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE;QAC3C,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;QAC7C,CAAC;QAED,OAAO,MAAM,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG;QACf,GAAG,iBAAiB;QACpB,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE;QAC/B,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,oBAAoB,EAAE;KACpD,CAAC;IAEF,MAAM,OAAO,GAAY;QACrB,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,QAAQ;QACd,OAAO;QACP,OAAO,EAAE,UAAU;KACtB,CAAC;IAEF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAqB,OAAuC,CAAC,CAAC;IAEzF,OAAO,MAAM,CAAC,MAAM,CAAC;AACzB,CAAC;AAED,aAAa"}
|
package/core/loader.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ILogger } from '@breadstone-infrastructure/utilities';
|
|
2
|
+
import type { ITokenEntry } from '../models/token-entry.js';
|
|
3
|
+
/**
|
|
4
|
+
* @description Loads theme component token JSON files and mixin metadata from disk.
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export declare namespace TokenLoader {
|
|
8
|
+
/**
|
|
9
|
+
* @description Reads all component JSON files for the specified themes.
|
|
10
|
+
*/
|
|
11
|
+
function loadThemeComponents(basePath: string, themes: ReadonlyArray<string>, logger: ILogger): ITokenEntry[];
|
|
12
|
+
/**
|
|
13
|
+
* @description Reads all available mixin names from the mixins directory.
|
|
14
|
+
*/
|
|
15
|
+
function loadMixinNames(mixinsDir: string): string[];
|
|
16
|
+
/**
|
|
17
|
+
* @description Reads all mixin files and returns a map of mixin name to its top-level token keys.
|
|
18
|
+
*/
|
|
19
|
+
function loadMixinContent(mixinsDir: string): Map<string, string[]>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/core/loader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AAGpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAI5D;;;GAGG;AACH,yBAAiB,WAAW,CAAC;IAIzB;;OAEG;IACH,SAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,GAAG,WAAW,EAAE,CAoCnH;IAED;;OAEG;IACH,SAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ1D;IAED;;OAEG;IACH,SAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAyBzE;CAGJ"}
|
package/core/loader.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// #region Imports
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
// #endregion
|
|
5
|
+
/**
|
|
6
|
+
* @description Loads theme component token JSON files and mixin metadata from disk.
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
export var TokenLoader;
|
|
10
|
+
(function (TokenLoader) {
|
|
11
|
+
// #region Functions
|
|
12
|
+
/**
|
|
13
|
+
* @description Reads all component JSON files for the specified themes.
|
|
14
|
+
*/
|
|
15
|
+
function loadThemeComponents(basePath, themes, logger) {
|
|
16
|
+
const entries = [];
|
|
17
|
+
for (const theme of themes) {
|
|
18
|
+
const themeDir = path.join(basePath, theme, 'components');
|
|
19
|
+
if (!fs.existsSync(themeDir)) {
|
|
20
|
+
logger.warn(`Skipping missing theme directory: ${themeDir}`);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
const files = fs.readdirSync(themeDir).filter((f) => f.endsWith('.json'));
|
|
24
|
+
for (const file of files) {
|
|
25
|
+
const filePath = path.join(themeDir, file);
|
|
26
|
+
try {
|
|
27
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
28
|
+
const content = JSON.parse(raw);
|
|
29
|
+
entries.push({
|
|
30
|
+
theme,
|
|
31
|
+
component: path.basename(file, '.json'),
|
|
32
|
+
filePath,
|
|
33
|
+
content,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
logger.error(`Failed to parse JSON in ${filePath}: ${err.message}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
logger.info(`Loaded ${files.length} components from theme: ${theme}`);
|
|
41
|
+
}
|
|
42
|
+
return entries;
|
|
43
|
+
}
|
|
44
|
+
TokenLoader.loadThemeComponents = loadThemeComponents;
|
|
45
|
+
/**
|
|
46
|
+
* @description Reads all available mixin names from the mixins directory.
|
|
47
|
+
*/
|
|
48
|
+
function loadMixinNames(mixinsDir) {
|
|
49
|
+
if (!fs.existsSync(mixinsDir)) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
return fs.readdirSync(mixinsDir)
|
|
53
|
+
.filter((f) => f.endsWith('.json'))
|
|
54
|
+
.map((f) => path.basename(f, '.json'));
|
|
55
|
+
}
|
|
56
|
+
TokenLoader.loadMixinNames = loadMixinNames;
|
|
57
|
+
/**
|
|
58
|
+
* @description Reads all mixin files and returns a map of mixin name to its top-level token keys.
|
|
59
|
+
*/
|
|
60
|
+
function loadMixinContent(mixinsDir) {
|
|
61
|
+
const result = new Map();
|
|
62
|
+
if (!fs.existsSync(mixinsDir)) {
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
const files = fs.readdirSync(mixinsDir).filter((f) => f.endsWith('.json'));
|
|
66
|
+
for (const file of files) {
|
|
67
|
+
const filePath = path.join(mixinsDir, file);
|
|
68
|
+
const mixinName = path.basename(file, '.json');
|
|
69
|
+
try {
|
|
70
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
71
|
+
const content = JSON.parse(raw);
|
|
72
|
+
const keys = Object.keys(content).filter(k => !k.startsWith('$'));
|
|
73
|
+
result.set(mixinName, keys);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Skip malformed mixin files
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
TokenLoader.loadMixinContent = loadMixinContent;
|
|
82
|
+
// #endregion
|
|
83
|
+
})(TokenLoader || (TokenLoader = {}));
|
|
84
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/core/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { IRule } from './rule.js';
|
|
2
|
+
/**
|
|
3
|
+
* @description Registry for managing token linter rules. Supports registration, enable/disable, and lookup.
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
export declare class RuleRegistry {
|
|
7
|
+
private readonly _rules;
|
|
8
|
+
private readonly _disabled;
|
|
9
|
+
/**
|
|
10
|
+
* @description Registers a single rule. Throws if a rule with the same name already exists.
|
|
11
|
+
*/
|
|
12
|
+
register(rule: IRule): void;
|
|
13
|
+
/**
|
|
14
|
+
* @description Registers multiple rules at once.
|
|
15
|
+
*/
|
|
16
|
+
registerAll(rules: ReadonlyArray<IRule>): void;
|
|
17
|
+
/**
|
|
18
|
+
* @description Disables a rule by name. Disabled rules are skipped during execution.
|
|
19
|
+
*/
|
|
20
|
+
disable(ruleName: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* @description Re-enables a previously disabled rule.
|
|
23
|
+
*/
|
|
24
|
+
enable(ruleName: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* @description Returns all registered rules regardless of enabled/disabled state.
|
|
27
|
+
*/
|
|
28
|
+
getAll(): ReadonlyArray<IRule>;
|
|
29
|
+
/**
|
|
30
|
+
* @description Returns only active (non-disabled) rules.
|
|
31
|
+
*/
|
|
32
|
+
getActive(): ReadonlyArray<IRule>;
|
|
33
|
+
/**
|
|
34
|
+
* @description Looks up a rule by name.
|
|
35
|
+
*/
|
|
36
|
+
getByName(name: string): IRule | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* @description Checks whether a rule with the given name is registered.
|
|
39
|
+
*/
|
|
40
|
+
has(name: string): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* @description Checks whether a rule is currently disabled.
|
|
43
|
+
*/
|
|
44
|
+
isDisabled(name: string): boolean;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=rule-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-registry.d.ts","sourceRoot":"","sources":["../../src/core/rule-registry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAIvC;;;GAGG;AACH,qBAAa,YAAY;IAIrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;IACxD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0B;IAMpD;;OAEG;IACI,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI;IAQlC;;OAEG;IACI,WAAW,CAAC,KAAK,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,IAAI;IAMrD;;OAEG;IACI,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAItC;;OAEG;IACI,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIrC;;OAEG;IACI,MAAM,IAAI,aAAa,CAAC,KAAK,CAAC;IAIrC;;OAEG;IACI,SAAS,IAAI,aAAa,CAAC,KAAK,CAAC;IAIxC;;OAEG;IACI,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIjD;;OAEG;IACI,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIjC;;OAEG;IACI,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAK3C"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// #region Imports
|
|
2
|
+
// #endregion
|
|
3
|
+
/**
|
|
4
|
+
* @description Registry for managing token linter rules. Supports registration, enable/disable, and lookup.
|
|
5
|
+
* @public
|
|
6
|
+
*/
|
|
7
|
+
export class RuleRegistry {
|
|
8
|
+
// #region Fields
|
|
9
|
+
_rules = new Map();
|
|
10
|
+
_disabled = new Set();
|
|
11
|
+
// #endregion
|
|
12
|
+
// #region Methods
|
|
13
|
+
/**
|
|
14
|
+
* @description Registers a single rule. Throws if a rule with the same name already exists.
|
|
15
|
+
*/
|
|
16
|
+
register(rule) {
|
|
17
|
+
if (this._rules.has(rule.name)) {
|
|
18
|
+
throw new Error(`Rule '${rule.name}' is already registered.`);
|
|
19
|
+
}
|
|
20
|
+
this._rules.set(rule.name, rule);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* @description Registers multiple rules at once.
|
|
24
|
+
*/
|
|
25
|
+
registerAll(rules) {
|
|
26
|
+
for (const rule of rules) {
|
|
27
|
+
this.register(rule);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* @description Disables a rule by name. Disabled rules are skipped during execution.
|
|
32
|
+
*/
|
|
33
|
+
disable(ruleName) {
|
|
34
|
+
this._disabled.add(ruleName);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* @description Re-enables a previously disabled rule.
|
|
38
|
+
*/
|
|
39
|
+
enable(ruleName) {
|
|
40
|
+
this._disabled.delete(ruleName);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* @description Returns all registered rules regardless of enabled/disabled state.
|
|
44
|
+
*/
|
|
45
|
+
getAll() {
|
|
46
|
+
return Array.from(this._rules.values());
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* @description Returns only active (non-disabled) rules.
|
|
50
|
+
*/
|
|
51
|
+
getActive() {
|
|
52
|
+
return Array.from(this._rules.values()).filter(rule => !this._disabled.has(rule.name));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* @description Looks up a rule by name.
|
|
56
|
+
*/
|
|
57
|
+
getByName(name) {
|
|
58
|
+
return this._rules.get(name);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* @description Checks whether a rule with the given name is registered.
|
|
62
|
+
*/
|
|
63
|
+
has(name) {
|
|
64
|
+
return this._rules.has(name);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* @description Checks whether a rule is currently disabled.
|
|
68
|
+
*/
|
|
69
|
+
isDisabled(name) {
|
|
70
|
+
return this._disabled.has(name);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=rule-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-registry.js","sourceRoot":"","sources":["../../src/core/rule-registry.ts"],"names":[],"mappings":"AAAA,kBAAkB;AAIlB,aAAa;AAEb;;;GAGG;AACH,MAAM,OAAO,YAAY;IAErB,iBAAiB;IAEA,MAAM,GAAuB,IAAI,GAAG,EAAE,CAAC;IACvC,SAAS,GAAgB,IAAI,GAAG,EAAE,CAAC;IAEpD,aAAa;IAEb,kBAAkB;IAElB;;OAEG;IACI,QAAQ,CAAC,IAAW;QACvB,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,KAAK,CAAC,SAAS,IAAI,CAAC,IAAI,0BAA0B,CAAC,CAAC;QAClE,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACI,WAAW,CAAC,KAA2B;QAC1C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;IACL,CAAC;IAED;;OAEG;IACI,OAAO,CAAC,QAAgB;QAC3B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACI,MAAM,CAAC,QAAgB;QAC1B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IAED;;OAEG;IACI,MAAM;QACT,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACI,SAAS;QACZ,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC3F,CAAC;IAED;;OAEG;IACI,SAAS,CAAC,IAAY;QACzB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACI,GAAG,CAAC,IAAY;QACnB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACI,UAAU,CAAC,IAAY;QAC1B,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;CAGJ"}
|
package/core/rule.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { IRuleContext } from '../models/rule-context.js';
|
|
2
|
+
import type { IRuleFinding } from '../models/rule-finding.js';
|
|
3
|
+
import type { IRuleResult } from '../models/rule-result.js';
|
|
4
|
+
import type { RuleSeverity } from '../models/rule-severity.js';
|
|
5
|
+
/**
|
|
6
|
+
* @description Contract for a token linter rule.
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
export interface IRule {
|
|
10
|
+
/**
|
|
11
|
+
* @description Unique identifier of the rule (kebab-case).
|
|
12
|
+
*/
|
|
13
|
+
readonly name: string;
|
|
14
|
+
/**
|
|
15
|
+
* @description Human-readable description of what the rule checks.
|
|
16
|
+
*/
|
|
17
|
+
readonly description: string;
|
|
18
|
+
/**
|
|
19
|
+
* @description Default severity when no override is configured.
|
|
20
|
+
*/
|
|
21
|
+
readonly defaultSeverity: RuleSeverity;
|
|
22
|
+
/**
|
|
23
|
+
* @description Whether the rule supports auto-fixing violations.
|
|
24
|
+
*/
|
|
25
|
+
readonly fixable: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* @description Whether the rule supports interactive resolution via user prompts.
|
|
28
|
+
*/
|
|
29
|
+
readonly interactive: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* @description Detects violations and returns findings. Must be side-effect free.
|
|
32
|
+
*/
|
|
33
|
+
run(context: IRuleContext): IRuleResult;
|
|
34
|
+
/**
|
|
35
|
+
* @description Applies automatic fixes for the given findings. Only called when `fixable` is `true` and `config.fix` is enabled.
|
|
36
|
+
* Returns the updated findings array with `fixed: true` on resolved items.
|
|
37
|
+
*/
|
|
38
|
+
fix?(context: IRuleContext, findings: ReadonlyArray<IRuleFinding>): IRuleFinding[];
|
|
39
|
+
/**
|
|
40
|
+
* @description Interactively resolves findings by prompting the user for decisions.
|
|
41
|
+
* Only called when `interactive` is `true` and `config.interactive` is enabled.
|
|
42
|
+
* Returns the updated findings array with `fixed: true` on resolved items.
|
|
43
|
+
*/
|
|
44
|
+
interact?(context: IRuleContext, findings: ReadonlyArray<IRuleFinding>): Promise<IRuleFinding[]>;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=rule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule.d.ts","sourceRoot":"","sources":["../../src/core/rule.ts"],"names":[],"mappings":"AAEA,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,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAI/D;;;GAGG;AACH,MAAM,WAAW,KAAK;IAElB;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B;;OAEG;IACH,QAAQ,CAAC,eAAe,EAAE,YAAY,CAAC;IAEvC;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAE1B;;OAEG;IACH,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAE9B;;OAEG;IACH,GAAG,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW,CAAC;IAExC;;;OAGG;IACH,GAAG,CAAC,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,YAAY,EAAE,CAAC;IAEnF;;;;OAIG;IACH,QAAQ,CAAC,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;CACpG"}
|
package/core/rule.js
ADDED
package/core/rule.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule.js","sourceRoot":"","sources":["../../src/core/rule.ts"],"names":[],"mappings":"AAAA,kBAAkB"}
|
package/core/runner.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ILogger } from '@breadstone-infrastructure/utilities';
|
|
2
|
+
import type { ILintResult } from '../models/lint-result.js';
|
|
3
|
+
import type { ITokenEntry } from '../models/token-entry.js';
|
|
4
|
+
import type { ITokenLinterConfig } from '../models/token-linter-config.js';
|
|
5
|
+
import type { RuleRegistry } from './rule-registry.js';
|
|
6
|
+
/**
|
|
7
|
+
* @description Orchestrates 3-phase rule execution (detect → fix → interact), severity overrides, and result aggregation.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
export declare namespace LintRunner {
|
|
11
|
+
/**
|
|
12
|
+
* @description Runs only the rules explicitly configured in `config.rules` and returns the aggregated lint result.
|
|
13
|
+
* Rules not listed in the config are not executed (opt-in model).
|
|
14
|
+
*
|
|
15
|
+
* Execution phases per rule:
|
|
16
|
+
* 1. **Detect** — `rule.run()` identifies findings (side-effect free).
|
|
17
|
+
* 2. **Fix** — `rule.fix()` auto-fixes findings (only when `config.fix` is enabled and `rule.fixable` is `true`).
|
|
18
|
+
* 3. **Interact** — `rule.interact()` prompts the user for resolution of remaining findings
|
|
19
|
+
* (only when `config.interactive` is enabled and `rule.interactive` is `true`).
|
|
20
|
+
*/
|
|
21
|
+
function run(registry: RuleRegistry, config: ITokenLinterConfig, entries: ReadonlyArray<ITokenEntry>, mixinNames: ReadonlyArray<string>, mixinKeys: ReadonlyMap<string, ReadonlyArray<string>>, logger: ILogger): Promise<ILintResult>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAK5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIvD;;;GAGG;AACH,yBAAiB,UAAU,CAAC;IAIxB;;;;;;;;;OASG;IACH,SAAsB,GAAG,CACrB,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,aAAa,CAAC,WAAW,CAAC,EACnC,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,EACjC,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,EACrD,MAAM,EAAE,OAAO,GAChB,OAAO,CAAC,WAAW,CAAC,CA2GtB;CAGJ"}
|
package/core/runner.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// #region Imports
|
|
2
|
+
import { RuleSeverity } from '../models/rule-severity.js';
|
|
3
|
+
// #endregion
|
|
4
|
+
/**
|
|
5
|
+
* @description Orchestrates 3-phase rule execution (detect → fix → interact), severity overrides, and result aggregation.
|
|
6
|
+
* @public
|
|
7
|
+
*/
|
|
8
|
+
export var LintRunner;
|
|
9
|
+
(function (LintRunner) {
|
|
10
|
+
// #region Functions
|
|
11
|
+
/**
|
|
12
|
+
* @description Runs only the rules explicitly configured in `config.rules` and returns the aggregated lint result.
|
|
13
|
+
* Rules not listed in the config are not executed (opt-in model).
|
|
14
|
+
*
|
|
15
|
+
* Execution phases per rule:
|
|
16
|
+
* 1. **Detect** — `rule.run()` identifies findings (side-effect free).
|
|
17
|
+
* 2. **Fix** — `rule.fix()` auto-fixes findings (only when `config.fix` is enabled and `rule.fixable` is `true`).
|
|
18
|
+
* 3. **Interact** — `rule.interact()` prompts the user for resolution of remaining findings
|
|
19
|
+
* (only when `config.interactive` is enabled and `rule.interactive` is `true`).
|
|
20
|
+
*/
|
|
21
|
+
async function run(registry, config, entries, mixinNames, mixinKeys, logger) {
|
|
22
|
+
const startTime = Date.now();
|
|
23
|
+
const results = [];
|
|
24
|
+
const context = {
|
|
25
|
+
entries,
|
|
26
|
+
themes: config.themes,
|
|
27
|
+
config,
|
|
28
|
+
logger,
|
|
29
|
+
fix: config.fix,
|
|
30
|
+
interactive: config.interactive,
|
|
31
|
+
mixinNames,
|
|
32
|
+
mixinKeys,
|
|
33
|
+
};
|
|
34
|
+
const configuredRuleNames = Object.keys(config.rules);
|
|
35
|
+
for (const ruleName of configuredRuleNames) {
|
|
36
|
+
const severityOrOff = config.rules[ruleName];
|
|
37
|
+
if (severityOrOff === 'off') {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const rule = registry.getByName(ruleName);
|
|
41
|
+
if (!rule) {
|
|
42
|
+
logger.warn(`Unknown rule '${ruleName}' in configuration — skipping.`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const effectiveSeverity = severityOrOff;
|
|
46
|
+
if (config.verbose) {
|
|
47
|
+
logger.info(`Running rule: ${rule.name}`);
|
|
48
|
+
}
|
|
49
|
+
const ruleStart = Date.now();
|
|
50
|
+
// Phase 1: Detect
|
|
51
|
+
const result = rule.run(context);
|
|
52
|
+
let findings = result.findings.map((finding) => {
|
|
53
|
+
if (finding.severity !== effectiveSeverity) {
|
|
54
|
+
return { ...finding, severity: effectiveSeverity };
|
|
55
|
+
}
|
|
56
|
+
return finding;
|
|
57
|
+
});
|
|
58
|
+
// Phase 2: Fix (auto-fix for fixable rules)
|
|
59
|
+
if (config.fix && rule.fixable && rule.fix) {
|
|
60
|
+
const unfixed = findings.filter(f => !f.fixed);
|
|
61
|
+
if (unfixed.length > 0) {
|
|
62
|
+
const fixedFindings = rule.fix(context, unfixed);
|
|
63
|
+
const fixedSet = new Set(unfixed);
|
|
64
|
+
findings = findings
|
|
65
|
+
.filter(f => !fixedSet.has(f))
|
|
66
|
+
.concat(fixedFindings);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Phase 3: Interact (interactive resolution for remaining unfixed findings)
|
|
70
|
+
if (config.interactive && rule.interactive && rule.interact) {
|
|
71
|
+
const unfixed = findings.filter(f => !f.fixed);
|
|
72
|
+
if (unfixed.length > 0) {
|
|
73
|
+
const interactedFindings = await rule.interact(context, unfixed);
|
|
74
|
+
const interactedSet = new Set(unfixed);
|
|
75
|
+
findings = findings
|
|
76
|
+
.filter(f => !interactedSet.has(f))
|
|
77
|
+
.concat(interactedFindings);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const duration = Date.now() - ruleStart;
|
|
81
|
+
results.push({
|
|
82
|
+
ruleName: result.ruleName,
|
|
83
|
+
findings,
|
|
84
|
+
duration,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
const totalErrors = results.reduce((sum, r) => sum + r.findings.filter(f => f.severity === RuleSeverity.Error).length, 0);
|
|
88
|
+
const totalWarnings = results.reduce((sum, r) => sum + r.findings.filter(f => f.severity === RuleSeverity.Warning).length, 0);
|
|
89
|
+
const totalInfos = results.reduce((sum, r) => sum + r.findings.filter(f => f.severity === RuleSeverity.Info).length, 0);
|
|
90
|
+
const totalFixes = results.reduce((sum, r) => sum + r.findings.filter(f => f.fixed).length, 0);
|
|
91
|
+
return {
|
|
92
|
+
results,
|
|
93
|
+
totalErrors,
|
|
94
|
+
totalWarnings,
|
|
95
|
+
totalInfos,
|
|
96
|
+
totalFixes,
|
|
97
|
+
duration: Date.now() - startTime,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
LintRunner.run = run;
|
|
101
|
+
// #endregion
|
|
102
|
+
})(LintRunner || (LintRunner = {}));
|
|
103
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/core/runner.ts"],"names":[],"mappings":"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"}
|