markuplint 5.0.0-alpha.1 → 5.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/lib/api/ml-engine.d.ts +0 -10
- package/lib/api/ml-engine.js +31 -34
- package/lib/api/types.d.ts +4 -2
- package/lib/cli/bootstrap.d.ts +5 -1
- package/lib/cli/bootstrap.js +5 -0
- package/lib/cli/command.js +11 -2
- package/lib/cli/dry-run-output.d.ts +9 -0
- package/lib/cli/dry-run-output.js +15 -0
- package/lib/reporter/github-reporter.js +1 -1
- package/lib/reporter/simple-reporter.js +2 -2
- package/lib/reporter/standard-reporter.js +2 -2
- package/lib/testing-tool/index.d.ts +2 -0
- package/lib/testing-tool/index.js +1 -0
- package/lib/types.d.ts +4 -1
- package/package.json +13 -13
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,20 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [5.0.0-alpha.3](https://github.com/markuplint/markuplint/compare/v5.0.0-alpha.2...v5.0.0-alpha.3) (2026-02-26)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- **markuplint:** add --fix-dry-run CLI flag and fix summary passthrough ([ecd4550](https://github.com/markuplint/markuplint/commit/ecd455042d732f950b16ca79c283bd95dc3c2a72))
|
|
11
|
+
- **markuplint:** add fixSummary to lint event and fixable test fixtures ([287a8be](https://github.com/markuplint/markuplint/commit/287a8be7d96e121115e357f1696314dd6b0f1a1c))
|
|
12
|
+
- **markuplint:** display specConformance in CLI reporters ([aaae2de](https://github.com/markuplint/markuplint/commit/aaae2de8166d6b6151f7c397ba7cd99d4a867442))
|
|
13
|
+
|
|
14
|
+
# [5.0.0-alpha.2](https://github.com/markuplint/markuplint/compare/v5.0.0-alpha.1...v5.0.0-alpha.2) (2026-02-23)
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
- **markuplint:** integrate autofix results into MLEngine ([1558a5c](https://github.com/markuplint/markuplint/commit/1558a5cbdddda6845cf2570252920f5c489a6acc))
|
|
19
|
+
|
|
6
20
|
# [5.0.0-alpha.1](https://github.com/markuplint/markuplint/compare/v5.0.0-alpha.0...v5.0.0-alpha.1) (2026-02-22)
|
|
7
21
|
|
|
8
22
|
**Note:** Version bump only for package markuplint
|
package/lib/api/ml-engine.d.ts
CHANGED
|
@@ -70,16 +70,6 @@ export declare class MLEngine extends Emitter<MLEngineEventMap> {
|
|
|
70
70
|
* @param enable - Whether to enable watch mode
|
|
71
71
|
*/
|
|
72
72
|
watchMode(enable: boolean): void;
|
|
73
|
-
private createCore;
|
|
74
|
-
private i18n;
|
|
75
|
-
private onChange;
|
|
76
|
-
private provide;
|
|
77
73
|
resolveConfig(cache: boolean): Promise<ConfigSet>;
|
|
78
|
-
private resolveParser;
|
|
79
|
-
private resolvePretenders;
|
|
80
|
-
private resolveRules;
|
|
81
|
-
private resolveRuleset;
|
|
82
|
-
private resolveSchemas;
|
|
83
|
-
private setup;
|
|
84
74
|
}
|
|
85
75
|
export {};
|
package/lib/api/ml-engine.js
CHANGED
|
@@ -90,22 +90,21 @@ export class MLEngine extends Emitter {
|
|
|
90
90
|
*/
|
|
91
91
|
async exec() {
|
|
92
92
|
log('exec: start');
|
|
93
|
-
const core = await this
|
|
93
|
+
const core = await this.#setup();
|
|
94
94
|
if (!core) {
|
|
95
95
|
log('exec: cancel (unsetuped yet)');
|
|
96
96
|
return null;
|
|
97
97
|
}
|
|
98
|
-
const
|
|
98
|
+
const verifyResult = await core.verify({ fix: this.#options?.fix ?? false }).catch(error => {
|
|
99
99
|
if (error instanceof Error) {
|
|
100
100
|
return error;
|
|
101
101
|
}
|
|
102
102
|
throw error;
|
|
103
103
|
});
|
|
104
104
|
const sourceCode = await this.#file.getCode();
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const errMessage = violations.stack ?? violations.message;
|
|
105
|
+
if (verifyResult instanceof Error) {
|
|
106
|
+
this.emit('lint-error', this.#file.path, sourceCode, verifyResult);
|
|
107
|
+
const errMessage = verifyResult.stack ?? verifyResult.message;
|
|
109
108
|
log('exec: error %O', errMessage);
|
|
110
109
|
return {
|
|
111
110
|
violations: [
|
|
@@ -120,19 +119,22 @@ export class MLEngine extends Emitter {
|
|
|
120
119
|
],
|
|
121
120
|
filePath: this.#file.path,
|
|
122
121
|
sourceCode,
|
|
123
|
-
fixedCode,
|
|
122
|
+
fixedCode: sourceCode,
|
|
124
123
|
status: 'processed',
|
|
125
124
|
};
|
|
126
125
|
}
|
|
126
|
+
const { violations, fixedCode, fixSummary } = verifyResult;
|
|
127
127
|
const debugMap = 'debugMap' in core.document ? core.document.debugMap() : null;
|
|
128
|
-
|
|
128
|
+
const resolvedFixedCode = fixedCode ?? sourceCode;
|
|
129
|
+
this.emit('lint', this.#file.path, sourceCode, violations, resolvedFixedCode, debugMap, fixSummary ?? null);
|
|
129
130
|
log('exec: end');
|
|
130
131
|
return {
|
|
131
|
-
violations,
|
|
132
|
+
violations: [...violations],
|
|
132
133
|
filePath: this.#file.path,
|
|
133
134
|
sourceCode,
|
|
134
|
-
fixedCode,
|
|
135
|
+
fixedCode: resolvedFixedCode,
|
|
135
136
|
status: 'processed',
|
|
137
|
+
fixSummary,
|
|
136
138
|
};
|
|
137
139
|
}
|
|
138
140
|
/**
|
|
@@ -141,7 +143,7 @@ export class MLEngine extends Emitter {
|
|
|
141
143
|
* @param code - The new markup source code
|
|
142
144
|
*/
|
|
143
145
|
async setCode(code) {
|
|
144
|
-
const core = await this
|
|
146
|
+
const core = await this.#setup();
|
|
145
147
|
if (!core) {
|
|
146
148
|
return;
|
|
147
149
|
}
|
|
@@ -160,13 +162,13 @@ export class MLEngine extends Emitter {
|
|
|
160
162
|
watch: enable,
|
|
161
163
|
};
|
|
162
164
|
if (enable) {
|
|
163
|
-
this.#watcher.on('change', this
|
|
165
|
+
this.#watcher.on('change', this.#onChange.bind(this));
|
|
164
166
|
}
|
|
165
167
|
else {
|
|
166
168
|
this.#watcher.removeAllListeners();
|
|
167
169
|
}
|
|
168
170
|
}
|
|
169
|
-
async createCore(fabric) {
|
|
171
|
+
async #createCore(fabric) {
|
|
170
172
|
fileLog('Get source code');
|
|
171
173
|
const sourceCode = await this.#file.getCode();
|
|
172
174
|
fileLog('Source code path: %s', this.#file.path);
|
|
@@ -182,17 +184,12 @@ export class MLEngine extends Emitter {
|
|
|
182
184
|
this.#core = core;
|
|
183
185
|
return core;
|
|
184
186
|
}
|
|
185
|
-
|
|
186
|
-
const i18nSettings = i18n(this.#options?.locale);
|
|
187
|
-
this.emit('i18n', this.#file.path, i18nSettings);
|
|
188
|
-
return i18nSettings;
|
|
189
|
-
}
|
|
190
|
-
async onChange(filePath) {
|
|
187
|
+
async #onChange(filePath) {
|
|
191
188
|
if (!this.#options?.watch) {
|
|
192
189
|
return;
|
|
193
190
|
}
|
|
194
191
|
this.emit('log', 'watch:onChange', filePath);
|
|
195
|
-
const fabric = await this
|
|
192
|
+
const fabric = await this.#provide(false);
|
|
196
193
|
if (!fabric) {
|
|
197
194
|
return;
|
|
198
195
|
}
|
|
@@ -203,7 +200,7 @@ export class MLEngine extends Emitter {
|
|
|
203
200
|
this.#core?.update(fabric);
|
|
204
201
|
await this.exec();
|
|
205
202
|
}
|
|
206
|
-
async provide(cache = true) {
|
|
203
|
+
async #provide(cache = true) {
|
|
207
204
|
let configSet;
|
|
208
205
|
try {
|
|
209
206
|
configSet = await this.resolveConfig(cache);
|
|
@@ -236,7 +233,7 @@ export class MLEngine extends Emitter {
|
|
|
236
233
|
fileLog('Excludes the file: %s', this.#file.path);
|
|
237
234
|
return null;
|
|
238
235
|
}
|
|
239
|
-
const { parser, parserOptions, matched } = await this
|
|
236
|
+
const { parser, parserOptions, matched } = await this.#resolveParser(configSet);
|
|
240
237
|
const checkingExt = !this.#options?.ignoreExt;
|
|
241
238
|
if (checkingExt && !matched) {
|
|
242
239
|
this.emit('log', 'ext-unmatched', `Avoided linting because a file is unmatched by the extension: ${this.#file.path}`);
|
|
@@ -247,11 +244,11 @@ export class MLEngine extends Emitter {
|
|
|
247
244
|
...configSet.config.severity,
|
|
248
245
|
...this.#options?.severity,
|
|
249
246
|
};
|
|
250
|
-
const pretenders = await this
|
|
247
|
+
const pretenders = await this.#resolvePretenders(configSet);
|
|
251
248
|
fileLog('Resolved pretenders: %O', pretenders);
|
|
252
|
-
const ruleset = this
|
|
249
|
+
const ruleset = this.#resolveRuleset(configSet);
|
|
253
250
|
fileLog('Resolved ruleset: %O', ruleset);
|
|
254
|
-
const schemas = await this
|
|
251
|
+
const schemas = await this.#resolveSchemas(configSet);
|
|
255
252
|
if (fileLog.enabled) {
|
|
256
253
|
if (schemas[0].cites.length > 0) {
|
|
257
254
|
const [, ...additionalSpecs] = schemas;
|
|
@@ -264,7 +261,7 @@ export class MLEngine extends Emitter {
|
|
|
264
261
|
fileLog('Resolved schemas: %O', schemas);
|
|
265
262
|
}
|
|
266
263
|
}
|
|
267
|
-
const rules = await this
|
|
264
|
+
const rules = await this.#resolveRules(configSet.plugins, ruleset);
|
|
268
265
|
fileLog('Resolved rules: %O', rules);
|
|
269
266
|
const locale = i18n(this.#options?.locale);
|
|
270
267
|
const ruleCommonSettings = configSet.config.ruleCommonSettings ?? {};
|
|
@@ -316,7 +313,7 @@ export class MLEngine extends Emitter {
|
|
|
316
313
|
}
|
|
317
314
|
return configSet;
|
|
318
315
|
}
|
|
319
|
-
async resolveParser(
|
|
316
|
+
async #resolveParser(
|
|
320
317
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
321
318
|
configSet) {
|
|
322
319
|
const parser = await resolveParser(this.#file, configSet.config.parser, configSet.config.parserOptions);
|
|
@@ -324,14 +321,14 @@ export class MLEngine extends Emitter {
|
|
|
324
321
|
fileLog('Fetched Parser module: %s', parser.parserModName);
|
|
325
322
|
return parser;
|
|
326
323
|
}
|
|
327
|
-
async resolvePretenders(
|
|
324
|
+
async #resolvePretenders(
|
|
328
325
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
329
326
|
configSet) {
|
|
330
327
|
const pretenders = await resolvePretenders(configSet.config.pretenders);
|
|
331
328
|
fileLog('Resolved pretenders: %O', pretenders);
|
|
332
329
|
return pretenders;
|
|
333
330
|
}
|
|
334
|
-
async resolveRules(plugins, ruleset) {
|
|
331
|
+
async #resolveRules(plugins, ruleset) {
|
|
335
332
|
const rules = await resolveRules(plugins, ruleset, this.#options?.importPresetRules ?? true, this.#options?.autoLoad ?? true);
|
|
336
333
|
if (this.#options?.rules) {
|
|
337
334
|
rules.push(...this.#options.rules);
|
|
@@ -339,31 +336,31 @@ export class MLEngine extends Emitter {
|
|
|
339
336
|
this.emit('rules', this.#file.path, rules);
|
|
340
337
|
return rules;
|
|
341
338
|
}
|
|
342
|
-
resolveRuleset(
|
|
339
|
+
#resolveRuleset(
|
|
343
340
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
344
341
|
configSet) {
|
|
345
342
|
const ruleset = convertRuleset(configSet.config);
|
|
346
343
|
this.emit('ruleset', this.#file.path, ruleset);
|
|
347
344
|
return ruleset;
|
|
348
345
|
}
|
|
349
|
-
async resolveSchemas(
|
|
346
|
+
async #resolveSchemas(
|
|
350
347
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
351
348
|
configSet) {
|
|
352
349
|
const { schemas } = await resolveSpecs(this.#file.path, configSet.config.specs);
|
|
353
350
|
this.emit('schemas', this.#file.path, schemas);
|
|
354
351
|
return schemas;
|
|
355
352
|
}
|
|
356
|
-
async setup() {
|
|
353
|
+
async #setup() {
|
|
357
354
|
if (this.#core) {
|
|
358
355
|
return this.#core;
|
|
359
356
|
}
|
|
360
|
-
const fabric = await this
|
|
357
|
+
const fabric = await this.#provide();
|
|
361
358
|
if (!fabric) {
|
|
362
359
|
return null;
|
|
363
360
|
}
|
|
364
361
|
if (fabric.configErrors) {
|
|
365
362
|
this.emit('config-errors', this.#file.path, fabric.configErrors);
|
|
366
363
|
}
|
|
367
|
-
return this
|
|
364
|
+
return this.#createCore(fabric);
|
|
368
365
|
}
|
|
369
366
|
}
|
package/lib/api/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ConfigSet } from '@markuplint/file-resolver';
|
|
2
2
|
import type { LocaleSet } from '@markuplint/i18n';
|
|
3
3
|
import type { Config, SeverityOptions, Violation } from '@markuplint/ml-config';
|
|
4
|
-
import type { AnyMLRule, MLSchema, Ruleset } from '@markuplint/ml-core';
|
|
4
|
+
import type { AnyMLRule, FixSummary, MLSchema, Ruleset } from '@markuplint/ml-core';
|
|
5
5
|
/**
|
|
6
6
|
* Options for the markuplint API, controlling configuration, locale, rules, and behavior.
|
|
7
7
|
*/
|
|
@@ -12,6 +12,8 @@ export type APIOptions = {
|
|
|
12
12
|
readonly noSearchConfig?: boolean;
|
|
13
13
|
readonly locale?: string;
|
|
14
14
|
readonly fix?: boolean;
|
|
15
|
+
/** When true, compute fixes without writing files (CLI dry-run mode). */
|
|
16
|
+
readonly fixDryRun?: boolean;
|
|
15
17
|
readonly ignoreExt?: boolean;
|
|
16
18
|
readonly rules?: readonly Readonly<AnyMLRule>[];
|
|
17
19
|
readonly importPresetRules?: boolean;
|
|
@@ -40,7 +42,7 @@ export type MLEngineEventMap = {
|
|
|
40
42
|
violations: readonly Violation[],
|
|
41
43
|
fixedCode: string,
|
|
42
44
|
debug: readonly string[] | null,
|
|
43
|
-
|
|
45
|
+
fixSummary: FixSummary | null
|
|
44
46
|
];
|
|
45
47
|
'lint-error': [filePath: string, sourceCode: string, error: Readonly<Error>];
|
|
46
48
|
'config-errors': [filePath: string, errors: readonly Readonly<Error>[]];
|
package/lib/cli/bootstrap.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ReadonlyDeep } from 'type-fest';
|
|
|
3
3
|
* Help text displayed when the CLI is invoked with `--help` or without arguments.
|
|
4
4
|
* Documents all available options, flags, and usage examples.
|
|
5
5
|
*/
|
|
6
|
-
export declare const help = "\nUsage\n\t$ markuplint <HTML file paths (glob format)>\n\t$ <stdout> | markuplint\n\nOptions\n\t--config, -c FILE_PATH A configuration file path.\n\t--fix, Fix HTML.\n\t--format, -f FORMAT Output format. Support \"JSON\", \"Simple\", \"GitHub\" and \"Standard\". Default: \"Standard\".\n\t--no-search-config No search a configure file automatically.\n\t--ignore-ext Evaluate files that are received even though the type of extension.\n\t--no-import-preset-rules No import preset rules.\n\t--locale Locale of the message of violation. Default is an OS setting.\n\t--no-color, Output no color.\n\t--problem-only, -p Output only problems, without passeds.\n\t--no-allow-warnings Return status code 1 even if there are warnings.\n\t--allow-empty-input Return status code 1 even if there are no input files.\n\t--show-config Output computed configuration of the target file. Supports \"details\" and empty. Default: empty.\n\t--verbose Output with detailed information.\n\t--include-node-modules Include files in node_modules directory. Default: false.\n\t--severity-parse-error Specifies the severity level of parse errors. Supports \"error\", \"warning\", and \"off\". Default: \"error\".\n\t--max-count Limit the number of violations shown. Default: 0 (no limit).\n\t--max-warnings Number of warnings to trigger nonzero exit code. Default: -1 (no limit).\n\t--progressive-output Output results immediately after processing each file. Default: false.\n\n\t--init Initialize settings interactively.\n\t--search Search lines of codes that include the target element by selectors.\n\n\t--help, -h Show help.\n\t--version, -v Show version.\n\nExamples\n\t$ markuplint verifyee.html --config path/to/.markuplintrc\n\t$ cat verifyee.html | markuplint\n";
|
|
6
|
+
export declare const help = "\nUsage\n\t$ markuplint <HTML file paths (glob format)>\n\t$ <stdout> | markuplint\n\nOptions\n\t--config, -c FILE_PATH A configuration file path.\n\t--fix, Fix HTML.\n\t--fix-dry-run Show what --fix would change without writing files.\n\t--format, -f FORMAT Output format. Support \"JSON\", \"Simple\", \"GitHub\" and \"Standard\". Default: \"Standard\".\n\t--no-search-config No search a configure file automatically.\n\t--ignore-ext Evaluate files that are received even though the type of extension.\n\t--no-import-preset-rules No import preset rules.\n\t--locale Locale of the message of violation. Default is an OS setting.\n\t--no-color, Output no color.\n\t--problem-only, -p Output only problems, without passeds.\n\t--no-allow-warnings Return status code 1 even if there are warnings.\n\t--allow-empty-input Return status code 1 even if there are no input files.\n\t--show-config Output computed configuration of the target file. Supports \"details\" and empty. Default: empty.\n\t--verbose Output with detailed information.\n\t--include-node-modules Include files in node_modules directory. Default: false.\n\t--severity-parse-error Specifies the severity level of parse errors. Supports \"error\", \"warning\", and \"off\". Default: \"error\".\n\t--max-count Limit the number of violations shown. Default: 0 (no limit).\n\t--max-warnings Number of warnings to trigger nonzero exit code. Default: -1 (no limit).\n\t--progressive-output Output results immediately after processing each file. Default: false.\n\n\t--init Initialize settings interactively.\n\t--search Search lines of codes that include the target element by selectors.\n\n\t--help, -h Show help.\n\t--version, -v Show version.\n\nExamples\n\t$ markuplint verifyee.html --config path/to/.markuplintrc\n\t$ cat verifyee.html | markuplint\n";
|
|
7
7
|
/**
|
|
8
8
|
* The parsed CLI instance created by `meow`, providing access to
|
|
9
9
|
* positional arguments (`cli.input`) and parsed flags (`cli.flags`).
|
|
@@ -17,6 +17,10 @@ export declare const cli: import("meow").Result<{
|
|
|
17
17
|
type: "boolean";
|
|
18
18
|
default: false;
|
|
19
19
|
};
|
|
20
|
+
fixDryRun: {
|
|
21
|
+
type: "boolean";
|
|
22
|
+
default: false;
|
|
23
|
+
};
|
|
20
24
|
format: {
|
|
21
25
|
type: "string";
|
|
22
26
|
shortFlag: string;
|
package/lib/cli/bootstrap.js
CHANGED
|
@@ -11,6 +11,7 @@ Usage
|
|
|
11
11
|
Options
|
|
12
12
|
--config, -c FILE_PATH A configuration file path.
|
|
13
13
|
--fix, Fix HTML.
|
|
14
|
+
--fix-dry-run Show what --fix would change without writing files.
|
|
14
15
|
--format, -f FORMAT Output format. Support "JSON", "Simple", "GitHub" and "Standard". Default: "Standard".
|
|
15
16
|
--no-search-config No search a configure file automatically.
|
|
16
17
|
--ignore-ext Evaluate files that are received even though the type of extension.
|
|
@@ -53,6 +54,10 @@ export const cli = meow(help, {
|
|
|
53
54
|
type: 'boolean',
|
|
54
55
|
default: false,
|
|
55
56
|
},
|
|
57
|
+
fixDryRun: {
|
|
58
|
+
type: 'boolean',
|
|
59
|
+
default: false,
|
|
60
|
+
},
|
|
56
61
|
format: {
|
|
57
62
|
type: 'string',
|
|
58
63
|
shortFlag: 'f',
|
package/lib/cli/command.js
CHANGED
|
@@ -4,6 +4,7 @@ import { resolveFiles } from '@markuplint/file-resolver';
|
|
|
4
4
|
import { ViolationCollector } from '@markuplint/ml-core';
|
|
5
5
|
import { MLEngine } from '../api/index.js';
|
|
6
6
|
import { log } from '../debug.js';
|
|
7
|
+
import { outputDryRunDiff } from './dry-run-output.js';
|
|
7
8
|
import { output } from './output.js';
|
|
8
9
|
/**
|
|
9
10
|
* Executes the markuplint linting command against the given files.
|
|
@@ -18,7 +19,12 @@ import { output } from './output.js';
|
|
|
18
19
|
* @returns `true` if any errors were found (or warnings exceeded the limit), `false` otherwise.
|
|
19
20
|
*/
|
|
20
21
|
export async function command(files, options, apiOptions) {
|
|
21
|
-
const
|
|
22
|
+
const fixDryRun = options.fixDryRun;
|
|
23
|
+
if (options.fix && fixDryRun) {
|
|
24
|
+
log('Both --fix and --fix-dry-run specified; --fix-dry-run takes precedence');
|
|
25
|
+
process.stderr.write('Warning: --fix-dry-run takes precedence over --fix. Files will not be modified.\n');
|
|
26
|
+
}
|
|
27
|
+
const fix = options.fix || fixDryRun;
|
|
22
28
|
const configFile = options.config &&
|
|
23
29
|
(path.isAbsolute(options.config) ? options.config : path.resolve(process.cwd(), options.config));
|
|
24
30
|
const locale = options.locale;
|
|
@@ -123,10 +129,13 @@ export async function command(files, options, apiOptions) {
|
|
|
123
129
|
if (!hasError && (errorCount > 0 || (warningCount > 0 && !options.allowWarnings))) {
|
|
124
130
|
hasError = true;
|
|
125
131
|
}
|
|
126
|
-
if (fix) {
|
|
132
|
+
if (fix && !fixDryRun) {
|
|
127
133
|
log('Overwrite file: %s', result.filePath);
|
|
128
134
|
await fs.writeFile(result.filePath, result.fixedCode, { encoding: 'utf8' });
|
|
129
135
|
}
|
|
136
|
+
else if (fix && fixDryRun && result.sourceCode !== result.fixedCode) {
|
|
137
|
+
outputDryRunDiff(result.filePath, result.sourceCode, result.fixedCode);
|
|
138
|
+
}
|
|
130
139
|
}
|
|
131
140
|
// Output results
|
|
132
141
|
if (format === 'json') {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outputs a unified diff showing what --fix would change.
|
|
3
|
+
* Writes the diff to stdout if there are differences.
|
|
4
|
+
*
|
|
5
|
+
* @param filePath - File path for the diff header
|
|
6
|
+
* @param original - Original source code
|
|
7
|
+
* @param fixed - Fixed source code after applying fixes
|
|
8
|
+
*/
|
|
9
|
+
export declare function outputDryRunDiff(filePath: string, original: string, fixed: string): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { unifiedDiff } from '@markuplint/cli-utils';
|
|
2
|
+
/**
|
|
3
|
+
* Outputs a unified diff showing what --fix would change.
|
|
4
|
+
* Writes the diff to stdout if there are differences.
|
|
5
|
+
*
|
|
6
|
+
* @param filePath - File path for the diff header
|
|
7
|
+
* @param original - Original source code
|
|
8
|
+
* @param fixed - Fixed source code after applying fixes
|
|
9
|
+
*/
|
|
10
|
+
export function outputDryRunDiff(filePath, original, fixed) {
|
|
11
|
+
const diff = unifiedDiff(filePath, original, fixed);
|
|
12
|
+
if (diff) {
|
|
13
|
+
process.stdout.write(diff + '\n');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -12,7 +12,7 @@ export function githubReporter(results) {
|
|
|
12
12
|
const out = [];
|
|
13
13
|
for (const violation of results.violations) {
|
|
14
14
|
const command = severityToCommand(violation.severity);
|
|
15
|
-
const meg = messageToString(violation.message, violation.reason);
|
|
15
|
+
const meg = messageToString(violation.message, violation.specConformance, violation.reason);
|
|
16
16
|
out.push(`::${command} file=${results.filePath},line=${violation.line},col=${violation.col}::${meg} (${violation.name ?? violation.ruleId})`);
|
|
17
17
|
}
|
|
18
18
|
return out;
|
|
@@ -22,7 +22,7 @@ export function simpleReporter(results, options) {
|
|
|
22
22
|
for (const violation of results.violations) {
|
|
23
23
|
sizes.line = Math.max(sizes.line, violation.line.toString(10).length);
|
|
24
24
|
sizes.col = Math.max(sizes.col, violation.col.toString(10).length);
|
|
25
|
-
const meg = messageToString(violation.message, violation.reason);
|
|
25
|
+
const meg = messageToString(violation.message, violation.specConformance, violation.reason);
|
|
26
26
|
sizes.meg = Math.max(sizes.meg, getWidth(meg));
|
|
27
27
|
}
|
|
28
28
|
const out = [];
|
|
@@ -30,7 +30,7 @@ export function simpleReporter(results, options) {
|
|
|
30
30
|
out.push(`<${commandName}> ${font.underline(results.filePath)}: ${loggerError('✗')}`);
|
|
31
31
|
for (const violation of results.violations) {
|
|
32
32
|
const s = violation.severity === 'error' ? loggerError('✖') : loggerWarning('⚠️');
|
|
33
|
-
const meg = messageToString(violation.message, violation.reason);
|
|
33
|
+
const meg = messageToString(violation.message, violation.specConformance, violation.reason);
|
|
34
34
|
out.push(` ${font.cyan(`${pad(violation.line, sizes.line, true)}:${pad(violation.col, sizes.col)}`)} ${s} ${pad(meg, sizes.meg)} ${xterm(8)(violation.name ?? violation.ruleId)} `);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
@@ -23,7 +23,7 @@ export function standardReporter(results, options) {
|
|
|
23
23
|
for (const violation of results.violations) {
|
|
24
24
|
sizes.line = Math.max(sizes.line, violation.line.toString(10).length);
|
|
25
25
|
sizes.col = Math.max(sizes.col, violation.col.toString(10).length);
|
|
26
|
-
const meg = messageToString(violation.message, violation.reason);
|
|
26
|
+
const meg = messageToString(violation.message, violation.specConformance, violation.reason);
|
|
27
27
|
sizes.meg = Math.max(sizes.meg, getWidth(meg));
|
|
28
28
|
}
|
|
29
29
|
const out = [];
|
|
@@ -31,7 +31,7 @@ export function standardReporter(results, options) {
|
|
|
31
31
|
const lines = results.sourceCode.split(/\r?\n/);
|
|
32
32
|
for (const violation of results.violations) {
|
|
33
33
|
const logger = violation.severity === 'error' ? loggerError : loggerWarning;
|
|
34
|
-
const meg = messageToString(violation.message, violation.reason);
|
|
34
|
+
const meg = messageToString(violation.message, violation.specConformance, violation.reason);
|
|
35
35
|
const startLine = violation.line - 1;
|
|
36
36
|
// Main message
|
|
37
37
|
out.push(`<${commandName}> ${logger(`${violation.severity}: ${meg} (${violation.name ?? violation.ruleId}) ${font.underline(`${results.filePath}:${violation.line}:${violation.col}`)}`)}`);
|
|
@@ -14,6 +14,7 @@ import type { AnyMLRule, RuleSeed } from '@markuplint/ml-core';
|
|
|
14
14
|
export declare function mlTest(sourceCode: string, config: Config, rules?: readonly Readonly<AnyMLRule>[], locale?: string, fix?: boolean): Promise<{
|
|
15
15
|
violations: readonly import("@markuplint/ml-config").Violation[];
|
|
16
16
|
fixedCode: string;
|
|
17
|
+
fixSummary: import("@markuplint/ml-core").FixSummary | undefined;
|
|
17
18
|
}>;
|
|
18
19
|
/**
|
|
19
20
|
* Tests a single rule against inline source code. Designed for rule unit testing.
|
|
@@ -34,6 +35,7 @@ export declare function mlRuleTest<T extends RuleConfigValue, O extends PlainDat
|
|
|
34
35
|
}, fix?: boolean, locale?: string): Promise<{
|
|
35
36
|
violations: readonly import("@markuplint/ml-config").Violation[];
|
|
36
37
|
fixedCode: string;
|
|
38
|
+
fixSummary: import("@markuplint/ml-core").FixSummary | undefined;
|
|
37
39
|
}>;
|
|
38
40
|
/**
|
|
39
41
|
* Lints a file target with a given configuration. Convenience function for integration testing.
|
package/lib/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Config, PlainData, RuleConfigValue, Violation } from '@markuplint/ml-config';
|
|
2
|
-
import type { Document, Ruleset } from '@markuplint/ml-core';
|
|
2
|
+
import type { Document, FixSummary, Ruleset } from '@markuplint/ml-core';
|
|
3
3
|
/**
|
|
4
4
|
* The result of linting a single file, including violations, source code, and fix results.
|
|
5
5
|
*/
|
|
@@ -9,6 +9,8 @@ export interface MLResultInfo {
|
|
|
9
9
|
readonly sourceCode: string;
|
|
10
10
|
readonly fixedCode: string;
|
|
11
11
|
readonly status: 'processed' | 'skipped';
|
|
12
|
+
/** Fix process summary. Present when fix mode was enabled and fixes were found. */
|
|
13
|
+
readonly fixSummary?: FixSummary;
|
|
12
14
|
}
|
|
13
15
|
/**
|
|
14
16
|
* @deprecated
|
|
@@ -28,3 +30,4 @@ export interface MLResultInfo_v1 {
|
|
|
28
30
|
error: string[];
|
|
29
31
|
};
|
|
30
32
|
}
|
|
33
|
+
export { type FixSummary } from '@markuplint/ml-core';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "markuplint",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.3",
|
|
4
4
|
"description": "An HTML linter for all markup developers",
|
|
5
5
|
"author": "Yusuke Hirao",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,17 +26,17 @@
|
|
|
26
26
|
"clean": "tsc --build --clean tsconfig.build.json"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@markuplint/cli-utils": "5.0.0-alpha.
|
|
30
|
-
"@markuplint/file-resolver": "5.0.0-alpha.
|
|
31
|
-
"@markuplint/html-parser": "5.0.0-alpha.
|
|
32
|
-
"@markuplint/html-spec": "5.0.0-alpha.
|
|
33
|
-
"@markuplint/i18n": "5.0.0-alpha.
|
|
34
|
-
"@markuplint/ml-ast": "5.0.0-alpha.
|
|
35
|
-
"@markuplint/ml-config": "5.0.0-alpha.
|
|
36
|
-
"@markuplint/ml-core": "5.0.0-alpha.
|
|
37
|
-
"@markuplint/ml-spec": "5.0.0-alpha.
|
|
38
|
-
"@markuplint/rules": "5.0.0-alpha.
|
|
39
|
-
"@markuplint/shared": "5.0.0-alpha.
|
|
29
|
+
"@markuplint/cli-utils": "5.0.0-alpha.3",
|
|
30
|
+
"@markuplint/file-resolver": "5.0.0-alpha.3",
|
|
31
|
+
"@markuplint/html-parser": "5.0.0-alpha.3",
|
|
32
|
+
"@markuplint/html-spec": "5.0.0-alpha.3",
|
|
33
|
+
"@markuplint/i18n": "5.0.0-alpha.3",
|
|
34
|
+
"@markuplint/ml-ast": "5.0.0-alpha.3",
|
|
35
|
+
"@markuplint/ml-config": "5.0.0-alpha.3",
|
|
36
|
+
"@markuplint/ml-core": "5.0.0-alpha.3",
|
|
37
|
+
"@markuplint/ml-spec": "5.0.0-alpha.3",
|
|
38
|
+
"@markuplint/rules": "5.0.0-alpha.3",
|
|
39
|
+
"@markuplint/shared": "5.0.0-alpha.3",
|
|
40
40
|
"@types/debug": "4.1.12",
|
|
41
41
|
"chokidar": "5.0.0",
|
|
42
42
|
"debug": "4.4.3",
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"strip-ansi": "7.1.2",
|
|
47
47
|
"type-fest": "5.4.4"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "2fbdf26daa3d021ac628ccc2f59f0eeae6ddd53d"
|
|
50
50
|
}
|