@salesforce-ux/slds-linter 0.1.9 → 0.2.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  SLDS Linter provides custom linting rules built for Salesforce Lightning Design System 2 (SLDS 2 beta). Lint your components against SLDS 2 best practices to ensure they adhere to the latest styling standards.
6
6
 
7
- SLDS Linter checks your Aura and Lightning web components CSS and markup files to identify styling issues that you can fix for SLDS 2 compatibility. SLDS Linter helps you maintain consistent styling and identify common issues with custom Lightning components.
7
+ SLDS Linter checks your Aura and Lightning web components' CSS and markup files to identify styling issues that you can fix for SLDS 2 compatibility. SLDS Linter helps you maintain consistent styling and identify common issues with custom Lightning components.
8
8
 
9
9
  ## Features
10
10
 
@@ -78,7 +78,7 @@ In your project root directory, follow these steps.
78
78
 
79
79
  ### Troubleshoot SARIF Viewer Navigation
80
80
 
81
- If the SARIF viewer doesnt automatically go to the line of code when you click on an error or warning, follow these steps.
81
+ If the SARIF viewer doesn't automatically go to the line of code when you click on an error or warning, follow these steps.
82
82
 
83
83
  1. In the SARIF viewer pop-up window, click Locate.
84
84
  2. In the file explorer or code editor, locate the file.
@@ -103,6 +103,7 @@ These options are available on SLDS Linter commands.
103
103
  | `--config-stylelint <path>` | Path to stylelint config file | `lint`, `report`|
104
104
  | `--config-eslint <path>` | Path to eslint config file | `lint`, `report`|
105
105
  | `--editor <editor>` | Editor to open files with (e.g., vscode, atom, sublime). Defaults to vscode | `lint` |
106
+ | `--format <type>` | Output format (sarif, csv). Defaults to sarif | `report` |
106
107
 
107
108
  To view help for these options, add `--help` to each command. For example, run `npx @salesforce-ux/slds-linter lint --help` to see which options you can use with `lint`.
108
109
 
@@ -167,4 +168,93 @@ Linting all `.html` and `.cmp` files:
167
168
  npx @salesforce-ux/slds-linter lint "**/*.{html,cmp}"
168
169
  ```
169
170
 
170
- For any questions or issues, open an issue in this repository.
171
+ For any questions or issues, open an issue in this repository.
172
+
173
+ ## Node.js API
174
+
175
+ The SLDS Linter provides a programmatic API for Node.js applications. This allows you to integrate the linter directly into your build process or other tools without relying on the command-line interface.
176
+
177
+ ### Installation
178
+
179
+ ```bash
180
+ npm install @salesforce-ux/slds-linter
181
+ ```
182
+
183
+ ### Usage
184
+
185
+ ```javascript
186
+ import { lint, report } from '@salesforce-ux/slds-linter/executor';
187
+
188
+ // Lint files in a directory
189
+ const results = await lint({
190
+ directory: './src',
191
+ fix: false // Set to true to auto-fix issues where possible
192
+ });
193
+
194
+ console.log(`Found ${results.length} files with issues`);
195
+
196
+ // Generate a report
197
+ const reportStream = await report({
198
+ directory: './src',
199
+ format: 'sarif'
200
+ }, results); // Pass the lint results as second parameter
201
+
202
+ // Process the report stream
203
+ let reportData = '';
204
+ reportStream.on('data', chunk => {
205
+ reportData += chunk;
206
+ });
207
+
208
+ reportStream.on('end', () => {
209
+ console.log('Report:', reportData);
210
+ });
211
+ ```
212
+
213
+ ### API Reference
214
+
215
+ The Node.js API provides the following methods:
216
+
217
+ #### `lint(options)`
218
+
219
+ Lints files for SLDS compliance.
220
+
221
+ **Options:**
222
+ - `directory`: Path to directory to scan for files to lint
223
+ - `fix`: Boolean indicating whether to automatically fix issues when possible
224
+ - `configStylelint`: Path to custom stylelint configuration file
225
+ - `configEslint`: Path to custom eslint configuration file
226
+
227
+ **Returns:** Promise resolving to an array of result objects containing linting issues
228
+
229
+ #### `report(options)`
230
+
231
+ Generates a report of linting issues.
232
+
233
+ **Options:**
234
+ - `directory`: Path to directory to scan (if `results` is not provided)
235
+ - `format`: Report format ('sarif' or 'csv')
236
+ - `configStylelint`: Path to custom stylelint configuration file (if `directory` is used)
237
+ - `configEslint`: Path to custom eslint configuration file (if `directory` is used)
238
+
239
+ **Parameters:**
240
+ - `options`: Configuration options as detailed above
241
+ - `results`: Optional array of lint results (from `lint()`). If not provided, will run lint on the specified directory
242
+
243
+ **Returns:** A readable stream containing the report data
244
+
245
+ ### Utility Functions
246
+
247
+ The package also provides utility functions to help with configuration:
248
+
249
+ #### `normalizeConfig(options)`
250
+
251
+ Normalizes configuration options with default values. Import from `@salesforce-ux/slds-linter/utils/config-utils`.
252
+
253
+ **Options:** Same as the options for `lint()` or `report()`
254
+
255
+ **Returns:** A normalized configuration object with default values applied
256
+
257
+ ### Examples
258
+
259
+ For complete examples, see the [examples directory](./examples/).
260
+
@@ -1,7 +1,7 @@
1
1
  // src/commands/emit.ts
2
2
  import chalk from "chalk";
3
3
  import { Logger } from "../utils/logger.js";
4
- import { normalizeCliOptions } from "../utils/cli-args.js";
4
+ import { normalizeCliOptions } from "../utils/config-utils.js";
5
5
  import {
6
6
  DEFAULT_ESLINT_CONFIG_PATH,
7
7
  DEFAULT_STYLELINT_CONFIG_PATH
@@ -2,12 +2,10 @@
2
2
  import { Option } from "commander";
3
3
  import chalk from "chalk";
4
4
  import { printLintResults } from "../utils/lintResultsUtil.js";
5
- import { normalizeCliOptions, nomalizeDirPath } from "../utils/cli-args.js";
5
+ import { normalizeCliOptions, normalizeDirectoryPath } from "../utils/config-utils.js";
6
6
  import { Logger } from "../utils/logger.js";
7
- import { FileScanner } from "../services/file-scanner.js";
8
- import { StyleFilePatterns, ComponentFilePatterns } from "../services/file-patterns.js";
9
- import { LintRunner } from "../services/lint-runner.js";
10
7
  import { DEFAULT_ESLINT_CONFIG_PATH, DEFAULT_STYLELINT_CONFIG_PATH } from "../services/config.resolver.js";
8
+ import { lint } from "../executor/index.js";
11
9
  function registerLintCommand(program) {
12
10
  program.command("lint").aliases(["lint:styles", "lint:components"]).configureHelp({
13
11
  commandUsage: () => {
@@ -22,54 +20,30 @@ function registerLintCommand(program) {
22
20
  configEslint: DEFAULT_ESLINT_CONFIG_PATH
23
21
  });
24
22
  if (directory) {
25
- normalizedOptions.directory = nomalizeDirPath(directory);
23
+ normalizedOptions.directory = normalizeDirectoryPath(directory);
26
24
  } else if (options.directory) {
27
25
  Logger.newLine().warning(chalk.yellow(
28
26
  `WARNING: --directory, -d option is deprecated. Supply as argument instead.
