@openrewrite/rewrite 8.92.2 → 8.92.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/data-table.d.ts +11 -0
- package/dist/data-table.d.ts.map +1 -1
- package/dist/data-table.js +7 -2
- package/dist/data-table.js.map +1 -1
- package/dist/javascript/type-mapping.d.ts.map +1 -1
- package/dist/javascript/type-mapping.js +17 -42
- package/dist/javascript/type-mapping.js.map +1 -1
- package/dist/recipe.d.ts +10 -0
- package/dist/recipe.d.ts.map +1 -1
- package/dist/recipe.js +8 -3
- package/dist/recipe.js.map +1 -1
- package/dist/rewrite-javascript-version.txt +1 -1
- package/dist/rpc/queue.d.ts +26 -1
- package/dist/rpc/queue.d.ts.map +1 -1
- package/dist/rpc/queue.js +56 -4
- package/dist/rpc/queue.js.map +1 -1
- package/dist/rpc/rewrite-rpc.d.ts +1 -0
- package/dist/rpc/rewrite-rpc.d.ts.map +1 -1
- package/dist/rpc/rewrite-rpc.js +6 -1
- package/dist/rpc/rewrite-rpc.js.map +1 -1
- package/dist/uuid.d.ts +0 -4
- package/dist/uuid.d.ts.map +1 -1
- package/dist/uuid.js +10 -3
- package/dist/uuid.js.map +1 -1
- package/package.json +1 -1
- package/src/data-table.ts +16 -4
- package/src/javascript/type-mapping.ts +18 -42
- package/src/recipe.ts +13 -0
- package/src/rpc/queue.ts +60 -3
- package/src/rpc/rewrite-rpc.ts +8 -2
- package/src/uuid.ts +10 -3
package/src/recipe.ts
CHANGED
|
@@ -21,6 +21,12 @@ import {mapAsync} from "./util";
|
|
|
21
21
|
|
|
22
22
|
const OPTIONS_KEY = "__recipe_options__";
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Java's OptionDescriptor declares `type` non-nullable, so an option omitting one
|
|
26
|
+
* degrades to String rather than reporting no type.
|
|
27
|
+
*/
|
|
28
|
+
export const DEFAULT_OPTION_TYPE = "String";
|
|
29
|
+
|
|
24
30
|
export type Minutes = number;
|
|
25
31
|
|
|
26
32
|
export abstract class Recipe {
|
|
@@ -100,6 +106,7 @@ export abstract class Recipe {
|
|
|
100
106
|
name: key,
|
|
101
107
|
value: (this as any)[key],
|
|
102
108
|
required: descriptor.required ?? true,
|
|
109
|
+
type: descriptor.type ?? DEFAULT_OPTION_TYPE,
|
|
103
110
|
...descriptor
|
|
104
111
|
})),
|
|
105
112
|
preconditions: [],
|
|
@@ -154,6 +161,12 @@ export interface OptionDescriptor {
|
|
|
154
161
|
readonly required?: boolean
|
|
155
162
|
readonly example?: string
|
|
156
163
|
readonly valid?: string[]
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Java simple type name, for example String, Long or Boolean. TypeScript erases types at
|
|
167
|
+
* runtime, so this cannot be derived; defaults to {@link DEFAULT_OPTION_TYPE}.
|
|
168
|
+
*/
|
|
169
|
+
readonly type?: string
|
|
157
170
|
}
|
|
158
171
|
|
|
159
172
|
export abstract class ScanningRecipe<P> extends Recipe {
|
package/src/rpc/queue.ts
CHANGED
|
@@ -316,6 +316,60 @@ export class RpcSendQueue {
|
|
|
316
316
|
}
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
+
/**
|
|
320
|
+
* Collapses repeated strings decoded from RPC messages to a single instance. Shared across every
|
|
321
|
+
* {@link RpcReceiveQueue} of a connection so the same discriminators, enum values and whitespace
|
|
322
|
+
* are deduplicated across the whole run rather than only within one received object.
|
|
323
|
+
*/
|
|
324
|
+
export class StringInternTable {
|
|
325
|
+
private readonly strings = new Map<string, string>();
|
|
326
|
+
|
|
327
|
+
constructor(private readonly maxEntries = 1 << 16,
|
|
328
|
+
private readonly maxValueLength = 200) {
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Interns a `kind`/`valueType` discriminator. This set is bounded by the number of LST node
|
|
333
|
+
* types, so it is always interned and never subject to the cap.
|
|
334
|
+
*/
|
|
335
|
+
internType(value: string): string {
|
|
336
|
+
const existing = this.strings.get(value);
|
|
337
|
+
if (existing !== undefined) {
|
|
338
|
+
return existing;
|
|
339
|
+
}
|
|
340
|
+
this.strings.set(value, value);
|
|
341
|
+
return value;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Interns a scalar string value, which is unbounded in principle. Only short strings are
|
|
346
|
+
* interned (whitespace and short tokens dominate the duplication), and the table stops growing
|
|
347
|
+
* at a cap so it can never turn into a leak; past either limit the original is returned as-is.
|
|
348
|
+
*/
|
|
349
|
+
internValue(value: string): string {
|
|
350
|
+
if (value.length > this.maxValueLength) {
|
|
351
|
+
return value;
|
|
352
|
+
}
|
|
353
|
+
const existing = this.strings.get(value);
|
|
354
|
+
if (existing !== undefined) {
|
|
355
|
+
return existing;
|
|
356
|
+
}
|
|
357
|
+
if (this.strings.size >= this.maxEntries) {
|
|
358
|
+
return value;
|
|
359
|
+
}
|
|
360
|
+
this.strings.set(value, value);
|
|
361
|
+
return value;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
clear(): void {
|
|
365
|
+
this.strings.clear();
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
get size(): number {
|
|
369
|
+
return this.strings.size;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
319
373
|
export class RpcReceiveQueue {
|
|
320
374
|
private batch: RpcObjectData[] = [];
|
|
321
375
|
private batchIndex = 0;
|
|
@@ -325,7 +379,8 @@ export class RpcReceiveQueue {
|
|
|
325
379
|
private readonly sourceFileType: string | undefined,
|
|
326
380
|
private readonly pull: () => Promise<RpcObjectData[]>,
|
|
327
381
|
private readonly logger: rpc.Logger | undefined,
|
|
328
|
-
private readonly trace: boolean
|
|
382
|
+
private readonly trace: boolean,
|
|
383
|
+
private readonly internedStrings: StringInternTable = new StringInternTable()) {
|
|
329
384
|
}
|
|
330
385
|
|
|
331
386
|
/**
|
|
@@ -432,7 +487,9 @@ export class RpcReceiveQueue {
|
|
|
432
487
|
} else if ((codec = RpcCodecs.forInstance(before, this.sourceFileType))) {
|
|
433
488
|
after = await codec.rpcReceive(before, this);
|
|
434
489
|
} else if (message.value !== undefined) {
|
|
435
|
-
after = message.valueType ?
|
|
490
|
+
after = message.valueType ?
|
|
491
|
+
{kind: this.internedStrings.internType(message.valueType), ...message.value} :
|
|
492
|
+
typeof message.value === "string" ? this.internedStrings.internValue(message.value) : message.value;
|
|
436
493
|
} else if (message.state === RpcObjectState.ADD && message.valueType) {
|
|
437
494
|
throw new Error(
|
|
438
495
|
`No RPC codec registered on the TypeScript side for '${message.valueType}'. ` +
|
|
@@ -515,7 +572,7 @@ export class RpcReceiveQueue {
|
|
|
515
572
|
if (codec?.rpcNew) {
|
|
516
573
|
return codec.rpcNew();
|
|
517
574
|
}
|
|
518
|
-
return {kind: type} as T;
|
|
575
|
+
return {kind: this.internedStrings.internType(type)} as T;
|
|
519
576
|
}
|
|
520
577
|
}
|
|
521
578
|
|
package/src/rpc/rewrite-rpc.ts
CHANGED
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
import {DataTableStore} from "../data-table";
|
|
41
41
|
import {RecipeMarketplace} from "../marketplace";
|
|
42
42
|
import {initializeMetricsCsv, setCacheSizeProvider} from "./request/metrics";
|
|
43
|
-
import {RpcObjectData, RpcObjectState, RpcReceiveQueue} from "./queue";
|
|
43
|
+
import {RpcObjectData, RpcObjectState, RpcReceiveQueue, StringInternTable} from "./queue";
|
|
44
44
|
import {RpcRecipe} from "./recipe";
|
|
45
45
|
import {ExecutionContext} from "../execution";
|
|
46
46
|
import {InstallRecipes, InstallRecipesResponse} from "./request/install-recipes";
|
|
@@ -68,6 +68,11 @@ export class RewriteRpc {
|
|
|
68
68
|
readonly remoteRefs: Map<number, any> = new Map();
|
|
69
69
|
readonly localRefs: ReferenceMap = new ReferenceMap();
|
|
70
70
|
|
|
71
|
+
// One table for the whole connection so repeated discriminators, enum values and whitespace
|
|
72
|
+
// decoded across the many getObject calls of a run collapse to a single string instance rather
|
|
73
|
+
// than one per received object.
|
|
74
|
+
private readonly internedStrings = new StringInternTable();
|
|
75
|
+
|
|
71
76
|
// Ref high-water per source file, captured before it is first visited so an Evict rolls
|
|
72
77
|
// back exactly the refs it introduced. `send` = localRefs snapshot, `recvMax` = max remoteRefs key.
|
|
73
78
|
readonly refCheckpoints: Map<string, { send: number, recvMax: number }> = new Map();
|
|
@@ -158,6 +163,7 @@ export class RewriteRpc {
|
|
|
158
163
|
this.remoteRefs.clear();
|
|
159
164
|
this.localRefs.clear();
|
|
160
165
|
this.refCheckpoints.clear();
|
|
166
|
+
this.internedStrings.clear();
|
|
161
167
|
preparedRecipes.clear();
|
|
162
168
|
this.remoteLanguages = undefined;
|
|
163
169
|
};
|
|
@@ -262,7 +268,7 @@ export class RewriteRpc {
|
|
|
262
268
|
nextPage = requestPage();
|
|
263
269
|
}
|
|
264
270
|
return page;
|
|
265
|
-
}, this.logger, this.traceGetObject.receive);
|
|
271
|
+
}, this.logger, this.traceGetObject.receive, this.internedStrings);
|
|
266
272
|
|
|
267
273
|
let remoteObject: P;
|
|
268
274
|
try {
|
package/src/uuid.ts
CHANGED
|
@@ -35,12 +35,19 @@ function fallbackRandomId(): UUID {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* Generate a random UUID v4.
|
|
39
|
-
*
|
|
40
38
|
* Uses native crypto.randomUUID() on Node 14.17.0+, falls back to
|
|
41
39
|
* crypto.randomBytes() on older versions. The implementation is
|
|
42
40
|
* selected once at module load time to avoid per-call overhead.
|
|
43
41
|
*/
|
|
44
|
-
|
|
42
|
+
const generateId: () => UUID = typeof crypto.randomUUID === 'function'
|
|
45
43
|
? crypto.randomUUID
|
|
46
44
|
: fallbackRandomId;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Generate a random UUID v4.
|
|
48
|
+
*/
|
|
49
|
+
export const randomId: () => UUID = () =>
|
|
50
|
+
// Both randomUUID() and concatenation yield an unflattened cons-string. An id is only ever
|
|
51
|
+
// compared or serialized, so nothing forces a flatten and each would be retained as a rope of
|
|
52
|
+
// tiny heap nodes for the life of the LST; the round-trip flattens it to a sequential string.
|
|
53
|
+
Buffer.from(generateId(), 'latin1').toString('latin1');
|