Skip to content

Commit 7b709f5

Browse files
committed
JavaScript: No Immer in RPC codec for NodeResolutionResult
As the data structure contains cycles Immer is not an option and it is also overkill. Using the simpler `updateIfChanged()` instead.
1 parent cd3367d commit 7b709f5

2 files changed

Lines changed: 70 additions & 71 deletions

File tree

rewrite-javascript/rewrite/src/javascript/markers.ts

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {Marker} from "../markers";
1717
import {J} from "../java";
1818
import {JS} from "./tree";
1919
import {RpcCodecs, RpcReceiveQueue, RpcSendQueue} from "../rpc";
20-
import {createDraft, finishDraft} from "immer";
2120
import {
2221
prettierStyle,
2322
PrettierStyle,
@@ -28,7 +27,8 @@ import {
2827
WrappingAndBracesStyle,
2928
WrappingAndBracesStyleDetailKind
3029
} from "./style";
31-
import {Autodetect, autodetect} from "./autodetect";
30+
import {Autodetect} from "./autodetect";
31+
import {updateIfChanged} from "../util";
3232

3333
declare module "./tree" {
3434
namespace JS {
@@ -96,10 +96,10 @@ function registerPrefixedMarkerCodec<M extends Marker & { prefix: J.Space }>(
9696
) {
9797
RpcCodecs.registerCodec(kind, {
9898
async rpcReceive(before: M, q: RpcReceiveQueue): Promise<M> {
99-
const draft = createDraft(before);
100-
draft.id = await q.receive(before.id);
101-
draft.prefix = await q.receive(before.prefix);
102-
return finishDraft(draft) as M;
99+
return updateIfChanged(before, {
100+
id: await q.receive(before.id),
101+
prefix: await q.receive(before.prefix)
102+
} as Partial<M>);
103103
},
104104

105105
async rpcSend(after: M, q: RpcSendQueue): Promise<void> {
@@ -139,9 +139,10 @@ RpcCodecs.registerCodec(StyleKind.PrettierStyle, {
139139
// Only serialize the variable fields (id, styles); constant fields are defined in the interface
140140
RpcCodecs.registerCodec(StyleKind.Autodetect, {
141141
async rpcReceive(before: Autodetect, q: RpcReceiveQueue): Promise<Autodetect> {
142-
const id = await q.receive(before.id);
143-
const styles = (await q.receiveList(before.styles))!;
144-
return autodetect(id, styles);
142+
return updateIfChanged(before, {
143+
id: await q.receive(before.id),
144+
styles: (await q.receiveList(before.styles))!,
145+
});
145146
},
146147

147148
async rpcSend(after: Autodetect, q: RpcSendQueue): Promise<void> {
@@ -161,11 +162,11 @@ function registerSimpleCodec<T extends { kind: string }>(
161162
) {
162163
RpcCodecs.registerCodec(kind, {
163164
async rpcReceive(before: T, q: RpcReceiveQueue): Promise<T> {
164-
const draft = createDraft(before);
165+
const updates: Partial<T> = {};
165166
for (const field of fields) {
166-
(draft as any)[field] = await q.receive((before as any)[field]);
167+
(updates as any)[field] = await q.receive((before as any)[field]);
167168
}
168-
return finishDraft(draft) as T;
169+
return updateIfChanged(before, updates);
169170
},
170171

171172
async rpcSend(after: T, q: RpcSendQueue): Promise<void> {
@@ -227,15 +228,15 @@ registerSimpleCodec<SpacesStyle.Other>(SpacesStyleDetailKind.SpacesStyleOther, [
227228
// SpacesStyle - has nested objects
228229
RpcCodecs.registerCodec(StyleKind.SpacesStyle, {
229230
async rpcReceive(before: SpacesStyle, q: RpcReceiveQueue): Promise<SpacesStyle> {
230-
const draft = createDraft(before);
231-
draft.beforeParentheses = await q.receive(before.beforeParentheses);
232-
draft.aroundOperators = await q.receive(before.aroundOperators);
233-
draft.beforeLeftBrace = await q.receive(before.beforeLeftBrace);
234-
draft.beforeKeywords = await q.receive(before.beforeKeywords);
235-
draft.within = await q.receive(before.within);
236-
draft.ternaryOperator = await q.receive(before.ternaryOperator);
237-
draft.other = await q.receive(before.other);
238-
return finishDraft(draft) as SpacesStyle;
231+
return updateIfChanged(before, {
232+
beforeParentheses: await q.receive(before.beforeParentheses),
233+
aroundOperators: await q.receive(before.aroundOperators),
234+
beforeLeftBrace: await q.receive(before.beforeLeftBrace),
235+
beforeKeywords: await q.receive(before.beforeKeywords),
236+
within: await q.receive(before.within),
237+
ternaryOperator: await q.receive(before.ternaryOperator),
238+
other: await q.receive(before.other),
239+
});
239240
},
240241

241242
async rpcSend(after: SpacesStyle, q: RpcSendQueue): Promise<void> {
@@ -262,10 +263,10 @@ registerSimpleCodec<WrappingAndBracesStyle.KeepWhenReformatting>(
262263

263264
RpcCodecs.registerCodec(StyleKind.WrappingAndBracesStyle, {
264265
async rpcReceive(before: WrappingAndBracesStyle, q: RpcReceiveQueue): Promise<WrappingAndBracesStyle> {
265-
const draft = createDraft(before);
266-
draft.ifStatement = await q.receive(before.ifStatement);
267-
draft.keepWhenReformatting = await q.receive(before.keepWhenReformatting);
268-
return finishDraft(draft) as WrappingAndBracesStyle;
266+
return updateIfChanged(before, {
267+
ifStatement: await q.receive(before.ifStatement),
268+
keepWhenReformatting: await q.receive(before.keepWhenReformatting),
269+
});
269270
},
270271

271272
async rpcSend(after: WrappingAndBracesStyle, q: RpcSendQueue): Promise<void> {

rewrite-javascript/rewrite/src/javascript/node-resolution-result.ts

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ import {findMarker, Marker, Markers} from "../markers";
1717
import {randomId, UUID} from "../uuid";
1818
import {asRef} from "../reference";
1919
import {RpcCodecs, RpcReceiveQueue, RpcSendQueue} from "../rpc";
20-
import {castDraft, createDraft, finishDraft} from "immer";
20+
import {castDraft} from "immer";
21+
import {updateIfChanged} from "../util";
2122
import * as semver from "semver";
2223
import * as fsp from "fs/promises";
2324
import * as path from "path";
@@ -815,12 +816,11 @@ export namespace NodeResolutionResultQueries {
815816
*/
816817
RpcCodecs.registerCodec(NpmrcKind, {
817818
async rpcReceive(before: Npmrc, q: RpcReceiveQueue): Promise<Npmrc> {
818-
const draft = createDraft(before);
819-
draft.kind = NpmrcKind;
820-
draft.scope = await q.receive(before.scope);
821-
draft.properties = await q.receive(before.properties);
822-
823-
return finishDraft(draft) as Npmrc;
819+
return updateIfChanged(before, {
820+
kind: NpmrcKind,
821+
scope: await q.receive(before.scope),
822+
properties: await q.receive(before.properties),
823+
});
824824
},
825825

826826
async rpcSend(after: Npmrc, q: RpcSendQueue): Promise<void> {
@@ -834,13 +834,12 @@ RpcCodecs.registerCodec(NpmrcKind, {
834834
*/
835835
RpcCodecs.registerCodec(DependencyKind, {
836836
async rpcReceive(before: Dependency, q: RpcReceiveQueue): Promise<Dependency> {
837-
const draft = createDraft(before);
838-
draft.kind = DependencyKind;
839-
draft.name = await q.receive(before.name);
840-
draft.versionConstraint = await q.receive(before.versionConstraint);
841-
draft.resolved = await q.receive(before.resolved);
842-
843-
return finishDraft(draft) as Dependency;
837+
return updateIfChanged(before, {
838+
kind: DependencyKind,
839+
name: await q.receive(before.name),
840+
versionConstraint: await q.receive(before.versionConstraint),
841+
resolved: await q.receive(before.resolved),
842+
});
844843
},
845844

846845
async rpcSend(after: Dependency, q: RpcSendQueue): Promise<void> {
@@ -855,18 +854,17 @@ RpcCodecs.registerCodec(DependencyKind, {
855854
*/
856855
RpcCodecs.registerCodec(ResolvedDependencyKind, {
857856
async rpcReceive(before: ResolvedDependency, q: RpcReceiveQueue): Promise<ResolvedDependency> {
858-
const draft = createDraft(before);
859-
draft.kind = ResolvedDependencyKind;
860-
draft.name = await q.receive(before.name);
861-
draft.version = await q.receive(before.version);
862-
draft.dependencies = (await q.receiveList(before.dependencies)) || undefined;
863-
draft.devDependencies = (await q.receiveList(before.devDependencies)) || undefined;
864-
draft.peerDependencies = (await q.receiveList(before.peerDependencies)) || undefined;
865-
draft.optionalDependencies = (await q.receiveList(before.optionalDependencies)) || undefined;
866-
draft.engines = await q.receive(before.engines);
867-
draft.license = await q.receive(before.license);
868-
869-
return finishDraft(draft) as ResolvedDependency;
857+
return updateIfChanged(before, {
858+
kind: ResolvedDependencyKind,
859+
name: await q.receive(before.name),
860+
version: await q.receive(before.version),
861+
dependencies: (await q.receiveList(before.dependencies)) || undefined,
862+
devDependencies: (await q.receiveList(before.devDependencies)) || undefined,
863+
peerDependencies: (await q.receiveList(before.peerDependencies)) || undefined,
864+
optionalDependencies: (await q.receiveList(before.optionalDependencies)) || undefined,
865+
engines: await q.receive(before.engines),
866+
license: await q.receive(before.license),
867+
});
870868
},
871869

872870
async rpcSend(after: ResolvedDependency, q: RpcSendQueue): Promise<void> {
@@ -888,29 +886,29 @@ RpcCodecs.registerCodec(ResolvedDependencyKind, {
888886
/**
889887
* Register RPC codec for NodeResolutionResult marker.
890888
* This handles serialization/deserialization for communication between JS and Java.
889+
* Note: We avoid Immer here because the dependency graph can contain cycles
890+
* (e.g., Dependency -> ResolvedDependency -> Dependency[]), and Immer's proxies
891+
* don't handle cyclic structures correctly.
891892
*/
892893
RpcCodecs.registerCodec(NodeResolutionResultKind, {
893894
async rpcReceive(before: NodeResolutionResult, q: RpcReceiveQueue): Promise<NodeResolutionResult> {
894-
const draft = createDraft(before);
895-
draft.id = await q.receive(before.id);
896-
draft.name = await q.receive(before.name);
897-
draft.version = await q.receive(before.version);
898-
draft.description = await q.receive(before.description);
899-
draft.path = await q.receive(before.path);
900-
draft.workspacePackagePaths = await q.receive(before.workspacePackagePaths);
901-
902-
draft.dependencies = (await q.receiveList(before.dependencies)) || [];
903-
draft.devDependencies = (await q.receiveList(before.devDependencies)) || [];
904-
draft.peerDependencies = (await q.receiveList(before.peerDependencies)) || [];
905-
draft.optionalDependencies = (await q.receiveList(before.optionalDependencies)) || [];
906-
draft.bundledDependencies = (await q.receiveList(before.bundledDependencies)) || [];
907-
draft.resolvedDependencies = (await q.receiveList(before.resolvedDependencies)) || [];
908-
909-
draft.packageManager = await q.receive(before.packageManager);
910-
draft.engines = await q.receive(before.engines);
911-
draft.npmrcConfigs = (await q.receiveList(before.npmrcConfigs)) || undefined;
912-
913-
return finishDraft(draft) as NodeResolutionResult;
895+
return updateIfChanged(before, {
896+
id: await q.receive(before.id),
897+
name: await q.receive(before.name),
898+
version: await q.receive(before.version),
899+
description: await q.receive(before.description),
900+
path: await q.receive(before.path),
901+
workspacePackagePaths: await q.receive(before.workspacePackagePaths),
902+
dependencies: (await q.receiveList(before.dependencies)) || [],
903+
devDependencies: (await q.receiveList(before.devDependencies)) || [],
904+
peerDependencies: (await q.receiveList(before.peerDependencies)) || [],
905+
optionalDependencies: (await q.receiveList(before.optionalDependencies)) || [],
906+
bundledDependencies: (await q.receiveList(before.bundledDependencies)) || [],
907+
resolvedDependencies: (await q.receiveList(before.resolvedDependencies)) || [],
908+
packageManager: await q.receive(before.packageManager),
909+
engines: await q.receive(before.engines),
910+
npmrcConfigs: (await q.receiveList(before.npmrcConfigs)) || undefined,
911+
});
914912
},
915913

916914
async rpcSend(after: NodeResolutionResult, q: RpcSendQueue): Promise<void> {

0 commit comments

Comments
 (0)