avancement planning

This commit is contained in:
2026-05-26 11:58:39 +02:00
parent 619a2b240a
commit 150b97cd2e
4892 changed files with 99214 additions and 429382 deletions
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
@@ -8,12 +8,12 @@
require('@angular-devkit/core');
require('node:path/posix');
var project_paths = require('./project_paths-Dr30Du8j.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-CaweCOep.cjs');
var project_paths = require('./project_paths-Bq_k0pof.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-D2eb40pS.cjs');
var ts = require('typescript');
require('os');
var apply_import_manager = require('./apply_import_manager-CPOYeJ7t.cjs');
require('./index-BXjkzENj.cjs');
var apply_import_manager = require('./apply_import_manager-Clb1Y0Nb.cjs');
require('./index-kR-YjYku.cjs');
require('path');
require('node:path');
require('@angular-devkit/schematics');
@@ -1,67 +0,0 @@
'use strict';
/**
* @license Angular v20.3.11
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
'use strict';
var ts = require('typescript');
require('os');
var project_tsconfig_paths = require('./project_tsconfig_paths-CaweCOep.cjs');
var project_paths = require('./project_paths-Dr30Du8j.cjs');
/**
* Applies import manager changes, and writes them as replacements the
* given result array.
*/
function applyImportManagerChanges(importManager, replacements, sourceFiles, info) {
const { newImports, updatedImports, deletedImports } = importManager.finalize();
const printer = ts.createPrinter({});
const pathToFile = new Map(sourceFiles.map((s) => [s.fileName, s]));
// Capture new imports
newImports.forEach((newImports, fileName) => {
newImports.forEach((newImport) => {
const printedImport = printer.printNode(ts.EmitHint.Unspecified, newImport, pathToFile.get(fileName));
replacements.push(new project_paths.Replacement(project_paths.projectFile(project_tsconfig_paths.absoluteFrom(fileName), info), new project_paths.TextUpdate({ position: 0, end: 0, toInsert: `${printedImport}\n` })));
});
});
// Capture updated imports
for (const [oldBindings, newBindings] of updatedImports.entries()) {
// The import will be generated as multi-line if it already is multi-line,
// or if the number of elements significantly increased and it previously
// consisted of very few specifiers.
const isMultiline = oldBindings.getText().includes('\n') ||
(newBindings.elements.length >= 6 && oldBindings.elements.length <= 3);
const hasSpaceBetweenBraces = oldBindings.getText().startsWith('{ ');
let formatFlags = ts.ListFormat.NamedImportsOrExportsElements |
ts.ListFormat.Indented |
ts.ListFormat.Braces |
ts.ListFormat.PreserveLines |
(isMultiline ? ts.ListFormat.MultiLine : ts.ListFormat.SingleLine);
if (hasSpaceBetweenBraces) {
formatFlags |= ts.ListFormat.SpaceBetweenBraces;
}
else {
formatFlags &= ~ts.ListFormat.SpaceBetweenBraces;
}
const printedBindings = printer.printList(formatFlags, newBindings.elements, oldBindings.getSourceFile());
replacements.push(new project_paths.Replacement(project_paths.projectFile(oldBindings.getSourceFile(), info), new project_paths.TextUpdate({
position: oldBindings.getStart(),
end: oldBindings.getEnd(),
// TS uses four spaces as indent. We migrate to two spaces as we
// assume this to be more common.
toInsert: printedBindings.replace(/^ {4}/gm, ' '),
})));
}
// Update removed imports
for (const removedImport of deletedImports) {
replacements.push(new project_paths.Replacement(project_paths.projectFile(removedImport.getSourceFile(), info), new project_paths.TextUpdate({
position: removedImport.getStart(),
end: removedImport.getEnd(),
toInsert: '',
})));
}
}
exports.applyImportManagerChanges = applyImportManagerChanges;
+5 -5
View File
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
@@ -8,14 +8,14 @@
require('@angular-devkit/core');
require('node:path/posix');
var project_paths = require('./project_paths-Dr30Du8j.cjs');
var project_paths = require('./project_paths-Bq_k0pof.cjs');
var ts = require('typescript');
require('os');
var project_tsconfig_paths = require('./project_tsconfig_paths-CaweCOep.cjs');
var index = require('./index-BXjkzENj.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-D2eb40pS.cjs');
var index = require('./index-kR-YjYku.cjs');
require('path');
require('node:path');
var apply_import_manager = require('./apply_import_manager-CPOYeJ7t.cjs');
var apply_import_manager = require('./apply_import_manager-Clb1Y0Nb.cjs');
require('@angular-devkit/schematics');
require('fs');
require('module');
@@ -1,319 +0,0 @@
'use strict';
/**
* @license Angular v20.3.11
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
'use strict';
var ts = require('typescript');
var project_tsconfig_paths = require('./project_tsconfig_paths-CaweCOep.cjs');
require('os');
var p = require('path');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var p__namespace = /*#__PURE__*/_interopNamespaceDefault(p);
/** Tracks changes that have to be made for specific files. */
class ChangeTracker {
_printer;
_importRemapper;
_changes = new Map();
_importManager;
_quotesCache = new WeakMap();
constructor(_printer, _importRemapper) {
this._printer = _printer;
this._importRemapper = _importRemapper;
this._importManager = new project_tsconfig_paths.ImportManager({
shouldUseSingleQuotes: (file) => this._getQuoteKind(file) === 0 /* QuoteKind.SINGLE */,
});
}
/**
* Tracks the insertion of some text.
* @param sourceFile File in which the text is being inserted.
* @param start Index at which the text is insert.
* @param text Text to be inserted.
*/
insertText(sourceFile, index, text) {
this._trackChange(sourceFile, { start: index, text });
}
/**
* Replaces text within a file.
* @param sourceFile File in which to replace the text.
* @param start Index from which to replace the text.
* @param removeLength Length of the text being replaced.
* @param text Text to be inserted instead of the old one.
*/
replaceText(sourceFile, start, removeLength, text) {
this._trackChange(sourceFile, { start, removeLength, text });
}
/**
* Replaces the text of an AST node with a new one.
* @param oldNode Node to be replaced.
* @param newNode New node to be inserted.
* @param emitHint Hint when formatting the text of the new node.
* @param sourceFileWhenPrinting File to use when printing out the new node. This is important
* when copying nodes from one file to another, because TypeScript might not output literal nodes
* without it.
*/
replaceNode(oldNode, newNode, emitHint = ts.EmitHint.Unspecified, sourceFileWhenPrinting) {
const sourceFile = oldNode.getSourceFile();
this.replaceText(sourceFile, oldNode.getStart(), oldNode.getWidth(), this._printer.printNode(emitHint, newNode, sourceFileWhenPrinting || sourceFile));
}
/**
* Removes the text of an AST node from a file.
* @param node Node whose text should be removed.
* @param useFullOffsets Whether to remove the node using its full offset (e.g. `getFullStart`
* rather than `fullStart`). This has the advantage of removing any comments that may be tied
* to the node, but can lead to too much code being deleted.
*/
removeNode(node, useFullOffsets = false) {
this._trackChange(node.getSourceFile(), {
start: useFullOffsets ? node.getFullStart() : node.getStart(),
removeLength: useFullOffsets ? node.getFullWidth() : node.getWidth(),
text: '',
});
}
/**
* Adds an import to a file.
* @param sourceFile File to which to add the import.
* @param symbolName Symbol being imported.
* @param moduleName Module from which the symbol is imported.
* @param alias Alias to use for the import.
*/
addImport(sourceFile, symbolName, moduleName, alias) {
if (this._importRemapper) {
moduleName = this._importRemapper(moduleName, sourceFile.fileName);
}
// It's common for paths to be manipulated with Node's `path` utilties which
// can yield a path with back slashes. Normalize them since outputting such
// paths will also cause TS to escape the forward slashes.
moduleName = normalizePath(moduleName);
if (!this._changes.has(sourceFile)) {
this._changes.set(sourceFile, []);
}
return this._importManager.addImport({
requestedFile: sourceFile,
exportSymbolName: symbolName,
exportModuleSpecifier: moduleName,
unsafeAliasOverride: alias,
});
}
/**
* Removes an import from a file.
* @param sourceFile File from which to remove the import.
* @param symbolName Original name of the symbol to be removed. Used even if the import is aliased.
* @param moduleName Module from which the symbol is imported.
*/
removeImport(sourceFile, symbolName, moduleName) {
// It's common for paths to be manipulated with Node's `path` utilties which
// can yield a path with back slashes. Normalize them since outputting such
// paths will also cause TS to escape the forward slashes.
moduleName = normalizePath(moduleName);
if (!this._changes.has(sourceFile)) {
this._changes.set(sourceFile, []);
}
this._importManager.removeImport(sourceFile, symbolName, moduleName);
}
/**
* Gets the changes that should be applied to all the files in the migration.
* The changes are sorted in the order in which they should be applied.
*/
recordChanges() {
this._recordImports();
return this._changes;
}
/**
* Clear the tracked changes
*/
clearChanges() {
this._changes.clear();
}
/**
* Adds a change to a `ChangesByFile` map.
* @param file File that the change is associated with.
* @param change Change to be added.
*/
_trackChange(file, change) {
const changes = this._changes.get(file);
if (changes) {
// Insert the changes in reverse so that they're applied in reverse order.
// This ensures that the offsets of subsequent changes aren't affected by
// previous changes changing the file's text.
const insertIndex = changes.findIndex((current) => current.start <= change.start);
if (insertIndex === -1) {
changes.push(change);
}
else {
changes.splice(insertIndex, 0, change);
}
}
else {
this._changes.set(file, [change]);
}
}
/** Determines what kind of quotes to use for a specific file. */
_getQuoteKind(sourceFile) {
if (this._quotesCache.has(sourceFile)) {
return this._quotesCache.get(sourceFile);
}
let kind = 0 /* QuoteKind.SINGLE */;
for (const statement of sourceFile.statements) {
if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
kind = statement.moduleSpecifier.getText()[0] === '"' ? 1 /* QuoteKind.DOUBLE */ : 0 /* QuoteKind.SINGLE */;
this._quotesCache.set(sourceFile, kind);
break;
}
}
return kind;
}
/** Records the pending import changes from the import manager. */
_recordImports() {
const { newImports, updatedImports, deletedImports } = this._importManager.finalize();
for (const [original, replacement] of updatedImports) {
this.replaceNode(original, replacement);
}
for (const node of deletedImports) {
this.removeNode(node);
}
for (const [sourceFile] of this._changes) {
const importsToAdd = newImports.get(sourceFile.fileName);
if (!importsToAdd) {
continue;
}
const importLines = [];
let lastImport = null;
for (const statement of sourceFile.statements) {
if (ts.isImportDeclaration(statement)) {
lastImport = statement;
}
}
for (const decl of importsToAdd) {
importLines.push(this._printer.printNode(ts.EmitHint.Unspecified, decl, sourceFile));
}
this.insertText(sourceFile, lastImport ? lastImport.getEnd() : 0, (lastImport ? '\n' : '') + importLines.join('\n'));
}
}
}
/** Normalizes a path to use posix separators. */
function normalizePath(path) {
return path.replace(/\\/g, '/');
}
function parseTsconfigFile(tsconfigPath, basePath) {
const { config } = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
const parseConfigHost = {
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
fileExists: ts.sys.fileExists,
readDirectory: ts.sys.readDirectory,
readFile: ts.sys.readFile,
};
// Throw if incorrect arguments are passed to this function. Passing relative base paths
// results in root directories not being resolved and in later type checking runtime errors.
// More details can be found here: https://github.com/microsoft/TypeScript/issues/37731.
if (!p__namespace.isAbsolute(basePath)) {
throw Error('Unexpected relative base path has been specified.');
}
return ts.parseJsonConfigFileContent(config, parseConfigHost, basePath, {});
}
/**
* Creates a TypeScript program instance for a TypeScript project within
* the virtual file system tree.
* @param tree Virtual file system tree that contains the source files.
* @param tsconfigPath Virtual file system path that resolves to the TypeScript project.
* @param basePath Base path for the virtual file system tree.
* @param fakeFileRead Optional file reader function. Can be used to overwrite files in
* the TypeScript program, or to add in-memory files (e.g. to add global types).
* @param additionalFiles Additional file paths that should be added to the program.
*/
function createMigrationProgram(tree, tsconfigPath, basePath, fakeFileRead, additionalFiles) {
const { rootNames, options, host } = createProgramOptions(tree, tsconfigPath, basePath, fakeFileRead);
return ts.createProgram(rootNames, options, host);
}
/**
* Creates the options necessary to instantiate a TypeScript program.
* @param tree Virtual file system tree that contains the source files.
* @param tsconfigPath Virtual file system path that resolves to the TypeScript project.
* @param basePath Base path for the virtual file system tree.
* @param fakeFileRead Optional file reader function. Can be used to overwrite files in
* the TypeScript program, or to add in-memory files (e.g. to add global types).
* @param additionalFiles Additional file paths that should be added to the program.
* @param optionOverrides Overrides of the parsed compiler options.
*/
function createProgramOptions(tree, tsconfigPath, basePath, fakeFileRead, additionalFiles, optionOverrides) {
// Resolve the tsconfig path to an absolute path. This is needed as TypeScript otherwise
// is not able to resolve root directories in the given tsconfig. More details can be found
// in the following issue: https://github.com/microsoft/TypeScript/issues/37731.
tsconfigPath = p.resolve(basePath, tsconfigPath);
const parsed = parseTsconfigFile(tsconfigPath, p.dirname(tsconfigPath));
const options = optionOverrides ? { ...parsed.options, ...optionOverrides } : parsed.options;
const host = createMigrationCompilerHost(tree, options, basePath, fakeFileRead);
return { rootNames: parsed.fileNames.concat([]), options, host };
}
function createMigrationCompilerHost(tree, options, basePath, fakeRead) {
const host = ts.createCompilerHost(options, true);
const defaultReadFile = host.readFile;
// We need to overwrite the host "readFile" method, as we want the TypeScript
// program to be based on the file contents in the virtual file tree. Otherwise
// if we run multiple migrations we might have intersecting changes and
// source files.
host.readFile = (fileName) => {
const treeRelativePath = p.relative(basePath, fileName);
let result = fakeRead?.(treeRelativePath);
if (typeof result !== 'string') {
// If the relative path resolved to somewhere outside of the tree, fall back to
// TypeScript's default file reading function since the `tree` will throw an error.
result = treeRelativePath.startsWith('..')
? defaultReadFile.call(host, fileName)
: tree.read(treeRelativePath)?.toString();
}
// Strip BOM as otherwise TSC methods (Ex: getWidth) will return an offset,
// which breaks the CLI UpdateRecorder.
// See: https://github.com/angular/angular/pull/30719
return typeof result === 'string' ? result.replace(/^\uFEFF/, '') : undefined;
};
return host;
}
/**
* Checks whether a file can be migrate by our automated migrations.
* @param basePath Absolute path to the project.
* @param sourceFile File being checked.
* @param program Program that includes the source file.
*/
function canMigrateFile(basePath, sourceFile, program) {
// We shouldn't migrate .d.ts files, files from an external library or type checking files.
if (sourceFile.fileName.endsWith('.ngtypecheck.ts') ||
sourceFile.isDeclarationFile ||
program.isSourceFileFromExternalLibrary(sourceFile)) {
return false;
}
// Our migrations are set up to create a `Program` from the project's tsconfig and to migrate all
// the files within the program. This can include files that are outside of the Angular CLI
// project. We can't migrate files outside of the project, because our file system interactions
// go through the CLI's `Tree` which assumes that all files are within the project. See:
// https://github.com/angular/angular-cli/blob/0b0961c9c233a825b6e4bb59ab7f0790f9b14676/packages/angular_devkit/schematics/src/tree/host-tree.ts#L131
return !p.relative(basePath, sourceFile.fileName).startsWith('..');
}
exports.ChangeTracker = ChangeTracker;
exports.canMigrateFile = canMigrateFile;
exports.createMigrationProgram = createMigrationProgram;
exports.createProgramOptions = createProgramOptions;
exports.normalizePath = normalizePath;
+3 -3
View File
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
@@ -8,8 +8,8 @@
var schematics = require('@angular-devkit/schematics');
var path = require('node:path');
var compiler_host = require('./compiler_host-BGZcziuy.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-CaweCOep.cjs');
var compiler_host = require('./compiler_host-AFZotBLM.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-D2eb40pS.cjs');
var ts = require('typescript');
var p = require('path');
require('os');
+5 -5
View File
@@ -1,19 +1,19 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
'use strict';
var project_tsconfig_paths = require('./project_tsconfig_paths-CaweCOep.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-D2eb40pS.cjs');
require('typescript');
require('os');
var apply_import_manager = require('./apply_import_manager-CPOYeJ7t.cjs');
require('./index-BXjkzENj.cjs');
var apply_import_manager = require('./apply_import_manager-Clb1Y0Nb.cjs');
require('./index-kR-YjYku.cjs');
require('path');
require('node:path');
var project_paths = require('./project_paths-Dr30Du8j.cjs');
var project_paths = require('./project_paths-Bq_k0pof.cjs');
var imports = require('./imports-CIX-JgAN.cjs');
require('@angular-devkit/core');
require('node:path/posix');
+1 -1
View File
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
@@ -8,12 +8,12 @@
var ts = require('typescript');
require('os');
var project_tsconfig_paths = require('./project_tsconfig_paths-CaweCOep.cjs');
require('./index-BXjkzENj.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-D2eb40pS.cjs');
require('./index-kR-YjYku.cjs');
require('path');
require('node:path');
var project_paths = require('./project_paths-Dr30Du8j.cjs');
var apply_import_manager = require('./apply_import_manager-CPOYeJ7t.cjs');
var project_paths = require('./project_paths-Bq_k0pof.cjs');
var apply_import_manager = require('./apply_import_manager-Clb1Y0Nb.cjs');
var imports = require('./imports-CIX-JgAN.cjs');
require('@angular-devkit/core');
require('node:path/posix');
+3 -3
View File
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
@@ -8,13 +8,13 @@
var schematics = require('@angular-devkit/schematics');
var p = require('path');
var compiler_host = require('./compiler_host-BGZcziuy.cjs');
var compiler_host = require('./compiler_host-AFZotBLM.cjs');
var ts = require('typescript');
var ng_decorators = require('./ng_decorators-B5HCqr20.cjs');
var imports = require('./imports-CIX-JgAN.cjs');
var nodes = require('./nodes-B16H9JUd.cjs');
var leading_space = require('./leading_space-D9nQ8UQC.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-CaweCOep.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-D2eb40pS.cjs');
require('os');
require('fs');
require('module');
+1 -1
View File
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
+1 -1
View File
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
+6 -6
View File
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
@@ -8,13 +8,13 @@
var ts = require('typescript');
require('os');
var project_tsconfig_paths = require('./project_tsconfig_paths-CaweCOep.cjs');
var index$1 = require('./index-BXjkzENj.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-D2eb40pS.cjs');
var index$1 = require('./index-kR-YjYku.cjs');
require('path');
require('node:path');
var project_paths = require('./project_paths-Dr30Du8j.cjs');
var apply_import_manager = require('./apply_import_manager-CPOYeJ7t.cjs');
var index = require('./index-BmMfRg5d.cjs');
var project_paths = require('./project_paths-Bq_k0pof.cjs');
var apply_import_manager = require('./apply_import_manager-Clb1Y0Nb.cjs');
var index = require('./index-CD4aCRVu.cjs');
require('@angular-devkit/core');
require('node:path/posix');
require('fs');
@@ -1,819 +0,0 @@
'use strict';
/**
* @license Angular v20.3.11
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
'use strict';
var index = require('./index-BXjkzENj.cjs');
var schematics = require('@angular-devkit/schematics');
var core = require('@angular-devkit/core');
var posixPath = require('node:path/posix');
var os = require('os');
var ts = require('typescript');
var project_tsconfig_paths = require('./project_tsconfig_paths-CaweCOep.cjs');
require('path');
var path = require('node:path');
function _interopNamespaceDefault(e) {
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n.default = e;
return Object.freeze(n);
}
var posixPath__namespace = /*#__PURE__*/_interopNamespaceDefault(posixPath);
var os__namespace = /*#__PURE__*/_interopNamespaceDefault(os);
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
/// <reference types="node" />
class NgtscCompilerHost {
fs;
options;
constructor(fs, options = {}) {
this.fs = fs;
this.options = options;
}
getSourceFile(fileName, languageVersion) {
const text = this.readFile(fileName);
return text !== undefined
? ts.createSourceFile(fileName, text, languageVersion, true)
: undefined;
}
getDefaultLibFileName(options) {
return this.fs.join(this.getDefaultLibLocation(), ts.getDefaultLibFileName(options));
}
getDefaultLibLocation() {
return this.fs.getDefaultLibLocation();
}
writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles) {
const path = project_tsconfig_paths.absoluteFrom(fileName);
this.fs.ensureDir(this.fs.dirname(path));
this.fs.writeFile(path, data);
}
getCurrentDirectory() {
return this.fs.pwd();
}
getCanonicalFileName(fileName) {
return this.useCaseSensitiveFileNames() ? fileName : fileName.toLowerCase();
}
useCaseSensitiveFileNames() {
return this.fs.isCaseSensitive();
}
getNewLine() {
switch (this.options.newLine) {
case ts.NewLineKind.CarriageReturnLineFeed:
return '\r\n';
case ts.NewLineKind.LineFeed:
return '\n';
default:
return os__namespace.EOL;
}
}
fileExists(fileName) {
const absPath = this.fs.resolve(fileName);
return this.fs.exists(absPath) && this.fs.stat(absPath).isFile();
}
readFile(fileName) {
const absPath = this.fs.resolve(fileName);
if (!this.fileExists(absPath)) {
return undefined;
}
return this.fs.readFile(absPath);
}
realpath(path) {
return this.fs.realpath(this.fs.resolve(path));
}
}
// We use TypeScript's native `ts.matchFiles` utility for the virtual file systems
// and their TypeScript compiler host `readDirectory` implementation. TypeScript's
// function implements complex logic for matching files with respect to root
// directory, extensions, excludes, includes etc. The function is currently
// internal but we can use it as the API most likely will not change any time soon,
// nor does it seem like this is being made public any time soon.
// Related issue for tracking: https://github.com/microsoft/TypeScript/issues/13793.
/**
* Creates a {@link ts.CompilerHost#readDirectory} implementation function,
* that leverages the specified file system (that may be e.g. virtual).
*/
function createFileSystemTsReadDirectoryFn(fs) {
if (ts.matchFiles === undefined) {
throw Error('Unable to read directory in configured file system. This means that ' +
'TypeScript changed its file matching internals.\n\nPlease consider downgrading your ' +
'TypeScript version, and report an issue in the Angular framework repository.');
}
const matchFilesFn = ts.matchFiles.bind(ts);
return (rootDir, extensions, excludes, includes, depth) => {
const directoryExists = (p) => {
const resolvedPath = fs.resolve(p);
return fs.exists(resolvedPath) && fs.stat(resolvedPath).isDirectory();
};
return matchFilesFn(rootDir, extensions, excludes, includes, fs.isCaseSensitive(), fs.pwd(), depth, (p) => {
const resolvedPath = fs.resolve(p);
// TS also gracefully returns an empty file set.
if (!directoryExists(resolvedPath)) {
return { directories: [], files: [] };
}
const children = fs.readdir(resolvedPath);
const files = [];
const directories = [];
for (const child of children) {
if (fs.stat(fs.join(resolvedPath, child))?.isDirectory()) {
directories.push(child);
}
else {
files.push(child);
}
}
return { files, directories };
}, (p) => fs.resolve(p), (p) => directoryExists(p));
};
}
function calcProjectFileAndBasePath(project, host = project_tsconfig_paths.getFileSystem()) {
const absProject = host.resolve(project);
const projectIsDir = host.lstat(absProject).isDirectory();
const projectFile = projectIsDir ? host.join(absProject, 'tsconfig.json') : absProject;
const projectDir = projectIsDir ? absProject : host.dirname(absProject);
const basePath = host.resolve(projectDir);
return { projectFile, basePath };
}
function readConfiguration(project, existingOptions, host = project_tsconfig_paths.getFileSystem()) {
try {
const fs = project_tsconfig_paths.getFileSystem();
const readConfigFile = (configFile) => ts.readConfigFile(configFile, (file) => host.readFile(host.resolve(file)));
const readAngularCompilerOptions = (configFile, parentOptions = {}) => {
const { config, error } = readConfigFile(configFile);
if (error) {
// Errors are handled later on by 'parseJsonConfigFileContent'
return parentOptions;
}
// Note: In Google, `angularCompilerOptions` are stored in `bazelOptions`.
// This function typically doesn't run for actual Angular compilations, but
// tooling like Tsurge, or schematics may leverage this helper, so we account
// for this here.
const angularCompilerOptions = config.angularCompilerOptions ?? config.bazelOptions?.angularCompilerOptions;
// we are only interested into merging 'angularCompilerOptions' as
// other options like 'compilerOptions' are merged by TS
let existingNgCompilerOptions = { ...angularCompilerOptions, ...parentOptions };
if (!config.extends) {
return existingNgCompilerOptions;
}
const extendsPaths = typeof config.extends === 'string' ? [config.extends] : config.extends;
// Call readAngularCompilerOptions recursively to merge NG Compiler options
// Reverse the array so the overrides happen from right to left.
return [...extendsPaths].reverse().reduce((prevOptions, extendsPath) => {
const extendedConfigPath = getExtendedConfigPath(configFile, extendsPath, host, fs);
return extendedConfigPath === null
? prevOptions
: readAngularCompilerOptions(extendedConfigPath, prevOptions);
}, existingNgCompilerOptions);
};
const { projectFile, basePath } = calcProjectFileAndBasePath(project, host);
const configFileName = host.resolve(host.pwd(), projectFile);
const { config, error } = readConfigFile(projectFile);
if (error) {
return {
project,
errors: [error],
rootNames: [],
options: {},
emitFlags: index.EmitFlags.Default,
};
}
const existingCompilerOptions = {
genDir: basePath,
basePath,
...readAngularCompilerOptions(configFileName),
...existingOptions,
};
const parseConfigHost = createParseConfigHost(host, fs);
const { options, errors, fileNames: rootNames, projectReferences, } = ts.parseJsonConfigFileContent(config, parseConfigHost, basePath, existingCompilerOptions, configFileName);
let emitFlags = index.EmitFlags.Default;
if (!(options['skipMetadataEmit'] || options['flatModuleOutFile'])) {
emitFlags |= index.EmitFlags.Metadata;
}
if (options['skipTemplateCodegen']) {
emitFlags = emitFlags & ~index.EmitFlags.Codegen;
}
return { project: projectFile, rootNames, projectReferences, options, errors, emitFlags };
}
catch (e) {
const errors = [
{
category: ts.DiagnosticCategory.Error,
messageText: e.stack ?? e.message,
file: undefined,
start: undefined,
length: undefined,
source: 'angular',
code: index.UNKNOWN_ERROR_CODE,
},
];
return { project: '', errors, rootNames: [], options: {}, emitFlags: index.EmitFlags.Default };
}
}
function createParseConfigHost(host, fs = project_tsconfig_paths.getFileSystem()) {
return {
fileExists: host.exists.bind(host),
readDirectory: createFileSystemTsReadDirectoryFn(fs),
readFile: host.readFile.bind(host),
useCaseSensitiveFileNames: fs.isCaseSensitive(),
};
}
function getExtendedConfigPath(configFile, extendsValue, host, fs) {
const result = getExtendedConfigPathWorker(configFile, extendsValue, host, fs);
if (result !== null) {
return result;
}
// Try to resolve the paths with a json extension append a json extension to the file in case if
// it is missing and the resolution failed. This is to replicate TypeScript behaviour, see:
// https://github.com/microsoft/TypeScript/blob/294a5a7d784a5a95a8048ee990400979a6bc3a1c/src/compiler/commandLineParser.ts#L2806
return getExtendedConfigPathWorker(configFile, `${extendsValue}.json`, host, fs);
}
function getExtendedConfigPathWorker(configFile, extendsValue, host, fs) {
if (extendsValue.startsWith('.') || fs.isRooted(extendsValue)) {
const extendedConfigPath = host.resolve(host.dirname(configFile), extendsValue);
if (host.exists(extendedConfigPath)) {
return extendedConfigPath;
}
}
else {
const parseConfigHost = createParseConfigHost(host, fs);
// Path isn't a rooted or relative path, resolve like a module.
const { resolvedModule } = ts.nodeModuleNameResolver(extendsValue, configFile, { moduleResolution: ts.ModuleResolutionKind.Node10, resolveJsonModule: true }, parseConfigHost);
if (resolvedModule) {
return project_tsconfig_paths.absoluteFrom(resolvedModule.resolvedFileName);
}
}
return null;
}
/**
* Angular compiler file system implementation that leverages an
* CLI schematic virtual file tree.
*/
class DevkitMigrationFilesystem {
tree;
constructor(tree) {
this.tree = tree;
}
extname(path) {
return core.extname(path);
}
isRoot(path) {
return path === core.normalize('/');
}
isRooted(path) {
return this.normalize(path).startsWith('/');
}
dirname(file) {
return this.normalize(core.dirname(file));
}
join(basePath, ...paths) {
return this.normalize(core.join(basePath, ...paths));
}
relative(from, to) {
return this.normalize(core.relative(from, to));
}
basename(filePath, extension) {
return posixPath__namespace.basename(filePath, extension);
}
normalize(path) {
return core.normalize(path);
}
resolve(...paths) {
const normalizedPaths = paths.map((p) => core.normalize(p));
// In dev-kit, the NodeJS working directory should never be
// considered, so `/` is the last resort over `cwd`.
return this.normalize(posixPath__namespace.resolve(core.normalize('/'), ...normalizedPaths));
}
pwd() {
return '/';
}
isCaseSensitive() {
return true;
}
exists(path) {
return statPath(this.tree, path) !== null;
}
readFile(path) {
return this.tree.readText(path);
}
readFileBuffer(path) {
const buffer = this.tree.read(path);
if (buffer === null) {
throw new Error(`File does not exist: ${path}`);
}
return buffer;
}
readdir(path) {
const dir = this.tree.getDir(path);
return [
...dir.subdirs,
...dir.subfiles,
];
}
lstat(path) {
const stat = statPath(this.tree, path);
if (stat === null) {
throw new Error(`File does not exist for "lstat": ${path}`);
}
return stat;
}
stat(path) {
const stat = statPath(this.tree, path);
if (stat === null) {
throw new Error(`File does not exist for "stat": ${path}`);
}
return stat;
}
realpath(filePath) {
return filePath;
}
getDefaultLibLocation() {
return 'node_modules/typescript/lib';
}
ensureDir(path) {
// Migrations should compute replacements and not write directly.
throw new Error('DevkitFilesystem#ensureDir is not supported.');
}
writeFile(path, data) {
// Migrations should compute replacements and not write directly.
throw new Error('DevkitFilesystem#writeFile is not supported.');
}
removeFile(path) {
// Migrations should compute replacements and not write directly.
throw new Error('DevkitFilesystem#removeFile is not supported.');
}
copyFile(from, to) {
// Migrations should compute replacements and not write directly.
throw new Error('DevkitFilesystem#copyFile is not supported.');
}
moveFile(from, to) {
// Migrations should compute replacements and not write directly.
throw new Error('DevkitFilesystem#moveFile is not supported.');
}
removeDeep(path) {
// Migrations should compute replacements and not write directly.
throw new Error('DevkitFilesystem#removeDeep is not supported.');
}
chdir(_path) {
throw new Error('FileSystem#chdir is not supported.');
}
symlink() {
throw new Error('FileSystem#symlink is not supported.');
}
}
/** Stats the given path in the virtual tree. */
function statPath(tree, path) {
let fileInfo = null;
let dirInfo = null;
try {
fileInfo = tree.get(path);
}
catch (e) {
if (e.constructor.name === 'PathIsDirectoryException') {
dirInfo = tree.getDir(path);
}
else {
throw e;
}
}
if (fileInfo !== null || dirInfo !== null) {
return {
isDirectory: () => dirInfo !== null,
isFile: () => fileInfo !== null,
isSymbolicLink: () => false,
};
}
return null;
}
/**
* Groups the given replacements per project relative
* file path.
*
* This allows for simple execution of the replacements
* against a given file. E.g. via {@link applyTextUpdates}.
*/
function groupReplacementsByFile(replacements) {
const result = new Map();
for (const { projectFile, update } of replacements) {
if (!result.has(projectFile.rootRelativePath)) {
result.set(projectFile.rootRelativePath, []);
}
result.get(projectFile.rootRelativePath).push(update);
}
return result;
}
/**
* Synchronously combines unit data for the given migration.
*
* Note: This helper is useful for testing and execution of
* Tsurge migrations in non-batchable environments. In general,
* prefer parallel execution of combining via e.g. Beam combiners.
*/
async function synchronouslyCombineUnitData(migration, unitDatas) {
if (unitDatas.length === 0) {
return null;
}
if (unitDatas.length === 1) {
return unitDatas[0];
}
let combined = unitDatas[0];
for (let i = 1; i < unitDatas.length; i++) {
const other = unitDatas[i];
combined = await migration.combine(combined, other);
}
return combined;
}
/** Whether we are executing inside Google */
function isGoogle3() {
return process.env['GOOGLE3_TSURGE'] === '1';
}
/**
* By default, Tsurge will always create an Angular compiler program
* for projects analyzed and migrated. This works perfectly fine in
* third-party where Tsurge migrations run in Angular CLI projects.
*
* In first party, when running against full Google3, creating an Angular
* program for e.g. plain `ts_library` targets is overly expensive and
* can result in out of memory issues for large TS targets. In 1P we can
* reliably distinguish between TS and Angular targets via the `angularCompilerOptions`.
*/
function google3UsePlainTsProgramIfNoKnownAngularOption() {
return process.env['GOOGLE3_TSURGE'] === '1';
}
/** Options that are good defaults for Tsurge migrations. */
const defaultMigrationTsOptions = {
// Avoid checking libraries to speed up migrations.
skipLibCheck: true,
skipDefaultLibCheck: true,
noEmit: true,
// Does not apply to g3 and externally is enforced when the app is built by the compiler.
disableTypeScriptVersionCheck: true,
};
/**
* Creates an instance of a TypeScript program for the given project.
*/
function createPlainTsProgram(tsHost, tsconfig, optionOverrides) {
const program = ts.createProgram({
rootNames: tsconfig.rootNames,
options: {
...tsconfig.options,
...defaultMigrationTsOptions,
...optionOverrides,
},
});
return {
ngCompiler: null,
program,
userOptions: tsconfig.options,
__programAbsoluteRootFileNames: tsconfig.rootNames,
host: tsHost,
};
}
/**
* Parses the configuration of the given TypeScript project and creates
* an instance of the Angular compiler for the project.
*/
function createNgtscProgram(tsHost, tsconfig, optionOverrides) {
const ngtscProgram = new index.NgtscProgram(tsconfig.rootNames, {
...tsconfig.options,
...defaultMigrationTsOptions,
...optionOverrides,
}, tsHost);
// Expose an easy way to debug-print ng semantic diagnostics.
if (process.env['DEBUG_NG_SEMANTIC_DIAGNOSTICS'] === '1') {
console.error(ts.formatDiagnosticsWithColorAndContext(ngtscProgram.getNgSemanticDiagnostics(), tsHost));
}
return {
ngCompiler: ngtscProgram.compiler,
program: ngtscProgram.getTsProgram(),
userOptions: tsconfig.options,
__programAbsoluteRootFileNames: tsconfig.rootNames,
host: tsHost,
};
}
/** Code of the error raised by TypeScript when a tsconfig doesn't match any files. */
const NO_INPUTS_ERROR_CODE = 18003;
/** Parses the given tsconfig file, supporting Angular compiler options. */
function parseTsconfigOrDie(absoluteTsconfigPath, fs) {
const tsconfig = readConfiguration(absoluteTsconfigPath, {}, fs);
// Skip the "No inputs found..." error since we don't want to interrupt the migration if a
// tsconfig doesn't match a file. This will result in an empty `Program` which is still valid.
const errors = tsconfig.errors.filter((diag) => diag.code !== NO_INPUTS_ERROR_CODE);
if (errors.length) {
throw new Error(`Tsconfig could not be parsed or is invalid:\n\n` + `${errors.map((e) => e.messageText)}`);
}
return tsconfig;
}
// Note: Try to keep mostly in sync with
// //depot/google3/javascript/angular2/tools/ngc_wrapped/tsc_plugin.ts
// TODO: Consider moving this logic into the 1P launcher.
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
function fileNameToModuleNameFactory(rootDirs, workspaceName) {
return (importedFilePath) => {
let relativePath = '';
for (const rootDir of rootDirs) {
const rel = path__namespace.posix.relative(rootDir, importedFilePath);
if (!rel.startsWith('.')) {
relativePath = rel;
break;
}
}
if (relativePath) {
return `${workspaceName}/${relativePath.replace(EXT, '')}`;
}
else {
return importedFilePath.replace(EXT, '');
}
};
}
/** Creates the base program info for the given tsconfig path. */
function createBaseProgramInfo(absoluteTsconfigPath, fs, optionOverrides = {}) {
// Make sure the FS becomes globally available. Some code paths
// of the Angular compiler, or tsconfig parsing aren't leveraging
// the specified file system.
project_tsconfig_paths.setFileSystem(fs);
const tsconfig = parseTsconfigOrDie(absoluteTsconfigPath, fs);
const tsHost = new NgtscCompilerHost(fs, tsconfig.options);
// When enabled, use a plain TS program if we are sure it's not
// an Angular project based on the `tsconfig.json`.
if (google3UsePlainTsProgramIfNoKnownAngularOption() &&
tsconfig.options['_useHostForImportGeneration'] === undefined) {
return createPlainTsProgram(tsHost, tsconfig, optionOverrides);
}
// The Angular program may try to emit references during analysis or migration.
// To replicate the Google3 import emission here, ensure the unified module resolution
// can be enabled by the compiler.
if (isGoogle3() && tsconfig.options.rootDirs) {
tsHost.fileNameToModuleName = fileNameToModuleNameFactory(tsconfig.options.rootDirs,
/* workspaceName*/ 'google3');
}
return createNgtscProgram(tsHost, tsconfig, optionOverrides);
}
/**
* Creates the {@link ProgramInfo} from the given base information.
*
* This function purely exists to support custom programs that are
* intended to be injected into Tsurge migrations. e.g. for language
* service refactorings.
*/
function getProgramInfoFromBaseInfo(baseInfo) {
const fullProgramSourceFiles = [...baseInfo.program.getSourceFiles()];
const sourceFiles = fullProgramSourceFiles.filter((f) => !f.isDeclarationFile &&
// Note `isShim` will work for the initial program, but for TCB programs, the shims are no longer annotated.
!project_tsconfig_paths.isShim(f) &&
!f.fileName.endsWith('.ngtypecheck.ts'));
// Sort it by length in reverse order (longest first). This speeds up lookups,
// since there's no need to keep going through the array once a match is found.
const sortedRootDirs = project_tsconfig_paths.getRootDirs(baseInfo.host, baseInfo.userOptions).sort((a, b) => b.length - a.length);
// TODO: Consider also following TS's logic here, finding the common source root.
// See: Program#getCommonSourceDirectory.
const primaryRoot = project_tsconfig_paths.absoluteFrom(baseInfo.userOptions.rootDir ?? sortedRootDirs.at(-1) ?? baseInfo.program.getCurrentDirectory());
return {
...baseInfo,
sourceFiles,
fullProgramSourceFiles,
sortedRootDirs,
projectRoot: primaryRoot,
};
}
/**
* @private
*
* Base class for the possible Tsurge migration variants.
*
* For example, this class exposes methods to conveniently create
* TypeScript programs, while also allowing migration authors to override.
*/
class TsurgeBaseMigration {
/**
* Creates the TypeScript program for a given compilation unit.
*
* By default:
* - In 3P: Ngtsc programs are being created.
* - In 1P: Ngtsc or TS programs are created based on the Blaze target.
*/
createProgram(tsconfigAbsPath, fs, optionsOverride) {
return getProgramInfoFromBaseInfo(createBaseProgramInfo(tsconfigAbsPath, fs, optionsOverride));
}
}
/**
* A simpler variant of a {@link TsurgeComplexMigration} that does not
* fan-out into multiple workers per compilation unit to compute
* the final migration replacements.
*
* This is faster and less resource intensive as workers and TS programs
* are only ever created once.
*
* This is commonly the case when migrations are refactored to eagerly
* compute replacements in the analyze stage, and then leverage the
* global unit data to filter replacements that turned out to be "invalid".
*/
class TsurgeFunnelMigration extends TsurgeBaseMigration {
}
/**
* Complex variant of a `Tsurge` migration.
*
* For example, every analyze worker may contribute to a list of TS
* references that are later combined. The migrate phase can then compute actual
* file updates for all individual compilation units, leveraging the global metadata
* to e.g. see if there are any references from other compilation units that may be
* problematic and prevent migration of a given file.
*/
class TsurgeComplexMigration extends TsurgeBaseMigration {
}
/*!
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
exports.MigrationStage = void 0;
(function (MigrationStage) {
/** The migration is analyzing an entrypoint */
MigrationStage[MigrationStage["Analysis"] = 0] = "Analysis";
/** The migration is about to migrate an entrypoint */
MigrationStage[MigrationStage["Migrate"] = 1] = "Migrate";
})(exports.MigrationStage || (exports.MigrationStage = {}));
/** Runs a Tsurge within an Angular Devkit context. */
async function runMigrationInDevkit(config) {
const { buildPaths, testPaths } = await project_tsconfig_paths.getProjectTsConfigPaths(config.tree);
if (!buildPaths.length && !testPaths.length) {
throw new schematics.SchematicsException('Could not find any tsconfig file. Cannot run the migration.');
}
const tsconfigPaths = [...buildPaths, ...testPaths];
const fs = new DevkitMigrationFilesystem(config.tree);
project_tsconfig_paths.setFileSystem(fs);
const migration = config.getMigration(fs);
const unitResults = [];
const isFunnelMigration = migration instanceof TsurgeFunnelMigration;
const compilationUnitAssignments = new Map();
for (const tsconfigPath of tsconfigPaths) {
config.beforeProgramCreation?.(tsconfigPath, exports.MigrationStage.Analysis);
const info = migration.createProgram(tsconfigPath, fs);
modifyProgramInfoToEnsureNonOverlappingFiles(tsconfigPath, info, compilationUnitAssignments);
config.afterProgramCreation?.(info, fs, exports.MigrationStage.Analysis);
config.beforeUnitAnalysis?.(tsconfigPath);
unitResults.push(await migration.analyze(info));
}
config.afterAllAnalyzed?.();
const combined = await synchronouslyCombineUnitData(migration, unitResults);
if (combined === null) {
config.afterAnalysisFailure?.();
return;
}
const globalMeta = await migration.globalMeta(combined);
let replacements;
if (isFunnelMigration) {
replacements = (await migration.migrate(globalMeta)).replacements;
}
else {
replacements = [];
for (const tsconfigPath of tsconfigPaths) {
config.beforeProgramCreation?.(tsconfigPath, exports.MigrationStage.Migrate);
const info = migration.createProgram(tsconfigPath, fs);
modifyProgramInfoToEnsureNonOverlappingFiles(tsconfigPath, info, compilationUnitAssignments);
config.afterProgramCreation?.(info, fs, exports.MigrationStage.Migrate);
const result = await migration.migrate(globalMeta, info);
replacements.push(...result.replacements);
}
}
const replacementsPerFile = new Map();
const changesPerFile = groupReplacementsByFile(replacements);
for (const [file, changes] of changesPerFile) {
if (!replacementsPerFile.has(file)) {
replacementsPerFile.set(file, changes);
}
}
for (const [file, changes] of replacementsPerFile) {
const recorder = config.tree.beginUpdate(file);
for (const c of changes) {
recorder
.remove(c.data.position, c.data.end - c.data.position)
.insertRight(c.data.position, c.data.toInsert);
}
config.tree.commitUpdate(recorder);
}
config.whenDone?.(await migration.stats(globalMeta));
}
/**
* Special logic for devkit migrations. In the Angular CLI, or in 3P precisely,
* projects can have tsconfigs with overlapping source files. i.e. two tsconfigs
* like e.g. build or test include the same `ts.SourceFile` (`.ts`). Migrations
* should never have 2+ compilation units with overlapping source files as this
* can result in duplicated replacements or analysis hence we only ever assign a
* source file to a compilation unit *once*.
*
* Note that this is fine as we expect Tsurge migrations to work together as
* isolated compilation units so it shouldn't matter if worst case a `.ts`
* file ends up in the e.g. test program.
*/
function modifyProgramInfoToEnsureNonOverlappingFiles(tsconfigPath, info, compilationUnitAssignments) {
const sourceFiles = [];
for (const sf of info.sourceFiles) {
const assignment = compilationUnitAssignments.get(sf.fileName);
// File is already assigned to a different compilation unit.
if (assignment !== undefined && assignment !== tsconfigPath) {
continue;
}
compilationUnitAssignments.set(sf.fileName, tsconfigPath);
sourceFiles.push(sf);
}
info.sourceFiles = sourceFiles;
}
/** A text replacement for the given file. */
class Replacement {
projectFile;
update;
constructor(projectFile, update) {
this.projectFile = projectFile;
this.update = update;
}
}
/** An isolated text update that may be applied to a file. */
class TextUpdate {
data;
constructor(data) {
this.data = data;
}
}
/** Confirms that the given data `T` is serializable. */
function confirmAsSerializable(data) {
return data;
}
/**
* Gets a project file instance for the given file.
*
* Use this helper for dealing with project paths throughout your
* migration. The return type is serializable.
*
* See {@link ProjectFile}.
*/
function projectFile(file, { sortedRootDirs, projectRoot }) {
const fs = project_tsconfig_paths.getFileSystem();
const filePath = fs.resolve(typeof file === 'string' ? file : file.fileName);
// Sorted root directories are sorted longest to shortest. First match
// is the appropriate root directory for ID computation.
for (const rootDir of sortedRootDirs) {
if (!isWithinBasePath(fs, rootDir, filePath)) {
continue;
}
return {
id: fs.relative(rootDir, filePath),
rootRelativePath: fs.relative(projectRoot, filePath),
};
}
// E.g. project directory may be `src/`, but files may be looked up
// from `node_modules/`. This is fine, but in those cases, no root
// directory matches.
const rootRelativePath = fs.relative(projectRoot, filePath);
return {
id: rootRelativePath,
rootRelativePath: rootRelativePath,
};
}
/**
* Whether `path` is a descendant of the `base`?
* E.g. `a/b/c` is within `a/b` but not within `a/x`.
*/
function isWithinBasePath(fs, base, path) {
return project_tsconfig_paths.isLocalRelativePath(fs.relative(base, path));
}
exports.Replacement = Replacement;
exports.TextUpdate = TextUpdate;
exports.TsurgeComplexMigration = TsurgeComplexMigration;
exports.TsurgeFunnelMigration = TsurgeFunnelMigration;
exports.confirmAsSerializable = confirmAsSerializable;
exports.projectFile = projectFile;
exports.runMigrationInDevkit = runMigrationInDevkit;
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
+3 -3
View File
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
@@ -9,8 +9,8 @@
var schematics = require('@angular-devkit/schematics');
var fs = require('fs');
var p = require('path');
var compiler_host = require('./compiler_host-BGZcziuy.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-CaweCOep.cjs');
var compiler_host = require('./compiler_host-AFZotBLM.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-D2eb40pS.cjs');
var ts = require('typescript');
var property_name = require('./property_name-BBwFuqMe.cjs');
require('os');
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
@@ -8,11 +8,11 @@
var ts = require('typescript');
require('os');
require('./project_tsconfig_paths-CaweCOep.cjs');
require('./index-BXjkzENj.cjs');
require('./project_tsconfig_paths-D2eb40pS.cjs');
require('./index-kR-YjYku.cjs');
require('path');
require('node:path');
var project_paths = require('./project_paths-Dr30Du8j.cjs');
var project_paths = require('./project_paths-Bq_k0pof.cjs');
var imports = require('./imports-CIX-JgAN.cjs');
var symbol = require('./symbol-VPWguRxr.cjs');
require('@angular-devkit/core');
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
@@ -8,11 +8,11 @@
var ts = require('typescript');
require('os');
var project_tsconfig_paths = require('./project_tsconfig_paths-CaweCOep.cjs');
require('./index-BXjkzENj.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-D2eb40pS.cjs');
require('./index-kR-YjYku.cjs');
require('path');
require('node:path');
var project_paths = require('./project_paths-Dr30Du8j.cjs');
var project_paths = require('./project_paths-Bq_k0pof.cjs');
var ng_decorators = require('./ng_decorators-B5HCqr20.cjs');
var property_name = require('./property_name-BBwFuqMe.cjs');
require('@angular-devkit/core');
+7 -7
View File
@@ -1,23 +1,23 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
'use strict';
var migrate_ts_type_references = require('./migrate_ts_type_references-7eTqUKA-.cjs');
var migrate_ts_type_references = require('./migrate_ts_type_references-BgYfSnnL.cjs');
var ts = require('typescript');
require('os');
var project_tsconfig_paths = require('./project_tsconfig_paths-CaweCOep.cjs');
var index$1 = require('./index-BXjkzENj.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-D2eb40pS.cjs');
var index$1 = require('./index-kR-YjYku.cjs');
require('path');
require('node:path');
var project_paths = require('./project_paths-Dr30Du8j.cjs');
var index = require('./index-BmMfRg5d.cjs');
var project_paths = require('./project_paths-Bq_k0pof.cjs');
var index = require('./index-CD4aCRVu.cjs');
var assert$1 = require('assert');
var assert = require('node:assert');
var apply_import_manager = require('./apply_import_manager-CPOYeJ7t.cjs');
var apply_import_manager = require('./apply_import_manager-Clb1Y0Nb.cjs');
require('@angular-devkit/core');
require('node:path/posix');
require('./leading_space-D9nQ8UQC.cjs');
@@ -1,23 +1,23 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
'use strict';
var project_tsconfig_paths = require('./project_tsconfig_paths-CaweCOep.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-D2eb40pS.cjs');
var ts = require('typescript');
require('os');
var index$1 = require('./index-BXjkzENj.cjs');
var index$1 = require('./index-kR-YjYku.cjs');
require('path');
require('node:path');
var project_paths = require('./project_paths-Dr30Du8j.cjs');
var apply_import_manager = require('./apply_import_manager-CPOYeJ7t.cjs');
var migrate_ts_type_references = require('./migrate_ts_type_references-7eTqUKA-.cjs');
var project_paths = require('./project_paths-Bq_k0pof.cjs');
var apply_import_manager = require('./apply_import_manager-Clb1Y0Nb.cjs');
var migrate_ts_type_references = require('./migrate_ts_type_references-BgYfSnnL.cjs');
var assert = require('assert');
require('node:assert');
var index = require('./index-BmMfRg5d.cjs');
var index = require('./index-CD4aCRVu.cjs');
require('@angular-devkit/core');
require('node:path/posix');
require('fs');
+7 -7
View File
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
@@ -10,7 +10,7 @@ var schematics = require('@angular-devkit/schematics');
var signalQueriesMigration = require('./signal-queries-migration.cjs');
var signalInputMigration = require('./signal-input-migration.cjs');
var outputMigration = require('./output-migration.cjs');
require('./project_tsconfig_paths-CaweCOep.cjs');
require('./project_tsconfig_paths-D2eb40pS.cjs');
require('typescript');
require('os');
require('fs');
@@ -18,14 +18,14 @@ require('module');
require('path');
require('url');
require('@angular-devkit/core');
require('./index-BXjkzENj.cjs');
require('./index-kR-YjYku.cjs');
require('node:path');
require('./project_paths-Dr30Du8j.cjs');
require('./project_paths-Bq_k0pof.cjs');
require('node:path/posix');
require('./apply_import_manager-CPOYeJ7t.cjs');
require('./migrate_ts_type_references-7eTqUKA-.cjs');
require('./apply_import_manager-Clb1Y0Nb.cjs');
require('./migrate_ts_type_references-BgYfSnnL.cjs');
require('assert');
require('./index-BmMfRg5d.cjs');
require('./index-CD4aCRVu.cjs');
require('./leading_space-D9nQ8UQC.cjs');
require('node:assert');
+4 -4
View File
@@ -1,18 +1,18 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
'use strict';
var schematics = require('@angular-devkit/schematics');
var index = require('./index-BXjkzENj.cjs');
var index = require('./index-kR-YjYku.cjs');
var fs = require('fs');
var p = require('path');
var ts = require('typescript');
var compiler_host = require('./compiler_host-BGZcziuy.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-CaweCOep.cjs');
var compiler_host = require('./compiler_host-AFZotBLM.cjs');
var project_tsconfig_paths = require('./project_tsconfig_paths-D2eb40pS.cjs');
var ng_decorators = require('./ng_decorators-B5HCqr20.cjs');
var nodes = require('./nodes-B16H9JUd.cjs');
var symbol = require('./symbol-VPWguRxr.cjs');
+1 -1
View File
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
+4 -4
View File
@@ -1,6 +1,6 @@
'use strict';
/**
* @license Angular v20.3.11
* @license Angular v20.3.21
* (c) 2010-2025 Google LLC. https://angular.io/
* License: MIT
*/
@@ -8,11 +8,11 @@
var ts = require('typescript');
require('os');
require('./project_tsconfig_paths-CaweCOep.cjs');
require('./index-BXjkzENj.cjs');
require('./project_tsconfig_paths-D2eb40pS.cjs');
require('./index-kR-YjYku.cjs');
require('path');
require('node:path');
var project_paths = require('./project_paths-Dr30Du8j.cjs');
var project_paths = require('./project_paths-Bq_k0pof.cjs');
var imports = require('./imports-CIX-JgAN.cjs');
var symbol = require('./symbol-VPWguRxr.cjs');
require('@angular-devkit/core');