@angular/core 19.1.0-next.4 → 19.1.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 (40) hide show
  1. package/LICENSE +1 -1
  2. package/fesm2022/core.mjs +85 -91
  3. package/fesm2022/core.mjs.map +1 -1
  4. package/fesm2022/primitives/event-dispatch.mjs +1 -24
  5. package/fesm2022/primitives/event-dispatch.mjs.map +1 -1
  6. package/fesm2022/primitives/signals.mjs +1 -1
  7. package/fesm2022/rxjs-interop.mjs +1 -1
  8. package/fesm2022/rxjs-interop.mjs.map +1 -1
  9. package/fesm2022/testing.mjs +4 -4
  10. package/index.d.ts +41 -36
  11. package/package.json +1 -1
  12. package/primitives/event-dispatch/index.d.ts +1 -1
  13. package/primitives/signals/index.d.ts +1 -1
  14. package/rxjs-interop/index.d.ts +1 -1
  15. package/schematics/bundles/apply_import_manager-5082ccea.js +732 -0
  16. package/schematics/bundles/{checker-884633eb.js → checker-aa999c96.js} +50 -25
  17. package/schematics/bundles/cleanup-unused-imports.js +295 -0
  18. package/schematics/bundles/{compiler_host-22f6513d.js → compiler_host-f0b570c8.js} +2 -2
  19. package/schematics/bundles/control-flow-migration.js +3 -3
  20. package/schematics/bundles/explicit-standalone-flag.js +5 -5
  21. package/schematics/bundles/{imports-abe29092.js → imports-31a38653.js} +1 -1
  22. package/schematics/bundles/index-02a11f43.js +30 -0
  23. package/schematics/bundles/{combine_units-4a95b1b9.js → index-15b61bae.js} +10 -723
  24. package/schematics/bundles/inject-migration.js +6 -6
  25. package/schematics/bundles/{leading_space-d190b83b.js → leading_space-6e7a8ec6.js} +1 -1
  26. package/schematics/bundles/{migrate_ts_type_references-4b11f3f2.js → migrate_ts_type_references-042ca765.js} +30 -29
  27. package/schematics/bundles/{nodes-a9f0b985.js → nodes-88c2157f.js} +2 -2
  28. package/schematics/bundles/output-migration.js +27 -26
  29. package/schematics/bundles/pending-tasks.js +5 -5
  30. package/schematics/bundles/{program-094352ba.js → program-393ca8f3.js} +106 -46
  31. package/schematics/bundles/{project_tsconfig_paths-e9ccccbf.js → project_tsconfig_paths-6c9cde78.js} +1 -1
  32. package/schematics/bundles/provide-initializer.js +5 -5
  33. package/schematics/bundles/route-lazy-loading.js +4 -4
  34. package/schematics/bundles/signal-input-migration.js +33 -32
  35. package/schematics/bundles/signal-queries-migration.js +56 -49
  36. package/schematics/bundles/signals.js +8 -7
  37. package/schematics/bundles/standalone-migration.js +12 -28
  38. package/schematics/collection.json +5 -0
  39. package/schematics/ng-generate/cleanup-unused-imports/schema.json +7 -0
  40. package/testing/index.d.ts +1 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v19.1.0-next.4
3
+ * @license Angular v19.1.0
4
4
  * (c) 2010-2024 Google LLC. https://angular.io/
5
5
  * License: MIT
6
6
  */
@@ -4285,7 +4285,7 @@ class TypeofExpression extends AST {
4285
4285
  this.expression = expression;
4286
4286
  }
4287
4287
  visit(visitor, context = null) {
4288
- return visitor.visitTypeofExpresion(this, context);
4288
+ return visitor.visitTypeofExpression(this, context);
4289
4289
  }
4290
4290
  }
