@openrewrite/rewrite 8.63.0 → 8.63.2
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/java/index.d.ts +1 -0
- package/dist/java/index.d.ts.map +1 -1
- package/dist/java/index.js +1 -0
- package/dist/java/index.js.map +1 -1
- package/dist/java/rpc.d.ts +2 -0
- package/dist/java/rpc.d.ts.map +1 -1
- package/dist/java/rpc.js +749 -410
- package/dist/java/rpc.js.map +1 -1
- package/dist/java/tree.d.ts +1 -1
- package/dist/java/tree.d.ts.map +1 -1
- package/dist/java/type-visitor.d.ts +48 -0
- package/dist/java/type-visitor.d.ts.map +1 -0
- package/dist/java/type-visitor.js +260 -0
- package/dist/java/type-visitor.js.map +1 -0
- package/dist/java/type.d.ts +2 -0
- package/dist/java/type.d.ts.map +1 -1
- package/dist/java/type.js +0 -317
- package/dist/java/type.js.map +1 -1
- package/dist/java/visitor.d.ts.map +1 -1
- package/dist/java/visitor.js +579 -363
- package/dist/java/visitor.js.map +1 -1
- package/dist/javascript/preconditions.d.ts +1 -1
- package/dist/javascript/preconditions.d.ts.map +1 -1
- package/dist/javascript/preconditions.js +7 -6
- package/dist/javascript/preconditions.js.map +1 -1
- package/dist/javascript/rpc.js +430 -350
- package/dist/javascript/rpc.js.map +1 -1
- package/dist/javascript/tree.d.ts +1 -1
- package/dist/javascript/tree.d.ts.map +1 -1
- package/dist/javascript/type-mapping.d.ts.map +1 -1
- package/dist/javascript/type-mapping.js +7 -0
- package/dist/javascript/type-mapping.js.map +1 -1
- package/dist/javascript/visitor.d.ts.map +1 -1
- package/dist/javascript/visitor.js +504 -309
- package/dist/javascript/visitor.js.map +1 -1
- package/dist/json/visitor.d.ts.map +1 -1
- package/dist/json/visitor.js +46 -21
- package/dist/json/visitor.js.map +1 -1
- package/dist/rpc/queue.d.ts +7 -4
- package/dist/rpc/queue.d.ts.map +1 -1
- package/dist/rpc/queue.js +22 -32
- package/dist/rpc/queue.js.map +1 -1
- package/dist/rpc/request/generate.d.ts.map +1 -1
- package/dist/rpc/request/generate.js +2 -3
- package/dist/rpc/request/generate.js.map +1 -1
- package/dist/rpc/request/get-languages.d.ts.map +1 -1
- package/dist/rpc/request/get-languages.js +4 -3
- package/dist/rpc/request/get-languages.js.map +1 -1
- package/dist/rpc/request/get-object.d.ts +1 -1
- package/dist/rpc/request/get-object.d.ts.map +1 -1
- package/dist/rpc/request/get-object.js +8 -7
- package/dist/rpc/request/get-object.js.map +1 -1
- package/dist/rpc/request/get-recipes.d.ts.map +1 -1
- package/dist/rpc/request/get-recipes.js +2 -2
- package/dist/rpc/request/get-recipes.js.map +1 -1
- package/dist/rpc/request/index.d.ts +1 -0
- package/dist/rpc/request/index.d.ts.map +1 -1
- package/dist/rpc/request/index.js +1 -0
- package/dist/rpc/request/index.js.map +1 -1
- package/dist/rpc/request/install-recipes.d.ts.map +1 -1
- package/dist/rpc/request/install-recipes.js +30 -21
- package/dist/rpc/request/install-recipes.js.map +1 -1
- package/dist/rpc/request/metrics.d.ts +10 -10
- package/dist/rpc/request/metrics.d.ts.map +1 -1
- package/dist/rpc/request/metrics.js +38 -31
- package/dist/rpc/request/metrics.js.map +1 -1
- package/dist/rpc/request/parse.d.ts.map +1 -1
- package/dist/rpc/request/parse.js +10 -12
- package/dist/rpc/request/parse.js.map +1 -1
- package/dist/rpc/request/prepare-recipe.d.ts.map +1 -1
- package/dist/rpc/request/prepare-recipe.js +4 -4
- package/dist/rpc/request/prepare-recipe.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 +10 -6
- package/dist/rpc/request/print.js.map +1 -1
- package/dist/rpc/request/trace-get-object.d.ts +5 -0
- package/dist/rpc/request/trace-get-object.d.ts.map +1 -0
- package/dist/rpc/request/trace-get-object.js +3 -0
- package/dist/rpc/request/trace-get-object.js.map +1 -0
- package/dist/rpc/request/visit.d.ts.map +1 -1
- package/dist/rpc/request/visit.js +2 -3
- package/dist/rpc/request/visit.js.map +1 -1
- package/dist/rpc/rewrite-rpc.d.ts +2 -3
- package/dist/rpc/rewrite-rpc.d.ts.map +1 -1
- package/dist/rpc/rewrite-rpc.js +14 -5
- package/dist/rpc/rewrite-rpc.js.map +1 -1
- package/dist/rpc/server.d.ts.map +1 -1
- package/dist/rpc/server.js +15 -44
- package/dist/rpc/server.js.map +1 -1
- package/dist/rpc/trace.d.ts +1 -1
- package/dist/rpc/trace.d.ts.map +1 -1
- package/dist/rpc/trace.js +3 -3
- package/dist/rpc/trace.js.map +1 -1
- package/dist/util.d.ts +6 -0
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +14 -0
- package/dist/util.js.map +1 -1
- package/dist/version.txt +1 -1
- package/package.json +1 -1
- package/src/java/index.ts +1 -0
- package/src/java/rpc.ts +726 -537
- package/src/java/tree.ts +1 -1
- package/src/java/type-visitor.ts +241 -0
- package/src/java/type.ts +13 -277
- package/src/java/visitor.ts +581 -378
- package/src/javascript/preconditions.ts +7 -6
- package/src/javascript/rpc.ts +431 -360
- package/src/javascript/tree.ts +1 -1
- package/src/javascript/type-mapping.ts +7 -0
- package/src/javascript/visitor.ts +505 -310
- package/src/json/visitor.ts +47 -22
- package/src/rpc/queue.ts +20 -17
- package/src/rpc/request/generate.ts +31 -25
- package/src/rpc/request/get-languages.ts +18 -10
- package/src/rpc/request/get-object.ts +42 -34
- package/src/rpc/request/get-recipes.ts +15 -8
- package/src/rpc/request/index.ts +1 -0
- package/src/rpc/request/install-recipes.ts +96 -79
- package/src/rpc/request/metrics.ts +54 -48
- package/src/rpc/request/parse.ts +31 -25
- package/src/rpc/request/prepare-recipe.ts +31 -23
- package/src/rpc/request/print.ts +28 -14
- package/src/rpc/request/trace-get-object.ts +4 -0
- package/src/rpc/request/visit.ts +22 -16
- package/src/rpc/rewrite-rpc.ts +23 -10
- package/src/rpc/server.ts +17 -52
- package/src/rpc/trace.ts +3 -3
- package/src/util.ts +14 -0
- package/dist/rpc/chrome-profiler.d.ts +0 -25
- package/dist/rpc/chrome-profiler.d.ts.map +0 -1
- package/dist/rpc/chrome-profiler.js +0 -405
- package/dist/rpc/chrome-profiler.js.map +0 -1
- package/src/rpc/chrome-profiler.ts +0 -373
package/src/json/visitor.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import {mapAsync} from "../util";
|
|
16
|
+
import {mapAsync, updateIfChanged} from "../util";
|
|
17
17
|
import {produceAsync, TreeVisitor, ValidImmerRecipeReturnType} from "../visitor";
|
|
18
18
|
import {SourceFile} from "../tree";
|
|
19
19
|
import {isJson, Json} from "./tree";
|
|
@@ -25,49 +25,74 @@ export class JsonVisitor<P> extends TreeVisitor<Json, P> {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
protected async visitArray(array: Json.Array, p: P): Promise<Json | undefined> {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
const updates: any = {
|
|
29
|
+
prefix: await this.visitSpace(array.prefix, p),
|
|
30
|
+
markers: await this.visitMarkers(array.markers, p),
|
|
31
|
+
values: await mapAsync(array.values, value => this.visitRightPadded(value, p))
|
|
32
|
+
};
|
|
33
|
+
return updateIfChanged(array, updates);
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
protected async visitDocument(document: Json.Document, p: P): Promise<Json | undefined> {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
const updates: any = {
|
|
38
|
+
prefix: await this.visitSpace(document.prefix, p),
|
|
39
|
+
markers: await this.visitMarkers(document.markers, p),
|
|
40
|
+
value: await this.visitDefined(document.value, p),
|
|
41
|
+
eof: await this.visitSpace(document.eof, p)
|
|
42
|
+
};
|
|
43
|
+
return updateIfChanged(document, updates);
|
|
38
44
|
}
|
|
39
45
|
|
|
40
46
|
protected async visitEmpty(empty: Json.Empty, p: P): Promise<Json | undefined> {
|
|
41
|
-
|
|
47
|
+
const updates: any = {
|
|
48
|
+
prefix: await this.visitSpace(empty.prefix, p),
|
|
49
|
+
markers: await this.visitMarkers(empty.markers, p)
|
|
50
|
+
};
|
|
51
|
+
return updateIfChanged(empty, updates);
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
protected async visitIdentifier(identifier: Json.Identifier, p: P): Promise<Json | undefined> {
|
|
45
|
-
|
|
55
|
+
const updates: any = {
|
|
56
|
+
prefix: await this.visitSpace(identifier.prefix, p),
|
|
57
|
+
markers: await this.visitMarkers(identifier.markers, p)
|
|
58
|
+
};
|
|
59
|
+
return updateIfChanged(identifier, updates);
|
|
46
60
|
}
|
|
47
61
|
|
|
48
62
|
protected async visitLiteral(literal: Json.Literal, p: P): Promise<Json | undefined> {
|
|
49
|
-
|
|
63
|
+
const updates: any = {
|
|
64
|
+
prefix: await this.visitSpace(literal.prefix, p),
|
|
65
|
+
markers: await this.visitMarkers(literal.markers, p)
|
|
66
|
+
};
|
|
67
|
+
return updateIfChanged(literal, updates);
|
|
50
68
|
}
|
|
51
69
|
|
|
52
70
|
protected async visitMember(member: Json.Member, p: P): Promise<Json | undefined> {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
71
|
+
const updates: any = {
|
|
72
|
+
prefix: await this.visitSpace(member.prefix, p),
|
|
73
|
+
markers: await this.visitMarkers(member.markers, p),
|
|
74
|
+
key: (await this.visitRightPadded(member.key, p))!,
|
|
75
|
+
value: await this.visitDefined(member.value, p)
|
|
76
|
+
};
|
|
77
|
+
return updateIfChanged(member, updates);
|
|
57
78
|
}
|
|
58
79
|
|
|
59
80
|
protected async visitObject(jsonObject: Json.Object, p: P): Promise<Json | undefined> {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
81
|
+
const updates: any = {
|
|
82
|
+
prefix: await this.visitSpace(jsonObject.prefix, p),
|
|
83
|
+
markers: await this.visitMarkers(jsonObject.markers, p),
|
|
84
|
+
members: await mapAsync(jsonObject.members, member => this.visitRightPadded(member, p))
|
|
85
|
+
};
|
|
86
|
+
return updateIfChanged(jsonObject, updates);
|
|
63
87
|
}
|
|
64
88
|
|
|
65
89
|
public async visitRightPadded<T extends Json>(right: Json.RightPadded<T>, p: P):
|
|
66
90
|
Promise<Json.RightPadded<T> | undefined> {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
91
|
+
const updates: any = {
|
|
92
|
+
element: await this.visitDefined(right.element, p),
|
|
93
|
+
after: await this.visitSpace(right.after, p)
|
|
94
|
+
};
|
|
95
|
+
return updateIfChanged(right, updates);
|
|
71
96
|
}
|
|
72
97
|
|
|
73
98
|
public async visitSpace(space: Json.Space, p: P): Promise<Json.Space> {
|
package/src/rpc/queue.ts
CHANGED
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
import * as rpc from "vscode-jsonrpc/node";
|
|
16
17
|
import {emptyMarkers, Markers} from "../markers";
|
|
17
18
|
import {saveTrace, trace} from "./trace";
|
|
18
19
|
import {createDraft, finishDraft} from "immer";
|
|
19
20
|
import {isRef, ReferenceMap} from "../reference";
|
|
20
|
-
import {Writable} from "node:stream";
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Interface representing an RPC codec that defines methods
|
|
@@ -261,7 +261,8 @@ export class RpcReceiveQueue {
|
|
|
261
261
|
constructor(private readonly refs: Map<number, any>,
|
|
262
262
|
private readonly sourceFileType: string | undefined,
|
|
263
263
|
private readonly pull: () => Promise<RpcObjectData[]>,
|
|
264
|
-
private readonly
|
|
264
|
+
private readonly logger: rpc.Logger | undefined,
|
|
265
|
+
private readonly trace: boolean) {
|
|
265
266
|
}
|
|
266
267
|
|
|
267
268
|
async take(): Promise<RpcObjectData> {
|
|
@@ -276,7 +277,7 @@ export class RpcReceiveQueue {
|
|
|
276
277
|
markers = emptyMarkers;
|
|
277
278
|
}
|
|
278
279
|
return this.receive(markers, async m => {
|
|
279
|
-
return saveTrace(this.
|
|
280
|
+
return saveTrace(this.trace, async () => {
|
|
280
281
|
const draft = createDraft(markers!);
|
|
281
282
|
draft.id = await this.receive(m.id);
|
|
282
283
|
draft.markers = (await this.receiveList(m.markers))!;
|
|
@@ -289,9 +290,9 @@ export class RpcReceiveQueue {
|
|
|
289
290
|
before: T | undefined,
|
|
290
291
|
onChange?: (before: T) => T | Promise<T | undefined> | undefined
|
|
291
292
|
): Promise<T> {
|
|
292
|
-
return saveTrace(this.
|
|
293
|
+
return saveTrace(this.trace, async () => {
|
|
293
294
|
const message = await this.take();
|
|
294
|
-
|
|
295
|
+
RpcObjectData.logTrace(message, this.trace, this.logger);
|
|
295
296
|
let ref: number | undefined;
|
|
296
297
|
switch (message.state) {
|
|
297
298
|
case RpcObjectState.NO_CHANGE:
|
|
@@ -353,9 +354,9 @@ export class RpcReceiveQueue {
|
|
|
353
354
|
before: T[] | undefined,
|
|
354
355
|
onChange?: (before: T) => T | Promise<T | undefined> | undefined
|
|
355
356
|
): Promise<T[] | undefined> {
|
|
356
|
-
return saveTrace(this.
|
|
357
|
+
return saveTrace(this.trace, async () => {
|
|
357
358
|
const message = await this.take();
|
|
358
|
-
|
|
359
|
+
RpcObjectData.logTrace(message, this.trace, this.logger);
|
|
359
360
|
switch (message.state) {
|
|
360
361
|
case RpcObjectState.NO_CHANGE:
|
|
361
362
|
return before;
|
|
@@ -385,16 +386,6 @@ export class RpcReceiveQueue {
|
|
|
385
386
|
});
|
|
386
387
|
}
|
|
387
388
|
|
|
388
|
-
private traceMessage(message: RpcObjectData) {
|
|
389
|
-
if (this.logFile && message.trace) {
|
|
390
|
-
const sendTrace = message.trace;
|
|
391
|
-
delete message.trace;
|
|
392
|
-
this.logFile.write(`${JSON.stringify(message)}\n`);
|
|
393
|
-
this.logFile.write(` ${sendTrace}\n`);
|
|
394
|
-
this.logFile.write(` ${trace("Receiver")}\n`);
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
389
|
private newObj<T>(type: string): T {
|
|
399
390
|
return {
|
|
400
391
|
kind: type
|
|
@@ -413,6 +404,18 @@ export interface RpcObjectData {
|
|
|
413
404
|
trace?: string
|
|
414
405
|
}
|
|
415
406
|
|
|
407
|
+
export namespace RpcObjectData {
|
|
408
|
+
export function logTrace(message: RpcObjectData, enabled: boolean, logger: rpc.Logger | undefined): void {
|
|
409
|
+
if (enabled && logger && message.trace) {
|
|
410
|
+
const sendTrace = message.trace;
|
|
411
|
+
delete message.trace;
|
|
412
|
+
logger.info(`${JSON.stringify(message)}`);
|
|
413
|
+
logger.info(` ${sendTrace || 'No sender trace'}`);
|
|
414
|
+
logger.info(` ${trace("Receiver") || 'No receiver trace'}`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
416
419
|
export enum RpcObjectState {
|
|
417
420
|
NO_CHANGE = "NO_CHANGE",
|
|
418
421
|
ADD = "ADD",
|
|
@@ -34,33 +34,39 @@ export class Generate {
|
|
|
34
34
|
recipeCursors: WeakMap<Recipe, Cursor>,
|
|
35
35
|
getObject: (id: string) => any,
|
|
36
36
|
metricsCsv?: string): void {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
connection.onRequest(
|
|
38
|
+
new rpc.RequestType<Generate, GenerateResponse, Error>("Generate"),
|
|
39
|
+
withMetrics<Generate, GenerateResponse>(
|
|
40
|
+
"Generate",
|
|
41
|
+
metricsCsv,
|
|
42
|
+
(context) => async (request) => {
|
|
43
|
+
context.target = request.id;
|
|
44
|
+
const recipe = preparedRecipes.get(request.id);
|
|
45
|
+
const response = {
|
|
46
|
+
ids: [],
|
|
47
|
+
sourceFileTypes: []
|
|
48
|
+
} as GenerateResponse;
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
if (recipe && recipe instanceof ScanningRecipe) {
|
|
51
|
+
let cursor = recipeCursors.get(recipe);
|
|
52
|
+
if (!cursor) {
|
|
53
|
+
cursor = rootCursor();
|
|
54
|
+
recipeCursors.set(recipe, cursor);
|
|
55
|
+
}
|
|
56
|
+
const ctx = getObject(request.p) as ExecutionContext;
|
|
57
|
+
const acc = recipe.accumulator(cursor, ctx);
|
|
58
|
+
const generated = await recipe.generate(acc, ctx)
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
for (const g of generated) {
|
|
61
|
+
localObjects.set(g.id.toString(), g);
|
|
62
|
+
response.ids.push(g.id.toString());
|
|
63
|
+
response.sourceFileTypes.push(g.kind);
|
|
64
|
+
}
|
|
61
65
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
}
|
|
67
|
+
return response;
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
);
|
|
65
71
|
}
|
|
66
72
|
}
|
|
@@ -3,15 +3,23 @@ import {withMetrics0} from "./metrics";
|
|
|
3
3
|
|
|
4
4
|
export class GetLanguages {
|
|
5
5
|
static handle(connection: rpc.MessageConnection, metricsCsv?: string): void {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
connection.onRequest(
|
|
7
|
+
new rpc.RequestType0<string[], Error>("GetLanguages"),
|
|
8
|
+
withMetrics0<string[]>(
|
|
9
|
+
"GetLanguages",
|
|
10
|
+
metricsCsv,
|
|
11
|
+
(context) => async () => {
|
|
12
|
+
// Include all languages you want this server to support receiving from a remote peer
|
|
13
|
+
const languages = [
|
|
14
|
+
"org.openrewrite.text.PlainText",
|
|
15
|
+
"org.openrewrite.json.tree.Json$Document",
|
|
16
|
+
"org.openrewrite.java.tree.J$CompilationUnit",
|
|
17
|
+
"org.openrewrite.javascript.tree.JS$CompilationUnit",
|
|
18
|
+
];
|
|
19
|
+
context.target = '';
|
|
20
|
+
return languages;
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
);
|
|
16
24
|
}
|
|
17
25
|
}
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import * as rpc from "vscode-jsonrpc/node";
|
|
17
17
|
import {RpcObjectData, RpcObjectState, RpcSendQueue} from "../queue";
|
|
18
18
|
import {ReferenceMap} from "../../reference";
|
|
19
|
-
import {
|
|
19
|
+
import {extractSourcePath, withMetrics} from "./metrics";
|
|
20
20
|
|
|
21
21
|
export class GetObject {
|
|
22
22
|
constructor(private readonly id: string,
|
|
@@ -29,49 +29,57 @@ export class GetObject {
|
|
|
29
29
|
localObjects: Map<string, any | ((input: string) => any)>,
|
|
30
30
|
localRefs: ReferenceMap,
|
|
31
31
|
batchSize: number,
|
|
32
|
-
trace: boolean,
|
|
33
|
-
metricsCsv?: string
|
|
32
|
+
trace: () => boolean,
|
|
33
|
+
metricsCsv?: string,
|
|
34
34
|
): void {
|
|
35
35
|
const pendingData = new Map<string, RpcObjectData[]>();
|
|
36
|
-
const target = { target: '' };
|
|
37
36
|
|
|
38
|
-
connection.onRequest(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
37
|
+
connection.onRequest(
|
|
38
|
+
new rpc.RequestType<GetObject, any, Error>("GetObject"),
|
|
39
|
+
withMetrics<GetObject, any>(
|
|
40
|
+
"GetObject",
|
|
41
|
+
metricsCsv,
|
|
42
|
+
(context) => async request => {
|
|
43
|
+
const objId = request.id;
|
|
44
|
+
if (!localObjects.has(objId)) {
|
|
45
|
+
context.target = '';
|
|
46
|
+
return [
|
|
47
|
+
{state: RpcObjectState.DELETE},
|
|
48
|
+
{state: RpcObjectState.END_OF_OBJECT}
|
|
49
|
+
];
|
|
50
|
+
}
|
|
46
51
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
+
const objectOrGenerator = localObjects.get(objId)!;
|
|
53
|
+
if (typeof objectOrGenerator === 'function') {
|
|
54
|
+
const obj = await objectOrGenerator(objId);
|
|
55
|
+
localObjects.set(objId, obj);
|
|
56
|
+
}
|
|
52
57
|
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
const obj = localObjects.get(objId);
|
|
59
|
+
context.target = extractSourcePath(obj);
|
|
55
60
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
61
|
+
let allData = pendingData.get(objId);
|
|
62
|
+
if (!allData) {
|
|
63
|
+
const after = obj;
|
|
64
|
+
const before = remoteObjects.get(objId);
|
|
60
65
|
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
allData = await new RpcSendQueue(localRefs, request.sourceFileType, trace())
|
|
67
|
+
.generate(after, before);
|
|
68
|
+
pendingData.set(objId, allData);
|
|
63
69
|
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
remoteObjects.set(objId, after);
|
|
71
|
+
}
|
|
66
72
|
|
|
67
|
-
|
|
73
|
+
const batch = allData.splice(0, batchSize);
|
|
68
74
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
// If we've sent all data, remove from pending
|
|
76
|
+
if (allData.length === 0) {
|
|
77
|
+
pendingData.delete(objId);
|
|
78
|
+
}
|
|
73
79
|
|
|
74
|
-
|
|
75
|
-
|
|
80
|
+
return batch;
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
);
|
|
76
84
|
}
|
|
77
85
|
}
|
|
@@ -19,13 +19,20 @@ import {withMetrics0} from "./metrics";
|
|
|
19
19
|
|
|
20
20
|
export class GetRecipes {
|
|
21
21
|
static handle(connection: rpc.MessageConnection, registry: RecipeRegistry, metricsCsv?: string): void {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
22
|
+
connection.onRequest(
|
|
23
|
+
new rpc.RequestType0<({ name: string } & RecipeDescriptor)[], Error>("GetRecipes"),
|
|
24
|
+
withMetrics0<({ name: string } & RecipeDescriptor)[]>(
|
|
25
|
+
"GetRecipes",
|
|
26
|
+
metricsCsv,
|
|
27
|
+
(context) => async () => {
|
|
28
|
+
const recipes = [];
|
|
29
|
+
for (const [_name, recipe] of registry.all.entries()) {
|
|
30
|
+
recipes.push(await new recipe().descriptor());
|
|
31
|
+
}
|
|
32
|
+
context.target = '';
|
|
33
|
+
return recipes;
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
);
|
|
30
37
|
}
|
|
31
38
|
}
|
package/src/rpc/request/index.ts
CHANGED
|
@@ -17,7 +17,7 @@ import * as rpc from "vscode-jsonrpc/node";
|
|
|
17
17
|
import {RecipeRegistry} from "../../recipe";
|
|
18
18
|
import * as path from "path";
|
|
19
19
|
import * as fs from "fs";
|
|
20
|
-
import {spawn
|
|
20
|
+
import {spawn} from "child_process";
|
|
21
21
|
import {withMetrics} from "./metrics";
|
|
22
22
|
|
|
23
23
|
export interface InstallRecipesResponse {
|
|
@@ -70,94 +70,111 @@ export class InstallRecipes {
|
|
|
70
70
|
|
|
71
71
|
static handle(connection: rpc.MessageConnection, installDir: string, registry: RecipeRegistry,
|
|
72
72
|
logger?: rpc.Logger, metricsCsv?: string): void {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
73
|
+
connection.onRequest(
|
|
74
|
+
new rpc.RequestType<InstallRecipes, InstallRecipesResponse, Error>("InstallRecipes"),
|
|
75
|
+
withMetrics<InstallRecipes, InstallRecipesResponse>(
|
|
76
|
+
"InstallRecipes",
|
|
77
|
+
metricsCsv,
|
|
78
|
+
(context) => async (request) => {
|
|
79
|
+
context.target = typeof request.recipes === "object" ? request.recipes.packageName : request.recipes;
|
|
80
|
+
const beforeInstall = registry.all.size;
|
|
81
|
+
let resolvedPath;
|
|
82
|
+
let recipesName = request.recipes;
|
|
83
|
+
|
|
84
|
+
if (typeof request.recipes === "object") {
|
|
85
|
+
const recipePackage = request.recipes;
|
|
86
|
+
const absoluteInstallDir = path.isAbsolute(installDir) ? installDir : path.join(process.cwd(), installDir);
|
|
87
|
+
|
|
88
|
+
// Ensure directory exists
|
|
89
|
+
if (!fs.existsSync(absoluteInstallDir)) {
|
|
90
|
+
fs.mkdirSync(absoluteInstallDir, {recursive: true});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Check if package.json exists, if not create one
|
|
94
|
+
const packageJsonPath = path.join(absoluteInstallDir, "package.json");
|
|
95
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
96
|
+
// Create a minimal package.json with a custom name
|
|
97
|
+
const packageJson = {
|
|
98
|
+
name: "openrewrite-recipes",
|
|
99
|
+
version: "1.0.0",
|
|
100
|
+
description: "OpenRewrite recipe marketplace",
|
|
101
|
+
private: true
|
|
102
|
+
};
|
|
103
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
104
|
+
if (logger) {
|
|
105
|
+
logger.info("Created package.json for recipe dependencies");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Rather than using npm on PATH, use `node_cli.js`.
|
|
110
|
+
// https://stackoverflow.com/questions/15957529/can-i-install-a-npm-package-from-javascript-running-in-node-js
|
|
111
|
+
const packageSpec = recipePackage.packageName + (recipePackage.version ? `@${recipePackage.version}` : "");
|
|
112
|
+
await spawnNpmCommand("npm", ["install", packageSpec, "--no-fund"], absoluteInstallDir, logger);
|
|
113
|
+
resolvedPath = require.resolve(path.join(absoluteInstallDir, "node_modules", recipePackage.packageName));
|
|
114
|
+
recipesName = request.recipes.packageName;
|
|
115
|
+
} else {
|
|
116
|
+
resolvedPath = request.recipes;
|
|
102
117
|
}
|
|
103
|
-
}
|
|
104
118
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
resolvedPath = request.recipes;
|
|
113
|
-
}
|
|
119
|
+
let recipeModule;
|
|
120
|
+
try {
|
|
121
|
+
setupSharedDependencies(resolvedPath);
|
|
122
|
+
recipeModule = require(resolvedPath);
|
|
123
|
+
} catch (e: any) {
|
|
124
|
+
throw new Error(`Failed to load recipe module from ${resolvedPath}: ${e.stack}`);
|
|
125
|
+
}
|
|
114
126
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
127
|
+
if (typeof recipeModule.activate === "function") {
|
|
128
|
+
// noinspection JSVoidFunctionReturnValueUsed
|
|
129
|
+
const activatePromise = recipeModule.activate(registry);
|
|
130
|
+
// noinspection SuspiciousTypeOfGuard
|
|
131
|
+
if (activatePromise instanceof Promise) {
|
|
132
|
+
await activatePromise;
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
throw new Error(`${recipesName} does not export an 'activate' function`);
|
|
136
|
+
}
|
|
122
137
|
|
|
123
|
-
|
|
124
|
-
// noinspection JSVoidFunctionReturnValueUsed
|
|
125
|
-
const activatePromise = recipeModule.activate(registry);
|
|
126
|
-
// noinspection SuspiciousTypeOfGuard
|
|
127
|
-
if (activatePromise instanceof Promise) {
|
|
128
|
-
await activatePromise;
|
|
138
|
+
return {recipesInstalled: registry.all.size - beforeInstall};
|
|
129
139
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return {recipesInstalled: registry.all.size - beforeInstall};
|
|
135
|
-
}));
|
|
140
|
+
)
|
|
141
|
+
);
|
|
136
142
|
}
|
|
137
143
|
}
|
|
138
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Ensures dynamically loaded modules share the same class instances as the host
|
|
147
|
+
* by mapping require.cache entries. This prevents instanceof failures when the
|
|
148
|
+
* same package is installed in multiple node_modules directories.
|
|
149
|
+
*/
|
|
139
150
|
function setupSharedDependencies(targetModulePath: string) {
|
|
140
|
-
const sharedDeps = [
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
151
|
+
const sharedDeps = ['@openrewrite/rewrite', 'vscode-jsonrpc'];
|
|
152
|
+
const targetDir = path.dirname(targetModulePath);
|
|
153
|
+
|
|
154
|
+
sharedDeps.forEach(depName => {
|
|
155
|
+
const depPattern = path.sep + 'node_modules' + path.sep + depName.replace('/', path.sep);
|
|
156
|
+
|
|
157
|
+
for (const cachedPath of Object.keys(require.cache)) {
|
|
158
|
+
if (!cachedPath.includes(depPattern)) continue;
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
// Extract subpath: /path/node_modules/@pkg/dist/tree.js -> dist/tree.js
|
|
162
|
+
const pkgIndex = cachedPath.indexOf(depPattern);
|
|
163
|
+
let subpath = cachedPath.substring(pkgIndex + depPattern.length)
|
|
164
|
+
.replace(/^[/\\]/, '') // Remove leading slash
|
|
165
|
+
.replace(/\.(js|ts)$/, '') // Remove extension
|
|
166
|
+
.replace(/^dist[/\\]/, '') // Remove dist/ prefix if present
|
|
167
|
+
.replace(/[/\\]index$/, ''); // Remove /index suffix
|
|
168
|
+
|
|
169
|
+
// Build require path: @pkg or @pkg/subpath
|
|
170
|
+
const requirePath = subpath ? `${depName}/${subpath}` : depName;
|
|
171
|
+
|
|
172
|
+
// Resolve from target's perspective and map cache
|
|
173
|
+
const targetDepPath = require.resolve(requirePath, {paths: [targetDir]});
|
|
174
|
+
require.cache[targetDepPath] = require.cache[cachedPath];
|
|
175
|
+
} catch (e) {
|
|
176
|
+
// Target can't resolve this path, skip
|
|
158
177
|
}
|
|
159
|
-
} catch (e) {
|
|
160
|
-
// Module not found or not resolvable, skip
|
|
161
178
|
}
|
|
162
179
|
});
|
|
163
180
|
}
|