editorconfig 2.0.0 → 3.0.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/lib/cli.d.ts CHANGED
@@ -1,5 +1,5 @@
1
+ import * as editorconfig from './index.js';
1
2
  import { type OutputConfiguration } from 'commander';
2
- import * as editorconfig from './';
3
3
  /**
4
4
  * Command line interface for editorconfig. Pulled out into a separate module
5
5
  * to make it easier to test.
package/lib/cli.js CHANGED
@@ -15,19 +15,30 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
28
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.default = cli;
40
+ const editorconfig = __importStar(require("./index.js"));
29
41
  const commander_1 = require("commander");
30
- const editorconfig = __importStar(require("./"));
31
42
  const package_json_1 = __importDefault(require("../package.json"));
32
43
  /**
33
44
  * Default output routine, goes to stdout.
@@ -53,13 +64,12 @@ async function cli(args, testing) {
53
64
  let writeOut = writeStdOut;
54
65
  if (testing) {
55
66
  if (testing.writeOut) {
56
- // eslint-disable-next-line @typescript-eslint/unbound-method
57
- writeOut = testing.writeOut;
67
+ ({ writeOut } = testing);
58
68
  }
59
69
  program.configureOutput(testing);
60
70
  program.exitOverride();
61
71
  }
62
- program.version('EditorConfig Node.js Core Version ' + package_json_1.default.version, '-v, --version', 'Display version information')
72
+ program.version(`EditorConfig Node.js Core Version ${package_json_1.default.version}`, '-v, --version', 'Display version information')
63
73
  .showHelpAfterError()
64
74
  .argument('<FILEPATH...>', 'Files to find configuration for. Can be a hyphen (-) if you want path(s) to be read from stdin.')
65
75
  .option('-f <path>', 'Specify conf filename other than \'.editorconfig\'')
@@ -88,7 +98,7 @@ async function cli(args, testing) {
88
98
  }
89
99
  return p;
90
100
  }
91
- return await processAll().then((parsed) => {
101
+ return processAll().then(parsed => {
92
102
  const header = parsed.length > 1;
93
103
  parsed.forEach((props, i) => {
94
104
  if (header) {
@@ -108,4 +118,3 @@ async function cli(args, testing) {
108
118
  return parsed;
109
119
  });
110
120
  }
111
- exports.default = cli;
@@ -0,0 +1 @@
1
+ import 'chai/register-should.js';
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ require("chai/register-should.js");
7
+ const cli_js_1 = __importDefault(require("./cli.js"));
8
+ async function exec(...args) {
9
+ const out = [];
10
+ const err = [];
11
+ const res = {
12
+ stdout: '',
13
+ stderr: '',
14
+ };
15
+ try {
16
+ res.props = await (0, cli_js_1.default)(['node', 'editorconfig', ...args], {
17
+ writeOut(s) {
18
+ out.push(s);
19
+ },
20
+ writeErr(s) {
21
+ err.push(s);
22
+ },
23
+ });
24
+ }
25
+ catch (er) {
26
+ res.err = er;
27
+ }
28
+ if (out.length) {
29
+ res.stdout = out.join('');
30
+ }
31
+ if (err.length) {
32
+ res.stderr = err.join('');
33
+ }
34
+ return res;
35
+ }
36
+ describe('Command line interface', () => {
37
+ it('helps', async () => {
38
+ const res = await exec('--help');
39
+ res.stdout.should.match(/^Usage:/);
40
+ });
41
+ it('Lists files', async () => {
42
+ const res = await exec('foo.md', '--files');
43
+ res.stdout.trim().should.match(/\.editorconfig \[\*\.md\]$/);
44
+ });
45
+ it('Lists multiple files', async () => {
46
+ const res = await exec('foo.md', 'bar.js', '--files');
47
+ res.stdout.should.match(/^\[foo\.md\]/);
48
+ res.stdout.trim().should.match(/\.editorconfig \[\*\]$/);
49
+ });
50
+ });
package/lib/index.d.ts CHANGED
@@ -1,24 +1,70 @@
1
- /// <reference types="node" />
1
+ import { Buffer } from 'node:buffer';
2
2
  import { Minimatch } from 'minimatch';
3
3
  export interface KnownProps {
4
+ /**
5
+ * Specifies the character set. Use of `utf-8-bom` is discouraged.
6
+ */
7
+ charset?: 'latin1' | 'utf-8' | 'utf-8-bom' | 'utf-16be' | 'utf-16le' | 'unset';
8
+ /**
9
+ * Specifies how line breaks are represented.
10
+ */
4
11
  end_of_line?: 'lf' | 'crlf' | 'unset';
