Skip to content

Commit f9d37d0

Browse files
committed
add a removals codemod
1 parent 2fe335d commit f9d37d0

7 files changed

Lines changed: 1654 additions & 1 deletion

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
"./react/internal": "./src/react/internal/index.ts",
6060
"./react/internal/compiler-runtime": "./src/react/internal/compiler-runtime/index.ts",
6161
"./react/ssr": "./src/react/ssr/index.ts",
62+
"./removals": "./src/removals.ts",
6263
"./testing": "./src/testing/index.ts",
6364
"./testing/react": "./src/testing/react/index.ts",
6465
"./utilities": "./src/utilities/index.ts",

scripts/codemods/ac3-to-ac4/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ npx @apollo/client-codemod-migrate-3-to-4 --parser ts file1.ts file2.ts --codem
1717
- `imports`: Moves imports that have been moved or renamed in Apollo Client 4. Also moves types into namespace imports where applicable.
1818
- `links`: Moves `split`, `from`, `concat` and `empty` onto the `ApolloLink` namespace, changes funtion link invocations like `createHttpLink(...)` to their class equivalents like (`new HttpLink(...)`).
1919
Does not change `setContext((operation, prevContext) => {})` to `new ContextLink((prevContext, operation) => {})` - this requires manual intervention, as the order of callback arguments is flipped and this is not reliable codemoddable.
20+
- `removals`: Points all imports of values or types that have been removed in Apollo Client 4 to the `@apollo/client/removals` namespace. That export contains context for each removal, oftentimes with migration instructions.
2021

2122
### Usage against TypeScript/TSX
2223

scripts/codemods/ac3-to-ac4/src/__tests__/__snapshots__/removals.test.ts.snap

Lines changed: 750 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { describe, expect, test } from "vitest";
2+
3+
import removals from "../removals.js";
4+
5+
import { createDiff } from "./diffTransform.js";
6+
import allExports from "./exports.json" with { type: "json" };
7+
const diff = createDiff(removals);
8+
9+
test("all exports", () => {
10+
const source = Object.entries(allExports)
11+
.map(([entryPoint, exports]) =>
12+
`
13+
import {
14+
${exports
15+
.map(
16+
(info) =>
17+
`${info.name} as ${entryPoint
18+
.replace(/@apollo\/client\/?/, "")
19+
.replace(/[/-]/g, "_")}_${info.name}`
20+
)
21+
.join(",\n ")},
22+
} from "${entryPoint}";
23+
`.trim()
24+
)
25+
.join("\n\n");
26+
27+
//console.log(source);
28+
29+
expect(diff(source)).toMatchSnapshot();
30+
});

scripts/codemods/ac3-to-ac4/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ import type { API, FileInfo, Options, Transform } from "jscodeshift";
22

33
import imports from "./imports.js";
44
import links from "./links.js";
5+
import removals from "./removals.js";
56

6-
export const codemods = { imports, links } satisfies Record<string, Transform>;
7+
export const codemods = { imports, links, removals } satisfies Record<
8+
string,
9+
Transform
10+
>;
711

