markdownlint-cli2 0.5.1 → 0.7.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2020-2022 David Anson
3
+ Copyright (c) David Anson
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -10,22 +10,36 @@
10
10
 
11
11
  As a global CLI:
12
12
 
13
- ```shell
13
+ ```bash
14
14
  npm install markdownlint-cli2 --global
15
15
  ```
16
16
 
17
- As a development dependency of the current package:
17
+ As a development dependency of the current [Node.js][nodejs] package:
18
18
 
19
- ```shell
19
+ ```bash
20
20
  npm install markdownlint-cli2 --save-dev
21
21
  ```
22
22
 
23
- Or as a Docker container image:
23
+ As a [Docker][docker] container image:
24
24
 
25
- ```shell
25
+ ```bash
26
26
  docker pull davidanson/markdownlint-cli2
27
27
  ```
28
28
 
29
+ As a global CLI with [Homebrew][homebrew]:
30
+
31
+ ```bash
32
+ brew install markdownlint-cli2
33
+ ```
34
+
35
+ As a [GitHub Action][github-action] via
36
+ [`markdownlint-cli2-action`][markdownlint-cli2-action]:
37
+
38
+ ```yaml
39
+ - name: markdownlint-cli2-action
40
+ uses: DavidAnson/markdownlint-cli2-action@v9
41
+ ```
42
+
29
43
  ## Overview
30
44
 
31
45
  - [`markdownlint`][markdownlint] is a library for linting [Markdown][markdown]/
@@ -131,7 +145,7 @@ A container image [`davidanson/markdownlint-cli2`][docker-hub-markdownlint-cli2]
131
145
  can also be used (e.g., as part of a CI pipeline):
132
146
 
133
147
  ```bash
134
- docker run -v $PWD:/workdir davidanson/markdownlint-cli2:0.5.1 "**/*.md" "#node_modules"
148
+ docker run -v $PWD:/workdir davidanson/markdownlint-cli2:v0.7.0 "**/*.md" "#node_modules"
135
149
  ```
136
150
 
137
151
  Notes:
@@ -148,16 +162,25 @@ Notes:
148
162
  - A custom working directory can be specified with Docker's `-w` flag:
149
163
 
150
164
  ```bash
151
- docker run -w /myfolder -v $PWD:/myfolder davidanson/markdownlint-cli2:0.5.1 "**/*.md" "#node_modules"
165
+ docker run -w /myfolder -v $PWD:/myfolder davidanson/markdownlint-cli2:v0.7.0 "**/*.md" "#node_modules"
152
166
  ```
153
167
 
154
168
  To invoke the `markdownlint-cli2-config` or `markdownlint-cli2-fix` commands
155
169
  instead, use Docker's `--entrypoint` flag:
156
170
 
157
171
  ```bash
158
- docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/markdownlint-cli2:0.5.1 "**/*.md" "#node_modules"
172
+ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/markdownlint-cli2:v0.7.0 "**/*.md" "#node_modules"
159
173
  ```
160
174
 
175
+ For convenience, the container image
176
+ [`davidanson/markdownlint-cli2-rules`][docker-hub-markdownlint-cli2-rules]
177
+ includes the latest versions of custom rules published to npm with the tag
178
+ [`markdownlint-rule`][markdownlint-rule]. These rules are installed globally
179
+ onto the base image `davidanson/markdownlint-cli2`.
180
+
181
+ **Note**: This container image exists for convenience and is not an endorsement
182
+ of the rules within.
183
+
161
184
  ### Exit Codes
162
185
 
163
186
  - `0`: Linting was successful and there were no errors
@@ -179,11 +202,20 @@ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/mark
179
202
  - See the [Configuration][markdownlint-configuration] section of the
180
203
  `markdownlint` documentation for information about the inline comment syntax
181
204
  for enabling and disabling rules with HTML comments.
182
- - In general, glob expressions match files under the current directory and the
183
- configuration for that directory applies to the entire tree.
205
+ - In general, glob expressions should match files under the current directory;
206
+ the configuration for that directory will apply to the entire tree.
184
207
  - When glob expressions match files *not* under the current directory,
185
208
  configuration for the current directory is applied to the closest common
186
209
  parent directory.
210
+ - There are two kinds of configuration file (both detailed below):
211
+ - Configuration files like `.markdownlint-cli2.*` allow complete control of
212
+ `markdownlint-cli2` behavior and are also used by `vscode-markdownlint`.
213
+ - Configuration files like `.markdownlint.*` allow control over only the
214
+ `markdownlint` `config` object and tend to be supported more broadly (such
215
+ as by `markdownlint-cli`).
216
+ - The VS Code extension `vscode-markdownlint` includes a schema definition for
217
+ the `JSON(C)` configuration files described below. This adds auto-complete and
218
+ can make it easier to define proper structure.
187
219
 
188
220
  ### `.markdownlint-cli2.jsonc`
189
221
 
@@ -194,6 +226,8 @@ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/mark
194
226
  rules for this part of the directory tree
195
227
  - If a `.markdownlint.{jsonc,json,yaml,yml,js}` file (see below) is present
196
228
  in the same directory, it overrides the value of this property
229
+ - If the `config` object contains an `extends` property, it will be resolved
230
+ the same as `.markdownlint.{jsonc,json,yaml,yml,js}` (see below)
197
231
  - `customRules`: `Array` of `String`s (or `Array`s of `String`s) of module
198
232
  names/paths of [custom rules][markdownlint-custom-rules] to load and use
199
233
  when linting
@@ -344,7 +378,7 @@ reference to the `repos` list in that project's `.pre-commit-config.yaml` like:
344
378
 
345
379
  ```yaml
