@redocly/recheck 0.1.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/README.md +544 -0
- package/dist/assertions/bullet-style.d.ts +3 -0
- package/dist/assertions/bullet-style.d.ts.map +1 -0
- package/dist/assertions/bullet-style.js +60 -0
- package/dist/assertions/bullet-style.js.map +1 -0
- package/dist/assertions/index.d.ts +21 -0
- package/dist/assertions/index.d.ts.map +1 -0
- package/dist/assertions/index.js +30 -0
- package/dist/assertions/index.js.map +1 -0
- package/dist/assertions/max-image-size.d.ts +3 -0
- package/dist/assertions/max-image-size.d.ts.map +1 -0
- package/dist/assertions/max-image-size.js +73 -0
- package/dist/assertions/max-image-size.js.map +1 -0
- package/dist/assertions/max-line-length.d.ts +3 -0
- package/dist/assertions/max-line-length.d.ts.map +1 -0
- package/dist/assertions/max-line-length.js +68 -0
- package/dist/assertions/max-line-length.js.map +1 -0
- package/dist/assertions/no-broken-fragment-links.d.ts +3 -0
- package/dist/assertions/no-broken-fragment-links.d.ts.map +1 -0
- package/dist/assertions/no-broken-fragment-links.js +79 -0
- package/dist/assertions/no-broken-fragment-links.js.map +1 -0
- package/dist/assertions/no-duplicate-headings.d.ts +3 -0
- package/dist/assertions/no-duplicate-headings.d.ts.map +1 -0
- package/dist/assertions/no-duplicate-headings.js +66 -0
- package/dist/assertions/no-duplicate-headings.js.map +1 -0
- package/dist/assertions/no-hard-tabs.d.ts +3 -0
- package/dist/assertions/no-hard-tabs.d.ts.map +1 -0
- package/dist/assertions/no-hard-tabs.js +63 -0
- package/dist/assertions/no-hard-tabs.js.map +1 -0
- package/dist/assertions/no-trailing-spaces.d.ts +3 -0
- package/dist/assertions/no-trailing-spaces.d.ts.map +1 -0
- package/dist/assertions/no-trailing-spaces.js +72 -0
- package/dist/assertions/no-trailing-spaces.js.map +1 -0
- package/dist/assertions/pattern.d.ts +3 -0
- package/dist/assertions/pattern.d.ts.map +1 -0
- package/dist/assertions/pattern.js +39 -0
- package/dist/assertions/pattern.js.map +1 -0
- package/dist/assertions/semantic-line-breaks.d.ts +3 -0
- package/dist/assertions/semantic-line-breaks.d.ts.map +1 -0
- package/dist/assertions/semantic-line-breaks.js +152 -0
- package/dist/assertions/semantic-line-breaks.js.map +1 -0
- package/dist/assertions/swap.d.ts +3 -0
- package/dist/assertions/swap.d.ts.map +1 -0
- package/dist/assertions/swap.js +39 -0
- package/dist/assertions/swap.js.map +1 -0
- package/dist/assertions/utils.d.ts +8 -0
- package/dist/assertions/utils.d.ts.map +1 -0
- package/dist/assertions/utils.js +57 -0
- package/dist/assertions/utils.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +125 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/run.d.ts +20 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +115 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/validate.d.ts +8 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +43 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/config/load.d.ts +20 -0
- package/dist/config/load.d.ts.map +1 -0
- package/dist/config/load.js +85 -0
- package/dist/config/load.js.map +1 -0
- package/dist/config/schema.d.ts +109 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +103 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/validate.d.ts +10 -0
- package/dist/config/validate.d.ts.map +1 -0
- package/dist/config/validate.js +129 -0
- package/dist/config/validate.js.map +1 -0
- package/dist/core/auto-fix.d.ts +16 -0
- package/dist/core/auto-fix.d.ts.map +1 -0
- package/dist/core/auto-fix.js +82 -0
- package/dist/core/auto-fix.js.map +1 -0
- package/dist/core/files.d.ts +6 -0
- package/dist/core/files.d.ts.map +1 -0
- package/dist/core/files.js +75 -0
- package/dist/core/files.js.map +1 -0
- package/dist/core/rule-filters.d.ts +28 -0
- package/dist/core/rule-filters.d.ts.map +1 -0
- package/dist/core/rule-filters.js +54 -0
- package/dist/core/rule-filters.js.map +1 -0
- package/dist/core/runner.d.ts +4 -0
- package/dist/core/runner.d.ts.map +1 -0
- package/dist/core/runner.js +135 -0
- package/dist/core/runner.js.map +1 -0
- package/dist/core/scope-parser.d.ts +26 -0
- package/dist/core/scope-parser.d.ts.map +1 -0
- package/dist/core/scope-parser.js +110 -0
- package/dist/core/scope-parser.js.map +1 -0
- package/dist/core/timing.d.ts +24 -0
- package/dist/core/timing.d.ts.map +1 -0
- package/dist/core/timing.js +39 -0
- package/dist/core/timing.js.map +1 -0
- package/dist/files.d.ts +2 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +39 -0
- package/dist/files.js.map +1 -0
- package/dist/load-config.d.ts +25 -0
- package/dist/load-config.d.ts.map +1 -0
- package/dist/load-config.js +104 -0
- package/dist/load-config.js.map +1 -0
- package/dist/load.d.ts +25 -0
- package/dist/load.d.ts.map +1 -0
- package/dist/load.js +112 -0
- package/dist/load.js.map +1 -0
- package/dist/reporter/fixes.d.ts +3 -0
- package/dist/reporter/fixes.d.ts.map +1 -0
- package/dist/reporter/fixes.js +20 -0
- package/dist/reporter/fixes.js.map +1 -0
- package/dist/reporter/formats/github-actions.d.ts +6 -0
- package/dist/reporter/formats/github-actions.d.ts.map +1 -0
- package/dist/reporter/formats/github-actions.js +20 -0
- package/dist/reporter/formats/github-actions.js.map +1 -0
- package/dist/reporter/formats/json.d.ts +6 -0
- package/dist/reporter/formats/json.d.ts.map +1 -0
- package/dist/reporter/formats/json.js +24 -0
- package/dist/reporter/formats/json.js.map +1 -0
- package/dist/reporter/formats/sarif.d.ts +10 -0
- package/dist/reporter/formats/sarif.d.ts.map +1 -0
- package/dist/reporter/formats/sarif.js +66 -0
- package/dist/reporter/formats/sarif.js.map +1 -0
- package/dist/reporter/formats/table.d.ts +6 -0
- package/dist/reporter/formats/table.d.ts.map +1 -0
- package/dist/reporter/formats/table.js +38 -0
- package/dist/reporter/formats/table.js.map +1 -0
- package/dist/reporter/index.d.ts +10 -0
- package/dist/reporter/index.d.ts.map +1 -0
- package/dist/reporter/index.js +42 -0
- package/dist/reporter/index.js.map +1 -0
- package/dist/reporter/prioritize-problems.d.ts +7 -0
- package/dist/reporter/prioritize-problems.d.ts.map +1 -0
- package/dist/reporter/prioritize-problems.js +29 -0
- package/dist/reporter/prioritize-problems.js.map +1 -0
- package/dist/reporter/statistics.d.ts +17 -0
- package/dist/reporter/statistics.d.ts.map +1 -0
- package/dist/reporter/statistics.js +52 -0
- package/dist/reporter/statistics.js.map +1 -0
- package/dist/reporter/summary.d.ts +10 -0
- package/dist/reporter/summary.d.ts.map +1 -0
- package/dist/reporter/summary.js +48 -0
- package/dist/reporter/summary.js.map +1 -0
- package/dist/scope.d.ts +26 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +110 -0
- package/dist/scope.js.map +1 -0
- package/dist/types/assertions.d.ts +56 -0
- package/dist/types/assertions.d.ts.map +1 -0
- package/dist/types/assertions.js +2 -0
- package/dist/types/assertions.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/problems.d.ts +21 -0
- package/dist/types/problems.d.ts.map +1 -0
- package/dist/types/problems.js +2 -0
- package/dist/types/problems.js.map +1 -0
- package/dist/types/reporting.d.ts +23 -0
- package/dist/types/reporting.d.ts.map +1 -0
- package/dist/types/reporting.js +2 -0
- package/dist/types/reporting.js.map +1 -0
- package/dist/types/rules.d.ts +43 -0
- package/dist/types/rules.d.ts.map +1 -0
- package/dist/types/rules.js +2 -0
- package/dist/types/rules.js.map +1 -0
- package/dist/types/validation.d.ts +6 -0
- package/dist/types/validation.d.ts.map +1 -0
- package/dist/types/validation.js +2 -0
- package/dist/types/validation.js.map +1 -0
- package/dist/types.d.ts +109 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.d.ts +31 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +154 -0
- package/dist/validate.js.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as yaml from 'js-yaml';
|
|
4
|
+
import { ConfigValidator } from './validate.js';
|
|
5
|
+
export class ConfigLoader {
|
|
6
|
+
constructor(validator) {
|
|
7
|
+
Object.defineProperty(this, "validator", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
configurable: true,
|
|
10
|
+
writable: true,
|
|
11
|
+
value: void 0
|
|
12
|
+
});
|
|
13
|
+
this.validator = validator;
|
|
14
|
+
}
|
|
15
|
+
static async create() {
|
|
16
|
+
const validator = await ConfigValidator.create();
|
|
17
|
+
return new ConfigLoader(validator);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Loads and validates a recheck configuration file
|
|
21
|
+
*/
|
|
22
|
+
async loadConfig(configPath) {
|
|
23
|
+
try {
|
|
24
|
+
// Check if file exists
|
|
25
|
+
await fs.access(configPath);
|
|
26
|
+
// Read file content
|
|
27
|
+
const fileContent = await fs.readFile(configPath, 'utf8');
|
|
28
|
+
// Parse YAML
|
|
29
|
+
let config;
|
|
30
|
+
try {
|
|
31
|
+
config = yaml.load(fileContent);
|
|
32
|
+
}
|
|
33
|
+
catch (yamlError) {
|
|
34
|
+
return {
|
|
35
|
+
success: false,
|
|
36
|
+
rules: [],
|
|
37
|
+
errors: [{ message: `YAML parsing error: ${yamlError.message}` }],
|
|
38
|
+
configPath,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
// Validate configuration
|
|
42
|
+
const validation = this.validator.validate(config);
|
|
43
|
+
return {
|
|
44
|
+
success: validation.isValid,
|
|
45
|
+
rules: validation.rules,
|
|
46
|
+
errors: validation.errors,
|
|
47
|
+
configPath,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
return {
|
|
52
|
+
success: false,
|
|
53
|
+
rules: [],
|
|
54
|
+
errors: [{ message: `Error loading configuration: ${error.message}` }],
|
|
55
|
+
configPath,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Finds a recheck configuration file in the current directory or parent directories
|
|
61
|
+
*/
|
|
62
|
+
async findConfigFile(startDir = process.cwd()) {
|
|
63
|
+
const configNames = ['recheck.yaml', 'recheck.yml', '.recheck.yaml', '.recheck.yml'];
|
|
64
|
+
let currentDir = startDir;
|
|
65
|
+
while (true) {
|
|
66
|
+
for (const configName of configNames) {
|
|
67
|
+
const configPath = path.join(currentDir, configName);
|
|
68
|
+
try {
|
|
69
|
+
await fs.access(configPath);
|
|
70
|
+
return configPath;
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// not found, continue
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const parentDir = path.dirname(currentDir);
|
|
77
|
+
if (parentDir === currentDir) {
|
|
78
|
+
// Reached root directory
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
currentDir = parentDir;
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Loads configuration with automatic discovery
|
|
87
|
+
*/
|
|
88
|
+
async loadConfigAuto(configPath) {
|
|
89
|
+
const actualConfigPath = configPath || (await this.findConfigFile());
|
|
90
|
+
if (!actualConfigPath) {
|
|
91
|
+
return {
|
|
92
|
+
success: false,
|
|
93
|
+
rules: [],
|
|
94
|
+
errors: [
|
|
95
|
+
{
|
|
96
|
+
message: 'No recheck configuration file found. Looking for: recheck.yaml, recheck.yml, .recheck.yaml, .recheck.yml',
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return this.loadConfig(actualConfigPath);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=load-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load-config.js","sourceRoot":"","sources":["../src/load-config.ts"],"names":[],"mappings":"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"}
|
package/dist/load.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { NormalizedRule, ValidationError } from './types.js';
|
|
2
|
+
export interface LoadResult {
|
|
3
|
+
success: boolean;
|
|
4
|
+
rules: NormalizedRule[];
|
|
5
|
+
errors: ValidationError[];
|
|
6
|
+
configPath?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare class ConfigLoader {
|
|
9
|
+
private validator;
|
|
10
|
+
private constructor();
|
|
11
|
+
static create(): Promise<ConfigLoader>;
|
|
12
|
+
/**
|
|
13
|
+
* Loads and validates a recheck configuration file
|
|
14
|
+
*/
|
|
15
|
+
loadConfig(configPath: string): Promise<LoadResult>;
|
|
16
|
+
/**
|
|
17
|
+
* Finds a recheck configuration file in the current directory or parent directories
|
|
18
|
+
*/
|
|
19
|
+
findConfigFile(startDir?: string): Promise<string | null>;
|
|
20
|
+
/**
|
|
21
|
+
* Loads configuration with automatic discovery
|
|
22
|
+
*/
|
|
23
|
+
loadConfigAuto(configPath?: string): Promise<LoadResult>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=load.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAIlE,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,SAAS,CAAkB;IAEnC,OAAO;WAIM,MAAM,IAAI,OAAO,CAAC,YAAY,CAAC;IAK5C;;OAEG;IACG,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAgDzD;;OAEG;IACG,cAAc,CAAC,QAAQ,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA2B9E;;OAEG;IACG,cAAc,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;CAkB/D"}
|
package/dist/load.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as yaml from 'js-yaml';
|
|
4
|
+
import { ConfigValidator } from './validate.js';
|
|
5
|
+
export class ConfigLoader {
|
|
6
|
+
constructor(validator) {
|
|
7
|
+
Object.defineProperty(this, "validator", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
configurable: true,
|
|
10
|
+
writable: true,
|
|
11
|
+
value: void 0
|
|
12
|
+
});
|
|
13
|
+
this.validator = validator;
|
|
14
|
+
}
|
|
15
|
+
static async create() {
|
|
16
|
+
const validator = await ConfigValidator.create();
|
|
17
|
+
return new ConfigLoader(validator);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Loads and validates a recheck configuration file
|
|
21
|
+
*/
|
|
22
|
+
async loadConfig(configPath) {
|
|
23
|
+
try {
|
|
24
|
+
// Check if file exists
|
|
25
|
+
await fs.access(configPath);
|
|
26
|
+
// Read file content
|
|
27
|
+
const fileContent = await fs.readFile(configPath, 'utf8');
|
|
28
|
+
// Parse YAML
|
|
29
|
+
let config;
|
|
30
|
+
try {
|
|
31
|
+
config = yaml.load(fileContent);
|
|
32
|
+
}
|
|
33
|
+
catch (yamlError) {
|
|
34
|
+
return {
|
|
35
|
+
success: false,
|
|
36
|
+
rules: [],
|
|
37
|
+
errors: [
|
|
38
|
+
{
|
|
39
|
+
message: `YAML parsing error: ${yamlError instanceof Error ? yamlError.message : 'Unknown error'}`,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
configPath,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// Validate configuration
|
|
46
|
+
const validation = this.validator.validate(config);
|
|
47
|
+
return {
|
|
48
|
+
success: validation.isValid,
|
|
49
|
+
rules: validation.rules,
|
|
50
|
+
errors: validation.errors,
|
|
51
|
+
configPath,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
return {
|
|
56
|
+
success: false,
|
|
57
|
+
rules: [],
|
|
58
|
+
errors: [
|
|
59
|
+
{
|
|
60
|
+
message: `Error loading configuration: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
configPath,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Finds a recheck configuration file in the current directory or parent directories
|
|
69
|
+
*/
|
|
70
|
+
async findConfigFile(startDir = process.cwd()) {
|
|
71
|
+
const configNames = ['recheck.yaml', 'recheck.yml', '.recheck.yaml', '.recheck.yml'];
|
|
72
|
+
let currentDir = startDir;
|
|
73
|
+
while (true) {
|
|
74
|
+
for (const configName of configNames) {
|
|
75
|
+
const configPath = path.join(currentDir, configName);
|
|
76
|
+
try {
|
|
77
|
+
await fs.access(configPath);
|
|
78
|
+
return configPath;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// not found, continue
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const parentDir = path.dirname(currentDir);
|
|
85
|
+
if (parentDir === currentDir) {
|
|
86
|
+
// Reached root directory
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
currentDir = parentDir;
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Loads configuration with automatic discovery
|
|
95
|
+
*/
|
|
96
|
+
async loadConfigAuto(configPath) {
|
|
97
|
+
const actualConfigPath = configPath || (await this.findConfigFile());
|
|
98
|
+
if (!actualConfigPath) {
|
|
99
|
+
return {
|
|
100
|
+
success: false,
|
|
101
|
+
rules: [],
|
|
102
|
+
errors: [
|
|
103
|
+
{
|
|
104
|
+
message: 'No recheck configuration file found. Looking for: recheck.yaml, recheck.yml, .recheck.yaml, .recheck.yml',
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
return this.loadConfig(actualConfigPath);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=load.js.map
|
package/dist/load.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixes.d.ts","sourceRoot":"","sources":["../../src/reporter/fixes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAE7C,wBAAgB,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,CAmB9C"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { cyan, green } from 'colorette';
|
|
2
|
+
export function reportFixes(fixes) {
|
|
3
|
+
console.log(cyan('\n🔧 Auto-fix Summary:'));
|
|
4
|
+
// Group fixes by file
|
|
5
|
+
const fixesByFile = {};
|
|
6
|
+
for (const fix of fixes) {
|
|
7
|
+
if (!fixesByFile[fix.file]) {
|
|
8
|
+
fixesByFile[fix.file] = [];
|
|
9
|
+
}
|
|
10
|
+
fixesByFile[fix.file].push(fix);
|
|
11
|
+
}
|
|
12
|
+
// Report fixes by file
|
|
13
|
+
for (const [file, fileFixes] of Object.entries(fixesByFile)) {
|
|
14
|
+
console.log(`\n ${file}:`);
|
|
15
|
+
for (const fix of fileFixes) {
|
|
16
|
+
console.log(green(` ✓ Line ${fix.line}: ${fix.description}`));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=fixes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixes.js","sourceRoot":"","sources":["../../src/reporter/fixes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAIxC,MAAM,UAAU,WAAW,CAAC,KAAY;IACtC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC;IAE5C,sBAAsB;IACtB,MAAM,WAAW,GAA0B,EAAE,CAAC;IAC9C,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACxB,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC3B,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,CAAC;QACD,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,uBAAuB;IACvB,KAAK,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5D,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,CAAC;QAC7B,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,eAAe,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-actions.d.ts","sourceRoot":"","sources":["../../../src/reporter/formats/github-actions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEpD;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,CAiBnE"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output problems in GitHub Actions format for inline file annotations
|
|
3
|
+
*/
|
|
4
|
+
export function outputGitHubActionsFormat(problems) {
|
|
5
|
+
for (const problem of problems) {
|
|
6
|
+
const command = problem.severity === 'error' ? 'error' : 'warning';
|
|
7
|
+
const properties = [
|
|
8
|
+
`title=${problem.ruleName}`,
|
|
9
|
+
`file=${problem.file}`,
|
|
10
|
+
`line=${problem.line}`,
|
|
11
|
+
`endLine=${problem.line}`,
|
|
12
|
+
`col=${problem.column}`,
|
|
13
|
+
`endColumn=${problem.column + (problem.match?.length || 1)}`,
|
|
14
|
+
].join(',');
|
|
15
|
+
// Escape the message for GitHub Actions format
|
|
16
|
+
const escapedMessage = problem.message.replace(/::/g, '%3A%3A').replace(/\n/g, '%0A');
|
|
17
|
+
console.log(`::${command} ${properties}::${escapedMessage}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=github-actions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-actions.js","sourceRoot":"","sources":["../../../src/reporter/formats/github-actions.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,yBAAyB,CAAC,QAAmB;IAC3D,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QACnE,MAAM,UAAU,GAAG;YACjB,SAAS,OAAO,CAAC,QAAQ,EAAE;YAC3B,QAAQ,OAAO,CAAC,IAAI,EAAE;YACtB,QAAQ,OAAO,CAAC,IAAI,EAAE;YACtB,WAAW,OAAO,CAAC,IAAI,EAAE;YACzB,OAAO,OAAO,CAAC,MAAM,EAAE;YACvB,aAAa,OAAO,CAAC,MAAM,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,CAAC,EAAE;SAC7D,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEZ,+CAA+C;QAC/C,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAEtF,OAAO,CAAC,GAAG,CAAC,KAAK,OAAO,IAAI,UAAU,KAAK,cAAc,EAAE,CAAC,CAAC;IAC/D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Problem } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Output problems in JSON format to file or stdout
|
|
4
|
+
*/
|
|
5
|
+
export declare function outputJsonFormat(problems: Problem[], fileCount: number, outputPath?: string): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../../src/reporter/formats/json.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAIpD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,OAAO,EAAE,EACnB,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAkBf"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import { getBreakdownStats } from '../statistics.js';
|
|
3
|
+
/**
|
|
4
|
+
* Output problems in JSON format to file or stdout
|
|
5
|
+
*/
|
|
6
|
+
export async function outputJsonFormat(problems, fileCount, outputPath) {
|
|
7
|
+
const report = {
|
|
8
|
+
summary: {
|
|
9
|
+
filesScanned: fileCount,
|
|
10
|
+
totalIssues: problems.length,
|
|
11
|
+
breakdown: getBreakdownStats(problems),
|
|
12
|
+
},
|
|
13
|
+
issues: problems,
|
|
14
|
+
};
|
|
15
|
+
const content = JSON.stringify(report, null, 2);
|
|
16
|
+
if (outputPath && outputPath.length > 0) {
|
|
17
|
+
await fs.writeFile(outputPath, content, 'utf8');
|
|
18
|
+
console.log(`\n Wrote JSON report to ${outputPath}`);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
console.log('\n' + content);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../../src/reporter/formats/json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAIlC,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAmB,EACnB,SAAiB,EACjB,UAAmB;IAEnB,MAAM,MAAM,GAAG;QACb,OAAO,EAAE;YACP,YAAY,EAAE,SAAS;YACvB,WAAW,EAAE,QAAQ,CAAC,MAAM;YAC5B,SAAS,EAAE,iBAAiB,CAAC,QAAQ,CAAC;SACvC;QACD,MAAM,EAAE,QAAQ;KACjB,CAAC;IAEF,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAEhD,IAAI,UAAU,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,6BAA6B,UAAU,EAAE,CAAC,CAAC;IACzD,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Problem } from '../../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Build SARIF format object from problems
|
|
4
|
+
*/
|
|
5
|
+
export declare function buildSarif(problems: Problem[]): any;
|
|
6
|
+
/**
|
|
7
|
+
* Output problems in SARIF format to file or stdout
|
|
8
|
+
*/
|
|
9
|
+
export declare function outputSarifFormat(problems: Problem[], outputPath?: string): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=sarif.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sarif.d.ts","sourceRoot":"","sources":["../../../src/reporter/formats/sarif.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAQpD;;GAEG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,GAAG,CA0CnD;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW/F"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
const SEVERITY_TO_LEVEL = {
|
|
3
|
+
error: 'error',
|
|
4
|
+
warn: 'warning',
|
|
5
|
+
info: 'note',
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Build SARIF format object from problems
|
|
9
|
+
*/
|
|
10
|
+
export function buildSarif(problems) {
|
|
11
|
+
const rulesMap = new Map();
|
|
12
|
+
for (const problem of problems) {
|
|
13
|
+
if (!rulesMap.has(problem.ruleName)) {
|
|
14
|
+
rulesMap.set(problem.ruleName, {
|
|
15
|
+
id: problem.ruleName,
|
|
16
|
+
shortDescription: { text: problem.ruleName.replace('recheck/', '') },
|
|
17
|
+
helpUri: undefined,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const results = problems.map((h) => ({
|
|
22
|
+
ruleId: h.ruleName,
|
|
23
|
+
level: SEVERITY_TO_LEVEL[h.severity] ?? 'warning',
|
|
24
|
+
message: { text: h.message },
|
|
25
|
+
locations: [
|
|
26
|
+
{
|
|
27
|
+
physicalLocation: {
|
|
28
|
+
artifactLocation: { uri: h.file },
|
|
29
|
+
region: { startLine: h.line, startColumn: h.column },
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
}));
|
|
34
|
+
return {
|
|
35
|
+
$schema: 'https://json.schemastore.org/sarif-2.1.0.json',
|
|
36
|
+
version: '2.1.0',
|
|
37
|
+
runs: [
|
|
38
|
+
{
|
|
39
|
+
tool: {
|
|
40
|
+
driver: {
|
|
41
|
+
name: 'recheck',
|
|
42
|
+
informationUri: 'https://redocly.com',
|
|
43
|
+
rules: Array.from(rulesMap.values()),
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
results,
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Output problems in SARIF format to file or stdout
|
|
53
|
+
*/
|
|
54
|
+
export async function outputSarifFormat(problems, outputPath) {
|
|
55
|
+
const sarif = buildSarif(problems);
|
|
56
|
+
const content = JSON.stringify(sarif, null, 2);
|
|
57
|
+
if (outputPath && outputPath.length > 0) {
|
|
58
|
+
await fs.writeFile(outputPath, content, 'utf8');
|
|
59
|
+
console.log(`\n Wrote SARIF to ${outputPath}`);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// Print to stdout; note: other logs may be mixed in unless you redirect only this call's output
|
|
63
|
+
console.log('\n' + content);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=sarif.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sarif.js","sourceRoot":"","sources":["../../../src/reporter/formats/sarif.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAIlC,MAAM,iBAAiB,GAAiD;IACtE,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,SAAS;IACf,IAAI,EAAE,MAAM;CACb,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,QAAmB;IAC5C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAe,CAAC;IACxC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACpC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE;gBAC7B,EAAE,EAAE,OAAO,CAAC,QAAQ;gBACpB,gBAAgB,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,EAAE;gBACpE,OAAO,EAAE,SAAS;aACnB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACnC,MAAM,EAAE,CAAC,CAAC,QAAQ;QAClB,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,SAAS;QACjD,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE;QAC5B,SAAS,EAAE;YACT;gBACE,gBAAgB,EAAE;oBAChB,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE;oBACjC,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;iBACrD;aACF;SACF;KACF,CAAC,CAAC,CAAC;IAEJ,OAAO;QACL,OAAO,EAAE,+CAA+C;QACxD,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE;YACJ;gBACE,IAAI,EAAE;oBACJ,MAAM,EAAE;wBACN,IAAI,EAAE,SAAS;wBACf,cAAc,EAAE,qBAAqB;wBACrC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;qBACrC;iBACF;gBACD,OAAO;aACR;SACF;KACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,QAAmB,EAAE,UAAmB;IAC9E,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAE/C,IAAI,UAAU,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,uBAAuB,UAAU,EAAE,CAAC,CAAC;IACnD,CAAC;SAAM,CAAC;QACN,gGAAgG;QAChG,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,CAAC;IAC9B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../src/reporter/formats/table.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAIpD;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,OAAO,EAAE,EACnB,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,OAAO,GAClB,IAAI,CAqCN"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { red, green, yellow, cyan } from 'colorette';
|
|
2
|
+
import { showDetailedStats } from '../statistics.js';
|
|
3
|
+
/**
|
|
4
|
+
* Output problems in table format to console
|
|
5
|
+
*/
|
|
6
|
+
export function outputTableFormat(problems, fileCount, showStats) {
|
|
7
|
+
if (problems.length === 0) {
|
|
8
|
+
console.log(green('\n🎉 No issues found!'));
|
|
9
|
+
if (showStats) {
|
|
10
|
+
console.log(`\n📊 Summary: ${fileCount} file(s) scanned, 0 issues found.`);
|
|
11
|
+
}
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
// Table format
|
|
15
|
+
console.log(cyan(`\n📋 Found ${problems.length} issue(s):\n`));
|
|
16
|
+
for (const problem of problems) {
|
|
17
|
+
const severityColor = problem.severity === 'error' ? red : problem.severity === 'warn' ? yellow : cyan;
|
|
18
|
+
const location = `${problem.file}:${problem.line}:${problem.column}`;
|
|
19
|
+
const ruleDisplay = problem.ruleName.replace('recheck/', '');
|
|
20
|
+
console.log(`${severityColor(ruleDisplay.padEnd(25))} ${location.padEnd(40)} ${problem.message}`);
|
|
21
|
+
}
|
|
22
|
+
// Summary
|
|
23
|
+
const errorCount = problems.filter((h) => h.severity === 'error').length;
|
|
24
|
+
const warnCount = problems.filter((h) => h.severity === 'warn').length;
|
|
25
|
+
const infoCount = problems.filter((h) => h.severity === 'info').length;
|
|
26
|
+
console.log('');
|
|
27
|
+
if (errorCount > 0)
|
|
28
|
+
console.log(red(` ${errorCount} error(s)`));
|
|
29
|
+
if (warnCount > 0)
|
|
30
|
+
console.log(yellow(` ${warnCount} warning(s)`));
|
|
31
|
+
if (infoCount > 0)
|
|
32
|
+
console.log(cyan(` ${infoCount} info message(s)`));
|
|
33
|
+
// Show detailed statistics if requested
|
|
34
|
+
if (showStats) {
|
|
35
|
+
showDetailedStats(fileCount, problems);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table.js","sourceRoot":"","sources":["../../../src/reporter/formats/table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAmB,EACnB,SAAiB,EACjB,SAAmB;IAEnB,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC,CAAC;QAC5C,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,iBAAiB,SAAS,mCAAmC,CAAC,CAAC;QAC7E,CAAC;QACD,OAAO;IACT,CAAC;IAED,eAAe;IACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,QAAQ,CAAC,MAAM,cAAc,CAAC,CAAC,CAAC;IAE/D,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,aAAa,GACjB,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QACnF,MAAM,QAAQ,GAAG,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACrE,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;QAE7D,OAAO,CAAC,GAAG,CACT,GAAG,aAAa,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CACrF,CAAC;IACJ,CAAC;IAED,UAAU;IACV,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IACzE,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IACvE,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,MAAM,CAAC;IAEvE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,IAAI,UAAU,GAAG,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,UAAU,WAAW,CAAC,CAAC,CAAC;IAClE,IAAI,SAAS,GAAG,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,SAAS,aAAa,CAAC,CAAC,CAAC;IACrE,IAAI,SAAS,GAAG,CAAC;QAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,SAAS,kBAAkB,CAAC,CAAC,CAAC;IAExE,wCAAwC;IACxC,IAAI,SAAS,EAAE,CAAC;QACd,iBAAiB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACzC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Problem, ReportOptions } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generate report in the specified format
|
|
4
|
+
*/
|
|
5
|
+
export declare function generateReport(problems: Problem[], fileCount: number, options: ReportOptions): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* Generate empty report for cases where no files are found
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateEmptyReport(options: ReportOptions): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/reporter/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAQhE;;GAEG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,OAAO,EAAE,EACnB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,IAAI,CAAC,CA8Bf;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/E"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { prioritizeProblems } from './prioritize-problems.js';
|
|
2
|
+
import { outputTableFormat } from './formats/table.js';
|
|
3
|
+
import { outputJsonFormat } from './formats/json.js';
|
|
4
|
+
import { outputSarifFormat } from './formats/sarif.js';
|
|
5
|
+
import { outputGitHubActionsFormat } from './formats/github-actions.js';
|
|
6
|
+
/**
|
|
7
|
+
* Generate report in the specified format
|
|
8
|
+
*/
|
|
9
|
+
export async function generateReport(problems, fileCount, options) {
|
|
10
|
+
const { format, showStats, annotationsLimit, outputPath } = options;
|
|
11
|
+
const prioritized = typeof annotationsLimit === 'number'
|
|
12
|
+
? prioritizeProblems(problems, annotationsLimit)
|
|
13
|
+
: problems;
|
|
14
|
+
switch (format) {
|
|
15
|
+
case 'sarif':
|
|
16
|
+
await outputSarifFormat(prioritized, outputPath);
|
|
17
|
+
break;
|
|
18
|
+
case 'github-actions':
|
|
19
|
+
outputGitHubActionsFormat(prioritized);
|
|
20
|
+
break;
|
|
21
|
+
case 'json':
|
|
22
|
+
await outputJsonFormat(prioritized, fileCount, outputPath);
|
|
23
|
+
break;
|
|
24
|
+
default:
|
|
25
|
+
outputTableFormat(problems, fileCount, showStats);
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
if (prioritized.length > 0) {
|
|
29
|
+
const limitInfoEnd = typeof options.annotationsLimit === 'number' ? ` (limit ${options.annotationsLimit})` : '';
|
|
30
|
+
console.log(`\n Annotations prepared: ${prioritized.length}${limitInfoEnd}`);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
console.log(`\n Annotations prepared: 0`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Generate empty report for cases where no files are found
|
|
38
|
+
*/
|
|
39
|
+
export async function generateEmptyReport(options) {
|
|
40
|
+
await generateReport([], 0, options);
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/reporter/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAExE;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAmB,EACnB,SAAiB,EACjB,OAAsB;IAEtB,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,gBAAgB,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;IAEpE,MAAM,WAAW,GACf,OAAO,gBAAgB,KAAK,QAAQ;QAClC,CAAC,CAAC,kBAAkB,CAAC,QAAQ,EAAE,gBAAgB,CAAC;QAChD,CAAC,CAAC,QAAQ,CAAC;IAEf,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,OAAO;YACV,MAAM,iBAAiB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;YACjD,MAAM;QACR,KAAK,gBAAgB;YACnB,yBAAyB,CAAC,WAAW,CAAC,CAAC;YACvC,MAAM;QACR,KAAK,MAAM;YACT,MAAM,gBAAgB,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;YAC3D,MAAM;QACR;YACE,iBAAiB,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;YAClD,MAAM;IACV,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,YAAY,GAChB,OAAO,OAAO,CAAC,gBAAgB,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,OAAO,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7F,OAAO,CAAC,GAAG,CAAC,8BAA8B,WAAW,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC,CAAC;IACjF,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAsB;IAC9D,MAAM,cAAc,CAAC,EAAE,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Problem } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Prioritize problems by severity (error > warn > info) and cap to a limit if provided.
|
|
4
|
+
* This is intended for CI annotations (e.g., SARIF) and does not affect CLI output.
|
|
5
|
+
*/
|
|
6
|
+
export declare function prioritizeProblems(problems: Problem[], limit?: number): Problem[];
|
|
7
|
+
//# sourceMappingURL=prioritize-problems.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prioritize-problems.d.ts","sourceRoot":"","sources":["../../src/reporter/prioritize-problems.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAQjD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,EAAE,CAgBjF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const SEVERITY_ORDER = {
|
|
2
|
+
error: 2,
|
|
3
|
+
warn: 1,
|
|
4
|
+
info: 0,
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Prioritize problems by severity (error > warn > info) and cap to a limit if provided.
|
|
8
|
+
* This is intended for CI annotations (e.g., SARIF) and does not affect CLI output.
|
|
9
|
+
*/
|
|
10
|
+
export function prioritizeProblems(problems, limit) {
|
|
11
|
+
if (problems.length === 0)
|
|
12
|
+
return [];
|
|
13
|
+
const sorted = [...problems].sort((a, b) => {
|
|
14
|
+
const sa = SEVERITY_ORDER[a.severity] ?? 0;
|
|
15
|
+
const sb = SEVERITY_ORDER[b.severity] ?? 0;
|
|
16
|
+
if (sb !== sa)
|
|
17
|
+
return sb - sa;
|
|
18
|
+
// Stable-ish tiebreaker: file then line then column
|
|
19
|
+
if (a.file !== b.file)
|
|
20
|
+
return a.file.localeCompare(b.file);
|
|
21
|
+
if (a.line !== b.line)
|
|
22
|
+
return a.line - b.line;
|
|
23
|
+
return a.column - b.column;
|
|
24
|
+
});
|
|
25
|
+
if (typeof limit === 'number' && limit >= 0)
|
|
26
|
+
return sorted.slice(0, limit);
|
|
27
|
+
return sorted;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=prioritize-problems.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prioritize-problems.js","sourceRoot":"","sources":["../../src/reporter/prioritize-problems.ts"],"names":[],"mappings":"AAEA,MAAM,cAAc,GAA2B;IAC7C,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;CACR,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAmB,EAAE,KAAc;IACpE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,MAAM,MAAM,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACzC,MAAM,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,GAAG,EAAE,CAAC;QAE9B,oDAAoD;QACpD,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC3D,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI;YAAE,OAAO,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC;QAC9C,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC3E,OAAO,MAAM,CAAC;AAChB,CAAC"}
|