5
- indent_style?: 'tab' | 'space' | 'unset';
12
+ /**
13
+ * Specifies the number of columns used for each indentation level
14
+ * and the width of soft tabs (when supported).
15
+ *
16
+ * If `indent_size` in the config is set to `tab`,
17
+ * the value of this property will be:
18
+ * - the same as the value of the {@link KnownProps.tab_width tab_width}
19
+ * if it is specified;
20
+ * - `tab` if it is not.
21
+ */
6
22
  indent_size?: number | 'tab' | 'unset';
23
+ /**
24
+ * Specifies whether tabs or spaces should be used for indentation.
25
+ * - `tab`: Use hard tabs for indentation,
26
+ * filling the remainder with spaces if needed.
27
+ * - `space`: Use spaces for indentation.
28
+ */
29
+ indent_style?: 'tab' | 'space' | 'unset';
30
+ /**
31
+ * Specifies whether a file should end with a newline character when saved.
32
+ * - `true`: Ensure the file ends with a newline.
33
+ * - `false`: Ensure the file does not end with a newline.
34
+ *
35
+ * Editors must not insert newlines in empty files
36
+ * when saving those files, even if `insert_final_newline` = true.
37
+ */
7
38
  insert_final_newline?: true | false | 'unset';
39
+ /**
40
+ * Specifies the number of columns used to represent a tab character.
41
+ *
42
+ * This defaults to the value of {@link KnownProps.indent_size indent_size}
43
+ * and should not usually need to be specified.
44
+ */
8
45
  tab_width?: number | 'unset';
46
+ /**
47
+ * Specifies whether all whitespace characters
48
+ * preceding newline characters in the file should be removed.
49
+ * - `true`: Remove all trailing whitespace before newlines.
50
+ * - `false`: Preserve trailing whitespace.
51
+ */
9
52
  trim_trailing_whitespace?: true | false | 'unset';
10
- charset?: string | 'unset';
11
53
  }