346
380
  - repo: https://github.com/DavidAnson/markdownlint-cli2
347
- rev: v0.5.1
381
+ rev: v0.7.0
348
382
  hooks:
349
383
  - id: markdownlint-cli2
350
384
  ```
@@ -354,41 +388,21 @@ reference to the `repos` list in that project's `.pre-commit-config.yaml` like:
354
388
 
355
389
  ## History
356
390
 
357
- - 0.0.2 - Initial release
358
- - 0.0.3 - Feature parity with `markdownlint-cli`
359
- - 0.0.4 - Support output formatters and `markdown-it` plugins
360
- - 0.0.5 - Improve support for ignoring files
361
- - 0.0.6 - Improve handling of very large directory trees
362
- - 0.0.7 - Support `.markdownlint-cli2.js` and `.markdownlint.js`
363
- - 0.0.8 - Support `.markdownlint-cli2.yaml`, add progress
364
- - 0.0.9 - Improve configuration file handling
365
- - 0.0.10 - Improve performance and configuration
366
- - 0.0.11 - Improve performance of `fix`, update banner
367
- - 0.0.12 - Update dependencies (including `markdownlint`)
368
- - 0.0.13 - Add `markdownlint-cli2-fix` command
369
- - 0.0.14 - Update dependencies (including `markdownlint`)
370
- - 0.0.15 - Improve extensibility
371
- - 0.1.0 - Simplify use of `require`, increment minor version
372
- - 0.1.1 - Restore previous use of `require`
373
- - 0.1.2 - Update use of `require` to be more flexible
374
- - 0.1.3 - Support rule collections
375
- - 0.2.0 - Improve handling of Windows paths using backslash
376
- - 0.3.0 - Add Docker container, update dependencies
377
- - 0.3.1 - Extensibility tweaks
378
- - 0.3.2 - Extensibility/Windows/consistency improvements
379
- - 0.4.0 - New rules, async custom rules, explicit config, CJS (breaking)
380
- - 0.5.0 - New rules, support modules (MJS) everywhere, include dotfiles
381
- - 0.5.1 - Update dependencies
391
+ See [CHANGELOG.md](CHANGELOG.md).
382
392
 
383
393
  <!-- markdownlint-disable line-length -->
384
394
 
385
395
  [commonmark]: https://commonmark.org/
386
396
  [commonjs-module]: https://nodejs.org/api/modules.html#modules_modules_commonjs_modules
387
397
  [ecmascript-module]: https://nodejs.org/api/esm.html#modules-ecmascript-modules
398
+ [docker]: https://www.docker.com
388
399
  [docker-bind-mounts]: https://docs.docker.com/storage/bind-mounts/
389
400
  [docker-hub-markdownlint-cli2]: https://hub.docker.com/r/davidanson/markdownlint-cli2
401
+ [docker-hub-markdownlint-cli2-rules]: https://hub.docker.com/r/davidanson/markdownlint-cli2-rules
390
402
  [front-matter]: https://jekyllrb.com/docs/frontmatter/
403
+ [github-action]: https://docs.github.com/actions
391
404
  [globby]: https://www.npmjs.com/package/globby
405
+ [homebrew]: https://brew.sh
392
406
  [html-comment]: https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started
393
407
  [json]: https://wikipedia.org/wiki/JSON
394
408
  [jsonc]: https://code.visualstudio.com/Docs/languages/json#_json-with-comments
@@ -407,6 +421,7 @@ reference to the `repos` list in that project's `.pre-commit-config.yaml` like:
407
421
  [markdownlint-rules-tags]: https://github.com/DavidAnson/markdownlint/blob/main/README.md#tags
408
422
  [markdownlint-cli]: https://github.com/igorshubovych/markdownlint-cli
409
423
  [markdownlint-cli2]: https://github.com/DavidAnson/markdownlint-cli2
424
+ [markdownlint-cli2-action]: https://github.com/marketplace/actions/markdownlint-cli2-action
410
425
  [markdownlint-cli2-blog]: https://dlaa.me/blog/post/markdownlintcli2
411
426
  [markdownlint-cli2-formatter]: https://www.npmjs.com/search?q=keywords:markdownlint-cli2-formatter
412
427
  [markdownlint-cli2-cjs]: test/markdownlint-cli2-cjs/.markdownlint-cli2.cjs
@@ -0,0 +1,5 @@
1
+ // @ts-check
2
+
3
+ "use strict";
4
+
5
+ module.exports = require("markdownlint/helpers");
@@ -0,0 +1,5 @@
1
+ // @ts-check
2
+
3
+ "use strict";
4
+
5
+ module.exports = require("markdownlint");
@@ -13,8 +13,11 @@ const dynamicRequire = (typeof __non_webpack_require__ === "undefined") ? requir
13
13
  const path = require("node:path");
14
14
  const { pathToFileURL } = require("node:url");
15
15
  const markdownlintLibrary = require("markdownlint");
16
- const { markdownlint, "readConfig": markdownlintReadConfig } =
17
- markdownlintLibrary.promises;
16
+ const {
17
+ markdownlint,
18
+ "extendConfig": markdownlintExtendConfig,
19
+ "readConfig": markdownlintReadConfig
20
+ } = markdownlintLibrary.promises;
18
21
  const markdownlintRuleHelpers = require("markdownlint/helpers");
19
22
  const appendToArray = require("./append-to-array");
20
23
  const mergeOptions = require("./merge-options");
@@ -22,7 +25,7 @@ const resolveAndRequire = require("./resolve-and-require");
22
25
 
23
26
  // Variables
24
27
  const packageName = "markdownlint-cli2";
25
- const packageVersion = "0.5.1";
28
+ const packageVersion = "0.7.0";
26
29
  const libraryName = "markdownlint";
27
30
  const libraryVersion = markdownlintLibrary.getVersion();
28
31
  const dotOnlySubstitute = "*.{md,markdown}";
@@ -34,8 +37,7 @@ const noop = () => null;
34
37
  // Gets a synchronous function to parse JSONC text
35
38
  const getJsoncParse = async () => {
36
39
  const { "default": stripJsonComments } =
37
- // eslint-disable-next-line max-len
38
- // eslint-disable-next-line no-inline-comments, node/no-unsupported-features/es-syntax
40
+ // eslint-disable-next-line no-inline-comments
39
41
  await import(/* webpackMode: "eager" */ "strip-json-comments");
40
42
  return (text) => JSON.parse(stripJsonComments(text));
41
43
  };
@@ -79,8 +81,7 @@ const importOrRequireResolve = async (dir, id) => {
79
81
  try {
80
82
  const fileUrlString =
81
83
  pathToFileURL(path.resolve(dir, expandId)).toString();
82
- // eslint-disable-next-line max-len
83
- // eslint-disable-next-line no-inline-comments, node/no-unsupported-features/es-syntax
84
+ // eslint-disable-next-line no-inline-comments
84
85
  const module = await import(/* webpackIgnore: true */ fileUrlString);
85
86
  return module.default;
86
87
  } catch (error) {
@@ -244,105 +245,121 @@ $ markdownlint-cli2 "**/*.md" "#node_modules"`
244
245
 