812
export default async function transform(
913
file: FileInfo,
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
import type { Transform } from "jscodeshift";
2+
3+
import type { IdentifierRename } from "./renames.js";
4+
import { handleIdentiferRename } from "./util/handleIdentiferRename.js";
5+
6+
// prettier-ignore
7+
const removals = [
8+
{ importType: "type", module: "@apollo/client", identifier: "ClientParseError" },
9+
{ importType: "type", module: "@apollo/client", identifier: "FetchMoreQueryOptions" },
10+
{ importType: "type", module: "@apollo/client", identifier: "FragmentMatcher" },
11+
{ importType: "type", module: "@apollo/client", identifier: "MethodKeys" },
12+
{ importType: "type", module: "@apollo/client", identifier: "MutationUpdaterFn" },
13+
{ importType: "type", module: "@apollo/client", identifier: "PureQueryOptions" },
14+
{ importType: "type", module: "@apollo/client", identifier: "Resolver" },
15+
{ importType: "type", module: "@apollo/client", identifier: "Resolvers" },
16+
{ importType: "type", module: "@apollo/client/errors", identifier: "ApolloErrorOptions" },
17+
{ importType: "type", module: "@apollo/client/errors", identifier: "GraphQLErrors" },
18+
{ importType: "type", module: "@apollo/client/errors", identifier: "NetworkError" },
19+
{ importType: "type", module: "@apollo/client/link/batch", identifier: "BatchableRequest" },
20+
{ importType: "type", module: "@apollo/client/link/http", identifier: "ClientParseError" },
21+
{ importType: "type", module: "@apollo/client/react", identifier: "BaseMutationOptions" },
22+
{ importType: "type", module: "@apollo/client/react", identifier: "BaseQueryOptions" },
23+
{ importType: "type", module: "@apollo/client/react", identifier: "CommonOptions" },
24+
{ importType: "type", module: "@apollo/client/react", identifier: "IDocumentDefinition" },
25+
{ importType: "type", module: "@apollo/client/react", identifier: "MutationDataOptions" },
26+
{ importType: "type", module: "@apollo/client/react", identifier: "ObservableQueryFields" },
27+
{ importType: "type", module: "@apollo/client/react", identifier: "QueryDataOptions" },
28+
{ importType: "type", module: "@apollo/client/react", identifier: "QueryLazyOptions" },
29+
{ importType: "type", module: "@apollo/client/react", identifier: "RefetchQueriesFunction" },
30+
{ importType: "type", module: "@apollo/client/react", identifier: "SubscriptionCurrentObservable" },
31+
{ importType: "type", module: "@apollo/client/react/components", identifier: "MutationComponentOptions" },
32+
{ importType: "type", module: "@apollo/client/react/components", identifier: "QueryComponentOptions" },
33+
{ importType: "type", module: "@apollo/client/react/components", identifier: "SubscriptionComponentOptions" },
34+
{ importType: "type", module: "@apollo/client/react/context", identifier: "ApolloConsumerProps" },
35+
{ importType: "type", module: "@apollo/client/react/hoc", identifier: "ChildDataProps" },
36+
{ importType: "type", module: "@apollo/client/react/hoc", identifier: "ChildMutateProps" },
37+
{ importType: "type", module: "@apollo/client/react/hoc", identifier: "ChildProps" },
38+
{ importType: "type", module: "@apollo/client/react/hoc", identifier: "DataProps" },
39+
{ importType: "type", module: "@apollo/client/react/hoc", identifier: "DataValue" },
40+
{ importType: "type", module: "@apollo/client/react/hoc", identifier: "MutateProps" },
41+
{ importType: "type", module: "@apollo/client/react/hoc", identifier: "OperationOption" },
42+
{ importType: "type", module: "@apollo/client/react/hoc", identifier: "OptionProps" },
43+
{ importType: "type", module: "@apollo/client/react/hoc", identifier: "QueryControls" },
44+
{ importType: "type", module: "@apollo/client/react/hoc", identifier: "WithApolloClient" },
45+
{ importType: "type", module: "@apollo/client/react/parser", identifier: "IDocumentDefinition" },
46+
{ importType: "type", module: "@apollo/client/utilities", identifier: "ConcastSourcesArray" },
47+
{ importType: "type", module: "@apollo/client/utilities", identifier: "ConcastSourcesIterable" },
48+
{ importType: "type", module: "@apollo/client/utilities", identifier: "DirectiveInfo" },
49+
{ importType: "type", module: "@apollo/client/utilities", identifier: "Directives" },
50+
{ importType: "type", module: "@apollo/client/utilities", identifier: "GetDirectiveConfig" },
51+
{ importType: "type", module: "@apollo/client/utilities", identifier: "GetFragmentSpreadConfig" },
52+
{ importType: "type", module: "@apollo/client/utilities", identifier: "GetNodeConfig" },
53+
{ importType: "type", module: "@apollo/client/utilities", identifier: "InclusionDirectives" },
54+
{ importType: "type", module: "@apollo/client/utilities", identifier: "IsStrictlyAny" },
55+
{ importType: "type", module: "@apollo/client/utilities", identifier: "OnlyRequiredProperties" },
56+
{ importType: "type", module: "@apollo/client/utilities", identifier: "PromiseWithState" },
57+
{ importType: "type", module: "@apollo/client/utilities", identifier: "ReconcilerFunction" },
58+
{ importType: "type", module: "@apollo/client/utilities", identifier: "RemoveArgumentsConfig" },
59+
{ importType: "type", module: "@apollo/client/utilities", identifier: "RemoveDirectiveConfig" },
60+
{ importType: "type", module: "@apollo/client/utilities", identifier: "RemoveFragmentDefinitionConfig" },
61+
{ importType: "type", module: "@apollo/client/utilities", identifier: "RemoveFragmentSpreadConfig" },
62+
{ importType: "type", module: "@apollo/client/utilities", identifier: "RemoveNodeConfig" },
63+
{ importType: "type", module: "@apollo/client/utilities", identifier: "RemoveVariableDefinitionConfig" },
64+
{ importType: "type", module: "@apollo/client/utilities", identifier: "TupleToIntersection" },
65+
{ importType: "type", module: "@apollo/client/utilities", identifier: "UnionToIntersection" },
66+
{ importType: "type", module: "@apollo/client/utilities", identifier: "VariableValue" },
67+
{ importType: "value", module: "@apollo/client", identifier: "ApolloError" },
68+
{ importType: "value", module: "@apollo/client", identifier: "DataProxy" },
69+
{ importType: "value", module: "@apollo/client", identifier: "fromError" },
70+
{ importType: "value", module: "@apollo/client", identifier: "fromPromise" },
71+
{ importType: "value", module: "@apollo/client", identifier: "isApolloError" },
72+
{ importType: "value", module: "@apollo/client", identifier: "ObservableSubscription" },
73+
{ importType: "value", module: "@apollo/client", identifier: "Observer" },
74+
{ importType: "value", module: "@apollo/client", identifier: "serializeFetchParameter" },
75+
{ importType: "value", module: "@apollo/client", identifier: "throwServerError" },
76+
{ importType: "value", module: "@apollo/client", identifier: "toPromise" },
77+
{ importType: "value", module: "@apollo/client/cache", identifier: "DataProxy" },
78+
{ importType: "value", module: "@apollo/client/errors", identifier: "ApolloError" },
79+
{ importType: "value", module: "@apollo/client/errors", identifier: "isApolloError" },
80+
{ importType: "value", module: "@apollo/client/link/batch", identifier: "OperationBatcher" },
81+
{ importType: "value", module: "@apollo/client/link/http", identifier: "serializeFetchParameter" },
82+
{ importType: "value", module: "@apollo/client/link/utils", identifier: "fromError" },
83+
{ importType: "value", module: "@apollo/client/link/utils", identifier: "fromPromise" },
84+
{ importType: "value", module: "@apollo/client/link/utils", identifier: "throwServerError" },
85+
{ importType: "value", module: "@apollo/client/link/utils", identifier: "toPromise" },
86+
{ importType: "value", module: "@apollo/client/link/utils", identifier: "transformOperation" },
87+
{ importType: "value", module: "@apollo/client/link/utils", identifier: "validateOperation" },
88+
{ importType: "value", module: "@apollo/client/react", identifier: "ApolloConsumer" },
89+
{ importType: "value", module: "@apollo/client/react", identifier: "DocumentType" },
90+
{ importType: "value", module: "@apollo/client/react", identifier: "operationName" },
91+
{ importType: "value", module: "@apollo/client/react", identifier: "parser" },
92+
{ importType: "value", module: "@apollo/client/react", identifier: "resetApolloContext" },
93+
{ importType: "value", module: "@apollo/client/react/components", identifier: "Mutation" },
94+
{ importType: "value", module: "@apollo/client/react/components", identifier: "Query" },
95+
{ importType: "value", module: "@apollo/client/react/components", identifier: "Subscription" },
96+
{ importType: "value", module: "@apollo/client/react/context", identifier: "ApolloConsumer" },
97+
{ importType: "value", module: "@apollo/client/react/context", identifier: "resetApolloContext" },
98+
{ importType: "value", module: "@apollo/client/react/hoc", identifier: "graphql" },
99+
{ importType: "value", module: "@apollo/client/react/hoc", identifier: "withApollo" },
100+
{ importType: "value", module: "@apollo/client/react/hoc", identifier: "withMutation" },
101+
{ importType: "value", module: "@apollo/client/react/hoc", identifier: "withQuery" },
102+
{ importType: "value", module: "@apollo/client/react/hoc", identifier: "withSubscription" },
103+
{ importType: "value", module: "@apollo/client/react/parser", identifier: "DocumentType" },
104+
{ importType: "value", module: "@apollo/client/react/parser", identifier: "operationName" },
105+
{ importType: "value", module: "@apollo/client/react/parser", identifier: "parser" },
106+
{ importType: "value", module: "@apollo/client/react/parser", identifier: "verifyDocumentType" },
107+
{ importType: "value", module: "@apollo/client/react/ssr", identifier: "RenderPromises" },
108+
{ importType: "value", module: "@apollo/client/testing", identifier: "createMockClient" },
109+
{ importType: "value", module: "@apollo/client/testing", identifier: "itAsync" },
110+
{ importType: "value", module: "@apollo/client/testing", identifier: "mockObservableLink" },
111+
{ importType: "value", module: "@apollo/client/testing", identifier: "mockSingleLink" },
112+
{ importType: "value", module: "@apollo/client/testing", identifier: "subscribeAndCount" },
113+
{ importType: "value", module: "@apollo/client/testing", identifier: "tick" },
114+
{ importType: "value", module: "@apollo/client/testing", identifier: "wait" },
115+
{ importType: "value", module: "@apollo/client/testing", identifier: "withErrorSpy" },
116+
{ importType: "value", module: "@apollo/client/testing", identifier: "withLogSpy" },
117+
{ importType: "value", module: "@apollo/client/testing", identifier: "withWarningSpy" },
118+
{ importType: "value", module: "@apollo/client/testing/core", identifier: "createMockClient" },
119+
{ importType: "value", module: "@apollo/client/testing/core", identifier: "itAsync" },
120+
{ importType: "value", module: "@apollo/client/testing/core", identifier: "mockObservableLink" },
121+
{ importType: "value", module: "@apollo/client/testing/core", identifier: "mockSingleLink" },
122+
{ importType: "value", module: "@apollo/client/testing/core", identifier: "subscribeAndCount" },
123+
{ importType: "value", module: "@apollo/client/testing/core", identifier: "tick" },
124+
{ importType: "value", module: "@apollo/client/testing/core", identifier: "withErrorSpy" },
125+
{ importType: "value", module: "@apollo/client/testing/core", identifier: "withLogSpy" },
126+
{ importType: "value", module: "@apollo/client/testing/core", identifier: "withWarningSpy" },
127+
{ importType: "value", module: "@apollo/client/testing/experimental", identifier: "createSchemaFetch" },
128+
{ importType: "value", module: "@apollo/client/testing/experimental", identifier: "createTestSchema" },
129+
{ importType: "value", module: "@apollo/client/utilities", identifier: "addNonReactiveToNamedFragments" },
130+
{ importType: "value", module: "@apollo/client/utilities", identifier: "asyncMap" },
131+
{ importType: "value", module: "@apollo/client/utilities", identifier: "buildQueryFromSelectionSet" },
132+
{ importType: "value", module: "@apollo/client/utilities", identifier: "canUseAsyncIteratorSymbol" },
133+
{ importType: "value", module: "@apollo/client/utilities", identifier: "canUseLayoutEffect" },
134+
{ importType: "value", module: "@apollo/client/utilities", identifier: "canUseSymbol" },
135+
{ importType: "value", module: "@apollo/client/utilities", identifier: "canUseWeakMap" },
136+
{ importType: "value", module: "@apollo/client/utilities", identifier: "canUseWeakSet" },
137+
{ importType: "value", module: "@apollo/client/utilities", identifier: "Concast" },
138+
{ importType: "value", module: "@apollo/client/utilities", identifier: "defaultCacheSizes" },
139+
{ importType: "value", module: "@apollo/client/utilities", identifier: "fixObservableSubclass" },
140+
{ importType: "value", module: "@apollo/client/utilities", identifier: "getDirectiveNames" },
141+
{ importType: "value", module: "@apollo/client/utilities", identifier: "getFragmentMaskMode" },
142+
{ importType: "value", module: "@apollo/client/utilities", identifier: "getInclusionDirectives" },
143+
{ importType: "value", module: "@apollo/client/utilities", identifier: "getTypenameFromResult" },
144+
{ importType: "value", module: "@apollo/client/utilities", identifier: "hasAllDirectives" },
145+
{ importType: "value", module: "@apollo/client/utilities", identifier: "hasAnyDirectives" },
146+
{ importType: "value", module: "@apollo/client/utilities", identifier: "hasClientExports" },
147+
{ importType: "value", module: "@apollo/client/utilities", identifier: "isApolloPayloadResult" },
148+
{ importType: "value", module: "@apollo/client/utilities", identifier: "isExecutionPatchIncrementalResult" },
149+
{ importType: "value", module: "@apollo/client/utilities", identifier: "isExecutionPatchInitialResult" },
150+
{ importType: "value", module: "@apollo/client/utilities", identifier: "isExecutionPatchResult" },
151+
{ importType: "value", module: "@apollo/client/utilities", identifier: "isFullyUnmaskedOperation" },
152+
{ importType: "value", module: "@apollo/client/utilities", identifier: "isInlineFragment" },
153+
{ importType: "value", module: "@apollo/client/utilities", identifier: "isStatefulPromise" },
154+
{ importType: "value", module: "@apollo/client/utilities", identifier: "iterateObserversSafely" },
155+
{ importType: "value", module: "@apollo/client/utilities", identifier: "mergeIncrementalData" },
156+
{ importType: "value", module: "@apollo/client/utilities", identifier: "ObservableSubscription" },
157+
{ importType: "value", module: "@apollo/client/utilities", identifier: "Observer" },
158+
{ importType: "value", module: "@apollo/client/utilities", identifier: "removeArgumentsFromDocument" },
159+
{ importType: "value", module: "@apollo/client/utilities", identifier: "removeClientSetsFromDocument" },
160+
{ importType: "value", module: "@apollo/client/utilities", identifier: "removeConnectionDirectiveFromDocument" },
161+
{ importType: "value", module: "@apollo/client/utilities", identifier: "removeFragmentSpreadFromDocument" },
162+
{ importType: "value", module: "@apollo/client/utilities", identifier: "valueToObjectRepresentation" },
163+
] satisfies Array<{
164+
module: string;
165+
identifier: string;
166+
importType: "type" | "value";
167+
}>;
168+
169+
const removalsTransform: Transform = function transform(file, api) {
170+
const j = api.jscodeshift;
171+
const source = j(file.source);
172+
const context = { j, source };
173+
174+
let modified = false;
175+
for (const removal of removals) {
176+
const rename: IdentifierRename = {
177+
from: {
178+
module: removal.module,
179+
identifier: removal.identifier,
180+
alternativeModules: ["@apollo/client", "@apollo/client/core"],
181+
},
182+
to: { module: "@apollo/client/removals", alternativeModules: [] },
183+
importType: removal.importType,
184+
};
185+
handleIdentiferRename({
186+
rename,
187+
context,
188+
onModify: () => {
189+
modified = true;
190+
},
191+
});
192+
}
193+
return modified ? source.toSource() : undefined;
194+
};
195+
export default removalsTransform;

0 commit comments

Comments
 (0)