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 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
@@ -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 {};
@@ -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.setup();
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 violations = 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
  }
102
102
  throw error;
103
103
  });
104
104
  const sourceCode = await this.#file.getCode();
105
- const fixedCode = core.document.toString(true);
106
- if (violations instanceof Error) {
107
- this.emit('lint-error', this.#file.path, sourceCode, violations);
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
- this.emit('lint', this.#file.path, sourceCode, violations, fixedCode, debugMap);
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.setup();
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.onChange.bind(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
- i18n() {
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.provide(false);
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.resolveParser(configSet);
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.resolvePretenders(configSet);
247
+ const pretenders = await this.#resolvePretenders(configSet);
251
248
  fileLog('Resolved pretenders: %O', pretenders);
252
- const ruleset = this.resolveRuleset(configSet);
249
+ const ruleset = this.#resolveRuleset(configSet);
253
250
  fileLog('Resolved ruleset: %O', ruleset);
254
- const schemas = await this.resolveSchemas(configSet);
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.resolveRules(configSet.plugins, ruleset);
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.provide();
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.createCore(fabric);
364
+ return this.#createCore(fabric);
368
365
  }
369
366
  }
@@ -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
- message?: string
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>[]];
@@ -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;
@@ -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',
@@ -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 fix = options.fix;
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.
@@ -26,6 +26,7 @@ export async function mlTest(sourceCode, config, rules, locale = 'en', fix = fal
26
26
  return {
27
27
  violations: result?.violations ?? [],
28
28
  fixedCode: result?.fixedCode ?? sourceCode,
29
+ fixSummary: result?.fixSummary,
29
30
  };
30
31
  }
31
32
  /**
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.1",
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.1",
30
- "@markuplint/file-resolver": "5.0.0-alpha.1",
31
- "@markuplint/html-parser": "5.0.0-alpha.1",
32
- "@markuplint/html-spec": "5.0.0-alpha.1",
33
- "@markuplint/i18n": "5.0.0-alpha.1",
34
- "@markuplint/ml-ast": "5.0.0-alpha.1",
35
- "@markuplint/ml-config": "5.0.0-alpha.1",
36
- "@markuplint/ml-core": "5.0.0-alpha.1",
37
- "@markuplint/ml-spec": "5.0.0-alpha.1",
38
- "@markuplint/rules": "5.0.0-alpha.1",
39
- "@markuplint/shared": "5.0.0-alpha.1",
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": "78a295e73a097a1ce09c777c06fa21ab68136387"
49
+ "gitHead": "2fbdf26daa3d021ac628ccc2f59f0eeae6ddd53d"
50
50
  }