123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- "use strict";
- /**
- * @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
- */
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.UpdateProject = void 0;
- const ts = require("typescript");
- const component_resource_collector_1 = require("./component-resource-collector");
- const logger_1 = require("./logger");
- const parse_tsconfig_1 = require("./utils/parse-tsconfig");
- const virtual_host_1 = require("./utils/virtual-host");
- /**
- * An update project that can be run against individual migrations. An update project
- * accepts a TypeScript program and a context that is provided to all migrations. The
- * context is usually not used by migrations, but in some cases migrations rely on
- * specifics from the tool that performs the update (e.g. the Angular CLI). In those cases,
- * the context can provide the necessary specifics to the migrations in a type-safe way.
- */
- class UpdateProject {
- constructor(
- /** Context provided to all migrations. */
- _context,
- /** TypeScript program using workspace paths. */
- _program,
- /** File system used for reading, writing and editing files. */
- _fileSystem,
- /**
- * Set of analyzed files. Used for avoiding multiple migration runs if
- * files overlap between targets.
- */
- _analyzedFiles = new Set(),
- /** Logger used for printing messages. */
- _logger = logger_1.defaultLogger) {
- this._context = _context;
- this._program = _program;
- this._fileSystem = _fileSystem;
- this._analyzedFiles = _analyzedFiles;
- this._logger = _logger;
- this._typeChecker = this._program.getTypeChecker();
- }
- /**
- * Migrates the project to the specified target version.
- * @param migrationTypes Migrations that should be run.
- * @param target Version the project should be updated to. Can be `null` if the set of
- * specified migrations runs regardless of a target version.
- * @param data Upgrade data that is passed to all migration rules.
- * @param additionalStylesheetPaths Additional stylesheets that should be migrated, if not
- * referenced in an Angular component. This is helpful for global stylesheets in a project.
- * @param limitToDirectory If specified, changes will be limited to the given directory.
- */
- migrate(migrationTypes, target, data, additionalStylesheetPaths, limitToDirectory) {
- limitToDirectory && (limitToDirectory = this._fileSystem.resolve(limitToDirectory));
- // Create instances of the specified migrations.
- const migrations = this._createMigrations(migrationTypes, target, data);
- // Creates the component resource collector. The collector can visit arbitrary
- // TypeScript nodes and will find Angular component resources. Resources include
- // templates and stylesheets. It also captures inline stylesheets and templates.
- const resourceCollector = new component_resource_collector_1.ComponentResourceCollector(this._typeChecker, this._fileSystem);
- // Collect all of the TypeScript source files we want to migrate. We don't
- // migrate type definition files, or source files from external libraries.
- const sourceFiles = this._program.getSourceFiles().filter(f => {
- return (!f.isDeclarationFile &&
- (limitToDirectory == null ||
- this._fileSystem.resolve(f.fileName).startsWith(limitToDirectory)) &&
- !this._program.isSourceFileFromExternalLibrary(f));
- });
- // Helper function that visits a given TypeScript node and collects all referenced
- // component resources (i.e. stylesheets or templates). Additionally, the helper
- // visits the node in each instantiated migration.
- const visitNodeAndCollectResources = (node) => {
- migrations.forEach(r => r.visitNode(node));
- ts.forEachChild(node, visitNodeAndCollectResources);
- resourceCollector.visitNode(node);
- };
- // Walk through all source file, if it has not been visited before, and
- // visit found nodes while collecting potential resources.
- sourceFiles.forEach(sourceFile => {
- const resolvedPath = this._fileSystem.resolve(sourceFile.fileName);
- // Do not visit source files which have been checked as part of a
- // previously migrated TypeScript project.
- if (!this._analyzedFiles.has(resolvedPath)) {
- visitNodeAndCollectResources(sourceFile);
- this._analyzedFiles.add(resolvedPath);
- }
- });
- // Walk through all resolved templates and visit them in each instantiated
- // migration. Note that this can only happen after source files have been
- // visited because we find templates through the TypeScript source files.
- resourceCollector.resolvedTemplates.forEach(template => {
- // Do not visit the template if it has been checked before. Inline
- // templates cannot be referenced multiple times.
- if (template.inline || !this._analyzedFiles.has(template.filePath)) {
- migrations.forEach(m => m.visitTemplate(template));
- this._analyzedFiles.add(template.filePath);
- }
- });
- // Walk through all resolved stylesheets and visit them in each instantiated
- // migration. Note that this can only happen after source files have been
- // visited because we find stylesheets through the TypeScript source files.
- resourceCollector.resolvedStylesheets.forEach(stylesheet => {
- // Do not visit the stylesheet if it has been checked before. Inline
- // stylesheets cannot be referenced multiple times.
- if (stylesheet.inline || !this._analyzedFiles.has(stylesheet.filePath)) {
- migrations.forEach(r => r.visitStylesheet(stylesheet));
- this._analyzedFiles.add(stylesheet.filePath);
- }
- });
- // In some applications, developers will have global stylesheets which are not
- // specified in any Angular component. Therefore we allow for additional stylesheets
- // being specified. We visit them in each migration unless they have been already
- // discovered before as actual component resource.
- if (additionalStylesheetPaths) {
- additionalStylesheetPaths.forEach(filePath => {
- const resolvedPath = this._fileSystem.resolve(filePath);
- if (limitToDirectory == null || resolvedPath.startsWith(limitToDirectory)) {
- const stylesheet = resourceCollector.resolveExternalStylesheet(resolvedPath, null);
- // Do not visit stylesheets which have been referenced from a component.
- if (!this._analyzedFiles.has(resolvedPath) && stylesheet) {
- migrations.forEach(r => r.visitStylesheet(stylesheet));
- this._analyzedFiles.add(resolvedPath);
- }
- }
- });
- }
- // Call the "postAnalysis" method for each migration.
- migrations.forEach(r => r.postAnalysis());
- // Collect all failures reported by individual migrations.
- const failures = migrations.reduce((res, m) => res.concat(m.failures), []);
- // In case there are failures, print these to the CLI logger as warnings.
- if (failures.length) {
- failures.forEach(({ filePath, message, position }) => {
- const lineAndCharacter = position ? `@${position.line + 1}:${position.character + 1}` : '';
- this._logger.warn(`${filePath}${lineAndCharacter} - ${message}`);
- });
- }
- return {
- hasFailures: !!failures.length,
- };
- }
- /**
- * Creates instances of the given migrations with the specified target
- * version and data.
- */
- _createMigrations(types, target, data) {
- const result = [];
- for (const ctor of types) {
- const instance = new ctor(this._program, this._typeChecker, target, this._context, data, this._fileSystem, this._logger);
- instance.init();
- if (instance.enabled) {
- result.push(instance);
- }
- }
- return result;
- }
- /**
- * Creates a program from the specified tsconfig and patches the host
- * to read files and directories through the given file system.
- *
- * @throws {TsconfigParseError} If the tsconfig could not be parsed.
- */
- static createProgramFromTsconfig(tsconfigPath, fs) {
- const parsed = (0, parse_tsconfig_1.parseTsconfigFile)(fs.resolve(tsconfigPath), fs);
- const host = (0, virtual_host_1.createFileSystemCompilerHost)(parsed.options, fs);
- return ts.createProgram(parsed.fileNames, parsed.options, host);
- }
- }
- exports.UpdateProject = UpdateProject;
- //# sourceMappingURL=index.js.map
|