markdownlint-cli2 0.4.0 → 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.
Files changed (3) hide show
  1. package/README.md +54 -30
  2. package/markdownlint-cli2.js +145 -64
  3. package/package.json +25 -25
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
 
@@ -70,10 +73,10 @@ Dot-only glob:
70
73
  Configuration via:
71
74
  - .markdownlint-cli2.jsonc
72
75
  - .markdownlint-cli2.yaml
73
- - .markdownlint-cli2.cjs
76
+ - .markdownlint-cli2.cjs or .markdownlint-cli2.mjs
74
77
  - .markdownlint.jsonc or .markdownlint.json
75
78
  - .markdownlint.yaml or .markdownlint.yml
76
- - .markdownlint.cjs
79
+ - .markdownlint.cjs or .markdownlint.mjs
77
80
 
78
81
  Cross-platform compatibility:
79
82
  - UNIX and Windows shells expand globs according to different rules; quoting arguments is recommended
@@ -87,9 +90,9 @@ $ markdownlint-cli2 "**/*.md" "#node_modules"
87
90
  ```
88
91
 
89
92
  For scenarios where it is preferable to specify glob expressions in a
90
- configuration file, the `globs` property of `.markdownlint-cli2.jsonc` or
91
- `.markdownlint-cli2.yaml` or `.markdownlint-cli2.cjs` may be used instead of (or
92
- 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.
93
96
 
94
97
  As shown above, a typical command-line for `markdownlint-cli2` looks something
95
98
  like:
@@ -116,6 +119,10 @@ accepts a path to any supported configuration file as its first argument:
116
119
  markdownlint-cli2-config "config/.markdownlint-cli2.jsonc" "**/*.md" "#node_modules"
117
120
  ```
118
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.
119
126
  Otherwise, this command behaves identically to `markdownlint-cli2`.
120
127
 
121
128
  ### Container Image
@@ -124,7 +131,7 @@ A container image [`davidanson/markdownlint-cli2`][docker-hub-markdownlint-cli2]
124
131
  can also be used (e.g., as part of a CI pipeline):
125
132
 
126
133
  ```bash
127
- docker run -v $PWD:/workdir davidanson/markdownlint-cli2:0.4.0 "**/*.md" "#node_modules"
134
+ docker run -v $PWD:/workdir davidanson/markdownlint-cli2:0.5.0 "**/*.md" "#node_modules"
128
135
  ```
129
136
 
130
137
  Notes:
@@ -141,14 +148,14 @@ Notes:
141
148
  - A custom working directory can be specified with Docker's `-w` flag:
142
149
 
143
150
  ```bash
144
- docker run -w /myfolder -v $PWD:/myfolder davidanson/markdownlint-cli2:0.4.0 "**/*.md" "#node_modules"
151
+ docker run -w /myfolder -v $PWD:/myfolder davidanson/markdownlint-cli2:0.5.0 "**/*.md" "#node_modules"
145
152
  ```
146
153
 
147
154
  To invoke the `markdownlint-cli2-config` or `markdownlint-cli2-fix` commands
148
155
  instead, use Docker's `--entrypoint` flag:
149
156
 
150
157
  ```bash
151
- docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/markdownlint-cli2:0.4.0 "**/*.md" "#node_modules"
158
+ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/markdownlint-cli2:0.5.0 "**/*.md" "#node_modules"
152
159
  ```
153
160
 
154
161
  ### Exit Codes
@@ -172,11 +179,11 @@ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/mark
172
179
  - See the [Configuration][markdownlint-configuration] section of the
173
180
  `markdownlint` documentation for information about the inline comment syntax
174
181
  for enabling and disabling rules with HTML comments.
175
- - In general, glob expressions match files under the current directory and
176
- 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.
177
184
  - When glob expressions match files *not* under the current directory,
178
- configuration for the current (top-level) directory is applied to the
179
- closest common parent directory
185
+ configuration for the current directory is applied to the closest common
186
+ parent directory.
180
187
 
181
188
  ### `.markdownlint-cli2.jsonc`
182
189
 
@@ -190,8 +197,6 @@ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/mark
190
197
  - `customRules`: `Array` of `String`s (or `Array`s of `String`s) of module
191
198
  names/paths of [custom rules][markdownlint-custom-rules] to load and use
192
199
  when linting