29
27
  Example: npx @salesforce-ux/slds-linter lint ${options.directory}`
30
28
  ));
31
29
  }
32
- Logger.newLine().info(chalk.blue("Scanning style files..."));
33
- const styleFileBatches = await FileScanner.scanFiles(normalizedOptions.directory, {
34
- patterns: StyleFilePatterns,
35
- batchSize: 100
36
- });
37
- const totalStyleFiles = styleFileBatches.reduce((sum, batch) => sum + batch.length, 0);
38
- Logger.info(chalk.blue(`Found ${totalStyleFiles} style file(s). Running stylelint...`));
39
- Logger.newLine().info(chalk.blue(`Running stylelint${normalizedOptions.fix ? " with autofix" : ""}...`));
40
- const styleResults = await LintRunner.runLinting(styleFileBatches, "style", {
41
- fix: normalizedOptions.fix,
42
- configPath: normalizedOptions.configStylelint
43
- });
44
- printLintResults(styleResults, normalizedOptions.editor);
45
- const styleErrorCount = styleResults.reduce((sum, r) => sum + r.errors.length, 0);
46
- const styleWarningCount = styleResults.reduce((sum, r) => sum + r.warnings.length, 0);
47
- Logger.newLine().info(chalk.blue("Scanning component files..."));
48
- const componentFileBatches = await FileScanner.scanFiles(normalizedOptions.directory, {
49
- patterns: ComponentFilePatterns,
50
- batchSize: 100
51
- });
52
- const totalComponentFiles = componentFileBatches.reduce((sum, batch) => sum + batch.length, 0);
53
- Logger.info(chalk.blue(`Found ${totalComponentFiles} component file(s). Running eslint...
54
- `));
55
- Logger.info(chalk.blue(`Running linting${normalizedOptions.fix ? " with autofix" : ""}...`));
56
- const componentResults = await LintRunner.runLinting(componentFileBatches, "component", {
30
+ const lintResults = await lint({
31
+ directory: normalizedOptions.directory,
57
32
  fix: normalizedOptions.fix,
58
- configPath: normalizedOptions.configEslint
33
+ configStylelint: normalizedOptions.configStylelint,
34
+ configEslint: normalizedOptions.configEslint
59
35
  });
60
- printLintResults(componentResults, normalizedOptions.editor);
61
- const componentErrorCount = componentResults.reduce((sum, r) => sum + r.errors.length, 0);
62
- const componentWarningCount = componentResults.reduce((sum, r) => sum + r.warnings.length, 0);
63
- const totalErrors = styleErrorCount + componentErrorCount;
64
- const totalWarnings = styleWarningCount + componentWarningCount;
36
+ printLintResults(lintResults, normalizedOptions.editor);
37
+ const errorCount = lintResults.reduce((sum, r) => sum + r.errors.length, 0);
38
+ const warningCount = lintResults.reduce((sum, r) => sum + r.warnings.length, 0);
65
39
  Logger.info(
66
40
  `
67
- ${chalk.red(`${totalErrors} error${totalErrors !== 1 ? "s" : ""}`)} ${chalk.yellow(`${totalWarnings} warning${totalWarnings !== 1 ? "s" : ""}`)}`
41
+ ${chalk.red(`${errorCount} error${errorCount !== 1 ? "s" : ""}`)} ${chalk.yellow(`${warningCount} warning${warningCount !== 1 ? "s" : ""}`)}`
68
42
  );
69
43
  const elapsedTime = ((Date.now() - startTime) / 1e3).toFixed(2);
70
44
  Logger.success(chalk.green(`
71
45
  Linting completed in ${elapsedTime} seconds.`));
