markdownlint-cli2 0.3.2 → 0.5.1

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-2021 David Anson
3
+ Copyright (c) 2020-2022 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
@@ -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 [use the container image](#container-image) available on
24
- [Docker Hub as davidanson/markdownlint-cli2][docker-hub-markdownlint-cli2].
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 / (when it's the only thing in a path part)
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.js
76
+ - .markdownlint-cli2.cjs or .markdownlint-cli2.mjs
71
77
  - .markdownlint.jsonc or .markdownlint.json
72
78
  - .markdownlint.yaml or .markdownlint.yml
73
- - .markdownlint.js
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
- Therefore, the most compatible glob syntax for cross-platform support:
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` or
88
- `.markdownlint-cli2.yaml` or `.markdownlint-cli2.js` may be used instead of (or
89
- in addition to) passing `glob0 ... globN` on the command-line.
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, the default command-line for `markdownlint-cli2` looks something
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
- However, because sharing configuration between "normal" and "fix" modes is so
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
- in both cases), these two commands behave identically.
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.3.2 "**/*.md" "#node_modules"
134
+ docker run -v $PWD:/workdir davidanson/markdownlint-cli2:0.5.1 "**/*.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
- _inside the container_. So, as shown above, [bind mount][docker-bind-mounts]
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.3.2 "**/*.md" "#node_modules"
151
+ docker run -w /myfolder -v $PWD:/myfolder davidanson/markdownlint-cli2:0.5.1 "**/*.md" "#node_modules"
132
152
  ```
133
153
 
134
- To invoke the `markdownlint-cli2-fix` command instead, specify it via Docker's
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.3.2 "**/*.md" "#node_modules"
158
+ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/markdownlint-cli2:0.5.1 "**/*.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 (top-level) directory applies to the entire tree
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 (top-level) directory is applied to the
166
- closest common parent directory
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.js`
273
+ ### `.markdownlint-cli2.cjs` or `.markdownlint-cli2.mjs`
249
274
 
250
- - The format of this file is a [CommonJS module][commonjs-module] that exports
251
- the object described above for `.markdownlint-cli2.jsonc`.
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
- - For example: [`.markdownlint-cli2.js`][markdownlint-cli2-js]
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.js`
313
+ ### `.markdownlint.cjs` or `.markdownlint.mjs`
286
314
 
287
- - The format of this file is a [CommonJS module][commonjs-module] that exports
288
- the [`markdownlint` `config` object][markdownlint-config].
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 `jsonc`, `json`, `yaml`, or `yml` file is present in the same directory,
291
- it takes precedence.
292
- - For example: [`.markdownlint.js`][markdownlint-js]
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.3.2
347
+ rev: v0.5.1
317
348
  hooks:
318
349
  - id: markdownlint-cli2
319
350
  ```
@@ -345,11 +376,15 @@ reference to the `repos` list in that project's `.pre-commit-config.yaml` like:
345
376
  - 0.3.0 - Add Docker container, update dependencies
346
377
  - 0.3.1 - Extensibility tweaks
347
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
348
382
 
349
383
  <!-- markdownlint-disable line-length -->
350
384
 
351
385
  [commonmark]: https://commonmark.org/
352
386
  [commonjs-module]: https://nodejs.org/api/modules.html#modules_modules_commonjs_modules
387
+ [ecmascript-module]: https://nodejs.org/api/esm.html#modules-ecmascript-modules
353
388
  [docker-bind-mounts]: https://docs.docker.com/storage/bind-mounts/
354
389
  [docker-hub-markdownlint-cli2]: https://hub.docker.com/r/davidanson/markdownlint-cli2
355
390
  [front-matter]: https://jekyllrb.com/docs/frontmatter/
@@ -374,16 +409,20 @@ reference to the `repos` list in that project's `.pre-commit-config.yaml` like:
374
409
  [markdownlint-cli2]: https://github.com/DavidAnson/markdownlint-cli2
375
410
  [markdownlint-cli2-blog]: https://dlaa.me/blog/post/markdownlintcli2
376
411
  [markdownlint-cli2-formatter]: https://www.npmjs.com/search?q=keywords:markdownlint-cli2-formatter
377
- [markdownlint-cli2-js]: test/markdownlint-cli2-js/.markdownlint-cli2.js
412
+ [markdownlint-cli2-cjs]: test/markdownlint-cli2-cjs/.markdownlint-cli2.cjs
378
413
  [markdownlint-cli2-jsonc]: test/markdownlint-cli2-jsonc-example/.markdownlint-cli2.jsonc
414
+ [markdownlint-cli2-mjs]: test/markdownlint-cli2-mjs/.markdownlint-cli2.mjs
379
415
  [markdownlint-cli2-yaml]: test/markdownlint-cli2-yaml-example/.markdownlint-cli2.yaml
380
- [markdownlint-js]: test/markdownlint-js/.markdownlint.js
416
+ [markdownlint-cjs]: test/markdownlint-cjs/.markdownlint.cjs
381
417
  [markdownlint-jsonc]: https://github.com/DavidAnson/markdownlint/blob/main/schema/.markdownlint.jsonc
418
+ [markdownlint-mjs]: test/markdownlint-mjs/.markdownlint.mjs
382
419
  [markdownlint-rule]: https://www.npmjs.com/search?q=keywords:markdownlint-rule
383
420
  [markdownlint-yaml]: https://github.com/DavidAnson/markdownlint/blob/main/schema/.markdownlint.yaml
384
421
  [nodejs]: https://nodejs.org/
385
422
  [nodejs-docker]: https://github.com/nodejs/docker-node
386
423
  [nodejs-docker-non-root]: https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md#non-root-user
424
+ [nodejs-import-expression]: https://nodejs.org/api/esm.html#import-expressions
425
+ [nodejs-import-meta-resolve]: https://nodejs.org/api/esm.html#importmetaresolvespecifier-parent
387
426
  [nodejs-require]: https://nodejs.org/api/modules.html#modules_require_id
388
427
  [npm-image]: https://img.shields.io/npm/v/markdownlint-cli2.svg
389
428
  [npm-url]: https://www.npmjs.com/package/markdownlint-cli2
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+
3
+ // @ts-check
4
+
5
+ "use strict";
6
+
7
+ const { run } = require("./markdownlint-cli2");
8
+
9
+ run({
10
+ "name": "markdownlint-cli2-config"
11
+ });
@@ -7,5 +7,6 @@
7
7
  const { run } = require("./markdownlint-cli2");
8
8
 
9
9
  run({
10
- "fixDefault": true
10
+ "fixDefault": true,
11
+ "name": "markdownlint-cli2-fix"
11
12
  });
@@ -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 globby = require("globby");
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-rule-helpers");
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.3.2";
25
+ const packageVersion = "0.5.1";
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
- // Parse JSONC text
35
- const jsoncParse = (text) => JSON.parse(require("strip-json-comments")(text));
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
- // Parse YAML text
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,143 @@ 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
- // @ts-ignore
52
- () => markdownlintReadConfig(file, [ jsoncParse, yamlParse ], fs),
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
- // Require a module ID with the specified directory in the path
58
- const requireResolve = (dir, id) => {
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
- return resolveAndRequire(dynamicRequire, id, dir);
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 max-len
83
+ // eslint-disable-next-line no-inline-comments, node/no-unsupported-features/es-syntax
84
+ const module = await import(/* webpackIgnore: true */ fileUrlString);
85
+ return module.default;
86
+ } catch (error) {
87
+ errors.push(error);
88
+ }
89
+ // Use AggregateError once available in Node 15+
90
+ throw new Error(errors.map((error) => error.message).join(" / "));
61
91
  }
62
92
  return id;
63
93
  };
64
94
 
65
- // Require an array of modules by ID
66
- const requireIds = (dir, ids, noRequire) => (
67
- noRequire ? [] : ids.map((id) => requireResolve(dir, id))
95
+ // Import or require an array of modules by ID
96
+ const importOrRequireIds = (dir, ids, noRequire) => (
97
+ Promise.all(noRequire ? [] : ids.map((id) => importOrRequireResolve(dir, id)))
68
98
  );
69
99
 
70
- // Require an array of modules by ID (preserving parameters)
71
- const requireIdsAndParams = (dir, idsAndParams, noRequire) => {
100
+ // Import or require an array of modules by ID (preserving parameters)
101
+ const importOrRequireIdsAndParams = async (dir, idsAndParams, noRequire) => {
72
102
  if (noRequire) {
73
103
  return [];
74
104
  }
75
105
  const ids = idsAndParams.map((entry) => entry[0]);
76
- const modules = requireIds(dir, ids);
106
+ const modules = await importOrRequireIds(dir, ids);
77
107
  const modulesAndParams = idsAndParams.
78
108
  map((entry, i) => [ modules[i], ...entry.slice(1) ]);
79
109
  return modulesAndParams;
80
110
  };
81
111
 
82
- // Require a JS file and return the exported object
83
- const requireConfig = (fs, dir, name, noRequire) => (
112
+ // Import or require a JavaScript file and return the exported object
113
+ const importOrRequireConfig = (fs, dir, name, noRequire, otherwise) => (
84
114
  () => (noRequire
85
115
  // eslint-disable-next-line prefer-promise-reject-errors
86
116
  ? Promise.reject()
87
117
  : fs.promises.access(path.posix.join(dir, name))
88
118
  ).
89
119
  then(
90
- () => requireResolve(dir, `./${name}`),
91
- noop
120
+ () => importOrRequireResolve(dir, `./${name}`),
121
+ otherwise
92
122
  )
93
123
  );
94
124
 
95
- // Process command-line arguments and return glob patterns
125
+ // Read an options or config file in any format and return the object
126
+ const readOptionsOrConfig = async (configPath, fs, noRequire) => {
127
+ const basename = path.basename(configPath);
128
+ const dirname = path.dirname(configPath);
129
+ let options = null;
130
+ let config = null;
131
+ if (basename.endsWith(".markdownlint-cli2.jsonc")) {
132
+ const jsoncParse = await getJsoncParse();
133
+ options = jsoncParse(await fs.promises.readFile(configPath, utf8));
134
+ } else if (basename.endsWith(".markdownlint-cli2.yaml")) {
135
+ options = yamlParse(await fs.promises.readFile(configPath, utf8));
136
+ } else if (
137
+ basename.endsWith(".markdownlint-cli2.cjs") ||
138
+ basename.endsWith(".markdownlint-cli2.mjs")
139
+ ) {
140
+ options = await (
141
+ importOrRequireConfig(fs, dirname, basename, noRequire, noop)()
142
+ );
143
+ } else if (
144
+ basename.endsWith(".markdownlint.jsonc") ||
145
+ basename.endsWith(".markdownlint.json") ||
146
+ basename.endsWith(".markdownlint.yaml") ||
147
+ basename.endsWith(".markdownlint.yml")
148
+ ) {
149
+ const jsoncParse = await getJsoncParse();
150
+ config =
151
+ await markdownlintReadConfig(configPath, [ jsoncParse, yamlParse ], fs);
152
+ } else if (
153
+ basename.endsWith(".markdownlint.cjs") ||
154
+ basename.endsWith(".markdownlint.mjs")
155
+ ) {
156
+ config = await (
157
+ importOrRequireConfig(fs, dirname, basename, noRequire, noop)()
158
+ );
159
+ } else {
160
+ throw new Error(
161
+ `Configuration file "${configPath}" is unrecognized; ` +
162
+ "its name should be (or end with) one of the supported types " +
163
+ "(e.g., \".markdownlint.json\" or \"example.markdownlint-cli2.jsonc\")."
164
+ );
165
+ }
166
+ return options || { config };
167
+ };
168
+
169
+ // Filter a list of files to ignore by glob
170
+ const removeIgnoredFiles = (dir, files, ignores) => {
171
+ const micromatch = require("micromatch");
172
+ return micromatch(
173
+ files.map((file) => path.posix.relative(dir, file)),
174
+ ignores
175
+ ).map((file) => path.posix.join(dir, file));
176
+ };
177
+
178
+ // Process/normalize command-line arguments and return glob patterns
96
179
  const processArgv = (argv) => {
97
180
  const globPatterns = (argv || []).map(
98
- (glob) => glob.replace(/^#/u, "!").replace(/\\(?![$()*+?[\]^])/gu, "/")
181
+ (glob) => {
182
+ if (glob.startsWith(":")) {
183
+ return glob;
184
+ }
185
+ // Escape RegExp special characters recognized by fast-glob
186
+ // https://github.com/mrmlnc/fast-glob#advanced-syntax
187
+ const specialCharacters = /\\(?![$()*+?[\]^])/gu;
188
+ if (glob.startsWith("\\:")) {
189
+ return `\\:${glob.slice(2).replace(specialCharacters, "/")}`;
190
+ }
191
+ return (glob.startsWith("#") ? `!${glob.slice(1)}` : glob).
192
+ replace(specialCharacters, "/");
193
+ }
99
194
  );
100
195
  if ((globPatterns.length === 1) && (globPatterns[0] === ".")) {
101
196
  // Substitute a more reasonable pattern
@@ -106,31 +201,33 @@ const processArgv = (argv) => {
106
201
 
107
202
  // Show help if missing arguments
108
203
  const showHelp = (logMessage) => {
109
- const { name, homepage } = require("./package.json");
110
204
  /* eslint-disable max-len */
111
- logMessage(`${homepage}
205
+ logMessage(`https://github.com/DavidAnson/markdownlint-cli2
112
206
 
113
- Syntax: ${name} glob0 [glob1] [...] [globN]
207
+ Syntax: markdownlint-cli2 glob0 [glob1] [...] [globN]
208
+ markdownlint-cli2-fix glob0 [glob1] [...] [globN]
209
+ markdownlint-cli2-config config-file glob0 [glob1] [...] [globN]
114
210
 
115
211
  Glob expressions (from the globby library):
116
212
  - * matches any number of characters, but not /
117
213
  - ? matches a single character, but not /
118
- - ** matches any number of characters, including / (when it's the only thing in a path part)
214
+ - ** matches any number of characters, including /
119
215
  - {} allows for a comma-separated list of "or" expressions
120
216
  - ! or # at the beginning of a pattern negate the match
217
+ - : at the beginning identifies a literal file path
121
218
 
122
219
  Dot-only glob:
123
- - The command "${name} ." would lint every file in the current directory tree which is probably not intended
124
- - Instead, it is mapped to "${name} ${dotOnlySubstitute}" which lints all Markdown files in the current directory
125
- - To lint every file in the current directory tree, the command "${name} **" can be used instead
220
+ - The command "markdownlint-cli2 ." would lint every file in the current directory tree which is probably not intended
221
+ - Instead, it is mapped to "markdownlint-cli2 ${dotOnlySubstitute}" which lints all Markdown files in the current directory
222
+ - To lint every file in the current directory tree, the command "markdownlint-cli2 **" can be used instead
126
223
 
127
224
  Configuration via:
128
225
  - .markdownlint-cli2.jsonc
129
226
  - .markdownlint-cli2.yaml
130
- - .markdownlint-cli2.js
227
+ - .markdownlint-cli2.cjs or .markdownlint-cli2.mjs
131
228
  - .markdownlint.jsonc or .markdownlint.json
132
229
  - .markdownlint.yaml or .markdownlint.yml
133
- - .markdownlint.js
230
+ - .markdownlint.cjs or .markdownlint.mjs
134
231
 
135
232
  Cross-platform compatibility:
136
233
  - UNIX and Windows shells expand globs according to different rules; quoting arguments is recommended
@@ -139,19 +236,20 @@ Cross-platform compatibility:
139
236
  - Some UNIX shells parse exclamation (!) in double-quotes; hashtag (#) is recommended in these cases
140
237
  - The path separator is forward slash (/) on all platforms; backslash (\\) is automatically converted
141
238
 
142
- Therefore, the most compatible glob syntax for cross-platform support:
143
- $ ${name} "**/*.md" "#node_modules"`
239
+ The most compatible syntax for cross-platform support:
240
+ $ markdownlint-cli2 "**/*.md" "#node_modules"`
144
241
  );
145
242
  /* eslint-enable max-len */
146
243
  };
147
244
 
148
245
  // Get (creating if necessary) and process a directory's info object
149
246
  const getAndProcessDirInfo =
150
- (fs, tasks, dirToDirInfo, dir, noRequire, func) => {
247
+ (fs, tasks, dirToDirInfo, dir, relativeDir, noRequire, func) => {
151
248
  let dirInfo = dirToDirInfo[dir];
152
249
  if (!dirInfo) {
153
250
  dirInfo = {
154
251
  dir,
252
+ relativeDir,
155
253
  "parent": null,
156
254
  "files": [],
157
255
  "markdownlintConfig": null,
@@ -169,17 +267,27 @@ const getAndProcessDirInfo =
169
267
  then(
170
268
  () => fs.promises.
171
269
  readFile(markdownlintCli2Jsonc, utf8).
172
- then(jsoncParse),
270
+ then(
271
+ (content) => getJsoncParse().
272
+ then((jsoncParse) => jsoncParse(content))
273
+ ),
173
274
  () => fs.promises.access(markdownlintCli2Yaml).
174
275
  then(
175
276
  () => fs.promises.
176
277
  readFile(markdownlintCli2Yaml, utf8).
177
278
  then(yamlParse),
178
- requireConfig(
279
+ importOrRequireConfig(
179
280
  fs,
180
281
  dir,
181
- ".markdownlint-cli2.js",
182
- noRequire
282
+ ".markdownlint-cli2.cjs",
283
+ noRequire,
284
+ importOrRequireConfig(
285
+ fs,
286
+ dir,
287
+ ".markdownlint-cli2.mjs",
288
+ noRequire,
289
+ noop
290
+ )
183
291
  )
184
292
  )
185
293
  ).
@@ -206,11 +314,18 @@ const getAndProcessDirInfo =
206
314
  fs,
207
315
  dir,
208
316
  ".markdownlint.yml",
209
- requireConfig(
317
+ importOrRequireConfig(
210
318
  fs,
211
319
  dir,
212
- ".markdownlint.js",
213
- noRequire
320
+ ".markdownlint.cjs",
321
+ noRequire,
322
+ importOrRequireConfig(
323
+ fs,
324
+ dir,
325
+ ".markdownlint.mjs",
326
+ noRequire,
327
+ noop
328
+ )
214
329
  )
215
330
  )
216
331
  )
@@ -233,20 +348,28 @@ const getAndProcessDirInfo =
233
348
  const getBaseOptions = async (
234
349
  fs,
235
350
  baseDir,
351
+ relativeDir,
236
352
  globPatterns,
237
- optionsDefault,
353
+ options,
238
354
  fixDefault,
239
355
  noGlobs,
240
356
  noRequire
241
357
  ) => {
242
358
  const tasks = [];
243
359
  const dirToDirInfo = {};
244
- getAndProcessDirInfo(fs, tasks, dirToDirInfo, baseDir, noRequire);
360
+ getAndProcessDirInfo(
361
+ fs,
362
+ tasks,
363
+ dirToDirInfo,
364
+ baseDir,
365
+ relativeDir,
366
+ noRequire
367
+ );
245
368
  await Promise.all(tasks);
246
369
  // eslint-disable-next-line no-multi-assign
247
370
  const baseMarkdownlintOptions = dirToDirInfo[baseDir].markdownlintOptions =
248
371
  mergeOptions(
249
- mergeOptions(optionsDefault, { "fix": fixDefault }),
372
+ mergeOptions(options, { "fix": fixDefault }),
250
373
  dirToDirInfo[baseDir].markdownlintOptions
251
374
  );
252
375
 
@@ -270,24 +393,51 @@ const getBaseOptions = async (
270
393
 
271
394
  // Enumerate files from globs and build directory infos
272
395
  const enumerateFiles =
273
- async (fs, baseDir, globPatterns, dirToDirInfo, noErrors, noRequire) => {
396
+ // eslint-disable-next-line max-len
397
+ async (fs, baseDirSystem, baseDir, globPatterns, dirToDirInfo, noErrors, noRequire) => {
274
398
  const tasks = [];
275
399
  const globbyOptions = {
276
400
  "absolute": true,
277
401
  "cwd": baseDir,
402
+ "dot": true,
278
403
  "expandDirectories": false,
279
404
  fs
280
405
  };
281
406
  if (noErrors) {
282
407
  globbyOptions.suppressErrors = true;
283
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;
284
430
  // Manually expand directories to avoid globby call to dir-glob.sync
285
431
  const expandedDirectories = await Promise.all(
286
- globPatterns.map((globPattern) => {
287
- const globPath = path.posix.join(
288
- baseDir,
289
- globPattern[0] === "!" ? globPattern.slice(1) : globPattern
290
- );
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);
291
441
  return fs.promises.stat(globPath).
292
442
  then((stats) => (stats.isDirectory()
293
443
  ? path.posix.join(globPattern, "**")
@@ -296,7 +446,13 @@ async (fs, baseDir, globPatterns, dirToDirInfo, noErrors, noRequire) => {
296
446
  })
297
447
  );
298
448
  // Process glob patterns
299
- const files = await globby(expandedDirectories, globbyOptions);
449
+ // 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
+ ];
300
456
  for (const file of files) {
301
457
  const dir = path.posix.dirname(file);
302
458
  getAndProcessDirInfo(
@@ -304,6 +460,7 @@ async (fs, baseDir, globPatterns, dirToDirInfo, noErrors, noRequire) => {
304
460
  tasks,
305
461
  dirToDirInfo,
306
462
  dir,
463
+ null,
307
464
  noRequire,
308
465
  (dirInfo) => {
309
466
  dirInfo.files.push(file);
@@ -341,6 +498,7 @@ const enumerateParents = async (fs, baseDir, dirToDirInfo, noRequire) => {
341
498
  tasks,
342
499
  dirToDirInfo,
343
500
  dir,
501
+ null,
344
502
  noRequire,
345
503
  // eslint-disable-next-line no-loop-func
346
504
  (dirInfo) => {
@@ -360,9 +518,10 @@ const enumerateParents = async (fs, baseDir, dirToDirInfo, noRequire) => {
360
518
  // Create directory info objects by enumerating file globs
361
519
  const createDirInfos =
362
520
  // eslint-disable-next-line max-len
363
- async (fs, baseDir, globPatterns, dirToDirInfo, optionsOverride, noErrors, noRequire) => {
521
+ async (fs, baseDirSystem, baseDir, globPatterns, dirToDirInfo, optionsOverride, noErrors, noRequire) => {
364
522
  await enumerateFiles(
365
523
  fs,
524
+ baseDirSystem,
366
525
  baseDir,
367
526
  globPatterns,
368
527
  dirToDirInfo,
@@ -381,11 +540,13 @@ async (fs, baseDir, globPatterns, dirToDirInfo, optionsOverride, noErrors, noReq
381
540
  dirs.sort((a, b) => b.length - a.length);
382
541
  const dirInfos = [];
383
542
  const noConfigDirInfo =
543
+ // eslint-disable-next-line unicorn/consistent-function-scoping
384
544
  (dirInfo) => (
385
545
  dirInfo.parent &&
386
546
  !dirInfo.markdownlintConfig &&
387
547
  !dirInfo.markdownlintOptions
388
548
  );
549
+ const tasks = [];
389
550
  for (const dir of dirs) {
390
551
  const dirInfo = dirToDirInfo[dir];
391
552
  if (noConfigDirInfo(dirInfo)) {
@@ -394,28 +555,34 @@ async (fs, baseDir, globPatterns, dirToDirInfo, optionsOverride, noErrors, noReq
394
555
  }
395
556
  dirToDirInfo[dir] = null;
396
557
  } else {
397
- const { markdownlintOptions } = dirInfo;
558
+ const { markdownlintOptions, relativeDir } = dirInfo;
398
559
  if (markdownlintOptions && markdownlintOptions.customRules) {
399
- const customRules =
400
- requireIds(
401
- dir,
560
+ tasks.push(
561
+ importOrRequireIds(
562
+ relativeDir || dir,
402
563
  markdownlintOptions.customRules,
403
564
  noRequire
404
- );
405
- // Expand nested arrays (for packages that export multiple rules)
406
- markdownlintOptions.customRules = customRules.flat();
565
+ ).then((customRules) => {
566
+ // Expand nested arrays (for packages that export multiple rules)
567
+ markdownlintOptions.customRules = customRules.flat();
568
+ })
569
+ );
407
570
  }
408
571
  if (markdownlintOptions && markdownlintOptions.markdownItPlugins) {
409
- markdownlintOptions.markdownItPlugins =
410
- requireIdsAndParams(
411
- dir,
572
+ tasks.push(
573
+ importOrRequireIdsAndParams(
574
+ relativeDir || dir,
412
575
  markdownlintOptions.markdownItPlugins,
413
576
  noRequire
414
- );
577
+ ).then((markdownItPlugins) => {
578
+ markdownlintOptions.markdownItPlugins = markdownItPlugins;
579
+ })
580
+ );
415
581
  }
416
582
  dirInfos.push(dirInfo);
417
583
  }
418
584
  }
585
+ await Promise.all(tasks);
419
586
  for (const dirInfo of dirInfos) {
420
587
  while (dirInfo.parent && !dirToDirInfo[dirInfo.parent.dir]) {
421
588
  dirInfo.parent = dirInfo.parent.parent;
@@ -481,7 +648,8 @@ async (fs, baseDir, globPatterns, dirToDirInfo, optionsOverride, noErrors, noReq
481
648
  };
482
649
 
483
650
  // Lint files in groups by shared configuration
484
- const lintFiles = (fs, dirInfos, fileContents) => {
651
+ const lintFiles = async (fs, dirInfos, fileContents) => {
652
+ const jsoncParse = await getJsoncParse();
485
653
  const tasks = [];
486
654
  // For each dirInfo
487
655
  for (const dirInfo of dirInfos) {
@@ -494,11 +662,7 @@ const lintFiles = (fs, dirInfos, fileContents) => {
494
662
  ) {
495
663
  // eslint-disable-next-line unicorn/no-array-callback-reference
496
664
  const ignores = markdownlintOptions.ignores.map(negateGlob);
497
- const micromatch = require("micromatch");
498
- filesAfterIgnores = micromatch(
499
- files.map((file) => path.posix.relative(dir, file)),
500
- ignores
501
- ).map((file) => path.posix.join(dir, file));
665
+ filesAfterIgnores = removeIgnoredFiles(dir, files, ignores);
502
666
  }
503
667
  const filteredFiles = filesAfterIgnores.filter(
504
668
  (file) => fileContents[file] === undefined
@@ -514,6 +678,7 @@ const lintFiles = (fs, dirInfos, fileContents) => {
514
678
  "files": filteredFiles,
515
679
  "strings": filteredStrings,
516
680
  "config": markdownlintConfig || markdownlintOptions.config,
681
+ "configParsers": [ jsoncParse ],
517
682
  "customRules": markdownlintOptions.customRules,
518
683
  "frontMatter": markdownlintOptions.frontMatter
519
684
  ? new RegExp(markdownlintOptions.frontMatter, "u")
@@ -595,26 +760,33 @@ const createSummary = (baseDir, taskResults) => {
595
760
  };
596
761
 
597
762
  // Output summary via formatters
598
- const outputSummary =
599
- async (baseDir, summary, outputFormatters, logMessage, logError) => {
600
- const errorsPresent = (summary.length > 0);
601
- if (errorsPresent || outputFormatters) {
602
- const formatterOptions = {
603
- "directory": baseDir,
604
- "results": summary,
605
- logMessage,
606
- logError
607
- };
608
- const formattersAndParams = outputFormatters
609
- ? requireIdsAndParams(baseDir, outputFormatters)
610
- : [ [ require("markdownlint-cli2-formatter-default") ] ];
611
- await Promise.all(formattersAndParams.map((formatterAndParams) => {
612
- const [ formatter, ...formatterParams ] = formatterAndParams;
613
- return formatter(formatterOptions, ...formatterParams);
614
- }));
615
- }
616
- return errorsPresent;
617
- };
763
+ const outputSummary = async (
764
+ baseDir,
765
+ relativeDir,
766
+ summary,
767
+ outputFormatters,
768
+ logMessage,
769
+ logError
770
+ ) => {
771
+ const errorsPresent = (summary.length > 0);
772
+ if (errorsPresent || outputFormatters) {
773
+ const formatterOptions = {
774
+ "directory": baseDir,
775
+ "results": summary,
776
+ logMessage,
777
+ logError
778
+ };
779
+ const dir = relativeDir || baseDir;
780
+ const formattersAndParams = outputFormatters
781
+ ? await importOrRequireIdsAndParams(dir, outputFormatters)
782
+ : [ [ require("markdownlint-cli2-formatter-default") ] ];
783
+ await Promise.all(formattersAndParams.map((formatterAndParams) => {
784
+ const [ formatter, ...formatterParams ] = formatterAndParams;
785
+ return formatter(formatterOptions, ...formatterParams);
786
+ }));
787
+ }
788
+ return errorsPresent;
789
+ };
618
790
 
619
791
  // Main function
620
792
  const main = async (params) => {
@@ -629,27 +801,39 @@ const main = async (params) => {
629
801
  nonFileContents,
630
802
  noErrors,
631
803
  noGlobs,
632
- noRequire
804
+ noRequire,
805
+ name
633
806
  } = params;
634
807
  const logMessage = params.logMessage || noop;
635
808
  const logError = params.logError || noop;
636
- const fs = params.fs || require("fs");
809
+ const fs = params.fs || require("node:fs");
637
810
  const baseDirSystem =
638
811
  (directory && path.resolve(directory)) ||
639
812
  process.cwd();
640
813
  const baseDir = posixPath(baseDirSystem);
641
814
  // Output banner
642
815
  logMessage(
643
- `${packageName} v${packageVersion} (${libraryName} v${libraryVersion})`
816
+ // eslint-disable-next-line max-len
817
+ `${name || packageName} v${packageVersion} (${libraryName} v${libraryVersion})`
644
818
  );
819
+ // Read argv configuration file (if relevant and present)
820
+ let optionsArgv = null;
821
+ let relativeDir = null;
822
+ const [ configPath ] = (argv || []);
823
+ if ((name === "markdownlint-cli2-config") && configPath) {
824
+ optionsArgv =
825
+ await readOptionsOrConfig(configPath, fs, noRequire);
826
+ relativeDir = path.dirname(configPath);
827
+ }
645
828
  // Process arguments and get base options
646
- const globPatterns = processArgv(argv);
829
+ const globPatterns = processArgv(optionsArgv ? argv.slice(1) : argv);
647
830
  const { baseMarkdownlintOptions, dirToDirInfo } =
648
831
  await getBaseOptions(
649
832
  fs,
650
833
  baseDir,
834
+ relativeDir,
651
835
  globPatterns,
652
- optionsDefault,
836
+ optionsArgv || optionsDefault,
653
837
  fixDefault,
654
838
  noGlobs,
655
839
  noRequire
@@ -681,6 +865,7 @@ const main = async (params) => {
681
865
  const dirInfos =
682
866
  await createDirInfos(
683
867
  fs,
868
+ baseDirSystem,
684
869
  baseDir,
685
870
  globPatterns,
686
871
  dirToDirInfo,
@@ -707,7 +892,7 @@ const main = async (params) => {
707
892
  (optionsOverride && optionsOverride.outputFormatters) ||
708
893
  baseMarkdownlintOptions.outputFormatters;
709
894
  const errorsPresent = await outputSummary(
710
- baseDir, summary, outputFormatters, logMessage, logError
895
+ baseDir, relativeDir, summary, outputFormatters, logMessage, logError
711
896
  );
712
897
  // Return result
713
898
  return errorsPresent ? 1 : 0;
package/package.json CHANGED
@@ -1,15 +1,18 @@
1
1
  {
2
2
  "name": "markdownlint-cli2",
3
- "version": "0.3.2",
3
+ "version": "0.5.1",
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
- "main": "markdownlint-cli2.js",
10
+ "type": "commonjs",
11
+ "main": "./markdownlint-cli2.js",
12
+ "exports": "./markdownlint-cli2.js",
11
13
  "bin": {
12
14
  "markdownlint-cli2": "markdownlint-cli2.js",
15
+ "markdownlint-cli2-config": "markdownlint-cli2-config.js",
13
16
  "markdownlint-cli2-fix": "markdownlint-cli2-fix.js"
14
17
  },
15
18
  "homepage": "https://github.com/DavidAnson/markdownlint-cli2",
@@ -19,55 +22,61 @@
19
22
  },
20
23
  "bugs": "https://github.com/DavidAnson/markdownlint-cli2/issues",
21
24
  "scripts": {
22
- "build-docker-image": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker build -t davidanson/markdownlint-cli2:$VERSION -f docker/Dockerfile .",
25
+ "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
26
  "ci": "npm-run-all --continue-on-error --parallel test-cover lint",
27
+ "docker-npm-install": "docker run --rm --tty --name npm-install --volume $PWD:/home/workdir --workdir /home/workdir --user node node:16 npm install",
28
+ "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
29
  "lint": "eslint --max-warnings 0 .",
25
30
  "lint-dockerfile": "docker run --rm -i hadolint/hadolint:latest-alpine < docker/Dockerfile",
26
31
  "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:$VERSION -t davidanson/markdownlint-cli2:latest -f docker/Dockerfile --push .",
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:$VERSION \"*.md\"",
30
- "test-docker-hub-image": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker image rm davidanson/markdownlint-cli2:$VERSION davidanson/markdownlint-cli2:latest || true && docker run --rm -v $PWD:/workdir davidanson/markdownlint-cli2:$VERSION \"*.md\" && docker run --rm -v $PWD:/workdir davidanson/markdownlint-cli2:latest \"*.md\"",
32
+ "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
+ "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
+ "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\"",
35
+ "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
36
  "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"
37
+ "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",
39
+ "upgrade": "npx --yes npm-check-updates --upgrade",
40
+ "webworker": "cd webworker && webpack --mode none",
41
+ "webworker-install": "npm run docker-npm-install -- --no-save path-browserify process setimmediate stream-browserify url util webpack-cli"
33
42
  },
34
43
  "engines": {
35
- "node": ">=12"
44
+ "node": ">=14"
36
45
  },
37
46
  "files": [
38
47
  "append-to-array.js",
39
48
  "markdownlint-cli2.js",
49
+ "markdownlint-cli2-config.js",
40
50
  "markdownlint-cli2-fix.js",
41
51
  "merge-options.js",
42
52
  "resolve-and-require.js"
43
53
  ],
44
54
  "dependencies": {
45
- "globby": "~11.0.4",
46
- "markdownlint": "~0.24.0",
47
- "markdownlint-cli2-formatter-default": "^0.0.2",
48
- "markdownlint-rule-helpers": "~0.15.0",
49
- "micromatch": "~4.0.4",
50
- "strip-json-comments": "~3.1.1",
51
- "yaml": "~1.10.2"
55
+ "globby": "13.1.2",
56
+ "markdownlint": "0.26.2",
57
+ "markdownlint-cli2-formatter-default": "0.0.3",
58
+ "micromatch": "4.0.5",
59
+ "strip-json-comments": "5.0.0",
60
+ "yaml": "2.1.1"
52
61
  },
53
62
  "devDependencies": {
54
- "@iktakahiro/markdown-it-katex": "~4.0.1",
55
- "ava": "~3.15.0",
56
- "c8": "~7.8.0",
57
- "cpy": "~8.1.2",
58
- "del": "~6.0.0",
59
- "eslint": "~7.32.0",
60
- "eslint-plugin-node": "~11.1.0",
61
- "eslint-plugin-unicorn": "~35.0.0",
62
- "execa": "~5.1.1",
63
- "markdown-it-emoji": "~2.0.0",
64
- "markdown-it-for-inline": "~0.1.1",
65
- "markdownlint-cli2-formatter-json": "^0.0.4",
66
- "markdownlint-cli2-formatter-junit": "^0.0.3",
67
- "markdownlint-cli2-formatter-pretty": "^0.0.2",
68
- "markdownlint-cli2-formatter-summarize": "^0.0.3",
69
- "markdownlint-rule-titlecase": "~0.1.0",
70
- "npm-run-all": "~4.1.5"
63
+ "@iktakahiro/markdown-it-katex": "4.0.1",
64
+ "ava": "4.3.1",
65
+ "c8": "7.12.0",
66
+ "cpy": "9.0.1",
67
+ "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",
72
+ "markdown-it-emoji": "2.0.2",
73
+ "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",
78
+ "markdownlint-rule-titlecase": "0.1.0",
79
+ "npm-run-all": "4.1.5"
71
80
  },
72
81
  "keywords": [
73
82
  "markdown",
@@ -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 {Object} req Node's require function (or equivalent).
9
- * @param {*} id Package identifier to require.
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) => {