Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Downgrade packages that are incompatible with Node v8 #113

Merged
merged 1 commit into from
Jul 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
/index.*
/npm-debug.log
/test.js
/test/fixtures/espree-v8/node_modules
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
"debug": "^4.1.1",
"eslint-scope": "^5.1.1",
"eslint-visitor-keys": "^1.1.0",
"espree": "^8.0.0",
"espree": "^6.2.1",
"esquery": "^1.4.0",
"lodash": "^4.17.21",
"semver": "^7.3.5"
"semver": "^6.3.0"
},
"devDependencies": {
"@mysticatea/eslint-plugin": "^13.0.0",
Expand Down
15 changes: 14 additions & 1 deletion scripts/update-fixtures-ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const fs = require("fs")
const path = require("path")
const parser = require("../")
const escope = require("eslint-scope")
const semver = require("semver")

//------------------------------------------------------------------------------
// Helpers
Expand All @@ -22,7 +23,7 @@ const ROOT = path.join(__dirname, "../test/fixtures/ast")
const TARGETS = fs.readdirSync(ROOT)
const PARSER_OPTIONS = {
comment: true,
ecmaVersion: 2022,
ecmaVersion: 2020,
loc: true,
range: true,
tokens: true,
Expand Down Expand Up @@ -201,6 +202,18 @@ function analyze(ast, parserOptions) {
//------------------------------------------------------------------------------

for (const name of TARGETS) {
const requirementsPath = path.join(ROOT, `${name}/requirements.json`)
const requirements = fs.existsSync(requirementsPath)
? JSON.parse(fs.readFileSync(requirementsPath, "utf8"))
: {}
if (
Object.entries(requirements).some(([pkgName, pkgVersion]) => {
const pkg = require(`${pkgName}/package.json`)
return !semver.satisfies(pkg.version, pkgVersion)
})
) {
continue
}
const sourcePath = path.join(ROOT, `${name}/source.vue`)
const optionsPath = path.join(ROOT, `${name}/parser-options.json`)
const astPath = path.join(ROOT, `${name}/ast.json`)
Expand Down
18 changes: 18 additions & 0 deletions src/common/create-require.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Module from "module"
import path from "path"
export const createRequire: (filename: string) => (modname: string) => any =
// Added in v12.2.0
(Module as any).createRequire ||
// Added in v10.12.0, but deprecated in v12.2.0.
// eslint-disable-next-line @mysticatea/node/no-deprecated-api
Module.createRequireFromPath ||
// Polyfill - This is not executed on the tests on node@>=10.
/* istanbul ignore next */
((modname) => {
const mod = new Module(modname)

mod.filename = modname
mod.paths = (Module as any)._nodeModulePaths(path.dirname(modname))
;(mod as any)._compile("module.exports = require;", modname)
return mod.exports
})
93 changes: 54 additions & 39 deletions src/common/espree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import type { ESLintExtendedProgram, ESLintProgram } from "../ast"
import type { ParserOptions } from "../common/parser-options"
import { getLinterRequire } from "./linter-require"
// @ts-expect-error -- ignore
import * as espree from "espree"
import * as dependencyEspree from "espree"
import { lte, lt } from "semver"
import { createRequire } from "./create-require"
import path from "path"

/**
* The interface of a result of ESLint custom parser.
Expand All @@ -17,66 +19,59 @@ export interface ESLintCustomParser {
parse(code: string, options: any): ESLintCustomParserResult
parseForESLint?(code: string, options: any): ESLintCustomParserResult
}
type OldEspree = ESLintCustomParser & {
latestEcmaVersion?: number
version: string
}
type Espree = ESLintCustomParser & {
latestEcmaVersion: number
latestEcmaVersion?: number
version: string
}
let espreeCache: OldEspree | Espree | null = null
let espreeCache: Espree | null = null

/**
* Gets the espree that the given ecmaVersion can parse.
*/
export function getEspreeFromEcmaVersion(
ecmaVersion: ParserOptions["ecmaVersion"],
): OldEspree | Espree {
): Espree {
const linterEspree = getEspreeFromLinter()
if (
linterEspree.version != null &&
lte(espree.version, linterEspree.version)
) {
// linterEspree is newest
return linterEspree
}
if (ecmaVersion == null) {
return linterEspree
}
if (ecmaVersion === "latest") {
return espree
return getNewestEspree()
}
if (normalizeEcmaVersion(ecmaVersion) <= getLinterLatestEcmaVersion()) {
if (
normalizeEcmaVersion(ecmaVersion) <= getLatestEcmaVersion(linterEspree)
) {
return linterEspree
}
return espree
const userEspree = getEspreeFromUser()
if (normalizeEcmaVersion(ecmaVersion) <= getLatestEcmaVersion(userEspree)) {
return userEspree
}
return linterEspree
}

function getLinterLatestEcmaVersion() {
if (linterEspree.latestEcmaVersion == null) {
for (const { v, latest } of [
{ v: "6.1.0", latest: 2020 },
{ v: "4.0.0", latest: 2019 },
]) {
if (lte(v, linterEspree.version)) {
return latest
}
}
return 2018
}
return normalizeEcmaVersion(linterEspree.latestEcmaVersion)
/**
* Load `espree` from the user dir.
*/
export function getEspreeFromUser(): Espree {
try {
const cwd = process.cwd()
const relativeTo = path.join(cwd, "__placeholder__.js")
return createRequire(relativeTo)("espree")
} catch {
return getEspreeFromLinter()
}
}

/**
* Load `espree` from the loaded ESLint.
* If the loaded ESLint was not found, just returns `require("espree")`.
*/
export function getEspreeFromLinter(): Espree | OldEspree {
export function getEspreeFromLinter(): Espree {
if (!espreeCache) {
espreeCache = getLinterRequire()?.("espree")
if (!espreeCache) {
espreeCache = espree
espreeCache = dependencyEspree
}
}

Expand All @@ -87,14 +82,19 @@ export function getEspreeFromLinter(): Espree | OldEspree {
* Load the newest `espree` from the loaded ESLint or dependency.
*/
function getNewestEspree(): Espree {
let newest = dependencyEspree
const linterEspree = getEspreeFromLinter()
if (
linterEspree.version == null ||
lte(linterEspree.version, espree.version)
linterEspree.version != null &&
lte(newest.version, linterEspree.version)
) {
return espree
newest = linterEspree
}
return linterEspree as Espree
const userEspree = getEspreeFromUser()
if (userEspree.version != null && lte(newest.version, userEspree.version)) {
newest = userEspree
}
return newest
}

export function getEcmaVersionIfUseEspree(
Expand All @@ -106,7 +106,7 @@ export function getEcmaVersionIfUseEspree(
}

if (parserOptions.ecmaVersion === "latest") {
return normalizeEcmaVersion(getNewestEspree().latestEcmaVersion)
return normalizeEcmaVersion(getLatestEcmaVersion(getNewestEspree()))
}
if (parserOptions.ecmaVersion == null) {
const defVer = getDefaultEcmaVersion()
Expand All @@ -120,7 +120,7 @@ function getDefaultEcmaVersion(): number {
return 5
}
// Perhaps the version 9 will change the default to "latest".
return normalizeEcmaVersion(getNewestEspree().latestEcmaVersion)
return normalizeEcmaVersion(getLatestEcmaVersion(getNewestEspree()))
}

/**
Expand All @@ -132,3 +132,18 @@ function normalizeEcmaVersion(version: number) {
}
return version
}

function getLatestEcmaVersion(espree: Espree) {
if (espree.latestEcmaVersion == null) {
for (const { v, latest } of [
{ v: "6.1.0", latest: 2020 },
{ v: "4.0.0", latest: 2019 },
]) {
if (lte(v, espree.version)) {
return latest
}
}
return 2018
}
return normalizeEcmaVersion(espree.latestEcmaVersion)
}
19 changes: 1 addition & 18 deletions src/common/linter-require.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,5 @@
import Module from "module"
import path from "path"

const createRequire: (filename: string) => (modname: string) => any =
// Added in v12.2.0
(Module as any).createRequire ||
// Added in v10.12.0, but deprecated in v12.2.0.
// eslint-disable-next-line @mysticatea/node/no-deprecated-api
Module.createRequireFromPath ||
// Polyfill - This is not executed on the tests on node@>=10.
/* istanbul ignore next */
((modname) => {
const mod = new Module(modname)

mod.filename = modname
mod.paths = (Module as any)._nodeModulePaths(path.dirname(modname))
;(mod as any)._compile("module.exports = require;", modname)
return mod.exports
})
import { createRequire } from "./create-require"

function isLinterPath(p: string): boolean {
return (
Expand Down
15 changes: 12 additions & 3 deletions src/script/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ import {
} from "./scope-analyzer"
import type { ESLintCustomParser } from "../common/espree"
import {
getEspreeFromEcmaVersion,
getEcmaVersionIfUseEspree,
getEspreeFromUser,
getEspreeFromEcmaVersion,
} from "../common/espree"
import type { ParserOptions } from "../common/parser-options"
import {
Expand Down Expand Up @@ -521,6 +522,14 @@ export interface ExpressionParseResult<T extends Node> {
variables: Variable[]
}

function loadParser(parser: string) {
if (parser !== "espree") {
// eslint-disable-next-line @mysticatea/ts/no-require-imports
return require(parser)
}
return getEspreeFromUser()
}

/**
* Parse the given source code.
*
Expand All @@ -534,9 +543,9 @@ export function parseScript(
): ESLintExtendedProgram {
const parser: ESLintCustomParser =
typeof parserOptions.parser === "string"
? // eslint-disable-next-line @mysticatea/ts/no-require-imports
require(parserOptions.parser)
? loadParser(parserOptions.parser)
: getEspreeFromEcmaVersion(parserOptions.ecmaVersion)

const result: any =
typeof parser.parseForESLint === "function"
? parser.parseForESLint(code, parserOptions)
Expand Down
4 changes: 2 additions & 2 deletions test/ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const ROOT = path.join(__dirname, "fixtures/ast")
const TARGETS = fs.readdirSync(ROOT)
const PARSER_OPTIONS = {
comment: true,
ecmaVersion: 2022,
ecmaVersion: 2020,
loc: true,
range: true,
tokens: true,
Expand Down Expand Up @@ -100,7 +100,7 @@ function getTree(source, parserOptions) {
source,
{
parser: PARSER,
parserOptions: Object.assign({ ecmaVersion: 2022 }, parserOptions),
parserOptions: Object.assign({ ecmaVersion: 2020 }, parserOptions),
rules: { maketree: "error" },
},
undefined,
Expand Down
Loading