@@ -2,7 +2,7 @@ import type { ParserOptions } from "../common/parser-options"
22import { getLinterRequire } from "./linter-require"
33// @ts -expect-error -- ignore
44import * as dependencyEspree from "espree"
5- import { lte , lt } from "semver"
5+ import { lte , satisfies } from "semver"
66import { createRequire } from "./create-require"
77import path from "path"
88import type { BasicParserObject } from "./parser-object"
@@ -11,73 +11,100 @@ type Espree = BasicParserObject & {
1111 latestEcmaVersion ?: number
1212 version : string
1313}
14- let espreeCache : Espree | null = null
15-
16- /**
17- * Gets the espree that the given ecmaVersion can parse.
18- */
19- export function getEspreeFromEcmaVersion (
20- ecmaVersion : ParserOptions [ "ecmaVersion" ] ,
21- ) : Espree {
22- const linterEspree = getEspreeFromLinter ( )
23- if ( ecmaVersion == null ) {
24- return linterEspree
25- }
26- if ( ecmaVersion === "latest" ) {
27- return getNewestEspree ( )
28- }
29- if (
30- normalizeEcmaVersion ( ecmaVersion ) <= getLatestEcmaVersion ( linterEspree )
31- ) {
32- return linterEspree
33- }
34- const userEspree = getEspreeFromUser ( )
35- if ( normalizeEcmaVersion ( ecmaVersion ) <= getLatestEcmaVersion ( userEspree ) ) {
36- return userEspree
37- }
38- return linterEspree
39- }
4014
4115/**
4216 * Load `espree` from the user dir.
4317 */
44- export function getEspreeFromUser ( ) : Espree {
18+ function getEspreeFromUser ( ) : Espree {
4519 try {
4620 const cwd = process . cwd ( )
4721 const relativeTo = path . join ( cwd , "__placeholder__.js" )
48- return createRequire ( relativeTo ) ( "espree" )
22+ const require = createRequire ( relativeTo )
23+ const espree = getEspreeFromRequireFunction ( require )
24+ if ( espree ) {
25+ if ( espree !== dependencyEspree ) {
26+ return espree
27+ }
28+ // If the user's espree is the same as the parser package's dependency espree,
29+ // it checks whether the user has explicitly installed it.
30+ if ( isExplicitlyInstalledEspree ( require as NodeRequire ) ) {
31+ return espree
32+ }
33+ }
4934 } catch {
50- return getEspreeFromLinter ( )
35+ // ignore
36+ }
37+ return getEspreeFromLinter ( )
38+
39+ function isExplicitlyInstalledEspree ( require : NodeRequire ) : boolean {
40+ try {
41+ const espreeRootPath = path . dirname (
42+ require . resolve ( "espree/package.json" ) ,
43+ )
44+ const nodeModulesPath = path . dirname ( espreeRootPath )
45+ const packageRootPath = path . dirname ( nodeModulesPath )
46+ let pkg
47+ try {
48+ pkg = require ( path . join ( packageRootPath , "package.json" ) )
49+ } catch {
50+ // ignore
51+ }
52+ if ( pkg ) {
53+ return Boolean (
54+ pkg . dependencies ?. espree || pkg . devDependencies ?. espree ,
55+ )
56+ }
57+ } catch {
58+ // ignore
59+ }
60+ // If no package.json is found,
61+ // it is assumed to have been explicitly installed by the user.
62+ return true
5163 }
5264}
5365
5466/**
5567 * Load `espree` from the loaded ESLint.
5668 * If the loaded ESLint was not found, just returns `require("espree")`.
5769 */
58- export function getEspreeFromLinter ( ) : Espree {
59- if ( ! espreeCache ) {
60- espreeCache = getLinterRequire ( ) ?.( "espree" )
61- if ( ! espreeCache ) {
62- espreeCache = dependencyEspree
70+ function getEspreeFromLinter ( ) : Espree {
71+ const require = getLinterRequire ( )
72+ if ( require ) {
73+ const espree = getEspreeFromRequireFunction ( require )
74+ if ( espree ) {
75+ return espree
6376 }
6477 }
78+ return dependencyEspree
79+ }
6580
66- return espreeCache !
81+ /**
82+ * Load `espree` from the given require function.
83+ */
84+ function getEspreeFromRequireFunction (
85+ require : ( name : string ) => any ,
86+ ) : Espree | null {
87+ try {
88+ const pkg = require ( "espree/package.json" )
89+ const supportNodeVersion = pkg . engines ?. node
90+ if (
91+ // If the node version is not supported then espree will not use it.
92+ ! supportNodeVersion ||
93+ satisfies ( process . version , supportNodeVersion )
94+ ) {
95+ return require ( "espree" )
96+ }
97+ } catch {
98+ // ignore
99+ }
100+ return null
67101}
68102
69103/**
70104 * Load the newest `espree` from the loaded ESLint or dependency.
71105 */
72- function getNewestEspree ( ) : Espree {
73- let newest = dependencyEspree
74- const linterEspree = getEspreeFromLinter ( )
75- if (
76- linterEspree . version != null &&
77- lte ( newest . version , linterEspree . version )
78- ) {
79- newest = linterEspree
80- }
106+ export function getNewestEspree ( ) : Espree {
107+ let newest = getEspreeFromLinter ( )
81108 const userEspree = getEspreeFromUser ( )
82109 if ( userEspree . version != null && lte ( newest . version , userEspree . version ) ) {
83110 newest = userEspree
@@ -87,30 +114,20 @@ function getNewestEspree(): Espree {
87114
88115export function getEcmaVersionIfUseEspree (
89116 parserOptions : ParserOptions ,
90- getDefault ?: ( defaultVer : number ) => number ,
91117) : number | undefined {
92118 if ( parserOptions . parser != null && parserOptions . parser !== "espree" ) {
93119 return undefined
94120 }
95121
96- if ( parserOptions . ecmaVersion === "latest" ) {
122+ if (
123+ parserOptions . ecmaVersion === "latest" ||
124+ parserOptions . ecmaVersion == null
125+ ) {
97126 return normalizeEcmaVersion ( getLatestEcmaVersion ( getNewestEspree ( ) ) )
98127 }
99- if ( parserOptions . ecmaVersion == null ) {
100- const defVer = getDefaultEcmaVersion ( )
101- return getDefault ?.( defVer ) ?? defVer
102- }
103128 return normalizeEcmaVersion ( parserOptions . ecmaVersion )
104129}
105130
106- function getDefaultEcmaVersion ( ) : number {
107- if ( lt ( getEspreeFromLinter ( ) . version , "9.0.0" ) ) {
108- return 5
109- }
110- // Perhaps the version 9 will change the default to "latest".
111- return normalizeEcmaVersion ( getLatestEcmaVersion ( getNewestEspree ( ) ) )
112- }
113-
114131/**
115132 * Normalize ECMAScript version
116133 */
0 commit comments