72
- process.exit(totalErrors > 0 ? 1 : 0);
46
+ process.exit(errorCount > 0 ? 1 : 0);
73
47
  } catch (error) {
74
48
  Logger.error(chalk.red(`Failed to complete linting: ${error.message}`));
75
49
  process.exit(1);
@@ -3,13 +3,11 @@ import { Option } from "commander";
3
3
  import path from "path";
4
4
  import ora from "ora";
5
5
  import chalk from "chalk";
6
- import { nomalizeDirPath, normalizeCliOptions } from "../utils/cli-args.js";
6
+ import fs from "fs";
7
+ import { normalizeCliOptions, normalizeDirectoryPath } from "../utils/config-utils.js";
7
8
  import { Logger } from "../utils/logger.js";
8
- import { FileScanner } from "../services/file-scanner.js";
9
- import { StyleFilePatterns, ComponentFilePatterns } from "../services/file-patterns.js";
10
- import { LintRunner } from "../services/lint-runner.js";
11
- import { ReportGenerator, CsvReportGenerator } from "../services/report-generator.js";
12
- import { DEFAULT_ESLINT_CONFIG_PATH, DEFAULT_STYLELINT_CONFIG_PATH, LINTER_CLI_VERSION } from "../services/config.resolver.js";
9
+ import { DEFAULT_ESLINT_CONFIG_PATH, DEFAULT_STYLELINT_CONFIG_PATH } from "../services/config.resolver.js";
10
+ import { report, lint } from "../executor/index.js";
13
11
  function registerReportCommand(program) {
14
12
  program.command("report").description("Generate report from linting results").argument("[directory]", "Target directory to scan (defaults to current directory). Support glob patterns").addOption(new Option("-d, --directory <path>", "Target directory to scan (defaults to current directory). Support glob patterns").hideHelp()).option("-o, --output <path>", "Output directory for reports (defaults to current directory)").option("--config-stylelint <path>", "Path to stylelint config file").option("--config-eslint <path>", "Path to eslint config file").addOption(new Option("--format <type>", "Output format").choices(["sarif", "csv"]).default("sarif")).action(async (directory, options) => {
15
13
  const spinner = ora("Starting report generation...");
@@ -19,7 +17,7 @@ function registerReportCommand(program) {
19
17
  configEslint: DEFAULT_ESLINT_CONFIG_PATH
20
18
  });
21
19
  if (directory) {
22
- normalizedOptions.directory = nomalizeDirPath(directory);
20
+ normalizedOptions.directory = normalizeDirectoryPath(directory);
23
21
  } else if (options.directory) {
24
22
  Logger.newLine().warning(chalk.yellow(
25
23
  `WARNING: --directory, -d option is deprecated. Supply as argument instead.
@@ -27,41 +25,33 @@ function registerReportCommand(program) {
27
25
  ));
28
26
  }
29
27
  spinner.start();
30
- spinner.text = "Running styles linting...";
31
- const styleFileBatches = await FileScanner.scanFiles(normalizedOptions.directory, {
32
- patterns: StyleFilePatterns,
33
- batchSize: 100
28
+ const reportFormat = normalizedOptions.format?.toLowerCase() || "sarif";
29
+ const lintResults = await lint({
30
+ directory: normalizedOptions.directory,
31
+ configStylelint: normalizedOptions.configStylelint,
32
+ configEslint: normalizedOptions.configEslint
34
33
  });
35
- const styleResults = await LintRunner.runLinting(styleFileBatches, "style", {
36
- configPath: normalizedOptions.configStylelint
37
- });
38
- spinner.text = "Running components linting...";
39
- const componentFileBatches = await FileScanner.scanFiles(normalizedOptions.directory, {
40
- patterns: ComponentFilePatterns,
41
- batchSize: 100
42
- });
43
- const componentResults = await LintRunner.runLinting(componentFileBatches, "component", {
44
- configPath: normalizedOptions.configEslint
45
- });
46
- const reportFormat = options.format.toLowerCase();
34
+ const reportStream = await report({
35
+ format: reportFormat
36
+ }, lintResults);
37
+ let outputFilePath;
47
38
  if (reportFormat === "sarif") {
48
- spinner.text = "Generating SARIF report...";
49
- const combinedReportPath = path.join(normalizedOptions.output, "slds-linter-report.sarif");
50
- await ReportGenerator.generateSarifReport([...styleResults, ...componentResults], {
51
- outputPath: combinedReportPath,
52
- toolName: "slds-linter",
53
- toolVersion: LINTER_CLI_VERSION
54
- });
55
- Logger.success(`SARIF report generated: ${combinedReportPath}
56
- `);
39
+ spinner.text = "Saving SARIF report...";
40
+ outputFilePath = path.join(normalizedOptions.output, "slds-linter-report.sarif");
57
41
  } else if (reportFormat === "csv") {
58
- spinner.text = "Generating CSV report...";
59
- const csvReportPath = await CsvReportGenerator.generate([...styleResults, ...componentResults]);
60
- Logger.success(`CSV report generated: ${csvReportPath}
61
- `);
42
+ spinner.text = "Saving CSV report...";
43
+ outputFilePath = path.join(normalizedOptions.output, "slds-linter-report.csv");
62
44
  } else {
63
45
  throw new Error(`Invalid format: ${reportFormat}. Supported formats: sarif, csv`);
64
46
  }
47
+ const writeStream = fs.createWriteStream(outputFilePath);
48
+ reportStream.pipe(writeStream);
49
+ await new Promise((resolve, reject) => {
50
+ writeStream.on("finish", resolve);
51
+ writeStream.on("error", reject);
52
+ });
53
+ Logger.success(`${reportFormat.toUpperCase()} report generated: ${outputFilePath}
54
+ `);
65
55
  spinner.succeed("Report generation completed");
66
56
  process.exit(0);
67
57
  } catch (error) {
@@ -0,0 +1,189 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __esm = (fn, res) => function __init() {
6
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
+ };
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/executor/index.ts
23
+ var executor_exports = {};
24
+ __export(executor_exports, {
25
+ lint: () => lint,
26
+ report: () => report
27
+ });
28
+ import { Readable } from "stream";
29
+ import { FileScanner } from "../services/file-scanner.js";
30
+ import { LintRunner } from "../services/lint-runner.js";
31
+ import { StyleFilePatterns, ComponentFilePatterns } from "../services/file-patterns.js";
32
+ import { ReportGenerator, CsvReportGenerator } from "../services/report-generator.js";
33
+ import { LINTER_CLI_VERSION } from "../services/config.resolver.js";
34
+ import { normalizeCliOptions } from "../utils/config-utils.js";
35
+ import { Logger } from "../utils/logger.js";
36
+ async function lint(config) {
37
+ try {
38
+ Logger.debug("Starting linting with Node API");
39
+ const normalizedConfig = normalizeCliOptions(config, {}, true);
40
+ const styleFiles = await FileScanner.scanFiles(normalizedConfig.directory, {
41
+ patterns: StyleFilePatterns,
42
+ batchSize: 100
43
+ });
44
+ const componentFiles = await FileScanner.scanFiles(normalizedConfig.directory, {
45
+ patterns: ComponentFilePatterns,
46
+ batchSize: 100
47
+ });
48
+ const lintOptions = {
49
+ fix: normalizedConfig.fix,
50
+ configPath: normalizedConfig.configStylelint
51
+ };
52
+ const styleResults = await LintRunner.runLinting(styleFiles, "style", {
53
+ ...lintOptions,
54
+ configPath: normalizedConfig.configStylelint
55
+ });
56
+ const componentResults = await LintRunner.runLinting(componentFiles, "component", {
57
+ ...lintOptions,
58
+ configPath: normalizedConfig.configEslint
59
+ });
60
+ const combinedResults = [...styleResults, ...componentResults];
61
+ return combinedResults;
62
+ } catch (error) {
63
+ const errorMessage = `Linting failed: ${error.message}`;
64
+ Logger.error(errorMessage);
65
+ throw new Error(errorMessage);
66
+ }
67
+ }
68
+ async function report(config, results) {
69
+ try {
70
+ Logger.debug("Starting report generation with Node API");
71
+ const normalizedConfig = normalizeCliOptions(config, {}, true);
72
+ const format = normalizedConfig.format || "sarif";
73
+ const lintResults = results || await lint({
74
+ directory: normalizedConfig.directory,
75
+ configStylelint: normalizedConfig.configStylelint,
76
+ configEslint: normalizedConfig.configEslint
77
+ });
78
+ switch (format) {
79
+ case "sarif":
80
+ return ReportGenerator.generateSarifReportStream(lintResults, {
81
+ toolName: "slds-linter",
82
+ toolVersion: LINTER_CLI_VERSION
83
+ });
84
+ case "csv":
85
+ const csvString = CsvReportGenerator.generateCsvString(lintResults);
86
+ const csvStream = new Readable();
87
+ csvStream.push(csvString);
88
+ csvStream.push(null);
89
+ return csvStream;
90
+ default:
91
+ const errorMessage = `Unsupported format: ${format}`;
92
+ Logger.error(errorMessage);
93
+ throw new Error(errorMessage);
94
+ }
95
+ } catch (error) {
96
+ const errorMessage = `Report generation failed: ${error.message}`;
97
+ Logger.error(errorMessage);
98
+ throw new Error(errorMessage);
99
+ }
100
+ }
101
+ var init_executor = __esm({
102
+ "src/executor/index.ts"() {
103
+ }
104
+ });
105
+
106
+ // src/executor/__tests__/executor.test.ts
107
+ import { lint as lint2, report as report2 } from "../index.js";
108
+ import { LintRunner as LintRunner2 } from "../../services/lint-runner.js";
109
+ import { FileScanner as FileScanner2 } from "../../services/file-scanner.js";
110
+ import { Readable as Readable2 } from "stream";
111
+ import { jest } from "@jest/globals.js";
112
+ var mockLintResult = {
113
+ filePath: "file1.css",
114
+ errors: [{ line: 1, column: 1, endColumn: 10, message: "Test error", ruleId: "test-rule", severity: 2 }],
115
+ warnings: []
116
+ };
117
+ jest.mock("../../services/lint-runner", () => {
118
+ return {
119
+ LintRunner: {
120
+ runLinting: jest.fn().mockImplementation(() => {
121
+ return Promise.resolve([mockLintResult]);
122
+ })
123
+ }
124
+ };
125
+ });
126
+ jest.mock("../../services/file-scanner", () => {
127
+ return {
128
+ FileScanner: {
129
+ scanFiles: jest.fn().mockImplementation(() => {
130
+ return Promise.resolve([["file1.css"]]);
131
+ })
132
+ }
133
+ };
134
+ });
135
+ jest.mock("fs/promises");
136
+ xdescribe("Executor functions", () => {
137
+ beforeEach(() => {
138
+ jest.clearAllMocks();
139
+ });
140
+ describe("lint", () => {
141
+ it("should scan directory and run linting when no files are provided", async () => {
142
+ const config = {
143
+ directory: "./src",
144
+ fix: true
145
+ };
146
+ const results = await lint2(config);
147
+ expect(FileScanner2.scanFiles).toHaveBeenCalledTimes(2);
148
+ expect(LintRunner2.runLinting).toHaveBeenCalledTimes(2);
149
+ expect(results).toHaveLength(2);
150
+ });
151
+ it("should use provided files and skip scanning when files are provided", async () => {
152
+ const config = {
153
+ files: ["file1.css", "component1.html"]
154
+ };
155
+ await lint2(config);
156
+ expect(FileScanner2.scanFiles).not.toHaveBeenCalled();
157
+ expect(LintRunner2.runLinting).toHaveBeenCalledTimes(2);
158
+ });
159
+ });
160
+ describe("report", () => {
161
+ it("should return a readable stream", async () => {
162
+ const config = {
163
+ directory: "./src",
164
+ format: "sarif"
165
+ };
166
+ const stream = await report2(config);
167
+ expect(stream).toBeInstanceOf(Readable2);
168
+ });
169
+ it("should use lint results to generate a report", async () => {
170
+ const lintMock = jest.spyOn((init_executor(), __toCommonJS(executor_exports)), "lint").mockResolvedValue([mockLintResult]);
171
+ const config = {
172
+ directory: "./src",
173
+ format: "sarif"
174
+ };
175
+ await report2(config);
176
+ expect(lintMock).toHaveBeenCalledWith({
177
+ directory: "./src",
178
+ configStylelint: expect.any(String),
179
+ configEslint: expect.any(String)
180
+ });
181
+ lintMock.mockRestore();
182
+ });
183
+ });
184
+ });
185
+ describe("Executor placeholder tests", () => {
186
+ it("should be implemented in the future", () => {
187
+ expect(true).toBe(true);
188
+ });
189
+ });
@@ -0,0 +1,19 @@
1
+ import { Readable } from 'stream';
2
+ import { LintResult, LintConfig, ReportConfig } from '../types';
3
+ /**
4
+ * Run linting on specified files or directory
5
+ *
6
+ * @param config Linting configuration options
7
+ * @returns Promise resolving to an array of lint results
8
+ * @throws Error if linting fails
9
+ */
10
+ export declare function lint(config: LintConfig): Promise<LintResult[]>;
11
+ /**
12
+ * Generate a report from linting results
13
+ *
14
+ * @param config Report configuration options
15
+ * @param results Optional lint results (if not provided, will run lint)
16
+ * @returns A readable stream containing the report data
17
+ * @throws Error if report generation fails
18
+ */
19
+ export declare function report(config: ReportConfig, results?: LintResult[]): Promise<Readable>;
@@ -0,0 +1,78 @@
1
+ // src/executor/index.ts
2
+ import { Readable } from "stream";
3
+ import { FileScanner } from "../services/file-scanner.js";
4
+ import { LintRunner } from "../services/lint-runner.js";
5
+ import { StyleFilePatterns, ComponentFilePatterns } from "../services/file-patterns.js";
6
+ import { ReportGenerator, CsvReportGenerator } from "../services/report-generator.js";
7
+ import { LINTER_CLI_VERSION } from "../services/config.resolver.js";
8
+ import { normalizeCliOptions } from "../utils/config-utils.js";
9
+ import { Logger } from "../utils/logger.js";
10
+ async function lint(config) {
11
+ try {
12
+ Logger.debug("Starting linting with Node API");
13
+ const normalizedConfig = normalizeCliOptions(config, {}, true);
14
+ const styleFiles = await FileScanner.scanFiles(normalizedConfig.directory, {
15
+ patterns: StyleFilePatterns,
16
+ batchSize: 100
17
+ });
18
+ const componentFiles = await FileScanner.scanFiles(normalizedConfig.directory, {
19
+ patterns: ComponentFilePatterns,
20
+ batchSize: 100
21
+ });
22
+ const lintOptions = {
23
+ fix: normalizedConfig.fix,
24
+ configPath: normalizedConfig.configStylelint
25
+ };
26
+ const styleResults = await LintRunner.runLinting(styleFiles, "style", {
27
+ ...lintOptions,
28
+ configPath: normalizedConfig.configStylelint
29
+ });
30
+ const componentResults = await LintRunner.runLinting(componentFiles, "component", {
31
+ ...lintOptions,
32
+ configPath: normalizedConfig.configEslint
33
+ });
34
+ const combinedResults = [...styleResults, ...componentResults];
35
+ return combinedResults;
36
+ } catch (error) {
37
+ const errorMessage = `Linting failed: ${error.message}`;
38
+ Logger.error(errorMessage);
39
+ throw new Error(errorMessage);
40
+ }
41
+ }
42
+ async function report(config, results) {
43
+ try {
44
+ Logger.debug("Starting report generation with Node API");
45
+ const normalizedConfig = normalizeCliOptions(config, {}, true);
46
+ const format = normalizedConfig.format || "sarif";
47
+ const lintResults = results || await lint({
48
+ directory: normalizedConfig.directory,
49
+ configStylelint: normalizedConfig.configStylelint,
50
+ configEslint: normalizedConfig.configEslint
51
+ });
52
+ switch (format) {
53
+ case "sarif":
54
+ return ReportGenerator.generateSarifReportStream(lintResults, {
55
+ toolName: "slds-linter",
56
+ toolVersion: LINTER_CLI_VERSION
57
+ });
58
+ case "csv":
59
+ const csvString = CsvReportGenerator.generateCsvString(lintResults);
60
+ const csvStream = new Readable();
61
+ csvStream.push(csvString);
62
+ csvStream.push(null);
63
+ return csvStream;
64
+ default:
65
+ const errorMessage = `Unsupported format: ${format}`;
66
+ Logger.error(errorMessage);
67
+ throw new Error(errorMessage);
68
+ }
69
+ } catch (error) {
70
+ const errorMessage = `Report generation failed: ${error.message}`;
71
+ Logger.error(errorMessage);
72
+ throw new Error(errorMessage);
73
+ }
74
+ }
75
+ export {
76
+ lint,
77
+ report
78
+ };
package/build/index.js CHANGED
@@ -19,7 +19,7 @@ process.on("uncaughtException", (error) => {
19
19
  var program = new Command();
20
20
  program.name("npx @salesforce-ux/slds-linter@latest").showHelpAfterError();
21
21
  function registerVersion() {
22
- program.description("SLDS Linter CLI tool for linting styles and components").version("0.1.9");
22
+ program.description("SLDS Linter CLI tool for linting styles and components").version("0.2.0-alpha.1");
23
23
  }
24
24
  registerLintCommand(program);
25
25
  registerReportCommand(program);
@@ -0,0 +1,6 @@
1
+ import { Artifact as SarifArtifact } from 'sarif';
2
+ /**
3
+ * Process artifacts and add file content properties
4
+ * @param artifacts Array of artifacts to process
5
+ */
6
+ export declare function processArtifacts(artifacts: SarifArtifact[]): Promise<void>;
@@ -0,0 +1,37 @@
1
+ // src/services/artifact-processor.ts
2
+ import path from "path";
3
+ import fs from "fs/promises";
4
+ import crypto from "crypto";
5
+ var BATCH_SIZE = 10;
6
+ async function processArtifacts(artifacts) {
7
+ const batches = Array.from(
8
+ { length: Math.ceil(artifacts.length / BATCH_SIZE) },
9
+ (_, i) => artifacts.slice(i * BATCH_SIZE, (i + 1) * BATCH_SIZE)
10
+ );
11
+ for (const batch of batches) {
12
+ await Promise.all(
13
+ batch.map(async (artifact) => {
14
+ try {
15
+ artifact.sourceLanguage = "html";
16
+ if (!artifact.location?.uri) {
17
+ console.warn("Warning: Artifact missing location URI");
18
+ return;
19
+ }
20
+ const filePath = path.join(process.cwd(), artifact.location.uri);
21
+ const content = await fs.readFile(filePath, "utf-8");
22
+ artifact.length = content.length;
23
+ const hash = crypto.createHash("sha256");
24
+ hash.update(content);
25
+ artifact.hashes = {
26
+ "sha-256": hash.digest("hex")
27
+ };
28
+ } catch (error) {
29
+ console.warn(`Warning: Could not process artifact ${artifact.location?.uri}: ${error.message}`);
30
+ }
31
+ })
32
+ );
33
+ }
34
+ }
35
+ export {
36
+ processArtifacts
37
+ };
@@ -5,7 +5,7 @@ var DEFAULT_ESLINT_CONFIG_PATH = resolvePath("@salesforce-ux/eslint-plugin-slds/
5
5
  var DEFAULT_STYLELINT_CONFIG_PATH = resolvePath("@salesforce-ux/stylelint-plugin-slds/.stylelintrc.yml", import.meta);
6
6
  var STYLELINT_VERSION = "16.14.1";
7
7
  var ESLINT_VERSION = "8.57.1";
8
- var LINTER_CLI_VERSION = "0.1.9";
8
+ var LINTER_CLI_VERSION = "0.2.0-alpha.1";
9
9
  var getRuleDescription = (ruleId) => {
10
10
  const ruleIdWithoutNameSpace = `${ruleId}`.replace(/\@salesforce-ux\//, "");
11
11
  return ruleMetadata(ruleIdWithoutNameSpace)?.ruleDesc || "--";
@@ -1,14 +1,23 @@
1
1
  import { LintResult } from '../types';
2
+ import { Readable } from 'stream';
2
3
  export interface ReportOptions {
3
- outputPath: string;
4
+ outputPath?: string;
4
5
  toolName: string;
5
6
  toolVersion: string;
6
7
  }
7
8
  export declare class ReportGenerator {
8
9
  /**
9
- * Generate SARIF report from lint results
10
+ * Generate SARIF report from lint results with file output
10
11
  */
11
12
  static generateSarifReport(results: LintResult[], options: ReportOptions): Promise<void>;
13
+ /**
14
+ * Generate SARIF report as a stream without creating a file
15
+ */
16
+ static generateSarifReportStream(results: LintResult[], options: ReportOptions): Promise<Readable>;
17
+ /**
18
+ * Build SARIF report data in memory
19
+ */
20
+ static buildSarifReport(results: LintResult[], options: ReportOptions): Promise<any>;
12
21
  /**
13
22
  * Extract unique rules from results
14
23
  */
@@ -19,5 +28,16 @@ export declare class ReportGenerator {
19
28
  private static addResultsToSarif;
20
29
  }
21
30
  export declare class CsvReportGenerator {
31
+ /**
32
+ * Generate CSV report and write to file
33
+ */
22
34
  static generate(results: any[]): Promise<string>;
35
+ /**
36
+ * Generate CSV string from lint results
37
+ */
38
+ static generateCsvString(results: any[]): string;
39
+ /**
40
+ * Convert lint results to CSV-compatible data format
41
+ */
42
+ private static convertResultsToCsvData;
23
43
  }
@@ -6,18 +6,56 @@ import { SarifBuilder, SarifRunBuilder, SarifResultBuilder, SarifRuleBuilder } f
6
6
  import { createWriteStream } from "fs";
7
7
  import { JsonStreamStringify } from "json-stream-stringify";
8
8
  import { getRuleDescription } from "./config.resolver.js";
9
- import { parseText, replaceNamespaceinRules } from "../utils/lintResultsUtil.js";
9
+ import { parseText, replaceNamespaceinRules, transformedResults } from "../utils/lintResultsUtil.js";
10
+ import { processArtifacts } from "./artifact-processor.js";
10
11
  var ReportGenerator = class {
11
12
  /**
12
- * Generate SARIF report from lint results
13
+ * Generate SARIF report from lint results with file output
13
14
  */
14
15
  static async generateSarifReport(results, options) {
16
+ if (!options.outputPath) {
17
+ return;
18
+ }
19
+ const sarifReport = await this.buildSarifReport(results, options);
20
+ for (const run of sarifReport.runs) {
21
+ await processArtifacts(run.artifacts);
22
+ }
23
+ const outputDir = path.dirname(options.outputPath);
24
+ await fs.mkdir(outputDir, { recursive: true });
25
+ const writeStream = createWriteStream(options.outputPath);
26
+ const jsonStream = new JsonStreamStringify(sarifReport, null, 2);
27
+ await new Promise((resolve, reject) => {
28
+ jsonStream.pipe(writeStream).on("finish", resolve).on("error", reject);
29
+ });
30
+ }
31
+ /**
32
+ * Generate SARIF report as a stream without creating a file
33
+ */
34
+ static async generateSarifReportStream(results, options) {
35
+ const sarifReport = await this.buildSarifReport(results, options);
36
+ return new JsonStreamStringify(sarifReport, null, 2);
37
+ }
38
+ /**
39
+ * Build SARIF report data in memory
40
+ */
41
+ static async buildSarifReport(results, options) {
15
42
  const builder = new SarifBuilder();
16
- const runBuilder = new SarifRunBuilder().initSimple({
43
+ const runBuilder = new SarifRunBuilder({
44
+ defaultSourceLanguage: "html"
45
+ }).initSimple({
17
46
  toolDriverName: options.toolName,
18
47
  toolDriverVersion: options.toolVersion,
19
48
  url: "https://github.com/salesforce-ux/slds-linter"
20
49
  });
50
+ runBuilder.run.properties = {
51
+ id: Number(Math.random().toString(10).substring(2, 10)),
52
+ version: options.toolVersion,
53
+ submissionDate: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
54
+ language: "html",
55
+ status: "accepted",
56
+ type: "source code"
57
+ };
58
+ runBuilder.run.tool.driver.organization = "Salesforce";
21
59
  const rules = this.extractRules(results);
22
60
  for (const rule of rules) {
23
61
  const ruleBuilder = new SarifRuleBuilder().initSimple({
@@ -30,14 +68,7 @@ var ReportGenerator = class {
30
68
  this.addResultsToSarif(runBuilder, result);
31
69
  }
32
70
  builder.addRun(runBuilder);
33
- const sarifReport = builder.buildSarifOutput();
34
- const outputDir = path.dirname(options.outputPath);
35
- await fs.mkdir(outputDir, { recursive: true });
36
- const writeStream = createWriteStream(options.outputPath);
37
- const jsonStream = new JsonStreamStringify(sarifReport, null, 2);
38
- await new Promise((resolve, reject) => {
39
- jsonStream.pipe(writeStream).on("finish", resolve).on("error", reject);
40
- });
71
+ return builder.buildSarifOutput();
41
72
  }
42
73
  /**
43
74
  * Extract unique rules from results
@@ -78,38 +109,39 @@ var ReportGenerator = class {
78
109
  * Add lint results to SARIF report
79
110
  */
80
111
  static addResultsToSarif(runBuilder, lintResult) {
81
- for (const error of lintResult.errors) {
82
- const resultBuilder = new SarifResultBuilder().initSimple({
83
- ruleId: replaceNamespaceinRules(error.ruleId),
84
- level: "error",
85
- messageText: parseText(error.message),
86
- fileUri: path.relative(process.cwd(), lintResult.filePath),
87
- startLine: error.line,
88
- startColumn: error.column,
89
- endLine: error.line,
90
- endColumn: error.endColumn
91
- });
112
+ lintResult.errors.forEach((error) => {
113
+ const resultBuilder = new SarifResultBuilder().initSimple(transformedResults(lintResult, error, "error"));
92
114
  runBuilder.addResult(resultBuilder);
93
- }
94
- for (const warning of lintResult.warnings) {
95
- const resultBuilder = new SarifResultBuilder().initSimple({
96
- ruleId: replaceNamespaceinRules(warning.ruleId),
97
- level: "warning",
98
- messageText: parseText(warning.message),
99
- fileUri: path.relative(process.cwd(), lintResult.filePath),
100
- startLine: warning.line,
101
- startColumn: warning.column,
102
- endLine: warning.line,
103
- endColumn: warning.endColumn
104
- });
115
+ });
116
+ lintResult.warnings.forEach((warning) => {
117
+ const resultBuilder = new SarifResultBuilder().initSimple(transformedResults(lintResult, warning, "warning"));
105
118
  runBuilder.addResult(resultBuilder);
106
- }
119
+ });
107
120
  }
108
121
  };
109
122
  var CsvReportGenerator = class {
123
+ /**
124
+ * Generate CSV report and write to file
125
+ */
110
126
  static async generate(results) {
127
+ const csvString = this.generateCsvString(results);
128
+ const csvReportPath = path.join(process.cwd(), "slds-linter-report.csv");
129
+ await writeFile(csvReportPath, csvString);
130
+ return csvReportPath;
131
+ }
132
+ /**
133
+ * Generate CSV string from lint results
134
+ */
135
+ static generateCsvString(results) {
136
+ const csvData = this.convertResultsToCsvData(results);
137
+ return asString(csvData);
138
+ }
139
+ /**
140
+ * Convert lint results to CSV-compatible data format
141
+ */
142
+ static convertResultsToCsvData(results) {
143
+ const cwd = process.cwd();
111
144
  const csvConfig = mkConfig({
112
- filename: "slds-linter-report",
113
145
  fieldSeparator: ",",
114
146
  quoteStrings: true,
115
147
  decimalSeparator: ".",
@@ -117,8 +149,7 @@ var CsvReportGenerator = class {
117
149
  useBom: true,
118
150
  useKeysAsHeaders: true
119
151
  });
120
- const cwd = process.cwd();
121
- const transformedResults = results.flatMap(
152
+ const transformedResults2 = results.flatMap(
122
153
  (result) => [
123
154
  ...result.errors.map((error) => ({
124
155
  "File Path": path.relative(cwd, result.filePath),
@@ -146,12 +177,7 @@ var CsvReportGenerator = class {
146
177
  }))
147
178
  ]
148
179
  );
149
- const csvData = generateCsv(csvConfig)(transformedResults);
150
- const csvString = asString(csvData);
151
- const csvReportPath = path.join(cwd, `${csvConfig.filename}.csv`);
152
- return writeFile(csvReportPath, csvString).then(() => {
153
- return csvReportPath;
154
- });
180
+ return generateCsv(csvConfig)(transformedResults2);
155
181
  }
156
182
  };
157
183
  export {
@@ -1,30 +1,44 @@
1
- export interface CliOptions {
1
+ export interface BaseConfig {
2
2
  directory?: string;
3
- output?: string;
4
- fix?: boolean;
3
+ files?: string[];
5
4
  configStylelint?: string;
6
5
  configEslint?: string;
6
+ }
7
+ /**
8
+ * CLI options interface extends BaseConfig for shared properties
9
+ */
10
+ export interface CliOptions extends BaseConfig {
11
+ output?: string;
12
+ fix?: boolean;
7
13
  editor?: string;
8
14
  format?: string;
9
15
  }
16
+ /**
17
+ * Configuration for linting operation in the Node API
18
+ * Extends the common base configuration
19
+ */
20
+ export interface LintConfig extends BaseConfig {
21
+ fix?: boolean;
22
+ }
23
+ /**
24
+ * Configuration for report generation in the Node API
25
+ * Extends the common base configuration
26
+ */
27
+ export interface ReportConfig extends BaseConfig {
28
+ format?: 'sarif' | 'csv';
29
+ }
30
+ export interface LintResultEntry {
31
+ line: number;
32
+ column: number;
33
+ endColumn: number;
34
+ message: string;
35
+ ruleId: string;
36
+ severity: number;
37
+ }
10
38
  export interface LintResult {
11
39
  filePath: string;
12
- errors: Array<{
13
- line: number;
14
- column: number;
15
- endColumn: number;
16
- message: string;
17
- ruleId: string;
18
- severity: number;
19
- }>;
20
- warnings: Array<{
21
- line: number;
22
- column: number;
23
- endColumn: number;
24
- message: string;
25
- ruleId: string;
26
- severity: number;
27
- }>;
40
+ errors: Array<LintResultEntry>;
41
+ warnings: Array<LintResultEntry>;
28
42
  }
29
43
  export type ExitCode = 0 | 1 | 2;
30
44
  export interface WorkerConfig {
@@ -49,3 +63,13 @@ export interface WorkerResult {
49
63
  ruleId: string;
50
64
  }>;
51
65
  }
66
+ export interface SarifResultEntry {
67
+ level: any;
68
+ messageText: string;
69
+ ruleId: string;
70
+ fileUri?: string;
71
+ startLine?: number;
72
+ startColumn?: number;
73
+ endLine?: number;
74
+ endColumn?: number;
75
+ }
@@ -0,0 +1,33 @@
1
+ import { LintConfig, ReportConfig, CliOptions } from '../types';
2
+ /**
3
+ * Normalize and validate a file path
4
+ * This function ensures that the provided path exists and is accessible
5
+ * If no path is provided, it defaults to the current working directory
6
+ *
7
+ * @param inputPath Input file path or undefined
8
+ * @returns Normalized and validated absolute path
9
+ * @throws Error if the path is invalid or inaccessible
10
+ */
11
+ export declare function normalizeAndValidatePath(inputPath?: string): string;
12
+ /**
13
+ * Normalize directory path with special handling for glob patterns
14
+ * This function preserves glob patterns and resolves regular paths to absolute paths
15
+ * If no directory is provided, it defaults to the current working directory
16
+ *
17
+ * @param directory Input directory or glob pattern or undefined
18
+ * @returns Normalized directory path
19
+ */
20
+ export declare function normalizeDirectoryPath(directory?: string): string;
21
+ /**
22
+ * Normalize configuration with appropriate defaults
23
+ * This function ensures all required options have valid values
24
+ * It applies provided defaults, then user-provided options, then normalizes paths
25
+ * Used by both CLI commands and Node API functions
26
+ *
27
+ * @param options Options to normalize
28
+ * @param defaultOptions Default options to apply
29
+ * @param isNodeApi Whether this is being called from the Node API
30
+ * @returns Normalized options with appropriate defaults
31
+ */
32
+ export declare function normalizeCliOptions<T extends CliOptions | LintConfig | ReportConfig>(options: T, defaultOptions?: Partial<T>, isNodeApi?: boolean): T;
33
+ export declare const normalizeConfig: typeof normalizeCliOptions;
@@ -0,0 +1,68 @@
1
+ // src/utils/config-utils.ts
2
+ import path from "path";
3
+ import { DEFAULT_ESLINT_CONFIG_PATH, DEFAULT_STYLELINT_CONFIG_PATH } from "../services/config.resolver.js";
4
+ import { isDynamicPattern } from "globby";
5
+ import { accessSync } from "fs";
6
+ import { Logger } from "./logger.js";
7
+ function normalizeAndValidatePath(inputPath) {
8
+ if (!inputPath) {
9
+ Logger.debug("No path provided, using current working directory");
10
+ return process.cwd();
11
+ }
12
+ const normalizedPath = path.resolve(inputPath);
13
+ Logger.debug(`Normalized path: ${normalizedPath}`);
14
+ try {
15
+ accessSync(normalizedPath);
16
+ return normalizedPath;
17
+ } catch (error) {
18
+ const errorMessage = `Invalid path: ${inputPath}`;
19
+ Logger.error(errorMessage);
20
+ throw new Error(errorMessage);
21
+ }
22
+ }
23
+ function normalizeDirectoryPath(directory) {
24
+ if (!directory) {
25
+ Logger.debug("No directory provided, using current working directory");
26
+ return process.cwd();
27
+ }
28
+ if (isDynamicPattern(directory)) {
29
+ Logger.debug(`Detected glob pattern: ${directory}`);
30
+ return directory;
31
+ }
32
+ Logger.debug(`Normalizing directory path: ${directory}`);
33
+ return path.resolve(directory);
34
+ }
35
+ function normalizeCliOptions(options, defaultOptions = {}, isNodeApi = false) {
36
+ const baseDefaults = {
37
+ files: [],
38
+ configStylelint: isNodeApi ? DEFAULT_STYLELINT_CONFIG_PATH : "",
39
+ configEslint: isNodeApi ? DEFAULT_ESLINT_CONFIG_PATH : ""
40
+ };
41
+ if (!isNodeApi) {
42
+ Object.assign(baseDefaults, {
43
+ fix: false,
44
+ editor: "vscode",
45
+ format: "sarif"
46
+ });
47
+ }
48
+ const normalizedOptions = {
49
+ ...baseDefaults,
50
+ ...defaultOptions,
51
+ ...options,
52
+ directory: normalizeDirectoryPath(options.directory)
53
+ };
54
+ if (!isNodeApi) {
55
+ normalizedOptions.output = options.output ? normalizeAndValidatePath(options.output) : process.cwd();
56
+ }
57
+ if ("format" in options && !options.format && isNodeApi) {
58
+ normalizedOptions.format = "sarif";
59
+ }
60
+ return normalizedOptions;
61
+ }
62
+ var normalizeConfig = normalizeCliOptions;
63
+ export {
64
+ normalizeAndValidatePath,
65
+ normalizeCliOptions,
66
+ normalizeConfig,
67
+ normalizeDirectoryPath
68
+ };
@@ -1,4 +1,4 @@
1
- import { LintResult } from '../types';
1
+ import { LintResult, LintResultEntry, SarifResultEntry } from '../types';
2
2
  /**
3
3
  *
4
4
  * @param id - Rule id
@@ -18,3 +18,4 @@ export declare function parseText(text: string): string;
18
18
  * @param editor - The chosen editor for clickable links (e.g., "vscode", "atom", "sublime").
19
19
  */
20
20
  export declare function printLintResults(results: LintResult[], editor: string): void;
21
+ export declare function transformedResults(lintResult: LintResult, entry: LintResultEntry, level: 'error' | 'warning'): SarifResultEntry;
@@ -7,12 +7,14 @@ function replaceNamespaceinRules(id) {
7
7
  return id.includes("@salesforce-ux/") ? id.replace("@salesforce-ux/", "") : id;
8
8
  }
9
9
  function parseText(text) {
10
+ let safeText = text;
10
11
  try {
11
12
  const parsed = JSON.parse(text);
12
- return parsed.message || JSON.stringify(parsed);
13
+ safeText = parsed.message || JSON.stringify(parsed);
13
14
  } catch (error) {
14
- return text;
15
+ safeText = text;
15
16
  }
17
+ return safeText.endsWith(".") ? safeText : `${safeText}.`;
16
18
  }
17
19
  function printLintResults(results, editor) {
18
20
  results.forEach((result) => {
@@ -48,8 +50,21 @@ function printLintResults(results, editor) {
48
50
  }
49
51
  });
50
52
  }
53
+ function transformedResults(lintResult, entry, level) {
54
+ return {
55
+ ruleId: replaceNamespaceinRules(entry.ruleId),
56
+ level,
57
+ messageText: parseText(entry.message),
58
+ fileUri: path.relative(process.cwd(), lintResult.filePath),
59
+ startLine: entry.line,
60
+ startColumn: entry.column,
61
+ endLine: entry.line,
62
+ endColumn: entry.endColumn
63
+ };
64
+ }
51
65
  export {
52
66
  parseText,
53
67
  printLintResults,
54
- replaceNamespaceinRules
68
+ replaceNamespaceinRules,
69
+ transformedResults
55
70
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce-ux/slds-linter",
3
- "version": "0.1.9",
3
+ "version": "0.2.0-alpha.2",
4
4
  "description": "SLDS Linter CLI tool for linting styles and components",
5
5
  "keywords": [
6
6
  "lightning design system linter",
@@ -12,16 +12,18 @@
12
12
  "author": "UXF Tooling Team",
13
13
  "type": "module",
14
14
  "main": "build/index.js",
15
+ "exports": {
16
+ ".": "./build/index.js",
17
+ "./executor": "./build/executor/index.js"
18
+ },
15
19
  "files": [
16
20
  "build/**",
17
21
  "README.md"
18
22
  ],
19
- "bin": {
20
- "slds-linter": "./build/index.js"
21
- },
23
+ "bin": "./build/index.js",
22
24
  "dependencies": {
23
- "@salesforce-ux/eslint-plugin-slds": "0.1.9",
24
- "@salesforce-ux/stylelint-plugin-slds": "0.1.9",
25
+ "@salesforce-ux/eslint-plugin-slds": "0.2.0-alpha.2",
26
+ "@salesforce-ux/stylelint-plugin-slds": "0.2.0-alpha.2",
25
27
  "@typescript-eslint/eslint-plugin": "^5.0.0",
26
28
  "@typescript-eslint/parser": "^5.0.0",
27
29
  "chalk": "^4.1.2",
@@ -1,4 +0,0 @@
1
- import { CliOptions } from "../types";
2
- export declare function nomalizeAndValidatePath(inputPath?: string): string;
3
- export declare function nomalizeDirPath(inputPath?: string): string;
4
- export declare function normalizeCliOptions(options: CliOptions, defultOptions?: Partial<CliOptions>): Required<CliOptions>;
@@ -1,43 +0,0 @@
1
- // src/utils/cli-args.ts
2
- import path from "path";
3
- import { accessSync } from "fs";
4
- import { isDynamicPattern } from "globby";
5
- function nomalizeAndValidatePath(inputPath) {
6
- if (!inputPath) {
7
- return process.cwd();
8
- }
9
- const normalizedPath = path.resolve(inputPath);
10
- try {
11
- accessSync(normalizedPath);
12
- return normalizedPath;
13
- } catch (error) {
14
- throw new Error(`Invalid path: ${inputPath}`);
15
- }
16
- }
17
- function nomalizeDirPath(inputPath) {
18
- if (!inputPath) {
19
- return process.cwd();
20
- }
21
- if (isDynamicPattern(inputPath)) {
22
- return inputPath;
23
- }
24
- return nomalizeAndValidatePath(inputPath);
25
- }
26
- function normalizeCliOptions(options, defultOptions = {}) {
27
- return {
28
- fix: false,
29
- editor: "vscode",
30
- configStylelint: "",
31
- configEslint: "",
32
- format: "sarif",
33
- ...defultOptions,
34
- ...options,
35
- directory: nomalizeDirPath(options.directory),
36
- output: nomalizeAndValidatePath(options.output)
37
- };
38
- }
39
- export {
40
- nomalizeAndValidatePath,
41
- nomalizeDirPath,
42
- normalizeCliOptions
43
- };