markuplint 5.0.0-alpha.2 → 5.0.0-dev.5
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 +8 -0
- package/lib/api/ml-engine.d.ts +0 -10
- package/lib/api/ml-engine.js +24 -28
- 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 +14 -14
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
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
|
+
|
|
6
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)
|
|
7
15
|
|
|
8
16
|
### Features
|
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,12 +90,12 @@ 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 verifyResult = await core.verify(this.#options?.fix).catch(error => {
|
|
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
|
}
|
|
@@ -123,10 +123,10 @@ export class MLEngine extends Emitter {
|
|
|
123
123
|
status: 'processed',
|
|
124
124
|
};
|
|
125
125
|
}
|
|
126
|
-
const { violations, fixedCode } = verifyResult;
|
|
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);
|
|
129
|
+
this.emit('lint', this.#file.path, sourceCode, violations, resolvedFixedCode, debugMap, fixSummary ?? null);
|
|
130
130
|
log('exec: end');
|
|
131
131
|
return {
|
|
132
132
|
violations: [...violations],
|
|
@@ -134,6 +134,7 @@ export class MLEngine extends Emitter {
|
|
|
134
134
|
sourceCode,
|
|
135
135
|
fixedCode: resolvedFixedCode,
|
|
136
136
|
status: 'processed',
|
|
137
|
+
fixSummary,
|
|
137
138
|
};
|
|
138
139
|
}
|
|
139
140
|
/**
|
|
@@ -142,7 +143,7 @@ export class MLEngine extends Emitter {
|
|
|
142
143
|
* @param code - The new markup source code
|
|
143
144
|
*/
|
|
144
145
|
async setCode(code) {
|
|
145
|
-
const core = await this
|
|
146
|
+
const core = await this.#setup();
|
|
146
147
|
if (!core) {
|
|
147
148
|
return;
|
|
148
149
|
}
|
|
@@ -161,13 +162,13 @@ export class MLEngine extends Emitter {
|
|
|
161
162
|
watch: enable,
|
|
162
163
|
};
|
|
163
164
|
if (enable) {
|
|
164
|
-
this.#watcher.on('change', this
|
|
165
|
+
this.#watcher.on('change', this.#onChange.bind(this));
|
|
165
166
|
}
|
|
166
167
|
else {
|
|
167
168
|
this.#watcher.removeAllListeners();
|
|
168
169
|
}
|
|
169
170
|
}
|
|
170
|
-
async createCore(fabric) {
|
|
171
|
+
async #createCore(fabric) {
|
|
171
172
|
fileLog('Get source code');
|
|
172
173
|
const sourceCode = await this.#file.getCode();
|
|
173
174
|
fileLog('Source code path: %s', this.#file.path);
|
|
@@ -183,17 +184,12 @@ export class MLEngine extends Emitter {
|
|
|
183
184
|
this.#core = core;
|
|
184
185
|
return core;
|
|
185
186
|
}
|
|
186
|
-
|
|
187
|
-
const i18nSettings = i18n(this.#options?.locale);
|
|
188
|
-
this.emit('i18n', this.#file.path, i18nSettings);
|
|
189
|
-
return i18nSettings;
|
|
190
|
-
}
|
|
191
|
-
async onChange(filePath) {
|
|
187
|
+
async #onChange(filePath) {
|
|
192
188
|
if (!this.#options?.watch) {
|
|
193
189
|
return;
|
|
194
190
|
}
|
|
195
191
|
this.emit('log', 'watch:onChange', filePath);
|
|
196
|
-
const fabric = await this
|
|
192
|
+
const fabric = await this.#provide(false);
|
|
197
193
|
if (!fabric) {
|
|
198
194
|
return;
|
|
199
195
|
}
|
|
@@ -204,7 +200,7 @@ export class MLEngine extends Emitter {
|
|
|
204
200
|
this.#core?.update(fabric);
|
|
205
201
|
await this.exec();
|
|
206
202
|
}
|
|
207
|
-
async provide(cache = true) {
|
|
203
|
+
async #provide(cache = true) {
|
|
208
204
|
let configSet;
|
|
209
205
|
try {
|
|
210
206
|
configSet = await this.resolveConfig(cache);
|
|
@@ -237,7 +233,7 @@ export class MLEngine extends Emitter {
|
|
|
237
233
|
fileLog('Excludes the file: %s', this.#file.path);
|
|
238
234
|
return null;
|
|
239
235
|
}
|
|
240
|
-
const { parser, parserOptions, matched } = await this
|
|
236
|
+
const { parser, parserOptions, matched } = await this.#resolveParser(configSet);
|
|
241
237
|
const checkingExt = !this.#options?.ignoreExt;
|
|
242
238
|
if (checkingExt && !matched) {
|
|
243
239
|
this.emit('log', 'ext-unmatched', `Avoided linting because a file is unmatched by the extension: ${this.#file.path}`);
|
|
@@ -248,11 +244,11 @@ export class MLEngine extends Emitter {
|
|
|
248
244
|
...configSet.config.severity,
|
|
249
245
|
...this.#options?.severity,
|
|
250
246
|
};
|
|
251
|
-
const pretenders = await this
|
|
247
|
+
const pretenders = await this.#resolvePretenders(configSet);
|
|
252
248
|
fileLog('Resolved pretenders: %O', pretenders);
|
|
253
|
-
const ruleset = this
|
|
249
|
+
const ruleset = this.#resolveRuleset(configSet);
|
|
254
250
|
fileLog('Resolved ruleset: %O', ruleset);
|
|
255
|
-
const schemas = await this
|
|
251
|
+
const schemas = await this.#resolveSchemas(configSet);
|
|
256
252
|
if (fileLog.enabled) {
|
|
257
253
|
if (schemas[0].cites.length > 0) {
|
|
258
254
|
const [, ...additionalSpecs] = schemas;
|
|
@@ -265,7 +261,7 @@ export class MLEngine extends Emitter {
|
|
|
265
261
|
fileLog('Resolved schemas: %O', schemas);
|
|
266
262
|
}
|
|
267
263
|
}
|
|
268
|
-
const rules = await this
|
|
264
|
+
const rules = await this.#resolveRules(configSet.plugins, ruleset);
|
|
269
265
|
fileLog('Resolved rules: %O', rules);
|
|
270
266
|
const locale = i18n(this.#options?.locale);
|
|
271
267
|
const ruleCommonSettings = configSet.config.ruleCommonSettings ?? {};
|
|
@@ -317,7 +313,7 @@ export class MLEngine extends Emitter {
|
|
|
317
313
|
}
|
|
318
314
|
return configSet;
|
|
319
315
|
}
|
|
320
|
-
async resolveParser(
|
|
316
|
+
async #resolveParser(
|
|
321
317
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
322
318
|
configSet) {
|
|
323
319
|
const parser = await resolveParser(this.#file, configSet.config.parser, configSet.config.parserOptions);
|
|
@@ -325,14 +321,14 @@ export class MLEngine extends Emitter {
|
|
|
325
321
|
fileLog('Fetched Parser module: %s', parser.parserModName);
|
|
326
322
|
return parser;
|
|
327
323
|
}
|
|
328
|
-
async resolvePretenders(
|
|
324
|
+
async #resolvePretenders(
|
|
329
325
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
330
326
|
configSet) {
|
|
331
327
|
const pretenders = await resolvePretenders(configSet.config.pretenders);
|
|
332
328
|
fileLog('Resolved pretenders: %O', pretenders);
|
|
333
329
|
return pretenders;
|
|
334
330
|
}
|
|
335
|
-
async resolveRules(plugins, ruleset) {
|
|
331
|
+
async #resolveRules(plugins, ruleset) {
|
|
336
332
|
const rules = await resolveRules(plugins, ruleset, this.#options?.importPresetRules ?? true, this.#options?.autoLoad ?? true);
|
|
337
333
|
if (this.#options?.rules) {
|
|
338
334
|
rules.push(...this.#options.rules);
|
|
@@ -340,31 +336,31 @@ export class MLEngine extends Emitter {
|
|
|
340
336
|
this.emit('rules', this.#file.path, rules);
|
|
341
337
|
return rules;
|
|
342
338
|
}
|
|
343
|
-
resolveRuleset(
|
|
339
|
+
#resolveRuleset(
|
|
344
340
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
345
341
|
configSet) {
|
|
346
342
|
const ruleset = convertRuleset(configSet.config);
|
|
347
343
|
this.emit('ruleset', this.#file.path, ruleset);
|
|
348
344
|
return ruleset;
|
|
349
345
|
}
|
|
350
|
-
async resolveSchemas(
|
|
346
|
+
async #resolveSchemas(
|
|
351
347
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly-parameter-types
|
|
352
348
|
configSet) {
|
|
353
349
|
const { schemas } = await resolveSpecs(this.#file.path, configSet.config.specs);
|
|
354
350
|
this.emit('schemas', this.#file.path, schemas);
|
|
355
351
|
return schemas;
|
|
356
352
|
}
|
|
357
|
-
async setup() {
|
|
353
|
+
async #setup() {
|
|
358
354
|
if (this.#core) {
|
|
359
355
|
return this.#core;
|
|
360
356
|
}
|
|
361
|
-
const fabric = await this
|
|
357
|
+
const fabric = await this.#provide();
|
|
362
358
|
if (!fabric) {
|
|
363
359
|
return null;
|
|
364
360
|
}
|
|
365
361
|
if (fabric.configErrors) {
|
|
366
362
|
this.emit('config-errors', this.#file.path, fabric.configErrors);
|
|
367
363
|
}
|
|
368
|
-
return this
|
|
364
|
+
return this.#createCore(fabric);
|
|
369
365
|
}
|
|
370
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-
|
|
3
|
+
"version": "5.0.0-dev.5+e96392f56",
|
|
4
4
|
"description": "An HTML linter for all markup developers",
|
|
5
5
|
"author": "Yusuke Hirao",
|
|
6
6
|
"license": "MIT",
|
|
@@ -26,25 +26,25 @@
|
|
|
26
26
|
"clean": "tsc --build --clean tsconfig.build.json"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@markuplint/cli-utils": "5.0.0-
|
|
30
|
-
"@markuplint/file-resolver": "5.0.0-
|
|
31
|
-
"@markuplint/html-parser": "5.0.0-
|
|
32
|
-
"@markuplint/html-spec": "5.0.0-
|
|
33
|
-
"@markuplint/i18n": "5.0.0-
|
|
34
|
-
"@markuplint/ml-ast": "5.0.0-
|
|
35
|
-
"@markuplint/ml-config": "5.0.0-
|
|
36
|
-
"@markuplint/ml-core": "5.0.0-
|
|
37
|
-
"@markuplint/ml-spec": "5.0.0-
|
|
38
|
-
"@markuplint/rules": "5.0.0-
|
|
39
|
-
"@markuplint/shared": "5.0.0-
|
|
29
|
+
"@markuplint/cli-utils": "5.0.0-dev.5+e96392f56",
|
|
30
|
+
"@markuplint/file-resolver": "5.0.0-dev.5+e96392f56",
|
|
31
|
+
"@markuplint/html-parser": "5.0.0-dev.5+e96392f56",
|
|
32
|
+
"@markuplint/html-spec": "5.0.0-dev.5+e96392f56",
|
|
33
|
+
"@markuplint/i18n": "5.0.0-dev.5+e96392f56",
|
|
34
|
+
"@markuplint/ml-ast": "5.0.0-dev.5+e96392f56",
|
|
35
|
+
"@markuplint/ml-config": "5.0.0-dev.5+e96392f56",
|
|
36
|
+
"@markuplint/ml-core": "5.0.0-dev.5+e96392f56",
|
|
37
|
+
"@markuplint/ml-spec": "5.0.0-dev.5+e96392f56",
|
|
38
|
+
"@markuplint/rules": "5.0.0-dev.5+e96392f56",
|
|
39
|
+
"@markuplint/shared": "5.0.0-dev.5+e96392f56",
|
|
40
40
|
"@types/debug": "4.1.12",
|
|
41
41
|
"chokidar": "5.0.0",
|
|
42
42
|
"debug": "4.4.3",
|
|
43
43
|
"meow": "14.1.0",
|
|
44
44
|
"os-locale": "8.0.0",
|
|
45
45
|
"strict-event-emitter": "0.5.1",
|
|
46
|
-
"strip-ansi": "7.
|
|
46
|
+
"strip-ansi": "7.2.0",
|
|
47
47
|
"type-fest": "5.4.4"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "e96392f56e4bc8165ba59622b41c822703a96372"
|
|
50
50
|
}
|