@nstudio/angular 15.0.4-rc.1 → 16.5.0
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 +21 -17
- package/collection.json +6 -1
- package/package.json +3 -3
- package/src/schematics/application/index.js +2 -2
- package/src/schematics/component/index.js +1 -1
- package/src/schematics/elements/index.js +10 -12
- package/src/schematics/feature/index.js +2 -2
- package/src/schematics/feature/index.spec.js +1 -1
- package/src/schematics/helpers/applitools/index.d.ts +2 -0
- package/src/schematics/helpers/applitools/index.js +115 -0
- package/src/schematics/helpers/applitools/index.js.map +1 -0
- package/src/schematics/helpers/index.d.ts +2 -0
- package/src/schematics/helpers/index.js +27 -0
- package/src/schematics/helpers/index.spec.d.ts +1 -0
- package/src/schematics/helpers/index.spec.js +95 -0
- package/src/schematics/helpers/schema.json +22 -0
- package/src/schematics/ngrx/_files/__name__.effects.spec.ts__tmpl__ +1 -1
- package/src/schematics/xplat/index.js +1 -1
- package/src/utils/ast.d.ts +75 -10
- package/src/utils/ast.js +261 -87
- package/src/utils/generator.js +58 -38
- package/src/utils/testing.js +2 -2
- package/src/utils/versions.d.ts +4 -5
- package/src/utils/versions.js +6 -7
- package/src/utils/xplat.js +7 -6
package/src/utils/ast.js
CHANGED
@@ -1,24 +1,25 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.getDecoratorPropertyValueNode = exports.readBootstrapInfo = exports.addEntryComponents = exports.addDeclarationToModule = exports.addProviderToModule = exports.
|
4
|
-
const
|
3
|
+
exports.getTsSourceFile = exports.getDecoratorPropertyValueNode = exports.readBootstrapInfo = exports.addEntryComponents = exports.addDeclarationToModule = exports.addProviderToComponent = exports.addProviderToModule = exports.addProviderToBootstrapApplication = exports.addRouteToNgModule = exports.getBootstrapComponent = exports.replaceIntoToTestBed = exports.addDeclarationsToTestBed = exports.addImportToTestBed = exports.addImportToModule = exports.addImportToPipe = exports.addImportToDirective = exports.addImportToComponent = exports.removeFromNgModule = exports._addSymbolToNgModuleMetadata = exports.getDecoratorMetadata = exports.isStandalone = exports.addToCollection = void 0;
|
4
|
+
const ensure_typescript_1 = require("@nx/js/src/utils/typescript/ensure-typescript");
|
5
5
|
const typescript_1 = require("nx/src/utils/typescript");
|
6
|
-
const
|
7
|
-
const
|
8
|
-
const
|
9
|
-
|
6
|
+
const ts = require("typescript");
|
7
|
+
const js_1 = require("@nx/js");
|
8
|
+
const path_1 = require("path");
|
9
|
+
const devkit_1 = require("@nx/devkit");
|
10
|
+
let tsModule;
|
11
|
+
function addToCollection(tree, source, barrelIndexPath, symbolName, insertSpaces = '') {
|
10
12
|
const collection = getCollection(source);
|
11
13
|
if (!collection)
|
12
|
-
return
|
14
|
+
return source;
|
13
15
|
// if (!collection) return [new NoopChange()];
|
14
16
|
// return [new NoopChange()];
|
17
|
+
console.log('collection.hasTrailingComma:', collection.hasTrailingComma);
|
15
18
|
if (collection.hasTrailingComma || collection.length === 0) {
|
16
|
-
return
|
19
|
+
return (0, js_1.insertChange)(tree, source, barrelIndexPath, collection.end, symbolName);
|
17
20
|
}
|
18
21
|
else {
|
19
|
-
return
|
20
|
-
new xplat_1.InsertChange(barrelIndexPath, collection.end, `,\n${insertSpaces}${symbolName}`),
|
21
|
-
];
|
22
|
+
return (0, js_1.insertChange)(tree, source, barrelIndexPath, collection.end, `,\n${insertSpaces}${symbolName}`);
|
22
23
|
}
|
23
24
|
}
|
24
25
|
exports.addToCollection = addToCollection;
|
@@ -36,10 +37,13 @@ function getCollection(source) {
|
|
36
37
|
return null;
|
37
38
|
}
|
38
39
|
function _angularImportsFromNode(node, _sourceFile) {
|
40
|
+
if (!tsModule) {
|
41
|
+
tsModule = (0, ensure_typescript_1.ensureTypescript)();
|
42
|
+
}
|
39
43
|
const ms = node.moduleSpecifier;
|
40
44
|
let modulePath;
|
41
45
|
switch (ms.kind) {
|
42
|
-
case
|
46
|
+
case tsModule.SyntaxKind.StringLiteral:
|
43
47
|
modulePath = ms.text;
|
44
48
|
break;
|
45
49
|
default:
|
@@ -55,10 +59,10 @@ function _angularImportsFromNode(node, _sourceFile) {
|
|
55
59
|
}
|
56
60
|
else if (node.importClause.namedBindings) {
|
57
61
|
const nb = node.importClause.namedBindings;
|
58
|
-
if (nb.kind ==
|
62
|
+
if (nb.kind == tsModule.SyntaxKind.NamespaceImport) {
|
59
63
|
// This is of the form `import * as name from 'path'`. Return `name.`.
|
60
64
|
return {
|
61
|
-
[nb.name.text
|
65
|
+
[`${nb.name.text}.`]: modulePath,
|
62
66
|
};
|
63
67
|
}
|
64
68
|
else {
|
@@ -79,8 +83,21 @@ function _angularImportsFromNode(node, _sourceFile) {
|
|
79
83
|
return {};
|
80
84
|
}
|
81
85
|
}
|
86
|
+
/**
|
87
|
+
* Check if the Component, Directive or Pipe is standalone
|
88
|
+
* @param sourceFile TS Source File containing the token to check
|
89
|
+
* @param decoratorName The type of decorator to check (Component, Directive, Pipe)
|
90
|
+
*/
|
91
|
+
function isStandalone(sourceFile, decoratorName) {
|
92
|
+
const decoratorMetadata = getDecoratorMetadata(sourceFile, decoratorName, '@angular/core');
|
93
|
+
return decoratorMetadata.some((node) => node.getText().includes('standalone: true'));
|
94
|
+
}
|
95
|
+
exports.isStandalone = isStandalone;
|
82
96
|
function getDecoratorMetadata(source, identifier, module) {
|
83
|
-
|
97
|
+
if (!tsModule) {
|
98
|
+
tsModule = (0, ensure_typescript_1.ensureTypescript)();
|
99
|
+
}
|
100
|
+
const angularImports = (0, typescript_1.findNodes)(source, tsModule.SyntaxKind.ImportDeclaration)
|
84
101
|
.map((node) => _angularImportsFromNode(node, source))
|
85
102
|
.reduce((acc, current) => {
|
86
103
|
for (const key of Object.keys(current)) {
|
@@ -88,60 +105,65 @@ function getDecoratorMetadata(source, identifier, module) {
|
|
88
105
|
}
|
89
106
|
return acc;
|
90
107
|
}, {});
|
91
|
-
return (0,
|
108
|
+
return (0, js_1.getSourceNodes)(source)
|
92
109
|
.filter((node) => {
|
93
|
-
return (node.kind ==
|
94
|
-
node.expression.kind ==
|
110
|
+
return (node.kind == tsModule.SyntaxKind.Decorator &&
|
111
|
+
node.expression.kind ==
|
112
|
+
tsModule.SyntaxKind.CallExpression);
|
95
113
|
})
|
96
114
|
.map((node) => node.expression)
|
97
115
|
.filter((expr) => {
|
98
|
-
if (expr.expression.kind ==
|
116
|
+
if (expr.expression.kind == tsModule.SyntaxKind.Identifier) {
|
99
117
|
const id = expr.expression;
|
100
118
|
return (id.getFullText(source) == identifier &&
|
101
119
|
angularImports[id.getFullText(source)] === module);
|
102
120
|
}
|
103
|
-
else if (expr.expression.kind ==
|
121
|
+
else if (expr.expression.kind == tsModule.SyntaxKind.PropertyAccessExpression) {
|
104
122
|
// This covers foo.NgModule when importing * as foo.
|
105
123
|
const paExpr = expr.expression;
|
106
124
|
// If the left expression is not an identifier, just give up at that point.
|
107
|
-
if (paExpr.expression.kind !==
|
125
|
+
if (paExpr.expression.kind !== tsModule.SyntaxKind.Identifier) {
|
108
126
|
return false;
|
109
127
|
}
|
110
128
|
const id = paExpr.name.text;
|
111
129
|
const moduleId = paExpr.expression.getText(source);
|
112
|
-
return id === identifier && angularImports[moduleId
|
130
|
+
return id === identifier && angularImports[`${moduleId}.`] === module;
|
113
131
|
}
|
114
132
|
return false;
|
115
133
|
})
|
116
134
|
.filter((expr) => expr.arguments[0] &&
|
117
|
-
expr.arguments[0].kind ==
|
135
|
+
expr.arguments[0].kind == tsModule.SyntaxKind.ObjectLiteralExpression)
|
118
136
|
.map((expr) => expr.arguments[0]);
|
119
137
|
}
|
120
|
-
|
121
|
-
|
138
|
+
exports.getDecoratorMetadata = getDecoratorMetadata;
|
139
|
+
function _addSymbolToDecoratorMetadata(host, source, filePath, metadataField, expression, decoratorName) {
|
140
|
+
const nodes = getDecoratorMetadata(source, decoratorName, '@angular/core');
|
122
141
|
let node = nodes[0]; // tslint:disable-line:no-any
|
123
142
|
// Find the decorator declaration.
|
124
143
|
if (!node) {
|
125
|
-
return
|
144
|
+
return source;
|
145
|
+
}
|
146
|
+
if (!tsModule) {
|
147
|
+
tsModule = (0, ensure_typescript_1.ensureTypescript)();
|
126
148
|
}
|
127
149
|
// Get all the children property assignment of object literals.
|
128
150
|
const matchingProperties = node.properties
|
129
|
-
.filter((prop) => prop.kind ==
|
151
|
+
.filter((prop) => prop.kind == tsModule.SyntaxKind.PropertyAssignment)
|
130
152
|
// Filter out every fields that's not "metadataField". Also handles string literals
|
131
153
|
// (but not expressions).
|
132
154
|
.filter((prop) => {
|
133
155
|
const name = prop.name;
|
134
156
|
switch (name.kind) {
|
135
|
-
case
|
157
|
+
case tsModule.SyntaxKind.Identifier:
|
136
158
|
return name.getText(source) == metadataField;
|
137
|
-
case
|
159
|
+
case tsModule.SyntaxKind.StringLiteral:
|
138
160
|
return name.text == metadataField;
|
139
161
|
}
|
140
162
|
return false;
|
141
163
|
});
|
142
164
|
// Get the last node of the array literal.
|
143
165
|
if (!matchingProperties) {
|
144
|
-
return
|
166
|
+
return source;
|
145
167
|
}
|
146
168
|
if (matchingProperties.length == 0) {
|
147
169
|
// We haven't found the field in the metadata declaration. Insert a new field.
|
@@ -164,13 +186,12 @@ function addSymbolToNgModuleMetadata(source, ngModulePath, metadataField, expres
|
|
164
186
|
toInsert = `, ${metadataField}: [${expression}]`;
|
165
187
|
}
|
166
188
|
}
|
167
|
-
|
168
|
-
return [newMetadataProperty];
|
189
|
+
return (0, js_1.insertChange)(host, source, filePath, position, toInsert);
|
169
190
|
}
|
170
191
|
const assignment = matchingProperties[0];
|
171
192
|
// If it's not an array, nothing we can do really.
|
172
|
-
if (assignment.initializer.kind !==
|
173
|
-
return
|
193
|
+
if (assignment.initializer.kind !== tsModule.SyntaxKind.ArrayLiteralExpression) {
|
194
|
+
return source;
|
174
195
|
}
|
175
196
|
const arrLiteral = assignment.initializer;
|
176
197
|
if (arrLiteral.elements.length == 0) {
|
@@ -182,20 +203,20 @@ function addSymbolToNgModuleMetadata(source, ngModulePath, metadataField, expres
|
|
182
203
|
}
|
183
204
|
if (!node) {
|
184
205
|
console.log('No app module found. Please add your new class to your component.');
|
185
|
-
return
|
206
|
+
return source;
|
186
207
|
}
|
187
208
|
const isArray = Array.isArray(node);
|
188
209
|
if (isArray) {
|
189
210
|
const nodeArray = node;
|
190
211
|
const symbolsArray = nodeArray.map((node) => node.getText());
|
191
212
|
if (symbolsArray.includes(expression)) {
|
192
|
-
return
|
213
|
+
return source;
|
193
214
|
}
|
194
215
|
node = node[node.length - 1];
|
195
216
|
}
|
196
217
|
let toInsert;
|
197
218
|
let position = node.getEnd();
|
198
|
-
if (!isArray && node.kind ==
|
219
|
+
if (!isArray && node.kind == tsModule.SyntaxKind.ObjectLiteralExpression) {
|
199
220
|
// We haven't found the field in the metadata declaration. Insert a new
|
200
221
|
// field.
|
201
222
|
const expr = node;
|
@@ -216,7 +237,8 @@ function addSymbolToNgModuleMetadata(source, ngModulePath, metadataField, expres
|
|
216
237
|
}
|
217
238
|
}
|
218
239
|
}
|
219
|
-
else if (!isArray &&
|
240
|
+
else if (!isArray &&
|
241
|
+
node.kind == tsModule.SyntaxKind.ArrayLiteralExpression) {
|
220
242
|
// We found the field but it's empty. Insert it just before the `]`.
|
221
243
|
position--;
|
222
244
|
toInsert = `${expression}`;
|
@@ -231,54 +253,130 @@ function addSymbolToNgModuleMetadata(source, ngModulePath, metadataField, expres
|
|
231
253
|
toInsert = `, ${expression}`;
|
232
254
|
}
|
233
255
|
}
|
234
|
-
|
235
|
-
return [insert];
|
256
|
+
return (0, js_1.insertChange)(host, source, filePath, position, toInsert);
|
236
257
|
}
|
237
|
-
|
238
|
-
|
258
|
+
function _addSymbolToNgModuleMetadata(host, source, ngModulePath, metadataField, expression) {
|
259
|
+
return _addSymbolToDecoratorMetadata(host, source, ngModulePath, metadataField, expression, 'NgModule');
|
260
|
+
}
|
261
|
+
exports._addSymbolToNgModuleMetadata = _addSymbolToNgModuleMetadata;
|
262
|
+
function removeFromNgModule(host, source, modulePath, property) {
|
239
263
|
const nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core');
|
240
264
|
let node = nodes[0]; // tslint:disable-line:no-any
|
241
265
|
// Find the decorator declaration.
|
242
266
|
if (!node) {
|
243
|
-
return
|
267
|
+
return source;
|
244
268
|
}
|
245
269
|
// Get all the children property assignment of object literals.
|
246
270
|
const matchingProperty = getMatchingProperty(source, property, 'NgModule', '@angular/core');
|
247
271
|
if (matchingProperty) {
|
248
|
-
return
|
249
|
-
new xplat_1.RemoveChange(modulePath, matchingProperty.getStart(source), matchingProperty.getFullText(source)),
|
250
|
-
];
|
251
|
-
}
|
252
|
-
else {
|
253
|
-
return [];
|
272
|
+
return (0, js_1.removeChange)(host, source, modulePath, matchingProperty.getStart(source), matchingProperty.getFullText(source));
|
254
273
|
}
|
255
274
|
}
|
256
275
|
exports.removeFromNgModule = removeFromNgModule;
|
257
|
-
|
258
|
-
|
276
|
+
/**
|
277
|
+
* Add an import to a Standalone Component
|
278
|
+
* @param host Virtual Tree
|
279
|
+
* @param source TS Source File containing the Component
|
280
|
+
* @param componentPath The path to the Component
|
281
|
+
* @param symbolName The import to add to the Component
|
282
|
+
*/
|
283
|
+
function addImportToComponent(host, source, componentPath, symbolName) {
|
284
|
+
return _addSymbolToDecoratorMetadata(host, source, componentPath, 'imports', symbolName, 'Component');
|
285
|
+
}
|
286
|
+
exports.addImportToComponent = addImportToComponent;
|
287
|
+
/**
|
288
|
+
* Add an import to a Standalone Directive
|
289
|
+
* @param host Virtual Tree
|
290
|
+
* @param source TS Source File containing the Directive
|
291
|
+
* @param directivePath The path to the Directive
|
292
|
+
* @param symbolName The import to add to the Directive
|
293
|
+
*/
|
294
|
+
function addImportToDirective(host, source, directivePath, symbolName) {
|
295
|
+
return _addSymbolToDecoratorMetadata(host, source, directivePath, 'imports', symbolName, 'Directive');
|
296
|
+
}
|
297
|
+
exports.addImportToDirective = addImportToDirective;
|
298
|
+
/**
|
299
|
+
* Add an import to a Standalone Pipe
|
300
|
+
* @param host Virtual Tree
|
301
|
+
* @param source TS Source File containing the Pipe
|
302
|
+
* @param pipePath The path to the Pipe
|
303
|
+
* @param symbolName The import to add to the Pipe
|
304
|
+
*/
|
305
|
+
function addImportToPipe(host, source, pipePath, symbolName) {
|
306
|
+
return _addSymbolToDecoratorMetadata(host, source, pipePath, 'imports', symbolName, 'Pipe');
|
307
|
+
}
|
308
|
+
exports.addImportToPipe = addImportToPipe;
|
309
|
+
/**
|
310
|
+
* Add an import to an NgModule
|
311
|
+
* @param host Virtual Tree
|
312
|
+
* @param source TS Source File containing the NgModule
|
313
|
+
* @param modulePath The path to the NgModule
|
314
|
+
* @param symbolName The import to add to the NgModule
|
315
|
+
*/
|
316
|
+
function addImportToModule(host, source, modulePath, symbolName) {
|
317
|
+
return _addSymbolToNgModuleMetadata(host, source, modulePath, 'imports', symbolName);
|
259
318
|
}
|
260
319
|
exports.addImportToModule = addImportToModule;
|
261
|
-
function addImportToTestBed(source, specPath, symbolName) {
|
262
|
-
|
320
|
+
function addImportToTestBed(host, source, specPath, symbolName) {
|
321
|
+
if (!tsModule) {
|
322
|
+
tsModule = (0, ensure_typescript_1.ensureTypescript)();
|
323
|
+
}
|
324
|
+
const allCalls = ((0, typescript_1.findNodes)(source, tsModule.SyntaxKind.CallExpression));
|
263
325
|
const configureTestingModuleObjectLiterals = allCalls
|
264
|
-
.filter((c) => c.expression.kind ===
|
326
|
+
.filter((c) => c.expression.kind === tsModule.SyntaxKind.PropertyAccessExpression)
|
265
327
|
.filter((c) => c.expression.name.getText(source) === 'configureTestingModule')
|
266
|
-
.map((c) => c.arguments[0].kind ===
|
328
|
+
.map((c) => c.arguments[0].kind === tsModule.SyntaxKind.ObjectLiteralExpression
|
267
329
|
? c.arguments[0]
|
268
330
|
: null);
|
269
331
|
if (configureTestingModuleObjectLiterals.length > 0) {
|
270
332
|
const startPosition = configureTestingModuleObjectLiterals[0]
|
271
333
|
.getFirstToken(source)
|
272
334
|
.getEnd();
|
273
|
-
return [
|
274
|
-
new xplat_1.InsertChange(specPath, startPosition, `imports: [${symbolName}], `),
|
275
|
-
];
|
276
|
-
}
|
277
|
-
else {
|
278
|
-
return [];
|
335
|
+
return (0, js_1.insertChange)(host, source, specPath, startPosition, `imports: [${symbolName}], `);
|
279
336
|
}
|
337
|
+
return source;
|
280
338
|
}
|
281
339
|
exports.addImportToTestBed = addImportToTestBed;
|
340
|
+
function addDeclarationsToTestBed(host, source, specPath, symbolName) {
|
341
|
+
if (!tsModule) {
|
342
|
+
tsModule = (0, ensure_typescript_1.ensureTypescript)();
|
343
|
+
}
|
344
|
+
const allCalls = ((0, typescript_1.findNodes)(source, tsModule.SyntaxKind.CallExpression));
|
345
|
+
const configureTestingModuleObjectLiterals = allCalls
|
346
|
+
.filter((c) => c.expression.kind === tsModule.SyntaxKind.PropertyAccessExpression)
|
347
|
+
.filter((c) => c.expression.name.getText(source) === 'configureTestingModule')
|
348
|
+
.map((c) => c.arguments[0].kind === tsModule.SyntaxKind.ObjectLiteralExpression
|
349
|
+
? c.arguments[0]
|
350
|
+
: null);
|
351
|
+
if (configureTestingModuleObjectLiterals.length > 0) {
|
352
|
+
const startPosition = configureTestingModuleObjectLiterals[0]
|
353
|
+
.getFirstToken(source)
|
354
|
+
.getEnd();
|
355
|
+
return (0, js_1.insertChange)(host, source, specPath, startPosition, `declarations: [${symbolName.join(',')}], `);
|
356
|
+
}
|
357
|
+
return source;
|
358
|
+
}
|
359
|
+
exports.addDeclarationsToTestBed = addDeclarationsToTestBed;
|
360
|
+
function replaceIntoToTestBed(host, source, specPath, newSymbol, previousSymbol) {
|
361
|
+
if (!tsModule) {
|
362
|
+
tsModule = (0, ensure_typescript_1.ensureTypescript)();
|
363
|
+
}
|
364
|
+
const allCalls = ((0, typescript_1.findNodes)(source, tsModule.SyntaxKind.CallExpression));
|
365
|
+
const configureTestingModuleObjectLiterals = allCalls
|
366
|
+
.filter((c) => c.expression.kind === tsModule.SyntaxKind.PropertyAccessExpression)
|
367
|
+
.filter((c) => c.expression.name.getText(source) === 'configureTestingModule')
|
368
|
+
.map((c) => c.arguments[0].kind === tsModule.SyntaxKind.ObjectLiteralExpression
|
369
|
+
? c.arguments[0]
|
370
|
+
: null);
|
371
|
+
if (configureTestingModuleObjectLiterals.length > 0) {
|
372
|
+
const startPosition = configureTestingModuleObjectLiterals[0]
|
373
|
+
.getFirstToken(source)
|
374
|
+
.getEnd();
|
375
|
+
return (0, js_1.replaceChange)(host, source, specPath, startPosition, newSymbol, previousSymbol);
|
376
|
+
}
|
377
|
+
return source;
|
378
|
+
}
|
379
|
+
exports.replaceIntoToTestBed = replaceIntoToTestBed;
|
282
380
|
function getBootstrapComponent(source, moduleClassName) {
|
283
381
|
const bootstrap = getMatchingProperty(source, 'bootstrap', 'NgModule', '@angular/core');
|
284
382
|
if (!bootstrap) {
|
@@ -301,56 +399,113 @@ function getMatchingProperty(source, property, identifier, module) {
|
|
301
399
|
// Get all the children property assignment of object literals.
|
302
400
|
return getMatchingObjectLiteralElement(node, source, property);
|
303
401
|
}
|
304
|
-
function
|
402
|
+
function addRouteToNgModule(host, ngModulePath, source, route) {
|
305
403
|
const routes = getListOfRoutes(source);
|
306
404
|
if (!routes)
|
307
|
-
return
|
405
|
+
return source;
|
308
406
|
if (routes.hasTrailingComma || routes.length === 0) {
|
309
|
-
return
|
407
|
+
return (0, js_1.insertChange)(host, source, ngModulePath, routes.end, route);
|
310
408
|
}
|
311
409
|
else {
|
312
|
-
return
|
410
|
+
return (0, js_1.insertChange)(host, source, ngModulePath, routes.end, `, ${route}`);
|
313
411
|
}
|
314
412
|
}
|
315
|
-
exports.
|
413
|
+
exports.addRouteToNgModule = addRouteToNgModule;
|
316
414
|
function getListOfRoutes(source) {
|
415
|
+
if (!tsModule) {
|
416
|
+
tsModule = (0, ensure_typescript_1.ensureTypescript)();
|
417
|
+
}
|
317
418
|
const imports = getMatchingProperty(source, 'imports', 'NgModule', '@angular/core');
|
318
|
-
if (imports.initializer.kind ===
|
419
|
+
if ((imports === null || imports === void 0 ? void 0 : imports.initializer.kind) === tsModule.SyntaxKind.ArrayLiteralExpression) {
|
319
420
|
const a = imports.initializer;
|
320
|
-
for (
|
321
|
-
if (e.kind ===
|
421
|
+
for (const e of a.elements) {
|
422
|
+
if (e.kind === tsModule.SyntaxKind.CallExpression) {
|
322
423
|
const ee = e;
|
323
424
|
const text = ee.expression.getText(source);
|
324
425
|
if ((text === 'RouterModule.forRoot' ||
|
325
426
|
text === 'RouterModule.forChild') &&
|
326
427
|
ee.arguments.length > 0) {
|
327
428
|
const routes = ee.arguments[0];
|
328
|
-
if (routes.kind ===
|
429
|
+
if (routes.kind === tsModule.SyntaxKind.ArrayLiteralExpression) {
|
329
430
|
return routes.elements;
|
330
431
|
}
|
432
|
+
else if (routes.kind === tsModule.SyntaxKind.Identifier) {
|
433
|
+
// find the array expression
|
434
|
+
const variableDeclarations = (0, typescript_1.findNodes)(source, tsModule.SyntaxKind.VariableDeclaration);
|
435
|
+
const routesDeclaration = variableDeclarations.find((x) => {
|
436
|
+
return x.name.getText() === routes.getText();
|
437
|
+
});
|
438
|
+
if (routesDeclaration) {
|
439
|
+
return routesDeclaration.initializer.elements;
|
440
|
+
}
|
441
|
+
}
|
331
442
|
}
|
332
443
|
}
|
333
444
|
}
|
334
445
|
}
|
335
446
|
return null;
|
336
447
|
}
|
337
|
-
|
338
|
-
|
448
|
+
/**
|
449
|
+
* Add a provider to bootstrapApplication call for Standalone Applications
|
450
|
+
* @param tree Virtual Tree
|
451
|
+
* @param filePath Path to the file containing the bootstrapApplication call
|
452
|
+
* @param providerToAdd Provider to add
|
453
|
+
*/
|
454
|
+
function addProviderToBootstrapApplication(tree, filePath, providerToAdd) {
|
455
|
+
(0, ensure_typescript_1.ensureTypescript)();
|
456
|
+
const { tsquery } = require('@phenomnomnominal/tsquery');
|
457
|
+
const PROVIDERS_ARRAY_SELECTOR = 'CallExpression:has(Identifier[name=bootstrapApplication]) ObjectLiteralExpression > PropertyAssignment:has(Identifier[name=providers]) > ArrayLiteralExpression';
|
458
|
+
const fileContents = tree.read(filePath, 'utf-8');
|
459
|
+
const ast = tsquery.ast(fileContents);
|
460
|
+
const providersArrayNodes = tsquery(ast, PROVIDERS_ARRAY_SELECTOR, {
|
461
|
+
visitAllChildren: true,
|
462
|
+
});
|
463
|
+
if (providersArrayNodes.length === 0) {
|
464
|
+
throw new Error(`Providers does not exist in the bootstrapApplication call within ${filePath}.`);
|
465
|
+
}
|
466
|
+
const arrayNode = providersArrayNodes[0];
|
467
|
+
const newFileContents = `${fileContents.slice(0, arrayNode.getStart() + 1)}${providerToAdd},${fileContents.slice(arrayNode.getStart() + 1, fileContents.length)}`;
|
468
|
+
tree.write(filePath, newFileContents);
|
469
|
+
}
|
470
|
+
exports.addProviderToBootstrapApplication = addProviderToBootstrapApplication;
|
471
|
+
/**
|
472
|
+
* Add a provider to an NgModule
|
473
|
+
* @param host Virtual Tree
|
474
|
+
* @param source TS Source File containing the NgModule
|
475
|
+
* @param modulePath Path to the NgModule
|
476
|
+
* @param symbolName The provider to add
|
477
|
+
*/
|
478
|
+
function addProviderToModule(host, source, modulePath, symbolName) {
|
479
|
+
return _addSymbolToNgModuleMetadata(host, source, modulePath, 'providers', symbolName);
|
339
480
|
}
|
340
481
|
exports.addProviderToModule = addProviderToModule;
|
341
|
-
|
342
|
-
|
482
|
+
/**
|
483
|
+
* Add a provider to a Standalone Component
|
484
|
+
* @param host Virtual Tree
|
485
|
+
* @param source TS Source File containing the Component
|
486
|
+
* @param componentPath Path to the Component
|
487
|
+
* @param symbolName The provider to add
|
488
|
+
*/
|
489
|
+
function addProviderToComponent(host, source, componentPath, symbolName) {
|
490
|
+
return _addSymbolToDecoratorMetadata(host, source, componentPath, 'providers', symbolName, 'Component');
|
491
|
+
}
|
492
|
+
exports.addProviderToComponent = addProviderToComponent;
|
493
|
+
function addDeclarationToModule(host, source, modulePath, symbolName) {
|
494
|
+
return _addSymbolToNgModuleMetadata(host, source, modulePath, 'declarations', symbolName);
|
343
495
|
}
|
344
496
|
exports.addDeclarationToModule = addDeclarationToModule;
|
345
|
-
function addEntryComponents(source, modulePath, symbolName) {
|
346
|
-
return
|
497
|
+
function addEntryComponents(host, source, modulePath, symbolName) {
|
498
|
+
return _addSymbolToNgModuleMetadata(host, source, modulePath, 'entryComponents', symbolName);
|
347
499
|
}
|
348
500
|
exports.addEntryComponents = addEntryComponents;
|
349
501
|
function readBootstrapInfo(host, app) {
|
350
|
-
|
502
|
+
if (!tsModule) {
|
503
|
+
tsModule = (0, ensure_typescript_1.ensureTypescript)();
|
504
|
+
}
|
505
|
+
const config = (0, devkit_1.readProjectConfiguration)(host, app);
|
351
506
|
let mainPath;
|
352
507
|
try {
|
353
|
-
mainPath = config.
|
508
|
+
mainPath = config.targets.build.options.main;
|
354
509
|
}
|
355
510
|
catch (e) {
|
356
511
|
throw new Error('Main file cannot be located');
|
@@ -359,21 +514,21 @@ function readBootstrapInfo(host, app) {
|
|
359
514
|
throw new Error('Main file cannot be located');
|
360
515
|
}
|
361
516
|
const mainSource = host.read(mainPath).toString('utf-8');
|
362
|
-
const main =
|
363
|
-
const moduleImports = (0,
|
517
|
+
const main = tsModule.createSourceFile(mainPath, mainSource, tsModule.ScriptTarget.Latest, true);
|
518
|
+
const moduleImports = (0, js_1.getImport)(main, (s) => s.indexOf('.module') > -1);
|
364
519
|
if (moduleImports.length !== 1) {
|
365
520
|
throw new Error(`main.ts can only import a single module`);
|
366
521
|
}
|
367
522
|
const moduleImport = moduleImports[0];
|
368
523
|
const moduleClassName = moduleImport.bindings.filter((b) => b.endsWith('Module'))[0];
|
369
|
-
const modulePath = `${
|
524
|
+
const modulePath = `${(0, path_1.join)((0, path_1.dirname)(mainPath), moduleImport.moduleSpec)}.ts`;
|
370
525
|
if (!host.exists(modulePath)) {
|
371
526
|
throw new Error(`Cannot find '${modulePath}'`);
|
372
527
|
}
|
373
528
|
const moduleSourceText = host.read(modulePath).toString('utf-8');
|
374
|
-
const moduleSource =
|
529
|
+
const moduleSource = tsModule.createSourceFile(modulePath, moduleSourceText, tsModule.ScriptTarget.Latest, true);
|
375
530
|
const bootstrapComponentClassName = getBootstrapComponent(moduleSource, moduleClassName);
|
376
|
-
const bootstrapComponentFileName = `./${
|
531
|
+
const bootstrapComponentFileName = `./${(0, path_1.join)((0, path_1.dirname)(moduleImport.moduleSpec), `${(0, devkit_1.names)(bootstrapComponentClassName.substring(0, bootstrapComponentClassName.length - 9)).fileName}.component`)}`;
|
377
532
|
return {
|
378
533
|
moduleSpec: moduleImport.moduleSpec,
|
379
534
|
mainPath,
|
@@ -386,25 +541,44 @@ function readBootstrapInfo(host, app) {
|
|
386
541
|
}
|
387
542
|
exports.readBootstrapInfo = readBootstrapInfo;
|
388
543
|
function getDecoratorPropertyValueNode(host, modulePath, identifier, property, module) {
|
544
|
+
if (!tsModule) {
|
545
|
+
tsModule = (0, ensure_typescript_1.ensureTypescript)();
|
546
|
+
}
|
389
547
|
const moduleSourceText = host.read(modulePath).toString('utf-8');
|
390
|
-
const moduleSource =
|
548
|
+
const moduleSource = tsModule.createSourceFile(modulePath, moduleSourceText, tsModule.ScriptTarget.Latest, true);
|
391
549
|
const templateNode = getMatchingProperty(moduleSource, property, identifier, module);
|
392
550
|
return templateNode.getChildAt(templateNode.getChildCount() - 1);
|
393
551
|
}
|
394
552
|
exports.getDecoratorPropertyValueNode = getDecoratorPropertyValueNode;
|
395
553
|
function getMatchingObjectLiteralElement(node, source, property) {
|
554
|
+
if (!tsModule) {
|
555
|
+
tsModule = (0, ensure_typescript_1.ensureTypescript)();
|
556
|
+
}
|
396
557
|
return (node.properties
|
397
|
-
.filter((prop) => prop.kind ==
|
558
|
+
.filter((prop) => prop.kind == tsModule.SyntaxKind.PropertyAssignment)
|
398
559
|
// Filter out every fields that's not "metadataField". Also handles string literals
|
399
560
|
// (but not expressions).
|
400
561
|
.filter((prop) => {
|
401
562
|
const name = prop.name;
|
402
563
|
switch (name.kind) {
|
403
|
-
case
|
564
|
+
case tsModule.SyntaxKind.Identifier:
|
404
565
|
return name.getText(source) === property;
|
405
|
-
case
|
566
|
+
case tsModule.SyntaxKind.StringLiteral:
|
406
567
|
return name.text === property;
|
407
568
|
}
|
408
569
|
return false;
|
409
570
|
})[0]);
|
410
571
|
}
|
572
|
+
function getTsSourceFile(host, path) {
|
573
|
+
if (!tsModule) {
|
574
|
+
tsModule = (0, ensure_typescript_1.ensureTypescript)();
|
575
|
+
}
|
576
|
+
const buffer = host.read(path);
|
577
|
+
if (!buffer) {
|
578
|
+
throw new Error(`Could not read TS file (${path}).`);
|
579
|
+
}
|
580
|
+
const content = buffer.toString();
|
581
|
+
const source = tsModule.createSourceFile(path, content, tsModule.ScriptTarget.Latest, true);
|
582
|
+
return source;
|
583
|
+
}
|
584
|
+
exports.getTsSourceFile = getTsSourceFile;
|