@openrewrite/rewrite 8.91.3 → 8.91.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/javascript/parser.d.ts +3 -2
- package/dist/javascript/parser.d.ts.map +1 -1
- package/dist/javascript/parser.js +154 -114
- package/dist/javascript/parser.js.map +1 -1
- package/dist/javascript/tsconfig.d.ts +32 -0
- package/dist/javascript/tsconfig.d.ts.map +1 -0
- package/dist/javascript/tsconfig.js +205 -0
- package/dist/javascript/tsconfig.js.map +1 -0
- package/dist/rewrite-javascript-version.txt +1 -1
- package/package.json +1 -1
- package/src/javascript/parser.ts +104 -58
- package/src/javascript/tsconfig.ts +177 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
export interface ResolvedTsConfig {
|
|
3
|
+
/**
|
|
4
|
+
* Absolute path of the config file the options came from. Undefined when no project
|
|
5
|
+
* config applied, in which case {@link options} are the parser's defaults.
|
|
6
|
+
*/
|
|
7
|
+
readonly configFilePath?: string;
|
|
8
|
+
readonly options: ts.CompilerOptions;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Finds the config file governing each file and merges its resolution options over a set of
|
|
12
|
+
* parser defaults, so that type-aware recipes see the same modules `tsc` would.
|
|
13
|
+
*/
|
|
14
|
+
export declare class TsConfigResolver {
|
|
15
|
+
private readonly defaults;
|
|
16
|
+
private readonly configByDir;
|
|
17
|
+
private readonly optionsByConfig;
|
|
18
|
+
private readonly root?;
|
|
19
|
+
/**
|
|
20
|
+
* @param defaults Options to fall back on, and to merge a project config over.
|
|
21
|
+
* @param relativeTo Root of the project being parsed, bounding the search. Without one,
|
|
22
|
+
* walking up from the process working directory picks up whatever config sits above it.
|
|
23
|
+
*/
|
|
24
|
+
constructor(defaults: ts.CompilerOptions, relativeTo?: string);
|
|
25
|
+
forFile(filePath: string): ResolvedTsConfig;
|
|
26
|
+
/** The nearest config file at or below the project root, searching upwards. */
|
|
27
|
+
private findConfig;
|
|
28
|
+
private optionsFor;
|
|
29
|
+
/** Undefined where the config cannot be read, leaving the caller on its defaults. */
|
|
30
|
+
private merge;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=tsconfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tsconfig.d.ts","sourceRoot":"","sources":["../../src/javascript/tsconfig.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,MAAM,YAAY,CAAC;AA+B5B,MAAM,WAAW,gBAAgB;IAC7B;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,eAAe,CAAC;CACxC;AAED;;;GAGG;AACH,qBAAa,gBAAgB;IAUb,OAAO,CAAC,QAAQ,CAAC,QAAQ;IATrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyC;IACrE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAqD;IACrF,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAS;IAE/B;;;;OAIG;gBAC0B,QAAQ,EAAE,EAAE,CAAC,eAAe,EAAE,UAAU,CAAC,EAAE,MAAM;IAI9E,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB;IAM3C,+EAA+E;IAC/E,OAAO,CAAC,UAAU;IA+BlB,OAAO,CAAC,UAAU;IAOlB,qFAAqF;IACrF,OAAO,CAAC,KAAK;CAmChB"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
36
|
+
var t = {};
|
|
37
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
38
|
+
t[p] = s[p];
|
|
39
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
40
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
41
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
42
|
+
t[p[i]] = s[p[i]];
|
|
43
|
+
}
|
|
44
|
+
return t;
|
|
45
|
+
};
|
|
46
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
47
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
48
|
+
};
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.TsConfigResolver = void 0;
|
|
51
|
+
/*
|
|
52
|
+
* Copyright 2025 the original author or authors.
|
|
53
|
+
* <p>
|
|
54
|
+
* Licensed under the Moderne Source Available License (the "License");
|
|
55
|
+
* you may not use this file except in compliance with the License.
|
|
56
|
+
* You may obtain a copy of the License at
|
|
57
|
+
* <p>
|
|
58
|
+
* https://docs.moderne.io/licensing/moderne-source-available-license
|
|
59
|
+
* <p>
|
|
60
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
61
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
62
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
63
|
+
* See the License for the specific language governing permissions and
|
|
64
|
+
* limitations under the License.
|
|
65
|
+
*/
|
|
66
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
67
|
+
const path = __importStar(require("path"));
|
|
68
|
+
/**
|
|
69
|
+
* What a project gets to decide: where a module specifier resolves to, and which ambient
|
|
70
|
+
* declarations are in scope. The shape of the types themselves stays with the parser — `target`
|
|
71
|
+
* and `lib` bound the global scope, `strict` adds a `null` to every nullable type — which pins
|
|
72
|
+
* the widest view it can rather than the one a project compiles against.
|
|
73
|
+
*/
|
|
74
|
+
const RESOLUTION_OPTIONS = [
|
|
75
|
+
"baseUrl",
|
|
76
|
+
"paths",
|
|
77
|
+
// Internal companion to `paths`: the directory its entries resolve against.
|
|
78
|
+
"pathsBasePath",
|
|
79
|
+
"rootDirs",
|
|
80
|
+
"types",
|
|
81
|
+
"typeRoots",
|
|
82
|
+
"moduleResolution",
|
|
83
|
+
"moduleSuffixes",
|
|
84
|
+
"customConditions",
|
|
85
|
+
"resolvePackageJsonExports",
|
|
86
|
+
"resolvePackageJsonImports",
|
|
87
|
+
"resolveJsonModule",
|
|
88
|
+
];
|
|
89
|
+
/**
|
|
90
|
+
* Config file names in precedence order. TypeScript reads jsconfig.json for JavaScript
|
|
91
|
+
* projects, which is where a JS-only codebase states its `paths`.
|
|
92
|
+
*/
|
|
93
|
+
const CONFIG_FILE_NAMES = ["tsconfig.json", "jsconfig.json"];
|
|
94
|
+
/**
|
|
95
|
+
* Finds the config file governing each file and merges its resolution options over a set of
|
|
96
|
+
* parser defaults, so that type-aware recipes see the same modules `tsc` would.
|
|
97
|
+
*/
|
|
98
|
+
class TsConfigResolver {
|
|
99
|
+
/**
|
|
100
|
+
* @param defaults Options to fall back on, and to merge a project config over.
|
|
101
|
+
* @param relativeTo Root of the project being parsed, bounding the search. Without one,
|
|
102
|
+
* walking up from the process working directory picks up whatever config sits above it.
|
|
103
|
+
*/
|
|
104
|
+
constructor(defaults, relativeTo) {
|
|
105
|
+
this.defaults = defaults;
|
|
106
|
+
this.configByDir = new Map();
|
|
107
|
+
this.optionsByConfig = new Map();
|
|
108
|
+
this.root = relativeTo ? path.resolve(relativeTo) : undefined;
|
|
109
|
+
}
|
|
110
|
+
forFile(filePath) {
|
|
111
|
+
const configFilePath = this.findConfig(path.dirname(path.resolve(filePath)));
|
|
112
|
+
const options = configFilePath === undefined ? undefined : this.optionsFor(configFilePath);
|
|
113
|
+
return options === undefined ? { options: this.defaults } : { configFilePath, options };
|
|
114
|
+
}
|
|
115
|
+
/** The nearest config file at or below the project root, searching upwards. */
|
|
116
|
+
findConfig(from) {
|
|
117
|
+
if (!this.root || !isAtOrUnder(from, this.root)) {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
const searched = [];
|
|
121
|
+
const memoize = (found) => {
|
|
122
|
+
for (const dir of searched) {
|
|
123
|
+
this.configByDir.set(dir, found);
|
|
124
|
+
}
|
|
125
|
+
return found;
|
|
126
|
+
};
|
|
127
|
+
for (let dir = from;; dir = path.dirname(dir)) {
|
|
128
|
+
if (this.configByDir.has(dir)) {
|
|
129
|
+
return memoize(this.configByDir.get(dir));
|
|
130
|
+
}
|
|
131
|
+
searched.push(dir);
|
|
132
|
+
for (const configFileName of CONFIG_FILE_NAMES) {
|
|
133
|
+
const candidate = path.join(dir, configFileName);
|
|
134
|
+
if (typescript_1.default.sys.fileExists(candidate)) {
|
|
135
|
+
return memoize(candidate);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (dir === this.root || path.dirname(dir) === dir) {
|
|
139
|
+
return memoize(undefined);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
optionsFor(configFilePath) {
|
|
144
|
+
if (!this.optionsByConfig.has(configFilePath)) {
|
|
145
|
+
this.optionsByConfig.set(configFilePath, this.merge(configFilePath));
|
|
146
|
+
}
|
|
147
|
+
return this.optionsByConfig.get(configFilePath);
|
|
148
|
+
}
|
|
149
|
+
/** Undefined where the config cannot be read, leaving the caller on its defaults. */
|
|
150
|
+
merge(configFilePath) {
|
|
151
|
+
let projectOptions;
|
|
152
|
+
try {
|
|
153
|
+
const { config, error } = typescript_1.default.readConfigFile(configFilePath, typescript_1.default.sys.readFile);
|
|
154
|
+
if (error || !config) {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
// `readDirectory` answers empty because only `options` is read here; left to `ts.sys` it
|
|
158
|
+
// walks the whole tree under the config to build a file list, once per config found.
|
|
159
|
+
const parseConfigHost = Object.assign(Object.assign({}, typescript_1.default.sys), { readDirectory: () => [] });
|
|
160
|
+
projectOptions = typescript_1.default.parseJsonConfigFileContent(config, parseConfigHost, path.dirname(configFilePath), undefined, configFilePath).options;
|
|
161
|
+
}
|
|
162
|
+
catch (_a) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
// A project's `baseUrl` stands alone, including where it states none: `baseUrl` takes
|
|
166
|
+
// precedence over `pathsBasePath`, so a default rooted at the repository would resolve a
|
|
167
|
+
// nested project's `paths` against the wrong directory.
|
|
168
|
+
const _b = this.defaults, { baseUrl: _ } = _b, defaults = __rest(_b, ["baseUrl"]);
|
|
169
|
+
const resolution = {};
|
|
170
|
+
for (const option of RESOLUTION_OPTIONS) {
|
|
171
|
+
if (projectOptions[option] !== undefined) {
|
|
172
|
+
resolution[option] = projectOptions[option];
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (resolution.moduleResolution === undefined) {
|
|
176
|
+
const paired = pairedModuleResolution(projectOptions);
|
|
177
|
+
if (paired !== undefined) {
|
|
178
|
+
resolution.moduleResolution = paired;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return Object.assign(Object.assign({}, defaults), resolution);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
exports.TsConfigResolver = TsConfigResolver;
|
|
185
|
+
/**
|
|
186
|
+
* The resolution TypeScript infers for a project that states only its `module`. Only the
|
|
187
|
+
* inference is adopted, since a module kind such as `node16` classifies files as CJS or ESM,
|
|
188
|
+
* and an ESM-only import from a CJS file is then the error TS1479, costing the file its LST.
|
|
189
|
+
* `Classic` is declined as well, searching no `node_modules`, so the default stands in.
|
|
190
|
+
*/
|
|
191
|
+
function pairedModuleResolution(projectOptions) {
|
|
192
|
+
const infer = typescript_1.default
|
|
193
|
+
.getEmitModuleResolutionKind;
|
|
194
|
+
if (projectOptions.module === undefined || !infer) {
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
const inferred = infer(projectOptions);
|
|
198
|
+
return inferred === typescript_1.default.ModuleResolutionKind.Classic ? undefined : inferred;
|
|
199
|
+
}
|
|
200
|
+
function isAtOrUnder(dir, root) {
|
|
201
|
+
const relative = path.relative(root, dir);
|
|
202
|
+
return relative === "" ||
|
|
203
|
+
(relative !== ".." && !relative.startsWith(".." + path.sep) && !path.isAbsolute(relative));
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=tsconfig.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tsconfig.js","sourceRoot":"","sources":["../../src/javascript/tsconfig.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
8.91.
|
|
1
|
+
8.91.4
|
package/package.json
CHANGED
package/src/javascript/parser.ts
CHANGED
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
TextSpan
|
|
47
47
|
} from "./parser-utils";
|
|
48
48
|
import {JavaScriptTypeMapping} from "./type-mapping";
|
|
49
|
+
import {TsConfigResolver} from "./tsconfig";
|
|
49
50
|
import {create as produce} from "mutative";
|
|
50
51
|
import ComputedPropertyName = JS.ComputedPropertyName;
|
|
51
52
|
import Attribute = JSX.Attribute;
|
|
@@ -90,9 +91,9 @@ type WithInvalidSyntaxSlots<T> = T & {
|
|
|
90
91
|
|
|
91
92
|
export class JavaScriptParser extends Parser {
|
|
92
93
|
|
|
93
|
-
private readonly
|
|
94
|
+
private readonly tsConfig: TsConfigResolver;
|
|
94
95
|
private readonly styles?: NamedStyles[];
|
|
95
|
-
private
|
|
96
|
+
private readonly oldPrograms = new Map<string, ts.Program>();
|
|
96
97
|
private readonly sourceFileCache?: Map<string, ts.SourceFile>;
|
|
97
98
|
|
|
98
99
|
constructor(
|
|
@@ -105,7 +106,7 @@ export class JavaScriptParser extends Parser {
|
|
|
105
106
|
}: JavaScriptParserOptions = {},
|
|
106
107
|
) {
|
|
107
108
|
super({ctx, relativeTo});
|
|
108
|
-
|
|
109
|
+
const defaultCompilerOptions: ts.CompilerOptions = {
|
|
109
110
|
target: ts.ScriptTarget.Latest,
|
|
110
111
|
// Bundler matches `exports` conditions leniently, so packages that publish types only under
|
|
111
112
|
// an `import` condition resolve; it pairs with `preserve`, which `commonjs` cannot (TS5095).
|
|
@@ -132,6 +133,7 @@ export class JavaScriptParser extends Parser {
|
|
|
132
133
|
types: types ?? ["*"],
|
|
133
134
|
baseUrl: relativeTo || process.cwd()
|
|
134
135
|
};
|
|
136
|
+
this.tsConfig = new TsConfigResolver(defaultCompilerOptions, relativeTo);
|
|
135
137
|
this.styles = styles;
|
|
136
138
|
this.sourceFileCache = sourceFileCache;
|
|
137
139
|
}
|
|
@@ -208,12 +210,14 @@ export class JavaScriptParser extends Parser {
|
|
|
208
210
|
// noinspection JSUnusedGlobalSymbols
|
|
209
211
|
reset(): this {
|
|
210
212
|
this.sourceFileCache && this.sourceFileCache.clear();
|
|
211
|
-
this.
|
|
213
|
+
this.oldPrograms.clear();
|
|
212
214
|
return this;
|
|
213
215
|
}
|
|
214
216
|
|
|
215
217
|
override async* parse(...inputs: ParserInput[]): AsyncGenerator<SourceFile> {
|
|
216
218
|
const inputFiles = new Map<SourcePath, ParserInput>();
|
|
219
|
+
const projectOf = new Map<SourcePath, string>();
|
|
220
|
+
const projects = new Map<string, { options: ts.CompilerOptions, rootNames: SourcePath[] }>();
|
|
217
221
|
|
|
218
222
|
// Populate inputFiles map and remove from cache if necessary
|
|
219
223
|
for (const input of inputs) {
|
|
@@ -228,8 +232,79 @@ export class JavaScriptParser extends Parser {
|
|
|
228
232
|
this.sourceFileCache && this.sourceFileCache.delete(normalizedSourcePath);
|
|
229
233
|
}
|
|
230
234
|
|
|
231
|
-
//
|
|
232
|
-
const
|
|
235
|
+
// Packages in a monorepo each configure their own module resolution.
|
|
236
|
+
for (const normalizedSourcePath of inputFiles.keys()) {
|
|
237
|
+
const {configFilePath, options} = this.tsConfig.forFile(normalizedSourcePath);
|
|
238
|
+
const projectKey = configFilePath ?? "";
|
|
239
|
+
projectOf.set(normalizedSourcePath, projectKey);
|
|
240
|
+
let project = projects.get(projectKey);
|
|
241
|
+
if (!project) {
|
|
242
|
+
projects.set(projectKey, project = {options, rootNames: []});
|
|
243
|
+
}
|
|
244
|
+
project.rootNames.push(normalizedSourcePath);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Module resolution probes a directory before the files in it, so a directory holding
|
|
248
|
+
// nothing but in-memory inputs has to answer too, or those inputs are unreachable.
|
|
249
|
+
const inputDirectories = new Set<string>();
|
|
250
|
+
for (const sourcePath of inputFiles.keys()) {
|
|
251
|
+
for (let dir = path.dirname(sourcePath); !inputDirectories.has(dir); dir = path.dirname(dir)) {
|
|
252
|
+
inputDirectories.add(dir);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const compiled = new Map<string, { program: ts.Program, typeMapping: JavaScriptTypeMapping }>();
|
|
257
|
+
for (const [projectKey, {options, rootNames}] of projects) {
|
|
258
|
+
// TypeScript carries the previous program's bound files forward when the root paths match,
|
|
259
|
+
// so a parser held across parses of one path costs a fraction of a freshly built one.
|
|
260
|
+
const program = ts.createProgram(rootNames, options,
|
|
261
|
+
this.createCompilerHost(options, inputFiles, inputDirectories), this.oldPrograms.get(projectKey));
|
|
262
|
+
this.oldPrograms.set(projectKey, program);
|
|
263
|
+
|
|
264
|
+
// A JavaScriptTypeMapping deduplicates by `ts.Type.id`, which is only unique within
|
|
265
|
+
// the TypeChecker that issued it, so each program needs its own.
|
|
266
|
+
compiled.set(projectKey, {program, typeMapping: new JavaScriptTypeMapping(program.getTypeChecker(), this.relativeTo)});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
for (const [sourcePath, input] of inputFiles) {
|
|
270
|
+
const {program, typeMapping} = compiled.get(projectOf.get(sourcePath)!)!;
|
|
271
|
+
const filePath = parserInputFile(input);
|
|
272
|
+
const sourceFile = program.getSourceFile(filePath);
|
|
273
|
+
if (!sourceFile) {
|
|
274
|
+
yield this.error(input, new Error('Parser returned undefined'));
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (hasFlowAnnotation(sourceFile)) {
|
|
279
|
+
yield this.error(input, new FlowSyntaxNotSupportedError("Flow syntax not supported"));
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const syntaxErrors = checkSyntaxErrors(program, sourceFile);
|
|
284
|
+
if (syntaxErrors.length > 0) {
|
|
285
|
+
let errors = syntaxErrors.map(e => `${e[0]} [${e[1]}]`).join('; ');
|
|
286
|
+
yield this.error(input, new SyntaxError(`Compiler error(s): ${errors}`));
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
try {
|
|
291
|
+
yield await this.requirePrintEqualsInput(produce(
|
|
292
|
+
new JavaScriptParserVisitor(sourceFile, this.relativePath(input), typeMapping)
|
|
293
|
+
.visit(sourceFile) as SourceFile,
|
|
294
|
+
draft => {
|
|
295
|
+
if (this.styles) {
|
|
296
|
+
draft.markers = this.styles.reduce((m, s) => replaceMarkerByKind(m, s), draft.markers);
|
|
297
|
+
}
|
|
298
|
+
}), input, escapeLoneSurrogates(sourceFile.getFullText()));
|
|
299
|
+
} catch (error) {
|
|
300
|
+
yield this.error(input, error instanceof Error ? error : new Error('Parser threw unknown error: ' + error));
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
private createCompilerHost(compilerOptions: ts.CompilerOptions, inputFiles: Map<SourcePath, ParserInput>,
|
|
306
|
+
inputDirectories: Set<string>): ts.CompilerHost {
|
|
307
|
+
const host = ts.createCompilerHost(compilerOptions);
|
|
233
308
|
|
|
234
309
|
// Set the current directory for module resolution
|
|
235
310
|
if (this.relativeTo) {
|
|
@@ -240,8 +315,13 @@ export class JavaScriptParser extends Parser {
|
|
|
240
315
|
// Override getSourceFile
|
|
241
316
|
host.getSourceFile = (fileName, languageVersion, onError) => {
|
|
242
317
|
const normalizedFileName = path.normalize(fileName);
|
|
318
|
+
// A file's module format is baked in when it is created and follows from the requesting
|
|
319
|
+
// project's `moduleResolution`, so it belongs in the key of a cache several projects share.
|
|
320
|
+
const cacheKey = typeof languageVersion === 'number' ?
|
|
321
|
+
normalizedFileName :
|
|
322
|
+
`${languageVersion.impliedNodeFormat ?? ''}\0${normalizedFileName}`;
|
|
243
323
|
// Check if the SourceFile is in the cache
|
|
244
|
-
let sourceFile = this.sourceFileCache && this.sourceFileCache.get(
|
|
324
|
+
let sourceFile = this.sourceFileCache && this.sourceFileCache.get(cacheKey);
|
|
245
325
|
if (sourceFile) {
|
|
246
326
|
return sourceFile;
|
|
247
327
|
}
|
|
@@ -276,7 +356,7 @@ export class JavaScriptParser extends Parser {
|
|
|
276
356
|
sourceFile = ts.createSourceFile(normalizedFileName, sourceText, sourceFileOptions, true, scriptKind);
|
|
277
357
|
// Cache the SourceFile if it's a dependency
|
|
278
358
|
if (!input && this.sourceFileCache) {
|
|
279
|
-
this.sourceFileCache.set(
|
|
359
|
+
this.sourceFileCache.set(cacheKey, sourceFile);
|
|
280
360
|
}
|
|
281
361
|
return sourceFile;
|
|
282
362
|
}
|
|
@@ -291,6 +371,11 @@ export class JavaScriptParser extends Parser {
|
|
|
291
371
|
return inputFiles.has(normalizedFileName) || ts.sys.fileExists(normalizedFileName);
|
|
292
372
|
};
|
|
293
373
|
|
|
374
|
+
host.directoryExists = (directoryName) => {
|
|
375
|
+
const normalizedDirectoryName = path.normalize(directoryName);
|
|
376
|
+
return inputDirectories.has(normalizedDirectoryName) || ts.sys.directoryExists(normalizedDirectoryName);
|
|
377
|
+
};
|
|
378
|
+
|
|
294
379
|
// Override readFile
|
|
295
380
|
host.readFile = (fileName) => {
|
|
296
381
|
const normalizedFileName = path.normalize(fileName);
|
|
@@ -301,7 +386,7 @@ export class JavaScriptParser extends Parser {
|
|
|
301
386
|
// Custom module resolution to handle in-memory imports
|
|
302
387
|
// This is required because TypeScript's default module resolution looks for files on disk,
|
|
303
388
|
// but our source files only exist in memory (in the inputFiles map)
|
|
304
|
-
host.resolveModuleNameLiterals = (moduleLiterals, containingFile) => {
|
|
389
|
+
host.resolveModuleNameLiterals = (moduleLiterals, containingFile, _redirectedReference, _options, containingSourceFile) => {
|
|
305
390
|
const resolvedModules: ts.ResolvedModuleWithFailedLookupLocations[] = [];
|
|
306
391
|
const normalizedFileName = path.normalize(containingFile);
|
|
307
392
|
const containingDir = path.dirname(normalizedFileName);
|
|
@@ -341,12 +426,18 @@ export class JavaScriptParser extends Parser {
|
|
|
341
426
|
}
|
|
342
427
|
}
|
|
343
428
|
|
|
344
|
-
// Fall back to TypeScript's default resolution for node_modules and absolute paths
|
|
429
|
+
// Fall back to TypeScript's default resolution for node_modules and absolute paths.
|
|
430
|
+
// Passing the usage location's mode keeps export conditions tied to the module kind
|
|
431
|
+
// pinned above, so every project reads the same branch of a dual package whatever
|
|
432
|
+
// `moduleResolution` it states.
|
|
345
433
|
const result = ts.resolveModuleName(
|
|
346
434
|
moduleName,
|
|
347
435
|
normalizedFileName,
|
|
348
|
-
|
|
349
|
-
host
|
|
436
|
+
compilerOptions,
|
|
437
|
+
host,
|
|
438
|
+
undefined,
|
|
439
|
+
undefined,
|
|
440
|
+
ts.getModeForUsageLocation(containingSourceFile, moduleLiteral, compilerOptions)
|
|
350
441
|
);
|
|
351
442
|
|
|
352
443
|
resolvedModules.push(result);
|
|
@@ -354,52 +445,7 @@ export class JavaScriptParser extends Parser {
|
|
|
354
445
|
return resolvedModules;
|
|
355
446
|
};
|
|
356
447
|
|
|
357
|
-
|
|
358
|
-
// so a parser held across parses of one path costs a fraction of a freshly built one.
|
|
359
|
-
const program = ts.createProgram([...inputFiles.keys()], this.compilerOptions, host, this.oldProgram);
|
|
360
|
-
|
|
361
|
-
// Update the oldProgram reference
|
|
362
|
-
this.oldProgram = program;
|
|
363
|
-
|
|
364
|
-
// Create a single JavaScriptTypeMapping instance to be shared across all files in this parse batch.
|
|
365
|
-
// This ensures that TypeScript types with the same type.id map to the same Type instance,
|
|
366
|
-
// preventing duplicate Type.Class, Type.Parameterized, etc. instances.
|
|
367
|
-
const typeChecker = program.getTypeChecker();
|
|
368
|
-
const typeMapping = new JavaScriptTypeMapping(typeChecker, this.relativeTo);
|
|
369
|
-
|
|
370
|
-
for (const input of inputFiles.values()) {
|
|
371
|
-
const filePath = parserInputFile(input);
|
|
372
|
-
const sourceFile = program.getSourceFile(filePath);
|
|
373
|
-
if (!sourceFile) {
|
|
374
|
-
yield this.error(input, new Error('Parser returned undefined'));
|
|
375
|
-
continue;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
if (hasFlowAnnotation(sourceFile)) {
|
|
379
|
-
yield this.error(input, new FlowSyntaxNotSupportedError("Flow syntax not supported"));
|
|
380
|
-
continue;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
const syntaxErrors = checkSyntaxErrors(program, sourceFile);
|
|
384
|
-
if (syntaxErrors.length > 0) {
|
|
385
|
-
let errors = syntaxErrors.map(e => `${e[0]} [${e[1]}]`).join('; ');
|
|
386
|
-
yield this.error(input, new SyntaxError(`Compiler error(s): ${errors}`));
|
|
387
|
-
continue;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
try {
|
|
391
|
-
yield await this.requirePrintEqualsInput(produce(
|
|
392
|
-
new JavaScriptParserVisitor(sourceFile, this.relativePath(input), typeMapping)
|
|
393
|
-
.visit(sourceFile) as SourceFile,
|
|
394
|
-
draft => {
|
|
395
|
-
if (this.styles) {
|
|
396
|
-
draft.markers = this.styles.reduce((m, s) => replaceMarkerByKind(m, s), draft.markers);
|
|
397
|
-
}
|
|
398
|
-
}), input, escapeLoneSurrogates(sourceFile.getFullText()));
|
|
399
|
-
} catch (error) {
|
|
400
|
-
yield this.error(input, error instanceof Error ? error : new Error('Parser threw unknown error: ' + error));
|
|
401
|
-
}
|
|
402
|
-
}
|
|
448
|
+
return host;
|
|
403
449
|
}
|
|
404
450
|
}
|
|
405
451
|
|