Skip to content

Commit 76fc219

Browse files
authored
feat(node-builtin): Add support for import.meta properties (#420)
1 parent 9ae39fb commit 76fc219

File tree

7 files changed

+228
-15
lines changed

7 files changed

+228
-15
lines changed

lib/eslint-utils.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ declare module "@eslint-community/eslint-utils" {
2424
iterateGlobalReferences<Info extends unknown>(traceMap: TraceMap<Info>): IterableIterator<Reference<Info>>;
2525
iterateCjsReferences<Info extends unknown>(traceMap: TraceMap<Info>): IterableIterator<Reference<Info>>;
2626
iterateEsmReferences<Info extends unknown>(traceMap: TraceMap<Info>): IterableIterator<Reference<Info>>;
27+
iteratePropertyReferences<Info extends unknown>(node: estree.Expression, traceMap: TraceMap<Info>): IterableIterator<Reference<Info>>;
2728
}
2829
export namespace ReferenceTracker {
2930
export { READ };

lib/rules/no-unsupported-features/node-builtins.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,20 @@
44
*/
55
"use strict"
66

7+
const { ReferenceTracker } = require("@eslint-community/eslint-utils")
78
const {
89
checkUnsupportedBuiltins,
10+
checkUnsupportedBuiltinReferences,
911
messages,
1012
} = require("../../util/check-unsupported-builtins")
1113
const enumeratePropertyNames = require("../../util/enumerate-property-names")
1214
const getConfiguredNodeVersion = require("../../util/get-configured-node-version")
15+
const { getSourceCode } = require("../../util/eslint-compat")
1316

1417
const {
1518
NodeBuiltinGlobals,
1619
NodeBuiltinModules,
20+
NodeBuiltinImportMeta,
1721
} = require("../../unsupported-features/node-builtins.js")
1822

1923
const traceMap = {
@@ -45,6 +49,11 @@ module.exports = {
4549
new Set([
4650
...enumeratePropertyNames(traceMap.globals),
4751
...enumeratePropertyNames(traceMap.modules),
52+
...[
53+
...enumeratePropertyNames(
54+
NodeBuiltinImportMeta
55+
),
56+
].map(s => `import.meta.${s}`),
4857
])
4958
),
5059
},
@@ -57,10 +66,37 @@ module.exports = {
5766
messages,
5867
},
5968
create(context) {
69+
const sourceCode = getSourceCode(context)
70+
const tracker = new ReferenceTracker(
71+
/** @type {NonNullable<typeof sourceCode.scopeManager.globalScope>} */ (
72+
sourceCode.scopeManager.globalScope
73+
)
74+
)
6075
return {
6176
"Program:exit"() {
6277
checkUnsupportedBuiltins(context, traceMap)
6378
},
79+
"MetaProperty:exit"(node) {
80+
if (
81+
node.meta.name !== "import" ||
82+
node.property.name !== "meta"
83+
) {
84+
return
85+
}
86+
87+
const references = [
88+
...tracker.iteratePropertyReferences(
89+
node,
90+
NodeBuiltinImportMeta
91+
),
92+
].map(reference => {
93+
return {
94+
...reference,
95+
path: ["import.meta", ...reference.path],
96+
}
97+
})
98+
checkUnsupportedBuiltinReferences(context, references)
99+
},
64100
}
65101
},
66102
}

lib/unsupported-features/node-builtins.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"use strict"
22

33
const NodeBuiltinGlobals = require("./node-globals.js")
4+
const NodeBuiltinImportMeta = require("./node-import-meta.js")
45

56
/**
67
* @type {import('./types.js').SupportVersionTraceMap}
@@ -50,4 +51,8 @@ const NodeBuiltinModules = {
5051
...require("./node-builtins-modules/zlib.js"),
5152
}
5253

53-
module.exports = { NodeBuiltinGlobals, NodeBuiltinModules }
54+
module.exports = {
55+
NodeBuiltinGlobals,
56+
NodeBuiltinModules,
57+
NodeBuiltinImportMeta,
58+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"use strict"
2+
3+
const { READ } = require("@eslint-community/eslint-utils")
4+
5+
/**
6+
* @type {import('./types.js').SupportVersionTraceMap}
7+
*/
8+
const importMeta = {
9+
resolve: {
10+
[READ]: {
11+
supported: ["18.19.0", "20.6.0"],
12+
experimental: ["12.16.2", "13.9.0"],
13+
},
14+
},
15+
dirname: {
16+
[READ]: {
17+
supported: ["21.2.0", "20.11.0"],
18+
},
19+
},
20+
filename: {
21+
[READ]: {
22+
supported: ["21.2.0", "20.11.0"],
23+
},
24+
},
25+
}
26+
27+
module.exports = importMeta

lib/util/check-unsupported-builtins.js

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,23 +80,13 @@ function versionsToString(versions) {
8080
}
8181

8282
/**
83-
* Verify the code to report unsupported APIs.
83+
* Verify the code to report unsupported API references.
8484
* @param {import('eslint').Rule.RuleContext} context The rule context.
85-
* @param {import('../unsupported-features/types.js').SupportVersionBuiltins} traceMap The map for APIs to report.
85+
* @param {import("@eslint-community/eslint-utils").Reference<import("../unsupported-features/types.js").SupportInfo>[]} references The references for APIs to report.
8686
* @returns {void}
8787
*/
88-
module.exports.checkUnsupportedBuiltins = function checkUnsupportedBuiltins(
89-
context,
90-
traceMap
91-
) {
88+
function checkUnsupportedBuiltinReferences(context, references) {
9289
const options = parseOptions(context)
93-
const scope = getScope(context)
94-
const tracker = new ReferenceTracker(scope, { mode: "legacy" })
95-
const references = [
96-
...tracker.iterateCjsReferences(traceMap.modules ?? {}),
97-
...tracker.iterateEsmReferences(traceMap.modules ?? {}),
98-
...tracker.iterateGlobalReferences(traceMap.globals ?? {}),
99-
]
10090

10191
for (const { node, path, info } of references) {
10292
const name = unprefixNodeColon(path.join("."))
@@ -154,6 +144,30 @@ module.exports.checkUnsupportedBuiltins = function checkUnsupportedBuiltins(
154144
}
155145
}
156146

147+
/**
148+
* Verify the code to report unsupported APIs.
149+
* @param {import('eslint').Rule.RuleContext} context The rule context.
150+
* @param {import('../unsupported-features/types.js').SupportVersionBuiltins} traceMap The map for APIs to report.
151+
* @returns {void}
152+
*/
153+
module.exports.checkUnsupportedBuiltins = function checkUnsupportedBuiltins(
154+
context,
155+
traceMap
156+
) {
157+
const scope = getScope(context)
158+
const tracker = new ReferenceTracker(scope, { mode: "legacy" })
159+
const references = [
160+
...tracker.iterateCjsReferences(traceMap.modules ?? {}),
161+
...tracker.iterateEsmReferences(traceMap.modules ?? {}),
162+
...tracker.iterateGlobalReferences(traceMap.globals ?? {}),
163+
]
164+
165+
checkUnsupportedBuiltinReferences(context, references)
166+
}
167+
168+
module.exports.checkUnsupportedBuiltinReferences =
169+
checkUnsupportedBuiltinReferences
170+
157171
exports.messages = {
158172
"not-experimental-till": [
159173
"The '{{name}}' is not an experimental feature",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"eslint": ">=8.23.0"
1818
},
1919
"dependencies": {
20-
"@eslint-community/eslint-utils": "^4.4.1",
20+
"@eslint-community/eslint-utils": "^4.5.0",
2121
"enhanced-resolve": "^5.17.1",
2222
"eslint-plugin-es-x": "^7.8.0",
2323
"get-tsconfig": "^4.8.1",

tests/lib/rules/no-unsupported-features/node-builtins.js

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5458,6 +5458,136 @@ new RuleTester({ languageOptions: { sourceType: "module" } }).run(
54585458
],
54595459
},
54605460

5461+
//----------------------------------------------------------------------
5462+
// import.meta
5463+
//----------------------------------------------------------------------
5464+
{
5465+
valid: [
5466+
...[
5467+
{ version: "22.0.0" },
5468+
{ version: "20.6.0" },
5469+
{ version: "18.19.0" },
5470+
{ version: "13.9.0", allowExperimental: true },
5471+
{ version: "12.16.2", allowExperimental: true },
5472+
{ version: "18.18.0", ignores: ["import.meta.resolve"] },
5473+
].map(option => {
5474+
return {
5475+
code: "import.meta.resolve(specifier)",
5476+
options: [option],
5477+
languageOptions: { ecmaVersion: "latest" },
5478+
}
5479+
}),
5480+
...[
5481+
{ version: "22.0.0" },
5482+
{ version: "21.2.0" },
5483+
{ version: "20.11.0" },
5484+
{ version: "20.10.0", ignores: ["import.meta.dirname"] },
5485+
].map(option => {
5486+
return {
5487+
code: "import.meta.dirname;",
5488+
options: [option],
5489+
languageOptions: { ecmaVersion: "latest" },
5490+
}
5491+
}),
5492+
...[
5493+
{ version: "22.0.0" },
5494+
{ version: "21.2.0" },
5495+
{ version: "20.11.0" },
5496+
{ version: "20.10.0", ignores: ["import.meta.filename"] },
5497+
].map(option => {
5498+
return {
5499+
code: "import.meta.filename;",
5500+
options: [option],
5501+
languageOptions: { ecmaVersion: "latest" },
5502+
}
5503+
}),
5504+
],
5505+
invalid: [
5506+
...[
5507+
{ version: "20.5.0" },
5508+
{ version: "19.8.1" },
5509+
{ version: "18.18.0" },
5510+
].map(option => {
5511+
return {
5512+
code: "import.meta.resolve(specifier)",
5513+
options: [option],
5514+
languageOptions: { ecmaVersion: "latest" },
5515+
errors: [
5516+
{
5517+
messageId: "not-supported-till",
5518+
data: {
5519+
name: "import.meta.resolve",
5520+
supported: "20.6.0 (backported: ^18.19.0)",
5521+
version: option.version,
5522+
},
5523+
},
5524+
],
5525+
}
5526+
}),
5527+
...[
5528+
{ version: "13.8.0", allowExperimental: true },
5529+
{ version: "12.15.0", allowExperimental: true },
5530+
].map(option => {
5531+
return {
5532+
code: "import.meta.resolve(specifier)",
5533+
options: [option],
5534+
languageOptions: { ecmaVersion: "latest" },
5535+
errors: [
5536+
{
5537+
messageId: "not-experimental-till",
5538+
data: {
5539+
name: "import.meta.resolve",
5540+
experimental:
5541+
"13.9.0 (backported: ^12.16.2)",
5542+
version: option.version,
5543+
},
5544+
},
5545+
],
5546+
}
5547+
}),
5548+
...[{ version: "21.1.0" }, { version: "20.10.0" }].map(
5549+
option => {
5550+
return {
5551+
code: "import.meta.dirname;",
5552+
options: [option],
5553+
languageOptions: { ecmaVersion: "latest" },
5554+
errors: [
5555+
{
5556+
messageId: "not-supported-till",
5557+
data: {
5558+
name: "import.meta.dirname",
5559+
supported:
5560+
"21.2.0 (backported: ^20.11.0)",
5561+
version: option.version,
5562+
},
5563+
},
5564+
],
5565+
}
5566+
}
5567+
),
5568+
...[{ version: "21.1.0" }, { version: "20.10.0" }].map(
5569+
option => {
5570+
return {
5571+
code: "import.meta.filename;",
5572+
options: [option],
5573+
languageOptions: { ecmaVersion: "latest" },
5574+
errors: [
5575+
{
5576+
messageId: "not-supported-till",
5577+
data: {
5578+
name: "import.meta.filename",
5579+
supported:
5580+
"21.2.0 (backported: ^20.11.0)",
5581+
version: option.version,
5582+
},
5583+
},
5584+
],
5585+
}
5586+
}
5587+
),
5588+
],
5589+
},
5590+
54615591
{
54625592
valid: [
54635593
{

0 commit comments

Comments
 (0)