@rhtml/schematics 0.0.133 → 0.0.135

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.
Files changed (43) hide show
  1. package/dist/lib/component/schema.json +1 -1
  2. package/dist/lib/controller/schema.json +1 -1
  3. package/dist/lib/module/schema.json +4 -4
  4. package/dist/lib/provider/schema.json +4 -4
  5. package/dist/lib/service/schema.json +3 -3
  6. package/dist/utils/metadata.manager.d.ts +65 -2
  7. package/dist/utils/metadata.manager.js +103 -23
  8. package/dist/utils/metadata.manager.ts +127 -46
  9. package/dist/utils/module-import.declarator.d.ts +31 -2
  10. package/dist/utils/module-import.declarator.js +42 -10
  11. package/dist/utils/module-import.declarator.ts +45 -12
  12. package/dist/utils/module-metadata.declarator.d.ts +12 -0
  13. package/dist/utils/module-metadata.declarator.js +13 -1
  14. package/dist/utils/module-metadata.declarator.ts +13 -1
  15. package/dist/utils/module.declarator.d.ts +21 -1
  16. package/dist/utils/module.declarator.js +23 -1
  17. package/dist/utils/module.declarator.ts +24 -2
  18. package/dist/utils/module.finder.d.ts +12 -0
  19. package/dist/utils/module.finder.js +13 -1
  20. package/dist/utils/module.finder.ts +13 -1
  21. package/dist/utils/name.parser.d.ts +6 -0
  22. package/dist/utils/name.parser.js +6 -0
  23. package/dist/utils/name.parser.ts +6 -0
  24. package/dist/utils/path.solver.d.ts +7 -0
  25. package/dist/utils/path.solver.js +7 -0
  26. package/dist/utils/path.solver.ts +7 -0
  27. package/dist/utils/source-root.helpers.d.ts +13 -1
  28. package/dist/utils/source-root.helpers.js +13 -1
  29. package/dist/utils/source-root.helpers.ts +14 -2
  30. package/package.json +5 -5
  31. package/src/lib/component/schema.json +1 -1
  32. package/src/lib/controller/schema.json +1 -1
  33. package/src/lib/module/schema.json +4 -4
  34. package/src/lib/provider/schema.json +4 -4
  35. package/src/lib/service/schema.json +3 -3
  36. package/src/utils/metadata.manager.ts +127 -46
  37. package/src/utils/module-import.declarator.ts +45 -12
  38. package/src/utils/module-metadata.declarator.ts +13 -1
  39. package/src/utils/module.declarator.ts +24 -2
  40. package/src/utils/module.finder.ts +13 -1
  41. package/src/utils/name.parser.ts +6 -0
  42. package/src/utils/path.solver.ts +7 -0
  43. package/src/utils/source-root.helpers.ts +14 -2
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/schema",
3
- "id": "SchematicsRHTMLComponent",
3
+ "$id": "SchematicsRHTMLComponent",
4
4
  "title": "@rhtml Component Options Schema",
5
5
  "type": "object",
6
6
  "properties": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/schema",
3
- "id": "SchematicsRHTMLController",
3
+ "$id": "SchematicsRHTMLController",
4
4
  "title": "RHTML Controller Options Schema",
5
5
  "type": "object",
6
6
  "properties": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/schema",
3
- "id": "SchematicsNestModule",
4
- "title": "Nest Module Options Schema",
3
+ "$id": "SchematicsRhtmlModule",
4
+ "title": "Rhtml Module Options Schema",
5
5
  "type": "object",
