@ngrx/signals 17.0.0-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.
Files changed (80) hide show
  1. package/LICENSE +25 -0
  2. package/README.md +3 -0
  3. package/esm2022/index.mjs +2 -0
  4. package/esm2022/ngrx-signals.mjs +5 -0
  5. package/esm2022/rxjs-interop/index.mjs +2 -0
  6. package/esm2022/rxjs-interop/ngrx-signals-rxjs-interop.mjs +5 -0
  7. package/esm2022/rxjs-interop/src/index.mjs +2 -0
  8. package/esm2022/rxjs-interop/src/rx-method.mjs +31 -0
  9. package/esm2022/src/deep-signal.mjs +22 -0
  10. package/esm2022/src/helpers.mjs +4 -0
  11. package/esm2022/src/index.mjs +9 -0
  12. package/esm2022/src/patch-state.mjs +8 -0
  13. package/esm2022/src/signal-state.mjs +12 -0
  14. package/esm2022/src/signal-store-feature.mjs +10 -0
  15. package/esm2022/src/signal-store-models.mjs +2 -0
  16. package/esm2022/src/signal-store.mjs +47 -0
  17. package/esm2022/src/ts-helpers.mjs +2 -0
  18. package/esm2022/src/with-computed.mjs +16 -0
  19. package/esm2022/src/with-hooks.mjs +30 -0
  20. package/esm2022/src/with-methods.mjs +22 -0
  21. package/esm2022/src/with-state.mjs +27 -0
  22. package/fesm2022/ngrx-signals-rxjs-interop.mjs +38 -0
  23. package/fesm2022/ngrx-signals-rxjs-interop.mjs.map +1 -0
  24. package/fesm2022/ngrx-signals.mjs +192 -0
  25. package/fesm2022/ngrx-signals.mjs.map +1 -0
  26. package/index.d.ts +1 -0
  27. package/migrations/migration.json +4 -0
  28. package/package.json +72 -0
  29. package/rxjs-interop/index.d.ts +1 -0
  30. package/rxjs-interop/src/index.d.ts +1 -0
  31. package/rxjs-interop/src/rx-method.d.ts +8 -0
  32. package/schematics/collection.json +10 -0
  33. package/schematics/ng-add/index.js +21 -0
  34. package/schematics/ng-add/index.js.map +1 -0
  35. package/schematics/ng-add/schema.js +3 -0
  36. package/schematics/ng-add/schema.js.map +1 -0
  37. package/schematics/ng-add/schema.json +14 -0
  38. package/schematics-core/index.js +77 -0
  39. package/schematics-core/index.js.map +1 -0
  40. package/schematics-core/utility/ast-utils.js +705 -0
  41. package/schematics-core/utility/ast-utils.js.map +1 -0
  42. package/schematics-core/utility/change.js +162 -0
  43. package/schematics-core/utility/change.js.map +1 -0
  44. package/schematics-core/utility/config.js +21 -0
  45. package/schematics-core/utility/config.js.map +1 -0
  46. package/schematics-core/utility/find-component.js +101 -0
  47. package/schematics-core/utility/find-component.js.map +1 -0
  48. package/schematics-core/utility/find-module.js +102 -0
  49. package/schematics-core/utility/find-module.js.map +1 -0
  50. package/schematics-core/utility/json-utilts.js +37 -0
  51. package/schematics-core/utility/json-utilts.js.map +1 -0
  52. package/schematics-core/utility/libs-version.js +5 -0
  53. package/schematics-core/utility/libs-version.js.map +1 -0
  54. package/schematics-core/utility/ngrx-utils.js +248 -0
  55. package/schematics-core/utility/ngrx-utils.js.map +1 -0
  56. package/schematics-core/utility/package.js +23 -0
  57. package/schematics-core/utility/package.js.map +1 -0
  58. package/schematics-core/utility/parse-name.js +14 -0
  59. package/schematics-core/utility/parse-name.js.map +1 -0
  60. package/schematics-core/utility/project.js +48 -0
  61. package/schematics-core/utility/project.js.map +1 -0
  62. package/schematics-core/utility/strings.js +138 -0
  63. package/schematics-core/utility/strings.js.map +1 -0
  64. package/schematics-core/utility/update.js +34 -0
  65. package/schematics-core/utility/update.js.map +1 -0
  66. package/schematics-core/utility/visitors.js +250 -0
  67. package/schematics-core/utility/visitors.js.map +1 -0
  68. package/src/deep-signal.d.ts +6 -0
  69. package/src/helpers.d.ts +1 -0
  70. package/src/index.d.ts +8 -0
  71. package/src/patch-state.d.ts +3 -0
  72. package/src/signal-state.d.ts +11 -0
  73. package/src/signal-store-feature.d.ts +22 -0
  74. package/src/signal-store-models.d.ts +49 -0
  75. package/src/signal-store.d.ts +21 -0
  76. package/src/ts-helpers.d.ts +11 -0
  77. package/src/with-computed.d.ts +5 -0
  78. package/src/with-hooks.d.ts +9 -0
  79. package/src/with-methods.d.ts +6 -0
  80. package/src/with-state.d.ts +10 -0