193
- - Each `String` is passed as the `id` parameter to Node's
194
- [require function][nodejs-require]
195
200
  - Relative paths are resolved based on the location of the `JSONC` file
196
201
  - Search [`markdownlint-rule` on npm][markdownlint-rule]
197
202
  - `fix`: `Boolean` value to enable fixing of linting errors reported by rules
@@ -242,9 +247,16 @@ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/mark
242
247
  - This top-level setting is valid **only** in the directory from which
243
248
  `markdownlint-cli2` is run
244
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
245
257
  - Settings in this file apply to the directory it is in and all subdirectories.
246
258
  - Settings **merge with** those applied by any versions of this file in a parent
247
- directory.
259
+ directory (up to the current directory).
248
260
  - For example: [`.markdownlint-cli2.jsonc`][markdownlint-cli2-jsonc] with all
249
261
  properties set
250
262
 
@@ -258,17 +270,20 @@ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/mark
258
270
  - For example: [`.markdownlint-cli2.yaml`][markdownlint-cli2-yaml] with all
259
271
  properties set
260
272
 
261
- ### `.markdownlint-cli2.cjs`
273
+ ### `.markdownlint-cli2.cjs` or `.markdownlint-cli2.mjs`
262
274
 
263
- - The format of this file is a [CommonJS module][commonjs-module] that exports
264
- 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`.
265
278
  - Instead of passing a `String` to identify the module name/path to load for
266
279
  `customRules`, `markdownItPlugins`, and `outputFormatters`, the corresponding
267
280
  `Object` or `Function` can be provided directly.
268
281
  - Other details are the same as for `.markdownlint-cli2.jsonc` described above.
269
282
  - If a `.markdownlint-cli2.jsonc` or `.markdownlint-cli2.yaml` file is present
270
- in the same directory, it takes precedence.
271
- - For example: [`.markdownlint-cli2.cjs`][markdownlint-cli2-cjs]
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]
272
287
 
273
288
  ### `.markdownlint.jsonc` or `.markdownlint.json`
274
289
 
@@ -276,7 +291,7 @@ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/mark
276
291
  the [`markdownlint` `config` object][markdownlint-config].
277
292
  - Settings in this file apply to the directory it is in and all subdirectories
278
293
  - Settings **override** those applied by any versions of this file in a parent
279
- directory.
294
+ directory (up to the current directory).
280
295
  - If `jsonc` and `json` files are present in the same directory, the `jsonc`
281
296
  version takes precedence.
282
297
  - To merge the settings of these files or share configuration, use the `extends`
@@ -295,14 +310,17 @@ docker run -v $PWD:/workdir --entrypoint="markdownlint-cli2-fix" davidanson/mark
295
310
  precedence.
296
311
  - For example: [`.markdownlint.yaml`][markdownlint-yaml]
297
312
 
298
- ### `.markdownlint.cjs`
313
+ ### `.markdownlint.cjs` or `.markdownlint.mjs`
299
314
 
300
- - The format of this file is a [CommonJS module][commonjs-module] that exports
301
- 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].
302
318
  - Other details are the same as for `jsonc`/`json` files described above.
303
- - If a `jsonc`, `json`, `yaml`, or `yml` file is present in the same directory,
304
- it takes precedence.
305
- - For example: [`.markdownlint.cjs`][markdownlint-cjs]
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]
306
324
 
307
325
  ## Compatibility
308
326
 
@@ -326,7 +344,7 @@ reference to the `repos` list in that project's `.pre-commit-config.yaml` like:
326
344
 
327
345
  ```yaml
328
346
  - repo: https://github.com/DavidAnson/markdownlint-cli2
329
- rev: v0.4.0
347
+ rev: v0.5.0
330
348
  hooks:
331
349
  - id: markdownlint-cli2
