@igniteui/angular-templates 17.2.1321-beta.0 → 17.2.1322-beta.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.
@@ -1,27 +1,31 @@
1
1
  import * as ts from 'typescript';
2
- import { KeyValuePair, TemplateDependency, FormatSettings } from '@igniteui/cli-core';
2
+ import { KeyValuePair, FormatSettings, PropertyAssignment, TemplateDependency, TypeScriptFileUpdate } from '@igniteui/cli-core';
3
3
  import { AngularRouteLike } from './types';
4
- export declare class AngularTypeScriptFileUpdate {
5
- private targetPath;
4
+ export declare class AngularTypeScriptFileUpdate extends TypeScriptFileUpdate {
5
+ protected targetPath: string;
6
6
  private standalone;
7
- private readonly astTransformer;
8
7
  constructor(targetPath: string, standalone?: boolean, formatSettings?: FormatSettings);
9
8
  /**
10
- * Adds a route to the Angular routing module.
9
+ * Adds a route entry to the Angular routing module's routes variable instance.
11
10
  * @param route The route to add.
12
11
  * @param multiline Whether to format the new entry as multiline.
12
+ * @param prepend Whether to insert the new entry before the anchor element.
13
+ * If no anchor is provided, the new entry will be added to the start or end of the array.
14
+ * @param anchorElement The anchor element to insert to.
13
15
  */
14
- addRoute(route: AngularRouteLike, multiline?: boolean): ts.SourceFile;
16
+ addRoute(route: AngularRouteLike, multiline?: boolean, prepend?: boolean, anchorElement?: PropertyAssignment): ts.SourceFile;
15
17
  /**
16
18
  * Adds a child route to a parent route.
17
19
  * @param parentPath The path of the parent route.
18
20
  * @param route The child route to add.
21
+ * @param asIdentifier Whether to initialize the {@link RouteTarget.Children} member with an identifier or an array literal.
19
22
  * @param multiline Whether to format the new entry as multiline.
20
23
  * @param prepend Whether to prepend the new added routes.
24
+ * @param anchorElement The anchor element to insert to.
21
25
  * @remarks The `parentPath` is used to determine where the child route should be added.
22
26
  */
23
- addChildRoute(parentPath: string, route: AngularRouteLike, multiline?: boolean, prepend?: boolean): ts.SourceFile;
24
- /**
27
+ addChildRoute(parentPath: string, route: AngularRouteLike, asIdentifier?: boolean, multiline?: boolean, prepend?: boolean, anchorElement?: PropertyAssignment): ts.SourceFile;
28
+ /** // TODO: update description
25
29
  * Adds an import identifier to a standalone component's metadata.
26
30
  * @param dep The dependency to add to the standalone component's metadata.
27
31
  * @param variables Variables to replace in the dependency strings.
@@ -36,10 +40,25 @@ export declare class AngularTypeScriptFileUpdate {
36
40
  */
37
41
  addNgModuleMeta(dep: TemplateDependency, variables?: KeyValuePair<string>, multiline?: boolean): ts.SourceFile;
38
42
  /**
39
- * Parses the AST and returns the resulting formatted source code.
40
- * @remarks This method should be called after all modifications have been made to the AST.
43
+ * Adds a new not lazy-loaded route entry to the routes array. With a component identifier and path.
44
+ * @param route The route to add.
45
+ * @param visitCondition The condition used to find the appropriate route node.
46
+ * @param multiline Whether to format the new entry as multiline.
47
+ * @param prepend Whether to insert the new entry before the anchor element.
48
+ * If no anchor is provided, the new entry will be added to the start or end of the array.
49
+ * @param anchorElement The anchor element to insert to.
50
+ */
51
+ protected addRouteEntry(route: AngularRouteLike, visitCondition: (node: ts.Node) => boolean, multiline: boolean, prepend: boolean, anchorElement: PropertyAssignment): ts.SourceFile;
52
+ /**
53
+ * Adds a new not lazy-loaded route entry to the routes array. With a redirect option.
54
+ * @param route The route to add.
55
+ * @param visitCondition The condition used to find the appropriate route node.
56
+ * @param multiline Whether to format the new entry as multiline.
57
+ * @param prepend Whether to insert the new entry before the anchor element.
58
+ * If no anchor is provided, the new entry will be added to the start or end of the array.
59
+ * @param anchorElement The anchor element to insert to.
41
60
  */
42
- finalize(): string;
61
+ protected addRedirectRouteEntry(route: AngularRouteLike, visitCondition: (node: ts.Node) => boolean, multiline: boolean, prepend: boolean, anchorElement: PropertyAssignment): ts.SourceFile;
43
62
  /**
44
63
  * Updates an Angular decorator's metadata.
45
64
  * @param name The name of the decorator to update.
@@ -61,61 +80,14 @@ export declare class AngularTypeScriptFileUpdate {
61
80
  * @param node The node to start checking from.
62
81
  */
63
82
  private findNgDecoratorProperty;
64
- /**
65
- * Creates an arrow function of the form `() => import(path).then(m => m.prop)`.
66
- * @param path The path to the module to import.
67
- * @param importedEntity The entity to import from the module.
68
- * @param root Whether it should be `loadChildren` or `loadComponent`.
69
- * @remarks If the `root` param is `true` the function will use `routes` as an `importedEntity`.
70
- */
71
- private createDynamicImport;
72
- /**
73
- * Converts a string or string array union to array.
74
- * @param value The value to convert.
75
- * @param variables Variables to replace in the strings.
76
- * @remarks Splits strings as comma delimited.
77
- */
78
- private asArray;
79
- /**
80
- * Applies a configuration transformation to a string.
81
- * @param data The string to transform.
82
- * @param configuration The items to replace in the string.
83
- */
84
- private applyConfigTransformation;
85
- /**
86
- * Adds a new entry to the routes array. With a component identifier and path or with redirect option.
87
- * @param route The route to add.
88
- * @param visitCondition The condition used to find the appropriate route node.
89
- * @param anchorElement The anchor element to insert.
90
- * @param multiline Whether to format the new entry as multiline.
91
- * @param prepend Whether to insert the new entry before the anchor element.
92
- */
93
- private addRedirectOrSimpleRouteEntry;
94
- /**
95
- * Adds a new not lazy-loaded route entry to the routes array. With a component identifier and path.
96
- * @param route The route to add.
97
- * @param visitCondition The condition used to find the appropriate route node.
98
- * @param anchorElement The anchor element to insert to.
99
- * @param multiline Whether to format the new entry as multiline.
100
- * @param prepend Whether to insert the new entry before the anchor element.
101
- */
102
- private addRouteEntry;
103
- /**
104
- * Adds a new not lazy-loaded route entry to the routes array. With a redirect option.
105
- * @param route The route to add.
106
- * @param visitCondition The condition used to find the appropriate route node.
107
- * @param anchorElement The anchor element to insert to.
108
- * @param multiline Whether to format the new entry as multiline.
109
- * @param prepend Whether to insert the new entry before the anchor element.
110
- */
111
- private addRedirectRouteEntry;
112
83
  /**
113
84
  * Adds a new lazy-loaded route entry to the routes array.
114
85
  * @param route The route to add.
115
86
  * @param visitCondition The condition used to find the appropriate route node.
116
- * @param anchorElement The anchor element to insert to.
117
87
  * @param multiline Whether to format the new entry as multiline.
118
88
  * @param prepend Whether to insert the new entry before the anchor element.
89
+ * If no anchor is provided, the new entry will be added to the start or end of the array.
90
+ * @param anchorElement The anchor element to insert to.
119
91
  */
120
92
  private addLazyLoadedRouteEntry;
121
93
  }
@@ -2,109 +2,53 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AngularTypeScriptFileUpdate = void 0;
4
4
  const ts = require("typescript");
5
- const os_1 = require("os");
6
5
  const cli_core_1 = require("@igniteui/cli-core");
7
6
  const types_1 = require("./types");
8
- // TODO: consider creating a global-constants file
9
- const ROUTES_VARIABLE_NAME = 'routes';
10
- const THEN_IDENTIFIER_NAME = 'then';
11
- const IMPORT_IDENTIFIER_NAME = 'import';
12
- const NG_MODULE_DECORATOR_NAME = 'NgModule';
13
- const NG_SA_DECORATOR_NAME = 'Component';
14
- const NG_FOR_ROOT_IDENTIFIER_NAME = 'forRoot';
15
- // insert before node that contains this element
16
- const anchorElement = {
17
- name: 'path',
18
- value: ts.factory.createStringLiteral('**'),
19
- };
20
- const printerOptions = {
21
- newLine: os_1.EOL === '\n'
22
- ? ts.NewLineKind.LineFeed
23
- : ts.NewLineKind.CarriageReturnLineFeed,
24
- };
25
- class AngularTypeScriptFileUpdate {
7
+ class AngularTypeScriptFileUpdate extends cli_core_1.TypeScriptFileUpdate {
26
8
  constructor(targetPath, standalone = false, formatSettings) {
9
+ super(targetPath, formatSettings);
27
10
  this.targetPath = targetPath;
28
11
  this.standalone = standalone;
29
- /**
30
- * Applies a configuration transformation to a string.
31
- * @param data The string to transform.
32
- * @param configuration The items to replace in the string.
33
- */
34
- this.applyConfigTransformation = (data, configuration) => {
35
- let key;
36
- for (key in configuration) {
37
- data = data.replace(new RegExp(cli_core_1.Util.escapeRegExp(key), 'g'), configuration[key]);
38
- }
39
- return data;
40
- };
41
- this.astTransformer = new cli_core_1.TypeScriptASTTransformer(cli_core_1.TypeScriptUtils.getFileSource(targetPath), new cli_core_1.TypeScriptFormattingService(targetPath, formatSettings), printerOptions // TODO: may not be needed
42
- );
43
12
  }
44
13
  //#region Public API
45
14
  /**
46
- * Adds a route to the Angular routing module.
15
+ * Adds a route entry to the Angular routing module's routes variable instance.
47
16
  * @param route The route to add.
48
17
  * @param multiline Whether to format the new entry as multiline.
18
+ * @param prepend Whether to insert the new entry before the anchor element.
19
+ * If no anchor is provided, the new entry will be added to the start or end of the array.
20
+ * @param anchorElement The anchor element to insert to.
49
21
  */
50
- addRoute(route, multiline = false) {
51
- const visitCondition = (node) => !!this.astTransformer.findNodeAncestor(node, (node) => ts.isVariableDeclaration(node) &&
52
- node.name.getText() === ROUTES_VARIABLE_NAME);
22
+ addRoute(route, multiline = false, prepend = true, anchorElement = cli_core_1.ANCHOR_ELEMENT) {
53
23
  if (route.lazyload &&
54
24
  route.path &&
55
25
  route.identifierName &&
56
26
  route.modulePath) {
57
- return this.addLazyLoadedRouteEntry(route, visitCondition, anchorElement, multiline, true // prepend
58
- );
27
+ return this.addLazyLoadedRouteEntry(route, (0, cli_core_1.RoutesVariableAsParentCondition)(this.astTransformer), multiline, prepend, anchorElement);
59
28
  }
60
- return this.addRedirectOrSimpleRouteEntry(route, visitCondition, anchorElement, multiline, true // prepend
61
- );
29
+ return this.addRedirectOrSimpleRouteEntry(route, (0, cli_core_1.RoutesVariableAsParentCondition)(this.astTransformer), multiline, prepend, anchorElement);
62
30
  }
63
31
  /**
64
32
  * Adds a child route to a parent route.
65
33
  * @param parentPath The path of the parent route.
66
34
  * @param route The child route to add.
35
+ * @param asIdentifier Whether to initialize the {@link RouteTarget.Children} member with an identifier or an array literal.
67
36
  * @param multiline Whether to format the new entry as multiline.
68
37
  * @param prepend Whether to prepend the new added routes.
38
+ * @param anchorElement The anchor element to insert to.
69
39
  * @remarks The `parentPath` is used to determine where the child route should be added.
70
40
  */
71
- addChildRoute(parentPath, route, multiline = false, prepend = false) {
72
- // find a node that has the parent's path
73
- const visitCondition = (node) => ts.isPropertyAssignment(node) &&
74
- node.name.getText() === cli_core_1.RouteTarget.Path &&
75
- ts.isStringLiteral(node.initializer) &&
76
- node.initializer.text === parentPath;
77
- const parentRoute = this.astTransformer.findPropertyAssignment(visitCondition);
78
- if (!parentRoute)
79
- return this.astTransformer.sourceFile;
80
- const parentContainsChildrenKey = ts.isObjectLiteralExpression(parentRoute.parent) &&
81
- parentRoute.parent.properties.find((p) => {
82
- var _a;
83
- return ts.isPropertyAssignment(p) &&
84
- ((_a = p.name) === null || _a === void 0 ? void 0 : _a.getText()) === types_1.AngularRouteTarget.Children;
85
- });
86
- if (!parentContainsChildrenKey) {
87
- // if the parent route does not have the children array, create it
88
- this.astTransformer.addMemberToObjectLiteral((node) => node.properties.some(visitCondition), {
89
- name: types_1.AngularRouteTarget.Children,
90
- value: this.astTransformer.createArrayLiteralExpression([], multiline),
91
- });
92
- }
41
+ addChildRoute(parentPath, route, asIdentifier = false, multiline = false, prepend = false, anchorElement = cli_core_1.ANCHOR_ELEMENT) {
93
42
  if (route.lazyload &&
94
43
  route.path &&
95
44
  route.identifierName &&
96
45
  route.modulePath) {
97
- return this.addLazyLoadedRouteEntry(route, visitCondition, anchorElement, multiline, true // prepend
98
- );
46
+ return this.addLazyLoadedRouteEntry(route, (0, cli_core_1.PropertyAssignmentWithStringLiteralValueCondition)(cli_core_1.RouteTarget.Path, parentPath), multiline, true, // prepend
47
+ cli_core_1.ANCHOR_ELEMENT);
99
48
  }
100
- // add the child route to the parent's children array
101
- return this.addRedirectOrSimpleRouteEntry(route, (node) => ts.isPropertyAssignment(node.parent) &&
102
- node.parent.name.getText() === types_1.AngularRouteTarget.Children &&
103
- // check if the parent route is the one we're looking for
104
- !!this.astTransformer.findNodeAncestor(node, (node) => ts.isObjectLiteralExpression(node) &&
105
- node.properties.some(visitCondition)), anchorElement, multiline, prepend);
49
+ return super.addChildRoute(parentPath, route, asIdentifier, multiline, prepend, anchorElement);
106
50
  }
107
- /**
51
+ /** // TODO: update description
108
52
  * Adds an import identifier to a standalone component's metadata.
109
53
  * @param dep The dependency to add to the standalone component's metadata.
110
54
  * @param variables Variables to replace in the dependency strings.
@@ -132,10 +76,10 @@ class AngularTypeScriptFileUpdate {
132
76
  });
133
77
  }
134
78
  if (copy.import.length > 0) {
135
- return this.mutateNgDecoratorMeta(NG_SA_DECORATOR_NAME, copy.import, types_1.AngularDecoratorMetaTarget.Imports, multiline);
79
+ return this.mutateNgDecoratorMeta(cli_core_1.NG_SA_DECORATOR_NAME, copy.import, types_1.AngularDecoratorMetaTarget.Imports, multiline);
136
80
  }
137
81
  if (copy.provide.length > 0) {
138
- return this.mutateNgDecoratorMeta(NG_SA_DECORATOR_NAME, copy.provide, types_1.AngularDecoratorMetaTarget.Providers, multiline);
82
+ return this.mutateNgDecoratorMeta(cli_core_1.NG_SA_DECORATOR_NAME, copy.provide, types_1.AngularDecoratorMetaTarget.Providers, multiline);
139
83
  }
140
84
  return this.astTransformer.sourceFile;
141
85
  }
@@ -172,170 +116,34 @@ class AngularTypeScriptFileUpdate {
172
116
  }
173
117
  if (dep.root && copy.import.length > 0) {
174
118
  // add forRoot to the module
175
- copy.import = copy.import.map((i) => this.astTransformer.printer.printNode(ts.EmitHint.Unspecified, this.astTransformer.createCallExpression(i, NG_FOR_ROOT_IDENTIFIER_NAME), this.astTransformer.sourceFile));
119
+ copy.import = copy.import.map((i) => this.astTransformer.printer.printNode(ts.EmitHint.Unspecified, this.astTransformer.createCallExpression(i, cli_core_1.NG_FOR_ROOT_IDENTIFIER_NAME), this.astTransformer.sourceFile));
176
120
  }
177
121
  if (copy.declare.length > 0) {
178
- this.mutateNgDecoratorMeta(NG_MODULE_DECORATOR_NAME, copy.declare, types_1.AngularDecoratorMetaTarget.Declarations, multiline);
122
+ this.mutateNgDecoratorMeta(cli_core_1.NG_MODULE_DECORATOR_NAME, copy.declare, types_1.AngularDecoratorMetaTarget.Declarations, multiline);
179
123
  }
180
124
  if (copy.import.length > 0) {
181
- this.mutateNgDecoratorMeta(NG_MODULE_DECORATOR_NAME, copy.import, types_1.AngularDecoratorMetaTarget.Imports, multiline);
125
+ this.mutateNgDecoratorMeta(cli_core_1.NG_MODULE_DECORATOR_NAME, copy.import, types_1.AngularDecoratorMetaTarget.Imports, multiline);
182
126
  }
183
127
  if (copy.provide.length > 0) {
184
- this.mutateNgDecoratorMeta(NG_MODULE_DECORATOR_NAME, copy.provide, types_1.AngularDecoratorMetaTarget.Providers, multiline);
128
+ this.mutateNgDecoratorMeta(cli_core_1.NG_MODULE_DECORATOR_NAME, copy.provide, types_1.AngularDecoratorMetaTarget.Providers, multiline);
185
129
  }
186
130
  if (copy.export.length > 0) {
187
- this.mutateNgDecoratorMeta(NG_MODULE_DECORATOR_NAME, copy.export, types_1.AngularDecoratorMetaTarget.Exports, multiline);
131
+ this.mutateNgDecoratorMeta(cli_core_1.NG_MODULE_DECORATOR_NAME, copy.export, types_1.AngularDecoratorMetaTarget.Exports, multiline);
188
132
  }
189
133
  return this.astTransformer.sourceFile;
190
134
  }
191
- /**
192
- * Parses the AST and returns the resulting formatted source code.
193
- * @remarks This method should be called after all modifications have been made to the AST.
194
- */
195
- finalize() {
196
- cli_core_1.TypeScriptUtils.saveFile(this.targetPath, this.astTransformer.sourceFile);
197
- return this.astTransformer.finalize();
198
- }
199
135
  //#endregion
200
- //#region Internals
201
- /**
202
- * Updates an Angular decorator's metadata.
203
- * @param name The name of the decorator to update.
204
- * @param meta Names of identifiers to be added.
205
- * @param target The target metadata property to update.
206
- * @param multiline Whether to format the new entry as multiline.
207
- */
208
- mutateNgDecoratorMeta(name, meta, target, multiline = false) {
209
- const identifiers = meta.map(ts.factory.createIdentifier);
210
- const targetMetaProp = this.findNgDecoratorProperty(name, target);
211
- if (!targetMetaProp) {
212
- return this.astTransformer.addMemberToObjectLiteral((node) => this.checkNgDecorator(name, node), {
213
- name: target,
214
- value: this.astTransformer.createArrayLiteralExpression(identifiers, multiline),
215
- });
216
- }
217
- if (ts.isArrayLiteralExpression(targetMetaProp.initializer)) {
218
- // prop assignment of the form { member: [...] }
219
- // store to avoid second type check due to different context in the filter
220
- const elementsAsNodeArray = targetMetaProp.initializer.elements;
221
- const elementsToAdd = identifiers.filter((i) => !elementsAsNodeArray.some((el) => el.getText() === i.text));
222
- return this.astTransformer.addMembersToArrayLiteral((node) => ts.isPropertyAssignment(node.parent) &&
223
- node.parent.name.getText() === target &&
224
- this.checkNgDecorator(name, node), elementsToAdd);
225
- }
226
- // prop assignment of the form { member: <some-val> }
227
- return this.astTransformer.updateObjectLiteralMember((node) => this.checkNgDecorator(name, node), {
228
- name: target,
229
- value: this.astTransformer.createArrayLiteralExpression([targetMetaProp.initializer, ...identifiers], multiline),
230
- });
231
- }
232
- /**
233
- * Checks if a node has an ancestor with a specific decorator.
234
- * @param name The name of the decorator.
235
- * @param node The node to start checking from.
236
- */
237
- checkNgDecorator(name, node) {
238
- return !!this.astTransformer.findNodeAncestor(node, (node) => {
239
- var _a;
240
- return ts.isDecorator(node) &&
241
- ((_a = node.expression.getFirstToken()) === null || _a === void 0 ? void 0 : _a.getText()) === name;
242
- });
243
- }
244
- /**
245
- * Finds a property assignment that exists in a specific NG decorator meta.
246
- * @param decoratorName The name of the decorator to check.
247
- * @param propName The property name to check.
248
- * @param node The node to start checking from.
249
- */
250
- findNgDecoratorProperty(decoratorName, propName) {
251
- return this.astTransformer.findPropertyAssignment((node) => node.name.getText() === propName &&
252
- !!this.astTransformer.findNodeAncestor(node, (node) => {
253
- var _a;
254
- return ts.isDecorator(node) &&
255
- ((_a = node.expression.getFirstToken()) === null || _a === void 0 ? void 0 : _a.getText()) === decoratorName;
256
- }));
257
- }
258
- /**
259
- * Creates an arrow function of the form `() => import(path).then(m => m.prop)`.
260
- * @param path The path to the module to import.
261
- * @param importedEntity The entity to import from the module.
262
- * @param root Whether it should be `loadChildren` or `loadComponent`.
263
- * @remarks If the `root` param is `true` the function will use `routes` as an `importedEntity`.
264
- */
265
- createDynamicImport(path, importedEntity, root = false) {
266
- const thenClause = root ? ROUTES_VARIABLE_NAME : importedEntity;
267
- // create the 'import(path)' expression
268
- const importExpression = ts.factory.createCallExpression(ts.factory.createIdentifier(IMPORT_IDENTIFIER_NAME), undefined, // type arguments
269
- [ts.factory.createStringLiteral(path)]);
270
- const thenFuncParamName = 'm';
271
- // create the 'm => m.prop' arrow function
272
- const thenExprArrowFuncBody = ts.factory.createArrowFunction(undefined, // modifiers
273
- undefined, // type parameters
274
- [
275
- ts.factory.createParameterDeclaration(undefined, // decorators
276
- undefined, // modifiers
277
- ts.factory.createIdentifier(thenFuncParamName)),
278
- ], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createPropertyAccessChain(ts.factory.createIdentifier(thenFuncParamName), undefined, // question-dot token
279
- thenClause));
280
- // build the '.then(m => m.prop)' expression and add it to the import expression
281
- const body = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(importExpression, THEN_IDENTIFIER_NAME), undefined, // type arguments
282
- [thenExprArrowFuncBody]);
283
- // Create the '() => import(path).then(m => m.prop)' arrow function
284
- const dynamicImport = ts.factory.createArrowFunction(undefined, // modifiers
285
- undefined, // type parameters
286
- [], // parameters
287
- undefined, // type
288
- ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), body);
289
- return dynamicImport;
290
- }
291
- /**
292
- * Converts a string or string array union to array.
293
- * @param value The value to convert.
294
- * @param variables Variables to replace in the strings.
295
- * @remarks Splits strings as comma delimited.
296
- */
297
- asArray(value, variables) {
298
- let result = [];
299
- if (value) {
300
- result = typeof value === 'string' ? value.split(/\s*,\s*/) : value;
301
- result = result.map((x) => this.applyConfigTransformation(x, variables));
302
- }
303
- return result;
304
- }
305
- /**
306
- * Adds a new entry to the routes array. With a component identifier and path or with redirect option.
307
- * @param route The route to add.
308
- * @param visitCondition The condition used to find the appropriate route node.
309
- * @param anchorElement The anchor element to insert.
310
- * @param multiline Whether to format the new entry as multiline.
311
- * @param prepend Whether to insert the new entry before the anchor element.
312
- */
313
- addRedirectOrSimpleRouteEntry(route, visitCondition, anchorElement, multiline = false, prepend = false) {
314
- var _a;
315
- if (route.lazyload)
316
- return this.astTransformer.sourceFile;
317
- if (route.path && route.identifierName) {
318
- this.addRouteEntry(route, visitCondition, anchorElement, multiline, prepend);
319
- }
320
- if (route.redirectTo) {
321
- this.addRedirectRouteEntry(route, visitCondition, anchorElement, multiline, prepend);
322
- }
323
- if ((_a = route.children) === null || _a === void 0 ? void 0 : _a.length) {
324
- route.children.forEach((child) => {
325
- this.addChildRoute(route.path, child, multiline, false);
326
- });
327
- }
328
- return this.astTransformer.sourceFile;
329
- }
136
+ //#region Protected Overrides
330
137
  /**
331
138
  * Adds a new not lazy-loaded route entry to the routes array. With a component identifier and path.
332
139
  * @param route The route to add.
333
140
  * @param visitCondition The condition used to find the appropriate route node.
334
- * @param anchorElement The anchor element to insert to.
335
141
  * @param multiline Whether to format the new entry as multiline.
336
142
  * @param prepend Whether to insert the new entry before the anchor element.
143
+ * If no anchor is provided, the new entry will be added to the start or end of the array.
144
+ * @param anchorElement The anchor element to insert to.
337
145
  */
338
- addRouteEntry(route, visitCondition, anchorElement, multiline = false, prepend = false) {
146
+ addRouteEntry(route, visitCondition, multiline = false, prepend = false, anchorElement) {
339
147
  if (route.modulePath) {
340
148
  // add an import for the given identifier
341
149
  const routeIdentifier = { name: route.identifierName };
@@ -370,11 +178,12 @@ class AngularTypeScriptFileUpdate {
370
178
  * Adds a new not lazy-loaded route entry to the routes array. With a redirect option.
371
179
  * @param route The route to add.
372
180
  * @param visitCondition The condition used to find the appropriate route node.
373
- * @param anchorElement The anchor element to insert to.
374
181
  * @param multiline Whether to format the new entry as multiline.
375
182
  * @param prepend Whether to insert the new entry before the anchor element.
183
+ * If no anchor is provided, the new entry will be added to the start or end of the array.
184
+ * @param anchorElement The anchor element to insert to.
376
185
  */
377
- addRedirectRouteEntry(route, visitCondition, anchorElement, multiline = false, prepend = false) {
186
+ addRedirectRouteEntry(route, visitCondition, multiline = false, prepend = false, anchorElement) {
378
187
  const structure = [
379
188
  {
380
189
  name: cli_core_1.RouteTarget.Path,
@@ -394,15 +203,75 @@ class AngularTypeScriptFileUpdate {
394
203
  const newRoute = this.astTransformer.createObjectLiteralExpression(structure, multiline);
395
204
  return this.astTransformer.addMembersToArrayLiteral(visitCondition, [newRoute], prepend, anchorElement);
396
205
  }
206
+ //#endregion
207
+ //#region Internals
208
+ /**
209
+ * Updates an Angular decorator's metadata.
210
+ * @param name The name of the decorator to update.
211
+ * @param meta Names of identifiers to be added.
212
+ * @param target The target metadata property to update.
213
+ * @param multiline Whether to format the new entry as multiline.
214
+ */
215
+ mutateNgDecoratorMeta(name, meta, target, multiline = false) {
216
+ const identifiers = meta.map(ts.factory.createIdentifier);
217
+ const targetMetaProp = this.findNgDecoratorProperty(name, target);
218
+ if (!targetMetaProp) {
219
+ return this.astTransformer.addMemberToObjectLiteral((node) => this.checkNgDecorator(name, node), {
220
+ name: target,
221
+ value: this.astTransformer.createArrayLiteralExpression(identifiers, multiline),
222
+ });
223
+ }
224
+ if (ts.isArrayLiteralExpression(targetMetaProp.initializer)) {
225
+ // prop assignment of the form { member: [...] }
226
+ // store to avoid second type check due to different context in the filter
227
+ const elementsAsNodeArray = targetMetaProp.initializer.elements;
228
+ const elementsToAdd = identifiers.filter((i) => !elementsAsNodeArray.some((el) => el.getText() === i.text));
229
+ return this.astTransformer.addMembersToArrayLiteral((node) => ts.isPropertyAssignment(node.parent) &&
230
+ node.parent.name.getText() === target &&
231
+ this.checkNgDecorator(name, node), elementsToAdd);
232
+ }
233
+ // prop assignment of the form { member: <some-val> }
234
+ return this.astTransformer.updateObjectLiteralMember((node) => this.checkNgDecorator(name, node), {
235
+ name: target,
236
+ value: this.astTransformer.createArrayLiteralExpression([targetMetaProp.initializer, ...identifiers], multiline),
237
+ });
238
+ }
239
+ /**
240
+ * Checks if a node has an ancestor with a specific decorator.
241
+ * @param name The name of the decorator.
242
+ * @param node The node to start checking from.
243
+ */
244
+ checkNgDecorator(name, node) {
245
+ return !!this.astTransformer.findNodeAncestor(node, (node) => {
246
+ var _a;
247
+ return ts.isDecorator(node) &&
248
+ ((_a = node.expression.getFirstToken()) === null || _a === void 0 ? void 0 : _a.getText()) === name;
249
+ });
250
+ }
251
+ /**
252
+ * Finds a property assignment that exists in a specific NG decorator meta.
253
+ * @param decoratorName The name of the decorator to check.
254
+ * @param propName The property name to check.
255
+ * @param node The node to start checking from.
256
+ */
257
+ findNgDecoratorProperty(decoratorName, propName) {
258
+ return this.astTransformer.findPropertyAssignment((node) => node.name.getText() === propName &&
259
+ !!this.astTransformer.findNodeAncestor(node, (node) => {
260
+ var _a;
261
+ return ts.isDecorator(node) &&
262
+ ((_a = node.expression.getFirstToken()) === null || _a === void 0 ? void 0 : _a.getText()) === decoratorName;
263
+ }));
264
+ }
397
265
  /**
398
266
  * Adds a new lazy-loaded route entry to the routes array.
399
267
  * @param route The route to add.
400
268
  * @param visitCondition The condition used to find the appropriate route node.
401
- * @param anchorElement The anchor element to insert to.
402
269
  * @param multiline Whether to format the new entry as multiline.
403
270
  * @param prepend Whether to insert the new entry before the anchor element.
271
+ * If no anchor is provided, the new entry will be added to the start or end of the array.
272
+ * @param anchorElement The anchor element to insert to.
404
273
  */
405
- addLazyLoadedRouteEntry(route, visitCondition, anchorElement, multiline = false, prepend = false) {
274
+ addLazyLoadedRouteEntry(route, visitCondition, multiline = false, prepend = false, anchorElement) {
406
275
  const lazyLoadedModule = this.createDynamicImport(route.modulePath, route.identifierName, route.root);
407
276
  const propAssignmentName = route.root
408
277
  ? types_1.AngularRouteTarget.LoadChildren
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@igniteui/angular-templates",
3
- "version": "17.2.1321-beta.0",
3
+ "version": "17.2.1322-beta.0",
4
4
  "description": "Templates for Ignite UI for Angular projects and components",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,7 +12,7 @@
12
12
  "author": "Infragistics",
13
13
  "license": "MIT",
14
14
  "dependencies": {
15
- "@igniteui/cli-core": "~13.2.1-beta.0",
15
+ "@igniteui/cli-core": "~13.2.2-beta.0",
16
16
  "typescript": "~5.4.3"
17
17
  }
18
18
  }
@@ -7,8 +7,6 @@ export interface AngularRouteLike extends RouteLike {
7
7
  root?: boolean;
8
8
  /** Additional developer-defined data provided to the component via `ActivatedRoute`. */
9
9
  data?: KeyValuePair<string>;
10
- /** A URL to redirect to when the path matches. */
11
- redirectTo?: string;
12
10
  /** An array of child `Route` objects that specifies a nested route configuration. */
13
- children?: AngularRouteLike[];
11
+ children?: AngularRouteLike | AngularRouteLike[];
14
12
  }