12
- interface UnknownMap {
54
+ export interface UnknownMap {
13
55
  [index: string]: unknown;
14
56
  }
15
- export type Props = KnownProps & UnknownMap;
57
+ export type PossibleValue = boolean | number | (string & {});
58
+ export type AddPossibleValues<T extends object> = {
59
+ [K in keyof T]: T[K] | PossibleValue;
60
+ };
61
+ export type Props = AddPossibleValues<KnownProps> & UnknownMap;
16
62
  export interface ECFile {
17
63
  name: string;
18
64
  contents?: Buffer;
19
65
  }
20
- type SectionGlob = Minimatch | null;
21
- type GlobbedProps = [SectionName, Props, SectionGlob][];
66
+ export type SectionGlob = Minimatch | null;
67
+ export type GlobbedProps = [SectionName, Props, SectionGlob][];
22
68
  export interface ProcessedFileConfig {
23
69
  root: boolean;
24
70
  name: string;
@@ -60,39 +106,39 @@ export declare function parseBuffer(data: Buffer): ParseStringResult;
60
106
  *
61
107
  * @param data String to parse.
62
108
  * @returns Parsed contents. Will be truncated if there was a parse error.
63
- * @deprecated Use {@link ParseBuffer} instead.
109
+ * @deprecated Use {@link parseBuffer} instead.
64
110
  */
65
111
  export declare function parseString(data: string): ParseStringResult;
112
+ /**
113
+ * For any pair, a value of `unset` removes the effect of that pair, even if
114
+ * it has been set before. This method modifies the properties object in
115
+ * place to remove any property that has a value of `unset`.
116
+ *
117
+ * @param props Properties object to modify.
118
+ */
119
+ export declare function unset(props: Props): void;
66
120
  /**
67
121
  * Low-level interface, which exists only for backward-compatibility.
68
122
  * Deprecated.
69
123
  *
70
124
  * @param filepath The name of the target file, relative to process.cwd().
71
- * @param files A promise for a list of objects describing the files.
125
+ * @param files A list of objects describing the files.
72
126
  * @param options All options
73
127
  * @returns The properties found for filepath
74
128
  * @deprecated
75
129
  */
76
- export declare function parseFromFiles(filepath: string, files: Promise<ECFile[]>, options?: ParseOptions): Promise<Props>;
130
+ export declare function parseFromFilesSync(filepath: string, files: ECFile[], options?: ParseOptions): Props;
77
131
  /**
78
132
  * Low-level interface, which exists only for backward-compatibility.
79
133
  * Deprecated.
80
134
  *
81
135
  * @param filepath The name of the target file, relative to process.cwd().
82
- * @param files A list of objects describing the files.
136
+ * @param files A promise for a list of objects describing the files.
83
137
  * @param options All options
84
138
  * @returns The properties found for filepath
85
139
  * @deprecated
86
140
  */
87
- export declare function parseFromFilesSync(filepath: string, files: ECFile[], options?: ParseOptions): Props;
88
- /**
89
- * For any pair, a value of `unset` removes the effect of that pair, even if
90
- * it has been set before. This method modifies the properties object in
91
- * place to remove any property that has a value of `unset`.
92
- *
93
- * @param props Properties object to modify.
94
- */
95
- export declare function unset(props: Props): void;
141
+ export declare function parseFromFiles(filepath: string, files: Promise<ECFile[]>, options?: ParseOptions): Promise<Props>;
96
142
  /**
97
143
  * Find all of the properties from matching sections in config files in the
98
144
  * same directory or toward the root of the filesystem.
@@ -125,4 +171,3 @@ export declare function parseSync(filepath: string, options?: ParseOptions): Pro
125
171
  * @private
126
172
  */
127
173
  export declare function matcher(options: ParseOptions, ...buffers: Buffer[]): (filepath: string) => Props;
128
- export {};
package/lib/index.js CHANGED
@@ -15,35 +15,52 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
28
38
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.matcher = exports.parseSync = exports.parse = exports.unset = exports.parseFromFilesSync = exports.parseFromFiles = exports.parseString = exports.parseBuffer = void 0;
30
- const fs = __importStar(require("fs"));
31
- const path = __importStar(require("path"));
39
+ exports.parseBuffer = parseBuffer;
40
+ exports.parseString = parseString;
41
+ exports.unset = unset;
42
+ exports.parseFromFilesSync = parseFromFilesSync;
43
+ exports.parseFromFiles = parseFromFiles;
44
+ exports.parse = parse;
45
+ exports.parseSync = parseSync;
46
+ exports.matcher = matcher;
47
+ const fs = __importStar(require("node:fs"));
48
+ const path = __importStar(require("node:path"));
32
49
  const semver = __importStar(require("semver"));
33
- const minimatch_1 = require("minimatch");
34
50
  const wasm_1 = require("@one-ini/wasm");
35
- // @ts-ignore So we can set the rootDir to be 'lib', without processing
36
- // package.json
51
+ const node_buffer_1 = require("node:buffer");
52
+ const minimatch_1 = require("minimatch");
37
53
  const package_json_1 = __importDefault(require("../package.json"));
38
54
  const escapedSep = new RegExp(path.sep.replace(/\\/g, '\\\\'), 'g');
39
55
  const matchOptions = { matchBase: true, dot: true };
40
56
  const knownPropNames = [
57
+ 'charset',
41
58
  'end_of_line',
42
- 'indent_style',
43
59
  'indent_size',
60
+ 'indent_style',
44
61
  'insert_final_newline',
62
+ // 'tab_width' // This should be an integer, not a string.
45
63
  'trim_trailing_whitespace',
46
- 'charset',
47
64
  ];
48
65
  const knownProps = new Set(knownPropNames);
49
66
  /**
@@ -81,19 +98,17 @@ function parseBuffer(data) {
81
98
  }
82
99
  return res;
83
100
  }
84
- exports.parseBuffer = parseBuffer;
85
101
  /**
86
102
  * Parses a string. If possible, you should always use ParseBuffer instead,
87
103
  * since this function does a UTF16-to-UTF8 conversion first.
88
104
  *
89
105
  * @param data String to parse.
90
106
  * @returns Parsed contents. Will be truncated if there was a parse error.
91
- * @deprecated Use {@link ParseBuffer} instead.
107
+ * @deprecated Use {@link parseBuffer} instead.
92
108
  */
93
109
  function parseString(data) {
94
- return parseBuffer(Buffer.from(data));
110
+ return parseBuffer(node_buffer_1.Buffer.from(data));
95
111
  }
96
- exports.parseString = parseString;
97
112
  /**
98
113
  * Gets a list of *potential* filenames based on the path of the target
99
114
  * filename.
@@ -121,23 +136,23 @@ function getConfigFileNames(filepath, options) {
121
136
  function processMatches(matches, version) {
122
137
  // Set indent_size to 'tab' if indent_size is unspecified and
123
138
  // indent_style is set to 'tab'.
124
- if ('indent_style' in matches
125
- && matches.indent_style === 'tab'
126
- && !('indent_size' in matches)
127
- && semver.gte(version, '0.10.0')) {
139
+ if ('indent_style' in matches &&
140
+ matches.indent_style === 'tab' &&
141
+ !('indent_size' in matches) &&
142
+ semver.gte(version, '0.10.0')) {
128
143
  matches.indent_size = 'tab';
129
144
  }
130
145
  // Set tab_width to indent_size if indent_size is specified and
131
146
  // tab_width is unspecified
132
- if ('indent_size' in matches
133
- && !('tab_width' in matches)
134
- && matches.indent_size !== 'tab') {
147
+ if ('indent_size' in matches &&
148
+ !('tab_width' in matches) &&
149
+ matches.indent_size !== 'tab') {
135
150
  matches.tab_width = matches.indent_size;
136
151
  }
137
152
  // Set indent_size to tab_width if indent_size is 'tab'
138
- if ('indent_size' in matches
139
- && 'tab_width' in matches
140
- && matches.indent_size === 'tab') {
153
+ if ('indent_size' in matches &&
154
+ 'tab_width' in matches &&
155
+ matches.indent_size === 'tab') {
141
156
  matches.indent_size = matches.tab_width;
142
157
  }
143
158
  return matches;
@@ -153,9 +168,11 @@ function buildFullGlob(pathPrefix, glob) {
153
168
  default:
154
169
  break;
155
170
  }
171
+ //
156
172
  // braces_escaped_backslash2
157
173
  // backslash_not_on_windows
158
174
  glob = glob.replace(/\\\\/g, '\\\\\\\\');
175
+ //
159
176
  // star_star_over_separator{1,3,5,6,9,15}
160
177
  glob = glob.replace(/\*\*/g, '{*,**/**/**}');
161
178
  // NOT path.join. Must stay in forward slashes.
@@ -172,7 +189,7 @@ function buildFullGlob(pathPrefix, glob) {
172
189
  function normalizeProps(options) {
173
190
  const props = {};
174
191
  for (const key in options) {
175
- if (options.hasOwnProperty(key)) {
192
+ if (Object.prototype.hasOwnProperty.call(options, key)) {
176
193
  const value = options[key];
177
194
  const key2 = key.toLowerCase();
178
195
  let value2 = value;
@@ -183,8 +200,11 @@ function normalizeProps(options) {
183
200
  try {
184
201
  value2 = JSON.parse(String(value));
185
202
  }
186
- catch (e) { }
203
+ catch (_e) {
204
+ // Ignored
205
+ }
187
206
  if (typeof value2 === 'undefined' || value2 === null) {
207
+ //
188
208
  // null and undefined are values specific to JSON (no special meaning
189
209
  // in editorconfig) & should just be returned as regular strings.
190
210
  value2 = String(value);
@@ -205,7 +225,8 @@ function normalizeProps(options) {
205
225
  * @returns Processed file with globs pre-computed.
206
226
  */
207
227
  function processFileContents(filepath, contents, options) {
208
- let res;
228
+ let res = undefined;
229
+ // eslint-disable-next-line no-negated-condition
209
230
  if (!contents) {
210
231
  // Negative cache
211
232
  res = {
@@ -236,7 +257,7 @@ function processFileContents(filepath, contents, options) {
236
257
  name ? buildFullGlob(pathPrefix, name) : null,
237
258
  ]);
238
259
  res = {
239
- root: !!globbed[0][1].root,
260
+ root: Boolean(globbed[0][1].root), // Global section: globbed[0]
240
261
  name: filepath,
241
262
  config: globbed,
242
263
  };
@@ -285,7 +306,7 @@ function getConfigSync(filepath, options) {
285
306
  return cached;
286
307
  }
287
308
  }
288
- let contents;
309
+ let contents = undefined;
289
310
  try {
290
311
  contents = fs.readFileSync(filepath);
291
312
  }
@@ -359,47 +380,21 @@ function opts(filepath, options = {}) {
359
380
  ];
360
381
  }
361
382
  /**
362
- * Low-level interface, which exists only for backward-compatibility.
363
- * Deprecated.
364
- *
365
- * @param filepath The name of the target file, relative to process.cwd().
366
- * @param files A promise for a list of objects describing the files.
367
- * @param options All options
368
- * @returns The properties found for filepath
369
- * @deprecated
370
- */
371
- async function parseFromFiles(filepath, files, options = {}) {
372
- return parseFromFilesSync(filepath, await files, options);
373
- }
374
- exports.parseFromFiles = parseFromFiles;
375
- /**
376
- * Low-level interface, which exists only for backward-compatibility.
377
- * Deprecated.
383
+ * For any pair, a value of `unset` removes the effect of that pair, even if
384
+ * it has been set before. This method modifies the properties object in
385
+ * place to remove any property that has a value of `unset`.
378
386
  *
379
- * @param filepath The name of the target file, relative to process.cwd().
380
- * @param files A list of objects describing the files.
381
- * @param options All options
382
- * @returns The properties found for filepath
383
- * @deprecated
387
+ * @param props Properties object to modify.
384
388
  */
385
- function parseFromFilesSync(filepath, files, options = {}) {
386
- const [resolvedFilePath, processedOptions] = opts(filepath, options);
387
- const configs = [];
388
- for (const ecf of files) {
389
- let cfg;
390
- if (!options.cache || !(cfg = options.cache.get(ecf.name))) { // Single "="!
391
- cfg = processFileContents(ecf.name, ecf.contents, processedOptions);
392
- }
393
- if (!cfg.notfound) {
394
- configs.push(cfg);
395
- }
396
- if (cfg.root) {
397
- break;
389
+ function unset(props) {
390
+ const keys = Object.keys(props);
391
+ for (const k of keys) {
392
+ if (props[k] === 'unset') {
393
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
394
+ delete props[k];
398
395
  }
399
396
  }
400
- return combine(resolvedFilePath, configs, processedOptions);
401
397
  }
402
- exports.parseFromFilesSync = parseFromFilesSync;
403
398
  /**
404
399
  * Combine the pre-parsed results of all matching config file sections, in
405
400
  * order.
@@ -412,7 +407,7 @@ exports.parseFromFilesSync = parseFromFilesSync;
412
407
  function combine(filepath, configs, options) {
413
408
  const ret = configs.reverse().reduce((props, processed) => {
414
409
  for (const [name, body, glob] of processed.config) {
415
- if (glob && glob.match(filepath)) {
410
+ if (glob === null || glob === void 0 ? void 0 : glob.match(filepath)) {
416
411
  Object.assign(props, body);
417
412
  if (options.files) {
418
413
  options.files.push({
@@ -430,21 +425,46 @@ function combine(filepath, configs, options) {
430
425
  return processMatches(ret, options.version);
431
426
  }
432
427
  /**
433
- * For any pair, a value of `unset` removes the effect of that pair, even if
434
- * it has been set before. This method modifies the properties object in
435
- * place to remove any property that has a value of `unset`.
428
+ * Low-level interface, which exists only for backward-compatibility.
429
+ * Deprecated.
436
430
  *
437
- * @param props Properties object to modify.
431
+ * @param filepath The name of the target file, relative to process.cwd().
432
+ * @param files A list of objects describing the files.
433
+ * @param options All options
434
+ * @returns The properties found for filepath
435
+ * @deprecated
438
436
  */
439
- function unset(props) {
440
- const keys = Object.keys(props);
441
- for (const k of keys) {
442
- if (props[k] === 'unset') {
443
- delete props[k];
437
+ function parseFromFilesSync(filepath, files, options = {}) {
438
+ const [resolvedFilePath, processedOptions] = opts(filepath, options);
439
+ const configs = [];
440
+ for (const ecf of files) {
441
+ let cfg = undefined;
442
+ if (!options.cache || !(cfg = options.cache.get(ecf.name))) { // Single "="!
443
+ cfg = processFileContents(ecf.name, ecf.contents, processedOptions);
444
+ }
445
+ if (!cfg.notfound) {
446
+ configs.push(cfg);
447
+ }
448
+ if (cfg.root) {
449
+ break;
444
450
  }
445
451
  }
452
+ return combine(resolvedFilePath, configs, processedOptions);
453
+ }
454
+ /**
455
+ * Low-level interface, which exists only for backward-compatibility.
456
+ * Deprecated.
457
+ *
458
+ * @param filepath The name of the target file, relative to process.cwd().
459
+ * @param files A promise for a list of objects describing the files.
460
+ * @param options All options
461
+ * @returns The properties found for filepath
462
+ * @deprecated
463
+ */
464
+ async function parseFromFiles(filepath, files, options = {}) {
465
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
466
+ return parseFromFilesSync(filepath, await files, options);
446
467
  }
447
- exports.unset = unset;
448
468
  /**
449
469
  * Find all of the properties from matching sections in config files in the
450
470
  * same directory or toward the root of the filesystem.
@@ -459,7 +479,6 @@ async function parse(filepath, options = {}) {
459
479
  const configs = await getAllConfigs(filepaths, processedOptions);
460
480
  return combine(resolvedFilePath, configs, processedOptions);
461
481
  }
462
- exports.parse = parse;
463
482
  /**
464
483
  * Find all of the properties from matching sections in config files in the
465
484
  * same directory or toward the root of the filesystem. Synchronous.
@@ -474,7 +493,6 @@ function parseSync(filepath, options = {}) {
474
493
  const configs = getAllConfigsSync(filepaths, processedOptions);
475
494
  return combine(resolvedFilePath, configs, processedOptions);
476
495
  }
477
- exports.parseSync = parseSync;
478
496
  /**
479
497
  * I think this may be of limited utility at the moment, but I need something
480
498
  * like this for testing. As such, the interface of this may change without
@@ -489,11 +507,10 @@ exports.parseSync = parseSync;
489
507
  * @private
490
508
  */
491
509
  function matcher(options, ...buffers) {
492
- const processedOptions = opts('', options)[1];
510
+ const [_fileName, processedOptions] = opts('', options);
493
511
  const configs = buffers.map((buf, i) => processFileContents(path.join(processedOptions.root, `buffer-${i}`), buf, processedOptions));
494
512
  return (filepath) => {
495
513
  const resolvedFilePath = path.resolve(filepath);
496
514
  return combine(resolvedFilePath, configs, processedOptions);
497
515
  };
498
516
  }
499
- exports.matcher = matcher;
@@ -0,0 +1 @@
1
+ import 'chai/register-should.js';
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ /* eslint-disable @typescript-eslint/no-deprecated */
37
+ require("chai/register-should.js");
38
+ const editorconfig = __importStar(require("./index.js"));
39
+ const fs = __importStar(require("node:fs"));
40
+ const path = __importStar(require("node:path"));
41
+ const node_buffer_1 = require("node:buffer");
42
+ describe('parse', () => {
43
+ const expected = {
44
+ indent_style: 'space',
45
+ indent_size: 2,
46
+ end_of_line: 'lf',
47
+ charset: 'utf-8',
48
+ trim_trailing_whitespace: true,
49
+ insert_final_newline: true,
50
+ tab_width: 2,
51
+ block_comment: '*',
52
+ block_comment_end: '*/',
53
+ block_comment_start: '/**',
54
+ };
55
+ const target = path.join(__dirname, '/app.js');
56
+ it('async', async () => {
57
+ const cfg = await editorconfig.parse(target);
58
+ cfg.should.eql(expected);
59
+ });
60
+ it('sync', () => {
61
+ const visited = [];
62
+ const cfg = editorconfig.parseSync(target, { files: visited });
63
+ cfg.should.eql(expected);
64
+ visited.should.have.lengthOf(1);
65
+ visited[0].glob.should.eql('*');
66
+ visited[0].fileName.should.match(/\.editorconfig$/);
67
+ });
68
+ it('caches', async () => {
69
+ const cache = new Map();
70
+ const cfg = await editorconfig.parse(target, { cache });
71
+ cfg.should.eql(expected);
72
+ cache.size.should.be.eql(2);
73
+ await editorconfig.parse(target, { cache });
74
+ cache.size.should.be.eql(2);
75
+ });
76
+ it('caches sync', () => {
77
+ const cache = new Map();
78
+ const cfg = editorconfig.parseSync(target, { cache });
79
+ cfg.should.eql(expected);
80
+ cache.size.should.be.eql(2);
81
+ editorconfig.parseSync(target, { cache });
82
+ cache.size.should.be.eql(2);
83
+ });
84
+ });
85
+ describe('parseFromFiles', () => {
86
+ const expected = {
87
+ block_comment_end: '*/',
88
+ block_comment_start: '/**',
89
+ block_comment: '*',
90
+ charset: 'utf-8',
91
+ end_of_line: 'lf',
92
+ indent_size: 2,
93
+ indent_style: 'space',
94
+ insert_final_newline: true,
95
+ tab_width: 2,
96
+ trim_trailing_whitespace: true,
97
+ };
98
+ const configs = [];
99
+ const configPath = path.resolve(__dirname, '../.editorconfig');
100
+ configs.push({
101
+ name: configPath,
102
+ contents: fs.readFileSync(configPath),
103
+ });
104
+ const target = path.join(__dirname, '/app.js');
105
+ const configs2 = [
106
+ { name: 'early', contents: node_buffer_1.Buffer.alloc(0) },
107
+ configs[0],
108
+ ];
109
+ it('async', async () => {
110
+ const cfg = await editorconfig.parseFromFiles(target, Promise.resolve(configs));
111
+ cfg.should.eql(expected);
112
+ });
113
+ it('sync', () => {
114
+ const cfg = editorconfig.parseFromFilesSync(target, configs);
115
+ cfg.should.eql(expected);
116
+ });
117
+ it('handles null', () => {
118
+ const cfg = editorconfig.parseFromFilesSync(target, [{
119
+ name: configPath,
120
+ contents: node_buffer_1.Buffer.from('[*]\nfoo = null\n'),
121
+ }]);
122
+ cfg.should.eql({ foo: 'null' });
123
+ });
124
+ it('caches async', async () => {
125
+ const cache = new Map();
126
+ const cfg = await editorconfig.parseFromFiles(target, Promise.resolve(configs2), { cache });
127
+ cfg.should.eql(expected);
128
+ cache.size.should.be.eql(2);
129
+ const cfg2 = await editorconfig.parseFromFiles(target, Promise.resolve(configs2), { cache });
130
+ cfg2.should.eql(expected);
131
+ cache.size.should.be.eql(2);
132
+ });
133
+ it('caches sync', () => {
134
+ const cache = new Map();
135
+ const cfg = editorconfig.parseFromFilesSync(target, configs2, { cache });
136
+ cfg.should.eql(expected);
137
+ cache.size.should.be.eql(2);
138
+ const cfg2 = editorconfig.parseFromFilesSync(target, configs2, { cache });
139
+ cfg2.should.eql(expected);
140
+ cache.size.should.be.eql(2);
141
+ });
142
+ it('handles minimatch escapables', () => {
143
+ // Note that this `#` does not actually test the /^#/ escaping logic,
144
+ // because this path will go through a `path.dirname` before that happens.
145
+ // It's here to catch what would happen if minimatch started to treat #
146
+ // differently inside a pattern.
147
+ const bogusPath = path.resolve(__dirname, '#?*+@!()|[]{}');
148
+ const escConfigs = [
149
+ {
150
+ name: `${bogusPath}/.editorconfig`,
151
+ contents: configs[0].contents,
152
+ },
153
+ ];
154
+ const escTarget = `${bogusPath}/app.js`;
155
+ const cfg = editorconfig.parseFromFilesSync(escTarget, escConfigs);
156
+ cfg.should.eql(expected);
157
+ });
158
+ });
159
+ describe('parseString', () => {
160
+ const expected = [
161
+ [null, { root: 'true' }],
162
+ ['*', {
163
+ block_comment_end: '*/',
164
+ block_comment_start: '/**',
165
+ block_comment: '*',
166
+ charset: 'utf-8',
167
+ end_of_line: 'lf',
168
+ indent_size: '2',
169
+ indent_style: 'space',
170
+ insert_final_newline: 'true',
171
+ trim_trailing_whitespace: 'true',
172
+ }],
173
+ ['*.md', { indent_size: '4' }],
174
+ ];
175
+ const configPath = path.resolve(__dirname, '../.editorconfig');
176
+ const contents = fs.readFileSync(configPath, 'utf8');
177
+ it('sync', () => {
178
+ const cfg = editorconfig.parseString(contents);
179
+ cfg.should.eql(expected);
180
+ });
181
+ it('handles errors', () => {
182
+ const cfg = editorconfig.parseString('root: ');
183
+ cfg.should.eql([[null, {}]]);
184
+ });
185
+ it('handles backslashes in glob', () => {
186
+ const cfg = editorconfig.parseString('[a\\\\b]');
187
+ cfg.should.eql([[null, {}], ['a\\\\b', {}]]);
188
+ });
189
+ it('handles blank comments', () => {
190
+ const cfg = editorconfig.parseString('#');
191
+ cfg.should.eql([[null, {}]]);
192
+ });
193
+ });
194
+ describe('extra behavior', () => {
195
+ it('handles extended globs', () => {
196
+ // These failed when we had noext: true in matchOptions
197
+ const matcher = editorconfig.matcher({
198
+ root: __dirname,
199
+ }, node_buffer_1.Buffer.from(`\
200
+ [*]
201
+ indent_size = 4
202
+
203
+ [!(package).json]
204
+ indent_size = 3`));
205
+ matcher(path.join(__dirname, 'package.json')).should.include({ indent_size: 4 });
206
+ matcher(path.join(__dirname, 'foo.json')).should.include({ indent_size: 3 });
207
+ });
208
+ });
209
+ describe('unset', () => {
210
+ it('pair witht the value `unset`', () => {
211
+ const matcher = editorconfig.matcher({
212
+ root: __dirname,
213
+ unset: true,
214
+ }, node_buffer_1.Buffer.from(`\
215
+ [*]
216
+ indent_size = 4
217
+
218
+ [*.json]
219
+ indent_size = unset
220
+ `));
221
+ matcher(path.join(__dirname, 'index.js')).should.include({ indent_size: 4 });
222
+ matcher(path.join(__dirname, 'index.json')).should.be.eql({});
223
+ });
224
+ });
package/package.json CHANGED
@@ -1,37 +1,27 @@
1
1
  {
2
2
  "name": "editorconfig",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "EditorConfig File Locator and Interpreter for Node.js",
5
5
  "keywords": [
6
6
  "editorconfig",
7
7
  "core"
8
8
  ],
9
9
  "main": "./lib/index.js",
10
+ "files": [
11
+ "lib/*",
12
+ "bin/*"
13
+ ],
10
14
  "contributors": [
11
15
  "Hong Xu (topbug.net)",
12
16
  "Jed Mao (https://github.com/jedmao/)",
13
17
  "Trey Hunner (http://treyhunner.com)",
14
- "Joe Hildebrand (https://github.com/hildjj/)"
18
+ "Joe Hildebrand (https://github.com/hildjj/)",
19
+ "SunsetTechuila (https://github.com/SunsetTechuila/)"
15
20
  ],
16
21
  "directories": {
17
22
  "bin": "./bin",
18
23
  "lib": "./lib"
19
24
  },
20
- "scripts": {
21
- "clean": "rimraf lib cmake_install.cmake CTestTestfile.cmake Makefile",
22
- "prebuild": "npm run clean",
23
- "build": "cmake . && tsc",
24
- "pretest": "npm run build && npm run lint",
25
- "test": "npm run test:all",
26
- "test:all": "mocha && ctest . --preset Test",
27
- "precoverage": "npm run build -- --inlineSourceMap",
28
- "coverage": "c8 npm run test:all",
29
- "postcoverage": "npm run build",
30
- "ci": "npm run coverage -- -- -VV --output-on-failure",
31
- "lint": "eslint . --ext ts",
32
- "prepub": "npm run lint && npm run build",
33
- "pub": "npm publish"
34
- },
35
25
  "repository": {
36
26
  "type": "git",
37
27
  "url": "git://github.com/editorconfig/editorconfig-core-js.git"
@@ -40,37 +30,12 @@
40
30
  "author": "EditorConfig Team",
41
31
  "license": "MIT",
42
32
  "dependencies": {
43
- "@one-ini/wasm": "0.1.1",
44
- "commander": "^11.0.0",
45
- "minimatch": "9.0.2",
46
- "semver": "^7.5.3"
47
- },
48
- "devDependencies": {
49
- "@types/chai": "4.3.5",
50
- "@types/mocha": "^10.0.1",
51
- "@types/node": "^20.3.3",
52
- "@types/semver": "^7.5.0",
53
- "@typescript-eslint/eslint-plugin": "5.60.1",
54
- "@typescript-eslint/parser": "5.60.1",
55
- "c8": "8.0.0",
56
- "chai": "4.3.7",
57
- "eslint": "8.44.0",
58
- "eslint-plugin-jsdoc": "46.4.3",
59
- "mocha": "^10.2.0",
60
- "rimraf": "^5.0.1",
61
- "typescript": "^5.1.6"
62
- },
63
- "pnpm": {
64
- "overrides": {
65
- "semver": ">=7.5.3",
66
- "word-wrap": "npm:@aashutoshrathi/word-wrap"
67
- }
68
- },
69
- "overrides": {
70
- "semver": "$semver",
71
- "word-wrap": "npm:@aashutoshrathi/word-wrap"
33
+ "@one-ini/wasm": "0.2.0",
34
+ "commander": "^14.0.0",
35
+ "minimatch": "10.0.1",
36
+ "semver": "^7.7.2"
72
37
  },
73
38
  "engines": {
74
- "node": ">=16"
39
+ "node": ">=20"
75
40
  }
76
41
  }