markdownlint-cli2 0.12.1 → 0.14.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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.14.0
4
+
5
+ - Handle `--` parameter per POSIX convention
6
+ - Add support for glob to `gitignore` configuration
7
+ - Update dependencies (including `markdownlint`)
8
+
9
+ ## 0.13.0
10
+
11
+ - Add `noBanner` and `gitignore` configuration options
12
+ - Reduce install size by switching to `js-yaml` package
13
+ - Add more detail to some error messages
14
+ - Export JSONC/YAML parsers for reuse
15
+ - Update dependencies (including `markdownlint`)
16
+
3
17
  ## 0.12.1
4
18
 
5
19
  - Update JSONC parsing to handle trailing commas
package/README.md CHANGED
@@ -103,6 +103,7 @@ Cross-platform compatibility:
103
103
  - Shells that expand globs do not support negated patterns (!node_modules); quoting is required here
104
104
  - Some UNIX shells parse exclamation (!) in double-quotes; hashtag (#) is recommended in these cases
105
105
  - The path separator is forward slash (/) on all platforms; backslash (\) is automatically converted
106
+ - On any platform, passing the parameter "--" causes all remaining parameters to be treated literally
106
107
 
107
108
  The most compatible syntax for cross-platform support:
108
109
  $ markdownlint-cli2 "**/*.md" "#node_modules"
@@ -147,7 +148,7 @@ A container image [`davidanson/markdownlint-cli2`][docker-hub-markdownlint-cli2]
147
148
  can also be used (e.g., as part of a CI pipeline):
148
149
 
149
150
  ```bash
150
- docker run -v $PWD:/workdir davidanson/markdownlint-cli2:v0.12.1 "**/*.md" "#node_modules"
151
+ docker run -v $PWD:/workdir davidanson/markdownlint-cli2:v0.14.0 "**/*.md" "#node_modules"
151
152
  ```
152
153
 
153
154
  Notes:
@@ -164,7 +165,7 @@ Notes:
164
165
  - A custom working directory can be specified with Docker's `-w` flag:
165
166
 
166
167
  ```bash
167
- docker run -w /myfolder -v $PWD:/myfolder davidanson/markdownlint-cli2:v0.12.1 "**/*.md" "#node_modules"
168
+ docker run -w /myfolder -v $PWD:/myfolder davidanson/markdownlint-cli2:v0.14.0 "**/*.md" "#node_modules"
168
169
  ```
169
170
 
170
171
  For convenience, the container image
@@ -256,6 +257,17 @@ of the rules within.
256
257
  - The `String` is passed as the `pattern` parameter to the
257
258
  [`RegExp` constructor][regexp-constructor]
258
259
  - For example: `(^---\s*$[^]*?^---\s*$)(\r\n|\r|\n|$)`
260
+ - `gitignore`: `Boolean` or `String` value to automatically ignore files
261
+ referenced by `.gitignore` (or similar) when linting
262
+ - When the value `true` is specified, all `.gitignore` files in the tree are
263
+ imported (default `git` behavior)
264
+ - When a `String` value is specified, that glob pattern is used to identify
265
+ the set of ignore files to import
266
+ - The value `**/.gitignore` corresponds to the `Boolean` value `true`
267
+ - The value `.gitignore` imports only the file in the root of the tree;
268
+ this is usually equivalent and can be much faster for large trees
269
+ - This top-level setting is valid **only** in the directory from which
270
+ `markdownlint-cli2` is run
259
271
  - `globs`: `Array` of `String`s defining glob expressions to append to the
260
272
  command-line arguments
261
273
  - This setting can be used instead of (or in addition to) passing globs on
@@ -285,6 +297,10 @@ of the rules within.
285
297
  - Search [`markdown-it-plugins` on npm][markdown-it-plugins]
286
298
  - `modulePaths`: `Array` of `String`s providing additional paths to use when
287
299
  resolving module references (e.g., alternate locations for `node_modules`)
300
+ - `noBanner`: `Boolean` value to disable the display of the banner message and
301
+ version numbers on `stdout`
302
+ - This top-level setting is valid **only** in the directory from which
303
+ `markdownlint-cli2` is run
288
304
  - `noInlineConfig`: `Boolean` value to disable the support of
289
305
  [HTML comments][html-comment] within Markdown content
290
306
  - For example: `<!-- markdownlint-disable some-rule -->`
@@ -396,7 +412,7 @@ reference to the `repos` list in that project's `.pre-commit-config.yaml` like:
396
412
 
397
413
  ```yaml
398
414
  - repo: https://github.com/DavidAnson/markdownlint-cli2
399
- rev: v0.12.1
415
+ rev: v0.14.0
400
416
  hooks:
401
417
  - id: markdownlint-cli2
402
418
  ```
@@ -6,9 +6,9 @@ const sliceSize = 1000;
6
6
 
7
7
  /**
8
8
  * Efficiently appends the source array to the destination array.
9
- * @param {Object[]} destination Destination Array.
10
- * @param {Object[]} source Source Array.
11
- * @returns void
9
+ * @param {object[]} destination Destination Array.
10
+ * @param {object[]} source Source Array.
11
+ * @returns {void}
12
12
  */
13
13
  const appendToArray = (destination, source) => {
14
14
  // NOTE: destination.push(...source) throws "RangeError: Maximum call stack
@@ -26,35 +26,37 @@ const resolveAndRequire = require("./resolve-and-require");
26
26
 
27
27
  // Variables
28
28
  const packageName = "markdownlint-cli2";
29
- const packageVersion = "0.12.1";
29
+ const packageVersion = "0.14.0";
30
30
  const libraryName = "markdownlint";
31
31
  const libraryVersion = markdownlintLibrary.getVersion();
32
+ const bannerMessage = `${packageName} v${packageVersion} (${libraryName} v${libraryVersion})`;
32
33
  const dotOnlySubstitute = "*.{md,markdown}";
33
34
  const utf8 = "utf8";
34
35
 
35
36
  // No-op function
36
37
  const noop = () => null;
37
38
 
38
- // Synchronous function to parse JSONC text
39
- const jsoncParse = (text) => {
40
- const { parse, printParseErrorCode } = require("jsonc-parser");
41
- const errors = [];
42
- const result = parse(text, errors, { "allowTrailingComma": true });
43
- if (errors.length > 0) {
44
- const aggregate = errors.map(
45
- (err) => `${printParseErrorCode(err.error)} (offset ${err.offset}, length ${err.length})`
46
- ).join(", ");
47
- throw new Error(`Unable to parse JSON(C) content, ${aggregate}`);
48
- }
49
- return result;
50
- };
39
+ // Gets a JSONC parser
40
+ const getJsoncParse = () => require("./parsers/jsonc-parse.js");
41
+
42
+ // Gets a YAML parser
43
+ const getYamlParse = () => require("./parsers/yaml-parse.js");
51
44
 
52
- // Synchronous function to parse YAML text
53
- const yamlParse = (text) => require("yaml").parse(text);
45
+ // Gets an ordered array of parsers
46
+ const getParsers = () => require("./parsers/parsers.js");
54
47
 
55
- // Negate a glob
48
+ // Negates a glob
56
49
  const negateGlob = (glob) => `!${glob}`;
57
50
 
51
+ // Throws a meaningful exception for an unusable configuration file
52
+ const throwForConfigurationFile = (file, error) => {
53
+ throw new Error(
54
+ `Unable to use configuration file '${file}'; ${error?.message}`,
55
+ // @ts-ignore
56
+ { "cause": error }
57
+ );
58
+ };
59
+
58
60
  // Return a posix path (even on Windows)
59
61
  const posixPath = (p) => p.split(pathDefault.sep).join(pathPosix.sep);
60
62
 
@@ -69,13 +71,13 @@ const resolveModulePaths = (dir, modulePaths) => (
69
71
  );
70
72
 
71
73
  // Read a JSON(C) or YAML file and return the object
72
- const readConfig = (fs, dir, name, otherwise) => {
74
+ const readConfig = (fs, dir, name, otherwise) => () => {
73
75
  const file = pathPosix.join(dir, name);
74
- return () => fs.promises.access(file).
76
+ return fs.promises.access(file).
75
77
  then(
76
78
  () => markdownlintReadConfig(
77
79
  file,
78
- [ jsoncParse, yamlParse ],
80
+ getParsers(),
79
81
  fs
80
82
  ),
81
83
  otherwise
@@ -83,11 +85,12 @@ const readConfig = (fs, dir, name, otherwise) => {
83
85
  };
84
86
 
85
87
  // Import or resolve/require a module ID with a custom directory in the path
86
- const importOrRequireResolve = async (dirs, id, noRequire) => {
88
+ const importOrRequireResolve = async (dirOrDirs, id, noRequire) => {
87
89
  if (typeof id === "string") {
88
90
  if (noRequire) {
89
91
  return null;
90
92
  }
93
+ const dirs = Array.isArray(dirOrDirs) ? dirOrDirs : [ dirOrDirs ];
91
94
  const expandId = expandTildePath(id);
92
95
  const errors = [];
93
96
  try {
@@ -96,10 +99,13 @@ const importOrRequireResolve = async (dirs, id, noRequire) => {
96
99
  errors.push(error);
97
100
  }
98
101
  try {
99
- const fileUrlString =
100
- pathToFileURL(pathDefault.resolve(dirs[0], expandId)).toString();
102
+ // eslint-disable-next-line n/no-unsupported-features/node-builtins
103
+ const isURL = !pathDefault.isAbsolute(expandId) && URL.canParse(expandId);
104
+ const urlString = (
105
+ isURL ? new URL(expandId) : pathToFileURL(pathDefault.resolve(dirs[0], expandId))
106
+ ).toString();
101
107
  // eslint-disable-next-line no-inline-comments
102
- const module = await import(/* webpackIgnore: true */ fileUrlString);
108
+ const module = await import(/* webpackIgnore: true */ urlString);
103
109
  return module.default;
104
110
  } catch (error) {
105
111
  errors.push(error);
@@ -133,11 +139,11 @@ const importOrRequireIdsAndParams = (dirs, idsAndParams, noRequire) => (
133
139
  );
134
140
 
135
141
  // Import or require a JavaScript file and return the exported object
136
- const importOrRequireConfig = (fs, dir, name, noRequire, otherwise) => {
137
- const id = pathPosix.join(dir, name);
138
- return () => fs.promises.access(id).
142
+ const importOrRequireConfig = (fs, dir, name, noRequire, otherwise) => () => {
143
+ const file = pathPosix.join(dir, name);
144
+ return fs.promises.access(file).
139
145
  then(
140
- () => (noRequire ? {} : importOrRequireResolve([ dir ], id)),
146
+ () => importOrRequireResolve(dir, name, noRequire),
141
147
  otherwise
142
148
  );
143
149
  };
@@ -148,7 +154,7 @@ const getExtendedConfig = (config, configPath, fs) => {
148
154
  return markdownlintExtendConfig(
149
155
  config,
150
156
  configPath,
151
- [ jsoncParse, yamlParse ],
157
+ getParsers(),
152
158
  fs
153
159
  );
154
160
  }
@@ -162,47 +168,43 @@ const readOptionsOrConfig = async (configPath, fs, noRequire) => {
162
168
  const dirname = pathPosix.dirname(configPath);
163
169
  let options = null;
164
170
  let config = null;
165
- if (basename.endsWith(".markdownlint-cli2.jsonc")) {
166
- options = jsoncParse(await fs.promises.readFile(configPath, utf8));
167
- } else if (basename.endsWith(".markdownlint-cli2.yaml")) {
168
- options = yamlParse(await fs.promises.readFile(configPath, utf8));
169
- } else if (
170
- basename.endsWith(".markdownlint-cli2.cjs") ||
171
- basename.endsWith(".markdownlint-cli2.mjs")
172
- ) {
173
- options = await (
174
- importOrRequireConfig(fs, dirname, basename, noRequire, noop)()
175
- );
176
- } else if (
177
- basename.endsWith(".markdownlint.jsonc") ||
178
- basename.endsWith(".markdownlint.json") ||
179
- basename.endsWith(".markdownlint.yaml") ||
180
- basename.endsWith(".markdownlint.yml")
181
- ) {
182
- config =
183
- await markdownlintReadConfig(configPath, [ jsoncParse, yamlParse ], fs);
184
- } else if (
185
- basename.endsWith(".markdownlint.cjs") ||
186
- basename.endsWith(".markdownlint.mjs")
187
- ) {
188
- config = await (
189
- importOrRequireConfig(fs, dirname, basename, noRequire, noop)()
190
- );
191
- } else {
192
- throw new Error(
193
- `Configuration file "${configPath}" is unrecognized; ` +
194
- "its name should be (or end with) one of the supported types " +
195
- "(e.g., \".markdownlint.json\" or \"example.markdownlint-cli2.jsonc\")."
196
- );
171
+ try {
172
+ if (basename.endsWith(".markdownlint-cli2.jsonc")) {
173
+ options = getJsoncParse()(await fs.promises.readFile(configPath, utf8));
174
+ } else if (basename.endsWith(".markdownlint-cli2.yaml")) {
175
+ options = getYamlParse()(await fs.promises.readFile(configPath, utf8));
176
+ } else if (
177
+ basename.endsWith(".markdownlint-cli2.cjs") ||
178
+ basename.endsWith(".markdownlint-cli2.mjs")
179
+ ) {
180
+ options = await importOrRequireResolve(dirname, basename, noRequire);
181
+ } else if (
182
+ basename.endsWith(".markdownlint.jsonc") ||
183
+ basename.endsWith(".markdownlint.json") ||
184
+ basename.endsWith(".markdownlint.yaml") ||
185
+ basename.endsWith(".markdownlint.yml")
186
+ ) {
187
+ config = await markdownlintReadConfig(configPath, getParsers(), fs);
188
+ } else if (
189
+ basename.endsWith(".markdownlint.cjs") ||
190
+ basename.endsWith(".markdownlint.mjs")
191
+ ) {
192
+ config = await importOrRequireResolve(dirname, basename, noRequire);
193
+ } else {
194
+ throw new Error(
195
+ "File name should be (or end with) one of the supported types " +
196
+ "(e.g., '.markdownlint.json' or 'example.markdownlint-cli2.jsonc')."
197
+ );
198
+ }
199
+ } catch (error) {
200
+ throwForConfigurationFile(configPath, error);
197
201
  }
198
-
199
202
  if (options) {
200
203
  if (options.config) {
201
204
  options.config = await getExtendedConfig(options.config, configPath, fs);
202
205
  }
203
206
  return options;
204
207
  }
205
-
206
208
  config = await getExtendedConfig(config, configPath, fs);
207
209
  return { config };
208
210
  };
@@ -241,7 +243,10 @@ const processArgv = (argv) => {
241
243
  };
242
244
 
243
245
  // Show help if missing arguments
244
- const showHelp = (logMessage) => {
246
+ const showHelp = (logMessage, showBanner) => {
247
+ if (showBanner) {
248
+ logMessage(bannerMessage);
249
+ }
245
250
  logMessage(`https://github.com/DavidAnson/markdownlint-cli2
246
251
 
247
252
  Syntax: markdownlint-cli2 glob0 [glob1] [...] [globN] [--config file] [--fix] [--help]
@@ -280,6 +285,7 @@ Cross-platform compatibility:
280
285
  - Shells that expand globs do not support negated patterns (!node_modules); quoting is required here
281
286
  - Some UNIX shells parse exclamation (!) in double-quotes; hashtag (#) is recommended in these cases
282
287
  - The path separator is forward slash (/) on all platforms; backslash (\\) is automatically converted
288
+ - On any platform, passing the parameter "--" causes all remaining parameters to be treated literally
283
289
 
284
290
  The most compatible syntax for cross-platform support:
285
291
  $ markdownlint-cli2 "**/*.md" "#node_modules"`
@@ -297,6 +303,7 @@ const getAndProcessDirInfo = (
297
303
  noRequire,
298
304
  allowPackageJson
299
305
  ) => {
306
+ // Create dirInfo
300
307
  let dirInfo = dirToDirInfo[dir];
301
308
  if (!dirInfo) {
302
309
  dirInfo = {
@@ -310,46 +317,41 @@ const getAndProcessDirInfo = (
310
317
  dirToDirInfo[dir] = dirInfo;
311
318
 
312
319
  // Load markdownlint-cli2 object(s)
313
- const markdownlintCli2Jsonc =
314
- pathPosix.join(dir, ".markdownlint-cli2.jsonc");
315
- const markdownlintCli2Yaml =
316
- pathPosix.join(dir, ".markdownlint-cli2.yaml");
320
+ const markdownlintCli2Jsonc = pathPosix.join(dir, ".markdownlint-cli2.jsonc");
321
+ const markdownlintCli2Yaml = pathPosix.join(dir, ".markdownlint-cli2.yaml");
322
+ const markdownlintCli2Cjs = pathPosix.join(dir, ".markdownlint-cli2.cjs");
323
+ const markdownlintCli2Mjs = pathPosix.join(dir, ".markdownlint-cli2.mjs");
317
324
  const packageJson = pathPosix.join(dir, "package.json");
325
+ let file = "[UNKNOWN]";
326
+ // eslint-disable-next-line no-return-assign
327
+ const captureFile = (f) => file = f;
318
328
  tasks.push(
319
- fs.promises.access(markdownlintCli2Jsonc).
329
+ fs.promises.access(captureFile(markdownlintCli2Jsonc)).
320
330
  then(
321
- () => fs.promises.
322
- readFile(markdownlintCli2Jsonc, utf8).
323
- then(jsoncParse),
324
- () => fs.promises.access(markdownlintCli2Yaml).
331
+ () => fs.promises.readFile(file, utf8).then(getJsoncParse()),
332
+ () => fs.promises.access(captureFile(markdownlintCli2Yaml)).
325
333
  then(
326
- () => fs.promises.
327
- readFile(markdownlintCli2Yaml, utf8).
328
- then(yamlParse),
329
- importOrRequireConfig(
330
- fs,
331
- dir,
332
- ".markdownlint-cli2.cjs",
333
- noRequire,
334
- importOrRequireConfig(
335
- fs,
336
- dir,
337
- ".markdownlint-cli2.mjs",
338
- noRequire,
339
- () => (allowPackageJson
340
- ? fs.promises.access(packageJson)
341
- // eslint-disable-next-line prefer-promise-reject-errors
342
- : Promise.reject()
343
- ).
334
+ () => fs.promises.readFile(file, utf8).then(getYamlParse()),
335
+ () => fs.promises.access(captureFile(markdownlintCli2Cjs)).
336
+ then(
337
+ () => importOrRequireResolve(dir, file, noRequire),
338
+ () => fs.promises.access(captureFile(markdownlintCli2Mjs)).
344
339
  then(
345
- () => fs.promises.
346
- readFile(packageJson, utf8).
347
- then(jsoncParse).
348
- then((obj) => obj[packageName]),
349
- noop
340
+ () => importOrRequireResolve(dir, file, noRequire),
341
+ () => (allowPackageJson
342
+ ? fs.promises.access(captureFile(packageJson))
343
+ // eslint-disable-next-line prefer-promise-reject-errors
344
+ : Promise.reject()
345
+ ).
346
+ then(
347
+ () => fs.promises.
348
+ readFile(file, utf8).
349
+ then(getJsoncParse()).
350
+ then((obj) => obj[packageName]),
351
+ noop
352
+ )
350
353
  )
351
354
  )
352
- )
353
355
  )
354
356
  ).
355
357
  then((options) => {
@@ -358,13 +360,16 @@ const getAndProcessDirInfo = (
358
360
  options.config &&
359
361
  getExtendedConfig(
360
362
  options.config,
361
- // Just needs to identify a file in the right directory
363
+ // Just need to identify a file in the right directory
362
364
  markdownlintCli2Jsonc,
363
365
  fs
364
366
  ).
365
367
  then((config) => {
366
368
  options.config = config;
367
369
  });
370
+ }).
371
+ catch((error) => {
372
+ throwForConfigurationFile(file, error);
368
373
  })
369
374
  );
370
375
 
@@ -410,6 +415,8 @@ const getAndProcessDirInfo = (
410
415
  })
411
416
  );
412
417
  }
418
+
419
+ // Return dirInfo
413
420
  return dirInfo;
414
421
  };
415
422
 
@@ -471,14 +478,19 @@ const enumerateFiles = async (
471
478
  baseDir,
472
479
  globPatterns,
473
480
  dirToDirInfo,
481
+ gitignore,
482
+ ignoreFiles,
474
483
  noRequire
475
484
  ) => {
476
485
  const tasks = [];
486
+ /** @type {import("globby").Options} */
477
487
  const globbyOptions = {
478
488
  "absolute": true,
479
489
  "cwd": baseDir,
480
490
  "dot": true,
481
491
  "expandDirectories": false,
492
+ gitignore,
493
+ ignoreFiles,
482
494
  "suppressErrors": true,
483
495
  fs
484
496
  };
@@ -603,6 +615,8 @@ const createDirInfos = async (
603
615
  globPatterns,
604
616
  dirToDirInfo,
605
617
  optionsOverride,
618
+ gitignore,
619
+ ignoreFiles,
606
620
  noRequire
607
621
  ) => {
608
622
  await enumerateFiles(
@@ -611,6 +625,8 @@ const createDirInfos = async (
611
625
  baseDir,
612
626
  globPatterns,
613
627
  dirToDirInfo,
628
+ gitignore,
629
+ ignoreFiles,
614
630
  noRequire
615
631
  );
616
632
  await enumerateParents(
@@ -767,7 +783,7 @@ const lintFiles = (fs, dirInfos, fileContents) => {
767
783
  "files": filteredFiles,
768
784
  "strings": filteredStrings,
769
785
  "config": markdownlintConfig || markdownlintOptions.config,
770
- "configParsers": [ jsoncParse, yamlParse ],
786
+ "configParsers": getParsers(),
771
787
  "customRules": markdownlintOptions.customRules,
772
788
  "frontMatter": markdownlintOptions.frontMatter
773
789
  ? new RegExp(markdownlintOptions.frontMatter, "u")
@@ -902,52 +918,52 @@ const main = async (params) => {
902
918
  (directory && pathDefault.resolve(directory)) ||
903
919
  process.cwd();
904
920
  const baseDir = posixPath(baseDirSystem);
905
- // Output banner
906
- logMessage(
907
- `${packageName} v${packageVersion} (${libraryName} v${libraryVersion})`
908
- );
909
921
  // Merge and process args/argv
910
922
  let fixDefault = false;
911
923
  // eslint-disable-next-line unicorn/no-useless-undefined
912
924
  let configPath = undefined;
925
+ let sawDashDash = false;
913
926
  let shouldShowHelp = false;
914
927
  const argvFiltered = (argv || []).filter((arg) => {
915
- if (configPath === null) {
928
+ if (sawDashDash) {
929
+ return true;
930
+ } else if (configPath === null) {
916
931
  configPath = arg;
917
- return false;
918
932
  // eslint-disable-next-line unicorn/prefer-switch
933
+ } else if (arg === "--") {
934
+ sawDashDash = true;
919
935
  } else if (arg === "--config") {
920
936
  configPath = null;
921
- return false;
922
937
  } else if (arg === "--fix") {
923
938
  fixDefault = true;
924
- return false;
925
939
  } else if (arg === "--help") {
926
940
  shouldShowHelp = true;
927
- return false;
928
941
  } else if (arg === "--no-globs") {
929
942
  noGlobs = true;
930
- return false;
943
+ } else {
944
+ return true;
931
945
  }
932
- return true;
946
+ return false;
933
947
  });
934
948
  if (shouldShowHelp) {
935
- return showHelp(logMessage);
949
+ return showHelp(logMessage, true);
936
950
  }
937
951
  // Read argv configuration file (if relevant and present)
938
952
  let optionsArgv = null;
939
953
  let relativeDir = null;
940
- if (configPath) {
941
- const resolvedConfigPath =
942
- posixPath(pathDefault.resolve(baseDirSystem, configPath));
943
- optionsArgv =
944
- await readOptionsOrConfig(resolvedConfigPath, fs, noRequire);
945
- relativeDir = pathPosix.dirname(resolvedConfigPath);
946
- }
947
- // Process arguments and get base options
948
- const globPatterns = processArgv(argvFiltered);
949
- const { baseMarkdownlintOptions, dirToDirInfo } =
950
- await getBaseOptions(
954
+ let globPatterns = null;
955
+ let baseOptions = null;
956
+ try {
957
+ if (configPath) {
958
+ const resolvedConfigPath =
959
+ posixPath(pathDefault.resolve(baseDirSystem, configPath));
960
+ optionsArgv =
961
+ await readOptionsOrConfig(resolvedConfigPath, fs, noRequire);
962
+ relativeDir = pathPosix.dirname(resolvedConfigPath);
963
+ }
964
+ // Process arguments and get base options
965
+ globPatterns = processArgv(argvFiltered);
966
+ baseOptions = await getBaseOptions(
951
967
  fs,
952
968
  baseDir,
953
969
  relativeDir,
@@ -957,13 +973,19 @@ const main = async (params) => {
957
973
  noGlobs,
958
974
  noRequire
959
975
  );
976
+ } finally {
977
+ if (!baseOptions?.baseMarkdownlintOptions.noBanner) {
978
+ logMessage(bannerMessage);
979
+ }
980
+ }
960
981
  if (
961
982
  ((globPatterns.length === 0) && !nonFileContents) ||
962
983
  (configPath === null)
963
984
  ) {
964
- return showHelp(logMessage);
985
+ return showHelp(logMessage, false);
965
986
  }
966
987
  // Include any file overrides or non-file content
988
+ const { baseMarkdownlintOptions, dirToDirInfo } = baseOptions;
967
989
  const resolvedFileContents = {};
968
990
  for (const file in fileContents) {
969
991
  const resolvedFile = posixPath(pathDefault.resolve(baseDirSystem, file));
@@ -983,6 +1005,13 @@ const main = async (params) => {
983
1005
  logMessage(`Finding: ${globPatterns.join(" ")}`);
984
1006
  }
985
1007
  // Create linting tasks
1008
+ const gitignore =
1009
+ // https://github.com/sindresorhus/globby/issues/265
1010
+ (!params.fs && (baseMarkdownlintOptions.gitignore === true));
1011
+ const ignoreFiles =
1012
+ (!params.fs && (typeof baseMarkdownlintOptions.gitignore === "string"))
1013
+ ? baseMarkdownlintOptions.gitignore
1014
+ : undefined;
986
1015
  const dirInfos =
987
1016
  await createDirInfos(
988
1017
  fs,
@@ -991,6 +1020,8 @@ const main = async (params) => {
991
1020
  globPatterns,
992
1021
  dirToDirInfo,
993
1022
  optionsOverride,
1023
+ gitignore,
1024
+ ignoreFiles,
994
1025
  noRequire
995
1026
  );
996
1027
  // Output linting status
package/merge-options.js CHANGED
@@ -4,9 +4,9 @@
4
4
 
5
5
  /**
6
6
  * Merges two options objects by combining config and replacing properties.
7
- * @param {Object} first First options object.
8
- * @param {Object} second Second options object.
9
- * @returns {Object} Merged options object.
7
+ * @param {object} first First options object.
8
+ * @param {object} second Second options object.
9
+ * @returns {object} Merged options object.
10
10
  */
11
11
  const mergeOptions = (first, second) => {
12
12
  const merged = {