Skip to content

Commit b575cca

Browse files
authored
Downgrade packages that are incompatible with Node v8 (#113)
- Downgrade espree - Downgrade semver - Change the parser so that if the user explicitly installs espree v8 and specifies espree for parserOptions.parser, it will be use.
1 parent 3908b34 commit b575cca

File tree

43 files changed

+235
-115
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+235
-115
lines changed

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
/index.*
77
/npm-debug.log
88
/test.js
9+
/test/fixtures/espree-v8/node_modules

Diff for: package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
"debug": "^4.1.1",
1717
"eslint-scope": "^5.1.1",
1818
"eslint-visitor-keys": "^1.1.0",
19-
"espree": "^8.0.0",
19+
"espree": "^6.2.1",
2020
"esquery": "^1.4.0",
2121
"lodash": "^4.17.21",
22-
"semver": "^7.3.5"
22+
"semver": "^6.3.0"
2323
},
2424
"devDependencies": {
2525
"@mysticatea/eslint-plugin": "^13.0.0",

Diff for: scripts/update-fixtures-ast.js

+14-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const fs = require("fs")
1313
const path = require("path")
1414
const parser = require("../")
1515
const escope = require("eslint-scope")
16+
const semver = require("semver")
1617

1718
//------------------------------------------------------------------------------
1819
// Helpers
@@ -22,7 +23,7 @@ const ROOT = path.join(__dirname, "../test/fixtures/ast")
2223
const TARGETS = fs.readdirSync(ROOT)
2324
const PARSER_OPTIONS = {
2425
comment: true,
25-
ecmaVersion: 2022,
26+
ecmaVersion: 2020,
2627
loc: true,
2728
range: true,
2829
tokens: true,
@@ -201,6 +202,18 @@ function analyze(ast, parserOptions) {
201202
//------------------------------------------------------------------------------
202203

203204
for (const name of TARGETS) {
205+
const requirementsPath = path.join(ROOT, `${name}/requirements.json`)
206+
const requirements = fs.existsSync(requirementsPath)
207+
? JSON.parse(fs.readFileSync(requirementsPath, "utf8"))
208+
: {}
209+
if (
210+
Object.entries(requirements).some(([pkgName, pkgVersion]) => {
211+
const pkg = require(`${pkgName}/package.json`)
212+
return !semver.satisfies(pkg.version, pkgVersion)
213+
})
214+
) {
215+
continue
216+
}
204217
const sourcePath = path.join(ROOT, `${name}/source.vue`)
205218
const optionsPath = path.join(ROOT, `${name}/parser-options.json`)
206219
const astPath = path.join(ROOT, `${name}/ast.json`)

Diff for: src/common/create-require.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Module from "module"
2+
import path from "path"
3+
export const createRequire: (filename: string) => (modname: string) => any =
4+
// Added in v12.2.0
5+
(Module as any).createRequire ||
6+
// Added in v10.12.0, but deprecated in v12.2.0.
7+
// eslint-disable-next-line @mysticatea/node/no-deprecated-api
8+
Module.createRequireFromPath ||
9+
// Polyfill - This is not executed on the tests on node@>=10.
10+
/* istanbul ignore next */
11+
((modname) => {
12+
const mod = new Module(modname)
13+
14+
mod.filename = modname
15+
mod.paths = (Module as any)._nodeModulePaths(path.dirname(modname))
16+
;(mod as any)._compile("module.exports = require;", modname)
17+
return mod.exports
18+
})

Diff for: src/common/espree.ts

+54-39
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import type { ESLintExtendedProgram, ESLintProgram } from "../ast"
22
import type { ParserOptions } from "../common/parser-options"
33
import { getLinterRequire } from "./linter-require"
44
// @ts-expect-error -- ignore
5-
import * as espree from "espree"
5+
import * as dependencyEspree from "espree"
66
import { lte, lt } from "semver"
7+
import { createRequire } from "./create-require"
8+
import path from "path"
79

810
/**
911
* The interface of a result of ESLint custom parser.
@@ -17,66 +19,59 @@ export interface ESLintCustomParser {
1719
parse(code: string, options: any): ESLintCustomParserResult
1820
parseForESLint?(code: string, options: any): ESLintCustomParserResult
1921
}
20-
type OldEspree = ESLintCustomParser & {
21-
latestEcmaVersion?: number
22-
version: string
23-
}
2422
type Espree = ESLintCustomParser & {
25-
latestEcmaVersion: number
23+
latestEcmaVersion?: number
2624
version: string
2725
}
28-
let espreeCache: OldEspree | Espree | null = null
26+
let espreeCache: Espree | null = null
2927

3028
/**
3129
* Gets the espree that the given ecmaVersion can parse.
3230
*/
3331
export function getEspreeFromEcmaVersion(
3432
ecmaVersion: ParserOptions["ecmaVersion"],
35-
): OldEspree | Espree {
33+
): Espree {
3634
const linterEspree = getEspreeFromLinter()
37-
if (
38-
linterEspree.version != null &&
39-
lte(espree.version, linterEspree.version)
40-
) {
41-
// linterEspree is newest
42-
return linterEspree
43-
}
4435
if (ecmaVersion == null) {
4536
return linterEspree
4637
}
4738
if (ecmaVersion === "latest") {
48-
return espree
39+
return getNewestEspree()
4940
}
50-
if (normalizeEcmaVersion(ecmaVersion) <= getLinterLatestEcmaVersion()) {
41+
if (
42+
normalizeEcmaVersion(ecmaVersion) <= getLatestEcmaVersion(linterEspree)
43+
) {
5144
return linterEspree
5245
}
53-
return espree
46+
const userEspree = getEspreeFromUser()
47+
if (normalizeEcmaVersion(ecmaVersion) <= getLatestEcmaVersion(userEspree)) {
48+
return userEspree
49+
}
50+
return linterEspree
51+
}
5452

55-
function getLinterLatestEcmaVersion() {
56-
if (linterEspree.latestEcmaVersion == null) {
57-
for (const { v, latest } of [
58-
{ v: "6.1.0", latest: 2020 },
59-
{ v: "4.0.0", latest: 2019 },
60-
]) {
61-
if (lte(v, linterEspree.version)) {
62-
return latest
63-
}
64-
}
65-
return 2018
66-
}
67-
return normalizeEcmaVersion(linterEspree.latestEcmaVersion)
53+
/**
54+
* Load `espree` from the user dir.
55+
*/
56+
export function getEspreeFromUser(): Espree {
57+
try {
58+
const cwd = process.cwd()
59+
const relativeTo = path.join(cwd, "__placeholder__.js")
60+
return createRequire(relativeTo)("espree")
61+
} catch {
62+
return getEspreeFromLinter()
6863
}
6964
}
7065

7166
/**
7267
* Load `espree` from the loaded ESLint.
7368
* If the loaded ESLint was not found, just returns `require("espree")`.
7469
*/
75-
export function getEspreeFromLinter(): Espree | OldEspree {
70+
export function getEspreeFromLinter(): Espree {
7671
if (!espreeCache) {
7772
espreeCache = getLinterRequire()?.("espree")
7873
if (!espreeCache) {
79-
espreeCache = espree
74+
espreeCache = dependencyEspree
8075
}
8176
}
8277

@@ -87,14 +82,19 @@ export function getEspreeFromLinter(): Espree | OldEspree {
8782
* Load the newest `espree` from the loaded ESLint or dependency.
8883
*/
8984
function getNewestEspree(): Espree {
85+
let newest = dependencyEspree
9086
const linterEspree = getEspreeFromLinter()
9187
if (
92-
linterEspree.version == null ||
93-
lte(linterEspree.version, espree.version)
88+
linterEspree.version != null &&
89+
lte(newest.version, linterEspree.version)
9490
) {
95-
return espree
91+
newest = linterEspree
9692
}
97-
return linterEspree as Espree
93+
const userEspree = getEspreeFromUser()
94+
if (userEspree.version != null && lte(newest.version, userEspree.version)) {
95+
newest = userEspree
96+
}
97+
return newest
9898
}
9999

100100
export function getEcmaVersionIfUseEspree(
@@ -106,7 +106,7 @@ export function getEcmaVersionIfUseEspree(
106106
}
107107

108108
if (parserOptions.ecmaVersion === "latest") {
109-
return normalizeEcmaVersion(getNewestEspree().latestEcmaVersion)
109+
return normalizeEcmaVersion(getLatestEcmaVersion(getNewestEspree()))
110110
}
111111
if (parserOptions.ecmaVersion == null) {
112112
const defVer = getDefaultEcmaVersion()
@@ -120,7 +120,7 @@ function getDefaultEcmaVersion(): number {
120120
return 5
121121
}
122122
// Perhaps the version 9 will change the default to "latest".
123-
return normalizeEcmaVersion(getNewestEspree().latestEcmaVersion)
123+
return normalizeEcmaVersion(getLatestEcmaVersion(getNewestEspree()))
124124
}
125125

126126
/**
@@ -132,3 +132,18 @@ function normalizeEcmaVersion(version: number) {
132132
}
133133
return version
134134
}
135+
136+
function getLatestEcmaVersion(espree: Espree) {
137+
if (espree.latestEcmaVersion == null) {
138+
for (const { v, latest } of [
139+
{ v: "6.1.0", latest: 2020 },
140+
{ v: "4.0.0", latest: 2019 },
141+
]) {
142+
if (lte(v, espree.version)) {
143+
return latest
144+
}
145+
}
146+
return 2018
147+
}
148+
return normalizeEcmaVersion(espree.latestEcmaVersion)
149+
}

Diff for: src/common/linter-require.ts

+1-18
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,5 @@
1-
import Module from "module"
21
import path from "path"
3-
4-
const createRequire: (filename: string) => (modname: string) => any =
5-
// Added in v12.2.0
6-
(Module as any).createRequire ||
7-
// Added in v10.12.0, but deprecated in v12.2.0.
8-
// eslint-disable-next-line @mysticatea/node/no-deprecated-api
9-
Module.createRequireFromPath ||
10-
// Polyfill - This is not executed on the tests on node@>=10.
11-
/* istanbul ignore next */
12-
((modname) => {
13-
const mod = new Module(modname)
14-
15-
mod.filename = modname
16-
mod.paths = (Module as any)._nodeModulePaths(path.dirname(modname))
17-
;(mod as any)._compile("module.exports = require;", modname)
18-
return mod.exports
19-
})
2+
import { createRequire } from "./create-require"
203

214
function isLinterPath(p: string): boolean {
225
return (

Diff for: src/script/index.ts

+12-3
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ import {
4444
} from "./scope-analyzer"
4545
import type { ESLintCustomParser } from "../common/espree"
4646
import {
47-
getEspreeFromEcmaVersion,
4847
getEcmaVersionIfUseEspree,
48+
getEspreeFromUser,
49+
getEspreeFromEcmaVersion,
4950
} from "../common/espree"
5051
import type { ParserOptions } from "../common/parser-options"
5152
import {
@@ -521,6 +522,14 @@ export interface ExpressionParseResult<T extends Node> {
521522
variables: Variable[]
522523
}
523524

525+
function loadParser(parser: string) {
526+
if (parser !== "espree") {
527+
// eslint-disable-next-line @mysticatea/ts/no-require-imports
528+
return require(parser)
529+
}
530+
return getEspreeFromUser()
531+
}
532+
524533
/**
525534
* Parse the given source code.
526535
*
@@ -534,9 +543,9 @@ export function parseScript(
534543
): ESLintExtendedProgram {
535544
const parser: ESLintCustomParser =
536545
typeof parserOptions.parser === "string"
537-
? // eslint-disable-next-line @mysticatea/ts/no-require-imports
538-
require(parserOptions.parser)
546+
? loadParser(parserOptions.parser)
539547
: getEspreeFromEcmaVersion(parserOptions.ecmaVersion)
548+
540549
const result: any =
541550
typeof parser.parseForESLint === "function"
542551
? parser.parseForESLint(code, parserOptions)

Diff for: test/ast.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const ROOT = path.join(__dirname, "fixtures/ast")
2626
const TARGETS = fs.readdirSync(ROOT)
2727
const PARSER_OPTIONS = {
2828
comment: true,
29-
ecmaVersion: 2022,
29+
ecmaVersion: 2020,
3030
loc: true,
3131
range: true,
3232
tokens: true,
@@ -100,7 +100,7 @@ function getTree(source, parserOptions) {
100100
source,
101101
{
102102
parser: PARSER,
103-
parserOptions: Object.assign({ ecmaVersion: 2022 }, parserOptions),
103+
parserOptions: Object.assign({ ecmaVersion: 2020 }, parserOptions),
104104
rules: { maketree: "error" },
105105
},
106106
undefined,

0 commit comments

Comments
 (0)