6
6
  "properties": {
7
7
  "name": {
@@ -25,11 +25,11 @@
25
25
  },
26
26
  "language": {
27
27
  "type": "string",
28
- "description": "Nest module language (ts/js)."
28
+ "description": "Rhtml module language (ts/js)."
29
29
  },
30
30
  "sourceRoot": {
31
31
  "type": "string",
32
- "description": "Nest module source root directory."
32
+ "description": "Rhtml module source root directory."
33
33
  },
34
34
  "skipImport": {
35
35
  "description": "Flag to skip the module import.",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/schema",
3
- "id": "SchematicsNestProvider",
4
- "title": "Nest Provider Options Schema",
3
+ "$id": "SchematicsRhtmlProvider",
4
+ "title": "Rhtml Provider Options Schema",
5
5
  "type": "object",
6
6
  "properties": {
7
7
  "name": {
@@ -20,11 +20,11 @@
20
20
  },
21
21
  "language": {
22
22
  "type": "string",
23
- "description": "Nest provider language (ts/js)."
23
+ "description": "Rhtml provider language (ts/js)."
24
24
  },
25
25
  "sourceRoot": {
26
26
  "type": "string",
27
- "description": "Nest provider source root directory."
27
+ "description": "Rhtml provider source root directory."
28
28
  },
29
29
  "flat": {
30
30
  "default": true,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/schema",
3
- "id": "SchematicsNestService",
4
- "title": "Nest Service Options Schema",
3
+ "$id": "SchematicsRhtmlService",
4
+ "title": "Rhtml Service Options Schema",
5
5
  "type": "object",
6
6
  "properties": {
7
7
  "name": {
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "language": {
22
22
  "type": "string",
23
- "description": "Nest service language (ts/js)."
23
+ "description": "Rhtml service language (ts/js)."
24
24
  },
25
25
  "sourceRoot": {
26
26
  "type": "string",
@@ -1,13 +1,76 @@
1
1
  import { DeclarationOptions } from './module.declarator';
2
+ /**
3
+ * The `MetadataManager` class provides utilities for managing metadata entries
4
+ * within a `@Module` decorator in a TypeScript source file. It allows for the
5
+ * insertion of new metadata entries, merging symbols with static options, and
6
+ * handling various scenarios such as empty module decorators or existing metadata
7
+ * properties.
8
+ */
2
9
  export declare class MetadataManager {
3
10
  private content;
4
11
  constructor(content: string);
5
- insert(metadata: string, symbol: string, staticOptions?: DeclarationOptions['staticOptions']): string;
6
- private getDecoratorMetadata;
12
+ /**
13
+ * Inserts a new metadata entry into the `@Module` decorator.
14
+ *
15
+ * @param metadata - The metadata key to insert.
16
+ * @param symbol - The symbol to insert.
17
+ * @param staticOptions - The static options to insert.
18
+ * @returns The new content string.
19
+ */
20
+ insert(metadata: string, symbol: string, staticOptions?: DeclarationOptions['staticOptions']): string | undefined;
21
+ /**
22
+ * Finds the first `@Module` decorator metadata in the source file.
23
+ *
24
+ * @param source - The source file to search.
25
+ * @param identifier - The identifier to match.
26
+ * @returns The first matching `ObjectLiteralExpression` or undefined.
27
+ */
28
+ private findFirstDecoratorMetadata;
29
+ /**
30
+ * Returns an array of all nodes in the source file.
31
+ */
7
32
  private getSourceNodes;
33
+ /**
34
+ * Inserts a new metadata entry into an empty `@Module` decorator.
35
+ * This method is called when the `@Module` decorator has no properties.
36
+ * It inserts the metadata and symbol into the decorator.
37
+ * @param expr - The `@Module` decorator node.
38
+ * @param metadata - The metadata key to insert.
39
+ * @param symbol - The symbol to insert.
40
+ * @returns The new content string.
41
+ */
8
42
  private insertMetadataToEmptyModuleDecorator;
43
+ /**
44
+ * Inserts a new symbol into an existing metadata property in the `@Module` decorator.
45
+ * This method is called when the metadata property already exists in the decorator.
46
+ * It inserts the symbol into the existing metadata property.
47
+ * @param source - The source file.
48
+ * @param matchingProperties - The matching metadata properties.
49
+ * @param symbol - The symbol to insert.
50
+ * @param staticOptions - The static options to insert.
51
+ * @returns The new content string.
52
+ */
9
53
  private insertNewMetadataToDecorator;
54
+ /**
55
+ * Inserts a new symbol into an existing metadata property in the `@Module` decorator.
56
+ * This method is called when the metadata property already exists in the decorator.
57
+ * It inserts the symbol into the existing metadata property.
58
+ * @param source - The source file.
59
+ * @param matchingProperties - The matching metadata properties.
60
+ * @param symbol - The symbol to insert.
61
+ * @param staticOptions - The static options to insert.
62
+ * @returns The new content string.
63
+ */
10
64
  private insertSymbolToMetadata;
65
+ /**
66
+ * Merges a symbol with static options into a single string.
67
+ * @param symbol - The symbol to merge.
68
+ * @param staticOptions - The static options to merge.
69
+ * @returns The merged string.
70
+ */
11
71
  private mergeSymbolAndExpr;
72
+ /**
73
+ * Adds blank lines around an expression.
74
+ */
12
75
  private addBlankLines;
13
76
  }
@@ -2,15 +2,33 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MetadataManager = void 0;
4
4
  const typescript_1 = require("typescript");
5
+ /**
6
+ * The `MetadataManager` class provides utilities for managing metadata entries
7
+ * within a `@Module` decorator in a TypeScript source file. It allows for the
8
+ * insertion of new metadata entries, merging symbols with static options, and
9
+ * handling various scenarios such as empty module decorators or existing metadata
10
+ * properties.
11
+ */
5
12
  class MetadataManager {
6
13
  constructor(content) {
7
14
  this.content = content;
8
15
  }
16
+ /**
17
+ * Inserts a new metadata entry into the `@Module` decorator.
18
+ *
19
+ * @param metadata - The metadata key to insert.
20
+ * @param symbol - The symbol to insert.
21
+ * @param staticOptions - The static options to insert.
22
+ * @returns The new content string.
23
+ */
9
24
  insert(metadata, symbol, staticOptions) {
10
25
  const source = (0, typescript_1.createSourceFile)('filename.ts', this.content, typescript_1.ScriptTarget.ES2017);
11
- const decoratorNodes = this.getDecoratorMetadata(source, '@Module');
12
- const node = decoratorNodes[0];
13
- const matchingProperties = node.properties
26
+ const moduleDecoratorNode = this.findFirstDecoratorMetadata(source, 'Module');
27
+ // If there is no occurrence of `@Module` decorator, nothing will be inserted
28
+ if (!moduleDecoratorNode) {
29
+ return;
30
+ }
31
+ const matchingProperties = moduleDecoratorNode.properties
14
32
  .filter((prop) => prop.kind === typescript_1.SyntaxKind.PropertyAssignment)
15
33
  .filter((prop) => {
16
34
  const name = prop.name;
@@ -28,7 +46,7 @@ class MetadataManager {
28
46
  symbol = staticOptions ? this.addBlankLines(symbol) : symbol;
29
47
  };
30
48
  if (matchingProperties.length === 0) {
31
- const expr = node;
49
+ const expr = moduleDecoratorNode;
32
50
  if (expr.properties.length === 0) {
33
51
  addBlankLinesIfDynamic();
34
52
  return this.insertMetadataToEmptyModuleDecorator(expr, metadata, symbol);
@@ -42,16 +60,38 @@ class MetadataManager {
42
60
  return this.insertSymbolToMetadata(source, matchingProperties, symbol, staticOptions);
43
61
  }
44
62
  }
45
- getDecoratorMetadata(source, identifier) {
46
- identifier;
47
- return this.getSourceNodes(source)
48
- .filter((node) => node.kind === typescript_1.SyntaxKind.Decorator &&
49
- node.expression.kind === typescript_1.SyntaxKind.CallExpression)
50
- .map((node) => node.expression)
51
- .filter((expr) => expr.arguments[0] &&
52
- expr.arguments[0].kind === typescript_1.SyntaxKind.ObjectLiteralExpression)
53
- .map((expr) => expr.arguments[0]);
63
+ /**
64
+ * Finds the first `@Module` decorator metadata in the source file.
65
+ *
66
+ * @param source - The source file to search.
67
+ * @param identifier - The identifier to match.
68
+ * @returns The first matching `ObjectLiteralExpression` or undefined.
69
+ */
70
+ findFirstDecoratorMetadata(source, identifier) {
71
+ var _a;
72
+ for (const node of this.getSourceNodes(source)) {
73
+ const isDecoratorFactoryNode = node.kind === typescript_1.SyntaxKind.Decorator &&
74
+ node.expression.kind === typescript_1.SyntaxKind.CallExpression;
75
+ if (!isDecoratorFactoryNode)
76
+ continue;
77
+ const expr = node.expression;
78
+ const isExpectedExpression = ((_a = expr.arguments[0]) === null || _a === void 0 ? void 0 : _a.kind) === typescript_1.SyntaxKind.ObjectLiteralExpression;
79
+ if (!isExpectedExpression)
80
+ continue;
81
+ if (expr.expression.kind === typescript_1.SyntaxKind.Identifier) {
82
+ const escapedText = expr.expression.escapedText;
83
+ const isTargetIdentifier = escapedText
84
+ ? escapedText.toLowerCase() === identifier.toLowerCase()
85
+ : true;
86
+ if (isTargetIdentifier) {
87
+ return expr.arguments[0];
88
+ }
89
+ }
90
+ }
54
91
  }
92
+ /**
93
+ * Returns an array of all nodes in the source file.
94
+ */
55
95
  getSourceNodes(sourceFile) {
56
96
  const nodes = [sourceFile];
57
97
  const result = [];
@@ -60,12 +100,21 @@ class MetadataManager {
60
100
  if (node) {
61
101
  result.push(node);
62
102
  if (node.getChildCount(sourceFile) >= 0) {
63
- nodes.unshift(...node.getChildren());
103
+ nodes.unshift(...node.getChildren(sourceFile));
64
104
  }
65
105
  }
66
106
  }
67
107
  return result;
68
108
  }
109
+ /**
110
+ * Inserts a new metadata entry into an empty `@Module` decorator.
111
+ * This method is called when the `@Module` decorator has no properties.
112
+ * It inserts the metadata and symbol into the decorator.
113
+ * @param expr - The `@Module` decorator node.
114
+ * @param metadata - The metadata key to insert.
115
+ * @param symbol - The symbol to insert.
116
+ * @returns The new content string.
117
+ */
69
118
  insertMetadataToEmptyModuleDecorator(expr, metadata, symbol) {
70
119
  const position = expr.getEnd() - 1;
71
120
  const toInsert = ` ${metadata}: [${symbol}]`;
@@ -78,13 +127,23 @@ class MetadataManager {
78
127
  }
79
128
  }, '');
80
129
  }
130
+ /**
131
+ * Inserts a new symbol into an existing metadata property in the `@Module` decorator.
132
+ * This method is called when the metadata property already exists in the decorator.
133
+ * It inserts the symbol into the existing metadata property.
134
+ * @param source - The source file.
135
+ * @param matchingProperties - The matching metadata properties.
136
+ * @param symbol - The symbol to insert.
137
+ * @param staticOptions - The static options to insert.
138
+ * @returns The new content string.
139
+ */
81
140
  insertNewMetadataToDecorator(expr, source, metadata, symbol) {
82
141
  const node = expr.properties[expr.properties.length - 1];
83
142
  const position = node.getEnd();
84
143
  const text = node.getFullText(source);
85
144
  const matches = text.match(/^\r?\n\s*/);
86
145
  let toInsert;
87
- if (matches.length > 0) {
146
+ if (matches) {
88
147
  toInsert = `,${matches[0]}${metadata}: [${symbol}]`;
89
148
  }
90
149
  else {
@@ -99,10 +158,24 @@ class MetadataManager {
99
158
  }
100
159
  }, '');
101
160
  }
161
+ /**
162
+ * Inserts a new symbol into an existing metadata property in the `@Module` decorator.
163
+ * This method is called when the metadata property already exists in the decorator.
164
+ * It inserts the symbol into the existing metadata property.
165
+ * @param source - The source file.
166
+ * @param matchingProperties - The matching metadata properties.
167
+ * @param symbol - The symbol to insert.
168
+ * @param staticOptions - The static options to insert.
169
+ * @returns The new content string.
170
+ */
102
171
  insertSymbolToMetadata(source, matchingProperties, symbol, staticOptions) {
103
172
  const assignment = matchingProperties[0];
104
173
  let node;
105
174
  const arrLiteral = assignment.initializer;
175
+ if (!arrLiteral.elements) {
176
+ // "imports" is not an array but rather function/constant
177
+ return this.content;
178
+ }
106
179
  if (arrLiteral.elements.length === 0) {
107
180
  node = arrLiteral;
108
181
  }
@@ -125,12 +198,10 @@ class MetadataManager {
125
198
  }
126
199
  else {
127
200
  const text = node.getFullText(source);
128
- if (text.match(/^\r?\n/)) {
129
- toInsert = `,${text.match(/^\r?\n(\r?)\s+/)[0]}${symbol}`;
130
- }
131
- else {
132
- toInsert = `, ${symbol}`;
133
- }
201
+ const itemSeparator = (text.match(/^\r?\n(\r?)\s+/) ||
202
+ text.match(/^\r?\n/) ||
203
+ ' ')[0];
204
+ toInsert = `,${itemSeparator}${symbol}`;
134
205
  }
135
206
  return this.content.split('').reduce((content, char, index) => {
136
207
  if (index === position) {
@@ -141,18 +212,27 @@ class MetadataManager {
141
212
  }
142
213
  }, '');
143
214
  }
215
+ /**
216
+ * Merges a symbol with static options into a single string.
217
+ * @param symbol - The symbol to merge.
218
+ * @param staticOptions - The static options to merge.
219
+ * @returns The merged string.
220
+ */
144
221
  mergeSymbolAndExpr(symbol, staticOptions) {
145
222
  if (!staticOptions) {
146
223
  return symbol;
147
224
  }
148
225
  const spacing = 6;
149
226
  let options = JSON.stringify(staticOptions.value, null, spacing);
150
- options = options.replace(/\"([^(\")"]+)\":/g, '$1:');
151
- options = options.replace(/\"/g, `'`);
227
+ options = options.replace(/"([^(")"]+)":/g, '$1:');
228
+ options = options.replace(/"/g, `'`);
152
229
  options = options.slice(0, options.length - 1) + ' }';
153
230
  symbol += `.${staticOptions.name}(${options})`;
154
231
  return symbol;
155
232
  }
233
+ /**
234
+ * Adds blank lines around an expression.
235
+ */
156
236
  addBlankLines(expr) {
157
237
  return `\n ${expr}\n `;
158
238
  }
@@ -12,49 +12,68 @@ import {
12
12
  PropertyAssignment,
13
13
  ScriptTarget,
14
14
  SourceFile,
15
- StringLiteral,
16
15
  SyntaxKind,
17
16
  } from 'typescript';
18
17
 
19
18
  import { DeclarationOptions } from './module.declarator';
20
19
 
20
+ /**
21
+ * The `MetadataManager` class provides utilities for managing metadata entries
22
+ * within a `@Module` decorator in a TypeScript source file. It allows for the
23
+ * insertion of new metadata entries, merging symbols with static options, and
24
+ * handling various scenarios such as empty module decorators or existing metadata
25
+ * properties.
26
+ */
21
27
  export class MetadataManager {
22
28
  constructor(private content: string) {}
23
29
 
30
+ /**
31
+ * Inserts a new metadata entry into the `@Module` decorator.
32
+ *
33
+ * @param metadata - The metadata key to insert.
34
+ * @param symbol - The symbol to insert.
35
+ * @param staticOptions - The static options to insert.
36
+ * @returns The new content string.
37
+ */
24
38
  public insert(
25
39
  metadata: string,
26
40
  symbol: string,
27
41
  staticOptions?: DeclarationOptions['staticOptions']
28
- ): string {
42
+ ): string | undefined {
29
43
  const source: SourceFile = createSourceFile(
30
44
  'filename.ts',
31
45
  this.content,
32
46
  ScriptTarget.ES2017
33
47
  );
34
- const decoratorNodes: Node[] = this.getDecoratorMetadata(source, '@Module');
35
- const node: Node = decoratorNodes[0];
36
- const matchingProperties: ObjectLiteralElement[] = (
37
- node as ObjectLiteralExpression
38
- ).properties
39
- .filter((prop) => prop.kind === SyntaxKind.PropertyAssignment)
40
- .filter((prop: PropertyAssignment) => {
41
- const name = prop.name;
42
- switch (name.kind) {
43
- case SyntaxKind.Identifier:
44
- return (name as Identifier).getText(source) === metadata;
45
- case SyntaxKind.StringLiteral:
46
- return (name as StringLiteral).text === metadata;
47
- default:
48
- return false;
49
- }
50
- });
48
+ const moduleDecoratorNode = this.findFirstDecoratorMetadata(
49
+ source,
50
+ 'Module'
51
+ );
52
+ // If there is no occurrence of `@Module` decorator, nothing will be inserted
53
+ if (!moduleDecoratorNode) {
54
+ return;
55
+ }
56
+ const matchingProperties: ObjectLiteralElement[] =
57
+ moduleDecoratorNode.properties
58
+ .filter((prop) => prop.kind === SyntaxKind.PropertyAssignment)
59
+ .filter((prop: PropertyAssignment) => {
60
+ const name = prop.name;
61
+ switch (name.kind) {
62
+ case SyntaxKind.Identifier:
63
+ return name.getText(source) === metadata;
64
+ case SyntaxKind.StringLiteral:
65
+ return name.text === metadata;
66
+ default:
67
+ return false;
68
+ }
69
+ });
51
70
 
52
71
  symbol = this.mergeSymbolAndExpr(symbol, staticOptions);
53
72
  const addBlankLinesIfDynamic = () => {
54
73
  symbol = staticOptions ? this.addBlankLines(symbol) : symbol;
55
74
  };
56
75
  if (matchingProperties.length === 0) {
57
- const expr = node as ObjectLiteralExpression;
76
+ const expr = moduleDecoratorNode;
58
77
  if (expr.properties.length === 0) {
59
78
  addBlankLinesIfDynamic();
60
79
  return this.insertMetadataToEmptyModuleDecorator(
@@ -81,38 +100,68 @@ export class MetadataManager {
81
100
  }
82
101
  }
83
102
 
84
- private getDecoratorMetadata(source: SourceFile, identifier: string): Node[] {
85
- identifier;
86
- return this.getSourceNodes(source)
87
- .filter(
88
- (node) =>
89
- node.kind === SyntaxKind.Decorator &&
90
- (node as Decorator).expression.kind === SyntaxKind.CallExpression
91
- )
92
- .map((node) => (node as Decorator).expression as CallExpression)
93
- .filter(
94
- (expr) =>
95
- expr.arguments[0] &&
96
- expr.arguments[0].kind === SyntaxKind.ObjectLiteralExpression
97
- )
98
- .map((expr) => expr.arguments[0] as ObjectLiteralExpression);
103
+ /**
104
+ * Finds the first `@Module` decorator metadata in the source file.
105
+ *
106
+ * @param source - The source file to search.
107
+ * @param identifier - The identifier to match.
108
+ * @returns The first matching `ObjectLiteralExpression` or undefined.
109
+ */
110
+ private findFirstDecoratorMetadata(
111
+ source: SourceFile,
112
+ identifier: string
113
+ ): ObjectLiteralExpression | undefined {
114
+ for (const node of this.getSourceNodes(source)) {
115
+ const isDecoratorFactoryNode =
116
+ node.kind === SyntaxKind.Decorator &&
117
+ (node as Decorator).expression.kind === SyntaxKind.CallExpression;
118
+ if (!isDecoratorFactoryNode) continue;
119
+
120
+ const expr = (node as Decorator).expression as CallExpression;
121
+
122
+ const isExpectedExpression =
123
+ expr.arguments[0]?.kind === SyntaxKind.ObjectLiteralExpression;
124
+ if (!isExpectedExpression) continue;
125
+
126
+ if (expr.expression.kind === SyntaxKind.Identifier) {
127
+ const escapedText = (expr.expression as Identifier).escapedText;
128
+ const isTargetIdentifier = escapedText
129
+ ? escapedText.toLowerCase() === identifier.toLowerCase()
130
+ : true;
131
+ if (isTargetIdentifier) {
132
+ return expr.arguments[0] as ObjectLiteralExpression;
133
+ }
134
+ }
135
+ }
99
136
  }
100
137
 
138
+ /**
139
+ * Returns an array of all nodes in the source file.
140
+ */
101
141
  private getSourceNodes(sourceFile: SourceFile): Node[] {
102
142
  const nodes: Node[] = [sourceFile];
103
- const result = [];
143
+ const result: Node[] = [];
104
144
  while (nodes.length > 0) {
105
145
  const node = nodes.shift();
106
146
  if (node) {
107
147
  result.push(node);
108
148
  if (node.getChildCount(sourceFile) >= 0) {
109
- nodes.unshift(...node.getChildren());
149
+ nodes.unshift(...node.getChildren(sourceFile));
110
150
  }
111
151
  }
112
152
  }
113
153
  return result;
114
154
  }
115
155
 
156
+ /**
157
+ * Inserts a new metadata entry into an empty `@Module` decorator.
158
+ * This method is called when the `@Module` decorator has no properties.
159
+ * It inserts the metadata and symbol into the decorator.
160
+ * @param expr - The `@Module` decorator node.
161
+ * @param metadata - The metadata key to insert.
162
+ * @param symbol - The symbol to insert.
163
+ * @returns The new content string.
164
+ */
116
165
  private insertMetadataToEmptyModuleDecorator(
117
166
  expr: ObjectLiteralExpression,
118
167
  metadata: string,
@@ -129,6 +178,16 @@ export class MetadataManager {
129
178
  }, '');
130
179
  }
131
180
 
181
+ /**
182
+ * Inserts a new symbol into an existing metadata property in the `@Module` decorator.
183
+ * This method is called when the metadata property already exists in the decorator.
184
+ * It inserts the symbol into the existing metadata property.
185
+ * @param source - The source file.
186
+ * @param matchingProperties - The matching metadata properties.
187
+ * @param symbol - The symbol to insert.
188
+ * @param staticOptions - The static options to insert.
189
+ * @returns The new content string.
190
+ */
132
191
  private insertNewMetadataToDecorator(
133
192
  expr: ObjectLiteralExpression,
134
193
  source: SourceFile,
@@ -140,7 +199,7 @@ export class MetadataManager {
140
199
  const text = node.getFullText(source);
141
200
  const matches = text.match(/^\r?\n\s*/);
142
201
  let toInsert: string;
143
- if (matches.length > 0) {
202
+ if (matches) {
144
203
  toInsert = `,${matches[0]}${metadata}: [${symbol}]`;
145
204
  } else {
146
205
  toInsert = `, ${metadata}: [${symbol}]`;
@@ -154,6 +213,16 @@ export class MetadataManager {
154
213
  }, '');
155
214
  }
156
215
 
216
+ /**
217
+ * Inserts a new symbol into an existing metadata property in the `@Module` decorator.
218
+ * This method is called when the metadata property already exists in the decorator.
219
+ * It inserts the symbol into the existing metadata property.
220
+ * @param source - The source file.
221
+ * @param matchingProperties - The matching metadata properties.
222
+ * @param symbol - The symbol to insert.
223
+ * @param staticOptions - The static options to insert.
224
+ * @returns The new content string.
225
+ */
157
226
  private insertSymbolToMetadata(
158
227
  source: SourceFile,
159
228
  matchingProperties: ObjectLiteralElement[],
@@ -163,13 +232,17 @@ export class MetadataManager {
163
232
  const assignment = matchingProperties[0] as PropertyAssignment;
164
233
  let node: Node | NodeArray<Expression>;
165
234
  const arrLiteral = assignment.initializer as ArrayLiteralExpression;
235
+ if (!arrLiteral.elements) {
236
+ // "imports" is not an array but rather function/constant
237
+ return this.content;
238
+ }
166
239
  if (arrLiteral.elements.length === 0) {
167
240
  node = arrLiteral;
168
241
  } else {
169
242
  node = arrLiteral.elements;
170
243
  }
171
244
  if (Array.isArray(node)) {
172
- const nodeArray = node as {} as Node[];
245
+ const nodeArray = node as unknown as Node[];
173
246
  const symbolsArray = nodeArray.map((childNode) =>
174
247
  childNode.getText(source)
175
248
  );
@@ -186,11 +259,10 @@ export class MetadataManager {
186
259
  toInsert = staticOptions ? this.addBlankLines(symbol) : `${symbol}`;
187
260
  } else {
188
261
  const text = (node as Node).getFullText(source);
189
- if (text.match(/^\r?\n/)) {
190
- toInsert = `,${text.match(/^\r?\n(\r?)\s+/)[0]}${symbol}`;
191
- } else {
192
- toInsert = `, ${symbol}`;
193
- }
262
+ const itemSeparator = (text.match(/^\r?\n(\r?)\s+/) ||
263
+ text.match(/^\r?\n/) ||
264
+ ' ')[0];
265
+ toInsert = `,${itemSeparator}${symbol}`;
194
266
  }
195
267
  return this.content.split('').reduce((content, char, index) => {
196
268
  if (index === position) {
@@ -201,6 +273,12 @@ export class MetadataManager {
201
273
  }, '');
202
274
  }
203
275
 
276
+ /**
277
+ * Merges a symbol with static options into a single string.
278
+ * @param symbol - The symbol to merge.
279
+ * @param staticOptions - The static options to merge.
280
+ * @returns The merged string.
281
+ */
204
282
  private mergeSymbolAndExpr(
205
283
  symbol: string,
206
284
  staticOptions?: DeclarationOptions['staticOptions']
@@ -210,13 +288,16 @@ export class MetadataManager {
210
288
  }
211
289
  const spacing = 6;
212
290
  let options = JSON.stringify(staticOptions.value, null, spacing);
213
- options = options.replace(/\"([^(\")"]+)\":/g, '$1:');
214
- options = options.replace(/\"/g, `'`);
291
+ options = options.replace(/"([^(")"]+)":/g, '$1:');
292
+ options = options.replace(/"/g, `'`);
215
293
  options = options.slice(0, options.length - 1) + ' }';
216
294
  symbol += `.${staticOptions.name}(${options})`;
217
295
  return symbol;
218
296
  }
219
297
 
298
+ /**
299
+ * Adds blank lines around an expression.
300
+ */
220
301
  private addBlankLines(expr: string): string {
221
302
  return `\n ${expr}\n `;
222
303
  }