@ethlete/query 6.0.0-next.51 → 6.0.0-next.53
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/CHANGELOG.md +78 -0
- package/fesm2022/ethlete-query-ngrx-toolkit.mjs +393 -0
- package/fesm2022/ethlete-query-ngrx-toolkit.mjs.map +1 -0
- package/fesm2022/ethlete-query-testing.mjs +67 -25
- package/fesm2022/ethlete-query-testing.mjs.map +1 -1
- package/fesm2022/ethlete-query.mjs +7895 -7226
- package/fesm2022/ethlete-query.mjs.map +1 -1
- package/generators/generators.json +5 -0
- package/generators/migrate-from-ngrx-toolkit/args-assignability.js +140 -0
- package/generators/migrate-from-ngrx-toolkit/consumers.js +521 -0
- package/generators/migrate-from-ngrx-toolkit/creators.js +301 -0
- package/generators/migrate-from-ngrx-toolkit/facade.js +295 -0
- package/generators/migrate-from-ngrx-toolkit/feature.js +513 -0
- package/generators/migrate-from-ngrx-toolkit/migration.js +140 -0
- package/generators/migrate-from-ngrx-toolkit/report.js +154 -0
- package/generators/migrate-from-ngrx-toolkit/schema.json +42 -0
- package/generators/migrate-from-ngrx-toolkit/store-removal.js +633 -0
- package/generators/migrate-from-ngrx-toolkit/ts-edits.js +128 -0
- package/generators/migrate-query-opt-in-features/migration.js +10 -9
- package/generators/migrate-to-query-v3/auth-provider-scaffold.js +29 -2
- package/generators/migrate-to-query-v3/cleanup-migration.js +163 -53
- package/generators/migrate-to-query-v3/legacy-query-creator-migration.js +39 -2
- package/generators/migrate-to-query-v3/migration-scope.js +2 -0
- package/generators/migrate-to-query-v3/migration.js +5 -4
- package/generators/migrate-to-query-v3/module-graph.js +41 -29
- package/generators/migrate-to-query-v3/query-client-migration.js +209 -126
- package/generators/migrate-to-query-v3/rename-symbols.js +38 -11
- package/generators/migrate-to-query-v3/report.js +40 -7
- package/generators/migrate-to-query-v3/shared.js +46 -1
- package/generators/prep-for-query-v3/migration.js +400 -57
- package/migrations/query-field-default-types.md +43 -0
- package/migrations/search-query-field-string.md +43 -0
- package/migrations.json +16 -0
- package/package.json +5 -1
- package/types/ethlete-query-ngrx-toolkit.d.ts +143 -0
- package/types/ethlete-query-testing.d.ts +28 -11
- package/types/ethlete-query.d.ts +789 -584
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
export const TOOLKIT_MIGRATION_REPORT_PATH = 'query-toolkit-migration-tasks.md';
|
|
2
|
+
/** Stable task ids. A task keeps its id across runs, so a follow-up list can be diffed and ticked off. */
|
|
3
|
+
export const TOOLKIT_TASK = {
|
|
4
|
+
MIXED_ACTIONS: 'NTK-MIXED-ACTIONS',
|
|
5
|
+
CUSTOM_EFFECT: 'NTK-CUSTOM-EFFECT',
|
|
6
|
+
CUSTOM_REDUCER: 'NTK-CUSTOM-REDUCER',
|
|
7
|
+
ACTION_WITHOUT_EFFECT: 'NTK-ACTION-WITHOUT-EFFECT',
|
|
8
|
+
SERVICE_UNSUPPORTED: 'NTK-SERVICE-UNSUPPORTED',
|
|
9
|
+
SERVICE_API_BASE: 'NTK-SERVICE-API-BASE',
|
|
10
|
+
SERVICE_HEADERS: 'NTK-SERVICE-HEADERS',
|
|
11
|
+
SERVICE_CACHE_EXPIRY: 'NTK-SERVICE-CACHE-EXPIRY',
|
|
12
|
+
ARGS_UNRESOLVED: 'NTK-ARGS-UNRESOLVED',
|
|
13
|
+
ARGS_INHERITED: 'NTK-ARGS-INHERITED',
|
|
14
|
+
FACADE_STORE_MEMBER: 'NTK-FACADE-STORE-MEMBER',
|
|
15
|
+
FACADE_WITHOUT_HTTP: 'NTK-FACADE-WITHOUT-HTTP',
|
|
16
|
+
DUPLICATE_ROUTE_MISMATCH: 'NTK-DUPLICATE-ROUTE-MISMATCH',
|
|
17
|
+
STORE_FILE_KEPT: 'NTK-STORE-FILE-KEPT',
|
|
18
|
+
COMMENTED_FEATURE: 'NTK-COMMENTED-FEATURE',
|
|
19
|
+
};
|
|
20
|
+
const TASK_DEFINITIONS = {
|
|
21
|
+
[TOOLKIT_TASK.MIXED_ACTIONS]: {
|
|
22
|
+
title: 'Feature has actions besides HTTP action groups',
|
|
23
|
+
action: 'Move the plain NgRx actions (and the facade members that dispatch them) out of the feature, then re-run the generator. The feature was left on the toolkit.',
|
|
24
|
+
},
|
|
25
|
+
[TOOLKIT_TASK.CUSTOM_EFFECT]: {
|
|
26
|
+
title: 'Feature has effects besides onAction* calls',
|
|
27
|
+
action: 'Move the custom effect out of the feature (or rewrite it on the v3 creator), then re-run the generator. The feature was left on the toolkit.',
|
|
28
|
+
},
|
|
29
|
+
[TOOLKIT_TASK.CUSTOM_REDUCER]: {
|
|
30
|
+
title: 'Feature reducer holds extra state',
|
|
31
|
+
action: 'The reducer keeps state besides the toolkit slice. Move that state out of the feature, then re-run the generator. The feature was left on the toolkit.',
|
|
32
|
+
},
|
|
33
|
+
[TOOLKIT_TASK.ACTION_WITHOUT_EFFECT]: {
|
|
34
|
+
title: 'Action group has no effect',
|
|
35
|
+
action: 'No effect sends this action group to the service, so the generator cannot tell which request it makes. Wire it up or delete it, then re-run. The feature was left on the toolkit.',
|
|
36
|
+
},
|
|
37
|
+
[TOOLKIT_TASK.SERVICE_UNSUPPORTED]: {
|
|
38
|
+
title: 'Service method the generator cannot read',
|
|
39
|
+
action: 'Rewrite the method to a plain `return this.get|post|put|patch|delete({ apiRoute, httpOpts: args, responseType })`, or write the v3 creator by hand. The feature was left on the toolkit.',
|
|
40
|
+
},
|
|
41
|
+
[TOOLKIT_TASK.SERVICE_API_BASE]: {
|
|
42
|
+
title: 'Service talks to another API base',
|
|
43
|
+
action: 'The service does not use the API base of the v3 client. Point a creator of the matching v3 client at it by hand. The feature was left on the toolkit.',
|
|
44
|
+
},
|
|
45
|
+
[TOOLKIT_TASK.SERVICE_HEADERS]: {
|
|
46
|
+
title: 'Service set request headers',
|
|
47
|
+
action: 'The service added headers the creator does not send. Pass them per call (`actionOptions.headers`) or add them to the client, then check the request.',
|
|
48
|
+
},
|
|
49
|
+
[TOOLKIT_TASK.SERVICE_CACHE_EXPIRY]: {
|
|
50
|
+
title: 'Service cached responses for a fixed time',
|
|
51
|
+
action: 'The toolkit kept this response for `cacheExpiresIn` seconds; the v3 creator requests again on every call. Decide whether the screen needs a cache.',
|
|
52
|
+
},
|
|
53
|
+
[TOOLKIT_TASK.ARGS_UNRESOLVED]: {
|
|
54
|
+
title: 'Args type the generator cannot read',
|
|
55
|
+
action: 'Declare the args as an interface or type literal with `queryParams` / `params` / `body` in the models file, then re-run. The feature was left on the toolkit.',
|
|
56
|
+
},
|
|
57
|
+
[TOOLKIT_TASK.ARGS_INHERITED]: {
|
|
58
|
+
title: 'Args type extends another type',
|
|
59
|
+
action: 'Only the members declared on the args type itself were mapped to the creator. If the base type adds `queryParams`, `params` or `body`, add them to the creator type.',
|
|
60
|
+
},
|
|
61
|
+
[TOOLKIT_TASK.FACADE_STORE_MEMBER]: {
|
|
62
|
+
title: 'Facade member uses the NgRx store',
|
|
63
|
+
action: 'Rewrite or remove the member (for example a `resetFeatureStore` dispatch), then re-run the generator. The feature was left on the toolkit.',
|
|
64
|
+
},
|
|
65
|
+
[TOOLKIT_TASK.FACADE_WITHOUT_HTTP]: {
|
|
66
|
+
title: 'Toolkit facade without HTTP state',
|
|
67
|
+
action: 'The facade extends `FacadeBase` but has no action groups. Drop `FacadeBase` and the store wiring by hand once nothing reads its state.',
|
|
68
|
+
},
|
|
69
|
+
[TOOLKIT_TASK.DUPLICATE_ROUTE_MISMATCH]: {
|
|
70
|
+
title: 'A v3 creator for the route already exists with other types',
|
|
71
|
+
action: 'The generator wrote a second creator. Merge the two once the types agree, and keep one.',
|
|
72
|
+
},
|
|
73
|
+
[TOOLKIT_TASK.STORE_FILE_KEPT]: {
|
|
74
|
+
title: 'Store files kept because code outside the feature uses them',
|
|
75
|
+
action: 'The facade now uses the v3 creators, but the listed code still imports the reducer, effects, selectors, service or action record. Rewrite it, then delete the store files and their registration.',
|
|
76
|
+
},
|
|
77
|
+
[TOOLKIT_TASK.COMMENTED_FEATURE]: {
|
|
78
|
+
title: 'Commented-out toolkit feature',
|
|
79
|
+
action: 'The feature only exists as comments. Delete the folder or restore it.',
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Collects the follow-up tasks of a toolkit migration run and writes them to
|
|
84
|
+
* `query-toolkit-migration-tasks.md`. Tasks are grouped by their stable id.
|
|
85
|
+
*/
|
|
86
|
+
export class ToolkitMigrationReport {
|
|
87
|
+
constructor() {
|
|
88
|
+
this.tasks = [];
|
|
89
|
+
this.definitions = new Map(Object.entries(TASK_DEFINITIONS));
|
|
90
|
+
}
|
|
91
|
+
/** Registers a task id another migration phase records, so its title and action render in the report. */
|
|
92
|
+
define(id, definition) {
|
|
93
|
+
this.definitions.set(id, definition);
|
|
94
|
+
}
|
|
95
|
+
add(input) {
|
|
96
|
+
const definition = this.definitions.get(input.id);
|
|
97
|
+
if (!definition) {
|
|
98
|
+
throw new Error(`Unknown toolkit migration task id "${input.id}".`);
|
|
99
|
+
}
|
|
100
|
+
const duplicate = this.tasks.some((task) => task.id === input.id &&
|
|
101
|
+
task.summary === input.summary &&
|
|
102
|
+
task.locations[0]?.filePath === input.locations[0]?.filePath);
|
|
103
|
+
if (!duplicate) {
|
|
104
|
+
this.tasks.push({ ...definition, ...input });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
count(id) {
|
|
108
|
+
return this.tasks.filter((task) => task.id === id).length;
|
|
109
|
+
}
|
|
110
|
+
printSummary() {
|
|
111
|
+
if (this.tasks.length === 0)
|
|
112
|
+
return;
|
|
113
|
+
const ids = [...new Set(this.tasks.map((task) => task.id))];
|
|
114
|
+
console.warn(`\n⚠️ Recorded ${this.tasks.length} follow-up task${this.tasks.length === 1 ? '' : 's'}:`);
|
|
115
|
+
ids.forEach((id) => console.warn(` - ${id}: ${this.count(id)}`));
|
|
116
|
+
console.warn(`\n📄 See ${TOOLKIT_MIGRATION_REPORT_PATH} for the list.`);
|
|
117
|
+
}
|
|
118
|
+
writeToTree(tree) {
|
|
119
|
+
tree.write(TOOLKIT_MIGRATION_REPORT_PATH, renderToolkitReport(this.tasks));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const renderLocation = (location) => `${location.filePath}${location.line ? `:${location.line}` : ''}`;
|
|
123
|
+
export const renderToolkitReport = (tasks) => {
|
|
124
|
+
const header = [
|
|
125
|
+
'# NgRx Toolkit Migration Follow-Up',
|
|
126
|
+
'',
|
|
127
|
+
'Generated by the `@ethlete/query:migrate-from-ngrx-toolkit` generator.',
|
|
128
|
+
'',
|
|
129
|
+
'## Instructions',
|
|
130
|
+
'',
|
|
131
|
+
'1. Re-read the listed files before changing anything.',
|
|
132
|
+
'2. Tasks that say "left on the toolkit" can be re-run: fix the cause, then run the generator again.',
|
|
133
|
+
'3. Remove a task only once the code and its tests confirm it is resolved.',
|
|
134
|
+
'',
|
|
135
|
+
];
|
|
136
|
+
if (tasks.length === 0) {
|
|
137
|
+
return [...header, '## Tasks', '', 'No follow-up tasks were recorded.', ''].join('\n');
|
|
138
|
+
}
|
|
139
|
+
const ids = [...new Set(tasks.map((task) => task.id))];
|
|
140
|
+
const sections = ids.flatMap((id) => {
|
|
141
|
+
const group = tasks.filter((task) => task.id === id);
|
|
142
|
+
const first = group[0];
|
|
143
|
+
return [
|
|
144
|
+
`### ${id} - ${first.title}`,
|
|
145
|
+
'',
|
|
146
|
+
`Action: ${first.action}`,
|
|
147
|
+
'',
|
|
148
|
+
...group.map((task) => `- [ ] ${task.summary} (${task.locations.map(renderLocation).join(', ') || 'no location'})`),
|
|
149
|
+
'',
|
|
150
|
+
];
|
|
151
|
+
});
|
|
152
|
+
return [...header, '## Tasks', '', ...sections].join('\n');
|
|
153
|
+
};
|
|
154
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/schema",
|
|
3
|
+
"$id": "migrate-from-ngrx-toolkit",
|
|
4
|
+
"title": "Migrate from @tomtomb/ngrx-toolkit",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"properties": {
|
|
7
|
+
"client": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"description": "The v3 query client the creators are built on, e.g. `apiClient` (or its `apiClientConfig`). Its generated helpers (`apiGet`, `apiPostSecure`, …) must exist - run `migrate-to-query-v3` first."
|
|
10
|
+
},
|
|
11
|
+
"clientImport": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"description": "Where the client helpers are imported from: a module specifier (e.g. `@app/queries`) or a workspace file (e.g. `libs/queries/src/lib/api.client.ts`)."
|
|
14
|
+
},
|
|
15
|
+
"publicRoutes": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "Comma separated route prefixes that are public, e.g. `/public,/status`. Every other route gets the secure helper. Without it every creator uses the public helper."
|
|
18
|
+
},
|
|
19
|
+
"serviceApiBase": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"description": "The `ServiceBase` API base the client points at, as written in the services (e.g. `environment.apiBaseURL`). Required when the services use more than one; features on the others are left alone."
|
|
22
|
+
},
|
|
23
|
+
"projects": {
|
|
24
|
+
"type": "array",
|
|
25
|
+
"items": { "type": "string" },
|
|
26
|
+
"description": "Nx projects to migrate. Defaults to every project in the workspace.",
|
|
27
|
+
"alias": "project"
|
|
28
|
+
},
|
|
29
|
+
"include": {
|
|
30
|
+
"type": "array",
|
|
31
|
+
"items": { "type": "string" },
|
|
32
|
+
"description": "Path prefixes to migrate, relative to the workspace root (e.g. 'libs/store'). Unioned with `projects`. Defaults to the whole workspace.",
|
|
33
|
+
"alias": "includePath"
|
|
34
|
+
},
|
|
35
|
+
"skipFormat": {
|
|
36
|
+
"type": "boolean",
|
|
37
|
+
"description": "Skip formatting files after migration",
|
|
38
|
+
"default": false
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"required": ["client", "clientImport"]
|
|
42
|
+
}
|