245
246
  // Get (creating if necessary) and process a directory's info object
246
247
  const getAndProcessDirInfo =
247
- (fs, tasks, dirToDirInfo, dir, relativeDir, noRequire, func) => {
248
- let dirInfo = dirToDirInfo[dir];
249
- if (!dirInfo) {
250
- dirInfo = {
251
- dir,
252
- relativeDir,
253
- "parent": null,
254
- "files": [],
255
- "markdownlintConfig": null,
256
- "markdownlintOptions": null
257
- };
258
- dirToDirInfo[dir] = dirInfo;
259
-
260
- // Load markdownlint-cli2 object(s)
261
- const markdownlintCli2Jsonc =
262
- path.posix.join(dir, ".markdownlint-cli2.jsonc");
263
- const markdownlintCli2Yaml =
264
- path.posix.join(dir, ".markdownlint-cli2.yaml");
265
- tasks.push(
266
- fs.promises.access(markdownlintCli2Jsonc).
267
- then(
268
- () => fs.promises.
269
- readFile(markdownlintCli2Jsonc, utf8).
270
- then(
271
- (content) => getJsoncParse().
272
- then((jsoncParse) => jsoncParse(content))
273
- ),
274
- () => fs.promises.access(markdownlintCli2Yaml).
275
- then(
276
- () => fs.promises.
277
- readFile(markdownlintCli2Yaml, utf8).
278
- then(yamlParse),
279
- importOrRequireConfig(
280
- fs,
281
- dir,
282
- ".markdownlint-cli2.cjs",
283
- noRequire,
248
+ (fs, tasks, dirToDirInfo, dir, relativeDir, noRequire, func) => {
249
+ let dirInfo = dirToDirInfo[dir];
250
+ if (!dirInfo) {
251
+ dirInfo = {
252
+ dir,
253
+ relativeDir,
254
+ "parent": null,
255
+ "files": [],
256
+ "markdownlintConfig": null,
257
+ "markdownlintOptions": null
258
+ };
259
+ dirToDirInfo[dir] = dirInfo;
260
+
261
+ // Load markdownlint-cli2 object(s)
262
+ const markdownlintCli2Jsonc =
263
+ path.posix.join(dir, ".markdownlint-cli2.jsonc");
264
+ const markdownlintCli2Yaml =
265
+ path.posix.join(dir, ".markdownlint-cli2.yaml");
266
+ tasks.push(
267
+ fs.promises.access(markdownlintCli2Jsonc).
268
+ then(
269
+ () => fs.promises.
270
+ readFile(markdownlintCli2Jsonc, utf8).
271
+ then(
272
+ (content) => getJsoncParse().
273
+ then((jsoncParse) => jsoncParse(content))
274
+ ),
275
+ () => fs.promises.access(markdownlintCli2Yaml).
276
+ then(
277
+ () => fs.promises.
278
+ readFile(markdownlintCli2Yaml, utf8).
279
+ then(yamlParse),
284
280
  importOrRequireConfig(
285
281
  fs,
286
282
  dir,
287
- ".markdownlint-cli2.mjs",
283
+ ".markdownlint-cli2.cjs",
288
284
  noRequire,
289
- noop
285
+ importOrRequireConfig(
286
+ fs,
287
+ dir,
288
+ ".markdownlint-cli2.mjs",
289
+ noRequire,
290
+ noop
291
+ )
290
292
  )
291
293
  )
292
- )
293
- ).
294
- then((options) => {
295
- dirInfo.markdownlintOptions = options;
296
- })
297
- );
294
+ ).
295
+ then((options) => {
296
+ dirInfo.markdownlintOptions = options;
297
+ return options &&
298
+ options.config &&
299
+ options.config.extends &&
300
+ getJsoncParse().
301
+ then(
302
+ (jsoncParse) => markdownlintExtendConfig(
303
+ options.config,
304
+ // Just needs to identify a file in the right directory
305
+ markdownlintCli2Jsonc,
306
+ [ jsoncParse, yamlParse ],
307
+ fs
308
+ )
309
+ ).
310
+ then((config) => {
311
+ options.config = config;
312
+ });
313
+ })
314
+ );
298
315
 
299
- // Load markdownlint object(s)
300
- const readConfigs =
301
- readConfig(
302
- fs,
303
- dir,
304
- ".markdownlint.jsonc",
316
+ // Load markdownlint object(s)
317
+ const readConfigs =
305
318
  readConfig(
306
319
  fs,
307
320
  dir,
308
- ".markdownlint.json",
321
+ ".markdownlint.jsonc",
309
322
  readConfig(
310
323
  fs,
311
324
  dir,
312
- ".markdownlint.yaml",
325
+ ".markdownlint.json",
313
326
  readConfig(
314
327
  fs,
315
328
  dir,
316
- ".markdownlint.yml",
317
- importOrRequireConfig(
329
+ ".markdownlint.yaml",
330
+ readConfig(
318
331
  fs,
319
332
  dir,
320
- ".markdownlint.cjs",
321
- noRequire,
333
+ ".markdownlint.yml",
322
334
  importOrRequireConfig(
323
335
  fs,
324
336
  dir,
325
- ".markdownlint.mjs",
337
+ ".markdownlint.cjs",
326
338
  noRequire,
327
- noop
339
+ importOrRequireConfig(
340
+ fs,
341
+ dir,
342
+ ".markdownlint.mjs",
343
+ noRequire,
344
+ noop
345
+ )
328
346
  )
329
347
  )
330
348
  )
331
349
  )
332
- )
350
+ );
351
+ tasks.push(
352
+ readConfigs().
353
+ then((config) => {
354
+ dirInfo.markdownlintConfig = config;
355
+ })
333
356
  );
334
- tasks.push(
335
- readConfigs().
336
- then((config) => {
337
- dirInfo.markdownlintConfig = config;
338
- })
339
- );
340
- }
341
- if (func) {
342
- func(dirInfo);
343
- }
344
- return dirInfo;
345
- };
357
+ }
358
+ if (func) {
359
+ func(dirInfo);
360
+ }
361
+ return dirInfo;
362
+ };
346
363
 
347
364
  // Get base markdownlint-cli2 options object
348
365
  const getBaseOptions = async (
@@ -369,7 +386,10 @@ const getBaseOptions = async (
369
386
  // eslint-disable-next-line no-multi-assign
370
387
  const baseMarkdownlintOptions = dirToDirInfo[baseDir].markdownlintOptions =
371
388
  mergeOptions(
372
- mergeOptions(options, { "fix": fixDefault }),
389
+ mergeOptions(
390
+ { "fix": fixDefault },
391
+ options
392
+ ),
373
393
  dirToDirInfo[baseDir].markdownlintOptions
374
394
  );
375
395
 
@@ -393,82 +413,81 @@ const getBaseOptions = async (
393
413
 
394
414
  // Enumerate files from globs and build directory infos
395
415
  const enumerateFiles =
396
- // eslint-disable-next-line max-len
397
- async (fs, baseDirSystem, baseDir, globPatterns, dirToDirInfo, noErrors, noRequire) => {
398
- const tasks = [];
399
- const globbyOptions = {
400
- "absolute": true,
401
- "cwd": baseDir,
402
- "dot": true,
403
- "expandDirectories": false,
404
- fs
405
- };
406
- if (noErrors) {
407
- globbyOptions.suppressErrors = true;
408
- }
409
- // Special-case literal files
410
- const literalFiles = [];
411
- const filteredGlobPatterns = globPatterns.filter(
412
- (globPattern) => {
413
- if (globPattern.startsWith(":")) {
414
- literalFiles.push(
415
- posixPath(path.resolve(baseDirSystem, globPattern.slice(1)))
416
- );
417
- return false;
418
- }
419
- return true;
420
- }
421
- ).map((globPattern) => globPattern.replace(/^\\:/u, ":"));
422
- const baseMarkdownlintOptions = dirToDirInfo[baseDir].markdownlintOptions;
423
- const globsForIgnore =
424
- (baseMarkdownlintOptions.globs || []).
425
- filter((glob) => glob.startsWith("!"));
426
- const filteredLiteralFiles =
427
- ((literalFiles.length > 0) && (globsForIgnore.length > 0))
428
- ? removeIgnoredFiles(baseDir, literalFiles, globsForIgnore)
429
- : literalFiles;
430
- // Manually expand directories to avoid globby call to dir-glob.sync
431
- const expandedDirectories = await Promise.all(
432
- filteredGlobPatterns.map((globPattern) => {
433
- const barePattern =
434
- globPattern.startsWith("!")
435
- ? globPattern.slice(1)
436
- : globPattern;
437
- const globPath =
438
- (path.posix.isAbsolute(barePattern) || path.isAbsolute(barePattern))
439
- ? barePattern
440
- : path.posix.join(baseDir, barePattern);
441
- return fs.promises.stat(globPath).
442
- then((stats) => (stats.isDirectory()
443
- ? path.posix.join(globPattern, "**")
444
- : globPattern)).
445
- catch(() => globPattern);
446
- })
447
- );
448
- // Process glob patterns
449
416
  // eslint-disable-next-line max-len
450
- // eslint-disable-next-line no-inline-comments, node/no-unsupported-features/es-syntax
451
- const { globby } = await import(/* webpackMode: "eager" */ "globby");
452
- const files = [
453
- ...await globby(expandedDirectories, globbyOptions),
454
- ...filteredLiteralFiles
455
- ];
456
- for (const file of files) {
457
- const dir = path.posix.dirname(file);
458
- getAndProcessDirInfo(
459
- fs,
460
- tasks,
461
- dirToDirInfo,
462
- dir,
463
- null,
464
- noRequire,
465
- (dirInfo) => {
466
- dirInfo.files.push(file);
417
+ async (fs, baseDirSystem, baseDir, globPatterns, dirToDirInfo, noErrors, noRequire) => {
418
+ const tasks = [];
419
+ const globbyOptions = {
420
+ "absolute": true,
421
+ "cwd": baseDir,
422
+ "dot": true,
423
+ "expandDirectories": false,
424
+ fs
425
+ };
426
+ if (noErrors) {
427
+ globbyOptions.suppressErrors = true;
428
+ }
429
+ // Special-case literal files
430
+ const literalFiles = [];
431
+ const filteredGlobPatterns = globPatterns.filter(
432
+ (globPattern) => {
433
+ if (globPattern.startsWith(":")) {
434
+ literalFiles.push(
435
+ posixPath(path.resolve(baseDirSystem, globPattern.slice(1)))
436
+ );
437
+ return false;
438
+ }
439
+ return true;
467
440
  }
441
+ ).map((globPattern) => globPattern.replace(/^\\:/u, ":"));
442
+ const baseMarkdownlintOptions = dirToDirInfo[baseDir].markdownlintOptions;
443
+ const globsForIgnore =
444
+ (baseMarkdownlintOptions.globs || []).
445
+ filter((glob) => glob.startsWith("!"));
446
+ const filteredLiteralFiles =
447
+ ((literalFiles.length > 0) && (globsForIgnore.length > 0))
448
+ ? removeIgnoredFiles(baseDir, literalFiles, globsForIgnore)
449
+ : literalFiles;
450
+ // Manually expand directories to avoid globby call to dir-glob.sync
451
+ const expandedDirectories = await Promise.all(
452
+ filteredGlobPatterns.map((globPattern) => {
453
+ const barePattern =
454
+ globPattern.startsWith("!")
455
+ ? globPattern.slice(1)
456
+ : globPattern;
457
+ const globPath =
458
+ (path.posix.isAbsolute(barePattern) || path.isAbsolute(barePattern))
459
+ ? barePattern
460
+ : path.posix.join(baseDir, barePattern);
461
+ return fs.promises.stat(globPath).
462
+ then((stats) => (stats.isDirectory()
463
+ ? path.posix.join(globPattern, "**")
464
+ : globPattern)).
465
+ catch(() => globPattern);
466
+ })
468
467
  );
469
- }
470
- await Promise.all(tasks);
471
- };
468
+ // Process glob patterns
469
+ // eslint-disable-next-line no-inline-comments
470
+ const { globby } = await import(/* webpackMode: "eager" */ "globby");
471
+ const files = [
472
+ ...await globby(expandedDirectories, globbyOptions),
473
+ ...filteredLiteralFiles
474
+ ];
475
+ for (const file of files) {
476
+ const dir = path.posix.dirname(file);
477
+ getAndProcessDirInfo(
478
+ fs,
479
+ tasks,
480
+ dirToDirInfo,
481
+ dir,
482
+ null,
483
+ noRequire,
484
+ (dirInfo) => {
485
+ dirInfo.files.push(file);
486
+ }
487
+ );
488
+ }
489
+ await Promise.all(tasks);
490
+ };
472
491
 
473
492
  // Enumerate (possibly missing) parent directories and update directory infos
474
493
  const enumerateParents = async (fs, baseDir, dirToDirInfo, noRequire) => {
@@ -517,135 +536,135 @@ const enumerateParents = async (fs, baseDir, dirToDirInfo, noRequire) => {
517
536
 
518
537
  // Create directory info objects by enumerating file globs
519
538
  const createDirInfos =
520
- // eslint-disable-next-line max-len
521
- async (fs, baseDirSystem, baseDir, globPatterns, dirToDirInfo, optionsOverride, noErrors, noRequire) => {
522
- await enumerateFiles(
523
- fs,
524
- baseDirSystem,
525
- baseDir,
526
- globPatterns,
527
- dirToDirInfo,
528
- noErrors,
529
- noRequire
530
- );
531
- await enumerateParents(
532
- fs,
533
- baseDir,
534
- dirToDirInfo,
535
- noRequire
536
- );
537
-
538
- // Merge file lists with identical configuration
539
- const dirs = Object.keys(dirToDirInfo);
540
- dirs.sort((a, b) => b.length - a.length);
541
- const dirInfos = [];
542
- const noConfigDirInfo =
543
- // eslint-disable-next-line unicorn/consistent-function-scoping
544
- (dirInfo) => (
545
- dirInfo.parent &&
546
- !dirInfo.markdownlintConfig &&
547
- !dirInfo.markdownlintOptions
539
+ // eslint-disable-next-line max-len
540
+ async (fs, baseDirSystem, baseDir, globPatterns, dirToDirInfo, optionsOverride, noErrors, noRequire) => {
541
+ await enumerateFiles(
542
+ fs,
543
+ baseDirSystem,
544
+ baseDir,
545
+ globPatterns,
546
+ dirToDirInfo,
547
+ noErrors,
548
+ noRequire
548
549
  );
549
- const tasks = [];
550
- for (const dir of dirs) {
551
- const dirInfo = dirToDirInfo[dir];
552
- if (noConfigDirInfo(dirInfo)) {
553
- if (dirInfo.parent) {
554
- appendToArray(dirInfo.parent.files, dirInfo.files);
555
- }
556
- dirToDirInfo[dir] = null;
557
- } else {
558
- const { markdownlintOptions, relativeDir } = dirInfo;
559
- if (markdownlintOptions && markdownlintOptions.customRules) {
560
- tasks.push(
561
- importOrRequireIds(
562
- relativeDir || dir,
563
- markdownlintOptions.customRules,
564
- noRequire
565
- ).then((customRules) => {
566
- // Expand nested arrays (for packages that export multiple rules)
567
- markdownlintOptions.customRules = customRules.flat();
568
- })
569
- );
570
- }
571
- if (markdownlintOptions && markdownlintOptions.markdownItPlugins) {
572
- tasks.push(
573
- importOrRequireIdsAndParams(
574
- relativeDir || dir,
575
- markdownlintOptions.markdownItPlugins,
576
- noRequire
577
- ).then((markdownItPlugins) => {
578
- markdownlintOptions.markdownItPlugins = markdownItPlugins;
579
- })
580
- );
550
+ await enumerateParents(
551
+ fs,
552
+ baseDir,
553
+ dirToDirInfo,
554
+ noRequire
555
+ );
556
+
557
+ // Merge file lists with identical configuration
558
+ const dirs = Object.keys(dirToDirInfo);
559
+ dirs.sort((a, b) => b.length - a.length);
560
+ const dirInfos = [];
561
+ const noConfigDirInfo =
562
+ // eslint-disable-next-line unicorn/consistent-function-scoping
563
+ (dirInfo) => (
564
+ dirInfo.parent &&
565
+ !dirInfo.markdownlintConfig &&
566
+ !dirInfo.markdownlintOptions
567
+ );
568
+ const tasks = [];
569
+ for (const dir of dirs) {
570
+ const dirInfo = dirToDirInfo[dir];
571
+ if (noConfigDirInfo(dirInfo)) {
572
+ if (dirInfo.parent) {
573
+ appendToArray(dirInfo.parent.files, dirInfo.files);
574
+ }
575
+ dirToDirInfo[dir] = null;
576
+ } else {
577
+ const { markdownlintOptions, relativeDir } = dirInfo;
578
+ if (markdownlintOptions && markdownlintOptions.customRules) {
579
+ tasks.push(
580
+ importOrRequireIds(
581
+ relativeDir || dir,
582
+ markdownlintOptions.customRules,
583
+ noRequire
584
+ ).then((customRules) => {
585
+ // Expand nested arrays (for packages that export multiple rules)
586
+ markdownlintOptions.customRules = customRules.flat();
587
+ })
588
+ );
589
+ }
590
+ if (markdownlintOptions && markdownlintOptions.markdownItPlugins) {
591
+ tasks.push(
592
+ importOrRequireIdsAndParams(
593
+ relativeDir || dir,
594
+ markdownlintOptions.markdownItPlugins,
595
+ noRequire
596
+ ).then((markdownItPlugins) => {
597
+ markdownlintOptions.markdownItPlugins = markdownItPlugins;
598
+ })
599
+ );
600
+ }
601
+ dirInfos.push(dirInfo);
581
602
  }
582
- dirInfos.push(dirInfo);
583
603
  }
584
- }
585
- await Promise.all(tasks);
586
- for (const dirInfo of dirInfos) {
587
- while (dirInfo.parent && !dirToDirInfo[dirInfo.parent.dir]) {
588
- dirInfo.parent = dirInfo.parent.parent;
604
+ await Promise.all(tasks);
605
+ for (const dirInfo of dirInfos) {
606
+ while (dirInfo.parent && !dirToDirInfo[dirInfo.parent.dir]) {
607
+ dirInfo.parent = dirInfo.parent.parent;
608
+ }
589
609
  }
590
- }
591
610
 
592
- // Verify dirInfos is simplified
593
- // if (
594
- // dirInfos.filter(
595
- // (di) => di.parent && !dirInfos.includes(di.parent)
596
- // ).length > 0
597
- // ) {
598
- // throw new Error("Extra parent");
599
- // }
600
- // if (
601
- // dirInfos.filter(
602
- // (di) => !di.parent && (di.dir !== baseDir)
603
- // ).length > 0
604
- // ) {
605
- // throw new Error("Missing parent");
606
- // }
607
- // if (
608
- // dirInfos.filter(
609
- // (di) => di.parent &&
610
- // !((di.markdownlintConfig ? 1 : 0) ^ (di.markdownlintOptions ? 1 : 0))
611
- // ).length > 0
612
- // ) {
613
- // throw new Error("Missing object");
614
- // }
615
- // if (dirInfos.filter((di) => di.dir === "/").length > 0) {
616
- // throw new Error("Includes root");
617
- // }
618
-
619
- // Merge configuration by inheritance
620
- for (const dirInfo of dirInfos) {
621
- let markdownlintOptions = dirInfo.markdownlintOptions || {};
622
- let { markdownlintConfig } = dirInfo;
623
- let parent = dirInfo;
624
- // eslint-disable-next-line prefer-destructuring
625
- while ((parent = parent.parent)) {
626
- if (parent.markdownlintOptions) {
627
- markdownlintOptions = mergeOptions(
628
- parent.markdownlintOptions,
629
- markdownlintOptions
630
- );
631
- }
632
- if (
633
- !markdownlintConfig &&
634
- parent.markdownlintConfig &&
635
- !markdownlintOptions.config
636
- ) {
637
- // eslint-disable-next-line prefer-destructuring
638
- markdownlintConfig = parent.markdownlintConfig;
611
+ // Verify dirInfos is simplified
612
+ // if (
613
+ // dirInfos.filter(
614
+ // (di) => di.parent && !dirInfos.includes(di.parent)
615
+ // ).length > 0
616
+ // ) {
617
+ // throw new Error("Extra parent");
618
+ // }
619
+ // if (
620
+ // dirInfos.filter(
621
+ // (di) => !di.parent && (di.dir !== baseDir)
622
+ // ).length > 0
623
+ // ) {
624
+ // throw new Error("Missing parent");
625
+ // }
626
+ // if (
627
+ // dirInfos.filter(
628
+ // (di) => di.parent &&
629
+ // !((di.markdownlintConfig ? 1 : 0) ^ (di.markdownlintOptions ? 1 : 0))
630
+ // ).length > 0
631
+ // ) {
632
+ // throw new Error("Missing object");
633
+ // }
634
+ // if (dirInfos.filter((di) => di.dir === "/").length > 0) {
635
+ // throw new Error("Includes root");
636
+ // }
637
+
638
+ // Merge configuration by inheritance
639
+ for (const dirInfo of dirInfos) {
640
+ let markdownlintOptions = dirInfo.markdownlintOptions || {};
641
+ let { markdownlintConfig } = dirInfo;
642
+ let parent = dirInfo;
643
+ // eslint-disable-next-line prefer-destructuring
644
+ while ((parent = parent.parent)) {
645
+ if (parent.markdownlintOptions) {
646
+ markdownlintOptions = mergeOptions(
647
+ parent.markdownlintOptions,
648
+ markdownlintOptions
649
+ );
650
+ }
651
+ if (
652
+ !markdownlintConfig &&
653
+ parent.markdownlintConfig &&
654
+ !markdownlintOptions.config
655
+ ) {
656
+ // eslint-disable-next-line prefer-destructuring
657
+ markdownlintConfig = parent.markdownlintConfig;
658
+ }
639
659
  }
660
+ dirInfo.markdownlintOptions = mergeOptions(
661
+ markdownlintOptions,
662
+ optionsOverride
663
+ );
664
+ dirInfo.markdownlintConfig = markdownlintConfig;
640
665
  }
641
- dirInfo.markdownlintOptions = mergeOptions(
642
- markdownlintOptions,
643
- optionsOverride
644
- );
645
- dirInfo.markdownlintConfig = markdownlintConfig;
646
- }
647
- return dirInfos;
648
- };
666
+ return dirInfos;
667
+ };
649
668
 
650
669
  // Lint files in groups by shared configuration
651
670
  const lintFiles = async (fs, dirInfos, fileContents) => {
@@ -678,7 +697,7 @@ const lintFiles = async (fs, dirInfos, fileContents) => {
678
697
  "files": filteredFiles,
679
698
  "strings": filteredStrings,
680
699
  "config": markdownlintConfig || markdownlintOptions.config,
681
- "configParsers": [ jsoncParse ],
700
+ "configParsers": [ jsoncParse, yamlParse ],
682
701
  "customRules": markdownlintOptions.customRules,
683
702
  "frontMatter": markdownlintOptions.frontMatter
684
703
  ? new RegExp(markdownlintOptions.frontMatter, "u")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markdownlint-cli2",
3
- "version": "0.5.1",
3
+ "version": "0.7.0",
4
4
  "description": "A fast, flexible, configuration-based command-line interface for linting Markdown/CommonMark files with the `markdownlint` library",
5
5
  "author": {
6
6
  "name": "David Anson",
@@ -9,7 +9,11 @@
9
9
  "license": "MIT",
10
10
  "type": "commonjs",
11
11
  "main": "./markdownlint-cli2.js",
12
- "exports": "./markdownlint-cli2.js",
12
+ "exports": {
13
+ ".": "./markdownlint-cli2.js",
14
+ "./markdownlint": "./export-markdownlint.js",
15
+ "./markdownlint/helpers": "./export-markdownlint-helpers.js"
16
+ },
13
17
  "bin": {
14
18
  "markdownlint-cli2": "markdownlint-cli2.js",
15
19
  "markdownlint-cli2-config": "markdownlint-cli2-config.js",
@@ -23,6 +27,7 @@
23
27
  "bugs": "https://github.com/DavidAnson/markdownlint-cli2/issues",
24
28
  "scripts": {
25
29
  "build-docker-image": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker build -t davidanson/markdownlint-cli2:v$VERSION -f docker/Dockerfile --label org.opencontainers.image.version=v$VERSION .",
30
+ "build-docker-image-rules": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker build -t davidanson/markdownlint-cli2-rules:v$VERSION -f docker/Dockerfile-rules --build-arg VERSION=v$VERSION --label org.opencontainers.image.version=v$VERSION .",
26
31
  "ci": "npm-run-all --continue-on-error --parallel test-cover lint",
27
32
  "docker-npm-install": "docker run --rm --tty --name npm-install --volume $PWD:/home/workdir --workdir /home/workdir --user node node:16 npm install",
28
33
  "docker-npm-run-upgrade": "docker run --rm --tty --name npm-run-upgrade --volume $PWD:/home/workdir --workdir /home/workdir --user node node:16 npm run upgrade",
@@ -32,19 +37,23 @@
32
37
  "publish-docker-image": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker buildx build --platform linux/arm64,linux/amd64 -t davidanson/markdownlint-cli2:v$VERSION -t davidanson/markdownlint-cli2:latest -f docker/Dockerfile --push .",
33
38
  "test": "ava --timeout=1m test/append-to-array-test.js test/fs-mock-test.js test/markdownlint-cli2-test.js test/markdownlint-cli2-test-exec.js test/markdownlint-cli2-test-fs.js test/markdownlint-cli2-test-main.js test/merge-options-test.js test/resolve-and-require-test.js",
34
39
  "test-docker-image": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker run --rm -v $PWD:/workdir davidanson/markdownlint-cli2:v$VERSION \"*.md\"",
40
+ "test-docker-image-rules": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker run --rm -v $PWD:/workdir davidanson/markdownlint-cli2-rules:v$VERSION \"*.md\"",
35
41
  "test-docker-hub-image": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker image rm davidanson/markdownlint-cli2:v$VERSION davidanson/markdownlint-cli2:latest || true && docker run --rm -v $PWD:/workdir davidanson/markdownlint-cli2:v$VERSION \"*.md\" && docker run --rm -v $PWD:/workdir davidanson/markdownlint-cli2:latest \"*.md\"",
42
+ "test-docker-hub-image-rules": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker image rm davidanson/markdownlint-cli2-rules:v$VERSION davidanson/markdownlint-cli2-rules:latest || true && docker run --rm -v $PWD:/workdir davidanson/markdownlint-cli2-rules:v$VERSION \"*.md\" && docker run --rm -v $PWD:/workdir davidanson/markdownlint-cli2-rules:latest \"*.md\"",
36
43
  "test-cover": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 npm test",
37
44
  "test-watch": "git ls-files | entr npm run test",
38
- "update-snapshots": "ava --update-snapshots test/markdownlint-cli2-test-exec.js test/markdownlint-cli2-test-fs.js test/markdownlint-cli2-test-main.js",
45
+ "update-snapshots": "ava --timeout=1m --update-snapshots test/markdownlint-cli2-test-exec.js test/markdownlint-cli2-test-fs.js test/markdownlint-cli2-test-main.js",
39
46
  "upgrade": "npx --yes npm-check-updates --upgrade",
40
47
  "webworker": "cd webworker && webpack --mode none",
41
48
  "webworker-install": "npm run docker-npm-install -- --no-save path-browserify process setimmediate stream-browserify url util webpack-cli"
42
49
  },
43
50
  "engines": {
44
- "node": ">=14"
51
+ "node": ">=14.18.0"
45
52
  },
46
53
  "files": [
47
54
  "append-to-array.js",
55
+ "export-markdownlint.js",
56
+ "export-markdownlint-helpers.js",
48
57
  "markdownlint-cli2.js",
49
58
  "markdownlint-cli2-config.js",
50
59
  "markdownlint-cli2-fix.js",
@@ -52,29 +61,30 @@
52
61
  "resolve-and-require.js"
53
62
  ],
54
63
  "dependencies": {
55
- "globby": "13.1.2",
56
- "markdownlint": "0.26.2",
57
- "markdownlint-cli2-formatter-default": "0.0.3",
64
+ "globby": "13.1.4",
65
+ "markdownlint": "0.28.1",
66
+ "markdownlint-cli2-formatter-default": "0.0.4",
58
67
  "micromatch": "4.0.5",
59
68
  "strip-json-comments": "5.0.0",
60
- "yaml": "2.1.1"
69
+ "yaml": "2.2.1"
61
70
  },
62
71
  "devDependencies": {
63
72
  "@iktakahiro/markdown-it-katex": "4.0.1",
64
- "ava": "4.3.1",
65
- "c8": "7.12.0",
73
+ "ava": "5.2.0",
74
+ "c8": "7.13.0",
66
75
  "cpy": "9.0.1",
67
76
  "del": "7.0.0",
68
- "eslint": "8.21.0",
69
- "eslint-plugin-node": "11.1.0",
70
- "eslint-plugin-unicorn": "43.0.2",
71
- "execa": "6.1.0",
77
+ "eslint": "8.38.0",
78
+ "eslint-plugin-n": "15.7.0",
79
+ "eslint-plugin-unicorn": "46.0.0",
80
+ "execa": "7.1.1",
72
81
  "markdown-it-emoji": "2.0.2",
73
82
  "markdown-it-for-inline": "0.1.1",
74
- "markdownlint-cli2-formatter-json": "0.0.6",
75
- "markdownlint-cli2-formatter-junit": "0.0.5",
76
- "markdownlint-cli2-formatter-pretty": "0.0.3",
77
- "markdownlint-cli2-formatter-summarize": "0.0.5",
83
+ "markdownlint-cli2-formatter-codequality": "0.0.4",
84
+ "markdownlint-cli2-formatter-json": "0.0.7",
85
+ "markdownlint-cli2-formatter-junit": "0.0.6",
86
+ "markdownlint-cli2-formatter-pretty": "0.0.4",
87
+ "markdownlint-cli2-formatter-summarize": "0.0.6",
78
88
  "markdownlint-rule-titlecase": "0.1.0",
79
89
  "npm-run-all": "4.1.5"
80
90
  },