332
350
  ```
@@ -359,11 +377,13 @@ reference to the `repos` list in that project's `.pre-commit-config.yaml` like:
359
377
  - 0.3.1 - Extensibility tweaks
360
378
  - 0.3.2 - Extensibility/Windows/consistency improvements
361
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
362
381
 
363
382
  <!-- markdownlint-disable line-length -->
364
383
 
365
384
  [commonmark]: https://commonmark.org/
366
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
367
387
  [docker-bind-mounts]: https://docs.docker.com/storage/bind-mounts/
368
388
  [docker-hub-markdownlint-cli2]: https://hub.docker.com/r/davidanson/markdownlint-cli2
369
389
  [front-matter]: https://jekyllrb.com/docs/frontmatter/
@@ -390,14 +410,18 @@ reference to the `repos` list in that project's `.pre-commit-config.yaml` like:
390
410
  [markdownlint-cli2-formatter]: https://www.npmjs.com/search?q=keywords:markdownlint-cli2-formatter
391
411
  [markdownlint-cli2-cjs]: test/markdownlint-cli2-cjs/.markdownlint-cli2.cjs
392
412
  [markdownlint-cli2-jsonc]: test/markdownlint-cli2-jsonc-example/.markdownlint-cli2.jsonc
413
+ [markdownlint-cli2-mjs]: test/markdownlint-cli2-mjs/.markdownlint-cli2.mjs
393
414
  [markdownlint-cli2-yaml]: test/markdownlint-cli2-yaml-example/.markdownlint-cli2.yaml
394
415
  [markdownlint-cjs]: test/markdownlint-cjs/.markdownlint.cjs
395
416
  [markdownlint-jsonc]: https://github.com/DavidAnson/markdownlint/blob/main/schema/.markdownlint.jsonc
417
+ [markdownlint-mjs]: test/markdownlint-mjs/.markdownlint.mjs
396
418
  [markdownlint-rule]: https://www.npmjs.com/search?q=keywords:markdownlint-rule
397
419
  [markdownlint-yaml]: https://github.com/DavidAnson/markdownlint/blob/main/schema/.markdownlint.yaml
398
420
  [nodejs]: https://nodejs.org/
399
421
  [nodejs-docker]: https://github.com/nodejs/docker-node
400
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
401
425
  [nodejs-require]: https://nodejs.org/api/modules.html#modules_require_id
402
426
  [npm-image]: https://img.shields.io/npm/v/markdownlint-cli2.svg
403
427
  [npm-url]: https://www.npmjs.com/package/markdownlint-cli2
@@ -10,18 +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");
13
+ const path = require("node:path");
14
+ const { pathToFileURL } = require("node:url");
14
15
  const markdownlintLibrary = require("markdownlint");
15
16
  const { markdownlint, "readConfig": markdownlintReadConfig } =
16
17
  markdownlintLibrary.promises;
17
- const markdownlintRuleHelpers = require("markdownlint-rule-helpers");
18
+ const markdownlintRuleHelpers = require("markdownlint/helpers");
18
19
  const appendToArray = require("./append-to-array");
19
20
  const mergeOptions = require("./merge-options");
20
21
  const resolveAndRequire = require("./resolve-and-require");
21
22
 
22
23
  // Variables
23
24
  const packageName = "markdownlint-cli2";
24
- const packageVersion = "0.4.0";
25
+ const packageVersion = "0.5.0";
25
26
  const libraryName = "markdownlint";
26
27
  const libraryVersion = markdownlintLibrary.getVersion();
27
28
  const dotOnlySubstitute = "*.{md,markdown}";
@@ -64,41 +65,59 @@ const readConfig = (fs, dir, name, otherwise) => {
64
65
  );
65
66
  };
66
67
 
67
- // Require a module ID with the specified directory in the path
68
- 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) => {
69
70
  if (typeof id === "string") {
70
- 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 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(" / "));
71
90
  }
72
91
  return id;
73
92
  };
74
93
 
75
- // Require an array of modules by ID
76
- const requireIds = (dir, ids, noRequire) => (
77
- noRequire ? [] : ids.map((id) => requireResolve(dir, 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)))
78
97
  );
79
98
 
80
- // Require an array of modules by ID (preserving parameters)
81
- const requireIdsAndParams = (dir, idsAndParams, noRequire) => {
99
+ // Import or require an array of modules by ID (preserving parameters)
100
+ const importOrRequireIdsAndParams = async (dir, idsAndParams, noRequire) => {
82
101
  if (noRequire) {
83
102
  return [];
84
103
  }
85
104
  const ids = idsAndParams.map((entry) => entry[0]);
86
- const modules = requireIds(dir, ids);
105
+ const modules = await importOrRequireIds(dir, ids);
87
106
  const modulesAndParams = idsAndParams.
88
107
  map((entry, i) => [ modules[i], ...entry.slice(1) ]);
89
108
  return modulesAndParams;
90
109
  };
91
110
 
92
- // Require a JS file and return the exported object
93
- const requireConfig = (fs, dir, name, noRequire) => (
111
+ // Import or require a JavaScript file and return the exported object
112
+ const importOrRequireConfig = (fs, dir, name, noRequire, otherwise) => (
94
113
  () => (noRequire
95
114
  // eslint-disable-next-line prefer-promise-reject-errors
96
115
  ? Promise.reject()
97
116
  : fs.promises.access(path.posix.join(dir, name))
98
117
  ).
99
118
  then(
100
- () => requireResolve(dir, `./${name}`),
101
- noop
119
+ () => importOrRequireResolve(dir, `./${name}`),
120
+ otherwise
102
121
  )
103
122
  );
104
123
 
@@ -113,8 +132,13 @@ const readOptionsOrConfig = async (configPath, fs, noRequire) => {
113
132
  options = jsoncParse(await fs.promises.readFile(configPath, utf8));
114
133
  } else if (basename.endsWith(".markdownlint-cli2.yaml")) {
115
134
  options = yamlParse(await fs.promises.readFile(configPath, utf8));
116
- } else if (basename.endsWith(".markdownlint-cli2.cjs")) {
117
- options = await (requireConfig(fs, dirname, basename, noRequire)());
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
+ );
118
142
  } else if (
119
143
  basename.endsWith(".markdownlint.jsonc") ||
120
144
  basename.endsWith(".markdownlint.json") ||
@@ -124,8 +148,19 @@ const readOptionsOrConfig = async (configPath, fs, noRequire) => {
124
148
  const jsoncParse = await getJsoncParse();
125
149
  config =
126
150
  await markdownlintReadConfig(configPath, [ jsoncParse, yamlParse ], fs);
127
- } else if (basename.endsWith(".markdownlint.cjs")) {
128
- config = await (requireConfig(fs, dirname, basename, noRequire)());
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
+ );
129
164
  }
130
165
  return options || { config };
131
166
  };
@@ -188,10 +223,10 @@ Dot-only glob:
188
223
  Configuration via:
189
224
  - .markdownlint-cli2.jsonc
190
225
  - .markdownlint-cli2.yaml
191
- - .markdownlint-cli2.cjs
226
+ - .markdownlint-cli2.cjs or .markdownlint-cli2.mjs
192
227
  - .markdownlint.jsonc or .markdownlint.json
193
228
  - .markdownlint.yaml or .markdownlint.yml
194
- - .markdownlint.cjs
229
+ - .markdownlint.cjs or .markdownlint.mjs
195
230
 
196
231
  Cross-platform compatibility:
197
232
  - UNIX and Windows shells expand globs according to different rules; quoting arguments is recommended
@@ -208,11 +243,12 @@ $ markdownlint-cli2 "**/*.md" "#node_modules"`
208
243
 
