Skip to content

Commit 3f6a7c8

Browse files
Merge pull request #2466 from ember-cli/add-editor-config-utils
Add editor config utils
2 parents 901865f + 053f6a3 commit 3f6a7c8

4 files changed

Lines changed: 183 additions & 0 deletions

File tree

lib/utils/editorconfig.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use strict';
2+
3+
const editorconfig = require('editorconfig');
4+
5+
/**
6+
* Resolve editorconfig properties for a given file path using the official
7+
* editorconfig library.
8+
*
9+
* Returns an object like `{ indent_size: 4, indent_style: 'space', ... }`
10+
* with only the properties that matched. Returns an empty object if no
11+
* .editorconfig is found or no sections match.
12+
*/
13+
function resolveEditorConfig(filePath) {
14+
return editorconfig.parseSync(filePath);
15+
}
16+
17+
module.exports = { resolveEditorConfig };

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"dependencies": {
6262
"@ember-data/rfc395-data": "^0.0.4",
6363
"css-tree": "^3.0.1",
64+
"editorconfig": "^3.0.2",
6465
"ember-eslint-parser": "^0.6.0",
6566
"ember-rfc176-data": "^0.3.18",
6667
"eslint-utils": "^3.0.0",

pnpm-lock.yaml

Lines changed: 55 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
'use strict';
2+
3+
const fs = require('fs');
4+
const path = require('path');
5+
const os = require('os');
6+
const { resolveEditorConfig } = require('../../../lib/utils/editorconfig');
7+
8+
describe('resolveEditorConfig', () => {
9+
let tmpDir;
10+
11+
beforeEach(() => {
12+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'editorconfig-test-'));
13+
});
14+
15+
afterEach(() => {
16+
fs.rmSync(tmpDir, { recursive: true, force: true });
17+
});
18+
19+
it('returns empty object when no .editorconfig exists', () => {
20+
const filePath = path.join(tmpDir, 'test.hbs');
21+
const result = resolveEditorConfig(filePath);
22+
expect(result).toEqual({});
23+
});
24+
25+
it('reads indent_size from .editorconfig', () => {
26+
fs.writeFileSync(
27+
path.join(tmpDir, '.editorconfig'),
28+
['root = true', '', '[*]', 'indent_size = 4'].join('\n')
29+
);
30+
const filePath = path.join(tmpDir, 'test.hbs');
31+
const result = resolveEditorConfig(filePath);
32+
expect(result.indent_size).toBe(4);
33+
});
34+
35+
it('matches *.hbs sections', () => {
36+
fs.writeFileSync(
37+
path.join(tmpDir, '.editorconfig'),
38+
['root = true', '', '[*.hbs]', 'indent_size = 3'].join('\n')
39+
);
40+
const filePath = path.join(tmpDir, 'test.hbs');
41+
const result = resolveEditorConfig(filePath);
42+
expect(result.indent_size).toBe(3);
43+
});
44+
45+
it('does not match non-matching glob', () => {
46+
fs.writeFileSync(
47+
path.join(tmpDir, '.editorconfig'),
48+
['root = true', '', '[*.js]', 'indent_size = 4'].join('\n')
49+
);
50+
const filePath = path.join(tmpDir, 'test.hbs');
51+
const result = resolveEditorConfig(filePath);
52+
expect(result.indent_size).toBeUndefined();
53+
});
54+
55+
it('handles brace expansion *.{hbs,gjs}', () => {
56+
fs.writeFileSync(
57+
path.join(tmpDir, '.editorconfig'),
58+
['root = true', '', '[*.{hbs,gjs}]', 'indent_size = 6'].join('\n')
59+
);
60+
expect(resolveEditorConfig(path.join(tmpDir, 'test.hbs')).indent_size).toBe(6);
61+
expect(resolveEditorConfig(path.join(tmpDir, 'test.gjs')).indent_size).toBe(6);
62+
expect(resolveEditorConfig(path.join(tmpDir, 'test.js')).indent_size).toBeUndefined();
63+
});
64+
65+
it('later sections override earlier ones', () => {
66+
fs.writeFileSync(
67+
path.join(tmpDir, '.editorconfig'),
68+
['root = true', '', '[*]', 'indent_size = 2', '', '[*.hbs]', 'indent_size = 4'].join('\n')
69+
);
70+
const filePath = path.join(tmpDir, 'test.hbs');
71+
const result = resolveEditorConfig(filePath);
72+
expect(result.indent_size).toBe(4);
73+
});
74+
75+
it('inner .editorconfig overrides outer', () => {
76+
// outer
77+
fs.writeFileSync(
78+
path.join(tmpDir, '.editorconfig'),
79+
['root = true', '', '[*]', 'indent_size = 2'].join('\n')
80+
);
81+
// inner dir
82+
const innerDir = path.join(tmpDir, 'app');
83+
fs.mkdirSync(innerDir);
84+
fs.writeFileSync(path.join(innerDir, '.editorconfig'), ['[*]', 'indent_size = 4'].join('\n'));
85+
const filePath = path.join(innerDir, 'test.hbs');
86+
const result = resolveEditorConfig(filePath);
87+
expect(result.indent_size).toBe(4);
88+
});
89+
90+
it('sets indent_size to tab when indent_style is tab and indent_size unset', () => {
91+
fs.writeFileSync(
92+
path.join(tmpDir, '.editorconfig'),
93+
['root = true', '', '[*]', 'indent_style = tab'].join('\n')
94+
);
95+
const filePath = path.join(tmpDir, 'test.hbs');
96+
const result = resolveEditorConfig(filePath);
97+
expect(result.indent_style).toBe('tab');
98+
expect(result.indent_size).toBe('tab');
99+
});
100+
101+
it('ignores comments', () => {
102+
fs.writeFileSync(
103+
path.join(tmpDir, '.editorconfig'),
104+
['root = true', '# a comment', '; another comment', '[*]', 'indent_size = 5'].join('\n')
105+
);
106+
const filePath = path.join(tmpDir, 'test.hbs');
107+
const result = resolveEditorConfig(filePath);
108+
expect(result.indent_size).toBe(5);
109+
});
110+
});

0 commit comments

Comments
 (0)