@craft-ng/dev-tools 0.5.0-beta.5 → 0.6.0-beta.1
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 +198 -23
- package/generators.json +26 -0
- package/package.json +23 -2
- package/src/bin/craft-migrate-primitives.d.ts +2 -0
- package/src/bin/craft-migrate-primitives.js +71 -0
- package/src/bin/craft-migrate-primitives.js.map +1 -0
- package/src/bin/craft-migrate-routes.d.ts +2 -0
- package/src/bin/craft-migrate-routes.js +77 -0
- package/src/bin/craft-migrate-routes.js.map +1 -0
- package/src/bin/craft-migrate-services.d.ts +2 -0
- package/src/bin/craft-migrate-services.js +75 -0
- package/src/bin/craft-migrate-services.js.map +1 -0
- package/src/bin/craft-migrate.d.ts +2 -0
- package/src/bin/craft-migrate.js +90 -0
- package/src/bin/craft-migrate.js.map +1 -0
- package/src/bin/craft.d.ts +2 -0
- package/src/bin/craft.js +166 -0
- package/src/bin/craft.js.map +1 -0
- package/src/eslint-rules/craft-computed-name-match.cjs +8 -125
- package/src/eslint-rules/craft-method-name-match.cjs +8 -166
- package/src/eslint-rules/craft-name-match-utils.cjs +179 -0
- package/src/eslint-rules/craft-signal-source-name-match.cjs +8 -0
- package/src/eslint-rules/craft-source-name-match.cjs +8 -0
- package/src/eslint-rules/global-exception-registry-match.cjs +78 -13
- package/src/eslint-rules/index.cjs +10 -2
- package/src/eslint-rules/require-cascade-route-di-check.cjs +223 -0
- package/src/eslint-rules/require-exception-component-di-check.cjs +66 -10
- package/src/eslint-rules/require-lazy-load-with-retry.cjs +148 -0
- package/src/eslint-rules/require-primitive-generator-unwrap.cjs +267 -0
- package/src/generators/route/compat.d.ts +3 -0
- package/src/generators/route/compat.js +6 -0
- package/src/generators/route/compat.js.map +1 -0
- package/src/generators/route/generator.d.ts +31 -0
- package/src/generators/route/generator.js +434 -0
- package/src/generators/route/generator.js.map +1 -0
- package/src/generators/route/schema.json +50 -0
- package/src/generators/route/split-schema.json +19 -0
- package/src/index.d.ts +9 -0
- package/src/index.js +9 -0
- package/src/index.js.map +1 -1
- package/src/scripts/angular-brand-codemod.d.ts +17 -0
- package/src/scripts/angular-brand-codemod.js +44 -8
- package/src/scripts/angular-brand-codemod.js.map +1 -1
- package/src/scripts/angular-brand-codemod.spec.ts +3 -3
- package/src/scripts/angular-brand-codemod.ts +78 -7
- package/src/scripts/migrate.d.ts +32 -0
- package/src/scripts/migrate.js +67 -0
- package/src/scripts/migrate.js.map +1 -0
- package/src/scripts/migrate.ts +128 -0
- package/src/scripts/migration-workspace.d.ts +2 -0
- package/src/scripts/migration-workspace.js +72 -0
- package/src/scripts/migration-workspace.js.map +1 -0
- package/src/scripts/migration-workspace.ts +93 -0
- package/src/scripts/primitives/migrate-primitive-generators.d.ts +27 -0
- package/src/scripts/primitives/migrate-primitive-generators.js +315 -0
- package/src/scripts/primitives/migrate-primitive-generators.js.map +1 -0
- package/src/scripts/primitives/migrate-primitive-generators.ts +402 -0
- package/src/scripts/primitives/migrate-primitives.d.ts +27 -0
- package/src/scripts/primitives/migrate-primitives.js +386 -0
- package/src/scripts/primitives/migrate-primitives.js.map +1 -0
- package/src/scripts/primitives/migrate-primitives.spec.ts +322 -0
- package/src/scripts/primitives/migrate-primitives.ts +601 -0
- package/src/scripts/primitives/migration-diagnostic.d.ts +8 -0
- package/src/scripts/primitives/migration-diagnostic.js +2 -0
- package/src/scripts/primitives/migration-diagnostic.js.map +1 -0
- package/src/scripts/primitives/migration-diagnostic.ts +14 -0
- package/src/scripts/routes/migrate-routes.d.ts +34 -0
- package/src/scripts/routes/migrate-routes.js +669 -0
- package/src/scripts/routes/migrate-routes.js.map +1 -0
- package/src/scripts/routes/migrate-routes.spec.ts +264 -0
- package/src/scripts/routes/migrate-routes.ts +895 -0
- package/src/scripts/routes/migration-diagnostic.d.ts +16 -0
- package/src/scripts/routes/migration-diagnostic.js +2 -0
- package/src/scripts/routes/migration-diagnostic.js.map +1 -0
- package/src/scripts/routes/migration-diagnostic.ts +25 -0
- package/src/scripts/routes/route-command.d.ts +75 -0
- package/src/scripts/routes/route-command.js +1187 -0
- package/src/scripts/routes/route-command.js.map +1 -0
- package/src/scripts/routes/route-command.spec.ts +553 -0
- package/src/scripts/routes/route-command.ts +1790 -0
- package/src/scripts/services/config.d.ts +2 -0
- package/src/scripts/services/config.js +39 -0
- package/src/scripts/services/config.js.map +1 -0
- package/src/scripts/services/config.ts +60 -0
- package/src/scripts/services/migrate-services.d.ts +29 -0
- package/src/scripts/services/migrate-services.js +929 -0
- package/src/scripts/services/migrate-services.js.map +1 -0
- package/src/scripts/services/migrate-services.spec.ts +761 -0
- package/src/scripts/services/migrate-services.ts +1333 -0
- package/src/scripts/services/migration-diagnostic.d.ts +8 -0
- package/src/scripts/services/migration-diagnostic.js +2 -0
- package/src/scripts/services/migration-diagnostic.js.map +1 -0
- package/src/scripts/services/migration-diagnostic.ts +28 -0
- package/src/eslint-rules/require-track-on-dependent-primitives.cjs +0 -219
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** Generates O(1) DI checks for
|
|
1
|
+
/** Generates O(1) DI checks for route, exception, and route-load error components. */
|
|
2
2
|
module.exports = {
|
|
3
3
|
meta: { type: 'problem', fixable: 'code', schema: [] },
|
|
4
4
|
create(context) {
|
|
@@ -6,7 +6,11 @@ module.exports = {
|
|
|
6
6
|
return {
|
|
7
7
|
'Program:exit'(program) {
|
|
8
8
|
const text = source.getText();
|
|
9
|
-
if (
|
|
9
|
+
if (
|
|
10
|
+
!/renderComponent|errorComponent|withErrorComponent|withRouteLoadError|provideRouteLoadErrorComponent/.test(
|
|
11
|
+
text,
|
|
12
|
+
)
|
|
13
|
+
)
|
|
10
14
|
return;
|
|
11
15
|
|
|
12
16
|
const cascade = readCascadeContext(text);
|
|
@@ -14,25 +18,34 @@ module.exports = {
|
|
|
14
18
|
walk(program, (node) => {
|
|
15
19
|
if (isCall(node, 'craftRoutes')) {
|
|
16
20
|
collectRouteChecks(node, source, cascade, checks);
|
|
17
|
-
} else if (
|
|
21
|
+
} else if (
|
|
22
|
+
isCall(node, 'withErrorComponent') ||
|
|
23
|
+
isCall(node, 'withRouteLoadError')
|
|
24
|
+
) {
|
|
18
25
|
const descriptor = node.arguments[0];
|
|
19
26
|
const deps = readProperty(descriptor, 'componentDeps', source);
|
|
20
27
|
if (deps) {
|
|
28
|
+
const routeLoad = isCall(node, 'withRouteLoadError');
|
|
21
29
|
checks.push({
|
|
22
30
|
deps,
|
|
23
|
-
names: joinNames(
|
|
31
|
+
names: joinNames(
|
|
32
|
+
cascade.names,
|
|
33
|
+
routeLoad
|
|
34
|
+
? ['CraftRouteLoadError', 'CraftRouteLoadRecovery']
|
|
35
|
+
: ['CraftGlobalError'],
|
|
36
|
+
),
|
|
24
37
|
values: cascade.values,
|
|
25
|
-
label:
|
|
38
|
+
label: routeLoad
|
|
39
|
+
? 'global route load error component'
|
|
40
|
+
: 'global error component',
|
|
26
41
|
});
|
|
27
42
|
}
|
|
28
43
|
}
|
|
29
44
|
});
|
|
30
45
|
|
|
46
|
+
const existingChecks = readExistingCheckDeps(text);
|
|
31
47
|
const missing = checks.filter(
|
|
32
|
-
(check) =>
|
|
33
|
-
!text.includes(
|
|
34
|
-
`RouteExceptionComponentCheckedDI<\n ${check.deps},`,
|
|
35
|
-
),
|
|
48
|
+
(check) => !existingChecks.has(normalizeTypeText(check.deps)),
|
|
36
49
|
);
|
|
37
50
|
if (missing.length === 0) return;
|
|
38
51
|
|
|
@@ -84,6 +97,29 @@ function collectRouteChecks(call, source, cascade, checks) {
|
|
|
84
97
|
});
|
|
85
98
|
}
|
|
86
99
|
|
|
100
|
+
const providers = propertyValue(def, 'providers');
|
|
101
|
+
if (providers?.type === 'ArrayExpression') {
|
|
102
|
+
for (const provider of providers.elements) {
|
|
103
|
+
if (!isCall(provider, 'provideRouteLoadErrorComponent')) continue;
|
|
104
|
+
const deps = readProperty(
|
|
105
|
+
provider.arguments[0],
|
|
106
|
+
'componentDeps',
|
|
107
|
+
source,
|
|
108
|
+
);
|
|
109
|
+
if (!deps) continue;
|
|
110
|
+
checks.push({
|
|
111
|
+
deps,
|
|
112
|
+
names: joinNames(cascade.names, [
|
|
113
|
+
...baseNames,
|
|
114
|
+
'CraftRouteLoadError',
|
|
115
|
+
'CraftRouteLoadRecovery',
|
|
116
|
+
]),
|
|
117
|
+
values: cascade.values,
|
|
118
|
+
label: `route load error component: ${path}`,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
87
123
|
const handlers = routeCall
|
|
88
124
|
? routeCall.arguments[2]
|
|
89
125
|
: propertyValue(def, 'handleExceptions');
|
|
@@ -193,10 +229,30 @@ function ensureImports(text) {
|
|
|
193
229
|
);
|
|
194
230
|
}
|
|
195
231
|
|
|
232
|
+
function readExistingCheckDeps(text) {
|
|
233
|
+
const deps = new Set();
|
|
234
|
+
const regex = /RouteExceptionComponentCheckedDI<\s*([\s\S]*?),\s*(?:'[^']*'|never)/g;
|
|
235
|
+
let match;
|
|
236
|
+
while ((match = regex.exec(text))) {
|
|
237
|
+
deps.add(normalizeTypeText(match[1]));
|
|
238
|
+
}
|
|
239
|
+
return deps;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function normalizeTypeText(text) {
|
|
243
|
+
return String(text).replace(/\s+/g, '');
|
|
244
|
+
}
|
|
245
|
+
|
|
196
246
|
function readProperty(node, name, source) {
|
|
197
247
|
const value = propertyValue(node, name);
|
|
198
|
-
return value ?
|
|
248
|
+
return value ? readTypeText(value, source) : undefined;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function readTypeText(node, source) {
|
|
252
|
+
if (node?.type === 'TSAsExpression') return source.getText(node.typeAnnotation);
|
|
253
|
+
return source.getText(node);
|
|
199
254
|
}
|
|
255
|
+
|
|
200
256
|
function propertyValue(node, name) {
|
|
201
257
|
if (node?.type !== 'ObjectExpression') return undefined;
|
|
202
258
|
return node.properties.find(
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const LAZY_PROPERTIES = new Set([
|
|
4
|
+
'loadComponent',
|
|
5
|
+
'loadChildren',
|
|
6
|
+
]);
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
meta: {
|
|
10
|
+
type: 'problem',
|
|
11
|
+
docs: {
|
|
12
|
+
description:
|
|
13
|
+
'Require lazy route imports to use the withRetry helper so browser-cached module failures can be retried.',
|
|
14
|
+
},
|
|
15
|
+
fixable: 'code',
|
|
16
|
+
schema: [],
|
|
17
|
+
},
|
|
18
|
+
create(context) {
|
|
19
|
+
const sourceCode = context.sourceCode ?? context.getSourceCode();
|
|
20
|
+
const importsByLoader = new Map();
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
ImportExpression(node) {
|
|
24
|
+
const loader = enclosingLazyLoader(node);
|
|
25
|
+
if (!loader || isWrappedWithRetry(node)) return;
|
|
26
|
+
|
|
27
|
+
const imports = importsByLoader.get(loader) ?? [];
|
|
28
|
+
imports.push(node);
|
|
29
|
+
importsByLoader.set(loader, imports);
|
|
30
|
+
},
|
|
31
|
+
'Program:exit'() {
|
|
32
|
+
for (const [loader, imports] of importsByLoader) {
|
|
33
|
+
context.report({
|
|
34
|
+
node: imports[0],
|
|
35
|
+
message:
|
|
36
|
+
'Lazy route imports must be wrapped with withRetry(import(...)).',
|
|
37
|
+
fix(fixer) {
|
|
38
|
+
const parameterFixes = addWithRetryParameter(
|
|
39
|
+
fixer,
|
|
40
|
+
sourceCode,
|
|
41
|
+
loader,
|
|
42
|
+
);
|
|
43
|
+
if (!parameterFixes) return null;
|
|
44
|
+
|
|
45
|
+
return [
|
|
46
|
+
...parameterFixes,
|
|
47
|
+
...imports.flatMap((moduleImport) => [
|
|
48
|
+
fixer.insertTextBefore(moduleImport, 'withRetry('),
|
|
49
|
+
fixer.insertTextAfter(moduleImport, ')'),
|
|
50
|
+
]),
|
|
51
|
+
];
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
function enclosingLazyLoader(node) {
|
|
61
|
+
let current = node.parent;
|
|
62
|
+
while (current) {
|
|
63
|
+
if (
|
|
64
|
+
(current.type === 'ArrowFunctionExpression' ||
|
|
65
|
+
current.type === 'FunctionExpression') &&
|
|
66
|
+
current.parent?.type === 'Property' &&
|
|
67
|
+
LAZY_PROPERTIES.has(propertyName(current.parent)) &&
|
|
68
|
+
isInsideCraftRoute(current.parent)
|
|
69
|
+
) {
|
|
70
|
+
return current;
|
|
71
|
+
}
|
|
72
|
+
if (current.type === 'Property' || current.type === 'Program') return null;
|
|
73
|
+
current = current.parent;
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function isInsideCraftRoute(node) {
|
|
79
|
+
let current = node.parent;
|
|
80
|
+
while (current) {
|
|
81
|
+
if (
|
|
82
|
+
current.type === 'CallExpression' &&
|
|
83
|
+
current.callee.type === 'Identifier' &&
|
|
84
|
+
(current.callee.name === 'craftRoute' ||
|
|
85
|
+
current.callee.name === 'craftRoutes')
|
|
86
|
+
) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
if (current.type === 'Program') return false;
|
|
90
|
+
current = current.parent;
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function propertyName(property) {
|
|
96
|
+
if (property.computed) return undefined;
|
|
97
|
+
if (property.key.type === 'Identifier') return property.key.name;
|
|
98
|
+
if (property.key.type === 'Literal') return property.key.value;
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function isWrappedWithRetry(node) {
|
|
103
|
+
return (
|
|
104
|
+
node.parent?.type === 'CallExpression' &&
|
|
105
|
+
node.parent.callee.type === 'Identifier' &&
|
|
106
|
+
node.parent.callee.name === 'withRetry' &&
|
|
107
|
+
node.parent.arguments[0] === node
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function addWithRetryParameter(fixer, sourceCode, loader) {
|
|
112
|
+
if (loader.params.length === 0) {
|
|
113
|
+
const arrow = sourceCode.getTokenBefore(loader.body, {
|
|
114
|
+
filter: (token) => token.value === '=>',
|
|
115
|
+
});
|
|
116
|
+
if (!arrow) return null;
|
|
117
|
+
|
|
118
|
+
const closeParen = sourceCode.getTokenBefore(arrow);
|
|
119
|
+
const openParen = closeParen && sourceCode.getTokenBefore(closeParen);
|
|
120
|
+
if (openParen?.value !== '(' || closeParen?.value !== ')') return null;
|
|
121
|
+
return [
|
|
122
|
+
fixer.replaceTextRange(
|
|
123
|
+
[openParen.range[1], closeParen.range[0]],
|
|
124
|
+
'{ withRetry }',
|
|
125
|
+
),
|
|
126
|
+
];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (loader.params.length !== 1 || loader.params[0].type !== 'ObjectPattern') {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const pattern = loader.params[0];
|
|
134
|
+
if (
|
|
135
|
+
pattern.properties.some(
|
|
136
|
+
(property) =>
|
|
137
|
+
property.type === 'Property' &&
|
|
138
|
+
property.key.type === 'Identifier' &&
|
|
139
|
+
property.key.name === 'withRetry',
|
|
140
|
+
)
|
|
141
|
+
) {
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const closingBrace = sourceCode.getLastToken(pattern);
|
|
146
|
+
const prefix = pattern.properties.length > 0 ? ', ' : '';
|
|
147
|
+
return [fixer.insertTextBefore(closingBrace, `${prefix}withRetry`)];
|
|
148
|
+
}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
const DEFAULT_PRIMITIVES = [
|
|
2
|
+
'state',
|
|
3
|
+
'query',
|
|
4
|
+
'mutation',
|
|
5
|
+
'asyncProcess',
|
|
6
|
+
'queryParam',
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
const FACTORY_HOST_CALLEES = new Set(['craftService', 'toCraftService']);
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
meta: {
|
|
13
|
+
type: 'problem',
|
|
14
|
+
docs: {
|
|
15
|
+
description:
|
|
16
|
+
'Require craft primitive invocations (which return a generator) to be consumed with `yield*` inside a generator factory or `craftUse(...)` elsewhere.',
|
|
17
|
+
},
|
|
18
|
+
fixable: 'code',
|
|
19
|
+
schema: [
|
|
20
|
+
{
|
|
21
|
+
type: 'object',
|
|
22
|
+
properties: {
|
|
23
|
+
primitives: {
|
|
24
|
+
type: 'array',
|
|
25
|
+
items: { type: 'string' },
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
additionalProperties: false,
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
messages: {
|
|
32
|
+
requireUnwrap:
|
|
33
|
+
"'{{name}}(...)' returns a primitive generator that must be consumed: use `yield* {{name}}(...)` inside a generator factory, or `craftUse({{name}}(...))` elsewhere.",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
create(context) {
|
|
37
|
+
const options = context.options[0] ?? {};
|
|
38
|
+
const primitives = new Set(options.primitives ?? DEFAULT_PRIMITIVES);
|
|
39
|
+
const sourceCode = context.sourceCode ?? context.getSourceCode();
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
CallExpression(node) {
|
|
43
|
+
if (
|
|
44
|
+
node.callee.type !== 'Identifier' ||
|
|
45
|
+
!primitives.has(node.callee.name) ||
|
|
46
|
+
// Creation calls always take a config; destructured readers such as
|
|
47
|
+
// `({ state }) => state().page` are argument-less.
|
|
48
|
+
node.arguments.length === 0
|
|
49
|
+
) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!resolvesToImport(node.callee, sourceCode, context)) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (
|
|
58
|
+
isConsumed(node) ||
|
|
59
|
+
isDirectFactoryReturn(node) ||
|
|
60
|
+
isTrackedTypeOnlyPosition(node)
|
|
61
|
+
) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const primitiveName = node.callee.name;
|
|
66
|
+
|
|
67
|
+
context.report({
|
|
68
|
+
node,
|
|
69
|
+
messageId: 'requireUnwrap',
|
|
70
|
+
data: { name: primitiveName },
|
|
71
|
+
fix(fixer) {
|
|
72
|
+
const text = sourceCode.getText(node);
|
|
73
|
+
|
|
74
|
+
if (isInsideGeneratorFunction(node)) {
|
|
75
|
+
const wrapped = needsYieldParens(node)
|
|
76
|
+
? `(yield* ${text})`
|
|
77
|
+
: `yield* ${text}`;
|
|
78
|
+
return [fixer.replaceText(node, wrapped)];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const fixes = [fixer.replaceText(node, `craftUse(${text})`)];
|
|
82
|
+
const importFix = createCraftUseImportFix(fixer, sourceCode);
|
|
83
|
+
if (importFix) {
|
|
84
|
+
fixes.push(importFix);
|
|
85
|
+
}
|
|
86
|
+
return fixes;
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
function resolvesToImport(identifier, sourceCode, context) {
|
|
95
|
+
const scope = sourceCode.getScope
|
|
96
|
+
? sourceCode.getScope(identifier)
|
|
97
|
+
: context.getScope();
|
|
98
|
+
let current = scope;
|
|
99
|
+
while (current) {
|
|
100
|
+
const variable = current.variables.find(
|
|
101
|
+
(candidate) => candidate.name === identifier.name,
|
|
102
|
+
);
|
|
103
|
+
if (variable) {
|
|
104
|
+
if (variable.defs.length === 0) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
return variable.defs.every((def) => def.type === 'ImportBinding');
|
|
108
|
+
}
|
|
109
|
+
current = current.upper;
|
|
110
|
+
}
|
|
111
|
+
// Unresolved (globals) — not an import of the primitive.
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function isConsumed(node) {
|
|
116
|
+
const parent = skipParens(node.parent);
|
|
117
|
+
if (!parent) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
if (parent.type === 'YieldExpression') {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
return (
|
|
124
|
+
parent.type === 'CallExpression' &&
|
|
125
|
+
parent.callee.type === 'Identifier' &&
|
|
126
|
+
parent.callee.name === 'craftUse' &&
|
|
127
|
+
skipParensDown(parent.arguments[0]) === node
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function isDirectFactoryReturn(node) {
|
|
132
|
+
const arrow = skipParens(node.parent);
|
|
133
|
+
if (!arrow || arrow.type !== 'ArrowFunctionExpression') {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
if (skipParensDown(arrow.body) !== node) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
return isFactoryHostArrow(arrow);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function isFactoryHostArrow(arrow) {
|
|
143
|
+
const parent = arrow.parent;
|
|
144
|
+
if (
|
|
145
|
+
parent &&
|
|
146
|
+
parent.type === 'CallExpression' &&
|
|
147
|
+
parent.callee.type === 'Identifier' &&
|
|
148
|
+
FACTORY_HOST_CALLEES.has(parent.callee.name)
|
|
149
|
+
) {
|
|
150
|
+
return parent.arguments.includes(arrow);
|
|
151
|
+
}
|
|
152
|
+
return (
|
|
153
|
+
parent &&
|
|
154
|
+
parent.type === 'Property' &&
|
|
155
|
+
parent.key &&
|
|
156
|
+
((parent.key.type === 'Identifier' && parent.key.name === 'queryParams') ||
|
|
157
|
+
(parent.key.type === 'Literal' && parent.key.value === 'queryParams')) &&
|
|
158
|
+
parent.value === arrow
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// `mockHttpRequestForRoute` / type-only fixtures sometimes reference a
|
|
163
|
+
// primitive purely for inference through `typeof`; those never run.
|
|
164
|
+
function isTrackedTypeOnlyPosition(node) {
|
|
165
|
+
let current = node.parent;
|
|
166
|
+
while (current) {
|
|
167
|
+
if (
|
|
168
|
+
current.type === 'TSTypeQuery' ||
|
|
169
|
+
current.type === 'TSTypeReference' ||
|
|
170
|
+
current.type === 'TSTypeAnnotation'
|
|
171
|
+
) {
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
current = current.parent;
|
|
175
|
+
}
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function isInsideGeneratorFunction(node) {
|
|
180
|
+
let current = node.parent;
|
|
181
|
+
while (current) {
|
|
182
|
+
if (current.type === 'ArrowFunctionExpression') {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
if (
|
|
186
|
+
current.type === 'FunctionDeclaration' ||
|
|
187
|
+
current.type === 'FunctionExpression'
|
|
188
|
+
) {
|
|
189
|
+
return current.generator === true;
|
|
190
|
+
}
|
|
191
|
+
current = current.parent;
|
|
192
|
+
}
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function needsYieldParens(node) {
|
|
197
|
+
const parent = node.parent;
|
|
198
|
+
if (!parent) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
return (
|
|
202
|
+
parent.type === 'SpreadElement' ||
|
|
203
|
+
parent.type === 'MemberExpression' ||
|
|
204
|
+
parent.type === 'BinaryExpression' ||
|
|
205
|
+
parent.type === 'ConditionalExpression' ||
|
|
206
|
+
parent.type === 'TemplateLiteral' ||
|
|
207
|
+
(parent.type === 'CallExpression' && parent.callee === node)
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function skipParens(node) {
|
|
212
|
+
let current = node;
|
|
213
|
+
while (current && current.type === 'ParenthesizedExpression') {
|
|
214
|
+
current = current.parent;
|
|
215
|
+
}
|
|
216
|
+
return current;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function skipParensDown(node) {
|
|
220
|
+
let current = node;
|
|
221
|
+
while (current && current.type === 'ParenthesizedExpression') {
|
|
222
|
+
current = current.expression;
|
|
223
|
+
}
|
|
224
|
+
return current;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function createCraftUseImportFix(fixer, sourceCode) {
|
|
228
|
+
const program = sourceCode.ast;
|
|
229
|
+
let craftImport;
|
|
230
|
+
|
|
231
|
+
for (const statement of program.body) {
|
|
232
|
+
if (
|
|
233
|
+
statement.type === 'ImportDeclaration' &&
|
|
234
|
+
statement.source.value === '@craft-ng/core'
|
|
235
|
+
) {
|
|
236
|
+
const alreadyImported = statement.specifiers.some(
|
|
237
|
+
(specifier) =>
|
|
238
|
+
specifier.type === 'ImportSpecifier' &&
|
|
239
|
+
specifier.imported.type === 'Identifier' &&
|
|
240
|
+
specifier.imported.name === 'craftUse',
|
|
241
|
+
);
|
|
242
|
+
if (alreadyImported) {
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
craftImport = statement;
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (!craftImport) {
|
|
251
|
+
return fixer.insertTextBefore(
|
|
252
|
+
program.body[0] ?? program,
|
|
253
|
+
"import { craftUse } from '@craft-ng/core';\n",
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const namedSpecifiers = craftImport.specifiers.filter(
|
|
258
|
+
(specifier) => specifier.type === 'ImportSpecifier',
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
if (namedSpecifiers.length === 0) {
|
|
262
|
+
return undefined;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const lastSpecifier = namedSpecifiers[namedSpecifiers.length - 1];
|
|
266
|
+
return fixer.insertTextAfter(lastSpecifier, ', craftUse');
|
|
267
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const routeSchematic: (generatorOptions: import("./schema.js").RouteGeneratorSchema) => (tree: any, context: any) => Promise<any>;
|
|
2
|
+
export declare const routeSplitSchematic: (generatorOptions: import("./schema.js").RouteSplitGeneratorSchema) => (tree: any, context: any) => Promise<any>;
|
|
3
|
+
export default routeSchematic;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { convertNxGenerator } from '@nx/devkit';
|
|
2
|
+
import { routeGenerator, routeSplitGenerator } from './generator.js';
|
|
3
|
+
export const routeSchematic = convertNxGenerator(routeGenerator);
|
|
4
|
+
export const routeSplitSchematic = convertNxGenerator(routeSplitGenerator);
|
|
5
|
+
export default routeSchematic;
|
|
6
|
+
//# sourceMappingURL=compat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compat.js","sourceRoot":"","sources":["../../../../../../libs/dev-tools/src/generators/route/compat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErE,MAAM,CAAC,MAAM,cAAc,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC;AACjE,MAAM,CAAC,MAAM,mBAAmB,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAC;AAE3E,eAAe,cAAc,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type GeneratorCallback, type Tree } from '@nx/devkit';
|
|
2
|
+
import type { RouteGeneratorSchema, RouteSplitGeneratorSchema } from './schema.js';
|
|
3
|
+
export declare function routeGenerator(tree: Tree, options: RouteGeneratorSchema): Promise<GeneratorCallback | void>;
|
|
4
|
+
type ConfiguredRouteTargetOptions = Pick<RouteGeneratorSchema, 'component' | 'createComponent' | 'redirectTo'>;
|
|
5
|
+
type ComponentCreationTarget = {
|
|
6
|
+
name: string;
|
|
7
|
+
path: string;
|
|
8
|
+
};
|
|
9
|
+
type ResolvedRouteTargetOptions = {
|
|
10
|
+
component?: string;
|
|
11
|
+
createComponent?: ComponentCreationTarget;
|
|
12
|
+
redirectTo?: string;
|
|
13
|
+
};
|
|
14
|
+
type RouteQuestion = (prompt: string) => Promise<string>;
|
|
15
|
+
type RouteParentOption = {
|
|
16
|
+
collectionName: string;
|
|
17
|
+
filePath: string;
|
|
18
|
+
routesName: string;
|
|
19
|
+
};
|
|
20
|
+
export declare function resolveRouteParentOption(parents: RouteParentOption[], interactive: {
|
|
21
|
+
configuredParent?: string;
|
|
22
|
+
rootDir: string;
|
|
23
|
+
routePath: string;
|
|
24
|
+
ask?: RouteQuestion;
|
|
25
|
+
}): Promise<string | undefined>;
|
|
26
|
+
export declare function resolveRouteTargetOptions(options: ConfiguredRouteTargetOptions, interactive: {
|
|
27
|
+
componentBase: string;
|
|
28
|
+
ask?: RouteQuestion;
|
|
29
|
+
}): Promise<ResolvedRouteTargetOptions>;
|
|
30
|
+
export declare function routeSplitGenerator(tree: Tree, options: RouteSplitGeneratorSchema): Promise<GeneratorCallback | void>;
|
|
31
|
+
export default routeGenerator;
|