@openrewrite/rewrite 8.92.16 → 8.92.18
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/README.md +48 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/java/formatting-utils.d.ts +2 -1
- package/dist/java/formatting-utils.d.ts.map +1 -1
- package/dist/java/formatting-utils.js +4 -3
- package/dist/java/formatting-utils.js.map +1 -1
- package/dist/java/rpc.d.ts.map +1 -1
- package/dist/java/rpc.js +2 -0
- package/dist/java/rpc.js.map +1 -1
- package/dist/java/tree.d.ts +8 -0
- package/dist/java/tree.d.ts.map +1 -1
- package/dist/java/tree.js +11 -1
- package/dist/java/tree.js.map +1 -1
- package/dist/java/type.d.ts +7 -1
- package/dist/java/type.d.ts.map +1 -1
- package/dist/java/type.js +16 -1
- package/dist/java/type.js.map +1 -1
- package/dist/javascript/add-import.d.ts +27 -21
- package/dist/javascript/add-import.d.ts.map +1 -1
- package/dist/javascript/add-import.js +303 -143
- package/dist/javascript/add-import.js.map +1 -1
- package/dist/javascript/amd.d.ts.map +1 -1
- package/dist/javascript/amd.js +25 -10
- package/dist/javascript/amd.js.map +1 -1
- package/dist/javascript/autodetect.js +36 -45
- package/dist/javascript/autodetect.js.map +1 -1
- package/dist/javascript/binding.d.ts +6 -4
- package/dist/javascript/binding.d.ts.map +1 -1
- package/dist/javascript/binding.js +54 -18
- package/dist/javascript/binding.js.map +1 -1
- package/dist/javascript/comparator.d.ts +22 -5
- package/dist/javascript/comparator.d.ts.map +1 -1
- package/dist/javascript/comparator.js +120 -38
- package/dist/javascript/comparator.js.map +1 -1
- package/dist/javascript/format/format.d.ts +2 -0
- package/dist/javascript/format/format.d.ts.map +1 -1
- package/dist/javascript/format/format.js +11 -1
- package/dist/javascript/format/format.js.map +1 -1
- package/dist/javascript/format/tabs-and-indents-visitor.d.ts.map +1 -1
- package/dist/javascript/format/tabs-and-indents-visitor.js +31 -4
- package/dist/javascript/format/tabs-and-indents-visitor.js.map +1 -1
- package/dist/javascript/index.d.ts +4 -2
- package/dist/javascript/index.d.ts.map +1 -1
- package/dist/javascript/index.js +10 -1
- package/dist/javascript/index.js.map +1 -1
- package/dist/javascript/markers.d.ts +12 -0
- package/dist/javascript/markers.d.ts.map +1 -1
- package/dist/javascript/markers.js +81 -2
- package/dist/javascript/markers.js.map +1 -1
- package/dist/javascript/method-matcher.d.ts +13 -2
- package/dist/javascript/method-matcher.d.ts.map +1 -1
- package/dist/javascript/method-matcher.js +32 -19
- package/dist/javascript/method-matcher.js.map +1 -1
- package/dist/javascript/node-resolution-result.js +3 -2
- package/dist/javascript/node-resolution-result.js.map +1 -1
- package/dist/javascript/package-name.d.ts +6 -0
- package/dist/javascript/package-name.d.ts.map +1 -0
- package/dist/javascript/package-name.js +47 -0
- package/dist/javascript/package-name.js.map +1 -0
- package/dist/javascript/parser.d.ts +9 -0
- package/dist/javascript/parser.d.ts.map +1 -1
- package/dist/javascript/parser.js +185 -88
- package/dist/javascript/parser.js.map +1 -1
- package/dist/javascript/preconditions.d.ts +4 -1
- package/dist/javascript/preconditions.d.ts.map +1 -1
- package/dist/javascript/preconditions.js +7 -4
- package/dist/javascript/preconditions.js.map +1 -1
- package/dist/javascript/print.d.ts +10 -1
- package/dist/javascript/print.d.ts.map +1 -1
- package/dist/javascript/print.js +120 -77
- package/dist/javascript/print.js.map +1 -1
- package/dist/javascript/recipes/change-method-target-to-import.d.ts +29 -0
- package/dist/javascript/recipes/change-method-target-to-import.d.ts.map +1 -0
- package/dist/javascript/recipes/change-method-target-to-import.js +164 -0
- package/dist/javascript/recipes/change-method-target-to-import.js.map +1 -0
- package/dist/javascript/recipes/index.d.ts +1 -0
- package/dist/javascript/recipes/index.d.ts.map +1 -1
- package/dist/javascript/recipes/index.js +1 -0
- package/dist/javascript/recipes/index.js.map +1 -1
- package/dist/javascript/scope.d.ts +60 -16
- package/dist/javascript/scope.d.ts.map +1 -1
- package/dist/javascript/scope.js +596 -131
- package/dist/javascript/scope.js.map +1 -1
- package/dist/javascript/search/uses-method.d.ts +1 -1
- package/dist/javascript/search/uses-method.d.ts.map +1 -1
- package/dist/javascript/search/uses-method.js +2 -2
- package/dist/javascript/search/uses-method.js.map +1 -1
- package/dist/javascript/search/uses-type.d.ts +14 -1
- package/dist/javascript/search/uses-type.d.ts.map +1 -1
- package/dist/javascript/search/uses-type.js +24 -9
- package/dist/javascript/search/uses-type.js.map +1 -1
- package/dist/javascript/templating/bindings.d.ts +1 -1
- package/dist/javascript/templating/bindings.d.ts.map +1 -1
- package/dist/javascript/templating/bindings.js +10 -50
- package/dist/javascript/templating/bindings.js.map +1 -1
- package/dist/javascript/templating/comparator.d.ts +8 -11
- package/dist/javascript/templating/comparator.d.ts.map +1 -1
- package/dist/javascript/templating/comparator.js +12 -110
- package/dist/javascript/templating/comparator.js.map +1 -1
- package/dist/javascript/templating/engine.d.ts +34 -24
- package/dist/javascript/templating/engine.d.ts.map +1 -1
- package/dist/javascript/templating/engine.js +208 -115
- package/dist/javascript/templating/engine.js.map +1 -1
- package/dist/javascript/templating/pattern.d.ts +11 -5
- package/dist/javascript/templating/pattern.d.ts.map +1 -1
- package/dist/javascript/templating/pattern.js +86 -20
- package/dist/javascript/templating/pattern.js.map +1 -1
- package/dist/javascript/templating/placeholder-replacement.d.ts +34 -3
- package/dist/javascript/templating/placeholder-replacement.d.ts.map +1 -1
- package/dist/javascript/templating/placeholder-replacement.js +126 -60
- package/dist/javascript/templating/placeholder-replacement.js.map +1 -1
- package/dist/javascript/templating/precedence.d.ts +3 -1
- package/dist/javascript/templating/precedence.d.ts.map +1 -1
- package/dist/javascript/templating/precedence.js +28 -8
- package/dist/javascript/templating/precedence.js.map +1 -1
- package/dist/javascript/templating/template.d.ts +7 -6
- package/dist/javascript/templating/template.d.ts.map +1 -1
- package/dist/javascript/templating/template.js +31 -28
- package/dist/javascript/templating/template.js.map +1 -1
- package/dist/javascript/templating/types.d.ts +6 -3
- package/dist/javascript/templating/types.d.ts.map +1 -1
- package/dist/javascript/templating/utils.d.ts +10 -1
- package/dist/javascript/templating/utils.d.ts.map +1 -1
- package/dist/javascript/templating/utils.js +22 -3
- package/dist/javascript/templating/utils.js.map +1 -1
- package/dist/javascript/tree-debug.d.ts +2 -0
- package/dist/javascript/tree-debug.d.ts.map +1 -1
- package/dist/javascript/tree-debug.js +6 -0
- package/dist/javascript/tree-debug.js.map +1 -1
- package/dist/javascript/tsconfig.d.ts.map +1 -1
- package/dist/javascript/tsconfig.js +7 -17
- package/dist/javascript/tsconfig.js.map +1 -1
- package/dist/javascript/type-mapping.d.ts +35 -16
- package/dist/javascript/type-mapping.d.ts.map +1 -1
- package/dist/javascript/type-mapping.js +271 -252
- package/dist/javascript/type-mapping.js.map +1 -1
- package/dist/javascript/type-report-cli.d.ts +7 -0
- package/dist/javascript/type-report-cli.d.ts.map +1 -0
- package/dist/javascript/type-report-cli.js +129 -0
- package/dist/javascript/type-report-cli.js.map +1 -0
- package/dist/javascript/type-report.d.ts +61 -0
- package/dist/javascript/type-report.d.ts.map +1 -0
- package/dist/javascript/type-report.js +488 -0
- package/dist/javascript/type-report.js.map +1 -0
- package/dist/markers.d.ts +4 -0
- package/dist/markers.d.ts.map +1 -1
- package/dist/markers.js +8 -0
- package/dist/markers.js.map +1 -1
- package/dist/print.d.ts +6 -1
- package/dist/print.d.ts.map +1 -1
- package/dist/print.js +21 -7
- package/dist/print.js.map +1 -1
- package/dist/recipe.d.ts +5 -0
- package/dist/recipe.d.ts.map +1 -1
- package/dist/recipe.js +5 -0
- package/dist/recipe.js.map +1 -1
- package/dist/rewrite-javascript-version.txt +1 -1
- package/dist/rpc/java-rpc-client.d.ts +2 -0
- package/dist/rpc/java-rpc-client.d.ts.map +1 -1
- package/dist/rpc/java-rpc-client.js +1 -0
- package/dist/rpc/java-rpc-client.js.map +1 -1
- package/dist/rpc/queue.d.ts +24 -0
- package/dist/rpc/queue.d.ts.map +1 -1
- package/dist/rpc/queue.js +71 -11
- package/dist/rpc/queue.js.map +1 -1
- package/dist/rpc/request/get-object.d.ts +4 -0
- package/dist/rpc/request/get-object.d.ts.map +1 -1
- package/dist/rpc/request/get-object.js +23 -1
- package/dist/rpc/request/get-object.js.map +1 -1
- package/dist/rpc/request/parse.d.ts.map +1 -1
- package/dist/rpc/request/parse.js +3 -1
- package/dist/rpc/request/parse.js.map +1 -1
- package/dist/rpc/request/prepare-recipe.d.ts +3 -1
- package/dist/rpc/request/prepare-recipe.d.ts.map +1 -1
- package/dist/rpc/request/prepare-recipe.js +13 -6
- package/dist/rpc/request/prepare-recipe.js.map +1 -1
- package/dist/rpc/request/print.d.ts +8 -2
- package/dist/rpc/request/print.d.ts.map +1 -1
- package/dist/rpc/request/print.js +12 -9
- package/dist/rpc/request/print.js.map +1 -1
- package/dist/rpc/rewrite-rpc.d.ts +3 -2
- package/dist/rpc/rewrite-rpc.d.ts.map +1 -1
- package/dist/rpc/rewrite-rpc.js +9 -3
- package/dist/rpc/rewrite-rpc.js.map +1 -1
- package/dist/rpc/server.d.ts.map +1 -1
- package/dist/rpc/server.js +19 -5
- package/dist/rpc/server.js.map +1 -1
- package/dist/search/is-source-file.d.ts +1 -0
- package/dist/search/is-source-file.d.ts.map +1 -1
- package/dist/search/is-source-file.js +7 -2
- package/dist/search/is-source-file.js.map +1 -1
- package/dist/test/java-rpc.d.ts.map +1 -1
- package/dist/test/java-rpc.js +3 -0
- package/dist/test/java-rpc.js.map +1 -1
- package/dist/test/rewrite-test.d.ts +5 -0
- package/dist/test/rewrite-test.d.ts.map +1 -1
- package/dist/test/rewrite-test.js +14 -3
- package/dist/test/rewrite-test.js.map +1 -1
- package/package.json +4 -3
- package/src/index.ts +3 -1
- package/src/java/formatting-utils.ts +5 -4
- package/src/java/rpc.ts +2 -0
- package/src/java/tree.ts +15 -0
- package/src/java/type.ts +19 -2
- package/src/javascript/add-import.ts +338 -152
- package/src/javascript/amd.ts +28 -12
- package/src/javascript/autodetect.ts +32 -41
- package/src/javascript/binding.ts +64 -22
- package/src/javascript/comparator.ts +129 -43
- package/src/javascript/format/format.ts +9 -0
- package/src/javascript/format/tabs-and-indents-visitor.ts +30 -3
- package/src/javascript/index.ts +6 -3
- package/src/javascript/markers.ts +77 -5
- package/src/javascript/method-matcher.ts +34 -22
- package/src/javascript/node-resolution-result.ts +3 -2
- package/src/javascript/package-name.ts +45 -0
- package/src/javascript/parser.ts +200 -91
- package/src/javascript/preconditions.ts +7 -4
- package/src/javascript/print.ts +123 -76
- package/src/javascript/recipes/change-method-target-to-import.ts +178 -0
- package/src/javascript/recipes/index.ts +1 -0
- package/src/javascript/scope.ts +705 -169
- package/src/javascript/search/uses-method.ts +2 -2
- package/src/javascript/search/uses-type.ts +30 -9
- package/src/javascript/templating/bindings.ts +13 -38
- package/src/javascript/templating/comparator.ts +16 -127
- package/src/javascript/templating/engine.ts +236 -129
- package/src/javascript/templating/pattern.ts +107 -28
- package/src/javascript/templating/placeholder-replacement.ts +154 -62
- package/src/javascript/templating/precedence.ts +33 -11
- package/src/javascript/templating/template.ts +35 -30
- package/src/javascript/templating/types.ts +6 -3
- package/src/javascript/templating/utils.ts +24 -2
- package/src/javascript/tree-debug.ts +9 -0
- package/src/javascript/tsconfig.ts +7 -17
- package/src/javascript/type-mapping.ts +277 -255
- package/src/javascript/type-report-cli.ts +96 -0
- package/src/javascript/type-report.ts +575 -0
- package/src/markers.ts +8 -0
- package/src/print.ts +23 -8
- package/src/recipe.ts +6 -0
- package/src/rpc/java-rpc-client.ts +3 -0
- package/src/rpc/queue.ts +80 -7
- package/src/rpc/request/get-object.ts +24 -0
- package/src/rpc/request/parse.ts +4 -1
- package/src/rpc/request/prepare-recipe.ts +16 -6
- package/src/rpc/request/print.ts +12 -8
- package/src/rpc/rewrite-rpc.ts +16 -5
- package/src/rpc/server.ts +18 -6
- package/src/search/is-source-file.ts +8 -3
- package/src/test/java-rpc.ts +3 -0
- package/src/test/rewrite-test.ts +14 -3
|
@@ -75,6 +75,8 @@ interface SlotConstraints {
|
|
|
75
75
|
readonly noLeadingDeclarationToken?: boolean;
|
|
76
76
|
/** The slot is followed by `.`, so a bare integer literal would lex as a decimal point. */
|
|
77
77
|
readonly followedByDot?: boolean;
|
|
78
|
+
/** The slot holds a `TypeTree`, so anything else is wrapped in `JS.TypeTreeExpression` as the parser does. */
|
|
79
|
+
readonly typeTree?: boolean;
|
|
78
80
|
}
|
|
79
81
|
|
|
80
82
|
/** The precedence of `expression` as printed; a kind this module does not model counts as Primary. */
|
|
@@ -247,7 +249,7 @@ function slotConstraints(parent: J, childId: string): SlotConstraints | undefine
|
|
|
247
249
|
case J.Kind.NewClass: {
|
|
248
250
|
const newClass = parent as J.NewClass;
|
|
249
251
|
if (newClass.class?.id === childId) {
|
|
250
|
-
return {precedence: Precedence.Call, noCallShape: true, noOptionalChain: true};
|
|
252
|
+
return {precedence: Precedence.Call, noCallShape: true, noOptionalChain: true, typeTree: true};
|
|
251
253
|
}
|
|
252
254
|
return isContainerElement(newClass.arguments, childId) ? {precedence: Precedence.Assignment} : undefined;
|
|
253
255
|
}
|
|
@@ -325,22 +327,42 @@ export function requiredPrecedence(parent: J, childId: string): number | undefin
|
|
|
325
327
|
*/
|
|
326
328
|
export function maybeParenthesize(parent: J | undefined, childId: string, expression: J,
|
|
327
329
|
slotMarkers?: Markers): J {
|
|
328
|
-
|
|
329
|
-
return expression;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
const constraints = slotConstraints(parent, childId);
|
|
330
|
+
const constraints = parent && slotConstraints(parent, childId);
|
|
333
331
|
if (!constraints) {
|
|
334
|
-
return expression;
|
|
332
|
+
return followsTrailingMarker(expression, slotMarkers) ? parenthesize(expression, slotMarkers) : expression;
|
|
335
333
|
}
|
|
336
334
|
|
|
337
335
|
// A statement wrapper is transparent here: the parentheses belong around the expression
|
|
338
336
|
if (expression.kind === JS.Kind.ExpressionStatement) {
|
|
339
337
|
const inner = (expression as JS.ExpressionStatement).expression;
|
|
340
|
-
const wrapped = wrapIfNeeded(parent
|
|
338
|
+
const wrapped = wrapIfNeeded(parent!, childId, constraints, inner, slotMarkers);
|
|
341
339
|
return wrapped === inner ? expression : {...expression, expression: wrapped} as JS.ExpressionStatement;
|
|
342
340
|
}
|
|
343
|
-
|
|
341
|
+
const wrapped = wrapIfNeeded(parent!, childId, constraints, expression, slotMarkers);
|
|
342
|
+
return constraints.typeTree ? asTypeTree(wrapped) : wrapped;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** Whether the slot puts a `!` or `?.` after `expression`, which binds looser than the left-hand side they follow. */
|
|
346
|
+
function followsTrailingMarker(expression: J, slotMarkers: Markers | undefined): boolean {
|
|
347
|
+
return !!slotMarkers?.markers.some(isTrailingMarker) && precedenceOf(expression) < Precedence.Call;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function asTypeTree(expression: J): J {
|
|
351
|
+
switch (expression.kind) {
|
|
352
|
+
case J.Kind.Identifier:
|
|
353
|
+
case J.Kind.FieldAccess:
|
|
354
|
+
case J.Kind.ArrayType:
|
|
355
|
+
case J.Kind.ParameterizedType:
|
|
356
|
+
case JS.Kind.TypeTreeExpression:
|
|
357
|
+
return expression;
|
|
358
|
+
}
|
|
359
|
+
return {
|
|
360
|
+
kind: JS.Kind.TypeTreeExpression,
|
|
361
|
+
id: randomId(),
|
|
362
|
+
prefix: expression.prefix,
|
|
363
|
+
markers: emptyMarkers,
|
|
364
|
+
expression: {...expression, prefix: emptySpace}
|
|
365
|
+
} as JS.TypeTreeExpression;
|
|
344
366
|
}
|
|
345
367
|
|
|
346
368
|
/** The nearest enclosing LST node in a cursor path, skipping the padding wrappers visitors push. */
|
|
@@ -383,7 +405,7 @@ export function parenthesize(expression: J, slotMarkers?: Markers): J.Parenthese
|
|
|
383
405
|
|
|
384
406
|
function wrapIfNeeded(parent: J, childId: string, constraints: SlotConstraints, expression: J,
|
|
385
407
|
slotMarkers: Markers | undefined): J {
|
|
386
|
-
if (precedenceOf(expression) < constraints.precedence ||
|
|
408
|
+
if (precedenceOf(expression) < constraints.precedence || followsTrailingMarker(expression, slotMarkers) ||
|
|
387
409
|
(constraints.noCallShape && isCallShaped(expression)) ||
|
|
388
410
|
(constraints.noOptionalChain && hasOptionalChain(expression)) ||
|
|
389
411
|
(constraints.noLeadingObjectLiteral && startsWithObjectLiteral(expression)) ||
|
|
@@ -582,7 +604,7 @@ function leftmostChild(expression: J): J | undefined {
|
|
|
582
604
|
}
|
|
583
605
|
|
|
584
606
|
/** Markers the printer emits *after* the node they sit on. */
|
|
585
|
-
function isTrailingMarker(marker: Marker): boolean {
|
|
607
|
+
export function isTrailingMarker(marker: Marker): boolean {
|
|
586
608
|
return marker.kind === JS.Markers.NonNullAssertion || marker.kind === JS.Markers.Optional;
|
|
587
609
|
}
|
|
588
610
|
|
|
@@ -17,10 +17,11 @@ import {Cursor, Tree} from '../..';
|
|
|
17
17
|
import {J} from '../../java';
|
|
18
18
|
import {ApplyOptions, Parameter, TemplateOptions, TemplateParameter} from './types';
|
|
19
19
|
import {maybeBind} from '../binding';
|
|
20
|
-
import {
|
|
20
|
+
import {ModuleScopeBinding} from '../add-import';
|
|
21
|
+
import {opensWithBrace, replacedByObjectLiteral} from './engine';
|
|
21
22
|
import {JavaScriptVisitor} from '../visitor';
|
|
22
23
|
import {MatchResult} from './pattern';
|
|
23
|
-
import {generateCacheKey, globalAstCache, WRAPPERS_MAP_SYMBOL} from './utils';
|
|
24
|
+
import {generateCacheKey, globalAstCache, LRUCache, PATTERN_PREFIXES_SYMBOL, WRAPPERS_MAP_SYMBOL} from './utils';
|
|
24
25
|
import {CAPTURE_NAME_SYMBOL, RAW_CODE_SYMBOL} from './capture';
|
|
25
26
|
import {TemplateEngine} from './engine';
|
|
26
27
|
import {JS} from '..';
|
|
@@ -176,8 +177,9 @@ export class TemplateBuilder {
|
|
|
176
177
|
*/
|
|
177
178
|
export class Template {
|
|
178
179
|
private options: TemplateOptions = {};
|
|
179
|
-
|
|
180
|
-
private
|
|
180
|
+
/** The parsed code, keyed by whether it was parsed as an expression and by its parameters' declarations. */
|
|
181
|
+
private _cachedTemplates = new LRUCache<string, J>(10);
|
|
182
|
+
private _contextBindings?: Promise<ModuleScopeBinding[]>;
|
|
181
183
|
|
|
182
184
|
/**
|
|
183
185
|
* Creates a new template.
|
|
@@ -230,14 +232,14 @@ export class Template {
|
|
|
230
232
|
}
|
|
231
233
|
this.options = {...this.options, ...options};
|
|
232
234
|
// Invalidate cache when configuration changes
|
|
233
|
-
this.
|
|
235
|
+
this._cachedTemplates.clear();
|
|
234
236
|
this._contextBindings = undefined;
|
|
235
237
|
return this;
|
|
236
238
|
}
|
|
237
239
|
|
|
238
240
|
/**
|
|
239
|
-
* Gets the template tree for this template, using
|
|
240
|
-
* - Level 1: Instance cache (this.
|
|
241
|
+
* Gets the template tree for this template, using three-level caching:
|
|
242
|
+
* - Level 1: Instance cache (this._cachedTemplates) - fastest, no lookup needed
|
|
241
243
|
* - Level 2: Global cache (globalAstCache) - fast, shared across all templates
|
|
242
244
|
* - Level 3: TemplateEngine - slow, parses and processes the template
|
|
243
245
|
*
|
|
@@ -248,10 +250,15 @@ export class Template {
|
|
|
248
250
|
* @returns The cached or newly computed template tree
|
|
249
251
|
* @internal
|
|
250
252
|
*/
|
|
251
|
-
private async getTemplateTree(): Promise<J> {
|
|
253
|
+
private async getTemplateTree(expression: boolean, values?: Pick<Map<string, J | J[]>, 'get'>): Promise<J> {
|
|
254
|
+
// The types of the bound values shape the parse, so each set of them is a tree of its own
|
|
255
|
+
const preamble = TemplateEngine.parameterPreamble(this.parameters, values);
|
|
256
|
+
const instanceKey = `${expression}::${preamble.join('')}`;
|
|
257
|
+
|
|
252
258
|
// Level 1: Instance cache (fastest path)
|
|
253
|
-
|
|
254
|
-
|
|
259
|
+
const instanceCached = this._cachedTemplates.get(instanceKey);
|
|
260
|
+
if (instanceCached) {
|
|
261
|
+
return instanceCached;
|
|
255
262
|
}
|
|
256
263
|
|
|
257
264
|
// Generate cache key for global lookup
|
|
@@ -265,12 +272,11 @@ export class Template {
|
|
|
265
272
|
return `raw:${value.code}`;
|
|
266
273
|
}
|
|
267
274
|
return i.toString();
|
|
268
|
-
}).join(',');
|
|
275
|
+
}).join(',') + (expression ? '::expression' : '');
|
|
269
276
|
const cacheKey = generateCacheKey(
|
|
270
277
|
this.templateParts,
|
|
271
278
|
parametersKey,
|
|
272
|
-
|
|
273
|
-
[...contextStatements, ...TemplateEngine.parameterPreamble(this.parameters)],
|
|
279
|
+
[...contextStatements, ...preamble],
|
|
274
280
|
this.options.dependencies || {},
|
|
275
281
|
this.options.types
|
|
276
282
|
);
|
|
@@ -278,7 +284,7 @@ export class Template {
|
|
|
278
284
|
// Level 2: Global cache (fast path - shared with Pattern)
|
|
279
285
|
const cached = globalAstCache.get(cacheKey);
|
|
280
286
|
if (cached) {
|
|
281
|
-
this.
|
|
287
|
+
this._cachedTemplates.set(instanceKey, cached);
|
|
282
288
|
return cached;
|
|
283
289
|
}
|
|
284
290
|
|
|
@@ -288,34 +294,34 @@ export class Template {
|
|
|
288
294
|
this.parameters,
|
|
289
295
|
contextStatements,
|
|
290
296
|
this.options.dependencies || {},
|
|
291
|
-
this.options.types
|
|
297
|
+
this.options.types,
|
|
298
|
+
expression,
|
|
299
|
+
preamble
|
|
292
300
|
);
|
|
293
301
|
|
|
294
302
|
// Cache in both levels
|
|
295
303
|
globalAstCache.set(cacheKey, result);
|
|
296
|
-
this.
|
|
304
|
+
this._cachedTemplates.set(instanceKey, result);
|
|
297
305
|
|
|
298
306
|
return result;
|
|
299
307
|
}
|
|
300
308
|
|
|
301
309
|
/**
|
|
302
310
|
* Binds every module this template declares in the file `visitor` is traversing, and returns
|
|
303
|
-
* the local names to hand back through {@link ApplyOptions.bindings}.
|
|
304
|
-
*
|
|
305
|
-
*
|
|
311
|
+
* the local names to hand back through {@link ApplyOptions.bindings}. Each is bound outright, so
|
|
312
|
+
* call this where the template is known to apply — {@link RewriteRule.tryOn} does, once a pattern
|
|
313
|
+
* matched.
|
|
306
314
|
*/
|
|
307
315
|
async resolveBindings(visitor: JavaScriptVisitor<any>): Promise<Record<string, string>> {
|
|
308
316
|
const resolved: Record<string, string> = {};
|
|
309
317
|
for (const binding of await this.contextBindings()) {
|
|
310
|
-
//
|
|
311
|
-
// workspace could not resolve is bound whether or not the template turns out to use it.
|
|
312
|
-
const onlyIfReferenced = binding.attributed;
|
|
318
|
+
// The template's code reads every binding listed, which its attribution cannot always show
|
|
313
319
|
const bound = maybeBind(visitor, {
|
|
314
320
|
module: binding.module!,
|
|
315
321
|
member: binding.member,
|
|
316
322
|
typeOnly: binding.typeOnly,
|
|
317
323
|
preferredName: binding.name,
|
|
318
|
-
onlyIfReferenced
|
|
324
|
+
onlyIfReferenced: false
|
|
319
325
|
});
|
|
320
326
|
// An unresolved binding is left out rather than recorded as `undefined`, so `apply()`'s
|
|
321
327
|
// own "applied without a local name" check catches it, same as a caller-omitted one.
|
|
@@ -332,11 +338,11 @@ export class Template {
|
|
|
332
338
|
}
|
|
333
339
|
|
|
334
340
|
/** What this template's context statements bind, which is what it needs bound in the target file. */
|
|
335
|
-
private contextBindings(): Promise<
|
|
341
|
+
private contextBindings(): Promise<ModuleScopeBinding[]> {
|
|
336
342
|
return this._contextBindings ??= this.deriveContextBindings();
|
|
337
343
|
}
|
|
338
344
|
|
|
339
|
-
private deriveContextBindings(): Promise<
|
|
345
|
+
private deriveContextBindings(): Promise<ModuleScopeBinding[]> {
|
|
340
346
|
return TemplateEngine.getContextBindings(
|
|
341
347
|
this.templateParts, this.parameters,
|
|
342
348
|
this.options.context || this.options.imports || [],
|
|
@@ -408,7 +414,6 @@ export class Template {
|
|
|
408
414
|
}
|
|
409
415
|
|
|
410
416
|
const renames: Record<string, string> = {};
|
|
411
|
-
const modules: Record<string, string> = {};
|
|
412
417
|
// Supplying names is what asks for the context's modules to be bound in the file being
|
|
413
418
|
// edited; without them a context import only types the template.
|
|
414
419
|
if (options?.bindings !== undefined) {
|
|
@@ -420,12 +425,11 @@ export class Template {
|
|
|
420
425
|
`already did — binding was refused, which an AMD block or a file requiring its modules can do.`);
|
|
421
426
|
}
|
|
422
427
|
renames[binding.name] = bound;
|
|
423
|
-
modules[binding.name] = binding.module!;
|
|
424
428
|
}
|
|
425
429
|
}
|
|
426
430
|
|
|
427
|
-
|
|
428
|
-
const ast = await this.getTemplateTree();
|
|
431
|
+
const expression = opensWithBrace(this.templateParts) && replacedByObjectLiteral(tree, cursor);
|
|
432
|
+
const ast = await this.getTemplateTree(expression, normalizedValues);
|
|
429
433
|
|
|
430
434
|
// Delegate to TemplateEngine for placeholder substitution and application
|
|
431
435
|
return TemplateEngine.applyTemplateFromAst(
|
|
@@ -440,7 +444,8 @@ export class Template {
|
|
|
440
444
|
wrappersMap,
|
|
441
445
|
options?.format ?? true,
|
|
442
446
|
renames,
|
|
443
|
-
|
|
447
|
+
// Unformatted, a capture the template spaces as the pattern did keeps the source's spacing
|
|
448
|
+
options?.format === false && values instanceof MatchResult ? values[PATTERN_PREFIXES_SYMBOL]() : undefined
|
|
444
449
|
);
|
|
445
450
|
}
|
|
446
451
|
}
|
|
@@ -533,9 +533,12 @@ export interface ApplyOptions {
|
|
|
533
533
|
values?: Map<Capture | string, J> | MatchResult | Record<string, J>;
|
|
534
534
|
|
|
535
535
|
/**
|
|
536
|
-
* Whether the
|
|
537
|
-
*
|
|
538
|
-
*
|
|
536
|
+
* Whether the template's own code is fitted to where it lands. Defaults to `true`. A substituted
|
|
537
|
+
* capture, parameter or container is only re-indented to the file's style, and keeps its line
|
|
538
|
+
* breaks and spacing.
|
|
539
|
+
* In a file Prettier formats, Prettier lays out the whole result.
|
|
540
|
+
* Pass `false` to assemble several results into one subtree and format that subtree once, rather
|
|
541
|
+
* than once per application. The anchor supplies the result's prefix either way.
|
|
539
542
|
*/
|
|
540
543
|
format?: boolean;
|
|
541
544
|
|
|
@@ -35,12 +35,23 @@ export type CaptureStorageValue = J | J.RightPadded<J> | J[] | J.RightPadded<J>[
|
|
|
35
35
|
*/
|
|
36
36
|
export const WRAPPERS_MAP_SYMBOL = Symbol('wrappersMap');
|
|
37
37
|
|
|
38
|
+
/** Symbol to access a match's pattern prefixes without exposing them as public API */
|
|
39
|
+
export const PATTERN_PREFIXES_SYMBOL = Symbol('patternPrefixes');
|
|
40
|
+
|
|
38
41
|
/**
|
|
39
42
|
* Shared wrapper function name used by both patterns and templates.
|
|
40
43
|
* Using the same name allows cache sharing when pattern and template code is identical.
|
|
41
44
|
*/
|
|
42
45
|
export const WRAPPER_FUNCTION_NAME = '__WRAPPER__';
|
|
43
46
|
|
|
47
|
+
/** The module of the file every template and pattern parses as. */
|
|
48
|
+
export const TEMPLATE_MODULE = 'template';
|
|
49
|
+
|
|
50
|
+
/** Template or pattern code as the body of the wrapper function, parenthesized to parse as an expression. */
|
|
51
|
+
export function wrapCode(code: string, expression: boolean): string {
|
|
52
|
+
return `function ${WRAPPER_FUNCTION_NAME}() { ${expression ? `(${code})` : code} }`;
|
|
53
|
+
}
|
|
54
|
+
|
|
44
55
|
/**
|
|
45
56
|
* Simple LRU (Least Recently Used) cache implementation using Map's insertion order.
|
|
46
57
|
* JavaScript Map maintains insertion order, so the first entry is the oldest.
|
|
@@ -329,6 +340,15 @@ export class PlaceholderUtils {
|
|
|
329
340
|
return undefined;
|
|
330
341
|
}
|
|
331
342
|
|
|
343
|
+
/** The name of a shorthand property, which is what a placeholder written as `{${x}}` parses to. */
|
|
344
|
+
static shorthandPropertyName(node: J): J | undefined {
|
|
345
|
+
if (node.kind === JS.Kind.PropertyAssignment) {
|
|
346
|
+
const property = node as JS.PropertyAssignment;
|
|
347
|
+
return property.initializer === undefined ? property.name.element : undefined;
|
|
348
|
+
}
|
|
349
|
+
return undefined;
|
|
350
|
+
}
|
|
351
|
+
|
|
332
352
|
/**
|
|
333
353
|
* Extracts the relevant AST node from a wrapper function.
|
|
334
354
|
* Used by both pattern and template processors to intelligently extract
|
|
@@ -336,9 +356,10 @@ export class PlaceholderUtils {
|
|
|
336
356
|
*
|
|
337
357
|
* @param lastStatement The last statement from the compilation unit
|
|
338
358
|
* @param contextName Context name for error messages (e.g., 'Pattern', 'Template')
|
|
359
|
+
* @param expression Whether {@link wrapCode} parenthesized the code
|
|
339
360
|
* @returns The extracted AST node
|
|
340
361
|
*/
|
|
341
|
-
static extractFromWrapper(lastStatement: J, contextName: string): J {
|
|
362
|
+
static extractFromWrapper(lastStatement: J, contextName: string, expression: boolean = false): J {
|
|
342
363
|
let extracted: J;
|
|
343
364
|
|
|
344
365
|
// Since we always wrap in function __WRAPPER__() { code }, look for it
|
|
@@ -378,6 +399,7 @@ export class PlaceholderUtils {
|
|
|
378
399
|
extracted = lastStatement;
|
|
379
400
|
}
|
|
380
401
|
|
|
381
|
-
return extracted
|
|
402
|
+
return expression && extracted.kind === J.Kind.Parentheses ?
|
|
403
|
+
(extracted as J.Parentheses<J>).tree.element : extracted;
|
|
382
404
|
}
|
|
383
405
|
}
|
|
@@ -18,6 +18,7 @@ import {Cursor, Tree} from "../tree";
|
|
|
18
18
|
import {Comment, isIdentifier, isJava, isLiteral, J, TextComment} from "../java";
|
|
19
19
|
import {JS} from "./tree";
|
|
20
20
|
import {JavaScriptVisitor} from "./visitor";
|
|
21
|
+
import {renderNodeType} from "./type-report";
|
|
21
22
|
import * as fs from "fs";
|
|
22
23
|
|
|
23
24
|
/**
|
|
@@ -38,6 +39,8 @@ export interface LstDebugOptions {
|
|
|
38
39
|
includeMarkers?: boolean;
|
|
39
40
|
/** Include node IDs in output. Default: false */
|
|
40
41
|
includeIds?: boolean;
|
|
42
|
+
/** Include each node's rendered type, as the type report renders it. Default: false */
|
|
43
|
+
includeTypes?: boolean;
|
|
41
44
|
/** Maximum depth to traverse (for print/recursive methods). Default: unlimited (-1) */
|
|
42
45
|
maxDepth?: number;
|
|
43
46
|
/** Properties to always exclude (in addition to defaults like 'type'). */
|
|
@@ -52,6 +55,7 @@ const DEFAULT_OPTIONS: Required<LstDebugOptions> = {
|
|
|
52
55
|
includeCursorMessages: true,
|
|
53
56
|
includeMarkers: false,
|
|
54
57
|
includeIds: false,
|
|
58
|
+
includeTypes: false,
|
|
55
59
|
maxDepth: -1,
|
|
56
60
|
excludeProperties: [],
|
|
57
61
|
output: 'console',
|
|
@@ -776,6 +780,11 @@ export class LstDebugPrinter {
|
|
|
776
780
|
header += ` (id=${node.id.substring(0, 8)}...)`;
|
|
777
781
|
}
|
|
778
782
|
|
|
783
|
+
const type = this.options.includeTypes ? renderNodeType(node) : undefined;
|
|
784
|
+
if (type !== undefined) {
|
|
785
|
+
header += ` : ${type}`;
|
|
786
|
+
}
|
|
787
|
+
|
|
779
788
|
this.outputLines.push(header);
|
|
780
789
|
|
|
781
790
|
// Print prefix
|
|
@@ -144,30 +144,20 @@ export class TsConfigResolver {
|
|
|
144
144
|
resolution[option] = projectOptions[option];
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
|
-
if (resolution.moduleResolution
|
|
148
|
-
|
|
149
|
-
if (paired !== undefined) {
|
|
150
|
-
resolution.moduleResolution = paired;
|
|
151
|
-
}
|
|
147
|
+
if (isNodeModuleResolution(resolution.moduleResolution)) {
|
|
148
|
+
delete resolution.moduleResolution;
|
|
152
149
|
}
|
|
153
150
|
return {...defaults, ...resolution};
|
|
154
151
|
}
|
|
155
152
|
}
|
|
156
153
|
|
|
157
154
|
/**
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
* `Classic` is declined as well, searching no `node_modules`, so the default stands in.
|
|
155
|
+
* Under the pinned `preserve` module kind every import resolves in ESM mode, where the `node16`
|
|
156
|
+
* family demands extensions on relative paths (TypeScript rejects the pairing, TS5110). The default
|
|
157
|
+
* `bundler` picks the same `import` branch of a dual package without that demand.
|
|
162
158
|
*/
|
|
163
|
-
function
|
|
164
|
-
|
|
165
|
-
.getEmitModuleResolutionKind;
|
|
166
|
-
if (projectOptions.module === undefined || !infer) {
|
|
167
|
-
return undefined;
|
|
168
|
-
}
|
|
169
|
-
const inferred = infer(projectOptions);
|
|
170
|
-
return inferred === ts.ModuleResolutionKind.Classic ? undefined : inferred;
|
|
159
|
+
function isNodeModuleResolution(kind: ts.ModuleResolutionKind | undefined): boolean {
|
|
160
|
+
return kind === ts.ModuleResolutionKind.Node16 || kind === ts.ModuleResolutionKind.NodeNext;
|
|
171
161
|
}
|
|
172
162
|
|
|
173
163
|
function isAtOrUnder(dir: string, root: string): boolean {
|