ember-eslint-parser 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/package.json +3 -3
- package/src/parser/gjs-gts-parser.js +11 -132
- package/src/parser/ts-patch.js +10 -12
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ember-eslint-parser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "git
|
|
8
|
+
"url": "git+https://github.com/ember-tooling/ember-eslint-parser.git"
|
|
9
9
|
},
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"author": "",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"vitest": "^1.2.2"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"@babel/eslint-parser": "^7.28.6",
|
|
58
|
+
"@babel/eslint-parser": "^7.28.6 || ^8.0.0",
|
|
59
59
|
"@typescript-eslint/parser": "*"
|
|
60
60
|
},
|
|
61
61
|
"peerDependenciesMeta": {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
|
-
import tsconfigUtils from '@typescript-eslint/tsconfig-utils';
|
|
3
2
|
import { registerParsedFile } from '../preprocessor/noop.js';
|
|
4
3
|
import { patchTs, replaceExtensions, syncMtsGtsSourceFiles, typescriptParser } from './ts-patch.js';
|
|
5
4
|
import { buildGlimmerVisitors } from './transforms.js';
|
|
@@ -13,15 +12,20 @@ const require = createRequire(import.meta.url);
|
|
|
13
12
|
// peer (TS-only setups don't need it), so a missing dep yields null and the JS
|
|
14
13
|
// path below emits a targeted error.
|
|
15
14
|
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
// is being parsed.
|
|
15
|
+
// Matches the parser ember-cli wires up for plain `.js` files in JS-only
|
|
16
|
+
// apps, so config discovery (decorators & friends) lines up with how the
|
|
17
|
+
// rest of the project is being parsed.
|
|
20
18
|
let babelParser = null;
|
|
21
19
|
try {
|
|
20
|
+
// @babel/eslint-parser < 8
|
|
22
21
|
babelParser = require('@babel/eslint-parser/experimental-worker');
|
|
23
22
|
} catch {
|
|
24
|
-
|
|
23
|
+
try {
|
|
24
|
+
// @babel/eslint-parser >= 8
|
|
25
|
+
babelParser = require('@babel/eslint-parser');
|
|
26
|
+
} catch {
|
|
27
|
+
// optional peer; left null
|
|
28
|
+
}
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
/**
|
|
@@ -35,115 +39,6 @@ try {
|
|
|
35
39
|
* a second AST traversal.
|
|
36
40
|
*/
|
|
37
41
|
|
|
38
|
-
/**
|
|
39
|
-
* @param {string} tsconfigPath
|
|
40
|
-
* @param {string} rootDir
|
|
41
|
-
* @returns {boolean|undefined}
|
|
42
|
-
*/
|
|
43
|
-
function parseAllowJsFromTsconfig(tsconfigPath, rootDir) {
|
|
44
|
-
try {
|
|
45
|
-
const parserPath = require.resolve('@typescript-eslint/parser');
|
|
46
|
-
// eslint-disable-next-line n/no-unpublished-require
|
|
47
|
-
const tsPath = require.resolve('typescript', { paths: [parserPath] });
|
|
48
|
-
const ts = require(tsPath);
|
|
49
|
-
const parsed = tsconfigUtils.getParsedConfigFile(ts, tsconfigPath, rootDir);
|
|
50
|
-
return parsed?.options?.allowJs;
|
|
51
|
-
} catch (e) {
|
|
52
|
-
// eslint-disable-next-line no-console
|
|
53
|
-
console.warn('[ember-eslint-parser] Failed to parse tsconfig:', tsconfigPath, e);
|
|
54
|
-
return undefined;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* @param {Array<boolean|undefined>} values
|
|
60
|
-
* @param {string} source
|
|
61
|
-
* @returns {boolean|null}
|
|
62
|
-
*/
|
|
63
|
-
function resolveAllowJs(values, source) {
|
|
64
|
-
const filtered = values.filter((val) => typeof val !== 'undefined');
|
|
65
|
-
if (filtered.length > 0) {
|
|
66
|
-
const uniqueValues = [...new Set(filtered)];
|
|
67
|
-
if (uniqueValues.length > 1) {
|
|
68
|
-
// eslint-disable-next-line no-console
|
|
69
|
-
console.warn(
|
|
70
|
-
`[ember-eslint-parser] Conflicting allowJs values in ${source}. Defaulting allowGjs to false.`
|
|
71
|
-
);
|
|
72
|
-
return false;
|
|
73
|
-
} else {
|
|
74
|
-
return uniqueValues[0];
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* @param {Array<{getCompilerOptions?: Function}>|undefined} programs
|
|
82
|
-
* @returns {boolean|null}
|
|
83
|
-
*/
|
|
84
|
-
function getAllowJsFromPrograms(programs) {
|
|
85
|
-
if (!Array.isArray(programs) || programs.length === 0) return null;
|
|
86
|
-
const allowJsValues = programs
|
|
87
|
-
.map((p) => p.getCompilerOptions?.())
|
|
88
|
-
.filter(Boolean)
|
|
89
|
-
.map((opts) => opts.allowJs);
|
|
90
|
-
return resolveAllowJs(allowJsValues, 'programs');
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* @param {boolean|object|undefined} projectService
|
|
95
|
-
* @returns {string|null}
|
|
96
|
-
*/
|
|
97
|
-
function getProjectServiceTsconfigPath(projectService) {
|
|
98
|
-
if (!projectService) return null;
|
|
99
|
-
|
|
100
|
-
if (projectService === true) {
|
|
101
|
-
return 'tsconfig.json';
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (typeof projectService === 'object') {
|
|
105
|
-
if (typeof projectService.allowDefaultProject !== 'undefined') {
|
|
106
|
-
// eslint-disable-next-line no-console
|
|
107
|
-
console.warn(
|
|
108
|
-
'[ember-eslint-parser] projectService.allowDefaultProject is specified. Behavior may differ depending on default project config.'
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
return projectService.defaultProject ?? 'tsconfig.json';
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return null;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Returns the resolved allowJs value based on priority: programs > projectService > project/tsconfig
|
|
119
|
-
*/
|
|
120
|
-
function getAllowJs(options) {
|
|
121
|
-
const allowJsFromPrograms = getAllowJsFromPrograms(options.programs);
|
|
122
|
-
if (allowJsFromPrograms !== null) return allowJsFromPrograms;
|
|
123
|
-
|
|
124
|
-
const rootDir = options.tsconfigRootDir || process.cwd();
|
|
125
|
-
|
|
126
|
-
const projectServiceTsconfigPath = getProjectServiceTsconfigPath(options.projectService);
|
|
127
|
-
if (projectServiceTsconfigPath) {
|
|
128
|
-
return parseAllowJsFromTsconfig(projectServiceTsconfigPath, rootDir);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
let tsconfigPaths = [];
|
|
132
|
-
if (Array.isArray(options.project)) {
|
|
133
|
-
tsconfigPaths = options.project;
|
|
134
|
-
} else if (typeof options.project === 'string') {
|
|
135
|
-
tsconfigPaths = [options.project];
|
|
136
|
-
} else if (options.project) {
|
|
137
|
-
tsconfigPaths = ['tsconfig.json'];
|
|
138
|
-
}
|
|
139
|
-
if (tsconfigPaths.length > 0) {
|
|
140
|
-
const allowJsValues = tsconfigPaths.map((cfg) => parseAllowJsFromTsconfig(cfg, rootDir));
|
|
141
|
-
return resolveAllowJs(allowJsValues, 'project');
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
42
|
/**
|
|
148
43
|
* @type {import('eslint').ParserModule}
|
|
149
44
|
*/
|
|
@@ -153,12 +48,9 @@ export const meta = {
|
|
|
153
48
|
};
|
|
154
49
|
|
|
155
50
|
export function parseForESLint(code, options) {
|
|
156
|
-
const allowGjsWasSet = options.allowGjs !== undefined;
|
|
157
|
-
const allowGjs = allowGjsWasSet ? options.allowGjs : getAllowJs(options);
|
|
158
|
-
let actualAllowGjs;
|
|
159
51
|
// Only patch TypeScript if we actually need it.
|
|
160
52
|
if (options.programs || options.projectService || options.project) {
|
|
161
|
-
|
|
53
|
+
patchTs();
|
|
162
54
|
}
|
|
163
55
|
registerParsedFile(options.filePath);
|
|
164
56
|
|
|
@@ -260,19 +152,6 @@ export function parseForESLint(code, options) {
|
|
|
260
152
|
}
|
|
261
153
|
|
|
262
154
|
if (result.services?.program) {
|
|
263
|
-
const programAllowJs = result.services.program.getCompilerOptions?.()?.allowJs;
|
|
264
|
-
if (
|
|
265
|
-
!allowGjsWasSet &&
|
|
266
|
-
programAllowJs !== undefined &&
|
|
267
|
-
actualAllowGjs !== undefined &&
|
|
268
|
-
actualAllowGjs !== programAllowJs
|
|
269
|
-
) {
|
|
270
|
-
// eslint-disable-next-line no-console
|
|
271
|
-
console.warn(
|
|
272
|
-
'[ember-eslint-parser] allowJs does not match the actual program. Consider setting allowGjs explicitly.\n' +
|
|
273
|
-
` Current: ${allowGjs}, Program: ${programAllowJs}`
|
|
274
|
-
);
|
|
275
|
-
}
|
|
276
155
|
syncMtsGtsSourceFiles(result.services.program);
|
|
277
156
|
}
|
|
278
157
|
|
package/src/parser/ts-patch.js
CHANGED
|
@@ -4,7 +4,7 @@ import { transformForLint, replaceRange } from './transforms.js';
|
|
|
4
4
|
|
|
5
5
|
const require = createRequire(import.meta.url);
|
|
6
6
|
|
|
7
|
-
let patchTs, replaceExtensions, syncMtsGtsSourceFiles, typescriptParser, isPatched
|
|
7
|
+
let patchTs, replaceExtensions, syncMtsGtsSourceFiles, typescriptParser, isPatched;
|
|
8
8
|
|
|
9
9
|
try {
|
|
10
10
|
const parserPath = require.resolve('@typescript-eslint/parser');
|
|
@@ -12,10 +12,9 @@ try {
|
|
|
12
12
|
const tsPath = require.resolve('typescript', { paths: [parserPath] });
|
|
13
13
|
const ts = require(tsPath);
|
|
14
14
|
typescriptParser = require('@typescript-eslint/parser');
|
|
15
|
-
patchTs = function patchTs(
|
|
16
|
-
if (isPatched) return
|
|
15
|
+
patchTs = function patchTs() {
|
|
16
|
+
if (isPatched) return;
|
|
17
17
|
isPatched = true;
|
|
18
|
-
allowGjs = options.allowGjs !== undefined ? options.allowGjs : true;
|
|
19
18
|
const sys = { ...ts.sys };
|
|
20
19
|
const newSys = {
|
|
21
20
|
...ts.sys,
|
|
@@ -24,14 +23,14 @@ try {
|
|
|
24
23
|
const gtsVirtuals = results
|
|
25
24
|
.filter((x) => x.endsWith('.gts'))
|
|
26
25
|
.map((f) => f.replace(/\.gts$/, '.mts'));
|
|
27
|
-
const gjsVirtuals =
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
const gjsVirtuals = results
|
|
27
|
+
.filter((x) => x.endsWith('.gjs'))
|
|
28
|
+
.map((f) => f.replace(/\.gjs$/, '.mjs'));
|
|
30
29
|
return results.concat(gtsVirtuals, gjsVirtuals);
|
|
31
30
|
},
|
|
32
31
|
fileExists(fileName) {
|
|
33
32
|
const gtsExists = fs.existsSync(fileName.replace(/\.m?ts$/, '.gts'));
|
|
34
|
-
const gjsExists =
|
|
33
|
+
const gjsExists = fs.existsSync(fileName.replace(/\.m?js$/, '.gjs'));
|
|
35
34
|
return gtsExists || gjsExists || fs.existsSync(fileName);
|
|
36
35
|
},
|
|
37
36
|
readFile(fname) {
|
|
@@ -46,12 +45,12 @@ try {
|
|
|
46
45
|
} catch {
|
|
47
46
|
if (fileName.match(/\.m?ts$/)) {
|
|
48
47
|
fileName = fileName.replace(/\.m?ts$/, '.gts');
|
|
49
|
-
} else if (
|
|
48
|
+
} else if (fileName.match(/\.m?js$/)) {
|
|
50
49
|
fileName = fileName.replace(/\.m?js$/, '.gjs');
|
|
51
50
|
}
|
|
52
51
|
content = fs.readFileSync(fileName).toString();
|
|
53
52
|
}
|
|
54
|
-
if (fileName.endsWith('.gts') ||
|
|
53
|
+
if (fileName.endsWith('.gts') || fileName.endsWith('.gjs')) {
|
|
55
54
|
try {
|
|
56
55
|
content = transformForLint(content).output;
|
|
57
56
|
} catch (e) {
|
|
@@ -62,7 +61,7 @@ try {
|
|
|
62
61
|
if (
|
|
63
62
|
(!fileName.endsWith('.d.ts') && fileName.endsWith('.ts')) ||
|
|
64
63
|
fileName.endsWith('.gts') ||
|
|
65
|
-
|
|
64
|
+
fileName.endsWith('.gjs')
|
|
66
65
|
) {
|
|
67
66
|
try {
|
|
68
67
|
content = replaceExtensions(content);
|
|
@@ -75,7 +74,6 @@ try {
|
|
|
75
74
|
},
|
|
76
75
|
};
|
|
77
76
|
ts.setSys(newSys);
|
|
78
|
-
return { allowGjs };
|
|
79
77
|
};
|
|
80
78
|
|
|
81
79
|
replaceExtensions = function replaceExtensions(code) {
|