@craft-ts/dev-tools 0.7.0-beta.13 → 0.7.0-beta.15
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/README.md +64 -10
- package/package.json +8 -2
- package/src/bin/agent-selector.d.ts +22 -0
- package/src/bin/agent-selector.js +100 -0
- package/src/bin/agent-selector.js.map +1 -0
- package/src/bin/craft-graph.js +74 -8
- package/src/bin/craft-graph.js.map +1 -1
- package/src/bin/craft.d.ts +23 -0
- package/src/bin/craft.js +245 -28
- package/src/bin/craft.js.map +1 -1
- package/src/eslint-rules/anchor-has-href.cjs +37 -3
- package/src/eslint-rules/craft-computed-name-match.cjs +26 -5
- package/src/eslint-rules/craft-name-match-utils.cjs +18 -9
- package/src/eslint-rules/hyperscript-walk.cjs +3 -3
- package/src/eslint-rules/index.cjs +46 -1
- package/src/eslint-rules/no-auth-token-in-local-storage.cjs +17 -0
- package/src/eslint-rules/no-craft-computed-side-effects.cjs +12 -5
- package/src/eslint-rules/no-craft-service-component-same-file.cjs +138 -0
- package/src/eslint-rules/no-effect-import-in-frontend.cjs +52 -0
- package/src/eslint-rules/no-effect-in-params.cjs +31 -1
- package/src/eslint-rules/no-explicit-effect-type.cjs +137 -0
- package/src/eslint-rules/no-free-has.cjs +47 -0
- package/src/eslint-rules/no-heading-level-skip.cjs +6 -6
- package/src/eslint-rules/no-raw-class.cjs +76 -0
- package/src/eslint-rules/no-raw-css-value.cjs +163 -0
- package/src/eslint-rules/no-raw-user-url.cjs +114 -0
- package/src/eslint-rules/no-trust-forwarded-headers.cjs +43 -0
- package/src/eslint-rules/no-unsafe-html.cjs +93 -0
- package/src/eslint-rules/no-unsafe-transfer-state.cjs +54 -0
- package/src/eslint-rules/prefer-craft-template-blocks.cjs +8 -8
- package/src/eslint-rules/prefer-direct-yieldable-callback.cjs +57 -14
- package/src/eslint-rules/prefer-inline-effect-insertion.cjs +263 -0
- package/src/eslint-rules/prefer-inline-route-providers.cjs +138 -0
- package/src/eslint-rules/recommended-config.cjs +6 -0
- package/src/eslint-rules/require-reactive-template-bindings.cjs +8 -8
- package/src/eslint-rules/require-route-security-policy.cjs +87 -0
- package/src/eslint-rules/require-server-function-timeout.cjs +39 -0
- package/src/eslint-rules/security-config.cjs +14 -0
- package/src/eslint-rules/security-rule-utils.cjs +21 -0
- package/src/eslint-rules/style-file-boundary.cjs +75 -0
- package/src/eslint-rules/sync-effect-body.cjs +343 -0
- package/src/index.d.ts +4 -0
- package/src/index.js +4 -0
- package/src/index.js.map +1 -1
- package/src/scripts/architecture-graph.js +8 -2
- package/src/scripts/architecture-graph.js.map +1 -1
- package/src/scripts/create/create-project.d.ts +71 -1
- package/src/scripts/create/create-project.js +1937 -176
- package/src/scripts/create/create-project.js.map +1 -1
- package/src/scripts/data-flow-graph.d.ts +1 -1
- package/src/scripts/effect-dependency-graph.d.ts +1 -1
- package/src/scripts/security-check.d.ts +30 -0
- package/src/scripts/security-check.js +223 -0
- package/src/scripts/security-check.js.map +1 -0
- package/src/scripts/style-architecture.d.ts +56 -0
- package/src/scripts/style-architecture.js +142 -0
- package/src/scripts/style-architecture.js.map +1 -0
- package/src/scripts/style-graph.d.ts +99 -0
- package/src/scripts/style-graph.js +179 -0
- package/src/scripts/style-graph.js.map +1 -0
- package/src/scripts/style-report.d.ts +55 -0
- package/src/scripts/style-report.js +67 -0
- package/src/scripts/style-report.js.map +1 -0
- package/src/scripts/template/migrate-template.js +1 -1
- package/src/scripts/template/migrate-template.js.map +1 -1
- package/src/scripts/angular-brand-codemod.ts +0 -3985
- package/src/scripts/architecture/migrate-architecture.ts +0 -653
- package/src/scripts/architecture-graph.ts +0 -3136
- package/src/scripts/components/migrate-components.ts +0 -227
- package/src/scripts/components/migration-diagnostic.ts +0 -8
- package/src/scripts/create/create-project.ts +0 -849
- package/src/scripts/data-flow-graph.ts +0 -240
- package/src/scripts/dependency-graph.ts +0 -5908
- package/src/scripts/effect-dependency-graph.ts +0 -630
- package/src/scripts/migrate.ts +0 -162
- package/src/scripts/migration-workspace.ts +0 -93
- package/src/scripts/primitives/migrate-named-primitives.ts +0 -627
- package/src/scripts/primitives/migrate-primitive-generators.ts +0 -410
- package/src/scripts/primitives/migrate-primitives.ts +0 -655
- package/src/scripts/primitives/migrate-yieldable-reactive-reads.ts +0 -499
- package/src/scripts/primitives/migration-diagnostic.ts +0 -15
- package/src/scripts/routes/migrate-routes.ts +0 -895
- package/src/scripts/routes/migration-diagnostic.ts +0 -25
- package/src/scripts/routes/route-command.ts +0 -1807
- package/src/scripts/routes/verify-routes.ts +0 -1511
- package/src/scripts/services/config.ts +0 -60
- package/src/scripts/services/migrate-services.ts +0 -1348
- package/src/scripts/services/migration-diagnostic.ts +0 -28
- package/src/scripts/template/migrate-template.ts +0 -418
|
@@ -1,499 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ArrowFunction,
|
|
3
|
-
CallExpression,
|
|
4
|
-
FunctionDeclaration,
|
|
5
|
-
FunctionExpression,
|
|
6
|
-
Identifier,
|
|
7
|
-
MethodDeclaration,
|
|
8
|
-
Node,
|
|
9
|
-
SourceFile,
|
|
10
|
-
SyntaxKind,
|
|
11
|
-
} from 'ts-morph';
|
|
12
|
-
import { dirname, relative, resolve } from 'node:path';
|
|
13
|
-
|
|
14
|
-
const CRAFT_USE = 'craftUse';
|
|
15
|
-
const GENERATOR_HOSTS = new Set([
|
|
16
|
-
'asyncProcess',
|
|
17
|
-
'craftComponent',
|
|
18
|
-
'craftComputed',
|
|
19
|
-
'craftService',
|
|
20
|
-
'query',
|
|
21
|
-
'queryParams',
|
|
22
|
-
'mutation',
|
|
23
|
-
'state',
|
|
24
|
-
]);
|
|
25
|
-
|
|
26
|
-
export type YieldableReactiveReadMigrationResult = {
|
|
27
|
-
changed: boolean;
|
|
28
|
-
changedReads: number;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Converts the old synchronous reader escape hatch into the public yieldable
|
|
33
|
-
* reader contract.
|
|
34
|
-
*
|
|
35
|
-
* A reader used in a generator-capable callback becomes a local binding:
|
|
36
|
-
*
|
|
37
|
-
* ```ts
|
|
38
|
-
* const item = craftUse(state()).find(...)
|
|
39
|
-
* // becomes
|
|
40
|
-
* const _state = yield* state();
|
|
41
|
-
* const item = _state.find(...)
|
|
42
|
-
* ```
|
|
43
|
-
*
|
|
44
|
-
* Ordinary callbacks keep `craftUse(...)`, but never through an alias such as
|
|
45
|
-
* `__craftRead`. This makes the migration output match the public API and
|
|
46
|
-
* keeps non-generator boundaries explicit.
|
|
47
|
-
*/
|
|
48
|
-
export function migrateYieldableReactiveReads(
|
|
49
|
-
sourceFile: SourceFile,
|
|
50
|
-
): YieldableReactiveReadMigrationResult {
|
|
51
|
-
const craftUseAliases = findCraftUseAliases(sourceFile);
|
|
52
|
-
|
|
53
|
-
let changed = false;
|
|
54
|
-
let changedReads = 0;
|
|
55
|
-
|
|
56
|
-
// Promote compatible callbacks before processing their readers. This is
|
|
57
|
-
// intentionally iterative because a reader can be nested in an insertion
|
|
58
|
-
// method inside a primitive factory.
|
|
59
|
-
for (let pass = 0; pass < 4; pass += 1) {
|
|
60
|
-
const wrappers = findCraftUseWrappers(sourceFile, craftUseAliases);
|
|
61
|
-
let promoted = false;
|
|
62
|
-
for (const wrapper of wrappers) {
|
|
63
|
-
if (wrapper.wasForgotten()) continue;
|
|
64
|
-
const argument = unwrap(wrapper.getArguments()[0]);
|
|
65
|
-
if (!argument || !isReactiveReaderInvocation(argument, true)) continue;
|
|
66
|
-
const functionLike = nearestFunction(wrapper);
|
|
67
|
-
if (
|
|
68
|
-
functionLike &&
|
|
69
|
-
!isGenerator(functionLike) &&
|
|
70
|
-
canPromoteToGenerator(functionLike)
|
|
71
|
-
) {
|
|
72
|
-
promoteToGenerator(functionLike);
|
|
73
|
-
promoted = true;
|
|
74
|
-
changed = true;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (!promoted) break;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
for (const wrapper of findCraftUseWrappers(
|
|
81
|
-
sourceFile,
|
|
82
|
-
craftUseAliases,
|
|
83
|
-
).sort((left, right) => right.getStart() - left.getStart())) {
|
|
84
|
-
if (wrapper.wasForgotten()) continue;
|
|
85
|
-
const argument = unwrap(wrapper.getArguments()[0]);
|
|
86
|
-
if (!argument || !isReactiveReaderInvocation(argument, true)) continue;
|
|
87
|
-
|
|
88
|
-
const functionLike = nearestFunction(wrapper);
|
|
89
|
-
if (functionLike && isGenerator(functionLike)) {
|
|
90
|
-
const name = createReaderBindingName(functionLike, argument);
|
|
91
|
-
insertReaderBinding(wrapper, name, argument.getText());
|
|
92
|
-
wrapper.replaceWithText(name);
|
|
93
|
-
changed = true;
|
|
94
|
-
changedReads += 1;
|
|
95
|
-
} else {
|
|
96
|
-
wrapper.getExpression().replaceWithText(CRAFT_USE);
|
|
97
|
-
changed = true;
|
|
98
|
-
changedReads += 1;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Handle readers that were not hidden behind craftUse. This is useful for
|
|
103
|
-
// partially migrated files and makes the codemod idempotent across passes.
|
|
104
|
-
for (const call of sourceFile
|
|
105
|
-
.getDescendantsOfKind(SyntaxKind.CallExpression)
|
|
106
|
-
.sort((left, right) => right.getStart() - left.getStart())) {
|
|
107
|
-
if (call.wasForgotten() || !isReactiveReaderInvocation(call, false)) continue;
|
|
108
|
-
if (isConsumedReader(call)) continue;
|
|
109
|
-
|
|
110
|
-
const functionLike = nearestFunction(call);
|
|
111
|
-
if (!functionLike || !isGenerator(functionLike)) continue;
|
|
112
|
-
|
|
113
|
-
const name = createReaderBindingName(functionLike, call);
|
|
114
|
-
insertReaderBinding(call, name, call.getText());
|
|
115
|
-
call.replaceWithText(name);
|
|
116
|
-
changed = true;
|
|
117
|
-
changedReads += 1;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
changed = normalizeCraftUseImports(sourceFile, craftUseAliases) || changed;
|
|
121
|
-
return { changed, changedReads };
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function findCraftUseAliases(sourceFile: SourceFile): Set<string> {
|
|
125
|
-
const aliases = new Set<string>();
|
|
126
|
-
for (const declaration of sourceFile.getImportDeclarations()) {
|
|
127
|
-
const specifier = declaration
|
|
128
|
-
.getNamedImports()
|
|
129
|
-
.find((item) => item.getName() === CRAFT_USE);
|
|
130
|
-
if (specifier) aliases.add(specifier.getAliasNode()?.getText() ?? CRAFT_USE);
|
|
131
|
-
}
|
|
132
|
-
return aliases;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function findCraftUseWrappers(
|
|
136
|
-
sourceFile: SourceFile,
|
|
137
|
-
aliases: Set<string>,
|
|
138
|
-
): CallExpression[] {
|
|
139
|
-
return sourceFile
|
|
140
|
-
.getDescendantsOfKind(SyntaxKind.CallExpression)
|
|
141
|
-
.filter((call) => {
|
|
142
|
-
const expression = call.getExpression();
|
|
143
|
-
return (
|
|
144
|
-
Node.isIdentifier(expression) &&
|
|
145
|
-
aliases.has(expression.getText()) &&
|
|
146
|
-
!isShadowed(expression) &&
|
|
147
|
-
call.getArguments().length === 1
|
|
148
|
-
);
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function isShadowed(identifier: Identifier): boolean {
|
|
153
|
-
const name = identifier.getText();
|
|
154
|
-
let node: Node | undefined = identifier.getParent();
|
|
155
|
-
while (node) {
|
|
156
|
-
if (
|
|
157
|
-
Node.isFunctionDeclaration(node) ||
|
|
158
|
-
Node.isFunctionExpression(node) ||
|
|
159
|
-
Node.isArrowFunction(node) ||
|
|
160
|
-
Node.isMethodDeclaration(node)
|
|
161
|
-
) {
|
|
162
|
-
for (const parameter of node.getParameters()) {
|
|
163
|
-
const binding = parameter.getNameNode();
|
|
164
|
-
if (binding.getText() === name) return true;
|
|
165
|
-
if (
|
|
166
|
-
Node.isObjectBindingPattern(binding) &&
|
|
167
|
-
binding.getElements().some((element) => element.getName() === name)
|
|
168
|
-
)
|
|
169
|
-
return true;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
node = node.getParent();
|
|
173
|
-
}
|
|
174
|
-
return false;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function isReactiveReaderInvocation(
|
|
178
|
-
node: Node,
|
|
179
|
-
allowSyntacticReader: boolean,
|
|
180
|
-
): node is CallExpression {
|
|
181
|
-
if (!Node.isCallExpression(node) || node.getArguments().length !== 0) {
|
|
182
|
-
return false;
|
|
183
|
-
}
|
|
184
|
-
const expression = node.getExpression();
|
|
185
|
-
if (
|
|
186
|
-
allowSyntacticReader &&
|
|
187
|
-
(Node.isIdentifier(expression) || Node.isPropertyAccessExpression(expression))
|
|
188
|
-
) {
|
|
189
|
-
return true;
|
|
190
|
-
}
|
|
191
|
-
if (allowSyntacticReader && Node.isElementAccessExpression(expression)) return true;
|
|
192
|
-
return hasReactiveReaderBrand(expression.getType(), new Set());
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
function hasReactiveReaderBrand(type: any, seen: Set<any>): boolean {
|
|
196
|
-
if (!type || seen.has(type)) return false;
|
|
197
|
-
seen.add(type);
|
|
198
|
-
if (type.isUnion?.())
|
|
199
|
-
return type.getUnionTypes().some((part: any) => hasReactiveReaderBrand(part, seen));
|
|
200
|
-
if (type.isIntersection?.())
|
|
201
|
-
return type
|
|
202
|
-
.getIntersectionTypes()
|
|
203
|
-
.some((part: any) => hasReactiveReaderBrand(part, seen));
|
|
204
|
-
return type
|
|
205
|
-
.getProperties?.()
|
|
206
|
-
.some((property: any) => property.getName().includes('RAW_REACTIVE_VALUE'));
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function isConsumedReader(call: CallExpression): boolean {
|
|
210
|
-
let node: Node = call;
|
|
211
|
-
let parent = node.getParent();
|
|
212
|
-
while (
|
|
213
|
-
parent &&
|
|
214
|
-
(Node.isParenthesizedExpression(parent) ||
|
|
215
|
-
Node.isAsExpression(parent) ||
|
|
216
|
-
Node.isTypeAssertion(parent) ||
|
|
217
|
-
Node.isNonNullExpression(parent))
|
|
218
|
-
) {
|
|
219
|
-
node = parent;
|
|
220
|
-
parent = node.getParent();
|
|
221
|
-
}
|
|
222
|
-
if (Node.isYieldExpression(parent) && parent.getAsteriskToken()) return true;
|
|
223
|
-
return (
|
|
224
|
-
Node.isCallExpression(parent) &&
|
|
225
|
-
Node.isIdentifier(parent.getExpression()) &&
|
|
226
|
-
parent.getExpression().getText() === CRAFT_USE
|
|
227
|
-
);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
function nearestFunction(node: Node):
|
|
231
|
-
| ArrowFunction
|
|
232
|
-
| FunctionDeclaration
|
|
233
|
-
| FunctionExpression
|
|
234
|
-
| MethodDeclaration
|
|
235
|
-
| undefined {
|
|
236
|
-
return node.getFirstAncestor(
|
|
237
|
-
(ancestor) =>
|
|
238
|
-
Node.isArrowFunction(ancestor) ||
|
|
239
|
-
Node.isFunctionDeclaration(ancestor) ||
|
|
240
|
-
Node.isFunctionExpression(ancestor) ||
|
|
241
|
-
Node.isMethodDeclaration(ancestor),
|
|
242
|
-
) as
|
|
243
|
-
| ArrowFunction
|
|
244
|
-
| FunctionDeclaration
|
|
245
|
-
| FunctionExpression
|
|
246
|
-
| MethodDeclaration
|
|
247
|
-
| undefined;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
function isGenerator(
|
|
251
|
-
node:
|
|
252
|
-
| ArrowFunction
|
|
253
|
-
| FunctionDeclaration
|
|
254
|
-
| FunctionExpression
|
|
255
|
-
| MethodDeclaration,
|
|
256
|
-
): boolean {
|
|
257
|
-
return !Node.isArrowFunction(node) && node.isGenerator();
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
function canPromoteToGenerator(
|
|
261
|
-
functionLike:
|
|
262
|
-
| ArrowFunction
|
|
263
|
-
| FunctionDeclaration
|
|
264
|
-
| FunctionExpression
|
|
265
|
-
| MethodDeclaration,
|
|
266
|
-
): boolean {
|
|
267
|
-
if (Node.isFunctionDeclaration(functionLike)) return false;
|
|
268
|
-
let node: Node = functionLike;
|
|
269
|
-
let parent = node.getParent();
|
|
270
|
-
while (parent) {
|
|
271
|
-
if (Node.isCallExpression(parent)) {
|
|
272
|
-
const callee = parent.getExpression().getText();
|
|
273
|
-
return GENERATOR_HOSTS.has(callee) && parent.getArguments().some((arg) => arg === node);
|
|
274
|
-
}
|
|
275
|
-
if (
|
|
276
|
-
Node.isParenthesizedExpression(parent) ||
|
|
277
|
-
Node.isPropertyAssignment(parent) ||
|
|
278
|
-
Node.isObjectLiteralExpression(parent) ||
|
|
279
|
-
Node.isArrayLiteralExpression(parent) ||
|
|
280
|
-
Node.isArrowFunction(parent)
|
|
281
|
-
) {
|
|
282
|
-
node = parent;
|
|
283
|
-
parent = node.getParent();
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
|
-
return false;
|
|
287
|
-
}
|
|
288
|
-
return false;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function promoteToGenerator(
|
|
292
|
-
functionLike:
|
|
293
|
-
| ArrowFunction
|
|
294
|
-
| FunctionDeclaration
|
|
295
|
-
| FunctionExpression
|
|
296
|
-
| MethodDeclaration,
|
|
297
|
-
): void {
|
|
298
|
-
if (Node.isArrowFunction(functionLike)) {
|
|
299
|
-
const parameters = functionLike
|
|
300
|
-
.getParameters()
|
|
301
|
-
.map((parameter) => parameter.getText())
|
|
302
|
-
.join(', ');
|
|
303
|
-
const body = functionLike.getBody();
|
|
304
|
-
if (!body) return;
|
|
305
|
-
const replacement = Node.isBlock(body)
|
|
306
|
-
? `function* (${parameters}) ${body.getText()}`
|
|
307
|
-
: `function* (${parameters}) { return ${body.getText()}; }`;
|
|
308
|
-
functionLike.replaceWithText(replacement);
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
if (Node.isMethodDeclaration(functionLike)) {
|
|
312
|
-
functionLike.replaceWithText(`*${functionLike.getText()}`);
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
functionLike.replaceWithText(
|
|
316
|
-
functionLike.getText().replace(/^function\b/, 'function*'),
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
function createReaderBindingName(
|
|
321
|
-
functionLike:
|
|
322
|
-
| ArrowFunction
|
|
323
|
-
| FunctionDeclaration
|
|
324
|
-
| FunctionExpression
|
|
325
|
-
| MethodDeclaration,
|
|
326
|
-
reader: CallExpression,
|
|
327
|
-
): string {
|
|
328
|
-
const expression = reader.getExpression();
|
|
329
|
-
let base = Node.isIdentifier(expression)
|
|
330
|
-
? expression.getText()
|
|
331
|
-
: Node.isPropertyAccessExpression(expression)
|
|
332
|
-
? `${expression.getExpression().getText()}${expression.getName()}`
|
|
333
|
-
: 'value';
|
|
334
|
-
base = base.replace(/[^A-Za-z0-9_$]/g, '');
|
|
335
|
-
if (!base) base = 'value';
|
|
336
|
-
if (/^\d/.test(base)) base = `value${base}`;
|
|
337
|
-
const preferred = `_${base}`;
|
|
338
|
-
const used = new Set(
|
|
339
|
-
functionLike
|
|
340
|
-
.getDescendantsOfKind(SyntaxKind.Identifier)
|
|
341
|
-
.map((identifier) => identifier.getText()),
|
|
342
|
-
);
|
|
343
|
-
if (!used.has(preferred)) return preferred;
|
|
344
|
-
for (let index = 2; ; index += 1) {
|
|
345
|
-
const candidate = `${preferred}${index}`;
|
|
346
|
-
if (!used.has(candidate)) return candidate;
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
function insertReaderBinding(
|
|
351
|
-
reader: CallExpression,
|
|
352
|
-
name: string,
|
|
353
|
-
expression: string,
|
|
354
|
-
): void {
|
|
355
|
-
const statement = reader.getFirstAncestor((ancestor) =>
|
|
356
|
-
Node.isStatement(ancestor),
|
|
357
|
-
);
|
|
358
|
-
if (!statement) return;
|
|
359
|
-
const parent = statement.getParent();
|
|
360
|
-
if (Node.isBlock(parent)) {
|
|
361
|
-
const index = parent.getStatements().indexOf(statement);
|
|
362
|
-
parent.insertStatements(index, `const ${name} = yield* ${expression};`);
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
statement.replaceWithText(
|
|
366
|
-
`const ${name} = yield* ${expression};\n${statement.getText()}`,
|
|
367
|
-
);
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
function normalizeCraftUseImports(
|
|
371
|
-
sourceFile: SourceFile,
|
|
372
|
-
aliases: Set<string>,
|
|
373
|
-
): boolean {
|
|
374
|
-
let changed = false;
|
|
375
|
-
for (const declaration of sourceFile.getImportDeclarations()) {
|
|
376
|
-
const specifier = declaration
|
|
377
|
-
.getNamedImports()
|
|
378
|
-
.find((item) => aliases.has(item.getAliasNode()?.getText() ?? item.getName()));
|
|
379
|
-
if (!specifier) continue;
|
|
380
|
-
const localNames = new Set(aliases);
|
|
381
|
-
const references = sourceFile
|
|
382
|
-
.getDescendantsOfKind(SyntaxKind.Identifier)
|
|
383
|
-
.filter(
|
|
384
|
-
(identifier) =>
|
|
385
|
-
localNames.has(identifier.getText()) &&
|
|
386
|
-
identifier.getFirstAncestorByKind(SyntaxKind.ImportDeclaration) !== declaration,
|
|
387
|
-
);
|
|
388
|
-
const canonicalReferences = sourceFile
|
|
389
|
-
.getDescendantsOfKind(SyntaxKind.Identifier)
|
|
390
|
-
.filter(
|
|
391
|
-
(identifier) =>
|
|
392
|
-
identifier.getText() === CRAFT_USE &&
|
|
393
|
-
!identifier.getFirstAncestorByKind(SyntaxKind.ImportDeclaration),
|
|
394
|
-
);
|
|
395
|
-
if (references.length > 0) {
|
|
396
|
-
for (const reference of references) {
|
|
397
|
-
if (reference.getText() !== CRAFT_USE) {
|
|
398
|
-
reference.replaceWithText(CRAFT_USE);
|
|
399
|
-
changed = true;
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
if (specifier.getAliasNode()) {
|
|
403
|
-
specifier.removeAlias();
|
|
404
|
-
changed = true;
|
|
405
|
-
}
|
|
406
|
-
} else if (canonicalReferences.length > 0) {
|
|
407
|
-
const hasOtherCanonicalImport = sourceFile
|
|
408
|
-
.getImportDeclarations()
|
|
409
|
-
.some(
|
|
410
|
-
(candidate) =>
|
|
411
|
-
candidate !== declaration &&
|
|
412
|
-
candidate
|
|
413
|
-
.getNamedImports()
|
|
414
|
-
.some((item) => item.getName() === CRAFT_USE),
|
|
415
|
-
);
|
|
416
|
-
if (hasOtherCanonicalImport) {
|
|
417
|
-
specifier.remove();
|
|
418
|
-
changed = true;
|
|
419
|
-
} else if (specifier.getAliasNode()) {
|
|
420
|
-
specifier.removeAlias();
|
|
421
|
-
changed = true;
|
|
422
|
-
}
|
|
423
|
-
} else {
|
|
424
|
-
specifier.remove();
|
|
425
|
-
changed = true;
|
|
426
|
-
if (
|
|
427
|
-
declaration.getNamedImports().length === 0 &&
|
|
428
|
-
!declaration.getDefaultImport() &&
|
|
429
|
-
!declaration.getNamespaceImport()
|
|
430
|
-
) {
|
|
431
|
-
declaration.remove();
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
if (
|
|
436
|
-
sourceFile
|
|
437
|
-
.getDescendantsOfKind(SyntaxKind.Identifier)
|
|
438
|
-
.some(
|
|
439
|
-
(identifier) =>
|
|
440
|
-
identifier.getText() === CRAFT_USE &&
|
|
441
|
-
!identifier.getFirstAncestorByKind(SyntaxKind.ImportDeclaration),
|
|
442
|
-
) &&
|
|
443
|
-
!sourceFile.getImportDeclarations().some((declaration) =>
|
|
444
|
-
declaration
|
|
445
|
-
.getNamedImports()
|
|
446
|
-
.some((item) => item.getName() === CRAFT_USE),
|
|
447
|
-
)
|
|
448
|
-
) {
|
|
449
|
-
ensureCraftUseImport(sourceFile);
|
|
450
|
-
changed = true;
|
|
451
|
-
}
|
|
452
|
-
return changed;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
function ensureCraftUseImport(sourceFile: SourceFile): void {
|
|
456
|
-
const filePath = resolve(sourceFile.getFilePath());
|
|
457
|
-
const workspace = resolve(process.cwd());
|
|
458
|
-
const insideCore = filePath.startsWith(`${workspace}/libs/core/src/lib/`);
|
|
459
|
-
const moduleSpecifier = insideCore
|
|
460
|
-
? localCraftUseSpecifier(filePath, workspace)
|
|
461
|
-
: '@craft-ts/core';
|
|
462
|
-
const existing = sourceFile
|
|
463
|
-
.getImportDeclarations()
|
|
464
|
-
.find((declaration) => declaration.getModuleSpecifierValue() === moduleSpecifier);
|
|
465
|
-
if (existing) {
|
|
466
|
-
existing.addNamedImport(CRAFT_USE);
|
|
467
|
-
return;
|
|
468
|
-
}
|
|
469
|
-
sourceFile.addImportDeclaration({
|
|
470
|
-
moduleSpecifier,
|
|
471
|
-
namedImports: [CRAFT_USE],
|
|
472
|
-
});
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
function localCraftUseSpecifier(filePath: string, workspace: string): string {
|
|
476
|
-
let specifier = relative(
|
|
477
|
-
dirname(filePath),
|
|
478
|
-
resolve(workspace, 'libs/core/src/lib/craft-use'),
|
|
479
|
-
).replace(/\\/g, '/');
|
|
480
|
-
if (!specifier.startsWith('.')) specifier = `./${specifier}`;
|
|
481
|
-
return specifier;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
function unwrap(node: Node | undefined): Node | undefined {
|
|
485
|
-
while (
|
|
486
|
-
node &&
|
|
487
|
-
(Node.isParenthesizedExpression(node) ||
|
|
488
|
-
Node.isAsExpression(node) ||
|
|
489
|
-
Node.isTypeAssertion(node) ||
|
|
490
|
-
Node.isNonNullExpression(node))
|
|
491
|
-
) {
|
|
492
|
-
node = Node.isParenthesizedExpression(node)
|
|
493
|
-
? node.getExpression()
|
|
494
|
-
: Node.isAsExpression(node) || Node.isTypeAssertion(node)
|
|
495
|
-
? node.getExpression()
|
|
496
|
-
: node.getExpression();
|
|
497
|
-
}
|
|
498
|
-
return node;
|
|
499
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export type PrimitiveMigrationDiagnosticCode =
|
|
2
|
-
| 'PRIMITIVE_NAME_REQUIRES_REVIEW'
|
|
3
|
-
| 'SIGNAL_FORM_REQUIRES_INSERT_FORM'
|
|
4
|
-
| 'ASYNC_VALIDATOR_REQUIRES_QUERY'
|
|
5
|
-
| 'RX_RESOURCE_REQUIRES_QUERY'
|
|
6
|
-
| 'FORM_TREE_INSERT_EXTRACTION_REQUIRES_REVIEW'
|
|
7
|
-
| 'IMPERATIVE_WORKFLOW_REQUIRES_REVIEW';
|
|
8
|
-
|
|
9
|
-
export type PrimitiveMigrationDiagnostic = {
|
|
10
|
-
code: PrimitiveMigrationDiagnosticCode;
|
|
11
|
-
filePath: string;
|
|
12
|
-
symbol?: string;
|
|
13
|
-
message: string;
|
|
14
|
-
manual: true;
|
|
15
|
-
};
|