209
244
  // Get (creating if necessary) and process a directory's info object
210
245
  const getAndProcessDirInfo =
211
- (fs, tasks, dirToDirInfo, dir, noRequire, func) => {
246
+ (fs, tasks, dirToDirInfo, dir, relativeDir, noRequire, func) => {
212
247
  let dirInfo = dirToDirInfo[dir];
213
248
  if (!dirInfo) {
214
249
  dirInfo = {
215
250
  dir,
251
+ relativeDir,
216
252
  "parent": null,
217
253
  "files": [],
218
254
  "markdownlintConfig": null,
@@ -239,11 +275,18 @@ const getAndProcessDirInfo =
239
275
  () => fs.promises.
240
276
  readFile(markdownlintCli2Yaml, utf8).
241
277
  then(yamlParse),
242
- requireConfig(
278
+ importOrRequireConfig(
243
279
  fs,
244
280
  dir,
245
281
  ".markdownlint-cli2.cjs",
246
- noRequire
282
+ noRequire,
283
+ importOrRequireConfig(
284
+ fs,
285
+ dir,
286
+ ".markdownlint-cli2.mjs",
287
+ noRequire,
288
+ noop
289
+ )
247
290
  )
248
291
  )
249
292
  ).
@@ -270,11 +313,18 @@ const getAndProcessDirInfo =
270
313
  fs,
271
314
  dir,
272
315
  ".markdownlint.yml",
273
- requireConfig(
316
+ importOrRequireConfig(
274
317
  fs,
275
318
  dir,
276
319
  ".markdownlint.cjs",
277
- noRequire
320
+ noRequire,
321
+ importOrRequireConfig(
322
+ fs,
323
+ dir,
324
+ ".markdownlint.mjs",
325
+ noRequire,
326
+ noop
327
+ )
278
328
  )
279
329
  )
280
330
  )
@@ -297,20 +347,28 @@ const getAndProcessDirInfo =
297
347
  const getBaseOptions = async (
298
348
  fs,
299
349
  baseDir,
350
+ relativeDir,
300
351
  globPatterns,
301
- optionsDefault,
352
+ options,
302
353
  fixDefault,
303
354
  noGlobs,
304
355
  noRequire
305
356
  ) => {
306
357
  const tasks = [];
307
358
  const dirToDirInfo = {};
308
- getAndProcessDirInfo(fs, tasks, dirToDirInfo, baseDir, noRequire);
359
+ getAndProcessDirInfo(
360
+ fs,
361
+ tasks,
362
+ dirToDirInfo,
363
+ baseDir,
364
+ relativeDir,
365
+ noRequire
366
+ );
309
367
  await Promise.all(tasks);
310
368
  // eslint-disable-next-line no-multi-assign
311
369
  const baseMarkdownlintOptions = dirToDirInfo[baseDir].markdownlintOptions =
312
370
  mergeOptions(
313
- mergeOptions(optionsDefault, { "fix": fixDefault }),
371
+ mergeOptions(options, { "fix": fixDefault }),
314
372
  dirToDirInfo[baseDir].markdownlintOptions
315
373
  );
316
374
 
@@ -340,6 +398,7 @@ async (fs, baseDirSystem, baseDir, globPatterns, dirToDirInfo, noErrors, noRequi
340
398
  const globbyOptions = {
341
399
  "absolute": true,
342
400
  "cwd": baseDir,
401
+ "dot": true,
343
402
  "expandDirectories": false,
344
403
  fs
345
404
  };
@@ -400,6 +459,7 @@ async (fs, baseDirSystem, baseDir, globPatterns, dirToDirInfo, noErrors, noRequi
400
459
  tasks,
401
460
  dirToDirInfo,
402
461
  dir,
462
+ null,
403
463
  noRequire,
404
464
  (dirInfo) => {
405
465
  dirInfo.files.push(file);
@@ -437,6 +497,7 @@ const enumerateParents = async (fs, baseDir, dirToDirInfo, noRequire) => {
437
497
  tasks,
438
498
  dirToDirInfo,
439
499
  dir,
500
+ null,
440
501
  noRequire,
441
502
  // eslint-disable-next-line no-loop-func
442
503
  (dirInfo) => {
@@ -478,11 +539,13 @@ async (fs, baseDirSystem, baseDir, globPatterns, dirToDirInfo, optionsOverride,
478
539
  dirs.sort((a, b) => b.length - a.length);
479
540
  const dirInfos = [];
480
541
  const noConfigDirInfo =
542
+ // eslint-disable-next-line unicorn/consistent-function-scoping
481
543
  (dirInfo) => (
482
544
  dirInfo.parent &&
483
545
  !dirInfo.markdownlintConfig &&
484
546
  !dirInfo.markdownlintOptions
485
547
  );
548
+ const tasks = [];
486
549
  for (const dir of dirs) {
487
550
  const dirInfo = dirToDirInfo[dir];
488
551
  if (noConfigDirInfo(dirInfo)) {
@@ -491,28 +554,34 @@ async (fs, baseDirSystem, baseDir, globPatterns, dirToDirInfo, optionsOverride,
491
554
  }
492
555
  dirToDirInfo[dir] = null;
493
556
  } else {
494
- const { markdownlintOptions } = dirInfo;
557
+ const { markdownlintOptions, relativeDir } = dirInfo;
495
558
  if (markdownlintOptions && markdownlintOptions.customRules) {
496
- const customRules =
497
- requireIds(
498
- dir,
559
+ tasks.push(
560
+ importOrRequireIds(
561
+ relativeDir || dir,
499
562
  markdownlintOptions.customRules,
500
563
  noRequire
501
- );
502
- // Expand nested arrays (for packages that export multiple rules)
503
- markdownlintOptions.customRules = customRules.flat();
564
+ ).then((customRules) => {
565
+ // Expand nested arrays (for packages that export multiple rules)
566
+ markdownlintOptions.customRules = customRules.flat();
567
+ })
568
+ );
504
569
  }
505
570
  if (markdownlintOptions && markdownlintOptions.markdownItPlugins) {
506
- markdownlintOptions.markdownItPlugins =
507
- requireIdsAndParams(
508
- dir,
571
+ tasks.push(
572
+ importOrRequireIdsAndParams(
573
+ relativeDir || dir,
509
574
  markdownlintOptions.markdownItPlugins,
510
575
  noRequire
511
- );
576
+ ).then((markdownItPlugins) => {
577
+ markdownlintOptions.markdownItPlugins = markdownItPlugins;
578
+ })
579
+ );
512
580
  }
513
581
  dirInfos.push(dirInfo);
514
582
  }
515
583
  }
584
+ await Promise.all(tasks);
516
585
  for (const dirInfo of dirInfos) {
517
586
  while (dirInfo.parent && !dirToDirInfo[dirInfo.parent.dir]) {
518
587
  dirInfo.parent = dirInfo.parent.parent;
@@ -578,7 +647,8 @@ async (fs, baseDirSystem, baseDir, globPatterns, dirToDirInfo, optionsOverride,
578
647
  };
579
648
 
580
649
  // Lint files in groups by shared configuration
581
- const lintFiles = (fs, dirInfos, fileContents) => {
650
+ const lintFiles = async (fs, dirInfos, fileContents) => {
651
+ const jsoncParse = await getJsoncParse();
582
652
  const tasks = [];
583
653
  // For each dirInfo
584
654
  for (const dirInfo of dirInfos) {
@@ -607,6 +677,7 @@ const lintFiles = (fs, dirInfos, fileContents) => {
607
677
  "files": filteredFiles,
608
678
  "strings": filteredStrings,
609
679
  "config": markdownlintConfig || markdownlintOptions.config,
680
+ "configParsers": [ jsoncParse ],
610
681
  "customRules": markdownlintOptions.customRules,
611
682
  "frontMatter": markdownlintOptions.frontMatter
612
683
  ? new RegExp(markdownlintOptions.frontMatter, "u")
@@ -688,26 +759,33 @@ const createSummary = (baseDir, taskResults) => {
688
759
  };
689
760
 
690
761
  // Output summary via formatters
691
- const outputSummary =
692
- async (baseDir, summary, outputFormatters, logMessage, logError) => {
693
- const errorsPresent = (summary.length > 0);
694
- if (errorsPresent || outputFormatters) {
695
- const formatterOptions = {
696
- "directory": baseDir,
697
- "results": summary,
698
- logMessage,
699
- logError
700
- };
701
- const formattersAndParams = outputFormatters
702
- ? requireIdsAndParams(baseDir, outputFormatters)
703
- : [ [ require("markdownlint-cli2-formatter-default") ] ];
704
- await Promise.all(formattersAndParams.map((formatterAndParams) => {
705
- const [ formatter, ...formatterParams ] = formatterAndParams;
706
- return formatter(formatterOptions, ...formatterParams);
707
- }));
708
- }
709
- return errorsPresent;
710
- };
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
+ };
711
789
 
712
790
  // Main function
713
791
  const main = async (params) => {
@@ -727,7 +805,7 @@ const main = async (params) => {
727
805
  } = params;
728
806
  const logMessage = params.logMessage || noop;
729
807
  const logError = params.logError || noop;
730
- const fs = params.fs || require("fs");
808
+ const fs = params.fs || require("node:fs");
731
809
  const baseDirSystem =
732
810
  (directory && path.resolve(directory)) ||
733
811
  process.cwd();
@@ -739,10 +817,12 @@ const main = async (params) => {
739
817
  );
740
818
  // Read argv configuration file (if relevant and present)
741
819
  let optionsArgv = null;
820
+ let relativeDir = null;
742
821
  const [ configPath ] = (argv || []);
743
822
  if ((name === "markdownlint-cli2-config") && configPath) {
744
823
  optionsArgv =
745
824
  await readOptionsOrConfig(configPath, fs, noRequire);
825
+ relativeDir = path.dirname(configPath);
746
826
  }
747
827
  // Process arguments and get base options
748
828
  const globPatterns = processArgv(optionsArgv ? argv.slice(1) : argv);
@@ -750,6 +830,7 @@ const main = async (params) => {
750
830
  await getBaseOptions(
751
831
  fs,
752
832
  baseDir,
833
+ relativeDir,
753
834
  globPatterns,
754
835
  optionsArgv || optionsDefault,
755
836
  fixDefault,
@@ -810,7 +891,7 @@ const main = async (params) => {
810
891
  (optionsOverride && optionsOverride.outputFormatters) ||
811
892
  baseMarkdownlintOptions.outputFormatters;
812
893
  const errorsPresent = await outputSummary(
813
- baseDir, summary, outputFormatters, logMessage, logError
894
+ baseDir, relativeDir, summary, outputFormatters, logMessage, logError
814
895
  );
815
896
  // Return result
816
897
  return errorsPresent ? 1 : 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "markdownlint-cli2",
3
- "version": "0.4.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",
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "license": "MIT",
10
10
  "type": "commonjs",
11
- "main": "markdownlint-cli2.js",
11
+ "exports": "./markdownlint-cli2.js",
12
12
  "bin": {
13
13
  "markdownlint-cli2": "markdownlint-cli2.js",
14
14
  "markdownlint-cli2-config": "markdownlint-cli2-config.js",
@@ -21,24 +21,26 @@
21
21
  },
22
22
  "bugs": "https://github.com/DavidAnson/markdownlint-cli2/issues",
23
23
  "scripts": {
24
- "build-docker-image": "VERSION=$(node -e \"process.stdout.write(require('./package.json').version)\") && docker build -t davidanson/markdownlint-cli2:$VERSION -f docker/Dockerfile .",
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 .",
25
25
  "ci": "npm-run-all --continue-on-error --parallel test-cover lint",
26
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
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",
28
28
  "lint": "eslint --max-warnings 0 .",
29
29
  "lint-dockerfile": "docker run --rm -i hadolint/hadolint:latest-alpine < docker/Dockerfile",
30
30
  "lint-watch": "git ls-files | entr npm run lint",
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:$VERSION -t davidanson/markdownlint-cli2:latest -f docker/Dockerfile --push .",
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
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:$VERSION \"*.md\"",
34
- "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\"",
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\"",
35
35
  "test-cover": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 npm test",
36
36
  "test-watch": "git ls-files | entr npm run test",
37
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"
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"
39
41
  },
40
42
  "engines": {
41
- "node": ">=12"
43
+ "node": ">=14"
42
44
  },
43
45
  "files": [
44
46
  "append-to-array.js",
@@ -49,31 +51,29 @@
49
51
  "resolve-and-require.js"
50
52
  ],
51
53
  "dependencies": {
52
- "globby": "12.1.0",
53
- "markdownlint": "0.25.1",
54
+ "globby": "13.1.2",
55
+ "markdownlint": "0.26.1",
54
56
  "markdownlint-cli2-formatter-default": "0.0.3",
55
- "markdownlint-rule-helpers": "0.16.0",
56
- "micromatch": "4.0.4",
57
- "strip-json-comments": "4.0.0",
58
- "yaml": "1.10.2"
57
+ "micromatch": "4.0.5",
58
+ "strip-json-comments": "5.0.0",
59
+ "yaml": "2.1.1"
59
60
  },
60
61
  "devDependencies": {
61
62
  "@iktakahiro/markdown-it-katex": "4.0.1",
62
- "ava": "4.0.1",
63
- "c8": "7.11.0",
64
- "cpy": "8.1.2",
65
- "del": "6.0.0",
66
- "eslint": "8.6.0",
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",
67
68
  "eslint-plugin-node": "11.1.0",
68
- "eslint-plugin-unicorn": "40.0.0",
69
- "execa": "6.0.0",
70
- "markdown-it-emoji": "2.0.0",
69
+ "eslint-plugin-unicorn": "43.0.2",
70
+ "execa": "6.1.0",
71
+ "markdown-it-emoji": "2.0.2",
71
72
  "markdown-it-for-inline": "0.1.1",
72
- "markdownlint-cli2-formatter-json": "0.0.5",
73
- "markdownlint-cli2-formatter-junit": "0.0.4",
73
+ "markdownlint-cli2-formatter-json": "0.0.6",
74
+ "markdownlint-cli2-formatter-junit": "0.0.5",
74
75
  "markdownlint-cli2-formatter-pretty": "0.0.3",
75
76
  "markdownlint-cli2-formatter-summarize": "0.0.5",
76
- "markdownlint-rule-github-internal-links": "0.1.0",
77
77
  "markdownlint-rule-titlecase": "0.1.0",
78
78
  "npm-run-all": "4.1.5"
79
79
  },