editorconfig 2.0.1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
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,7 +106,7 @@ 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;
66
112
  /**
@@ -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
@@ -54,12 +54,13 @@ const package_json_1 = __importDefault(require("../package.json"));
54
54
  const escapedSep = new RegExp(path.sep.replace(/\\/g, '\\\\'), 'g');
55
55
  const matchOptions = { matchBase: true, dot: true };
56
56
  const knownPropNames = [
57
+ 'charset',
57
58
  'end_of_line',
58
- 'indent_style',
59
59
  'indent_size',
60
+ 'indent_style',
60
61
  'insert_final_newline',
62
+ // 'tab_width' // This should be an integer, not a string.
61
63
  'trim_trailing_whitespace',
62
- 'charset',
63
64
  ];
64
65
  const knownProps = new Set(knownPropNames);
65
66
  /**
@@ -103,7 +104,7 @@ function parseBuffer(data) {
103
104
  *
104
105
  * @param data String to parse.
105
106
  * @returns Parsed contents. Will be truncated if there was a parse error.
106
- * @deprecated Use {@link ParseBuffer} instead.
107
+ * @deprecated Use {@link parseBuffer} instead.
107
108
  */
108
109
  function parseString(data) {
109
110
  return parseBuffer(node_buffer_1.Buffer.from(data));
@@ -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,17 +1,22 @@
1
1
  {
2
2
  "name": "editorconfig",
3
- "version": "2.0.1",
3
+ "version": "3.0.1",
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",
@@ -26,11 +31,11 @@
26
31
  "license": "MIT",
27
32
  "dependencies": {
28
33
  "@one-ini/wasm": "0.2.0",
29
- "commander": "^13.1.0",
34
+ "commander": "^14.0.0",
30
35
  "minimatch": "10.0.1",
31
- "semver": "^7.7.1"
36
+ "semver": "^7.7.2"
32
37
  },
33
38
  "engines": {
34
- "node": ">=18"
39
+ "node": ">=20"
35
40
  }
36
41
  }
package/eslint.config.mjs DELETED
@@ -1,13 +0,0 @@
1
- import base from '@cto.af/eslint-config';
2
- import ts from '@cto.af/eslint-config/ts.js';
3
-
4
- export default [
5
- {
6
- ignores: [
7
- 'lib/**',
8
- '**/*.d.ts',
9
- ],
10
- },
11
- ...base,
12
- ...ts,
13
- ];