@openrewrite/rewrite 8.91.2 → 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/execution.d.ts +8 -0
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +31 -0
- package/dist/execution.js.map +1 -1
- package/dist/javascript/add-import.d.ts +64 -9
- package/dist/javascript/add-import.d.ts.map +1 -1
- package/dist/javascript/add-import.js +398 -71
- package/dist/javascript/add-import.js.map +1 -1
- package/dist/javascript/amd.d.ts +11 -1
- package/dist/javascript/amd.d.ts.map +1 -1
- package/dist/javascript/amd.js +43 -9
- package/dist/javascript/amd.js.map +1 -1
- package/dist/javascript/binding.d.ts +10 -2
- package/dist/javascript/binding.d.ts.map +1 -1
- package/dist/javascript/binding.js +44 -71
- package/dist/javascript/binding.js.map +1 -1
- package/dist/javascript/comparator.d.ts +2 -0
- package/dist/javascript/comparator.d.ts.map +1 -1
- package/dist/javascript/comparator.js +5 -1
- package/dist/javascript/comparator.js.map +1 -1
- package/dist/javascript/format/format.d.ts +5 -2
- package/dist/javascript/format/format.d.ts.map +1 -1
- package/dist/javascript/format/format.js +51 -11
- package/dist/javascript/format/format.js.map +1 -1
- package/dist/javascript/format/minimum-viable-spacing-visitor.d.ts +19 -0
- package/dist/javascript/format/minimum-viable-spacing-visitor.d.ts.map +1 -1
- package/dist/javascript/format/minimum-viable-spacing-visitor.js +180 -7
- package/dist/javascript/format/minimum-viable-spacing-visitor.js.map +1 -1
- package/dist/javascript/format/prettier-format.d.ts +2 -1
- package/dist/javascript/format/prettier-format.d.ts.map +1 -1
- package/dist/javascript/format/prettier-format.js +33 -23
- package/dist/javascript/format/prettier-format.js.map +1 -1
- package/dist/javascript/index.d.ts +3 -3
- package/dist/javascript/index.d.ts.map +1 -1
- package/dist/javascript/index.js +21 -1
- package/dist/javascript/index.js.map +1 -1
- package/dist/javascript/parser-utils.d.ts.map +1 -1
- package/dist/javascript/parser-utils.js +5 -9
- package/dist/javascript/parser-utils.js.map +1 -1
- package/dist/javascript/parser.d.ts +3 -2
- package/dist/javascript/parser.d.ts.map +1 -1
- package/dist/javascript/parser.js +202 -117
- package/dist/javascript/parser.js.map +1 -1
- package/dist/javascript/print.d.ts +1 -0
- package/dist/javascript/print.d.ts.map +1 -1
- package/dist/javascript/print.js +9 -0
- package/dist/javascript/print.js.map +1 -1
- package/dist/javascript/recipes/change-import.d.ts +6 -3
- package/dist/javascript/recipes/change-import.d.ts.map +1 -1
- package/dist/javascript/recipes/change-import.js +17 -277
- package/dist/javascript/recipes/change-import.js.map +1 -1
- package/dist/javascript/rpc.js +2 -0
- package/dist/javascript/rpc.js.map +1 -1
- package/dist/javascript/scope.d.ts +40 -7
- package/dist/javascript/scope.d.ts.map +1 -1
- package/dist/javascript/scope.js +182 -30
- package/dist/javascript/scope.js.map +1 -1
- package/dist/javascript/templating/bindings.js +2 -20
- package/dist/javascript/templating/bindings.js.map +1 -1
- package/dist/javascript/templating/comparator.d.ts +2 -0
- package/dist/javascript/templating/comparator.d.ts.map +1 -1
- package/dist/javascript/templating/comparator.js +25 -0
- package/dist/javascript/templating/comparator.js.map +1 -1
- package/dist/javascript/templating/engine.d.ts +5 -0
- package/dist/javascript/templating/engine.d.ts.map +1 -1
- package/dist/javascript/templating/engine.js +30 -12
- package/dist/javascript/templating/engine.js.map +1 -1
- package/dist/javascript/templating/template.d.ts.map +1 -1
- package/dist/javascript/templating/template.js +6 -0
- package/dist/javascript/templating/template.js.map +1 -1
- package/dist/javascript/templating/types.d.ts +5 -0
- package/dist/javascript/templating/types.d.ts.map +1 -1
- package/dist/javascript/tree.d.ts +1 -0
- package/dist/javascript/tree.d.ts.map +1 -1
- package/dist/javascript/tree.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/javascript/type-mapping.d.ts.map +1 -1
- package/dist/javascript/type-mapping.js +14 -0
- package/dist/javascript/type-mapping.js.map +1 -1
- package/dist/javascript/visitor.d.ts.map +1 -1
- package/dist/javascript/visitor.js +1 -0
- package/dist/javascript/visitor.js.map +1 -1
- package/dist/parser.d.ts +6 -0
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +23 -1
- package/dist/parser.js.map +1 -1
- package/dist/print.d.ts.map +1 -1
- package/dist/print.js +5 -2
- package/dist/print.js.map +1 -1
- package/dist/rewrite-javascript-version.txt +1 -1
- package/dist/rpc/request/parse-project.d.ts +11 -1
- package/dist/rpc/request/parse-project.d.ts.map +1 -1
- package/dist/rpc/request/parse-project.js +7 -2
- package/dist/rpc/request/parse-project.js.map +1 -1
- package/dist/rpc/request/parse.d.ts +13 -1
- package/dist/rpc/request/parse.d.ts.map +1 -1
- package/dist/rpc/request/parse.js +8 -2
- package/dist/rpc/request/parse.js.map +1 -1
- package/package.json +1 -1
- package/src/execution.ts +23 -0
- package/src/javascript/add-import.ts +449 -78
- package/src/javascript/amd.ts +49 -10
- package/src/javascript/binding.ts +60 -74
- package/src/javascript/comparator.ts +6 -1
- package/src/javascript/format/format.ts +56 -12
- package/src/javascript/format/minimum-viable-spacing-visitor.ts +196 -7
- package/src/javascript/format/prettier-format.ts +35 -25
- package/src/javascript/index.ts +10 -3
- package/src/javascript/parser-utils.ts +5 -11
- package/src/javascript/parser.ts +167 -62
- package/src/javascript/print.ts +10 -0
- package/src/javascript/recipes/change-import.ts +19 -349
- package/src/javascript/rpc.ts +2 -0
- package/src/javascript/scope.ts +210 -31
- package/src/javascript/templating/bindings.ts +2 -25
- package/src/javascript/templating/comparator.ts +29 -2
- package/src/javascript/templating/engine.ts +41 -14
- package/src/javascript/templating/template.ts +6 -0
- package/src/javascript/templating/types.ts +6 -0
- package/src/javascript/tree.ts +1 -0
- package/src/javascript/tsconfig.ts +177 -0
- package/src/javascript/type-mapping.ts +15 -0
- package/src/javascript/visitor.ts +1 -0
- package/src/parser.ts +24 -1
- package/src/print.ts +5 -2
- package/src/rpc/request/parse-project.ts +6 -2
- package/src/rpc/request/parse.ts +7 -2
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;
|
|
@@ -79,11 +80,20 @@ function getScriptKindFromFileName(fileName: string): ts.ScriptKind {
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
|
|
83
|
+
/**
|
|
84
|
+
* TypeScript's public typings model valid syntax only, so slots its parser still fills for invalid code —
|
|
85
|
+
* an initializer on a type member, a modifier on an object literal member — are missing from them.
|
|
86
|
+
*/
|
|
87
|
+
type WithInvalidSyntaxSlots<T> = T & {
|
|
88
|
+
initializer?: ts.Expression;
|
|
89
|
+
modifiers?: ts.NodeArray<ts.ModifierLike>;
|
|
90
|
+
};
|
|
91
|
+
|
|
82
92
|
export class JavaScriptParser extends Parser {
|
|
83
93
|
|
|
84
|
-
private readonly
|
|
94
|
+
private readonly tsConfig: TsConfigResolver;
|
|
85
95
|
private readonly styles?: NamedStyles[];
|
|
86
|
-
private
|
|
96
|
+
private readonly oldPrograms = new Map<string, ts.Program>();
|
|
87
97
|
private readonly sourceFileCache?: Map<string, ts.SourceFile>;
|
|
88
98
|
|
|
89
99
|
constructor(
|
|
@@ -96,7 +106,7 @@ export class JavaScriptParser extends Parser {
|
|
|
96
106
|
}: JavaScriptParserOptions = {},
|
|
97
107
|
) {
|
|
98
108
|
super({ctx, relativeTo});
|
|
99
|
-
|
|
109
|
+
const defaultCompilerOptions: ts.CompilerOptions = {
|
|
100
110
|
target: ts.ScriptTarget.Latest,
|
|
101
111
|
// Bundler matches `exports` conditions leniently, so packages that publish types only under
|
|
102
112
|
// an `import` condition resolve; it pairs with `preserve`, which `commonjs` cannot (TS5095).
|
|
@@ -123,6 +133,7 @@ export class JavaScriptParser extends Parser {
|
|
|
123
133
|
types: types ?? ["*"],
|
|
124
134
|
baseUrl: relativeTo || process.cwd()
|
|
125
135
|
};
|
|
136
|
+
this.tsConfig = new TsConfigResolver(defaultCompilerOptions, relativeTo);
|
|
126
137
|
this.styles = styles;
|
|
127
138
|
this.sourceFileCache = sourceFileCache;
|
|
128
139
|
}
|
|
@@ -199,12 +210,14 @@ export class JavaScriptParser extends Parser {
|
|
|
199
210
|
// noinspection JSUnusedGlobalSymbols
|
|
200
211
|
reset(): this {
|
|
201
212
|
this.sourceFileCache && this.sourceFileCache.clear();
|
|
202
|
-
this.
|
|
213
|
+
this.oldPrograms.clear();
|
|
203
214
|
return this;
|
|
204
215
|
}
|
|
205
216
|
|
|
206
217
|
override async* parse(...inputs: ParserInput[]): AsyncGenerator<SourceFile> {
|
|
207
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[] }>();
|
|
208
221
|
|
|
209
222
|
// Populate inputFiles map and remove from cache if necessary
|
|
210
223
|
for (const input of inputs) {
|
|
@@ -219,8 +232,79 @@ export class JavaScriptParser extends Parser {
|
|
|
219
232
|
this.sourceFileCache && this.sourceFileCache.delete(normalizedSourcePath);
|
|
220
233
|
}
|
|
221
234
|
|
|
222
|
-
//
|
|
223
|
-
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);
|
|
224
308
|
|
|
225
309
|
// Set the current directory for module resolution
|
|
226
310
|
if (this.relativeTo) {
|
|
@@ -231,8 +315,13 @@ export class JavaScriptParser extends Parser {
|
|
|
231
315
|
// Override getSourceFile
|
|
232
316
|
host.getSourceFile = (fileName, languageVersion, onError) => {
|
|
233
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}`;
|
|
234
323
|
// Check if the SourceFile is in the cache
|
|
235
|
-
let sourceFile = this.sourceFileCache && this.sourceFileCache.get(
|
|
324
|
+
let sourceFile = this.sourceFileCache && this.sourceFileCache.get(cacheKey);
|
|
236
325
|
if (sourceFile) {
|
|
237
326
|
return sourceFile;
|
|
238
327
|
}
|
|
@@ -267,7 +356,7 @@ export class JavaScriptParser extends Parser {
|
|
|
267
356
|
sourceFile = ts.createSourceFile(normalizedFileName, sourceText, sourceFileOptions, true, scriptKind);
|
|
268
357
|
// Cache the SourceFile if it's a dependency
|
|
269
358
|
if (!input && this.sourceFileCache) {
|
|
270
|
-
this.sourceFileCache.set(
|
|
359
|
+
this.sourceFileCache.set(cacheKey, sourceFile);
|
|
271
360
|
}
|
|
272
361
|
return sourceFile;
|
|
273
362
|
}
|
|
@@ -282,6 +371,11 @@ export class JavaScriptParser extends Parser {
|
|
|
282
371
|
return inputFiles.has(normalizedFileName) || ts.sys.fileExists(normalizedFileName);
|
|
283
372
|
};
|
|
284
373
|
|
|
374
|
+
host.directoryExists = (directoryName) => {
|
|
375
|
+
const normalizedDirectoryName = path.normalize(directoryName);
|
|
376
|
+
return inputDirectories.has(normalizedDirectoryName) || ts.sys.directoryExists(normalizedDirectoryName);
|
|
377
|
+
};
|
|
378
|
+
|
|
285
379
|
// Override readFile
|
|
286
380
|
host.readFile = (fileName) => {
|
|
287
381
|
const normalizedFileName = path.normalize(fileName);
|
|
@@ -292,7 +386,7 @@ export class JavaScriptParser extends Parser {
|
|
|
292
386
|
// Custom module resolution to handle in-memory imports
|
|
293
387
|
// This is required because TypeScript's default module resolution looks for files on disk,
|
|
294
388
|
// but our source files only exist in memory (in the inputFiles map)
|
|
295
|
-
host.resolveModuleNameLiterals = (moduleLiterals, containingFile) => {
|
|
389
|
+
host.resolveModuleNameLiterals = (moduleLiterals, containingFile, _redirectedReference, _options, containingSourceFile) => {
|
|
296
390
|
const resolvedModules: ts.ResolvedModuleWithFailedLookupLocations[] = [];
|
|
297
391
|
const normalizedFileName = path.normalize(containingFile);
|
|
298
392
|
const containingDir = path.dirname(normalizedFileName);
|
|
@@ -332,12 +426,18 @@ export class JavaScriptParser extends Parser {
|
|
|
332
426
|
}
|
|
333
427
|
}
|
|
334
428
|
|
|
335
|
-
// 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.
|
|
336
433
|
const result = ts.resolveModuleName(
|
|
337
434
|
moduleName,
|
|
338
435
|
normalizedFileName,
|
|
339
|
-
|
|
340
|
-
host
|
|
436
|
+
compilerOptions,
|
|
437
|
+
host,
|
|
438
|
+
undefined,
|
|
439
|
+
undefined,
|
|
440
|
+
ts.getModeForUsageLocation(containingSourceFile, moduleLiteral, compilerOptions)
|
|
341
441
|
);
|
|
342
442
|
|
|
343
443
|
resolvedModules.push(result);
|
|
@@ -345,52 +445,7 @@ export class JavaScriptParser extends Parser {
|
|
|
345
445
|
return resolvedModules;
|
|
346
446
|
};
|
|
347
447
|
|
|
348
|
-
|
|
349
|
-
// so a parser held across parses of one path costs a fraction of a freshly built one.
|
|
350
|
-
const program = ts.createProgram([...inputFiles.keys()], this.compilerOptions, host, this.oldProgram);
|
|
351
|
-
|
|
352
|
-
// Update the oldProgram reference
|
|
353
|
-
this.oldProgram = program;
|
|
354
|
-
|
|
355
|
-
// Create a single JavaScriptTypeMapping instance to be shared across all files in this parse batch.
|
|
356
|
-
// This ensures that TypeScript types with the same type.id map to the same Type instance,
|
|
357
|
-
// preventing duplicate Type.Class, Type.Parameterized, etc. instances.
|
|
358
|
-
const typeChecker = program.getTypeChecker();
|
|
359
|
-
const typeMapping = new JavaScriptTypeMapping(typeChecker, this.relativeTo);
|
|
360
|
-
|
|
361
|
-
for (const input of inputFiles.values()) {
|
|
362
|
-
const filePath = parserInputFile(input);
|
|
363
|
-
const sourceFile = program.getSourceFile(filePath);
|
|
364
|
-
if (!sourceFile) {
|
|
365
|
-
yield this.error(input, new Error('Parser returned undefined'));
|
|
366
|
-
continue;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
if (hasFlowAnnotation(sourceFile)) {
|
|
370
|
-
yield this.error(input, new FlowSyntaxNotSupportedError("Flow syntax not supported"));
|
|
371
|
-
continue;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
const syntaxErrors = checkSyntaxErrors(program, sourceFile);
|
|
375
|
-
if (syntaxErrors.length > 0) {
|
|
376
|
-
let errors = syntaxErrors.map(e => `${e[0]} [${e[1]}]`).join('; ');
|
|
377
|
-
yield this.error(input, new SyntaxError(`Compiler error(s): ${errors}`));
|
|
378
|
-
continue;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
try {
|
|
382
|
-
yield produce(
|
|
383
|
-
new JavaScriptParserVisitor(sourceFile, this.relativePath(input), typeMapping)
|
|
384
|
-
.visit(sourceFile) as SourceFile,
|
|
385
|
-
draft => {
|
|
386
|
-
if (this.styles) {
|
|
387
|
-
draft.markers = this.styles.reduce((m, s) => replaceMarkerByKind(m, s), draft.markers);
|
|
388
|
-
}
|
|
389
|
-
});
|
|
390
|
-
} catch (error) {
|
|
391
|
-
yield this.error(input, error instanceof Error ? error : new Error('Parser threw unknown error: ' + error));
|
|
392
|
-
}
|
|
393
|
-
}
|
|
448
|
+
return host;
|
|
394
449
|
}
|
|
395
450
|
}
|
|
396
451
|
|
|
@@ -573,7 +628,12 @@ export class JavaScriptParserVisitor {
|
|
|
573
628
|
| ts.FunctionDeclaration | ts.ParameterDeclaration | ts.MethodDeclaration | ts.EnumDeclaration | ts.InterfaceDeclaration
|
|
574
629
|
| ts.PropertySignature | ts.ConstructorDeclaration | ts.ModuleDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration
|
|
575
630
|
| ts.ArrowFunction | ts.IndexSignatureDeclaration | ts.TypeAliasDeclaration | ts.ExportDeclaration | ts.ExportAssignment | ts.FunctionExpression
|
|
576
|
-
| ts.ConstructorTypeNode | ts.TypeParameterDeclaration | ts.ImportDeclaration | ts.ImportEqualsDeclaration
|
|
631
|
+
| ts.ConstructorTypeNode | ts.TypeParameterDeclaration | ts.ImportDeclaration | ts.ImportEqualsDeclaration
|
|
632
|
+
| ts.PropertyAssignment | ts.ShorthandPropertyAssignment): J.Modifier[] {
|
|
633
|
+
if (ts.isPropertyAssignment(node) || ts.isShorthandPropertyAssignment(node)) {
|
|
634
|
+
const modifiers = (node as WithInvalidSyntaxSlots<typeof node>).modifiers;
|
|
635
|
+
return modifiers ? modifiers.filter(ts.isModifier).map(this.mapModifier) : [];
|
|
636
|
+
}
|
|
577
637
|
if (ts.isVariableStatement(node) || ts.isModuleDeclaration(node) || ts.isClassDeclaration(node) || ts.isEnumDeclaration(node)
|
|
578
638
|
|| ts.isInterfaceDeclaration(node) || ts.isPropertyDeclaration(node) || ts.isPropertySignature(node) || ts.isParameter(node)
|
|
579
639
|
|| ts.isMethodDeclaration(node) || ts.isConstructorDeclaration(node) || ts.isArrowFunction(node)
|
|
@@ -1175,6 +1235,8 @@ export class JavaScriptParserVisitor {
|
|
|
1175
1235
|
visitPropertySignature(node: ts.PropertySignature): J.VariableDeclarations {
|
|
1176
1236
|
// FIXME We are mapping the literals in things like type ascii = { " ": 32; "!": 33; } to
|
|
1177
1237
|
// named variables, which is not a good use of this construct.
|
|
1238
|
+
|
|
1239
|
+
const initializer = (node as WithInvalidSyntaxSlots<ts.PropertySignature>).initializer;
|
|
1178
1240
|
return {
|
|
1179
1241
|
kind: J.Kind.VariableDeclarations,
|
|
1180
1242
|
id: randomId(),
|
|
@@ -1193,6 +1255,7 @@ export class JavaScriptParserVisitor {
|
|
|
1193
1255
|
draft.markers = this.maybeAddOptionalMarker(draft, node);
|
|
1194
1256
|
}) as VariableDeclarator,
|
|
1195
1257
|
dimensionsAfterName: [],
|
|
1258
|
+
initializer: initializer && this.leftPadded(this.prefix(node.getChildAt(node.getChildren().indexOf(initializer) - 1)), this.visit(initializer)),
|
|
1196
1259
|
variableType: this.mapVariableType(node)
|
|
1197
1260
|
},
|
|
1198
1261
|
emptySpace
|
|
@@ -1355,7 +1418,8 @@ export class JavaScriptParserVisitor {
|
|
|
1355
1418
|
|
|
1356
1419
|
private mapTypeInfo(node: ts.MethodDeclaration | ts.PropertyDeclaration | ts.VariableDeclaration | ts.ParameterDeclaration
|
|
1357
1420
|
| ts.PropertySignature | ts.MethodSignature | ts.ArrowFunction | ts.CallSignatureDeclaration | ts.GetAccessorDeclaration
|
|
1358
|
-
| ts.FunctionDeclaration | ts.ConstructSignatureDeclaration | ts.FunctionExpression | ts.NamedTupleMember
|
|
1421
|
+
| ts.FunctionDeclaration | ts.ConstructSignatureDeclaration | ts.FunctionExpression | ts.NamedTupleMember
|
|
1422
|
+
| ts.ConstructorDeclaration | ts.SetAccessorDeclaration): JS.TypeInfo | undefined {
|
|
1359
1423
|
return node.type && {
|
|
1360
1424
|
kind: JS.Kind.TypeInfo,
|
|
1361
1425
|
id: randomId(),
|
|
@@ -1397,6 +1461,7 @@ export class JavaScriptParserVisitor {
|
|
|
1397
1461
|
leadingAnnotations: this.mapDecorators(node),
|
|
1398
1462
|
modifiers: this.mapModifiers(node),
|
|
1399
1463
|
nameAnnotations: [],
|
|
1464
|
+
returnTypeExpression: this.mapTypeInfo(node),
|
|
1400
1465
|
name: {...this.mapIdentifier(constructorKeyword, constructorKeyword.getText(), false), type: methodType},
|
|
1401
1466
|
parameters: this.mapCommaSeparatedList(this.getParameterListNodes(node)),
|
|
1402
1467
|
dimensionsAfterName: [],
|
|
@@ -1416,6 +1481,7 @@ export class JavaScriptParserVisitor {
|
|
|
1416
1481
|
markers: emptyMarkers,
|
|
1417
1482
|
leadingAnnotations: this.mapDecorators(node),
|
|
1418
1483
|
modifiers: this.mapModifiers(node),
|
|
1484
|
+
typeParameters: node.typeParameters && this.mapTypeParametersAsObject(node),
|
|
1419
1485
|
returnTypeExpression: this.mapTypeInfo(node),
|
|
1420
1486
|
name: name as ComputedPropertyName,
|
|
1421
1487
|
parameters: this.mapCommaSeparatedList(this.getParameterListNodes(node)),
|
|
@@ -1431,6 +1497,7 @@ export class JavaScriptParserVisitor {
|
|
|
1431
1497
|
markers: emptyMarkers,
|
|
1432
1498
|
leadingAnnotations: this.mapDecorators(node),
|
|
1433
1499
|
modifiers: this.mapModifiers(node),
|
|
1500
|
+
typeParameters: node.typeParameters && this.mapTypeParametersAsObject(node),
|
|
1434
1501
|
returnTypeExpression: this.mapTypeInfo(node),
|
|
1435
1502
|
nameAnnotations: [],
|
|
1436
1503
|
name: name as J.Identifier,
|
|
@@ -1452,6 +1519,8 @@ export class JavaScriptParserVisitor {
|
|
|
1452
1519
|
markers: emptyMarkers,
|
|
1453
1520
|
leadingAnnotations: this.mapDecorators(node),
|
|
1454
1521
|
modifiers: this.mapModifiers(node),
|
|
1522
|
+
typeParameters: node.typeParameters && this.mapTypeParametersAsObject(node),
|
|
1523
|
+
returnTypeExpression: this.mapTypeInfo(node),
|
|
1455
1524
|
name: name as ComputedPropertyName,
|
|
1456
1525
|
parameters: this.mapCommaSeparatedList(this.getParameterListNodes(node)),
|
|
1457
1526
|
body: node.body && this.convert<J.Block>(node.body),
|
|
@@ -1466,6 +1535,8 @@ export class JavaScriptParserVisitor {
|
|
|
1466
1535
|
markers: emptyMarkers,
|
|
1467
1536
|
leadingAnnotations: this.mapDecorators(node),
|
|
1468
1537
|
modifiers: this.mapModifiers(node),
|
|
1538
|
+
typeParameters: node.typeParameters && this.mapTypeParametersAsObject(node),
|
|
1539
|
+
returnTypeExpression: this.mapTypeInfo(node),
|
|
1469
1540
|
nameAnnotations: [],
|
|
1470
1541
|
name: name as J.Identifier,
|
|
1471
1542
|
parameters: this.mapCommaSeparatedList(this.getParameterListNodes(node)),
|
|
@@ -4219,6 +4290,7 @@ export class JavaScriptParserVisitor {
|
|
|
4219
4290
|
id: randomId(),
|
|
4220
4291
|
prefix: this.prefix(node),
|
|
4221
4292
|
markers: emptyMarkers,
|
|
4293
|
+
modifiers: this.mapModifiers(node),
|
|
4222
4294
|
name: this.rightPadded(this.visit(node.name), this.suffix(node.name)),
|
|
4223
4295
|
assigmentToken: JS.PropertyAssignment.Token.Colon,
|
|
4224
4296
|
initializer: this.visit(node.initializer)
|
|
@@ -4231,6 +4303,7 @@ export class JavaScriptParserVisitor {
|
|
|
4231
4303
|
id: randomId(),
|
|
4232
4304
|
prefix: this.prefix(node),
|
|
4233
4305
|
markers: emptyMarkers,
|
|
4306
|
+
modifiers: this.mapModifiers(node),
|
|
4234
4307
|
name: this.rightPadded(this.visit(node.name), this.suffix(node.name)),
|
|
4235
4308
|
assigmentToken: JS.PropertyAssignment.Token.Equals,
|
|
4236
4309
|
initializer: node.objectAssignmentInitializer && this.visit(node.objectAssignmentInitializer)
|
|
@@ -4654,7 +4727,8 @@ export class JavaScriptParserVisitor {
|
|
|
4654
4727
|
}
|
|
4655
4728
|
|
|
4656
4729
|
private mapTypeParametersAsObject(node: ts.MethodDeclaration | ts.MethodSignature | ts.FunctionDeclaration
|
|
4657
|
-
| ts.CallSignatureDeclaration | ts.ConstructSignatureDeclaration | ts.FunctionExpression | ts.ArrowFunction | ts.TypeAliasDeclaration | ts.FunctionTypeNode | ts.ConstructorTypeNode
|
|
4730
|
+
| ts.CallSignatureDeclaration | ts.ConstructSignatureDeclaration | ts.FunctionExpression | ts.ArrowFunction | ts.TypeAliasDeclaration | ts.FunctionTypeNode | ts.ConstructorTypeNode
|
|
4731
|
+
| ts.GetAccessorDeclaration | ts.SetAccessorDeclaration): J.TypeParameters | undefined {
|
|
4658
4732
|
const typeParameters = node.typeParameters;
|
|
4659
4733
|
if (!typeParameters) return undefined;
|
|
4660
4734
|
|
|
@@ -4806,6 +4880,8 @@ class FlowSyntaxNotSupportedError extends SyntaxError {
|
|
|
4806
4880
|
|
|
4807
4881
|
const SURR_FIRST = 0xD800;
|
|
4808
4882
|
const SURR_LAST = 0xDFFF;
|
|
4883
|
+
const HIGH_SURR_LAST = 0xDBFF;
|
|
4884
|
+
const LOW_SURR_FIRST = 0xDC00;
|
|
4809
4885
|
|
|
4810
4886
|
/**
|
|
4811
4887
|
* Extracts invalid UTF-16 surrogate pairs from a string literal's value source.
|
|
@@ -4819,6 +4895,26 @@ const SURR_LAST = 0xDFFF;
|
|
|
4819
4895
|
* 1. Unicode escape sequences (\uXXXX) where XXXX is in the surrogate range
|
|
4820
4896
|
* 2. Raw surrogate characters in the source (character codes 0xD800-0xDFFF)
|
|
4821
4897
|
*/
|
|
4898
|
+
/** The form {@link extractSurrogateEscapes} can hold, against which print idempotence is measured. */
|
|
4899
|
+
function escapeLoneSurrogates(source: string): string {
|
|
4900
|
+
let escaped = '';
|
|
4901
|
+
for (let j = 0; j < source.length; j++) {
|
|
4902
|
+
const charCode = source.charCodeAt(j);
|
|
4903
|
+
if (charCode >= SURR_FIRST && charCode <= SURR_LAST) {
|
|
4904
|
+
const next = source.charCodeAt(j + 1);
|
|
4905
|
+
if (charCode <= HIGH_SURR_LAST && next >= LOW_SURR_FIRST && next <= SURR_LAST) {
|
|
4906
|
+
escaped += source.charAt(j) + source.charAt(j + 1);
|
|
4907
|
+
j++;
|
|
4908
|
+
continue;
|
|
4909
|
+
}
|
|
4910
|
+
escaped += "\\u" + charCode.toString(16).toUpperCase().padStart(4, '0');
|
|
4911
|
+
continue;
|
|
4912
|
+
}
|
|
4913
|
+
escaped += source.charAt(j);
|
|
4914
|
+
}
|
|
4915
|
+
return escaped;
|
|
4916
|
+
}
|
|
4917
|
+
|
|
4822
4918
|
function extractSurrogateEscapes(valueSource: string): { cleanedSource: string, unicodeEscapes: J.LiteralUnicodeEscape[] } {
|
|
4823
4919
|
const unicodeEscapes: J.LiteralUnicodeEscape[] = [];
|
|
4824
4920
|
let cleanedSource = '';
|
|
@@ -4842,8 +4938,17 @@ function extractSurrogateEscapes(valueSource: string): { cleanedSource: string,
|
|
|
4842
4938
|
}
|
|
4843
4939
|
}
|
|
4844
4940
|
|
|
4845
|
-
//
|
|
4941
|
+
// A raw surrogate pair spells one code point — an emoji, say — and is carried as itself. A lone
|
|
4942
|
+
// surrogate is not text on its own and does not survive serialization (#6599), so it is held as a
|
|
4943
|
+
// `\uXXXX` escape and prints back as one.
|
|
4846
4944
|
if (charCode >= SURR_FIRST && charCode <= SURR_LAST) {
|
|
4945
|
+
const next = valueSource.charCodeAt(j + 1);
|
|
4946
|
+
if (charCode <= HIGH_SURR_LAST && next >= LOW_SURR_FIRST && next <= SURR_LAST) {
|
|
4947
|
+
cleanedSource += c + valueSource.charAt(j + 1);
|
|
4948
|
+
cleanedIndex += 2;
|
|
4949
|
+
j++;
|
|
4950
|
+
continue;
|
|
4951
|
+
}
|
|
4847
4952
|
const codePoint = charCode.toString(16).toUpperCase().padStart(4, '0');
|
|
4848
4953
|
unicodeEscapes.push({ valueSourceIndex: cleanedIndex, codePoint });
|
|
4849
4954
|
continue;
|
package/src/javascript/print.ts
CHANGED
|
@@ -950,6 +950,13 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
|
|
|
950
950
|
return typeDeclaration;
|
|
951
951
|
}
|
|
952
952
|
|
|
953
|
+
override async visitUnknownSource(source: J.UnknownSource, p: PrintOutputCapture): Promise<J | undefined> {
|
|
954
|
+
await this.beforeSyntax(source, p);
|
|
955
|
+
p.append(source.text);
|
|
956
|
+
await this.afterSyntax(source, p);
|
|
957
|
+
return source;
|
|
958
|
+
}
|
|
959
|
+
|
|
953
960
|
override async visitLiteralType(literalType: JS.LiteralType, p: PrintOutputCapture): Promise<J | undefined> {
|
|
954
961
|
await this.beforeSyntax(literalType, p);
|
|
955
962
|
await this.visit(literalType.literal, p);
|
|
@@ -1413,6 +1420,9 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
|
|
|
1413
1420
|
override async visitPropertyAssignment(propertyAssignment: JS.PropertyAssignment, p: PrintOutputCapture): Promise<J | undefined> {
|
|
1414
1421
|
await this.beforeSyntax(propertyAssignment, p);
|
|
1415
1422
|
|
|
1423
|
+
for (const m of propertyAssignment.modifiers) {
|
|
1424
|
+
await this.visitModifier(m, p);
|
|
1425
|
+
}
|
|
1416
1426
|
await this.visitRightPadded(propertyAssignment.name, p);
|
|
1417
1427
|
|
|
1418
1428
|
if (propertyAssignment.initializer) {
|