@salesforce-ux/slds-linter 0.0.11 → 0.0.12-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/commands/lint-components.d.ts +2 -0
- package/build/commands/lint-components.js +50 -0
- package/build/commands/lint-styles.d.ts +2 -0
- package/build/commands/lint-styles.js +50 -0
- package/build/commands/lint.d.ts +2 -0
- package/build/commands/lint.js +86 -0
- package/build/commands/report.d.ts +2 -0
- package/build/commands/report.js +50 -0
- package/build/index.d.ts +2 -1
- package/build/index.js +24 -0
- package/build/services/__tests__/file-scanner.test.js +44 -0
- package/build/services/batch-processor.d.ts +29 -0
- package/build/services/batch-processor.js +84 -0
- package/build/services/config.resolver.d.ts +6 -0
- package/build/services/config.resolver.js +23 -0
- package/build/services/file-patterns.d.ts +3 -0
- package/build/services/file-patterns.js +33 -0
- package/build/services/file-scanner.d.ts +26 -0
- package/build/services/file-scanner.js +69 -0
- package/build/services/lint-runner.d.ts +17 -0
- package/build/services/lint-runner.js +68 -0
- package/build/services/report-generator.d.ts +20 -0
- package/build/services/report-generator.js +119 -0
- package/build/types/index.d.ts +47 -0
- package/build/types/index.js +0 -0
- package/build/utils/cli-args.d.ts +3 -0
- package/build/utils/cli-args.js +30 -0
- package/build/utils/editorLinkUtil.d.ts +21 -0
- package/build/utils/editorLinkUtil.js +21 -0
- package/build/utils/lintResultsUtil.d.ts +7 -0
- package/build/utils/lintResultsUtil.js +43 -0
- package/build/utils/logger.d.ts +7 -0
- package/build/utils/logger.js +24 -0
- package/build/workers/base.worker.d.ts +15 -0
- package/build/workers/base.worker.js +44 -0
- package/build/workers/eslint.worker.js +48 -0
- package/build/workers/stylelint.worker.d.ts +1 -0
- package/build/workers/stylelint.worker.js +39 -0
- package/package.json +46 -41
- package/README.md +0 -74
- package/bin/slds-linter.js +0 -100
- package/build/setup.js +0 -42
- /package/build/{setup.d.ts → workers/eslint.worker.d.ts} +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// src/services/lint-runner.ts
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { BatchProcessor } from "./batch-processor.js";
|
|
4
|
+
import { Logger } from "../utils/logger.js";
|
|
5
|
+
var LintRunner = class {
|
|
6
|
+
/**
|
|
7
|
+
* Run linting on batches of files
|
|
8
|
+
*/
|
|
9
|
+
static async runLinting(fileBatches, workerType, options = {}) {
|
|
10
|
+
try {
|
|
11
|
+
const workerScript = path.resolve(
|
|
12
|
+
import.meta.dirname,
|
|
13
|
+
"../workers",
|
|
14
|
+
workerType === "style" ? "stylelint.worker.js" : "eslint.worker.js"
|
|
15
|
+
);
|
|
16
|
+
const workerConfig = {
|
|
17
|
+
configPath: options.configPath,
|
|
18
|
+
fix: options.fix
|
|
19
|
+
};
|
|
20
|
+
const results = await BatchProcessor.processBatches(
|
|
21
|
+
fileBatches,
|
|
22
|
+
workerScript,
|
|
23
|
+
workerConfig,
|
|
24
|
+
{
|
|
25
|
+
maxWorkers: options.maxWorkers,
|
|
26
|
+
timeoutMs: options.timeoutMs
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
return this.processResults(results);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
Logger.error(`Linting failed: ${error.message}`);
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Process and normalize worker results
|
|
37
|
+
*/
|
|
38
|
+
static processResults(batchResults) {
|
|
39
|
+
const results = [];
|
|
40
|
+
for (const batch of batchResults) {
|
|
41
|
+
if (!batch.success || !batch.results) {
|
|
42
|
+
Logger.warning(`Batch failed: ${batch.error}`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
for (const result of batch.results) {
|
|
46
|
+
if (result.error) {
|
|
47
|
+
Logger.warning(`File processing failed: ${result.file} - ${result.error}`);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
results.push({
|
|
51
|
+
filePath: result.file,
|
|
52
|
+
errors: result.errors?.map((e) => ({
|
|
53
|
+
...e,
|
|
54
|
+
severity: 2
|
|
55
|
+
})) || [],
|
|
56
|
+
warnings: result.warnings?.map((w) => ({
|
|
57
|
+
...w,
|
|
58
|
+
severity: 1
|
|
59
|
+
})) || []
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return results;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
export {
|
|
67
|
+
LintRunner
|
|
68
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { LintResult } from '../types';
|
|
2
|
+
export interface ReportOptions {
|
|
3
|
+
outputPath: string;
|
|
4
|
+
toolName: string;
|
|
5
|
+
toolVersion: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class ReportGenerator {
|
|
8
|
+
/**
|
|
9
|
+
* Generate SARIF report from lint results
|
|
10
|
+
*/
|
|
11
|
+
static generateSarifReport(results: LintResult[], options: ReportOptions): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Extract unique rules from results
|
|
14
|
+
*/
|
|
15
|
+
private static extractRules;
|
|
16
|
+
/**
|
|
17
|
+
* Add lint results to SARIF report
|
|
18
|
+
*/
|
|
19
|
+
private static addResultsToSarif;
|
|
20
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// src/services/report-generator.ts
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fs from "fs/promises";
|
|
4
|
+
import { Logger } from "../utils/logger.js";
|
|
5
|
+
import { SarifBuilder, SarifRunBuilder, SarifResultBuilder, SarifRuleBuilder } from "node-sarif-builder";
|
|
6
|
+
import { createWriteStream } from "fs";
|
|
7
|
+
import { JsonStreamStringify } from "json-stream-stringify";
|
|
8
|
+
import { getRuleDescription } from "./config.resolver.js";
|
|
9
|
+
var ReportGenerator = class {
|
|
10
|
+
/**
|
|
11
|
+
* Generate SARIF report from lint results
|
|
12
|
+
*/
|
|
13
|
+
static async generateSarifReport(results, options) {
|
|
14
|
+
try {
|
|
15
|
+
const builder = new SarifBuilder();
|
|
16
|
+
const runBuilder = new SarifRunBuilder().initSimple({
|
|
17
|
+
toolDriverName: options.toolName,
|
|
18
|
+
toolDriverVersion: options.toolVersion,
|
|
19
|
+
url: options.toolName === "eslint" ? "https://eslint.org" : "https://stylelint.io"
|
|
20
|
+
});
|
|
21
|
+
const rules = this.extractRules(results);
|
|
22
|
+
for (const rule of rules) {
|
|
23
|
+
const ruleBuilder = new SarifRuleBuilder().initSimple({
|
|
24
|
+
ruleId: rule.id,
|
|
25
|
+
shortDescriptionText: rule.shortDescription?.text,
|
|
26
|
+
helpUri: rule.helpUri
|
|
27
|
+
});
|
|
28
|
+
runBuilder.addRule(ruleBuilder);
|
|
29
|
+
}
|
|
30
|
+
for (const result of results) {
|
|
31
|
+
this.addResultsToSarif(runBuilder, result);
|
|
32
|
+
}
|
|
33
|
+
builder.addRun(runBuilder);
|
|
34
|
+
const sarifReport = builder.buildSarifOutput();
|
|
35
|
+
const outputDir = path.dirname(options.outputPath);
|
|
36
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
37
|
+
const writeStream = createWriteStream(options.outputPath);
|
|
38
|
+
const jsonStream = new JsonStreamStringify(sarifReport, null, 2);
|
|
39
|
+
await new Promise((resolve, reject) => {
|
|
40
|
+
jsonStream.pipe(writeStream).on("finish", resolve).on("error", reject);
|
|
41
|
+
});
|
|
42
|
+
Logger.success(`SARIF report generated: ${options.outputPath}`);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
Logger.error(`Failed to generate SARIF report: ${error.message}`);
|
|
45
|
+
throw error;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Extract unique rules from results
|
|
50
|
+
*/
|
|
51
|
+
static extractRules(results) {
|
|
52
|
+
const rules = /* @__PURE__ */ new Map();
|
|
53
|
+
for (const result of results) {
|
|
54
|
+
for (const error of result.errors) {
|
|
55
|
+
if (!rules.has(error.ruleId)) {
|
|
56
|
+
rules.set(error.ruleId, {
|
|
57
|
+
id: error.ruleId,
|
|
58
|
+
shortDescription: {
|
|
59
|
+
text: getRuleDescription(error.ruleId)
|
|
60
|
+
},
|
|
61
|
+
helpUri: error.ruleId.startsWith("slds/") ? `https://github.com/salesforce/slds-linting-plugin/blob/main/docs/rules/${error.ruleId.replace("slds/", "")}.md` : `https://stylelint.io/user-guide/rules/${error.ruleId}`,
|
|
62
|
+
properties: {
|
|
63
|
+
category: "Style"
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
for (const warning of result.warnings) {
|
|
69
|
+
if (!rules.has(warning.ruleId)) {
|
|
70
|
+
rules.set(warning.ruleId, {
|
|
71
|
+
id: warning.ruleId,
|
|
72
|
+
shortDescription: {
|
|
73
|
+
text: getRuleDescription(warning.ruleId)
|
|
74
|
+
},
|
|
75
|
+
helpUri: warning.ruleId.startsWith("slds/") ? `https://github.com/salesforce/slds-linting-plugin/blob/main/docs/rules/${warning.ruleId.replace("slds/", "")}.md` : `https://stylelint.io/user-guide/rules/${warning.ruleId}`,
|
|
76
|
+
properties: {
|
|
77
|
+
category: "Style"
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return Array.from(rules.values());
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Add lint results to SARIF report
|
|
87
|
+
*/
|
|
88
|
+
static addResultsToSarif(runBuilder, lintResult) {
|
|
89
|
+
for (const error of lintResult.errors) {
|
|
90
|
+
const resultBuilder = new SarifResultBuilder().initSimple({
|
|
91
|
+
ruleId: error.ruleId,
|
|
92
|
+
level: "error",
|
|
93
|
+
messageText: error.message,
|
|
94
|
+
fileUri: lintResult.filePath,
|
|
95
|
+
startLine: error.line,
|
|
96
|
+
startColumn: error.column,
|
|
97
|
+
endLine: error.line,
|
|
98
|
+
endColumn: error.column + 1
|
|
99
|
+
});
|
|
100
|
+
runBuilder.addResult(resultBuilder);
|
|
101
|
+
}
|
|
102
|
+
for (const warning of lintResult.warnings) {
|
|
103
|
+
const resultBuilder = new SarifResultBuilder().initSimple({
|
|
104
|
+
ruleId: warning.ruleId,
|
|
105
|
+
level: "warning",
|
|
106
|
+
messageText: warning.message,
|
|
107
|
+
fileUri: lintResult.filePath,
|
|
108
|
+
startLine: warning.line,
|
|
109
|
+
startColumn: warning.column,
|
|
110
|
+
endLine: warning.line,
|
|
111
|
+
endColumn: warning.column + 1
|
|
112
|
+
});
|
|
113
|
+
runBuilder.addResult(resultBuilder);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
export {
|
|
118
|
+
ReportGenerator
|
|
119
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface CliOptions {
|
|
2
|
+
directory?: string;
|
|
3
|
+
output?: string;
|
|
4
|
+
fix?: boolean;
|
|
5
|
+
config?: string;
|
|
6
|
+
configStyle?: string;
|
|
7
|
+
configEslint?: string;
|
|
8
|
+
editor?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface LintResult {
|
|
11
|
+
filePath: string;
|
|
12
|
+
errors: Array<{
|
|
13
|
+
line: number;
|
|
14
|
+
column: number;
|
|
15
|
+
message: string;
|
|
16
|
+
ruleId: string;
|
|
17
|
+
severity: number;
|
|
18
|
+
}>;
|
|
19
|
+
warnings: Array<{
|
|
20
|
+
line: number;
|
|
21
|
+
column: number;
|
|
22
|
+
message: string;
|
|
23
|
+
ruleId: string;
|
|
24
|
+
severity: number;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
export type ExitCode = 0 | 1 | 2;
|
|
28
|
+
export interface WorkerConfig {
|
|
29
|
+
configPath?: string;
|
|
30
|
+
fix?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface WorkerResult {
|
|
33
|
+
file: string;
|
|
34
|
+
error?: string;
|
|
35
|
+
warnings?: Array<{
|
|
36
|
+
line: number;
|
|
37
|
+
column: number;
|
|
38
|
+
message: string;
|
|
39
|
+
ruleId: string;
|
|
40
|
+
}>;
|
|
41
|
+
errors?: Array<{
|
|
42
|
+
line: number;
|
|
43
|
+
column: number;
|
|
44
|
+
message: string;
|
|
45
|
+
ruleId: string;
|
|
46
|
+
}>;
|
|
47
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// src/utils/cli-args.ts
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { accessSync } from "fs";
|
|
4
|
+
function validateAndNormalizePath(inputPath) {
|
|
5
|
+
if (!inputPath) {
|
|
6
|
+
return process.cwd();
|
|
7
|
+
}
|
|
8
|
+
const normalizedPath = path.resolve(inputPath);
|
|
9
|
+
try {
|
|
10
|
+
accessSync(normalizedPath);
|
|
11
|
+
return normalizedPath;
|
|
12
|
+
} catch (error) {
|
|
13
|
+
throw new Error(`Invalid path: ${inputPath}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function normalizeCliOptions(options) {
|
|
17
|
+
return {
|
|
18
|
+
directory: validateAndNormalizePath(options.directory),
|
|
19
|
+
output: validateAndNormalizePath(options.output),
|
|
20
|
+
fix: options.fix || false,
|
|
21
|
+
config: options.config || "",
|
|
22
|
+
configStyle: options.configStyle || "",
|
|
23
|
+
configEslint: options.configEslint || "",
|
|
24
|
+
editor: options.editor || "vscode"
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
normalizeCliOptions,
|
|
29
|
+
validateAndNormalizePath
|
|
30
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns an editor-specific link for opening a file at a given line and column.
|
|
3
|
+
*
|
|
4
|
+
* @param editor - The editor to use (e.g., 'vscode', 'atom', 'sublime').
|
|
5
|
+
* @param absolutePath - The absolute path to the file.
|
|
6
|
+
* @param line - The line number in the file.
|
|
7
|
+
* @param column - The column number in the file.
|
|
8
|
+
* @returns A URL string that can be used to open the file in the specified editor.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getEditorLink(editor: string, absolutePath: string, line: number, column: number): string;
|
|
11
|
+
/**
|
|
12
|
+
* Creates an ANSI hyperlink (if supported) for the line:column text.
|
|
13
|
+
*
|
|
14
|
+
* @param lineCol - The line:column string (e.g., "10:5").
|
|
15
|
+
* @param absolutePath - The absolute path to the file.
|
|
16
|
+
* @param line - The line number in the file.
|
|
17
|
+
* @param column - The column number in the file.
|
|
18
|
+
* @param editor - The editor to use (e.g., 'vscode', 'atom', 'sublime').
|
|
19
|
+
* @returns A string with ANSI escape sequences to create a clickable hyperlink.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createClickableLineCol(lineCol: string, absolutePath: string, line: number, column: number, editor: string): string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// src/utils/editorLinkUtil.ts
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
function getEditorLink(editor, absolutePath, line, column) {
|
|
4
|
+
if (editor === "vscode") {
|
|
5
|
+
return `vscode://file/${absolutePath}:${line}:${column}`;
|
|
6
|
+
} else if (editor === "atom") {
|
|
7
|
+
return `atom://core/open/file?filename=${absolutePath}&line=${line}&column=${column}`;
|
|
8
|
+
} else if (editor === "sublime") {
|
|
9
|
+
return `file://${absolutePath}:${line}:${column}`;
|
|
10
|
+
} else {
|
|
11
|
+
return `file://${absolutePath}:${line}:${column}`;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function createClickableLineCol(lineCol, absolutePath, line, column, editor) {
|
|
15
|
+
const link = getEditorLink(editor, absolutePath, line, column);
|
|
16
|
+
return `\x1B]8;;${link}\x07${chalk.blueBright(lineCol)}\x1B]8;;\x07`;
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
createClickableLineCol,
|
|
20
|
+
getEditorLink
|
|
21
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prints detailed lint results for each file that has issues.
|
|
3
|
+
*
|
|
4
|
+
* @param results - Array of lint results.
|
|
5
|
+
* @param editor - The chosen editor for clickable links (e.g., "vscode", "atom", "sublime").
|
|
6
|
+
*/
|
|
7
|
+
export declare function printLintResults(results: any[], editor: string): void;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// src/utils/lintResultsUtil.ts
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { createClickableLineCol } from "./editorLinkUtil.js";
|
|
5
|
+
import { Logger } from "../utils/logger.js";
|
|
6
|
+
function printLintResults(results, editor) {
|
|
7
|
+
results.forEach((result) => {
|
|
8
|
+
const hasErrors = result.errors && result.errors.length > 0;
|
|
9
|
+
const hasWarnings = result.warnings && result.warnings.length > 0;
|
|
10
|
+
if (!hasErrors && !hasWarnings) return;
|
|
11
|
+
const absolutePath = result.filePath || "";
|
|
12
|
+
const relativeFile = path.relative(process.cwd(), absolutePath) || "Unknown file";
|
|
13
|
+
Logger.info(`
|
|
14
|
+
${chalk.bold(relativeFile)}`);
|
|
15
|
+
if (hasErrors) {
|
|
16
|
+
result.errors.forEach((error) => {
|
|
17
|
+
if (error.line && error.column && absolutePath) {
|
|
18
|
+
const lineCol = `${error.line}:${error.column}`;
|
|
19
|
+
const clickable = createClickableLineCol(lineCol, absolutePath, error.line, error.column, editor);
|
|
20
|
+
const ruleId = error.ruleId ? chalk.dim(error.ruleId) : "";
|
|
21
|
+
Logger.error(` ${clickable} ${error.message} ${ruleId}`);
|
|
22
|
+
} else {
|
|
23
|
+
Logger.error(` ${chalk.red("Error:")} ${error.message}`);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
if (hasWarnings) {
|
|
28
|
+
result.warnings.forEach((warn) => {
|
|
29
|
+
if (warn.line && warn.column && absolutePath) {
|
|
30
|
+
const lineCol = `${warn.line}:${warn.column}`;
|
|
31
|
+
const clickable = createClickableLineCol(lineCol, absolutePath, warn.line, warn.column, editor);
|
|
32
|
+
const ruleId = warn.ruleId ? chalk.dim(warn.ruleId) : "";
|
|
33
|
+
Logger.warning(` ${clickable} ${warn.message} ${ruleId}`);
|
|
34
|
+
} else {
|
|
35
|
+
Logger.warning(` ${chalk.yellow("Warning:")} ${warn.message}`);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
printLintResults
|
|
43
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// src/utils/logger.ts
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
var Logger = class {
|
|
4
|
+
static info(message) {
|
|
5
|
+
console.log(chalk.blue("\u2139"), message);
|
|
6
|
+
}
|
|
7
|
+
static success(message) {
|
|
8
|
+
console.log(chalk.green("\u2713"), message);
|
|
9
|
+
}
|
|
10
|
+
static warning(message) {
|
|
11
|
+
console.warn(chalk.yellow("\u26A0"), message);
|
|
12
|
+
}
|
|
13
|
+
static error(message) {
|
|
14
|
+
console.error(chalk.red("\u2716"), message);
|
|
15
|
+
}
|
|
16
|
+
static debug(message) {
|
|
17
|
+
if (process.env.DEBUG) {
|
|
18
|
+
console.debug(chalk.gray("\u{1F50D}"), message);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
export {
|
|
23
|
+
Logger
|
|
24
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BatchTask } from '../services/batch-processor';
|
|
2
|
+
export declare abstract class BaseWorker<T, R> {
|
|
3
|
+
protected task: BatchTask<T>;
|
|
4
|
+
constructor();
|
|
5
|
+
/**
|
|
6
|
+
* Process a single file
|
|
7
|
+
* @param filePath Path to the file to process
|
|
8
|
+
* @returns Processing result
|
|
9
|
+
*/
|
|
10
|
+
protected abstract processFile(filePath: string): Promise<R>;
|
|
11
|
+
/**
|
|
12
|
+
* Start processing the batch of files
|
|
13
|
+
*/
|
|
14
|
+
process(): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// src/workers/base.worker.ts
|
|
2
|
+
import { parentPort, workerData } from "worker_threads";
|
|
3
|
+
var BaseWorker = class {
|
|
4
|
+
task;
|
|
5
|
+
constructor() {
|
|
6
|
+
this.task = workerData;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Start processing the batch of files
|
|
10
|
+
*/
|
|
11
|
+
async process() {
|
|
12
|
+
try {
|
|
13
|
+
const results = [];
|
|
14
|
+
for (const file of this.task.files) {
|
|
15
|
+
try {
|
|
16
|
+
const result = await this.processFile(file);
|
|
17
|
+
results.push(result);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
results.push({
|
|
20
|
+
file,
|
|
21
|
+
error: error.message
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const batchResult = {
|
|
26
|
+
success: true,
|
|
27
|
+
results
|
|
28
|
+
};
|
|
29
|
+
parentPort?.postMessage(batchResult);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
const errorResult = {
|
|
32
|
+
success: false,
|
|
33
|
+
error: error.message,
|
|
34
|
+
results: []
|
|
35
|
+
};
|
|
36
|
+
parentPort?.postMessage(errorResult);
|
|
37
|
+
} finally {
|
|
38
|
+
process.exit(0);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
export {
|
|
43
|
+
BaseWorker
|
|
44
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// src/workers/eslint.worker.ts
|
|
2
|
+
import { ESLint } from "eslint";
|
|
3
|
+
import { BaseWorker } from "./base.worker.js";
|
|
4
|
+
var ESLintWorker = class extends BaseWorker {
|
|
5
|
+
eslint;
|
|
6
|
+
constructor() {
|
|
7
|
+
super();
|
|
8
|
+
this.eslint = new ESLint({
|
|
9
|
+
useEslintrc: true,
|
|
10
|
+
fix: this.task.config.fix,
|
|
11
|
+
overrideConfigFile: this.task.config.configPath
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
async processFile(filePath) {
|
|
15
|
+
try {
|
|
16
|
+
const results = await this.eslint.lintFiles([filePath]);
|
|
17
|
+
const fileResult = results[0];
|
|
18
|
+
if (this.task.config.fix && fileResult.output) {
|
|
19
|
+
await ESLint.outputFixes(results);
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
file: filePath,
|
|
23
|
+
warnings: fileResult.messages.filter((msg) => msg.severity === 1).map((warning) => ({
|
|
24
|
+
line: warning.line,
|
|
25
|
+
column: warning.column,
|
|
26
|
+
message: warning.message,
|
|
27
|
+
ruleId: warning.ruleId || "unknown"
|
|
28
|
+
})),
|
|
29
|
+
errors: fileResult.messages.filter((msg) => msg.severity === 2).map((error) => ({
|
|
30
|
+
line: error.line,
|
|
31
|
+
column: error.column,
|
|
32
|
+
message: error.message,
|
|
33
|
+
ruleId: error.ruleId || "unknown"
|
|
34
|
+
}))
|
|
35
|
+
};
|
|
36
|
+
} catch (error) {
|
|
37
|
+
return {
|
|
38
|
+
file: filePath,
|
|
39
|
+
error: error.message
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var worker = new ESLintWorker();
|
|
45
|
+
worker.process().catch((error) => {
|
|
46
|
+
console.error("Worker failed:", error);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// src/workers/stylelint.worker.ts
|
|
2
|
+
import stylelint from "stylelint";
|
|
3
|
+
import { BaseWorker } from "./base.worker.js";
|
|
4
|
+
var StylelintWorker = class extends BaseWorker {
|
|
5
|
+
async processFile(filePath) {
|
|
6
|
+
try {
|
|
7
|
+
const options = {
|
|
8
|
+
files: filePath,
|
|
9
|
+
fix: this.task.config.fix
|
|
10
|
+
};
|
|
11
|
+
if (this.task.config.configPath) {
|
|
12
|
+
options.configFile = this.task.config.configPath;
|
|
13
|
+
}
|
|
14
|
+
const result = await stylelint.lint(options);
|
|
15
|
+
const fileResult = result.results[0];
|
|
16
|
+
return {
|
|
17
|
+
file: filePath,
|
|
18
|
+
warnings: fileResult.warnings.map((warning) => ({
|
|
19
|
+
line: warning.line,
|
|
20
|
+
column: warning.column,
|
|
21
|
+
message: warning.text,
|
|
22
|
+
ruleId: warning.rule
|
|
23
|
+
})),
|
|
24
|
+
errors: []
|
|
25
|
+
// Stylelint doesn't differentiate between warnings and errors
|
|
26
|
+
};
|
|
27
|
+
} catch (error) {
|
|
28
|
+
return {
|
|
29
|
+
file: filePath,
|
|
30
|
+
error: error.message
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var worker = new StylelintWorker();
|
|
36
|
+
worker.process().catch((error) => {
|
|
37
|
+
console.error("Worker failed:", error);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
});
|
package/package.json
CHANGED
|
@@ -1,42 +1,47 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
2
|
+
"name": "@salesforce-ux/slds-linter",
|
|
3
|
+
"version": "0.0.12-alpha.0",
|
|
4
|
+
"description": "SLDS CLI tool for linting styles and components",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"lint",
|
|
7
|
+
"eslint",
|
|
8
|
+
"stylelint",
|
|
9
|
+
"cli",
|
|
10
|
+
"sarif",
|
|
11
|
+
"parallel",
|
|
12
|
+
"performance"
|
|
13
|
+
],
|
|
14
|
+
"author": "UXF Tooling Team",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "build/index.js",
|
|
17
|
+
"files": [
|
|
18
|
+
"build/**",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"bin": {
|
|
22
|
+
"slds-linter": "./build/index.js"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@salesforce-ux/eslint-plugin-slds": "0.0.12-alpha.0",
|
|
26
|
+
"@salesforce-ux/stylelint-plugin-slds": "0.0.12-alpha.0",
|
|
27
|
+
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
|
28
|
+
"@typescript-eslint/parser": "^5.0.0",
|
|
29
|
+
"chalk": "^4.1.2",
|
|
30
|
+
"commander": "^13.1.0",
|
|
31
|
+
"eslint": "^8.0.0",
|
|
32
|
+
"glob": "^11.0.0",
|
|
33
|
+
"json-stream-stringify": "^3.1.6",
|
|
34
|
+
"node-sarif-builder": "^3.2.0",
|
|
35
|
+
"ora": "^5.4.1",
|
|
36
|
+
"stylelint": "^16.10.0"
|
|
37
|
+
},
|
|
38
|
+
"license": "ISC",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git+https://github.com/yourusername/linting-cli.git"
|
|
42
|
+
},
|
|
43
|
+
"bugs": {
|
|
44
|
+
"url": "https://github.com/yourusername/linting-cli/issues"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://github.com/yourusername/linting-cli#readme"
|
|
47
|
+
}
|