@@ -0,0 +1,705 @@
1
+ "use strict";
2
+ var __values = (this && this.__values) || function(o) {
3
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
4
+ if (m) return m.call(o);
5
+ if (o && typeof o.length === "number") return {
6
+ next: function () {
7
+ if (o && i >= o.length) o = void 0;
8
+ return { value: o && o[i++], done: !o };
9
+ }
10
+ };
11
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
12
+ };
13
+ var __read = (this && this.__read) || function (o, n) {
14
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
15
+ if (!m) return o;
16
+ var i = m.call(o), r, ar = [], e;
17
+ try {
18
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
19
+ }
20
+ catch (error) { e = { error: error }; }
21
+ finally {
22
+ try {
23
+ if (r && !r.done && (m = i["return"])) m.call(i);
24
+ }
25
+ finally { if (e) throw e.error; }
26
+ }
27
+ return ar;
28
+ };
29
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
30
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
31
+ if (ar || !(i in from)) {
32
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
33
+ ar[i] = from[i];
34
+ }
35
+ }
36
+ return to.concat(ar || Array.prototype.slice.call(from));
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.containsProperty = exports.replaceImport = exports.insertImport = exports.addBootstrapToModule = exports.addExportToModule = exports.addProviderToComponent = exports.addProviderToModule = exports.addImportToModule = exports.addDeclarationToModule = exports.getDecoratorMetadata = exports.getContentOfKeyLiteral = exports.insertAfterLastOccurrence = exports.getSourceNodes = exports.findNodes = void 0;
40
+ /* istanbul ignore file */
41
+ /**
42
+ * @license
43
+ * Copyright Google Inc. All Rights Reserved.
44
+ *
45
+ * Use of this source code is governed by an MIT-style license that can be
46
+ * found in the LICENSE file at https://angular.io/license
47
+ */
48
+ var ts = require("typescript");
49
+ var change_1 = require("./change");
50
+ /**
51
+ * Find all nodes from the AST in the subtree of node of SyntaxKind kind.
52
+ * @param node
53
+ * @param kind
54
+ * @param max The maximum number of items to return.
55
+ * @return all nodes of kind, or [] if none is found
56
+ */
57
+ function findNodes(node, kind, max) {
58
+ var e_1, _a;
59
+ if (max === void 0) { max = Infinity; }
60
+ if (!node || max == 0) {
61
+ return [];
62
+ }
63
+ var arr = [];
64
+ if (node.kind === kind) {
65
+ arr.push(node);
66
+ max--;
67
+ }
68
+ if (max > 0) {
69
+ try {
70
+ for (var _b = __values(node.getChildren()), _c = _b.next(); !_c.done; _c = _b.next()) {
71
+ var child = _c.value;
72
+ findNodes(child, kind, max).forEach(function (node) {
73
+ if (max > 0) {
74
+ arr.push(node);
75
+ }
76
+ max--;
77
+ });
78
+ if (max <= 0) {
79
+ break;
80
+ }
81
+ }
82
+ }
83
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
84
+ finally {
85
+ try {
86
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
87
+ }
88
+ finally { if (e_1) throw e_1.error; }
89
+ }
90
+ }
91
+ return arr;
92
+ }
93
+ exports.findNodes = findNodes;
94
+ /**
95
+ * Get all the nodes from a source.
96
+ * @param sourceFile The source file object.
97
+ * @returns {Observable<ts.Node>} An observable of all the nodes in the source.
98
+ */
99
+ function getSourceNodes(sourceFile) {
100
+ var nodes = [sourceFile];
101
+ var result = [];
102
+ while (nodes.length > 0) {
103
+ var node = nodes.shift();
104
+ if (node) {
105
+ result.push(node);
106
+ if (node.getChildCount(sourceFile) >= 0) {
107
+ nodes.unshift.apply(nodes, __spreadArray([], __read(node.getChildren()), false));
108
+ }
109
+ }
110
+ }
111
+ return result;
112
+ }
113
+ exports.getSourceNodes = getSourceNodes;
114
+ /**
115
+ * Helper for sorting nodes.
116
+ * @return function to sort nodes in increasing order of position in sourceFile
117
+ */
118
+ function nodesByPosition(first, second) {
119
+ return first.pos - second.pos;
120
+ }
121
+ /**
122
+ * Insert `toInsert` after the last occurence of `ts.SyntaxKind[nodes[i].kind]`
123
+ * or after the last of occurence of `syntaxKind` if the last occurence is a sub child
124
+ * of ts.SyntaxKind[nodes[i].kind] and save the changes in file.
125
+ *
126
+ * @param nodes insert after the last occurence of nodes
127
+ * @param toInsert string to insert
128
+ * @param file file to insert changes into
129
+ * @param fallbackPos position to insert if toInsert happens to be the first occurence
130
+ * @param syntaxKind the ts.SyntaxKind of the subchildren to insert after
131
+ * @return Change instance
132
+ * @throw Error if toInsert is first occurence but fall back is not set
133
+ */
134
+ function insertAfterLastOccurrence(nodes, toInsert, file, fallbackPos, syntaxKind) {
135
+ var lastItem = nodes.sort(nodesByPosition).pop();
136
+ if (!lastItem) {
137
+ throw new Error();
138
+ }
139
+ if (syntaxKind) {
140
+ lastItem = findNodes(lastItem, syntaxKind).sort(nodesByPosition).pop();
141
+ }
142
+ if (!lastItem && fallbackPos == undefined) {
143
+ throw new Error("tried to insert ".concat(toInsert, " as first occurence with no fallback position"));
144
+ }
145
+ var lastItemPosition = lastItem ? lastItem.end : fallbackPos;
146
+ return new change_1.InsertChange(file, lastItemPosition, toInsert);
147
+ }
148
+ exports.insertAfterLastOccurrence = insertAfterLastOccurrence;
149
+ function getContentOfKeyLiteral(_source, node) {
150
+ if (node.kind == ts.SyntaxKind.Identifier) {
151
+ return node.text;
152
+ }
153
+ else if (node.kind == ts.SyntaxKind.StringLiteral) {
154
+ return node.text;
155
+ }
156
+ else {
157
+ return null;
158
+ }
159
+ }
160
+ exports.getContentOfKeyLiteral = getContentOfKeyLiteral;
161
+ function _angularImportsFromNode(node, _sourceFile) {
162
+ var _a;
163
+ var ms = node.moduleSpecifier;
164
+ var modulePath;
165
+ switch (ms.kind) {
166
+ case ts.SyntaxKind.StringLiteral:
167
+ modulePath = ms.text;
168
+ break;
169
+ default:
170
+ return {};
171
+ }
172
+ if (!modulePath.startsWith('@angular/')) {
173
+ return {};
174
+ }
175
+ if (node.importClause) {
176
+ if (node.importClause.name) {
177
+ // This is of the form `import Name from 'path'`. Ignore.
178
+ return {};
179
+ }
180
+ else if (node.importClause.namedBindings) {
181
+ var nb = node.importClause.namedBindings;
182
+ if (nb.kind == ts.SyntaxKind.NamespaceImport) {
183
+ // This is of the form `import * as name from 'path'`. Return `name.`.
184
+ return _a = {},
185
+ _a[nb.name.text + '.'] = modulePath,
186
+ _a;
187
+ }
188
+ else {
189
+ // This is of the form `import {a,b,c} from 'path'`
190
+ var namedImports = nb;
191
+ return namedImports.elements
192
+ .map(function (is) {
193
+ return is.propertyName ? is.propertyName.text : is.name.text;
194
+ })
195
+ .reduce(function (acc, curr) {
196
+ acc[curr] = modulePath;
197
+ return acc;
198
+ }, {});
199
+ }
200
+ }
201
+ return {};
202
+ }
203
+ else {
204
+ // This is of the form `import 'path';`. Nothing to do.
205
+ return {};
206
+ }
207
+ }
208
+ function getDecoratorMetadata(source, identifier, module) {
209
+ var angularImports = findNodes(source, ts.SyntaxKind.ImportDeclaration)
210
+ .map(function (node) {
211
+ return _angularImportsFromNode(node, source);
212
+ })
213
+ .reduce(function (acc, current) {
214
+ var e_2, _a;
215
+ try {
216
+ for (var _b = __values(Object.keys(current)), _c = _b.next(); !_c.done; _c = _b.next()) {
217
+ var key = _c.value;
218
+ acc[key] = current[key];
219
+ }
220
+ }
221
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
222
+ finally {
223
+ try {
224
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
225
+ }
226
+ finally { if (e_2) throw e_2.error; }
227
+ }
228
+ return acc;
229
+ }, {});
230
+ return getSourceNodes(source)
231
+ .filter(function (node) {
232
+ return (node.kind == ts.SyntaxKind.Decorator &&
233
+ node.expression.kind == ts.SyntaxKind.CallExpression);
234
+ })
235
+ .map(function (node) { return node.expression; })
236
+ .filter(function (expr) {
237
+ if (expr.expression.kind == ts.SyntaxKind.Identifier) {
238
+ var id = expr.expression;
239
+ return (id.getFullText(source) == identifier &&
240
+ angularImports[id.getFullText(source)] === module);
241
+ }
242
+ else if (expr.expression.kind == ts.SyntaxKind.PropertyAccessExpression) {
243
+ // This covers foo.NgModule when importing * as foo.
244
+ var paExpr = expr.expression;
245
+ // If the left expression is not an identifier, just give up at that point.
246
+ if (paExpr.expression.kind !== ts.SyntaxKind.Identifier) {
247
+ return false;
248
+ }
249
+ var id = paExpr.name.text;
250
+ var moduleId = paExpr.expression.getText(source);
251
+ return id === identifier && angularImports[moduleId + '.'] === module;
252
+ }
253
+ return false;
254
+ })
255
+ .filter(function (expr) {
256
+ return expr.arguments[0] &&
257
+ expr.arguments[0].kind == ts.SyntaxKind.ObjectLiteralExpression;
258
+ })
259
+ .map(function (expr) { return expr.arguments[0]; });
260
+ }
261
+ exports.getDecoratorMetadata = getDecoratorMetadata;
262
+ function _addSymbolToNgModuleMetadata(source, ngModulePath, metadataField, symbolName, importPath) {
263
+ var nodes = getDecoratorMetadata(source, 'NgModule', '@angular/core');
264
+ var node = nodes[0]; // eslint-disable-line @typescript-eslint/no-explicit-any
265
+ // Find the decorator declaration.
266
+ if (!node) {
267
+ return [];
268
+ }
269
+ // Get all the children property assignment of object literals.
270
+ var matchingProperties = node.properties
271
+ .filter(function (prop) { return prop.kind == ts.SyntaxKind.PropertyAssignment; })
272
+ // Filter out every fields that's not "metadataField". Also handles string literals
273
+ // (but not expressions).
274
+ .filter(function (prop) {
275
+ var name = prop.name;
276
+ switch (name.kind) {
277
+ case ts.SyntaxKind.Identifier:
278
+ return name.getText(source) == metadataField;
279
+ case ts.SyntaxKind.StringLiteral:
280
+ return name.text == metadataField;
281
+ }
282
+ return false;
283
+ });
284
+ // Get the last node of the array literal.
285
+ if (!matchingProperties) {
286
+ return [];
287
+ }
288
+ if (matchingProperties.length == 0) {
289
+ // We haven't found the field in the metadata declaration. Insert a new field.
290
+ var expr = node;
291
+ var position_1;
292
+ var toInsert_1;
293
+ if (expr.properties.length == 0) {
294
+ position_1 = expr.getEnd() - 1;
295
+ toInsert_1 = " ".concat(metadataField, ": [").concat(symbolName, "]\n");
296
+ }
297
+ else {
298
+ node = expr.properties[expr.properties.length - 1];
299
+ position_1 = node.getEnd();
300
+ // Get the indentation of the last element, if any.
301
+ var text = node.getFullText(source);
302
+ var matches = text.match(/^\r?\n\s*/);
303
+ if (matches.length > 0) {
304
+ toInsert_1 = ",".concat(matches[0]).concat(metadataField, ": [").concat(symbolName, "]");
305
+ }
306
+ else {
307
+ toInsert_1 = ", ".concat(metadataField, ": [").concat(symbolName, "]");
308
+ }
309
+ }
310
+ var newMetadataProperty = new change_1.InsertChange(ngModulePath, position_1, toInsert_1);
311
+ var newMetadataImport = insertImport(source, ngModulePath, symbolName.replace(/\..*$/, ''), importPath);
312
+ return [newMetadataProperty, newMetadataImport];
313
+ }
314
+ var assignment = matchingProperties[0];
315
+ // If it's not an array, nothing we can do really.
316
+ if (assignment.initializer.kind !== ts.SyntaxKind.ArrayLiteralExpression) {
317
+ return [];
318
+ }
319
+ var arrLiteral = assignment.initializer;
320
+ if (arrLiteral.elements.length == 0) {
321
+ // Forward the property.
322
+ node = arrLiteral;
323
+ }
324
+ else {
325
+ node = arrLiteral.elements;
326
+ }
327
+ if (!node) {
328
+ console.log('No app module found. Please add your new class to your component.');
329
+ return [];
330
+ }
331
+ if (Array.isArray(node)) {
332
+ var nodeArray = node;
333
+ var symbolsArray = nodeArray.map(function (node) { return node.getText(); });
334
+ if (symbolsArray.includes(symbolName)) {
335
+ return [];
336
+ }
337
+ node = node[node.length - 1];
338
+ var effectsModule = nodeArray.find(function (node) {
339
+ return (node.getText().includes('EffectsModule.forRoot') &&
340
+ symbolName.includes('EffectsModule.forRoot')) ||
341
+ (node.getText().includes('EffectsModule.forFeature') &&
342
+ symbolName.includes('EffectsModule.forFeature'));
343
+ });
344
+ if (effectsModule && symbolName.includes('EffectsModule')) {
345
+ var effectsArgs = effectsModule.arguments.shift();
346
+ if (effectsArgs &&
347
+ effectsArgs.kind === ts.SyntaxKind.ArrayLiteralExpression) {
348
+ var effectsElements = effectsArgs
349
+ .elements;
350
+ var _a = __read(symbolName.match(/\[(.*)\]/), 2), effectsSymbol = _a[1];
351
+ var epos = void 0;
352
+ if (effectsElements.length === 0) {
353
+ epos = effectsArgs.getStart() + 1;
354
+ return [new change_1.InsertChange(ngModulePath, epos, effectsSymbol)];
355
+ }
356
+ else {
357
+ var lastEffect = effectsElements[effectsElements.length - 1];
358
+ epos = lastEffect.getEnd();
359
+ // Get the indentation of the last element, if any.
360
+ var text = lastEffect.getFullText(source);
361
+ var effectInsert = void 0;
362
+ if (text.match('^\r?\r?\n')) {
363
+ effectInsert = ",".concat(text.match(/^\r?\n\s+/)[0]).concat(effectsSymbol);
364
+ }
365
+ else {
366
+ effectInsert = ", ".concat(effectsSymbol);
367
+ }
368
+ return [new change_1.InsertChange(ngModulePath, epos, effectInsert)];
369
+ }
370
+ }
371
+ else {
372
+ return [];
373
+ }
374
+ }
375
+ }
376
+ var toInsert;
377
+ var position = node.getEnd();
378
+ if (node.kind == ts.SyntaxKind.ObjectLiteralExpression) {
379
+ // We haven't found the field in the metadata declaration. Insert a new
380
+ // field.
381
+ var expr = node;
382
+ if (expr.properties.length == 0) {
383
+ position = expr.getEnd() - 1;
384
+ toInsert = " ".concat(metadataField, ": [").concat(symbolName, "]\n");
385
+ }
386
+ else {
387
+ node = expr.properties[expr.properties.length - 1];
388
+ position = node.getEnd();
389
+ // Get the indentation of the last element, if any.
390
+ var text = node.getFullText(source);
391
+ if (text.match('^\r?\r?\n')) {
392
+ toInsert = ",".concat(text.match(/^\r?\n\s+/)[0]).concat(metadataField, ": [").concat(symbolName, "]");
393
+ }
394
+ else {
395
+ toInsert = ", ".concat(metadataField, ": [").concat(symbolName, "]");
396
+ }
397
+ }
398
+ }
399
+ else if (node.kind == ts.SyntaxKind.ArrayLiteralExpression) {
400
+ // We found the field but it's empty. Insert it just before the `]`.
401
+ position--;
402
+ toInsert = "".concat(symbolName);
403
+ }
404
+ else {
405
+ // Get the indentation of the last element, if any.
406
+ var text = node.getFullText(source);
407
+ if (text.match(/^\r?\n/)) {
408
+ toInsert = ",".concat(text.match(/^\r?\n(\r?)\s+/)[0]).concat(symbolName);
409
+ }
410
+ else {
411
+ toInsert = ", ".concat(symbolName);
412
+ }
413
+ }
414
+ var insert = new change_1.InsertChange(ngModulePath, position, toInsert);
415
+ var importInsert = insertImport(source, ngModulePath, symbolName.replace(/\..*$/, ''), importPath);
416
+ return [insert, importInsert];
417
+ }
418
+ function _addSymbolToComponentMetadata(source, componentPath, metadataField, symbolName, importPath) {
419
+ var nodes = getDecoratorMetadata(source, 'Component', '@angular/core');
420
+ var node = nodes[0]; // eslint-disable-line @typescript-eslint/no-explicit-any
421
+ // Find the decorator declaration.
422
+ if (!node) {
423
+ return [];
424
+ }
425
+ // Get all the children property assignment of object literals.
426
+ var matchingProperties = node.properties
427
+ .filter(function (prop) { return prop.kind == ts.SyntaxKind.PropertyAssignment; })
428
+ // Filter out every fields that's not "metadataField". Also handles string literals
429
+ // (but not expressions).
430
+ .filter(function (prop) {
431
+ var name = prop.name;
432
+ switch (name.kind) {
433
+ case ts.SyntaxKind.Identifier:
434
+ return name.getText(source) == metadataField;
435
+ case ts.SyntaxKind.StringLiteral:
436
+ return name.text == metadataField;
437
+ }
438
+ return false;
439
+ });
440
+ // Get the last node of the array literal.
441
+ if (!matchingProperties) {
442
+ return [];
443
+ }
444
+ if (matchingProperties.length == 0) {
445
+ // We haven't found the field in the metadata declaration. Insert a new field.
446
+ var expr = node;
447
+ var position_2;
448
+ var toInsert_2;
449
+ if (expr.properties.length == 0) {
450
+ position_2 = expr.getEnd() - 1;
451
+ toInsert_2 = " ".concat(metadataField, ": [").concat(symbolName, "]\n");
452
+ }
453
+ else {
454
+ node = expr.properties[expr.properties.length - 1];
455
+ position_2 = node.getEnd();
456
+ // Get the indentation of the last element, if any.
457
+ var text = node.getFullText(source);
458
+ var matches = text.match(/^\r?\n\s*/);
459
+ if (matches.length > 0) {
460
+ toInsert_2 = ",".concat(matches[0]).concat(metadataField, ": [").concat(symbolName, "]");
461
+ }
462
+ else {
463
+ toInsert_2 = ", ".concat(metadataField, ": [").concat(symbolName, "]");
464
+ }
465
+ }
466
+ var newMetadataProperty = new change_1.InsertChange(componentPath, position_2, toInsert_2);
467
+ var newMetadataImport = insertImport(source, componentPath, symbolName.replace(/\..*$/, ''), importPath);
468
+ return [newMetadataProperty, newMetadataImport];
469
+ }
470
+ var assignment = matchingProperties[0];
471
+ // If it's not an array, nothing we can do really.
472
+ if (assignment.initializer.kind !== ts.SyntaxKind.ArrayLiteralExpression) {
473
+ return [];
474
+ }
475
+ var arrLiteral = assignment.initializer;
476
+ if (arrLiteral.elements.length == 0) {
477
+ // Forward the property.
478
+ node = arrLiteral;
479
+ }
480
+ else {
481
+ node = arrLiteral.elements;
482
+ }
483
+ if (!node) {
484
+ console.log('No component found. Please add your new class to your component.');
485
+ return [];
486
+ }
487
+ if (Array.isArray(node)) {
488
+ var nodeArray = node;
489
+ var symbolsArray = nodeArray.map(function (node) { return node.getText(); });
490
+ if (symbolsArray.includes(symbolName)) {
491
+ return [];
492
+ }
493
+ node = node[node.length - 1];
494
+ }
495
+ var toInsert;
496
+ var position = node.getEnd();
497
+ if (node.kind == ts.SyntaxKind.ObjectLiteralExpression) {
498
+ // We haven't found the field in the metadata declaration. Insert a new
499
+ // field.
500
+ var expr = node;
501
+ if (expr.properties.length == 0) {
502
+ position = expr.getEnd() - 1;
503
+ toInsert = " ".concat(metadataField, ": [").concat(symbolName, "]\n");
504
+ }
505
+ else {
506
+ node = expr.properties[expr.properties.length - 1];
507
+ position = node.getEnd();
508
+ // Get the indentation of the last element, if any.
509
+ var text = node.getFullText(source);
510
+ if (text.match('^\r?\r?\n')) {
511
+ toInsert = ",".concat(text.match(/^\r?\n\s+/)[0]).concat(metadataField, ": [").concat(symbolName, "]");
512
+ }
513
+ else {
514
+ toInsert = ", ".concat(metadataField, ": [").concat(symbolName, "]");
515
+ }
516
+ }
517
+ }
518
+ else if (node.kind == ts.SyntaxKind.ArrayLiteralExpression) {
519
+ // We found the field but it's empty. Insert it just before the `]`.
520
+ position--;
521
+ toInsert = "".concat(symbolName);
522
+ }
523
+ else {
524
+ // Get the indentation of the last element, if any.
525
+ var text = node.getFullText(source);
526
+ if (text.match(/^\r?\n/)) {
527
+ toInsert = ",".concat(text.match(/^\r?\n(\r?)\s+/)[0]).concat(symbolName);
528
+ }
529
+ else {
530
+ toInsert = ", ".concat(symbolName);
531
+ }
532
+ }
533
+ var insert = new change_1.InsertChange(componentPath, position, toInsert);
534
+ var importInsert = insertImport(source, componentPath, symbolName.replace(/\..*$/, ''), importPath);
535
+ return [insert, importInsert];
536
+ }
537
+ /**
538
+ * Custom function to insert a declaration (component, pipe, directive)
539
+ * into NgModule declarations. It also imports the component.
540
+ */
541
+ function addDeclarationToModule(source, modulePath, classifiedName, importPath) {
542
+ return _addSymbolToNgModuleMetadata(source, modulePath, 'declarations', classifiedName, importPath);
543
+ }
544
+ exports.addDeclarationToModule = addDeclarationToModule;
545
+ /**
546
+ * Custom function to insert a declaration (component, pipe, directive)
547
+ * into NgModule declarations. It also imports the component.
548
+ */
549
+ function addImportToModule(source, modulePath, classifiedName, importPath) {
550
+ return _addSymbolToNgModuleMetadata(source, modulePath, 'imports', classifiedName, importPath);
551
+ }
552
+ exports.addImportToModule = addImportToModule;
553
+ /**
554
+ * Custom function to insert a provider into NgModule. It also imports it.
555
+ */
556
+ function addProviderToModule(source, modulePath, classifiedName, importPath) {
557
+ return _addSymbolToNgModuleMetadata(source, modulePath, 'providers', classifiedName, importPath);
558
+ }
559
+ exports.addProviderToModule = addProviderToModule;
560
+ /**
561
+ * Custom function to insert a provider into Component. It also imports it.
562
+ */
563
+ function addProviderToComponent(source, componentPath, classifiedName, importPath) {
564
+ return _addSymbolToComponentMetadata(source, componentPath, 'providers', classifiedName, importPath);
565
+ }
566
+ exports.addProviderToComponent = addProviderToComponent;
567
+ /**
568
+ * Custom function to insert an export into NgModule. It also imports it.
569
+ */
570
+ function addExportToModule(source, modulePath, classifiedName, importPath) {
571
+ return _addSymbolToNgModuleMetadata(source, modulePath, 'exports', classifiedName, importPath);
572
+ }
573
+ exports.addExportToModule = addExportToModule;
574
+ /**
575
+ * Custom function to insert an export into NgModule. It also imports it.
576
+ */
577
+ function addBootstrapToModule(source, modulePath, classifiedName, importPath) {
578
+ return _addSymbolToNgModuleMetadata(source, modulePath, 'bootstrap', classifiedName, importPath);
579
+ }
580
+ exports.addBootstrapToModule = addBootstrapToModule;
581
+ /**
582
+ * Add Import `import { symbolName } from fileName` if the import doesn't exit
583
+ * already. Assumes fileToEdit can be resolved and accessed.
584
+ * @param fileToEdit (file we want to add import to)
585
+ * @param symbolName (item to import)
586
+ * @param fileName (path to the file)
587
+ * @param isDefault (if true, import follows style for importing default exports)
588
+ * @return Change
589
+ */
590
+ function insertImport(source, fileToEdit, symbolName, fileName, isDefault) {
591
+ if (isDefault === void 0) { isDefault = false; }
592
+ var rootNode = source;
593
+ var allImports = findNodes(rootNode, ts.SyntaxKind.ImportDeclaration);
594
+ // get nodes that map to import statements from the file fileName
595
+ var relevantImports = allImports.filter(function (node) {
596
+ // StringLiteral of the ImportDeclaration is the import file (fileName in this case).
597
+ var importFiles = node
598
+ .getChildren()
599
+ .filter(function (child) { return child.kind === ts.SyntaxKind.StringLiteral; })
600
+ .map(function (n) { return n.text; });
601
+ return importFiles.filter(function (file) { return file === fileName; }).length === 1;
602
+ });
603
+ if (relevantImports.length > 0) {
604
+ var importsAsterisk_1 = false;
605
+ // imports from import file
606
+ var imports_1 = [];
607
+ relevantImports.forEach(function (n) {
608
+ Array.prototype.push.apply(imports_1, findNodes(n, ts.SyntaxKind.Identifier));
609
+ if (findNodes(n, ts.SyntaxKind.AsteriskToken).length > 0) {
610
+ importsAsterisk_1 = true;
611
+ }
612
+ });
613
+ // if imports * from fileName, don't add symbolName
614
+ if (importsAsterisk_1) {
615
+ return new change_1.NoopChange();
616
+ }
617
+ var importTextNodes = imports_1.filter(function (n) { return n.text === symbolName; });
618
+ // insert import if it's not there
619
+ if (importTextNodes.length === 0) {
620
+ var fallbackPos_1 = findNodes(relevantImports[0], ts.SyntaxKind.CloseBraceToken)[0].getStart() ||
621
+ findNodes(relevantImports[0], ts.SyntaxKind.FromKeyword)[0].getStart();
622
+ return insertAfterLastOccurrence(imports_1, ", ".concat(symbolName), fileToEdit, fallbackPos_1);
623
+ }
624
+ return new change_1.NoopChange();
625
+ }
626
+ // no such import declaration exists
627
+ var useStrict = findNodes(rootNode, ts.SyntaxKind.StringLiteral).filter(function (n) { return n.getText() === 'use strict'; });
628
+ var fallbackPos = 0;
629
+ if (useStrict.length > 0) {
630
+ fallbackPos = useStrict[0].end;
631
+ }
632
+ var open = isDefault ? '' : '{ ';
633
+ var close = isDefault ? '' : ' }';
634
+ // if there are no imports or 'use strict' statement, insert import at beginning of file
635
+ var insertAtBeginning = allImports.length === 0 && useStrict.length === 0;
636
+ var separator = insertAtBeginning ? '' : ';\n';
637
+ var toInsert = "".concat(separator, "import ").concat(open).concat(symbolName).concat(close) +
638
+ " from '".concat(fileName, "'").concat(insertAtBeginning ? ';\n' : '');
639
+ return insertAfterLastOccurrence(allImports, toInsert, fileToEdit, fallbackPos, ts.SyntaxKind.StringLiteral);
640
+ }
641
+ exports.insertImport = insertImport;
642
+ function replaceImport(sourceFile, path, importFrom, importAsIs, importToBe) {
643
+ var imports = sourceFile.statements
644
+ .filter(ts.isImportDeclaration)
645
+ .filter(function (_a) {
646
+ var moduleSpecifier = _a.moduleSpecifier;
647
+ return moduleSpecifier.getText(sourceFile) === "'".concat(importFrom, "'") ||
648
+ moduleSpecifier.getText(sourceFile) === "\"".concat(importFrom, "\"");
649
+ });
650
+ if (imports.length === 0) {
651
+ return [];
652
+ }
653
+ var importText = function (specifier) {
654
+ if (specifier.name.text) {
655
+ return specifier.name.text;
656
+ }
657
+ // if import is renamed
658
+ if (specifier.propertyName && specifier.propertyName.text) {
659
+ return specifier.propertyName.text;
660
+ }
661
+ return '';
662
+ };
663
+ var changes = imports.map(function (p) {
664
+ var _a;
665
+ var namedImports = (_a = p === null || p === void 0 ? void 0 : p.importClause) === null || _a === void 0 ? void 0 : _a.namedBindings;
666
+ if (!namedImports) {
667
+ return [];
668
+ }
669
+ var importSpecifiers = namedImports.elements;
670
+ var isAlreadyImported = importSpecifiers
671
+ .map(importText)
672
+ .includes(importToBe);
673
+ var importChanges = importSpecifiers.map(function (specifier, index) {
674
+ var text = importText(specifier);
675
+ // import is not the one we're looking for, can be skipped
676
+ if (text !== importAsIs) {
677
+ return undefined;
678
+ }
679
+ // identifier has not been imported, simply replace the old text with the new text
680
+ if (!isAlreadyImported) {
681
+ return (0, change_1.createReplaceChange)(sourceFile, specifier, importAsIs, importToBe);
682
+ }
683
+ var nextIdentifier = importSpecifiers[index + 1];
684
+ // identifer is not the last, also clean up the comma
685
+ if (nextIdentifier) {
686
+ return (0, change_1.createRemoveChange)(sourceFile, specifier, specifier.getStart(sourceFile), nextIdentifier.getStart(sourceFile));
687
+ }
688
+ // there are no imports following, just remove it
689
+ return (0, change_1.createRemoveChange)(sourceFile, specifier, specifier.getStart(sourceFile), specifier.getEnd());
690
+ });
691
+ return importChanges.filter(Boolean);
692
+ });
693
+ return changes.reduce(function (imports, curr) { return imports.concat(curr); }, []);
694
+ }
695
+ exports.replaceImport = replaceImport;
696
+ function containsProperty(objectLiteral, propertyName) {
697
+ return (objectLiteral &&
698
+ objectLiteral.properties.some(function (prop) {
699
+ return ts.isPropertyAssignment(prop) &&
700
+ ts.isIdentifier(prop.name) &&
701
+ prop.name.text === propertyName;
702
+ }));
703
+ }
704
+ exports.containsProperty = containsProperty;
705
+ //# sourceMappingURL=ast-utils.js.map