markdownlint-cli2 0.3.1 → 0.5.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 +1 -1
- package/README.md +80 -41
- package/markdownlint-cli2-config.js +11 -0
- package/markdownlint-cli2-fix.js +2 -1
- package/markdownlint-cli2.js +305 -101
- package/package.json +41 -33
- package/resolve-and-require.js +3 -4
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -20,8 +20,11 @@ As a development dependency of the current package:
|
|
|
20
20
|
npm install markdownlint-cli2 --save-dev
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
Or
|
|
24
|
-
|
|
23
|
+
Or as a Docker container image:
|
|
24
|
+
|
|
25
|
+
```shell
|
|
26
|
+
docker pull davidanson/markdownlint-cli2
|
|
27
|
+
```
|
|
25
28
|
|
|
26
29
|
## Overview
|
|
27
30
|
|
|
@@ -51,13 +54,16 @@ markdownlint-cli2 vX.Y.Z (markdownlint vX.Y.Z)
|
|
|
51
54
|
https://github.com/DavidAnson/markdownlint-cli2
|
|
52
55
|
|
|
53
56
|
Syntax: markdownlint-cli2 glob0 [glob1] [...] [globN]
|
|
57
|
+
markdownlint-cli2-fix glob0 [glob1] [...] [globN]
|
|
58
|
+
markdownlint-cli2-config config-file glob0 [glob1] [...] [globN]
|
|
54
59
|
|
|
55
60
|
Glob expressions (from the globby library):
|
|
56
61
|
- * matches any number of characters, but not /
|
|
57
62
|
- ? matches a single character, but not /
|
|
58
|
-
- ** matches any number of characters, including /
|
|
63
|
+
- ** matches any number of characters, including /
|
|
59
64
|
- {} allows for a comma-separated list of "or" expressions
|
|
60
65
|
- ! or # at the beginning of a pattern negate the match
|
|
66
|
+
- : at the beginning identifies a literal file path
|
|
61
67
|
|
|
62
68
|
Dot-only glob:
|
|
63
69
|
- The command "markdownlint-cli2 ." would lint every file in the current directory tree which is probably not intended
|
|
@@ -67,10 +73,10 @@ Dot-only glob:
|
|
|
67
73
|
Configuration via:
|
|
68
74
|
- .markdownlint-cli2.jsonc
|
|
69
75
|
- .markdownlint-cli2.yaml
|
|
70
|
-
- .markdownlint-cli2.
|
|
76
|
+
- .markdownlint-cli2.cjs or .markdownlint-cli2.mjs
|
|
71
77
|
- .markdownlint.jsonc or .markdownlint.json
|
|
72
78
|
- .markdownlint.yaml or .markdownlint.yml
|
|
73
|
-
- .markdownlint.
|
|
79
|
+
- .markdownlint.cjs or .markdownlint.mjs
|
|
74
80
|
|
|
75
81
|
Cross-platform compatibility:
|
|
76
82
|
- UNIX and Windows shells expand globs according to different rules; quoting arguments is recommended
|
|
@@ -79,31 +85,45 @@ Cross-platform compatibility:
|
|
|
79
85
|
- Some UNIX shells parse exclamation (!) in double-quotes; hashtag (#) is recommended in these cases
|
|
80
86
|
- The path separator is forward slash (/) on all platforms; backslash (\) is automatically converted
|
|
81
87
|
|
|
82
|
-
|
|
88
|
+
The most compatible syntax for cross-platform support:
|
|
83
89
|
$ markdownlint-cli2 "**/*.md" "#node_modules"
|
|
84
90
|
```
|
|
85
91
|
|
|
86
92
|
For scenarios where it is preferable to specify glob expressions in a
|
|
87
|
-
configuration file, the `globs` property of `.markdownlint-cli2.jsonc
|
|
88
|
-
`.
|
|
89
|
-
|
|
93
|
+
configuration file, the `globs` property of `.markdownlint-cli2.jsonc`, `.yaml`,
|
|
94
|
+
`.cjs`, or `.mjs` may be used instead of (or in addition to) passing
|
|
95
|
+
`glob0 ... globN` on the command-line.
|
|
90
96
|
|
|
91
|
-
As shown above,
|
|
97
|
+
As shown above, a typical command-line for `markdownlint-cli2` looks something
|
|
92
98
|
like:
|
|
93
99
|
|
|
94
100
|
```bash
|
|
95
101
|
markdownlint-cli2 "**/*.md" "#node_modules"
|
|
96
102
|
```
|
|
97
103
|
|
|
98
|
-
|
|
104
|
+
Because sharing the same configuration between "normal" and "fix" modes is
|
|
99
105
|
common, the following command defaults the `fix` property (see below) to `true`:
|
|
100
106
|
|
|
101
107
|
```bash
|
|
102
108
|
markdownlint-cli2-fix "**/*.md" "#node_modules"
|
|
103
109
|
```
|
|
104
110
|
|
|
105
|
-
Other than the default behavior of the `fix` property (which can be overridden
|
|
106
|
-
|
|
111
|
+
Other than the default behavior of the `fix` property (which can be overridden),
|
|
112
|
+
these two commands behave identically.
|
|
113
|
+
|
|
114
|
+
In cases where it is not convenient to store a configuration file in the root
|
|
115
|
+
of a project, the `markdownlint-cli2-config` command can be used. This command
|
|
116
|
+
accepts a path to any supported configuration file as its first argument:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
markdownlint-cli2-config "config/.markdownlint-cli2.jsonc" "**/*.md" "#node_modules"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The configuration file name must be (or end with) one of the supported types
|
|
123
|
+
above. For example, `.markdownlint.json` or `example.markdownlint-cli2.jsonc`.
|
|
124
|
+
The specified configuration file will be loaded, parsed, and applied as a base
|
|
125
|
+
configuration for the current directory - which will then be handled normally.
|
|
126
|
+
Otherwise, this command behaves identically to `markdownlint-cli2`.
|
|
107
127
|
|
|
108
128
|
### Container Image
|
|
109
129
|
|
|
@@ -111,7 +131,7 @@ A container image [`davidanson/markdownlint-cli2`][docker-hub-markdownlint-cli2]
|
|
|
111
131
|
can also be used (e.g., as part of a CI pipeline):
|
|
112
132
|
|
|
113
133
|
```bash
|
|
114
|
-
docker run -v $PWD:/workdir davidanson/markdownlint-cli2:0.
|
|
134
|
+
docker run -v $PWD:/workdir davidanson/markdownlint-cli2:0.5.0 "**/*.md" "#node_modules"
|
|
115
135
|
```
|
|
116
136
|
|
|
117
137
|
Notes:
|
|
@@ -123,19 +143,19 @@ Notes:
|
|
|
123
143
|
runs with restricted permissions. If it is necessary to run as `root`, pass
|
|
124
144
|
the `-u root` option when invoking `docker`.
|
|
125
145
|
- By default, `markdownlint-cli2` will execute within the `/workdir` directory
|
|
126
|
-
|
|
146
|
+
*inside the container*. So, as shown above, [bind mount][docker-bind-mounts]
|
|
127
147
|
the project's directory there.
|
|
128
148
|
- A custom working directory can be specified with Docker's `-w` flag:
|
|
129
149
|
|
|
130
150
|
```bash
|
|
131
|
-
docker run -w /myfolder -v $PWD:/myfolder davidanson/markdownlint-cli2:0.
|
|
151
|
+
docker run -w /myfolder -v $PWD:/myfolder davidanson/markdownlint-cli2:0.5.0 "**/*.md" "#node_modules"
|
|
132
152
|
```
|
|
133
153
|
|
|
134
|
-
To invoke the `markdownlint-cli2-
|
|
135
|
-
`--entrypoint` flag:
|
|
154
|
+
To invoke the `markdownlint-cli2-config` or `markdownlint-cli2-fix` commands
|
|
155
|
+
instead, use Docker's `--entrypoint` flag:
|
|
136
156
|
|
|
137
157
|
```bash
|
|
138
|
-
docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/markdownlint-cli2:0.
|
|
158
|
+
docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/markdownlint-cli2:0.5.0 "**/*.md" "#node_modules"
|
|
139
159
|
```
|
|
140
160
|
|
|
141
161
|
### Exit Codes
|
|
@@ -159,11 +179,11 @@ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/mark
|
|
|
159
179
|
- See the [Configuration][markdownlint-configuration] section of the
|
|
160
180
|
`markdownlint` documentation for information about the inline comment syntax
|
|
161
181
|
for enabling and disabling rules with HTML comments.
|
|
162
|
-
- In general, glob expressions match files under the current directory and
|
|
163
|
-
configuration for that
|
|
182
|
+
- In general, glob expressions match files under the current directory and the
|
|
183
|
+
configuration for that directory applies to the entire tree.
|
|
164
184
|
- When glob expressions match files *not* under the current directory,
|
|
165
|
-
configuration for the current
|
|
166
|
-
|
|
185
|
+
configuration for the current directory is applied to the closest common
|
|
186
|
+
parent directory.
|
|
167
187
|
|
|
168
188
|
### `.markdownlint-cli2.jsonc`
|
|
169
189
|
|
|
@@ -177,8 +197,6 @@ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/mark
|
|
|
177
197
|
- `customRules`: `Array` of `String`s (or `Array`s of `String`s) of module
|
|
178
198
|
names/paths of [custom rules][markdownlint-custom-rules] to load and use
|
|
179
199
|
when linting
|
|
180
|
-
- Each `String` is passed as the `id` parameter to Node's
|
|
181
|
-
[require function][nodejs-require]
|
|
182
200
|
- Relative paths are resolved based on the location of the `JSONC` file
|
|
183
201
|
- Search [`markdownlint-rule` on npm][markdownlint-rule]
|
|
184
202
|
- `fix`: `Boolean` value to enable fixing of linting errors reported by rules
|
|
@@ -229,9 +247,16 @@ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/mark
|
|
|
229
247
|
- This top-level setting is valid **only** in the directory from which
|
|
230
248
|
`markdownlint-cli2` is run
|
|
231
249
|
- Search [`markdownlint-cli2-formatter` on npm][markdownlint-cli2-formatter]
|
|
250
|
+
- When referencing a module via the `customRules`, `markdownItPlugins`, or
|
|
251
|
+
`outputFormatters` properties, each `String` identifier is passed to Node's
|
|
252
|
+
[`require` function][nodejs-require] then (if that failed) its
|
|
253
|
+
[`import` expression][nodejs-import-expression]
|
|
254
|
+
- Importing a locally-installed module using a bare specifier (ex:
|
|
255
|
+
`package-name`) or using a directory name (ex: `./package-dir`) will not
|
|
256
|
+
work until [`import.meta.resolve`][nodejs-import-meta-resolve] is available
|
|
232
257
|
- Settings in this file apply to the directory it is in and all subdirectories.
|
|
233
258
|
- Settings **merge with** those applied by any versions of this file in a parent
|
|
234
|
-
directory.
|
|
259
|
+
directory (up to the current directory).
|
|
235
260
|
- For example: [`.markdownlint-cli2.jsonc`][markdownlint-cli2-jsonc] with all
|
|
236
261
|
properties set
|
|
237
262
|
|
|
@@ -245,17 +270,20 @@ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/mark
|
|
|
245
270
|
- For example: [`.markdownlint-cli2.yaml`][markdownlint-cli2-yaml] with all
|
|
246
271
|
properties set
|
|
247
272
|
|
|
248
|
-
### `.markdownlint-cli2.
|
|
273
|
+
### `.markdownlint-cli2.cjs` or `.markdownlint-cli2.mjs`
|
|
249
274
|
|
|
250
|
-
- The format of this file is a [CommonJS module][commonjs-module]
|
|
251
|
-
|
|
275
|
+
- The format of this file is a [CommonJS module][commonjs-module] (`.cjs`) or
|
|
276
|
+
[ECMAScript module][ecmascript-module] (`.mjs`) that exports the object
|
|
277
|
+
described above for `.markdownlint-cli2.jsonc`.
|
|
252
278
|
- Instead of passing a `String` to identify the module name/path to load for
|
|
253
279
|
`customRules`, `markdownItPlugins`, and `outputFormatters`, the corresponding
|
|
254
280
|
`Object` or `Function` can be provided directly.
|
|
255
281
|
- Other details are the same as for `.markdownlint-cli2.jsonc` described above.
|
|
256
282
|
- If a `.markdownlint-cli2.jsonc` or `.markdownlint-cli2.yaml` file is present
|
|
257
|
-
in the same directory, it takes precedence.
|
|
258
|
-
|
|
283
|
+
in the same directory, it takes precedence; `.markdownlint-cli2.cjs` takes
|
|
284
|
+
precedence over `.markdownlint-cli2.mjs`.
|
|
285
|
+
- For example: [`.markdownlint-cli2.cjs`][markdownlint-cli2-cjs] or
|
|
286
|
+
[`.markdownlint-cli2.mjs`][markdownlint-cli2-mjs]
|
|
259
287
|
|
|
260
288
|
### `.markdownlint.jsonc` or `.markdownlint.json`
|
|
261
289
|
|
|
@@ -263,7 +291,7 @@ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/mark
|
|
|
263
291
|
the [`markdownlint` `config` object][markdownlint-config].
|
|
264
292
|
- Settings in this file apply to the directory it is in and all subdirectories
|
|
265
293
|
- Settings **override** those applied by any versions of this file in a parent
|
|
266
|
-
directory.
|
|
294
|
+
directory (up to the current directory).
|
|
267
295
|
- If `jsonc` and `json` files are present in the same directory, the `jsonc`
|
|
268
296
|
version takes precedence.
|
|
269
297
|
- To merge the settings of these files or share configuration, use the `extends`
|
|
@@ -282,14 +310,17 @@ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/mark
|
|
|
282
310
|
precedence.
|
|
283
311
|
- For example: [`.markdownlint.yaml`][markdownlint-yaml]
|
|
284
312
|
|
|
285
|
-
### `.markdownlint.
|
|
313
|
+
### `.markdownlint.cjs` or `.markdownlint.mjs`
|
|
286
314
|
|
|
287
|
-
- The format of this file is a [CommonJS module][commonjs-module]
|
|
288
|
-
|
|
315
|
+
- The format of this file is a [CommonJS module][commonjs-module] (`.cjs`) or
|
|
316
|
+
[ECMAScript module][ecmascript-module] (`.mjs`) that exports the
|
|
317
|
+
[`markdownlint` `config` object][markdownlint-config].
|
|
289
318
|
- Other details are the same as for `jsonc`/`json` files described above.
|
|
290
|
-
- If a
|
|
291
|
-
it takes precedence.
|
|
292
|
-
|
|
319
|
+
- If a `.markdownlint.jsonc`, `.json`, `.yaml`, or `.yml` file is present in the
|
|
320
|
+
same directory, it takes precedence; `.markdownlint.cjs` takes precedence over
|
|
321
|
+
`.markdownlint.mjs`.
|
|
322
|
+
- For example: [`.markdownlint.cjs`][markdownlint-cjs] or
|
|
323
|
+
[`.markdownlint.mjs`][markdownlint-mjs]
|
|
293
324
|
|
|
294
325
|
## Compatibility
|
|
295
326
|
|
|
@@ -313,7 +344,7 @@ reference to the `repos` list in that project's `.pre-commit-config.yaml` like:
|
|
|
313
344
|
|
|
314
345
|
```yaml
|
|
315
346
|
- repo: https://github.com/DavidAnson/markdownlint-cli2
|
|
316
|
-
rev: v0.
|
|
347
|
+
rev: v0.5.0
|
|
317
348
|
hooks:
|
|
318
349
|
- id: markdownlint-cli2
|
|
319
350
|
```
|
|
@@ -344,11 +375,15 @@ reference to the `repos` list in that project's `.pre-commit-config.yaml` like:
|
|
|
344
375
|
- 0.2.0 - Improve handling of Windows paths using backslash
|
|
345
376
|
- 0.3.0 - Add Docker container, update dependencies
|
|
346
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
|
|
347
381
|
|
|
348
382
|
<!-- markdownlint-disable line-length -->
|
|
349
383
|
|
|
350
384
|
[commonmark]: https://commonmark.org/
|
|
351
385
|
[commonjs-module]: https://nodejs.org/api/modules.html#modules_modules_commonjs_modules
|
|
386
|
+
[ecmascript-module]: https://nodejs.org/api/esm.html#modules-ecmascript-modules
|
|
352
387
|
[docker-bind-mounts]: https://docs.docker.com/storage/bind-mounts/
|
|
353
388
|
[docker-hub-markdownlint-cli2]: https://hub.docker.com/r/davidanson/markdownlint-cli2
|
|
354
389
|
[front-matter]: https://jekyllrb.com/docs/frontmatter/
|
|
@@ -373,16 +408,20 @@ reference to the `repos` list in that project's `.pre-commit-config.yaml` like:
|
|
|
373
408
|
[markdownlint-cli2]: https://github.com/DavidAnson/markdownlint-cli2
|
|
374
409
|
[markdownlint-cli2-blog]: https://dlaa.me/blog/post/markdownlintcli2
|
|
375
410
|
[markdownlint-cli2-formatter]: https://www.npmjs.com/search?q=keywords:markdownlint-cli2-formatter
|
|
376
|
-
[markdownlint-cli2-
|
|
411
|
+
[markdownlint-cli2-cjs]: test/markdownlint-cli2-cjs/.markdownlint-cli2.cjs
|
|
377
412
|
[markdownlint-cli2-jsonc]: test/markdownlint-cli2-jsonc-example/.markdownlint-cli2.jsonc
|
|
413
|
+
[markdownlint-cli2-mjs]: test/markdownlint-cli2-mjs/.markdownlint-cli2.mjs
|
|
378
414
|
[markdownlint-cli2-yaml]: test/markdownlint-cli2-yaml-example/.markdownlint-cli2.yaml
|
|
379
|
-
[markdownlint-
|
|
415
|
+
[markdownlint-cjs]: test/markdownlint-cjs/.markdownlint.cjs
|
|
380
416
|
[markdownlint-jsonc]: https://github.com/DavidAnson/markdownlint/blob/main/schema/.markdownlint.jsonc
|
|
417
|
+
[markdownlint-mjs]: test/markdownlint-mjs/.markdownlint.mjs
|
|
381
418
|
[markdownlint-rule]: https://www.npmjs.com/search?q=keywords:markdownlint-rule
|
|
382
419
|
[markdownlint-yaml]: https://github.com/DavidAnson/markdownlint/blob/main/schema/.markdownlint.yaml
|
|
383
420
|
[nodejs]: https://nodejs.org/
|
|
384
421
|
[nodejs-docker]: https://github.com/nodejs/docker-node
|
|
385
422
|
[nodejs-docker-non-root]: https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md#non-root-user
|
|
423
|
+
[nodejs-import-expression]: https://nodejs.org/api/esm.html#import-expressions
|
|
424
|
+
[nodejs-import-meta-resolve]: https://nodejs.org/api/esm.html#importmetaresolvespecifier-parent
|
|
386
425
|
[nodejs-require]: https://nodejs.org/api/modules.html#modules_require_id
|
|
387
426
|
[npm-image]: https://img.shields.io/npm/v/markdownlint-cli2.svg
|
|
388
427
|
[npm-url]: https://www.npmjs.com/package/markdownlint-cli2
|
package/markdownlint-cli2-fix.js
CHANGED
package/markdownlint-cli2.js
CHANGED
|
@@ -10,19 +10,19 @@ const dynamicRequire = (typeof __non_webpack_require__ === "undefined") ? requir
|
|
|
10
10
|
// Capture native require implementation for dynamic loading of modules
|
|
11
11
|
|
|
12
12
|
// Requires
|
|
13
|
-
const path = require("path");
|
|
14
|
-
const
|
|
13
|
+
const path = require("node:path");
|
|
14
|
+
const { pathToFileURL } = require("node:url");
|
|
15
15
|
const markdownlintLibrary = require("markdownlint");
|
|
16
16
|
const { markdownlint, "readConfig": markdownlintReadConfig } =
|
|
17
17
|
markdownlintLibrary.promises;
|
|
18
|
-
const markdownlintRuleHelpers = require("markdownlint
|
|
18
|
+
const markdownlintRuleHelpers = require("markdownlint/helpers");
|
|
19
19
|
const appendToArray = require("./append-to-array");
|
|
20
20
|
const mergeOptions = require("./merge-options");
|
|
21
21
|
const resolveAndRequire = require("./resolve-and-require");
|
|
22
22
|
|
|
23
23
|
// Variables
|
|
24
24
|
const packageName = "markdownlint-cli2";
|
|
25
|
-
const packageVersion = "0.
|
|
25
|
+
const packageVersion = "0.5.0";
|
|
26
26
|
const libraryName = "markdownlint";
|
|
27
27
|
const libraryVersion = markdownlintLibrary.getVersion();
|
|
28
28
|
const dotOnlySubstitute = "*.{md,markdown}";
|
|
@@ -31,10 +31,16 @@ const utf8 = "utf8";
|
|
|
31
31
|
// No-op function
|
|
32
32
|
const noop = () => null;
|
|
33
33
|
|
|
34
|
-
//
|
|
35
|
-
const
|
|
34
|
+
// Gets a synchronous function to parse JSONC text
|
|
35
|
+
const getJsoncParse = async () => {
|
|
36
|
+
const { "default": stripJsonComments } =
|
|
37
|
+
// eslint-disable-next-line max-len
|
|
38
|
+
// eslint-disable-next-line no-inline-comments, node/no-unsupported-features/es-syntax
|
|
39
|
+
await import(/* webpackMode: "eager" */ "strip-json-comments");
|
|
40
|
+
return (text) => JSON.parse(stripJsonComments(text));
|
|
41
|
+
};
|
|
36
42
|
|
|
37
|
-
//
|
|
43
|
+
// Synchronous function to parse YAML text
|
|
38
44
|
const yamlParse = (text) => require("yaml").parse(text);
|
|
39
45
|
|
|
40
46
|
// Negate a glob
|
|
@@ -48,54 +54,142 @@ const readConfig = (fs, dir, name, otherwise) => {
|
|
|
48
54
|
const file = path.posix.join(dir, name);
|
|
49
55
|
return () => fs.promises.access(file).
|
|
50
56
|
then(
|
|
51
|
-
|
|
52
|
-
|
|
57
|
+
() => getJsoncParse().then(
|
|
58
|
+
(jsoncParse) => markdownlintReadConfig(
|
|
59
|
+
file,
|
|
60
|
+
[ jsoncParse, yamlParse ],
|
|
61
|
+
fs
|
|
62
|
+
)
|
|
63
|
+
),
|
|
53
64
|
otherwise
|
|
54
65
|
);
|
|
55
66
|
};
|
|
56
67
|
|
|
57
|
-
//
|
|
58
|
-
const
|
|
68
|
+
// Import or resolve/require a module ID with a custom directory in the path
|
|
69
|
+
const importOrRequireResolve = async (dir, id) => {
|
|
59
70
|
if (typeof id === "string") {
|
|
60
|
-
|
|
71
|
+
const expandId =
|
|
72
|
+
markdownlintRuleHelpers.expandTildePath(id, require("node:os"));
|
|
73
|
+
const errors = [];
|
|
74
|
+
try {
|
|
75
|
+
return resolveAndRequire(dynamicRequire, expandId, dir);
|
|
76
|
+
} catch (error) {
|
|
77
|
+
errors.push(error);
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const fileUrlString =
|
|
81
|
+
pathToFileURL(path.resolve(dir, expandId)).toString();
|
|
82
|
+
// eslint-disable-next-line node/no-unsupported-features/es-syntax
|
|
83
|
+
const module = await import(fileUrlString);
|
|
84
|
+
return module.default;
|
|
85
|
+
} catch (error) {
|
|
86
|
+
errors.push(error);
|
|
87
|
+
}
|
|
88
|
+
// Use AggregateError once available in Node 15+
|
|
89
|
+
throw new Error(errors.map((error) => error.message).join(" / "));
|
|
61
90
|
}
|
|
62
91
|
return id;
|
|
63
92
|
};
|
|
64
93
|
|
|
65
|
-
//
|
|
66
|
-
const
|
|
67
|
-
noRequire ? [] : ids.map((id) =>
|
|
94
|
+
// Import or require an array of modules by ID
|
|
95
|
+
const importOrRequireIds = (dir, ids, noRequire) => (
|
|
96
|
+
Promise.all(noRequire ? [] : ids.map((id) => importOrRequireResolve(dir, id)))
|
|
68
97
|
);
|
|
69
98
|
|
|
70
|
-
//
|
|
71
|
-
const
|
|
99
|
+
// Import or require an array of modules by ID (preserving parameters)
|
|
100
|
+
const importOrRequireIdsAndParams = async (dir, idsAndParams, noRequire) => {
|
|
72
101
|
if (noRequire) {
|
|
73
102
|
return [];
|
|
74
103
|
}
|
|
75
104
|
const ids = idsAndParams.map((entry) => entry[0]);
|
|
76
|
-
const modules =
|
|
105
|
+
const modules = await importOrRequireIds(dir, ids);
|
|
77
106
|
const modulesAndParams = idsAndParams.
|
|
78
107
|
map((entry, i) => [ modules[i], ...entry.slice(1) ]);
|
|
79
108
|
return modulesAndParams;
|
|
80
109
|
};
|
|
81
110
|
|
|
82
|
-
//
|
|
83
|
-
const
|
|
111
|
+
// Import or require a JavaScript file and return the exported object
|
|
112
|
+
const importOrRequireConfig = (fs, dir, name, noRequire, otherwise) => (
|
|
84
113
|
() => (noRequire
|
|
85
114
|
// eslint-disable-next-line prefer-promise-reject-errors
|
|
86
115
|
? Promise.reject()
|
|
87
116
|
: fs.promises.access(path.posix.join(dir, name))
|
|
88
117
|
).
|
|
89
118
|
then(
|
|
90
|
-
() =>
|
|
91
|
-
|
|
119
|
+
() => importOrRequireResolve(dir, `./${name}`),
|
|
120
|
+
otherwise
|
|
92
121
|
)
|
|
93
122
|
);
|
|
94
123
|
|
|
95
|
-
//
|
|
124
|
+
// Read an options or config file in any format and return the object
|
|
125
|
+
const readOptionsOrConfig = async (configPath, fs, noRequire) => {
|
|
126
|
+
const basename = path.basename(configPath);
|
|
127
|
+
const dirname = path.dirname(configPath);
|
|
128
|
+
let options = null;
|
|
129
|
+
let config = null;
|
|
130
|
+
if (basename.endsWith(".markdownlint-cli2.jsonc")) {
|
|
131
|
+
const jsoncParse = await getJsoncParse();
|
|
132
|
+
options = jsoncParse(await fs.promises.readFile(configPath, utf8));
|
|
133
|
+
} else if (basename.endsWith(".markdownlint-cli2.yaml")) {
|
|
134
|
+
options = yamlParse(await fs.promises.readFile(configPath, utf8));
|
|
135
|
+
} else if (
|
|
136
|
+
basename.endsWith(".markdownlint-cli2.cjs") ||
|
|
137
|
+
basename.endsWith(".markdownlint-cli2.mjs")
|
|
138
|
+
) {
|
|
139
|
+
options = await (
|
|
140
|
+
importOrRequireConfig(fs, dirname, basename, noRequire, noop)()
|
|
141
|
+
);
|
|
142
|
+
} else if (
|
|
143
|
+
basename.endsWith(".markdownlint.jsonc") ||
|
|
144
|
+
basename.endsWith(".markdownlint.json") ||
|
|
145
|
+
basename.endsWith(".markdownlint.yaml") ||
|
|
146
|
+
basename.endsWith(".markdownlint.yml")
|
|
147
|
+
) {
|
|
148
|
+
const jsoncParse = await getJsoncParse();
|
|
149
|
+
config =
|
|
150
|
+
await markdownlintReadConfig(configPath, [ jsoncParse, yamlParse ], fs);
|
|
151
|
+
} else if (
|
|
152
|
+
basename.endsWith(".markdownlint.cjs") ||
|
|
153
|
+
basename.endsWith(".markdownlint.mjs")
|
|
154
|
+
) {
|
|
155
|
+
config = await (
|
|
156
|
+
importOrRequireConfig(fs, dirname, basename, noRequire, noop)()
|
|
157
|
+
);
|
|
158
|
+
} else {
|
|
159
|
+
throw new Error(
|
|
160
|
+
`Configuration file "${configPath}" is unrecognized; ` +
|
|
161
|
+
"its name should be (or end with) one of the supported types " +
|
|
162
|
+
"(e.g., \".markdownlint.json\" or \"example.markdownlint-cli2.jsonc\")."
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
return options || { config };
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
// Filter a list of files to ignore by glob
|
|
169
|
+
const removeIgnoredFiles = (dir, files, ignores) => {
|
|
170
|
+
const micromatch = require("micromatch");
|
|
171
|
+
return micromatch(
|
|
172
|
+
files.map((file) => path.posix.relative(dir, file)),
|
|
173
|
+
ignores
|
|
174
|
+
).map((file) => path.posix.join(dir, file));
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// Process/normalize command-line arguments and return glob patterns
|
|
96
178
|
const processArgv = (argv) => {
|
|
97
179
|
const globPatterns = (argv || []).map(
|
|
98
|
-
(glob) =>
|
|
180
|
+
(glob) => {
|
|
181
|
+
if (glob.startsWith(":")) {
|
|
182
|
+
return glob;
|
|
183
|
+
}
|
|
184
|
+
// Escape RegExp special characters recognized by fast-glob
|
|
185
|
+
// https://github.com/mrmlnc/fast-glob#advanced-syntax
|
|
186
|
+
const specialCharacters = /\\(?![$()*+?[\]^])/gu;
|
|
187
|
+
if (glob.startsWith("\\:")) {
|
|
188
|
+
return `\\:${glob.slice(2).replace(specialCharacters, "/")}`;
|
|
189
|
+
}
|
|
190
|
+
return (glob.startsWith("#") ? `!${glob.slice(1)}` : glob).
|
|
191
|
+
replace(specialCharacters, "/");
|
|
192
|
+
}
|
|
99
193
|
);
|
|
100
194
|
if ((globPatterns.length === 1) && (globPatterns[0] === ".")) {
|
|
101
195
|
// Substitute a more reasonable pattern
|
|
@@ -106,31 +200,33 @@ const processArgv = (argv) => {
|
|
|
106
200
|
|
|
107
201
|
// Show help if missing arguments
|
|
108
202
|
const showHelp = (logMessage) => {
|
|
109
|
-
const { name, homepage } = require("./package.json");
|
|
110
203
|
/* eslint-disable max-len */
|
|
111
|
-
logMessage(
|
|
204
|
+
logMessage(`https://github.com/DavidAnson/markdownlint-cli2
|
|
112
205
|
|
|
113
|
-
Syntax:
|
|
206
|
+
Syntax: markdownlint-cli2 glob0 [glob1] [...] [globN]
|
|
207
|
+
markdownlint-cli2-fix glob0 [glob1] [...] [globN]
|
|
208
|
+
markdownlint-cli2-config config-file glob0 [glob1] [...] [globN]
|
|
114
209
|
|
|
115
210
|
Glob expressions (from the globby library):
|
|
116
211
|
- * matches any number of characters, but not /
|
|
117
212
|
- ? matches a single character, but not /
|
|
118
|
-
- ** matches any number of characters, including /
|
|
213
|
+
- ** matches any number of characters, including /
|
|
119
214
|
- {} allows for a comma-separated list of "or" expressions
|
|
120
215
|
- ! or # at the beginning of a pattern negate the match
|
|
216
|
+
- : at the beginning identifies a literal file path
|
|
121
217
|
|
|
122
218
|
Dot-only glob:
|
|
123
|
-
- The command "
|
|
124
|
-
- Instead, it is mapped to "
|
|
125
|
-
- To lint every file in the current directory tree, the command "
|
|
219
|
+
- The command "markdownlint-cli2 ." would lint every file in the current directory tree which is probably not intended
|
|
220
|
+
- Instead, it is mapped to "markdownlint-cli2 ${dotOnlySubstitute}" which lints all Markdown files in the current directory
|
|
221
|
+
- To lint every file in the current directory tree, the command "markdownlint-cli2 **" can be used instead
|
|
126
222
|
|
|
127
223
|
Configuration via:
|
|
128
224
|
- .markdownlint-cli2.jsonc
|
|
129
225
|
- .markdownlint-cli2.yaml
|
|
130
|
-
- .markdownlint-cli2.
|
|
226
|
+
- .markdownlint-cli2.cjs or .markdownlint-cli2.mjs
|
|
131
227
|
- .markdownlint.jsonc or .markdownlint.json
|
|
132
228
|
- .markdownlint.yaml or .markdownlint.yml
|
|
133
|
-
- .markdownlint.
|
|
229
|
+
- .markdownlint.cjs or .markdownlint.mjs
|
|
134
230
|
|
|
135
231
|
Cross-platform compatibility:
|
|
136
232
|
- UNIX and Windows shells expand globs according to different rules; quoting arguments is recommended
|
|
@@ -139,19 +235,20 @@ Cross-platform compatibility:
|
|
|
139
235
|
- Some UNIX shells parse exclamation (!) in double-quotes; hashtag (#) is recommended in these cases
|
|
140
236
|
- The path separator is forward slash (/) on all platforms; backslash (\\) is automatically converted
|
|
141
237
|
|
|
142
|
-
|
|
143
|
-
$
|
|
238
|
+
The most compatible syntax for cross-platform support:
|
|
239
|
+
$ markdownlint-cli2 "**/*.md" "#node_modules"`
|
|
144
240
|
);
|
|
145
241
|
/* eslint-enable max-len */
|
|
146
242
|
};
|
|
147
243
|
|
|
148
244
|
// Get (creating if necessary) and process a directory's info object
|
|
149
245
|
const getAndProcessDirInfo =
|
|
150
|
-
(fs, tasks, dirToDirInfo, dir, noRequire, func) => {
|
|
246
|
+
(fs, tasks, dirToDirInfo, dir, relativeDir, noRequire, func) => {
|
|
151
247
|
let dirInfo = dirToDirInfo[dir];
|
|
152
248
|
if (!dirInfo) {
|
|
153
249
|
dirInfo = {
|
|
154
250
|
dir,
|
|
251
|
+
relativeDir,
|
|
155
252
|
"parent": null,
|
|
156
253
|
"files": [],
|
|
157
254
|
"markdownlintConfig": null,
|
|
@@ -169,17 +266,27 @@ const getAndProcessDirInfo =
|
|
|
169
266
|
then(
|
|
170
267
|
() => fs.promises.
|
|
171
268
|
readFile(markdownlintCli2Jsonc, utf8).
|
|
172
|
-
then(
|
|
269
|
+
then(
|
|
270
|
+
(content) => getJsoncParse().
|
|
271
|
+
then((jsoncParse) => jsoncParse(content))
|
|
272
|
+
),
|
|
173
273
|
() => fs.promises.access(markdownlintCli2Yaml).
|
|
174
274
|
then(
|
|
175
275
|
() => fs.promises.
|
|
176
276
|
readFile(markdownlintCli2Yaml, utf8).
|
|
177
277
|
then(yamlParse),
|
|
178
|
-
|
|
278
|
+
importOrRequireConfig(
|
|
179
279
|
fs,
|
|
180
280
|
dir,
|
|
181
|
-
".markdownlint-cli2.
|
|
182
|
-
noRequire
|
|
281
|
+
".markdownlint-cli2.cjs",
|
|
282
|
+
noRequire,
|
|
283
|
+
importOrRequireConfig(
|
|
284
|
+
fs,
|
|
285
|
+
dir,
|
|
286
|
+
".markdownlint-cli2.mjs",
|
|
287
|
+
noRequire,
|
|
288
|
+
noop
|
|
289
|
+
)
|
|
183
290
|
)
|
|
184
291
|
)
|
|
185
292
|
).
|
|
@@ -206,11 +313,18 @@ const getAndProcessDirInfo =
|
|
|
206
313
|
fs,
|
|
207
314
|
dir,
|
|
208
315
|
".markdownlint.yml",
|
|
209
|
-
|
|
316
|
+
importOrRequireConfig(
|
|
210
317
|
fs,
|
|
211
318
|
dir,
|
|
212
|
-
".markdownlint.
|
|
213
|
-
noRequire
|
|
319
|
+
".markdownlint.cjs",
|
|
320
|
+
noRequire,
|
|
321
|
+
importOrRequireConfig(
|
|
322
|
+
fs,
|
|
323
|
+
dir,
|
|
324
|
+
".markdownlint.mjs",
|
|
325
|
+
noRequire,
|
|
326
|
+
noop
|
|
327
|
+
)
|
|
214
328
|
)
|
|
215
329
|
)
|
|
216
330
|
)
|
|
@@ -233,20 +347,28 @@ const getAndProcessDirInfo =
|
|
|
233
347
|
const getBaseOptions = async (
|
|
234
348
|
fs,
|
|
235
349
|
baseDir,
|
|
350
|
+
relativeDir,
|
|
236
351
|
globPatterns,
|
|
237
|
-
|
|
352
|
+
options,
|
|
238
353
|
fixDefault,
|
|
239
354
|
noGlobs,
|
|
240
355
|
noRequire
|
|
241
356
|
) => {
|
|
242
357
|
const tasks = [];
|
|
243
358
|
const dirToDirInfo = {};
|
|
244
|
-
getAndProcessDirInfo(
|
|
359
|
+
getAndProcessDirInfo(
|
|
360
|
+
fs,
|
|
361
|
+
tasks,
|
|
362
|
+
dirToDirInfo,
|
|
363
|
+
baseDir,
|
|
364
|
+
relativeDir,
|
|
365
|
+
noRequire
|
|
366
|
+
);
|
|
245
367
|
await Promise.all(tasks);
|
|
246
368
|
// eslint-disable-next-line no-multi-assign
|
|
247
369
|
const baseMarkdownlintOptions = dirToDirInfo[baseDir].markdownlintOptions =
|
|
248
370
|
mergeOptions(
|
|
249
|
-
mergeOptions(
|
|
371
|
+
mergeOptions(options, { "fix": fixDefault }),
|
|
250
372
|
dirToDirInfo[baseDir].markdownlintOptions
|
|
251
373
|
);
|
|
252
374
|
|
|
@@ -261,7 +383,6 @@ const getBaseOptions = async (
|
|
|
261
383
|
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
262
384
|
(baseMarkdownlintOptions.ignores || []).map(negateGlob);
|
|
263
385
|
appendToArray(globPatterns, ignorePatterns);
|
|
264
|
-
delete baseMarkdownlintOptions.ignores;
|
|
265
386
|
|
|
266
387
|
return {
|
|
267
388
|
baseMarkdownlintOptions,
|
|
@@ -271,21 +392,51 @@ const getBaseOptions = async (
|
|
|
271
392
|
|
|
272
393
|
// Enumerate files from globs and build directory infos
|
|
273
394
|
const enumerateFiles =
|
|
274
|
-
|
|
395
|
+
// eslint-disable-next-line max-len
|
|
396
|
+
async (fs, baseDirSystem, baseDir, globPatterns, dirToDirInfo, noErrors, noRequire) => {
|
|
275
397
|
const tasks = [];
|
|
276
398
|
const globbyOptions = {
|
|
277
399
|
"absolute": true,
|
|
278
400
|
"cwd": baseDir,
|
|
401
|
+
"dot": true,
|
|
279
402
|
"expandDirectories": false,
|
|
280
403
|
fs
|
|
281
404
|
};
|
|
405
|
+
if (noErrors) {
|
|
406
|
+
globbyOptions.suppressErrors = true;
|
|
407
|
+
}
|
|
408
|
+
// Special-case literal files
|
|
409
|
+
const literalFiles = [];
|
|
410
|
+
const filteredGlobPatterns = globPatterns.filter(
|
|
411
|
+
(globPattern) => {
|
|
412
|
+
if (globPattern.startsWith(":")) {
|
|
413
|
+
literalFiles.push(
|
|
414
|
+
posixPath(path.resolve(baseDirSystem, globPattern.slice(1)))
|
|
415
|
+
);
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
return true;
|
|
419
|
+
}
|
|
420
|
+
).map((globPattern) => globPattern.replace(/^\\:/u, ":"));
|
|
421
|
+
const baseMarkdownlintOptions = dirToDirInfo[baseDir].markdownlintOptions;
|
|
422
|
+
const globsForIgnore =
|
|
423
|
+
(baseMarkdownlintOptions.globs || []).
|
|
424
|
+
filter((glob) => glob.startsWith("!"));
|
|
425
|
+
const filteredLiteralFiles =
|
|
426
|
+
((literalFiles.length > 0) && (globsForIgnore.length > 0))
|
|
427
|
+
? removeIgnoredFiles(baseDir, literalFiles, globsForIgnore)
|
|
428
|
+
: literalFiles;
|
|
282
429
|
// Manually expand directories to avoid globby call to dir-glob.sync
|
|
283
430
|
const expandedDirectories = await Promise.all(
|
|
284
|
-
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
431
|
+
filteredGlobPatterns.map((globPattern) => {
|
|
432
|
+
const barePattern =
|
|
433
|
+
globPattern.startsWith("!")
|
|
434
|
+
? globPattern.slice(1)
|
|
435
|
+
: globPattern;
|
|
436
|
+
const globPath =
|
|
437
|
+
(path.posix.isAbsolute(barePattern) || path.isAbsolute(barePattern))
|
|
438
|
+
? barePattern
|
|
439
|
+
: path.posix.join(baseDir, barePattern);
|
|
289
440
|
return fs.promises.stat(globPath).
|
|
290
441
|
then((stats) => (stats.isDirectory()
|
|
291
442
|
? path.posix.join(globPattern, "**")
|
|
@@ -294,7 +445,13 @@ async (fs, baseDir, globPatterns, dirToDirInfo, noRequire) => {
|
|
|
294
445
|
})
|
|
295
446
|
);
|
|
296
447
|
// Process glob patterns
|
|
297
|
-
|
|
448
|
+
// eslint-disable-next-line max-len
|
|
449
|
+
// eslint-disable-next-line no-inline-comments, node/no-unsupported-features/es-syntax
|
|
450
|
+
const { globby } = await import(/* webpackMode: "eager" */ "globby");
|
|
451
|
+
const files = [
|
|
452
|
+
...await globby(expandedDirectories, globbyOptions),
|
|
453
|
+
...filteredLiteralFiles
|
|
454
|
+
];
|
|
298
455
|
for (const file of files) {
|
|
299
456
|
const dir = path.posix.dirname(file);
|
|
300
457
|
getAndProcessDirInfo(
|
|
@@ -302,6 +459,7 @@ async (fs, baseDir, globPatterns, dirToDirInfo, noRequire) => {
|
|
|
302
459
|
tasks,
|
|
303
460
|
dirToDirInfo,
|
|
304
461
|
dir,
|
|
462
|
+
null,
|
|
305
463
|
noRequire,
|
|
306
464
|
(dirInfo) => {
|
|
307
465
|
dirInfo.files.push(file);
|
|
@@ -339,6 +497,7 @@ const enumerateParents = async (fs, baseDir, dirToDirInfo, noRequire) => {
|
|
|
339
497
|
tasks,
|
|
340
498
|
dirToDirInfo,
|
|
341
499
|
dir,
|
|
500
|
+
null,
|
|
342
501
|
noRequire,
|
|
343
502
|
// eslint-disable-next-line no-loop-func
|
|
344
503
|
(dirInfo) => {
|
|
@@ -357,20 +516,36 @@ const enumerateParents = async (fs, baseDir, dirToDirInfo, noRequire) => {
|
|
|
357
516
|
|
|
358
517
|
// Create directory info objects by enumerating file globs
|
|
359
518
|
const createDirInfos =
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
await
|
|
519
|
+
// eslint-disable-next-line max-len
|
|
520
|
+
async (fs, baseDirSystem, baseDir, globPatterns, dirToDirInfo, optionsOverride, noErrors, noRequire) => {
|
|
521
|
+
await enumerateFiles(
|
|
522
|
+
fs,
|
|
523
|
+
baseDirSystem,
|
|
524
|
+
baseDir,
|
|
525
|
+
globPatterns,
|
|
526
|
+
dirToDirInfo,
|
|
527
|
+
noErrors,
|
|
528
|
+
noRequire
|
|
529
|
+
);
|
|
530
|
+
await enumerateParents(
|
|
531
|
+
fs,
|
|
532
|
+
baseDir,
|
|
533
|
+
dirToDirInfo,
|
|
534
|
+
noRequire
|
|
535
|
+
);
|
|
363
536
|
|
|
364
537
|
// Merge file lists with identical configuration
|
|
365
538
|
const dirs = Object.keys(dirToDirInfo);
|
|
366
539
|
dirs.sort((a, b) => b.length - a.length);
|
|
367
540
|
const dirInfos = [];
|
|
368
541
|
const noConfigDirInfo =
|
|
542
|
+
// eslint-disable-next-line unicorn/consistent-function-scoping
|
|
369
543
|
(dirInfo) => (
|
|
370
544
|
dirInfo.parent &&
|
|
371
545
|
!dirInfo.markdownlintConfig &&
|
|
372
546
|
!dirInfo.markdownlintOptions
|
|
373
547
|
);
|
|
548
|
+
const tasks = [];
|
|
374
549
|
for (const dir of dirs) {
|
|
375
550
|
const dirInfo = dirToDirInfo[dir];
|
|
376
551
|
if (noConfigDirInfo(dirInfo)) {
|
|
@@ -379,28 +554,34 @@ async (fs, baseDir, globPatterns, dirToDirInfo, optionsOverride, noRequire) => {
|
|
|
379
554
|
}
|
|
380
555
|
dirToDirInfo[dir] = null;
|
|
381
556
|
} else {
|
|
382
|
-
const { markdownlintOptions } = dirInfo;
|
|
557
|
+
const { markdownlintOptions, relativeDir } = dirInfo;
|
|
383
558
|
if (markdownlintOptions && markdownlintOptions.customRules) {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
dir,
|
|
559
|
+
tasks.push(
|
|
560
|
+
importOrRequireIds(
|
|
561
|
+
relativeDir || dir,
|
|
387
562
|
markdownlintOptions.customRules,
|
|
388
563
|
noRequire
|
|
389
|
-
)
|
|
390
|
-
|
|
391
|
-
|
|
564
|
+
).then((customRules) => {
|
|
565
|
+
// Expand nested arrays (for packages that export multiple rules)
|
|
566
|
+
markdownlintOptions.customRules = customRules.flat();
|
|
567
|
+
})
|
|
568
|
+
);
|
|
392
569
|
}
|
|
393
570
|
if (markdownlintOptions && markdownlintOptions.markdownItPlugins) {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
dir,
|
|
571
|
+
tasks.push(
|
|
572
|
+
importOrRequireIdsAndParams(
|
|
573
|
+
relativeDir || dir,
|
|
397
574
|
markdownlintOptions.markdownItPlugins,
|
|
398
575
|
noRequire
|
|
399
|
-
)
|
|
576
|
+
).then((markdownItPlugins) => {
|
|
577
|
+
markdownlintOptions.markdownItPlugins = markdownItPlugins;
|
|
578
|
+
})
|
|
579
|
+
);
|
|
400
580
|
}
|
|
401
581
|
dirInfos.push(dirInfo);
|
|
402
582
|
}
|
|
403
583
|
}
|
|
584
|
+
await Promise.all(tasks);
|
|
404
585
|
for (const dirInfo of dirInfos) {
|
|
405
586
|
while (dirInfo.parent && !dirToDirInfo[dirInfo.parent.dir]) {
|
|
406
587
|
dirInfo.parent = dirInfo.parent.parent;
|
|
@@ -466,21 +647,21 @@ async (fs, baseDir, globPatterns, dirToDirInfo, optionsOverride, noRequire) => {
|
|
|
466
647
|
};
|
|
467
648
|
|
|
468
649
|
// Lint files in groups by shared configuration
|
|
469
|
-
const lintFiles = (fs, dirInfos, fileContents) => {
|
|
650
|
+
const lintFiles = async (fs, dirInfos, fileContents) => {
|
|
651
|
+
const jsoncParse = await getJsoncParse();
|
|
470
652
|
const tasks = [];
|
|
471
653
|
// For each dirInfo
|
|
472
654
|
for (const dirInfo of dirInfos) {
|
|
473
655
|
const { dir, files, markdownlintConfig, markdownlintOptions } = dirInfo;
|
|
474
656
|
// Filter file/string inputs to only those in the dirInfo
|
|
475
657
|
let filesAfterIgnores = files;
|
|
476
|
-
if (
|
|
658
|
+
if (
|
|
659
|
+
markdownlintOptions.ignores &&
|
|
660
|
+
(markdownlintOptions.ignores.length > 0)
|
|
661
|
+
) {
|
|
477
662
|
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
478
663
|
const ignores = markdownlintOptions.ignores.map(negateGlob);
|
|
479
|
-
|
|
480
|
-
filesAfterIgnores = micromatch(
|
|
481
|
-
files.map((file) => path.posix.relative(dir, file)),
|
|
482
|
-
ignores
|
|
483
|
-
).map((file) => path.posix.join(dir, file));
|
|
664
|
+
filesAfterIgnores = removeIgnoredFiles(dir, files, ignores);
|
|
484
665
|
}
|
|
485
666
|
const filteredFiles = filesAfterIgnores.filter(
|
|
486
667
|
(file) => fileContents[file] === undefined
|
|
@@ -496,6 +677,7 @@ const lintFiles = (fs, dirInfos, fileContents) => {
|
|
|
496
677
|
"files": filteredFiles,
|
|
497
678
|
"strings": filteredStrings,
|
|
498
679
|
"config": markdownlintConfig || markdownlintOptions.config,
|
|
680
|
+
"configParsers": [ jsoncParse ],
|
|
499
681
|
"customRules": markdownlintOptions.customRules,
|
|
500
682
|
"frontMatter": markdownlintOptions.frontMatter
|
|
501
683
|
? new RegExp(markdownlintOptions.frontMatter, "u")
|
|
@@ -577,26 +759,33 @@ const createSummary = (baseDir, taskResults) => {
|
|
|
577
759
|
};
|
|
578
760
|
|
|
579
761
|
// Output summary via formatters
|
|
580
|
-
const outputSummary =
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
762
|
+
const outputSummary = async (
|
|
763
|
+
baseDir,
|
|
764
|
+
relativeDir,
|
|
765
|
+
summary,
|
|
766
|
+
outputFormatters,
|
|
767
|
+
logMessage,
|
|
768
|
+
logError
|
|
769
|
+
) => {
|
|
770
|
+
const errorsPresent = (summary.length > 0);
|
|
771
|
+
if (errorsPresent || outputFormatters) {
|
|
772
|
+
const formatterOptions = {
|
|
773
|
+
"directory": baseDir,
|
|
774
|
+
"results": summary,
|
|
775
|
+
logMessage,
|
|
776
|
+
logError
|
|
777
|
+
};
|
|
778
|
+
const dir = relativeDir || baseDir;
|
|
779
|
+
const formattersAndParams = outputFormatters
|
|
780
|
+
? await importOrRequireIdsAndParams(dir, outputFormatters)
|
|
781
|
+
: [ [ require("markdownlint-cli2-formatter-default") ] ];
|
|
782
|
+
await Promise.all(formattersAndParams.map((formatterAndParams) => {
|
|
783
|
+
const [ formatter, ...formatterParams ] = formatterAndParams;
|
|
784
|
+
return formatter(formatterOptions, ...formatterParams);
|
|
785
|
+
}));
|
|
786
|
+
}
|
|
787
|
+
return errorsPresent;
|
|
788
|
+
};
|
|
600
789
|
|
|
601
790
|
// Main function
|
|
602
791
|
const main = async (params) => {
|
|
@@ -609,28 +798,41 @@ const main = async (params) => {
|
|
|
609
798
|
fixDefault,
|
|
610
799
|
fileContents,
|
|
611
800
|
nonFileContents,
|
|
801
|
+
noErrors,
|
|
612
802
|
noGlobs,
|
|
613
|
-
noRequire
|
|
803
|
+
noRequire,
|
|
804
|
+
name
|
|
614
805
|
} = params;
|
|
615
806
|
const logMessage = params.logMessage || noop;
|
|
616
807
|
const logError = params.logError || noop;
|
|
617
|
-
const fs = params.fs || require("fs");
|
|
808
|
+
const fs = params.fs || require("node:fs");
|
|
618
809
|
const baseDirSystem =
|
|
619
810
|
(directory && path.resolve(directory)) ||
|
|
620
811
|
process.cwd();
|
|
621
812
|
const baseDir = posixPath(baseDirSystem);
|
|
622
813
|
// Output banner
|
|
623
814
|
logMessage(
|
|
624
|
-
|
|
815
|
+
// eslint-disable-next-line max-len
|
|
816
|
+
`${name || packageName} v${packageVersion} (${libraryName} v${libraryVersion})`
|
|
625
817
|
);
|
|
818
|
+
// Read argv configuration file (if relevant and present)
|
|
819
|
+
let optionsArgv = null;
|
|
820
|
+
let relativeDir = null;
|
|
821
|
+
const [ configPath ] = (argv || []);
|
|
822
|
+
if ((name === "markdownlint-cli2-config") && configPath) {
|
|
823
|
+
optionsArgv =
|
|
824
|
+
await readOptionsOrConfig(configPath, fs, noRequire);
|
|
825
|
+
relativeDir = path.dirname(configPath);
|
|
826
|
+
}
|
|
626
827
|
// Process arguments and get base options
|
|
627
|
-
const globPatterns = processArgv(argv);
|
|
828
|
+
const globPatterns = processArgv(optionsArgv ? argv.slice(1) : argv);
|
|
628
829
|
const { baseMarkdownlintOptions, dirToDirInfo } =
|
|
629
830
|
await getBaseOptions(
|
|
630
831
|
fs,
|
|
631
832
|
baseDir,
|
|
833
|
+
relativeDir,
|
|
632
834
|
globPatterns,
|
|
633
|
-
optionsDefault,
|
|
835
|
+
optionsArgv || optionsDefault,
|
|
634
836
|
fixDefault,
|
|
635
837
|
noGlobs,
|
|
636
838
|
noRequire
|
|
@@ -662,10 +864,12 @@ const main = async (params) => {
|
|
|
662
864
|
const dirInfos =
|
|
663
865
|
await createDirInfos(
|
|
664
866
|
fs,
|
|
867
|
+
baseDirSystem,
|
|
665
868
|
baseDir,
|
|
666
869
|
globPatterns,
|
|
667
870
|
dirToDirInfo,
|
|
668
871
|
optionsOverride,
|
|
872
|
+
noErrors,
|
|
669
873
|
noRequire
|
|
670
874
|
);
|
|
671
875
|
// Output linting status
|
|
@@ -687,7 +891,7 @@ const main = async (params) => {
|
|
|
687
891
|
(optionsOverride && optionsOverride.outputFormatters) ||
|
|
688
892
|
baseMarkdownlintOptions.outputFormatters;
|
|
689
893
|
const errorsPresent = await outputSummary(
|
|
690
|
-
baseDir, summary, outputFormatters, logMessage, logError
|
|
894
|
+
baseDir, relativeDir, summary, outputFormatters, logMessage, logError
|
|
691
895
|
);
|
|
692
896
|
// Return result
|
|
693
897
|
return errorsPresent ? 1 : 0;
|
package/package.json
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "markdownlint-cli2",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.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",
|
|
7
7
|
"url": "https://dlaa.me/"
|
|
8
8
|
},
|
|
9
9
|
"license": "MIT",
|
|
10
|
-
"
|
|
10
|
+
"type": "commonjs",
|
|
11
|
+
"exports": "./markdownlint-cli2.js",
|
|
11
12
|
"bin": {
|
|
12
13
|
"markdownlint-cli2": "markdownlint-cli2.js",
|
|
14
|
+
"markdownlint-cli2-config": "markdownlint-cli2-config.js",
|
|
13
15
|
"markdownlint-cli2-fix": "markdownlint-cli2-fix.js"
|
|
14
16
|
},
|
|
15
17
|
"homepage": "https://github.com/DavidAnson/markdownlint-cli2",
|
|
@@ -19,55 +21,61 @@
|
|
|
19
21
|
},
|
|
20
22
|
"bugs": "https://github.com/DavidAnson/markdownlint-cli2/issues",
|
|
21
23
|
"scripts": {
|
|
22
|
-
"build-docker-image": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker build -t davidanson/markdownlint-cli2
|
|
24
|
+
"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 .",
|
|
23
25
|
"ci": "npm-run-all --continue-on-error --parallel test-cover lint",
|
|
26
|
+
"docker-npm-install": "docker run --rm --tty --name npm-install --volume $PWD:/home/workdir --workdir /home/workdir --user node node:16 npm install",
|
|
27
|
+
"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",
|
|
24
28
|
"lint": "eslint --max-warnings 0 .",
|
|
25
29
|
"lint-dockerfile": "docker run --rm -i hadolint/hadolint:latest-alpine < docker/Dockerfile",
|
|
26
30
|
"lint-watch": "git ls-files | entr npm run lint",
|
|
27
|
-
"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
|
|
28
|
-
"test": "ava 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",
|
|
29
|
-
"test-docker-image": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker run --rm -v $PWD:/workdir davidanson/markdownlint-cli2
|
|
30
|
-
"test-docker-hub-image": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker image rm davidanson/markdownlint-cli2
|
|
31
|
+
"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 .",
|
|
32
|
+
"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",
|
|
33
|
+
"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\"",
|
|
34
|
+
"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\"",
|
|
31
35
|
"test-cover": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 npm test",
|
|
32
|
-
"test-watch": "git ls-files | entr npm run test"
|
|
36
|
+
"test-watch": "git ls-files | entr npm run test",
|
|
37
|
+
"update-snapshots": "ava --update-snapshots test/markdownlint-cli2-test-exec.js test/markdownlint-cli2-test-fs.js test/markdownlint-cli2-test-main.js",
|
|
38
|
+
"upgrade": "npx --yes npm-check-updates --upgrade",
|
|
39
|
+
"webworker": "cd webworker && webpack --mode none",
|
|
40
|
+
"webworker-install": "npm run docker-npm-install -- --no-save path-browserify process setimmediate stream-browserify url util webpack-cli"
|
|
33
41
|
},
|
|
34
42
|
"engines": {
|
|
35
|
-
"node": ">=
|
|
43
|
+
"node": ">=14"
|
|
36
44
|
},
|
|
37
45
|
"files": [
|
|
38
46
|
"append-to-array.js",
|
|
39
47
|
"markdownlint-cli2.js",
|
|
48
|
+
"markdownlint-cli2-config.js",
|
|
40
49
|
"markdownlint-cli2-fix.js",
|
|
41
50
|
"merge-options.js",
|
|
42
51
|
"resolve-and-require.js"
|
|
43
52
|
],
|
|
44
53
|
"dependencies": {
|
|
45
|
-
"globby": "
|
|
46
|
-
"markdownlint": "
|
|
47
|
-
"markdownlint-cli2-formatter-default": "
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"yaml": "~1.10.2"
|
|
54
|
+
"globby": "13.1.2",
|
|
55
|
+
"markdownlint": "0.26.1",
|
|
56
|
+
"markdownlint-cli2-formatter-default": "0.0.3",
|
|
57
|
+
"micromatch": "4.0.5",
|
|
58
|
+
"strip-json-comments": "5.0.0",
|
|
59
|
+
"yaml": "2.1.1"
|
|
52
60
|
},
|
|
53
61
|
"devDependencies": {
|
|
54
|
-
"@iktakahiro/markdown-it-katex": "
|
|
55
|
-
"ava": "
|
|
56
|
-
"c8": "
|
|
57
|
-
"cpy": "
|
|
58
|
-
"del": "
|
|
59
|
-
"eslint": "
|
|
60
|
-
"eslint-plugin-node": "
|
|
61
|
-
"eslint-plugin-unicorn": "
|
|
62
|
-
"execa": "
|
|
63
|
-
"markdown-it-emoji": "
|
|
64
|
-
"markdown-it-for-inline": "
|
|
65
|
-
"markdownlint-cli2-formatter-json": "
|
|
66
|
-
"markdownlint-cli2-formatter-junit": "
|
|
67
|
-
"markdownlint-cli2-formatter-pretty": "
|
|
68
|
-
"markdownlint-cli2-formatter-summarize": "
|
|
69
|
-
"markdownlint-rule-titlecase": "
|
|
70
|
-
"npm-run-all": "
|
|
62
|
+
"@iktakahiro/markdown-it-katex": "4.0.1",
|
|
63
|
+
"ava": "4.3.1",
|
|
64
|
+
"c8": "7.12.0",
|
|
65
|
+
"cpy": "9.0.1",
|
|
66
|
+
"del": "7.0.0",
|
|
67
|
+
"eslint": "8.20.0",
|
|
68
|
+
"eslint-plugin-node": "11.1.0",
|
|
69
|
+
"eslint-plugin-unicorn": "43.0.2",
|
|
70
|
+
"execa": "6.1.0",
|
|
71
|
+
"markdown-it-emoji": "2.0.2",
|
|
72
|
+
"markdown-it-for-inline": "0.1.1",
|
|
73
|
+
"markdownlint-cli2-formatter-json": "0.0.6",
|
|
74
|
+
"markdownlint-cli2-formatter-junit": "0.0.5",
|
|
75
|
+
"markdownlint-cli2-formatter-pretty": "0.0.3",
|
|
76
|
+
"markdownlint-cli2-formatter-summarize": "0.0.5",
|
|
77
|
+
"markdownlint-rule-titlecase": "0.1.0",
|
|
78
|
+
"npm-run-all": "4.1.5"
|
|
71
79
|
},
|
|
72
80
|
"keywords": [
|
|
73
81
|
"markdown",
|
package/resolve-and-require.js
CHANGED
|
@@ -4,10 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Wrapper for calling Node's require.resolve/require with an additional path.
|
|
7
|
-
*
|
|
8
|
-
* @param {
|
|
9
|
-
* @param {
|
|
10
|
-
* @param {*} dir Directory to include when resolving paths.
|
|
7
|
+
* @param {Object} req Node's require implementation (or equivalent).
|
|
8
|
+
* @param {String} id Package identifier to require.
|
|
9
|
+
* @param {String} dir Directory to include when resolving paths.
|
|
11
10
|
* @returns {Object} Exported module content.
|
|
12
11
|
*/
|
|
13
12
|
const resolveAndRequire = (req, id, dir) => {
|