Skip to content

Commit 972f828

Browse files
committed
✨ no-unsupported-features/node-builtins recognize backporting
Fixes #192 Closes #194
1 parent 276a9ad commit 972f828

File tree

3 files changed

+170
-65
lines changed

3 files changed

+170
-65
lines changed

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

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const trackMap = {
2323
modules: {
2424
assert: {
2525
strict: {
26-
[READ]: { supported: "9.9.0" },
26+
[READ]: { supported: "9.9.0", backported: ["8.13.0"] },
2727
doesNotReject: { [READ]: { supported: "10.0.0" } },
2828
rejects: { [READ]: { supported: "10.0.0" } },
2929
},
@@ -51,9 +51,11 @@ const trackMap = {
5151
ChildProcess: { [READ]: { supported: "2.2.0" } },
5252
},
5353
console: {
54-
clear: { [READ]: { supported: "8.3.0" } },
55-
count: { [READ]: { supported: "8.3.0" } },
56-
countReset: { [READ]: { supported: "8.3.0" } },
54+
clear: { [READ]: { supported: "8.3.0", backported: ["6.13.0"] } },
55+
count: { [READ]: { supported: "8.3.0", backported: ["6.13.0"] } },
56+
countReset: {
57+
[READ]: { supported: "8.3.0", backported: ["6.13.0"] },
58+
},
5759
debug: { [READ]: { supported: "8.0.0" } },
5860
dirxml: { [READ]: { supported: "8.0.0" } },
5961
group: { [READ]: { supported: "8.5.0" } },
@@ -74,6 +76,7 @@ const trackMap = {
7476
exportPublicKey: { [READ]: { supported: "9.0.0" } },
7577
verifySpkac: { [READ]: { supported: "9.0.0" } },
7678
},
79+
ECDH: { [READ]: { supported: "8.8.0", backported: ["6.13.0"] } },
7780
KeyObject: { [READ]: { supported: "11.6.0" } },
7881
createPrivateKey: { [READ]: { supported: "11.6.0" } },
7982
createPublicKey: { [READ]: { supported: "11.6.0" } },
@@ -86,8 +89,12 @@ const trackMap = {
8689
getFips: { [READ]: { supported: "10.0.0" } },
8790
privateEncrypt: { [READ]: { supported: "1.1.0" } },
8891
publicDecrypt: { [READ]: { supported: "1.1.0" } },
89-
randomFillSync: { [READ]: { supported: "7.10.0" } },
90-
randomFill: { [READ]: { supported: "7.10.0" } },
92+
randomFillSync: {
93+
[READ]: { supported: "7.10.0", backported: ["6.13.0"] },
94+
},
95+
randomFill: {
96+
[READ]: { supported: "7.10.0", backported: ["6.13.0"] },
97+
},
9198
scrypt: { [READ]: { supported: "10.5.0" } },
9299
scryptSync: { [READ]: { supported: "10.5.0" } },
93100
setFips: { [READ]: { supported: "10.0.0" } },
@@ -99,14 +106,20 @@ const trackMap = {
99106
Resolver: { [READ]: { supported: "8.3.0" } },
100107
resolvePtr: { [READ]: { supported: "6.0.0" } },
101108
promises: {
102-
[READ]: { supported: "11.14.0", experimental: "10.6.0" },
109+
[READ]: {
110+
supported: "11.14.0",
111+
backported: ["10.17.0"],
112+
experimental: "10.6.0",
113+
},
103114
},
104115
},
105116
events: {
106117
EventEmitter: {
107-
once: { [READ]: { supported: "11.13.0" } },
118+
once: {
119+
[READ]: { supported: "11.13.0", backported: ["10.16.0"] },
120+
},
108121
},
109-
once: { [READ]: { supported: "11.13.0" } },
122+
once: { [READ]: { supported: "11.13.0", backported: ["10.16.0"] } },
110123
},
111124
fs: {
112125
Dirent: { [READ]: { supported: "10.10.0" } },
@@ -121,25 +134,43 @@ const trackMap = {
121134
native: { [READ]: { supported: "9.2.0" } },
122135
},
123136
promises: {
124-
[READ]: { supported: "11.14.0", experimental: "10.1.0" },
137+
[READ]: {
138+
supported: "11.14.0",
139+
backported: ["10.17.0"],
140+
experimental: "10.1.0",
141+
},
125142
},
126143
writev: { [READ]: { supported: "12.9.0" } },
127144
writevSync: { [READ]: { supported: "12.9.0" } },
128145
},
129146
http2: {
130-
[READ]: { supported: "10.10.0", experimental: "8.4.0" },
147+
[READ]: {
148+
supported: "10.10.0",
149+
backported: ["8.13.0"],
150+
experimental: "8.4.0",
151+
},
131152
},
132153
inspector: {
133154
[READ]: { supported: null, experimental: "8.0.0" },
134155
},
135156
module: {
136157
Module: {
137-
builtinModules: { [READ]: { supported: "9.3.0" } },
158+
builtinModules: {
159+
[READ]: {
160+
supported: "9.3.0",
161+
backported: ["6.13.0", "8.10.0"],
162+
},
163+
},
138164
createRequireFromPath: { [READ]: { supported: "10.12.0" } },
139165
createRequire: { [READ]: { supported: "12.2.0" } },
140166
syncBuiltinESMExports: { [READ]: { supported: "12.12.0" } },
141167
},
142-
builtinModules: { [READ]: { supported: "9.3.0" } },
168+
builtinModules: {
169+
[READ]: {
170+
supported: "9.3.0",
171+
backported: ["6.13.0", "8.10.0"],
172+
},
173+
},
143174
createRequireFromPath: { [READ]: { supported: "10.12.0" } },
144175
createRequire: { [READ]: { supported: "12.2.0" } },
145176
syncBuiltinESMExports: { [READ]: { supported: "12.12.0" } },
@@ -175,7 +206,12 @@ const trackMap = {
175206
hrtime: {
176207
bigint: { [READ]: { supported: "10.7.0" } },
177208
},
178-
ppid: { [READ]: { supported: "9.2.0" } },
209+
ppid: {
210+
[READ]: {
211+
supported: "9.2.0",
212+
backported: ["6.13.0", "8.10.0"],
213+
},
214+
},
179215
release: { [READ]: { supported: "3.0.0" } },
180216
report: { [READ]: { supported: null, experimental: "11.8.0" } },
181217
resourceUsage: { [READ]: { supported: "12.6.0" } },
@@ -195,7 +231,9 @@ const trackMap = {
195231
},
196232
stream: {
197233
Readable: {
198-
from: { [READ]: { supported: "12.3.0" } },
234+
from: {
235+
[READ]: { supported: "12.3.0", backported: ["10.17.0"] },
236+
},
199237
},
200238
finished: { [READ]: { supported: "10.0.0" } },
201239
pipeline: { [READ]: { supported: "10.0.0" } },
@@ -204,24 +242,32 @@ const trackMap = {
204242
[READ]: { supported: "10.0.0" },
205243
},
206244
url: {
207-
URL: { [READ]: { supported: "7.0.0" } },
208-
URLSearchParams: { [READ]: { supported: "7.5.0" } },
245+
URL: { [READ]: { supported: "7.0.0", backported: ["6.13.0"] } },
246+
URLSearchParams: {
247+
[READ]: { supported: "7.5.0", backported: ["6.13.0"] },
248+
},
209249
domainToASCII: { [READ]: { supported: "7.4.0" } },
210250
domainToUnicode: { [READ]: { supported: "7.4.0" } },
211251
},
212252
util: {
213253
callbackify: { [READ]: { supported: "8.2.0" } },
214254
formatWithOptions: { [READ]: { supported: "10.0.0" } },
215-
getSystemErrorName: { [READ]: { supported: "9.7.0" } },
255+
getSystemErrorName: {
256+
[READ]: { supported: "9.7.0", backported: ["8.12.0"] },
257+
},
216258
inspect: {
217259
custom: { [READ]: { supported: "6.6.0" } },
218260
defaultOptions: { [READ]: { supported: "6.4.0" } },
219261
replDefaults: { [READ]: { supported: "11.12.0" } },
220262
},
221263
isDeepStrictEqual: { [READ]: { supported: "9.0.0" } },
222264
promisify: { [READ]: { supported: "8.0.0" } },
223-
TextDecoder: { [READ]: { supported: "8.3.0" } },
224-
TextEncoder: { [READ]: { supported: "8.3.0" } },
265+
TextDecoder: {
266+
[READ]: { supported: "8.9.0", experimental: "8.3.0" },
267+
},
268+
TextEncoder: {
269+
[READ]: { supported: "8.9.0", experimental: "8.3.0" },
270+
},
225271
types: {
226272
[READ]: { supported: "10.0.0" },
227273
isBoxedPrimitive: { [READ]: { supported: "10.11.0" } },

lib/util/check-unsupported-builtins.js

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,18 @@
44
*/
55
"use strict"
66

7-
const { Range } = require("semver") //eslint-disable-line no-unused-vars
7+
const { Range, lt, major } = require("semver") //eslint-disable-line no-unused-vars
88
const { ReferenceTracker } = require("eslint-utils")
99
const getConfiguredNodeVersion = require("./get-configured-node-version")
1010
const getSemverRange = require("./get-semver-range")
1111

12+
/**
13+
* @typedef {Object} SupportInfo
14+
* @property {string | null} supported The stably supported version. If `null` is present, it hasn't been supported yet.
15+
* @property {string[]} [backported] The backported versions.
16+
* @property {string} [experimental] The added version as experimental.
17+
*/
18+
1219
/**
1320
* Parses the options.
1421
* @param {RuleContext} context The rule context.
@@ -23,6 +30,50 @@ function parseOptions(context) {
2330
return Object.freeze({ version, ignores })
2431
}
2532

33+
/**
34+
* Check if it has been supported.
35+
* @param {SupportInfo} info The support info.
36+
* @param {Range} configured The configured version range.
37+
*/
38+
function isSupported({ backported, supported }, configured) {
39+
if (
40+
backported &&
41+
backported.length >= 2 &&
42+
!backported.every((v, i) => i === 0 || lt(backported[i - 1], v))
43+
) {
44+
throw new Error("Invalid BackportConfiguration")
45+
}
46+
47+
if (supported == null) {
48+
return false
49+
}
50+
if (backported == null || backported.length === 0) {
51+
return !configured.intersects(getSemverRange(`<${supported}`))
52+
}
53+
54+
return !configured.intersects(
55+
getSemverRange(
56+
[...backported, supported]
57+
.map((v, i) => (i === 0 ? `<${v}` : `>=${major(v)}.0.0 <${v}`))
58+
.join(" || ")
59+
)
60+
)
61+
}
62+
63+
/**
64+
* Get the formatted text of a given supported version.
65+
* @param {SupportInfo} info The support info.
66+
*/
67+
function supportedVersionToString({ backported, supported }) {
68+
if (supported == null) {
69+
return "(none yet)"
70+
}
71+
if (backported == null || backported.length === 0) {
72+
return supported
73+
}
74+
return `${supported} (backported: ^${backported.join(", ^")})`
75+
}
76+
2677
/**
2778
* Verify the code to report unsupported APIs.
2879
* @param {RuleContext} context The rule context.
@@ -40,17 +91,15 @@ module.exports = function checkUnsupportedBuiltins(context, trackMap) {
4091

4192
for (const { node, path, info } of references) {
4293
const name = path.join(".")
43-
const supported =
44-
Boolean(info.supported) &&
45-
!options.version.intersects(getSemverRange(`<${info.supported}`))
94+
const supported = isSupported(info, options.version)
4695

4796
if (!supported && !options.ignores.has(name)) {
4897
context.report({
4998
node,
5099
messageId: "unsupported",
51100
data: {
52101
name,
53-
supported: info.supported || "???",
102+
supported: supportedVersionToString(info),
54103
version: options.version.raw,
55104
},
56105
})

0 commit comments

Comments
 (0)