4291
4291
  class NonNullAssert extends AST {
@@ -4445,7 +4445,7 @@ class RecursiveAstVisitor {
4445
4445
  visitPrefixNot(ast, context) {
4446
4446
  this.visit(ast.expression, context);
4447
4447
  }
4448
- visitTypeofExpresion(ast, context) {
4448
+ visitTypeofExpression(ast, context) {
4449
4449
  this.visit(ast.expression, context);
4450
4450
  }
4451
4451
  visitNonNullAssert(ast, context) {
@@ -7350,7 +7350,7 @@ class ShadowCss {
7350
7350
  *
7351
7351
  * For example, we convert this css:
7352
7352
  *
7353
- * ```
7353
+ * ```scss
7354
7354
  * .box {
7355
7355
  * animation: box-animation 1s forwards;
7356
7356
  * }
@@ -7364,7 +7364,7 @@ class ShadowCss {
7364
7364
  *
7365
7365
  * to this:
7366
7366
  *
7367
- * ```
7367
+ * ```scss
7368
7368
  * .box {
7369
7369
  * animation: scopeName_box-animation 1s forwards;
7370
7370
  * }
@@ -7393,7 +7393,7 @@ class ShadowCss {
7393
7393
  *
7394
7394
  * For example, it takes a rule such as:
7395
7395
  *
7396
- * ```
7396
+ * ```scss
7397
7397
  * @keyframes box-animation {
7398
7398
  * to {
7399
7399
  * background-color: green;
@@ -7403,7 +7403,7 @@ class ShadowCss {
7403
7403
  *
7404
7404
  * and returns:
7405
7405
  *
7406
- * ```
7406
+ * ```scss
7407
7407
  * @keyframes scopeName_box-animation {
7408
7408
  * to {
7409
7409
  * background-color: green;
@@ -17764,7 +17764,7 @@ class Parser {
17764
17764
  * parsing errors in case the given expression is invalid.
17765
17765
  *
17766
17766
  * For example,
17767
- * ```
17767
+ * ```html
17768
17768
  * <div *ngFor="let item of items">
17769
17769
  * ^ ^ absoluteValueOffset for `templateValue`
17770
17770
  * absoluteKeyOffset for `templateKey`
@@ -17775,7 +17775,7 @@ class Parser {
17775
17775
  * 3. ngForOf -> items
17776
17776
  *
17777
17777
  * This is apparent from the de-sugared template:
17778
- * ```
17778
+ * ```html
17779
17779
  * <ng-template ngFor let-item [ngForOf]="items">
17780
17780
  * ```
17781
17781
  *
@@ -18632,7 +18632,7 @@ class _ParseAST {
18632
18632
  * parsing errors in case the given expression is invalid.
18633
18633
  *
18634
18634
  * For example,
18635
- * ```
18635
+ * ```html
18636
18636
  * <div *ngFor="let item of items; index as i; trackBy: func">
18637
18637
  * ```
18638
18638
  * contains five bindings:
@@ -19023,7 +19023,7 @@ class SerializeExpressionVisitor {
19023
19023
  .map((e) => e.visit(this, context))
19024
19024
  .join(', ')})`;
19025
19025
  }
19026
- visitTypeofExpresion(ast, context) {
19026
+ visitTypeofExpression(ast, context) {
19027
19027
  return `typeof ${ast.expression.visit(this, context)}`;
19028
19028
  }
19029
19029
  visitASTWithSource(ast, context) {
@@ -26382,7 +26382,7 @@ class BindingParser {
26382
26382
  }
26383
26383
  /**
26384
26384
  * Parses the bindings in a microsyntax expression, e.g.
26385
- * ```
26385
+ * ```html
26386
26386
  * <tag *tplKey="let value1 = prop; let value2 = localVar">
26387
26387
  * ```
26388
26388
  *
@@ -26642,6 +26642,14 @@ class BindingParser {
26642
26642
  if (ast instanceof NonNullAssert) {
26643
26643
  return this._isAllowedAssignmentEvent(ast.expression);
26644
26644
  }
26645
+ if (ast instanceof Call &&
26646
+ ast.args.length === 1 &&
26647
+ ast.receiver instanceof PropertyRead &&
26648
+ ast.receiver.name === '$any' &&
26649
+ ast.receiver.receiver instanceof ImplicitReceiver &&
26650
+ !(ast.receiver.receiver instanceof ThisReceiver)) {
26651
+ return this._isAllowedAssignmentEvent(ast.args[0]);
26652
+ }
26645
26653
  if (ast instanceof PropertyRead || ast instanceof KeyedRead) {
26646
26654
  return true;
26647
26655
  }
@@ -26968,7 +26976,7 @@ function parseForLoopParameters(block, errors, bindingParser) {
26968
26976
  }
26969
26977
  continue;
26970
26978
  }
26971
- errors.push(new ParseError(param.sourceSpan, `Unrecognized @for loop paramater "${param.expression}"`));
26979
+ errors.push(new ParseError(param.sourceSpan, `Unrecognized @for loop parameter "${param.expression}"`));
26972
26980
  }
26973
26981
  return result;
26974
26982
  }
@@ -27115,7 +27123,7 @@ function parseConditionalBlockParameters(block, errors, bindingParser) {
27115
27123
  // For now conditionals can only have an `as` parameter.
27116
27124
  // We may want to rework this later if we add more.
27117
27125
  if (aliasMatch === null) {
27118
- errors.push(new ParseError(param.sourceSpan, `Unrecognized conditional paramater "${param.expression}"`));
27126
+ errors.push(new ParseError(param.sourceSpan, `Unrecognized conditional parameter "${param.expression}"`));
27119
27127
  }
27120
27128
  else if (block.name !== 'if') {
27121
27129
  errors.push(new ParseError(param.sourceSpan, '"as" expression is only allowed on the primary @if block'));
@@ -30410,7 +30418,7 @@ function publishFacade(global) {
30410
30418
  * @description
30411
30419
  * Entry point for all public APIs of the compiler package.
30412
30420
  */
30413
- new Version('19.1.0-next.4');
30421
+ new Version('19.1.0');
30414
30422
 
30415
30423
  const _I18N_ATTR = 'i18n';
30416
30424
  const _I18N_ATTR_PREFIX = 'i18n-';
@@ -31114,7 +31122,7 @@ exports.ErrorCode = void 0;
31114
31122
  * The left-hand side of an assignment expression was a template variable. Effectively, the
31115
31123
  * template looked like:
31116
31124
  *
31117
- * ```
31125
+ * ```html
31118
31126
  * <ng-template let-something>
31119
31127
  * <button (click)="something = ...">...</button>
31120
31128
  * </ng-template>
@@ -31818,7 +31826,7 @@ class NodeJSPathManipulation {
31818
31826
  // G3-ESM-MARKER: G3 uses CommonJS, but externally everything in ESM.
31819
31827
  // CommonJS/ESM interop for determining the current file name and containing dir.
31820
31828
  const isCommonJS = typeof __filename !== 'undefined';
31821
- const currentFileUrl = isCommonJS ? null : (typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT' && document.currentScript.src || new URL('checker-884633eb.js', document.baseURI).href));
31829
+ const currentFileUrl = isCommonJS ? null : (typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT' && document.currentScript.src || new URL('checker-aa999c96.js', document.baseURI).href));
31822
31830
  const currentFileName = isCommonJS ? __filename : url.fileURLToPath(currentFileUrl);
31823
31831
  /**
31824
31832
  * A wrapper around the Node.js file-system that supports readonly operations and path manipulation.
@@ -32917,9 +32925,16 @@ function classMemberAccessLevelToString(level) {
32917
32925
  class TypeScriptReflectionHost {
32918
32926
  checker;
32919
32927
  isLocalCompilation;
32920
- constructor(checker, isLocalCompilation = false) {
32928
+ skipPrivateValueDeclarationTypes;
32929
+ /**
32930
+ * @param skipPrivateValueDeclarationTypes Avoids using a value declaration that is considered private (using a ɵ-prefix),
32931
+ * instead using the first available declaration. This is needed for the {@link FormControl} API of
32932
+ * which the type declaration documents the type and the value declaration corresponds with an implementation detail.
32933
+ */
32934
+ constructor(checker, isLocalCompilation = false, skipPrivateValueDeclarationTypes = false) {
32921
32935
  this.checker = checker;
32922
32936
  this.isLocalCompilation = isLocalCompilation;
32937
+ this.skipPrivateValueDeclarationTypes = skipPrivateValueDeclarationTypes;
32923
32938
  }
32924
32939
  getDecoratorsOfDeclaration(declaration) {
32925
32940
  const decorators = ts__default["default"].canHaveDecorators(declaration)
@@ -33146,13 +33161,13 @@ class TypeScriptReflectionHost {
33146
33161
  *
33147
33162
  * For example, if the identifier is the `Directive` part of a qualified type chain like:
33148
33163
  *
33149
- * ```
33164
+ * ```ts
33150
33165
  * core.Directive
33151
33166
  * ```
33152
33167
  *
33153
33168
  * then it might be that `core` is a namespace import such as:
33154
33169
  *
33155
- * ```
33170
+ * ```ts
33156
33171
  * import * as core from 'tslib';
33157
33172
  * ```
33158
33173
  *
@@ -33218,9 +33233,10 @@ class TypeScriptReflectionHost {
33218
33233
  while (symbol.flags & ts__default["default"].SymbolFlags.Alias) {
33219
33234
  symbol = this.checker.getAliasedSymbol(symbol);
33220
33235
  }
33221
- // Look at the resolved Symbol's declarations and pick one of them to return. Value declarations
33222
- // are given precedence over type declarations.
33223
- if (symbol.valueDeclaration !== undefined) {
33236
+ // Look at the resolved Symbol's declarations and pick one of them to return.
33237
+ // Value declarations are given precedence over type declarations if not specified otherwise
33238
+ if (symbol.valueDeclaration !== undefined &&
33239
+ (!this.skipPrivateValueDeclarationTypes || !isPrivateSymbol(this.checker, symbol))) {
33224
33240
  return {
33225
33241
  node: symbol.valueDeclaration,
33226
33242
  viaModule: this._viaModule(symbol.valueDeclaration, originalId, importInfo),
@@ -33531,6 +33547,14 @@ function propertyNameToString(node) {
33531
33547
  return null;
33532
33548
  }
33533
33549
  }
33550
+ /** Determines whether a given symbol represents a private API (symbols with names that start with `ɵ`) */
33551
+ function isPrivateSymbol(typeChecker, symbol) {
33552
+ if (symbol.valueDeclaration !== undefined) {
33553
+ const symbolType = typeChecker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration);
33554
+ return symbolType?.symbol?.name.startsWith('ɵ') === true;
33555
+ }
33556
+ return false;
33557
+ }
33534
33558
  /**
33535
33559
  * Compute the left most identifier in a qualified type chain. E.g. the `a` of `a.b.c.SomeType`.
33536
33560
  * @param qualifiedName The starting property access expression from which we want to compute
@@ -41051,7 +41075,7 @@ class AstTranslator {
41051
41075
  addParseSpanInfo(node, ast.sourceSpan);
41052
41076
  return node;
41053
41077
  }
41054
- visitTypeofExpresion(ast) {
41078
+ visitTypeofExpression(ast) {
41055
41079
  const expression = wrapForDiagnostics(this.translate(ast.expression));
41056
41080
  const node = ts__default["default"].factory.createTypeOfExpression(expression);
41057
41081
  addParseSpanInfo(node, ast.sourceSpan);
@@ -41265,7 +41289,7 @@ class VeSafeLhsInferenceBugDetector {
41265
41289
  visitPrefixNot(ast) {
41266
41290
  return ast.expression.visit(this);
41267
41291
  }
41268
- visitTypeofExpresion(ast) {
41292
+ visitTypeofExpression(ast) {
41269
41293
  return ast.expression.visit(this);
41270
41294
  }
41271
41295
  visitNonNullAssert(ast) {
@@ -45961,6 +45985,7 @@ exports.IcuPlaceholder = IcuPlaceholder;
45961
45985
  exports.Identifiers = Identifiers;
45962
45986
  exports.ImplicitReceiver = ImplicitReceiver;
45963
45987
  exports.ImportManager = ImportManager;
45988
+ exports.InstantiateExpr = InstantiateExpr;
45964
45989
  exports.Interpolation = Interpolation$1;
45965
45990
  exports.InterpolationConfig = InterpolationConfig;
45966
45991
  exports.InvokeFunctionExpr = InvokeFunctionExpr;
@@ -0,0 +1,295 @@
1
+ 'use strict';
2
+ /**
3
+ * @license Angular v19.1.0
4
+ * (c) 2010-2024 Google LLC. https://angular.io/
5
+ * License: MIT
6
+ */
7
+ 'use strict';
8
+
9
+ Object.defineProperty(exports, '__esModule', { value: true });
10
+
11
+ var schematics = require('@angular-devkit/schematics');
12
+ var project_tsconfig_paths = require('./project_tsconfig_paths-6c9cde78.js');
13
+ var apply_import_manager = require('./apply_import_manager-5082ccea.js');
14
+ require('os');
15
+ var ts = require('typescript');
16
+ var checker = require('./checker-aa999c96.js');
17
+ var program = require('./program-393ca8f3.js');
18
+ require('path');
19
+ require('./index-02a11f43.js');
20
+ require('@angular-devkit/core');
21
+ require('node:path/posix');
22
+ require('fs');
23
+ require('module');
24
+ require('url');
25
+
26
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
27
+
28
+ var ts__default = /*#__PURE__*/_interopDefaultLegacy(ts);
29
+
30
+ /** Migration that cleans up unused imports from a project. */
31
+ class UnusedImportsMigration extends apply_import_manager.TsurgeFunnelMigration {
32
+ printer = ts__default["default"].createPrinter();
33
+ createProgram(tsconfigAbsPath, fs) {
34
+ return super.createProgram(tsconfigAbsPath, fs, {
35
+ extendedDiagnostics: {
36
+ checks: {
37
+ // Ensure that the diagnostic is enabled.
38
+ unusedStandaloneImports: program.DiagnosticCategoryLabel.Warning,
39
+ },
40
+ },
41
+ });
42
+ }
43
+ async analyze(info) {
44
+ const nodePositions = new Map();
45
+ const replacements = [];
46
+ let removedImports = 0;
47
+ let changedFiles = 0;
48
+ info.ngCompiler?.getDiagnostics().forEach((diag) => {
49
+ if (diag.file !== undefined &&
50
+ diag.start !== undefined &&
51
+ diag.length !== undefined &&
52
+ diag.code === checker.ngErrorCode(checker.ErrorCode.UNUSED_STANDALONE_IMPORTS)) {
53
+ if (!nodePositions.has(diag.file)) {
54
+ nodePositions.set(diag.file, new Set());
55
+ }
56
+ nodePositions.get(diag.file).add(this.getNodeKey(diag.start, diag.length));
57
+ }
58
+ });
59
+ nodePositions.forEach((locations, sourceFile) => {
60
+ const resolvedLocations = this.resolveRemovalLocations(sourceFile, locations);
61
+ const usageAnalysis = this.analyzeUsages(sourceFile, resolvedLocations);
62
+ if (resolvedLocations.allRemovedIdentifiers.size > 0) {
63
+ removedImports += resolvedLocations.allRemovedIdentifiers.size;
64
+ changedFiles++;
65
+ }
66
+ this.generateReplacements(sourceFile, resolvedLocations, usageAnalysis, info, replacements);
67
+ });
68
+ return apply_import_manager.confirmAsSerializable({ replacements, removedImports, changedFiles });
69
+ }
70
+ async migrate(globalData) {
71
+ return apply_import_manager.confirmAsSerializable(globalData);
72
+ }
73
+ async combine(unitA, unitB) {
74
+ return apply_import_manager.confirmAsSerializable({
75
+ replacements: [...unitA.replacements, ...unitB.replacements],
76
+ removedImports: unitA.removedImports + unitB.removedImports,
77
+ changedFiles: unitA.changedFiles + unitB.changedFiles,
78
+ });
79
+ }
80
+ async globalMeta(combinedData) {
81
+ return apply_import_manager.confirmAsSerializable(combinedData);
82
+ }
83
+ async stats(globalMetadata) {
84
+ return {
85
+ counters: {
86
+ removedImports: globalMetadata.removedImports,
87
+ changedFiles: globalMetadata.changedFiles,
88
+ },
89
+ };
90
+ }
91
+ /** Gets a key that can be used to look up a node based on its location. */
92
+ getNodeKey(start, length) {
93
+ return `${start}/${length}`;
94
+ }
95
+ /**
96
+ * Resolves a set of node locations to the actual AST nodes that need to be migrated.
97
+ * @param sourceFile File in which to resolve the locations.
98
+ * @param locations Location keys that should be resolved.
99
+ */
100
+ resolveRemovalLocations(sourceFile, locations) {
101
+ const result = {
102
+ fullRemovals: new Set(),
103
+ partialRemovals: new Map(),
104
+ allRemovedIdentifiers: new Set(),
105
+ };
106
+ const walk = (node) => {
107
+ if (!ts__default["default"].isIdentifier(node)) {
108
+ node.forEachChild(walk);
109
+ return;
110
+ }
111
+ // The TS typings don't reflect that the parent can be undefined.
112
+ const parent = node.parent;
113
+ if (!parent) {
114
+ return;
115
+ }
116
+ if (locations.has(this.getNodeKey(node.getStart(), node.getWidth()))) {
117
+ // When the entire array needs to be cleared, the diagnostic is
118
+ // reported on the property assignment, rather than an array element.
119
+ if (ts__default["default"].isPropertyAssignment(parent) &&
120
+ parent.name === node &&
121
+ ts__default["default"].isArrayLiteralExpression(parent.initializer)) {
122
+ result.fullRemovals.add(parent.initializer);
123
+ parent.initializer.elements.forEach((element) => {
124
+ if (ts__default["default"].isIdentifier(element)) {
125
+ result.allRemovedIdentifiers.add(element.text);
126
+ }
127
+ });
128
+ }
129
+ else if (ts__default["default"].isArrayLiteralExpression(parent)) {
130
+ if (!result.partialRemovals.has(parent)) {
131
+ result.partialRemovals.set(parent, new Set());
132
+ }
133
+ result.partialRemovals.get(parent).add(node);
134
+ result.allRemovedIdentifiers.add(node.text);
135
+ }
136
+ }
137
+ };
138
+ walk(sourceFile);
139
+ return result;
140
+ }
141
+ /**
142
+ * Analyzes how identifiers are used across a file.
143
+ * @param sourceFile File to be analyzed.
144
+ * @param locations Locations that will be changed as a part of this migration.
145
+ */
146
+ analyzeUsages(sourceFile, locations) {
147
+ const { partialRemovals, fullRemovals } = locations;
148
+ const result = {
149
+ importedSymbols: new Map(),
150
+ identifierCounts: new Map(),
151
+ };
152
+ const walk = (node) => {
153
+ if (ts__default["default"].isIdentifier(node) &&
154
+ node.parent &&
155
+ // Don't track individual identifiers marked for removal.
156
+ (!ts__default["default"].isArrayLiteralExpression(node.parent) ||
157
+ !partialRemovals.has(node.parent) ||
158
+ !partialRemovals.get(node.parent).has(node))) {
159
+ result.identifierCounts.set(node.text, (result.identifierCounts.get(node.text) ?? 0) + 1);
160
+ }
161
+ // Don't track identifiers in array literals that are about to be removed.
162
+ if (ts__default["default"].isArrayLiteralExpression(node) && fullRemovals.has(node)) {
163
+ return;
164
+ }
165
+ if (ts__default["default"].isImportDeclaration(node)) {
166
+ const namedBindings = node.importClause?.namedBindings;
167
+ const moduleName = ts__default["default"].isStringLiteral(node.moduleSpecifier)
168
+ ? node.moduleSpecifier.text
169
+ : null;
170
+ if (namedBindings && ts__default["default"].isNamedImports(namedBindings) && moduleName !== null) {
171
+ namedBindings.elements.forEach((imp) => {
172
+ if (!result.importedSymbols.has(moduleName)) {
173
+ result.importedSymbols.set(moduleName, new Map());
174
+ }
175
+ const symbolName = (imp.propertyName || imp.name).text;
176
+ const localName = imp.name.text;
177
+ result.importedSymbols.get(moduleName).set(localName, symbolName);
178
+ });
179
+ }
180
+ // Don't track identifiers in imports.
181
+ return;
182
+ }
183
+ // Track identifiers in all other node kinds.
184
+ node.forEachChild(walk);
185
+ };
186
+ walk(sourceFile);
187
+ return result;
188
+ }
189
+ /**
190
+ * Generates text replacements based on the data produced by the migration.
191
+ * @param sourceFile File being migrated.
192
+ * @param removalLocations Data about nodes being removed.
193
+ * @param usages Data about identifier usage.
194
+ * @param info Information about the current program.
195
+ * @param replacements Array tracking all text replacements.
196
+ */
197
+ generateReplacements(sourceFile, removalLocations, usages, info, replacements) {
198
+ const { fullRemovals, partialRemovals, allRemovedIdentifiers } = removalLocations;
199
+ const { importedSymbols, identifierCounts } = usages;
200
+ const importManager = new checker.ImportManager();
201
+ // Replace full arrays with empty ones. This allows preserves more of the user's formatting.
202
+ fullRemovals.forEach((node) => {
203
+ replacements.push(new apply_import_manager.Replacement(apply_import_manager.projectFile(sourceFile, info), new apply_import_manager.TextUpdate({
204
+ position: node.getStart(),
205
+ end: node.getEnd(),
206
+ toInsert: '[]',
207
+ })));
208
+ });
209
+ // Filter out the unused identifiers from an array.
210
+ partialRemovals.forEach((toRemove, node) => {
211
+ const newNode = ts__default["default"].factory.updateArrayLiteralExpression(node, node.elements.filter((el) => !toRemove.has(el)));
212
+ replacements.push(new apply_import_manager.Replacement(apply_import_manager.projectFile(sourceFile, info), new apply_import_manager.TextUpdate({
213
+ position: node.getStart(),
214
+ end: node.getEnd(),
215
+ toInsert: this.printer.printNode(ts__default["default"].EmitHint.Unspecified, newNode, sourceFile),
216
+ })));
217
+ });
218
+ // Attempt to clean up unused import declarations. Note that this isn't foolproof, because we
219
+ // do the matching based on identifier text, rather than going through the type checker which
220
+ // can be expensive. This should be enough for the vast majority of cases in this schematic
221
+ // since we're dealing exclusively with directive/pipe class names which tend to be very
222
+ // specific. In the worst case we may end up not removing an import declaration which would
223
+ // still be valid code that the user can clean up themselves.
224
+ importedSymbols.forEach((names, moduleName) => {
225
+ names.forEach((symbolName, localName) => {
226
+ // Note that in the `identifierCounts` lookup both zero and undefined
227
+ // are valid and mean that the identifiers isn't being used anymore.
228
+ if (allRemovedIdentifiers.has(localName) && !identifierCounts.get(localName)) {
229
+ importManager.removeImport(sourceFile, symbolName, moduleName);
230
+ }
231
+ });
232
+ });
233
+ apply_import_manager.applyImportManagerChanges(importManager, replacements, [sourceFile], info);
234
+ }
235
+ }
236
+
237
+ function migrate() {
238
+ return async (tree, context) => {
239
+ const { buildPaths, testPaths } = await project_tsconfig_paths.getProjectTsConfigPaths(tree);
240
+ if (!buildPaths.length && !testPaths.length) {
241
+ throw new schematics.SchematicsException('Could not find any tsconfig file. Cannot clean up unused imports.');
242
+ }
243
+ const fs = new apply_import_manager.DevkitMigrationFilesystem(tree);
244
+ checker.setFileSystem(fs);
245
+ const migration = new UnusedImportsMigration();
246
+ const unitResults = [];
247
+ const programInfos = [...buildPaths, ...testPaths].map((tsconfigPath) => {
248
+ context.logger.info(`Preparing analysis for ${tsconfigPath}`);
249
+ const baseInfo = migration.createProgram(tsconfigPath, fs);
250
+ const info = migration.prepareProgram(baseInfo);
251
+ return { info, tsconfigPath };
252
+ });
253
+ for (const { info, tsconfigPath } of programInfos) {
254
+ context.logger.info(`Scanning for unused imports using ${tsconfigPath}`);
255
+ unitResults.push(await migration.analyze(info));
256
+ }
257
+ const combined = await apply_import_manager.synchronouslyCombineUnitData(migration, unitResults);
258
+ if (combined === null) {
259
+ context.logger.error('Schematic failed unexpectedly with no analysis data');
260
+ return;
261
+ }
262
+ const globalMeta = await migration.globalMeta(combined);
263
+ const replacementsPerFile = new Map();
264
+ const { replacements } = await migration.migrate(globalMeta);
265
+ const changesPerFile = apply_import_manager.groupReplacementsByFile(replacements);
266
+ for (const [file, changes] of changesPerFile) {
267
+ if (!replacementsPerFile.has(file)) {
268
+ replacementsPerFile.set(file, changes);
269
+ }
270
+ }
271
+ for (const [file, changes] of replacementsPerFile) {
272
+ const recorder = tree.beginUpdate(file);
273
+ for (const c of changes) {
274
+ recorder
275
+ .remove(c.data.position, c.data.end - c.data.position)
276
+ .insertRight(c.data.position, c.data.toInsert);
277
+ }
278
+ tree.commitUpdate(recorder);
279
+ }
280
+ const { counters: { removedImports, changedFiles }, } = await migration.stats(globalMeta);
281
+ let statsMessage;
282
+ if (removedImports === 0) {
283
+ statsMessage = 'Schematic could not find unused imports in the project';
284
+ }
285
+ else {
286
+ statsMessage =
287
+ `Removed ${removedImports} import${removedImports !== 1 ? 's' : ''} ` +
288
+ `in ${changedFiles} file${changedFiles !== 1 ? 's' : ''}`;
289
+ }
290
+ context.logger.info('');
291
+ context.logger.info(statsMessage);
292
+ };
293
+ }
294
+
295
+ exports.migrate = migrate;
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v19.1.0-next.4
3
+ * @license Angular v19.1.0
4
4
  * (c) 2010-2024 Google LLC. https://angular.io/
5
5
  * License: MIT
6
6
  */
7
7
  'use strict';
8
8
 
9
9
  var ts = require('typescript');
10
- var checker = require('./checker-884633eb.js');
10
+ var checker = require('./checker-aa999c96.js');
11
11
  require('os');
12
12
  var p = require('path');
13
13
 
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v19.1.0-next.4
3
+ * @license Angular v19.1.0
4
4
  * (c) 2010-2024 Google LLC. https://angular.io/
5
5
  * License: MIT
6
6
  */
@@ -10,8 +10,8 @@ Object.defineProperty(exports, '__esModule', { value: true });
10
10
 
11
11
  var schematics = require('@angular-devkit/schematics');
12
12
  var p = require('path');
13
- var compiler_host = require('./compiler_host-22f6513d.js');
14
- var checker = require('./checker-884633eb.js');
13
+ var compiler_host = require('./compiler_host-f0b570c8.js');
14
+ var checker = require('./checker-aa999c96.js');
15
15
  var ts = require('typescript');
16
16
  require('os');
17
17
  require('fs');
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v19.1.0-next.4
3
+ * @license Angular v19.1.0
4
4
  * (c) 2010-2024 Google LLC. https://angular.io/
5
5
  * License: MIT
6
6
  */
@@ -10,12 +10,12 @@ Object.defineProperty(exports, '__esModule', { value: true });
10
10
 
11
11
  var schematics = require('@angular-devkit/schematics');
12
12
  var p = require('path');
13
- var project_tsconfig_paths = require('./project_tsconfig_paths-e9ccccbf.js');
14
- var compiler_host = require('./compiler_host-22f6513d.js');
13
+ var project_tsconfig_paths = require('./project_tsconfig_paths-6c9cde78.js');
14
+ var compiler_host = require('./compiler_host-f0b570c8.js');
15
15
  var ts = require('typescript');
16
- var imports = require('./imports-abe29092.js');
16
+ var imports = require('./imports-31a38653.js');
17
17
  require('@angular-devkit/core');
18
- require('./checker-884633eb.js');
18
+ require('./checker-aa999c96.js');
19
19
  require('os');
20
20
  require('fs');
21
21
  require('module');
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v19.1.0-next.4
3
+ * @license Angular v19.1.0
4
4
  * (c) 2010-2024 Google LLC. https://angular.io/
5
5
  * License: MIT
6
6
  */
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+ /**
3
+ * @license Angular v19.1.0
4
+ * (c) 2010-2024 Google LLC. https://angular.io/
5
+ * License: MIT
6
+ */
7
+ 'use strict';
8
+
9
+ require('os');
10
+ require('typescript');
11
+ var checker = require('./checker-aa999c96.js');
12
+ require('./program-393ca8f3.js');
13
+ require('path');
14
+
15
+ /**
16
+ * @module
17
+ * @description
18
+ * Entry point for all public APIs of the compiler-cli package.
19
+ */
20
+ new checker.Version('19.1.0');
21
+
22
+ var LogLevel;
23
+ (function (LogLevel) {
24
+ LogLevel[LogLevel["debug"] = 0] = "debug";
25
+ LogLevel[LogLevel["info"] = 1] = "info";
26
+ LogLevel[LogLevel["warn"] = 2] = "warn";
27
+ LogLevel[LogLevel["error"] = 3] = "error";
28
+ })(LogLevel || (LogLevel = {}));
29
+
30
+ checker.setFileSystem(new checker.NodeJSFileSystem());