@openrewrite/rewrite 8.62.3 → 8.62.5
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.map +1 -1
- package/dist/execution.js.map +1 -1
- package/dist/java/rpc.d.ts +1 -0
- package/dist/java/rpc.d.ts.map +1 -1
- package/dist/java/rpc.js +81 -0
- package/dist/java/rpc.js.map +1 -1
- package/dist/java/tree.d.ts +12 -6
- package/dist/java/tree.d.ts.map +1 -1
- package/dist/java/tree.js +12 -92
- package/dist/java/tree.js.map +1 -1
- package/dist/java/type.d.ts +2 -0
- package/dist/java/type.d.ts.map +1 -1
- package/dist/java/type.js +12 -0
- package/dist/java/type.js.map +1 -1
- package/dist/java/visitor.d.ts +12 -4
- package/dist/java/visitor.d.ts.map +1 -1
- package/dist/java/visitor.js +23 -1
- package/dist/java/visitor.js.map +1 -1
- package/dist/javascript/format.d.ts +2 -2
- package/dist/javascript/format.d.ts.map +1 -1
- package/dist/javascript/format.js.map +1 -1
- package/dist/javascript/index.d.ts +3 -0
- package/dist/javascript/index.d.ts.map +1 -1
- package/dist/javascript/index.js +3 -0
- package/dist/javascript/index.js.map +1 -1
- package/dist/javascript/method-matcher.d.ts +16 -0
- package/dist/javascript/method-matcher.d.ts.map +1 -0
- package/dist/javascript/method-matcher.js +222 -0
- package/dist/javascript/method-matcher.js.map +1 -0
- package/dist/javascript/parser.d.ts +1 -1
- package/dist/javascript/parser.d.ts.map +1 -1
- package/dist/javascript/parser.js +27 -5
- package/dist/javascript/parser.js.map +1 -1
- package/dist/javascript/preconditions.d.ts +6 -0
- package/dist/javascript/preconditions.d.ts.map +1 -0
- package/dist/javascript/preconditions.js +58 -0
- package/dist/javascript/preconditions.js.map +1 -0
- package/dist/javascript/print.d.ts +2 -2
- package/dist/javascript/print.d.ts.map +1 -1
- package/dist/javascript/print.js.map +1 -1
- package/dist/javascript/remove-import.d.ts +56 -0
- package/dist/javascript/remove-import.d.ts.map +1 -0
- package/dist/javascript/remove-import.js +715 -0
- package/dist/javascript/remove-import.js.map +1 -0
- package/dist/javascript/rpc.js +3 -18
- package/dist/javascript/rpc.js.map +1 -1
- package/dist/javascript/search/index.d.ts +3 -0
- package/dist/javascript/search/index.d.ts.map +1 -0
- package/dist/javascript/search/index.js +19 -0
- package/dist/javascript/search/index.js.map +1 -0
- package/dist/javascript/search/uses-method.d.ts +8 -0
- package/dist/javascript/search/uses-method.d.ts.map +1 -0
- package/dist/javascript/search/uses-method.js +35 -0
- package/dist/javascript/search/uses-method.js.map +1 -0
- package/dist/javascript/search/uses-type.d.ts +8 -0
- package/dist/javascript/search/uses-type.d.ts.map +1 -0
- package/dist/javascript/search/uses-type.js +71 -0
- package/dist/javascript/search/uses-type.js.map +1 -0
- package/dist/javascript/templating.d.ts +1 -1
- package/dist/javascript/templating.d.ts.map +1 -1
- package/dist/javascript/templating.js +1 -1
- package/dist/javascript/templating.js.map +1 -1
- package/dist/javascript/tree.d.ts +3 -3
- package/dist/javascript/tree.d.ts.map +1 -1
- package/dist/javascript/tree.js +28 -0
- package/dist/javascript/tree.js.map +1 -1
- package/dist/javascript/type-mapping.d.ts +7 -18
- package/dist/javascript/type-mapping.d.ts.map +1 -1
- package/dist/javascript/type-mapping.js +290 -203
- package/dist/javascript/type-mapping.js.map +1 -1
- package/dist/javascript/visitor.d.ts +1 -1
- package/dist/javascript/visitor.d.ts.map +1 -1
- package/dist/javascript/visitor.js +1 -1
- package/dist/javascript/visitor.js.map +1 -1
- package/dist/json/print.js.map +1 -1
- package/dist/json/rpc.js +46 -17
- package/dist/json/rpc.js.map +1 -1
- package/dist/json/visitor.d.ts +2 -2
- package/dist/json/visitor.d.ts.map +1 -1
- package/dist/json/visitor.js.map +1 -1
- package/dist/print.d.ts +1 -0
- package/dist/print.d.ts.map +1 -1
- package/dist/print.js +6 -0
- package/dist/print.js.map +1 -1
- package/dist/rpc/queue.d.ts +15 -6
- package/dist/rpc/queue.d.ts.map +1 -1
- package/dist/rpc/queue.js +37 -13
- package/dist/rpc/queue.js.map +1 -1
- package/dist/rpc/request/generate.d.ts +4 -0
- package/dist/rpc/request/generate.d.ts.map +1 -1
- package/dist/rpc/request/generate.js +9 -4
- package/dist/rpc/request/generate.js.map +1 -1
- package/dist/rpc/request/get-object.d.ts +2 -2
- package/dist/rpc/request/get-object.d.ts.map +1 -1
- package/dist/rpc/request/get-object.js +4 -12
- 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.map +1 -1
- package/dist/rpc/request/print.d.ts +1 -1
- package/dist/rpc/request/print.d.ts.map +1 -1
- package/dist/rpc/request/print.js +1 -1
- package/dist/rpc/request/print.js.map +1 -1
- package/dist/rpc/request/visit.d.ts +3 -2
- package/dist/rpc/request/visit.d.ts.map +1 -1
- package/dist/rpc/request/visit.js +5 -4
- package/dist/rpc/request/visit.js.map +1 -1
- package/dist/rpc/rewrite-rpc.d.ts +4 -4
- package/dist/rpc/rewrite-rpc.d.ts.map +1 -1
- package/dist/rpc/rewrite-rpc.js +16 -17
- package/dist/rpc/rewrite-rpc.js.map +1 -1
- package/dist/search/index.d.ts +2 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +18 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/is-source-file.d.ts +8 -0
- package/dist/search/is-source-file.d.ts.map +1 -0
- package/dist/search/is-source-file.js +70 -0
- package/dist/search/is-source-file.js.map +1 -0
- package/dist/test/rewrite-test.d.ts.map +1 -1
- package/dist/test/rewrite-test.js +3 -0
- package/dist/test/rewrite-test.js.map +1 -1
- package/dist/text/rpc.js +37 -40
- package/dist/text/rpc.js.map +1 -1
- package/dist/util.d.ts +1 -0
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +13 -0
- package/dist/util.js.map +1 -1
- package/dist/version.txt +1 -1
- package/dist/visitor.d.ts +1 -1
- package/dist/visitor.d.ts.map +1 -1
- package/dist/visitor.js +3 -2
- package/dist/visitor.js.map +1 -1
- package/package.json +3 -1
- package/src/execution.ts +0 -2
- package/src/java/rpc.ts +68 -0
- package/src/java/tree.ts +20 -76
- package/src/java/type.ts +14 -0
- package/src/java/visitor.ts +32 -12
- package/src/javascript/format.ts +2 -2
- package/src/javascript/index.ts +4 -0
- package/src/javascript/method-matcher.ts +250 -0
- package/src/javascript/parser.ts +20 -6
- package/src/javascript/preconditions.ts +40 -0
- package/src/javascript/print.ts +3 -3
- package/src/javascript/remove-import.ts +780 -0
- package/src/javascript/rpc.ts +6 -19
- package/src/javascript/search/index.ts +2 -0
- package/src/javascript/search/uses-method.ts +21 -0
- package/src/javascript/search/uses-type.ts +27 -0
- package/src/javascript/templating.ts +4 -3
- package/src/javascript/tree.ts +47 -3
- package/src/javascript/type-mapping.ts +320 -214
- package/src/javascript/visitor.ts +126 -126
- package/src/json/print.ts +1 -1
- package/src/json/rpc.ts +40 -19
- package/src/json/visitor.ts +2 -2
- package/src/print.ts +9 -3
- package/src/rpc/queue.ts +36 -12
- package/src/rpc/request/generate.ts +18 -6
- package/src/rpc/request/get-object.ts +6 -13
- package/src/rpc/request/parse.ts +1 -1
- package/src/rpc/request/print.ts +2 -2
- package/src/rpc/request/visit.ts +6 -5
- package/src/rpc/rewrite-rpc.ts +22 -21
- package/src/search/index.ts +1 -0
- package/src/search/is-source-file.ts +26 -0
- package/src/test/rewrite-test.ts +5 -2
- package/src/text/rpc.ts +33 -37
- package/src/util.ts +19 -4
- package/src/visitor.ts +3 -3
package/src/rpc/queue.ts
CHANGED
|
@@ -46,37 +46,58 @@ export interface RpcCodec<T> {
|
|
|
46
46
|
* A registry for managing RPC codecs based on object types.
|
|
47
47
|
*/
|
|
48
48
|
export class RpcCodecs {
|
|
49
|
-
private static
|
|
49
|
+
private static nonTreeCodecs = new Map<string, RpcCodec<any>>();
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The first key is on sourceFileType and the second on object type
|
|
53
|
+
*/
|
|
54
|
+
private static treeCodecs = new Map<string, Map<string, RpcCodec<any>>>();
|
|
50
55
|
|
|
51
56
|
/**
|
|
52
57
|
* Registers an RPC codec for a given type.
|
|
53
58
|
*
|
|
54
59
|
* @param type - The string identifier of the object type.
|
|
55
60
|
* @param codec - The codec implementation to be registered.
|
|
61
|
+
* @param sourceFileType The source file type of the source file containing (or will contain) this element.
|
|
56
62
|
*/
|
|
57
|
-
static registerCodec(type: string, codec: RpcCodec<any
|
|
58
|
-
|
|
63
|
+
static registerCodec(type: string, codec: RpcCodec<any>, sourceFileType?: string): void {
|
|
64
|
+
if (sourceFileType) {
|
|
65
|
+
let codecsForSourceFile = this.treeCodecs.get(sourceFileType);
|
|
66
|
+
if (!codecsForSourceFile) {
|
|
67
|
+
codecsForSourceFile = new Map<string, RpcCodec<any>>();
|
|
68
|
+
this.treeCodecs.set(sourceFileType, codecsForSourceFile);
|
|
69
|
+
}
|
|
70
|
+
codecsForSourceFile.set(type, codec);
|
|
71
|
+
} else {
|
|
72
|
+
this.nonTreeCodecs.set(type, codec);
|
|
73
|
+
}
|
|
59
74
|
}
|
|
60
75
|
|
|
61
76
|
/**
|
|
62
77
|
* Retrieves the registered codec for a given type.
|
|
63
78
|
*
|
|
64
79
|
* @param type - The string identifier of the object type.
|
|
80
|
+
* @param sourceFileType The source file type of the source file containing (or will contain) this element.
|
|
65
81
|
* @returns The corresponding `RpcCodec`, or `undefined` if not found.
|
|
66
82
|
*/
|
|
67
|
-
static forType(type: string): RpcCodec<any> | undefined {
|
|
68
|
-
|
|
83
|
+
static forType(type: string, sourceFileType?: string): RpcCodec<any> | undefined {
|
|
84
|
+
if (sourceFileType) {
|
|
85
|
+
const treeCodec = this.treeCodecs.get(sourceFileType)?.get(type);
|
|
86
|
+
return treeCodec || this.nonTreeCodecs.get(type);
|
|
87
|
+
}
|
|
88
|
+
return this.nonTreeCodecs.get(type);
|
|
69
89
|
}
|
|
70
90
|
|
|
71
91
|
/**
|
|
72
92
|
* Determines the appropriate codec for an instance based on its `kind` property.
|
|
73
93
|
*
|
|
74
94
|
* @param before - The object instance to find a codec for.
|
|
95
|
+
* @param sourceFileType The source file type of the source file containing (or will contain) this element.
|
|
75
96
|
* @returns The corresponding `RpcCodec`, or `undefined` if no matching codec is found.
|
|
76
97
|
*/
|
|
77
|
-
static forInstance(before: any): RpcCodec<any> | undefined {
|
|
98
|
+
static forInstance(before: any, sourceFileType?: string): RpcCodec<any> | undefined {
|
|
78
99
|
if (before !== undefined && before !== null && typeof before === "object" && "kind" in before) {
|
|
79
|
-
return RpcCodecs.forType(before["kind"] as string);
|
|
100
|
+
return RpcCodecs.forType(before["kind"] as string, sourceFileType);
|
|
80
101
|
}
|
|
81
102
|
}
|
|
82
103
|
}
|
|
@@ -86,7 +107,9 @@ export class RpcSendQueue {
|
|
|
86
107
|
|
|
87
108
|
private before?: any;
|
|
88
109
|
|
|
89
|
-
constructor(private readonly refs: ReferenceMap,
|
|
110
|
+
constructor(private readonly refs: ReferenceMap,
|
|
111
|
+
private readonly sourceFileType: string | undefined,
|
|
112
|
+
private readonly trace: boolean) {
|
|
90
113
|
}
|
|
91
114
|
|
|
92
115
|
async generate(after: any, before: any): Promise<RpcObjectData[]> {
|
|
@@ -132,7 +155,7 @@ export class RpcSendQueue {
|
|
|
132
155
|
} else if (after === undefined) {
|
|
133
156
|
this.put({state: RpcObjectState.DELETE});
|
|
134
157
|
} else {
|
|
135
|
-
let afterCodec = onChange ? undefined : RpcCodecs.forInstance(after);
|
|
158
|
+
let afterCodec = onChange ? undefined : RpcCodecs.forInstance(after, this.sourceFileType);
|
|
136
159
|
this.put({state: RpcObjectState.CHANGE, value: onChange || afterCodec ? undefined : after});
|
|
137
160
|
await this.doChange(after, before, onChange, afterCodec);
|
|
138
161
|
}
|
|
@@ -161,7 +184,7 @@ export class RpcSendQueue {
|
|
|
161
184
|
this.put({state: RpcObjectState.NO_CHANGE});
|
|
162
185
|
} else {
|
|
163
186
|
this.put({state: RpcObjectState.CHANGE});
|
|
164
|
-
await this.doChange(anAfter, aBefore, onChangeRun, RpcCodecs.forInstance(anAfter));
|
|
187
|
+
await this.doChange(anAfter, aBefore, onChangeRun, RpcCodecs.forInstance(anAfter, this.sourceFileType));
|
|
165
188
|
}
|
|
166
189
|
}
|
|
167
190
|
}
|
|
@@ -199,7 +222,7 @@ export class RpcSendQueue {
|
|
|
199
222
|
}
|
|
200
223
|
ref = this.refs.create(after);
|
|
201
224
|
}
|
|
202
|
-
let afterCodec = onChange ? undefined : RpcCodecs.forInstance(after);
|
|
225
|
+
let afterCodec = onChange ? undefined : RpcCodecs.forInstance(after, this.sourceFileType);
|
|
203
226
|
this.put({
|
|
204
227
|
state: RpcObjectState.ADD,
|
|
205
228
|
valueType: this.getValueType(after),
|
|
@@ -236,6 +259,7 @@ export class RpcReceiveQueue {
|
|
|
236
259
|
private batch: RpcObjectData[] = [];
|
|
237
260
|
|
|
238
261
|
constructor(private readonly refs: Map<number, any>,
|
|
262
|
+
private readonly sourceFileType: string | undefined,
|
|
239
263
|
private readonly pull: () => Promise<RpcObjectData[]>,
|
|
240
264
|
private readonly logFile?: Writable) {
|
|
241
265
|
}
|
|
@@ -301,7 +325,7 @@ export class RpcReceiveQueue {
|
|
|
301
325
|
let codec;
|
|
302
326
|
if (onChange) {
|
|
303
327
|
after = await onChange(before!);
|
|
304
|
-
} else if ((codec = RpcCodecs.forInstance(before))) {
|
|
328
|
+
} else if ((codec = RpcCodecs.forInstance(before, this.sourceFileType))) {
|
|
305
329
|
after = await codec.rpcReceive(before, this);
|
|
306
330
|
} else if (message.value !== undefined) {
|
|
307
331
|
after = message.valueType ? {kind: message.valueType, ...message.value} : message.value;
|
|
@@ -17,7 +17,11 @@ import * as rpc from "vscode-jsonrpc/node";
|
|
|
17
17
|
import {Recipe, ScanningRecipe} from "../../recipe";
|
|
18
18
|
import {Cursor, rootCursor} from "../../tree";
|
|
19
19
|
import {ExecutionContext} from "../../execution";
|
|
20
|
-
|
|
20
|
+
|
|
21
|
+
export interface GenerateResponse {
|
|
22
|
+
ids: string[]
|
|
23
|
+
sourceFileTypes: string[]
|
|
24
|
+
}
|
|
21
25
|
|
|
22
26
|
export class Generate {
|
|
23
27
|
constructor(private readonly id: string, private readonly p: string) {
|
|
@@ -28,8 +32,13 @@ export class Generate {
|
|
|
28
32
|
preparedRecipes: Map<String, Recipe>,
|
|
29
33
|
recipeCursors: WeakMap<Recipe, Cursor>,
|
|
30
34
|
getObject: (id: string) => any): void {
|
|
31
|
-
connection.onRequest(new rpc.RequestType<Generate,
|
|
35
|
+
connection.onRequest(new rpc.RequestType<Generate, GenerateResponse, Error>("Generate"), async (request) => {
|
|
32
36
|
const recipe = preparedRecipes.get(request.id);
|
|
37
|
+
const response = {
|
|
38
|
+
ids: [],
|
|
39
|
+
sourceFileTypes: []
|
|
40
|
+
} as GenerateResponse;
|
|
41
|
+
|
|
33
42
|
if (recipe && recipe instanceof ScanningRecipe) {
|
|
34
43
|
let cursor = recipeCursors.get(recipe);
|
|
35
44
|
if (!cursor) {
|
|
@@ -39,12 +48,15 @@ export class Generate {
|
|
|
39
48
|
const ctx = getObject(request.p) as ExecutionContext;
|
|
40
49
|
const acc = recipe.accumulator(cursor, ctx);
|
|
41
50
|
const generated = await recipe.generate(acc, ctx)
|
|
42
|
-
|
|
51
|
+
|
|
52
|
+
for (const g of generated) {
|
|
43
53
|
localObjects.set(g.id.toString(), g);
|
|
44
|
-
|
|
45
|
-
|
|
54
|
+
response.ids.push(g.id.toString());
|
|
55
|
+
response.sourceFileTypes.push(g.kind);
|
|
56
|
+
}
|
|
57
|
+
|
|
46
58
|
}
|
|
47
|
-
return
|
|
59
|
+
return response;
|
|
48
60
|
});
|
|
49
61
|
}
|
|
50
62
|
}
|
|
@@ -18,7 +18,8 @@ import {RpcObjectData, RpcObjectState, RpcSendQueue} from "../queue";
|
|
|
18
18
|
import {ReferenceMap} from "../../reference";
|
|
19
19
|
|
|
20
20
|
export class GetObject {
|
|
21
|
-
constructor(private readonly id: string,
|
|
21
|
+
constructor(private readonly id: string,
|
|
22
|
+
private readonly sourceFileType?: string) {
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
static handle(
|
|
@@ -49,18 +50,9 @@ export class GetObject {
|
|
|
49
50
|
let allData = pendingData.get(objId);
|
|
50
51
|
if (!allData) {
|
|
51
52
|
const after = localObjects.get(objId);
|
|
52
|
-
|
|
53
|
-
// Determine what the remote has cached
|
|
54
|
-
let before = undefined;
|
|
55
|
-
if (request.lastKnownId) {
|
|
56
|
-
before = remoteObjects.get(request.lastKnownId);
|
|
57
|
-
if (before === undefined) {
|
|
58
|
-
// Remote had something cached, but we've evicted it - must send full object
|
|
59
|
-
remoteObjects.delete(request.lastKnownId);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
53
|
+
const before = remoteObjects.get(objId);
|
|
62
54
|
|
|
63
|
-
allData = await new RpcSendQueue(localRefs, trace).generate(after, before);
|
|
55
|
+
allData = await new RpcSendQueue(localRefs, request.sourceFileType, trace).generate(after, before);
|
|
64
56
|
pendingData.set(objId, allData);
|
|
65
57
|
|
|
66
58
|
remoteObjects.set(objId, after);
|
|
@@ -75,4 +67,5 @@ export class GetObject {
|
|
|
75
67
|
|
|
76
68
|
return batch;
|
|
77
69
|
});
|
|
78
|
-
}
|
|
70
|
+
}
|
|
71
|
+
}
|
package/src/rpc/request/parse.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import * as rpc from "vscode-jsonrpc/node";
|
|
17
17
|
import {ExecutionContext} from "../../execution";
|
|
18
18
|
import {UUID} from "node:crypto";
|
|
19
|
-
import {
|
|
19
|
+
import {ParserInput, Parsers} from "../../parser";
|
|
20
20
|
import {randomId} from "../../uuid";
|
|
21
21
|
import {produce} from "immer";
|
|
22
22
|
import {SourceFile} from "../../tree";
|
package/src/rpc/request/print.ts
CHANGED
|
@@ -29,9 +29,9 @@ export class Print {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
static handle(connection: rpc.MessageConnection,
|
|
32
|
-
getObject: (id: string) => any): void {
|
|
32
|
+
getObject: (id: string, sourceFileType?: string) => any): void {
|
|
33
33
|
connection.onRequest(new rpc.RequestType<Print, string, Error>("Print"), async request => {
|
|
34
|
-
const tree: Tree = await getObject(request.treeId.toString());
|
|
34
|
+
const tree: Tree = await getObject(request.treeId.toString(), request.sourceFileType);
|
|
35
35
|
const out = new PrintOutputCapture(PrintMarkerPrinter[request.markerPrinter]);
|
|
36
36
|
if (isSourceFile(tree)) {
|
|
37
37
|
return await printer(tree).print(tree, out);
|
package/src/rpc/request/visit.ts
CHANGED
|
@@ -25,6 +25,7 @@ export interface VisitResponse {
|
|
|
25
25
|
|
|
26
26
|
export class Visit {
|
|
27
27
|
constructor(private readonly visitor: string,
|
|
28
|
+
private readonly sourceFileType: string,
|
|
28
29
|
private readonly visitorOptions: Map<string, any> | undefined,
|
|
29
30
|
private readonly treeId: string,
|
|
30
31
|
private readonly p: string,
|
|
@@ -35,15 +36,15 @@ export class Visit {
|
|
|
35
36
|
localObjects: Map<string, any>,
|
|
36
37
|
preparedRecipes: Map<String, Recipe>,
|
|
37
38
|
recipeCursors: WeakMap<Recipe, Cursor>,
|
|
38
|
-
getObject: (id: string) => any,
|
|
39
|
-
getCursor: (cursorIds: string[] | undefined) => Promise<Cursor>): void {
|
|
39
|
+
getObject: (id: string, sourceFileType?: string) => any,
|
|
40
|
+
getCursor: (cursorIds: string[] | undefined, sourceFileType?: string) => Promise<Cursor>): void {
|
|
40
41
|
connection.onRequest(new rpc.RequestType<Visit, VisitResponse, Error>("Visit"), async (request) => {
|
|
41
|
-
const p = await getObject(request.p);
|
|
42
|
-
const before: Tree = await getObject(request.treeId);
|
|
42
|
+
const p = await getObject(request.p, undefined);
|
|
43
|
+
const before: Tree = await getObject(request.treeId, request.sourceFileType);
|
|
43
44
|
localObjects.set(before.id.toString(), before);
|
|
44
45
|
|
|
45
46
|
const visitor = await Visit.instantiateVisitor(request, preparedRecipes, recipeCursors, p);
|
|
46
|
-
const after = await visitor.visit(before, p, await getCursor(request.cursor));
|
|
47
|
+
const after = await visitor.visit(before, p, await getCursor(request.cursor, request.sourceFileType));
|
|
47
48
|
if (!after) {
|
|
48
49
|
localObjects.delete(before.id.toString());
|
|
49
50
|
} else if (after !== before) {
|
package/src/rpc/rewrite-rpc.ts
CHANGED
|
@@ -19,7 +19,7 @@ import {Cursor, isSourceFile, isTree, rootCursor, SourceFile, Tree} from "../tre
|
|
|
19
19
|
import {Recipe, RecipeDescriptor, RecipeRegistry} from "../recipe";
|
|
20
20
|
import {SnowflakeId} from "@akashrajpurohit/snowflake-id";
|
|
21
21
|
import {
|
|
22
|
-
Generate,
|
|
22
|
+
Generate, GenerateResponse,
|
|
23
23
|
GetObject,
|
|
24
24
|
GetRecipes,
|
|
25
25
|
Parse,
|
|
@@ -69,8 +69,8 @@ export class RewriteRpc {
|
|
|
69
69
|
const recipeCursors: WeakMap<Recipe, Cursor> = new WeakMap()
|
|
70
70
|
|
|
71
71
|
// Need this indirection, otherwise `this` will be undefined when executed in the handlers.
|
|
72
|
-
const getObject = (id: string) => this.getObject(id);
|
|
73
|
-
const getCursor = (cursorIds: string[] | undefined) => this.getCursor(cursorIds);
|
|
72
|
+
const getObject = (id: string, sourceFileType?: string) => this.getObject(id, sourceFileType);
|
|
73
|
+
const getCursor = (cursorIds: string[] | undefined, sourceFileType?: string) => this.getCursor(cursorIds, sourceFileType);
|
|
74
74
|
|
|
75
75
|
const registry = options.registry || new RecipeRegistry();
|
|
76
76
|
|
|
@@ -92,10 +92,7 @@ export class RewriteRpc {
|
|
|
92
92
|
this._global = value;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
static get(): RewriteRpc {
|
|
96
|
-
if (!this._global) {
|
|
97
|
-
throw new Error("RewriteRpc not initialized");
|
|
98
|
-
}
|
|
95
|
+
static get(): RewriteRpc | undefined {
|
|
99
96
|
return this._global;
|
|
100
97
|
}
|
|
101
98
|
|
|
@@ -104,14 +101,13 @@ export class RewriteRpc {
|
|
|
104
101
|
return this;
|
|
105
102
|
}
|
|
106
103
|
|
|
107
|
-
async getObject<P>(id: string): Promise<P> {
|
|
104
|
+
async getObject<P>(id: string, sourceFileType?: string): Promise<P> {
|
|
108
105
|
const localObject = this.localObjects.get(id);
|
|
109
|
-
const lastKnownId = localObject ? id : undefined;
|
|
110
106
|
|
|
111
|
-
const q = new RpcReceiveQueue(this.remoteRefs, () => {
|
|
107
|
+
const q = new RpcReceiveQueue(this.remoteRefs, sourceFileType, () => {
|
|
112
108
|
return this.connection.sendRequest(
|
|
113
109
|
new rpc.RequestType<GetObject, RpcObjectData[], Error>("GetObject"),
|
|
114
|
-
new GetObject(id,
|
|
110
|
+
new GetObject(id, sourceFileType)
|
|
115
111
|
);
|
|
116
112
|
}, this.options.traceGetObjectInput);
|
|
117
113
|
|
|
@@ -128,11 +124,11 @@ export class RewriteRpc {
|
|
|
128
124
|
return remoteObject;
|
|
129
125
|
}
|
|
130
126
|
|
|
131
|
-
async getCursor(cursorIds: string[] | undefined): Promise<Cursor> {
|
|
127
|
+
async getCursor(cursorIds: string[] | undefined, sourceFileType?: string): Promise<Cursor> {
|
|
132
128
|
let cursor = rootCursor();
|
|
133
129
|
if (cursorIds) {
|
|
134
130
|
for (let i = cursorIds.length - 1; i >= 0; i--) {
|
|
135
|
-
const cursorObject = await this.getObject(cursorIds[i]);
|
|
131
|
+
const cursorObject = await this.getObject(cursorIds[i], sourceFileType);
|
|
136
132
|
this.remoteObjects.set(cursorIds[i], cursorObject);
|
|
137
133
|
cursor = new Cursor(cursorObject, cursor);
|
|
138
134
|
}
|
|
@@ -140,13 +136,13 @@ export class RewriteRpc {
|
|
|
140
136
|
return cursor;
|
|
141
137
|
}
|
|
142
138
|
|
|
143
|
-
async parse(inputs: ParserInput[], relativeTo?: string): Promise<SourceFile[]> {
|
|
139
|
+
async parse(inputs: ParserInput[], sourceFileType: string, relativeTo?: string): Promise<SourceFile[]> {
|
|
144
140
|
const parsed: SourceFile[] = [];
|
|
145
141
|
for (const g of await this.connection.sendRequest(
|
|
146
142
|
new rpc.RequestType<Parse, string[], Error>("Parse"),
|
|
147
143
|
new Parse(inputs, relativeTo)
|
|
148
144
|
)) {
|
|
149
|
-
parsed.push(await this.getObject(g));
|
|
145
|
+
parsed.push(await this.getObject(g, sourceFileType));
|
|
150
146
|
}
|
|
151
147
|
return parsed;
|
|
152
148
|
}
|
|
@@ -193,21 +189,26 @@ export class RewriteRpc {
|
|
|
193
189
|
this.localObjects.set(tree.id.toString(), tree);
|
|
194
190
|
const pId = this.localObject(p);
|
|
195
191
|
const cursorIds = this.getCursorIds(cursor);
|
|
192
|
+
|
|
193
|
+
const sourceFileType = isSourceFile(tree) ? tree.kind :
|
|
194
|
+
cursor!.firstEnclosing(t => isSourceFile(t))!.kind;
|
|
195
|
+
|
|
196
196
|
const response = await this.connection.sendRequest(
|
|
197
197
|
new rpc.RequestType<Visit, VisitResponse, Error>("Visit"),
|
|
198
|
-
new Visit(visitorName, undefined, tree.id.toString(), pId, cursorIds)
|
|
198
|
+
new Visit(visitorName, sourceFileType, undefined, tree.id.toString(), pId, cursorIds)
|
|
199
199
|
);
|
|
200
|
-
return response.modified ? this.getObject(tree.id.toString()) : tree;
|
|
200
|
+
return response.modified ? this.getObject(tree.id.toString(), sourceFileType) : tree;
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
async generate(remoteRecipeId: string, ctx: ExecutionContext): Promise<SourceFile[]> {
|
|
204
204
|
const ctxId = this.localObject(ctx);
|
|
205
205
|
const generated: SourceFile[] = [];
|
|
206
|
-
|
|
207
|
-
new rpc.RequestType<Generate,
|
|
206
|
+
const response = await this.connection.sendRequest(
|
|
207
|
+
new rpc.RequestType<Generate, GenerateResponse, Error>("Generate"),
|
|
208
208
|
new Generate(remoteRecipeId, ctxId)
|
|
209
|
-
)
|
|
210
|
-
|
|
209
|
+
);
|
|
210
|
+
for (let i = 0; i < response.ids.length; i++) {
|
|
211
|
+
generated.push(await this.getObject(response.ids[i], response.sourceFileTypes[i]));
|
|
211
212
|
}
|
|
212
213
|
return generated;
|
|
213
214
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './is-source-file'
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {TreeVisitor} from "../visitor";
|
|
2
|
+
import {ExecutionContext} from "../execution";
|
|
3
|
+
import {isSourceFile} from "../tree";
|
|
4
|
+
import {foundSearchResult} from "../markers";
|
|
5
|
+
import * as picomatch from "picomatch";
|
|
6
|
+
|
|
7
|
+
export class IsSourceFile extends TreeVisitor<any, ExecutionContext> {
|
|
8
|
+
private readonly matcher: picomatch.Matcher;
|
|
9
|
+
|
|
10
|
+
constructor(filePattern: string) {
|
|
11
|
+
super();
|
|
12
|
+
// Create a picomatch matcher for the pattern
|
|
13
|
+
this.matcher = picomatch.default ? picomatch.default(filePattern) : (picomatch as any)(filePattern);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
protected async preVisit(tree: any, _: ExecutionContext): Promise<any> {
|
|
17
|
+
this.stopAfterPreVisit();
|
|
18
|
+
if (isSourceFile(tree) && tree.sourcePath) {
|
|
19
|
+
const path = tree.sourcePath.replace(/\\/g, '/'); // Normalize to Unix separators
|
|
20
|
+
if (this.matcher(path)) {
|
|
21
|
+
return foundSearchResult(tree);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return tree;
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/test/rewrite-test.ts
CHANGED
|
@@ -22,7 +22,7 @@ import {SourceFile} from "../tree";
|
|
|
22
22
|
import dedent from "dedent";
|
|
23
23
|
import {Result, scheduleRun} from "../run";
|
|
24
24
|
import {SnowflakeId} from "@akashrajpurohit/snowflake-id";
|
|
25
|
-
import {mapAsync} from "../util";
|
|
25
|
+
import {mapAsync, trimIndent} from "../util";
|
|
26
26
|
import {ParseErrorKind} from "../parse-error";
|
|
27
27
|
import {MarkersKind, ParseExceptionResult} from "../markers";
|
|
28
28
|
import {JavaScriptVisitor} from "../javascript";
|
|
@@ -158,6 +158,9 @@ export class RecipeSpec {
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
private async expectAfter(spec: SourceSpec<any>, after?: SourceFile) {
|
|
161
|
+
if (!after) {
|
|
162
|
+
throw new Error('Expected for recipe to have produced a change for file:\n' + trimIndent(spec.before))
|
|
163
|
+
}
|
|
161
164
|
expect(after).toBeDefined();
|
|
162
165
|
await new ValidateWhitespaceVisitor().visit(after!, this.executionContext);
|
|
163
166
|
const actualAfter = await TreePrinters.print(after!);
|
|
@@ -212,7 +215,7 @@ export class RecipeSpec {
|
|
|
212
215
|
}
|
|
213
216
|
|
|
214
217
|
class ValidateWhitespaceVisitor extends JavaScriptVisitor<ExecutionContext> {
|
|
215
|
-
|
|
218
|
+
public override async visitSpace(space: J.Space, p: ExecutionContext): Promise<J.Space> {
|
|
216
219
|
const ret = super.visitSpace(space, p);
|
|
217
220
|
expect(space.whitespace).toMatch(/^\s*$/);
|
|
218
221
|
return ret;
|
package/src/text/rpc.ts
CHANGED
|
@@ -13,10 +13,9 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import {
|
|
16
|
+
import {RpcCodecs, RpcReceiveQueue, RpcSendQueue} from "../rpc";
|
|
17
17
|
import {PlainText} from "./tree";
|
|
18
18
|
import {createDraft, Draft, finishDraft} from "immer";
|
|
19
|
-
import {TreeKind} from "../tree";
|
|
20
19
|
|
|
21
20
|
async function receiveSnippet(before: PlainText.Snippet, q: RpcReceiveQueue): Promise<PlainText.Snippet | undefined> {
|
|
22
21
|
const draft: Draft<PlainText.Snippet> = createDraft(before);
|
|
@@ -26,40 +25,37 @@ async function receiveSnippet(before: PlainText.Snippet, q: RpcReceiveQueue): Pr
|
|
|
26
25
|
return finishDraft(draft);
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
28
|
+
// Register codec for all Java AST node types
|
|
29
|
+
for (const kind of Object.values(PlainText.Kind)) {
|
|
30
|
+
RpcCodecs.registerCodec(kind as string, {
|
|
31
|
+
async rpcReceive(before: PlainText, q: RpcReceiveQueue): Promise<PlainText> {
|
|
32
|
+
const draft: Draft<PlainText> = createDraft(before);
|
|
33
|
+
draft.id = await q.receive(before.id);
|
|
34
|
+
draft.markers = await q.receive(before.markers);
|
|
35
|
+
draft.sourcePath = await q.receive(before.sourcePath);
|
|
36
|
+
draft.charsetName = await q.receive(before.charsetName);
|
|
37
|
+
draft.charsetBomMarked = await q.receive(before.charsetBomMarked);
|
|
38
|
+
draft.checksum = await q.receive(before.checksum);
|
|
39
|
+
draft.fileAttributes = await q.receive(before.fileAttributes);
|
|
40
|
+
draft.text = await q.receive(before.text);
|
|
41
|
+
draft.snippets = (await q.receiveList(before.snippets, snippet => receiveSnippet(snippet, q)))!;
|
|
42
|
+
return finishDraft(draft);
|
|
43
|
+
},
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
45
|
+
async rpcSend(after: PlainText, q: RpcSendQueue): Promise<void> {
|
|
46
|
+
await q.getAndSend(after, p => p.id);
|
|
47
|
+
await q.getAndSend(after, p => p.markers);
|
|
48
|
+
await q.getAndSend(after, p => p.sourcePath);
|
|
49
|
+
await q.getAndSend(after, p => p.charsetName);
|
|
50
|
+
await q.getAndSend(after, p => p.charsetBomMarked);
|
|
51
|
+
await q.getAndSend(after, p => p.checksum);
|
|
52
|
+
await q.getAndSend(after, p => p.fileAttributes);
|
|
53
|
+
await q.getAndSend(after, p => p.text);
|
|
54
|
+
await q.getAndSendList(after, a => a.snippets, s => s.id, async (snippet) => {
|
|
55
|
+
await q.getAndSend(snippet, p => p.id);
|
|
56
|
+
await q.getAndSend(snippet, p => p.markers);
|
|
57
|
+
await q.getAndSend(snippet, p => p.text);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}, PlainText.Kind.PlainText);
|
|
59
61
|
}
|
|
60
|
-
|
|
61
|
-
Object.values(PlainText.Kind).forEach(kind => {
|
|
62
|
-
if (!Object.values(TreeKind).includes(kind as any)) {
|
|
63
|
-
RpcCodecs.registerCodec(kind, textCodec);
|
|
64
|
-
}
|
|
65
|
-
});
|
package/src/util.ts
CHANGED
|
@@ -15,15 +15,15 @@
|
|
|
15
15
|
*/
|
|
16
16
|
export async function mapAsync<T, U>(arr: T[], fn: (t: T, i: number) => Promise<U | undefined>): Promise<U[]> {
|
|
17
17
|
let results: U[] | undefined = undefined;
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
for (let i = 0; i < arr.length; i++) {
|
|
20
20
|
const result = await fn(arr[i], i);
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
if (result !== arr[i]) {
|
|
23
23
|
if (results === undefined) {
|
|
24
24
|
results = arr.slice(0, i) as unknown[] as U[];
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
|
|
27
27
|
if (result !== undefined) {
|
|
28
28
|
results.push(result);
|
|
29
29
|
}
|
|
@@ -31,6 +31,21 @@ export async function mapAsync<T, U>(arr: T[], fn: (t: T, i: number) => Promise<
|
|
|
31
31
|
results.push(result);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
return results === undefined ? arr as unknown[] as U[] : results;
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
export function trimIndent(str: string | null | undefined): string {
|
|
39
|
+
if (!str) {
|
|
40
|
+
return "";
|
|
41
|
+
}
|
|
42
|
+
const lines = str.split("\n");
|
|
43
|
+
const nonEmpty = lines.filter(l => l.trim().length > 0);
|
|
44
|
+
const minIndent = Math.min(
|
|
45
|
+
...nonEmpty.map(l => l.match(/^(\s*)/)![0].length)
|
|
46
|
+
);
|
|
47
|
+
return lines
|
|
48
|
+
.map(l => l.slice(minIndent))
|
|
49
|
+
.join("\n")
|
|
50
|
+
.trim();
|
|
51
|
+
}
|
package/src/visitor.ts
CHANGED
|
@@ -40,7 +40,7 @@ const stopAfterPreVisit = Symbol("STOP_AFTER_PRE_VISIT")
|
|
|
40
40
|
export abstract class TreeVisitor<T extends Tree, P> {
|
|
41
41
|
protected cursor: Cursor = rootCursor();
|
|
42
42
|
private visitCount: number = 0;
|
|
43
|
-
|
|
43
|
+
public afterVisit: TreeVisitor<any, P>[] = [];
|
|
44
44
|
|
|
45
45
|
async visitDefined<R extends T>(tree: Tree, p: P, parent?: Cursor): Promise<R> {
|
|
46
46
|
return (await this.visit<R>(tree, p, parent))!;
|
|
@@ -80,14 +80,14 @@ export abstract class TreeVisitor<T extends Tree, P> {
|
|
|
80
80
|
|
|
81
81
|
if (topLevel) {
|
|
82
82
|
if (this.afterVisit) {
|
|
83
|
-
|
|
83
|
+
while (this.afterVisit.length > 0) {
|
|
84
|
+
const v = this.afterVisit.shift()!;
|
|
84
85
|
v.cursor = this.cursor;
|
|
85
86
|
if (t !== undefined) {
|
|
86
87
|
t = await v.visit(t, p);
|
|
87
88
|
}
|
|
88
89
|
}
|
|
89
90
|
}
|
|
90
|
-
this.afterVisit = undefined;
|
|
91
91
|
this.visitCount = 0;
|
|
92
92
|
}
|
|
93
93
|
} catch (e) {
|