mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-15 10:11:50 +08:00
refactor(@schematics/angular): remove v19 migrations
These migrations are no longer executed.
This commit is contained in:
parent
b5a86709b7
commit
dd7fe11f4b
@ -1,22 +1,12 @@
|
||||
{
|
||||
"schematics": {
|
||||
"use-application-builder": {
|
||||
"version": "19.0.0",
|
||||
"version": "20.0.0",
|
||||
"factory": "./use-application-builder/migration",
|
||||
"description": "Migrate application projects to the new build system. Application projects that are using the '@angular-devkit/build-angular' package's 'browser' and/or 'browser-esbuild' builders will be migrated to use the new 'application' builder. You can read more about this, including known issues and limitations, here: https://angular.dev/tools/cli/build-system-migration",
|
||||
"optional": true,
|
||||
"recommended": true,
|
||||
"documentation": "tools/cli/build-system-migration"
|
||||
},
|
||||
"update-workspace-config": {
|
||||
"version": "19.0.0",
|
||||
"factory": "./update-workspace-config/migration",
|
||||
"description": "Update the workspace configuration by replacing deprecated options in 'angular.json' for compatibility with the latest Angular CLI changes."
|
||||
},
|
||||
"update-ssr-imports": {
|
||||
"version": "19.0.0",
|
||||
"factory": "./update-ssr-imports/migration",
|
||||
"description": "Update '@angular/ssr' import paths to use the new '/node' entry point when 'CommonEngine' is detected."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,97 +0,0 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
import { DirEntry, Rule, UpdateRecorder } from '@angular-devkit/schematics';
|
||||
import * as ts from '../../third_party/github.com/Microsoft/TypeScript/lib/typescript';
|
||||
import { getPackageJsonDependency } from '../../utility/dependencies';
|
||||
|
||||
function* visit(directory: DirEntry): IterableIterator<ts.SourceFile> {
|
||||
for (const path of directory.subfiles) {
|
||||
if (path.endsWith('.ts') && !path.endsWith('.d.ts')) {
|
||||
const entry = directory.file(path);
|
||||
if (entry) {
|
||||
const content = entry.content;
|
||||
if (content.includes('CommonEngine') && !content.includes('@angular/ssr/node')) {
|
||||
const source = ts.createSourceFile(
|
||||
entry.path,
|
||||
content.toString().replace(/^\uFEFF/, ''),
|
||||
ts.ScriptTarget.Latest,
|
||||
true,
|
||||
);
|
||||
|
||||
yield source;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const path of directory.subdirs) {
|
||||
if (path === 'node_modules' || path.startsWith('.')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
yield* visit(directory.dir(path));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schematics rule that identifies and updates import declarations in TypeScript files.
|
||||
* Specifically, it modifies imports of '@angular/ssr' by appending '/node' if the
|
||||
* `CommonEngine` is used from the old entry point.
|
||||
*
|
||||
*/
|
||||
export default function (): Rule {
|
||||
return (tree) => {
|
||||
if (!getPackageJsonDependency(tree, '@angular/ssr')) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const sourceFile of visit(tree.root)) {
|
||||
let recorder: UpdateRecorder | undefined;
|
||||
|
||||
const allImportDeclarations = sourceFile.statements.filter((n) => ts.isImportDeclaration(n));
|
||||
if (allImportDeclarations.length === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const ssrImports = allImportDeclarations.filter(
|
||||
(n) => ts.isStringLiteral(n.moduleSpecifier) && n.moduleSpecifier.text === '@angular/ssr',
|
||||
);
|
||||
for (const ssrImport of ssrImports) {
|
||||
const ssrNamedBinding = getNamedImports(ssrImport);
|
||||
if (ssrNamedBinding) {
|
||||
const isUsingOldEntryPoint = ssrNamedBinding.elements.some((e) =>
|
||||
e.name.text.startsWith('CommonEngine'),
|
||||
);
|
||||
|
||||
if (!isUsingOldEntryPoint) {
|
||||
continue;
|
||||
}
|
||||
|
||||
recorder ??= tree.beginUpdate(sourceFile.fileName);
|
||||
recorder.insertRight(ssrImport.moduleSpecifier.getEnd() - 1, '/node');
|
||||
}
|
||||
}
|
||||
|
||||
if (recorder) {
|
||||
tree.commitUpdate(recorder);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function getNamedImports(
|
||||
importDeclaration: ts.ImportDeclaration | undefined,
|
||||
): ts.NamedImports | undefined {
|
||||
const namedBindings = importDeclaration?.importClause?.namedBindings;
|
||||
if (namedBindings && ts.isNamedImports(namedBindings)) {
|
||||
return namedBindings;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
import { tags } from '@angular-devkit/core';
|
||||
import { EmptyTree } from '@angular-devkit/schematics';
|
||||
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
|
||||
|
||||
describe('CommonEngine migration', () => {
|
||||
const schematicRunner = new SchematicTestRunner(
|
||||
'migrations',
|
||||
require.resolve('../migration-collection.json'),
|
||||
);
|
||||
|
||||
let tree: UnitTestTree;
|
||||
beforeEach(() => {
|
||||
tree = new UnitTestTree(new EmptyTree());
|
||||
tree.create(
|
||||
'package.json',
|
||||
JSON.stringify({
|
||||
dependencies: {
|
||||
'@angular/ssr': '0.0.0',
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
function runMigration(): Promise<UnitTestTree> {
|
||||
return schematicRunner.runSchematic('update-ssr-imports', {}, tree);
|
||||
}
|
||||
|
||||
it(`should replace 'CommonEngine*' imports from '@angular/ssr' to '@angular/ssr/node'`, async () => {
|
||||
tree.create(
|
||||
'/index.ts',
|
||||
tags.stripIndents`
|
||||
import { CommonEngine } from '@angular/ssr';
|
||||
import type { CommonEngineOptions, CommonEngineRenderOptions } from '@angular/ssr';
|
||||
`,
|
||||
);
|
||||
|
||||
const newTree = await runMigration();
|
||||
expect(newTree.readContent('/index.ts')).toBe(tags.stripIndents`
|
||||
import { CommonEngine } from '@angular/ssr/node';
|
||||
import type { CommonEngineOptions, CommonEngineRenderOptions } from '@angular/ssr/node';
|
||||
`);
|
||||
});
|
||||
|
||||
it(`should not replace 'CommonEngine*' imports from '@angular/ssr/node'`, async () => {
|
||||
const input = tags.stripIndents`
|
||||
import { CommonEngine } from '@angular/ssr/node';
|
||||
import type { CommonEngineOptions, CommonEngineRenderOptions } from '@angular/ssr/node';
|
||||
`;
|
||||
|
||||
tree.create('/index.ts', input);
|
||||
|
||||
const newTree = await runMigration();
|
||||
expect(newTree.readContent('/index.ts')).toBe(input);
|
||||
});
|
||||
|
||||
it(`should not replace 'CommonEngine*' imports from other package`, async () => {
|
||||
const input = tags.stripIndents`
|
||||
import { CommonEngine } from 'unknown';
|
||||
import type { CommonEngineOptions, CommonEngineRenderOptions } from 'unknown';
|
||||
`;
|
||||
|
||||
tree.create('/index.ts', input);
|
||||
|
||||
const newTree = await runMigration();
|
||||
expect(newTree.readContent('/index.ts')).toBe(input);
|
||||
});
|
||||
});
|
@ -1,89 +0,0 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
import { Rule } from '@angular-devkit/schematics';
|
||||
import { allTargetOptions, updateWorkspace } from '../../utility/workspace';
|
||||
import { Builders, ProjectType } from '../../utility/workspace-models';
|
||||
|
||||
/**
|
||||
* Main entry point for the migration rule.
|
||||
*
|
||||
* This schematic migration performs updates to the Angular workspace configuration
|
||||
* to ensure that application projects are properly configured with polyfills
|
||||
* required for internationalization (`localize`).
|
||||
*
|
||||
* It specifically targets application projects that use either the `application`
|
||||
* or `browser-esbuild` builders.
|
||||
*
|
||||
* The migration process involves:
|
||||
*
|
||||
* 1. Iterating over all projects in the workspace.
|
||||
* 2. Checking each project to determine if it is an application-type project.
|
||||
* 3. For each application project, examining the associated build targets.
|
||||
* 4. If a build target's `localize` option is enabled but the polyfill
|
||||
* `@angular/localize/init` is missing from the `polyfills` array, the polyfill
|
||||
* is automatically added to ensure proper internationalization support.
|
||||
*
|
||||
* Additionally, this migration updates projects that use the `dev-server` or `extract-i18n`
|
||||
* builders to ensure that deprecated `browserTarget` options are migrated to the
|
||||
* newer `buildTarget` field.
|
||||
*
|
||||
*/
|
||||
export default function (): Rule {
|
||||
return updateWorkspace((workspace) => {
|
||||
for (const project of workspace.projects.values()) {
|
||||
if (project.extensions.projectType !== ProjectType.Application) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const target of project.targets.values()) {
|
||||
if (target.builder === Builders.DevServer || target.builder === Builders.ExtractI18n) {
|
||||
// Migrate `browserTarget` to `buildTarget`
|
||||
|
||||
for (const [, options] of allTargetOptions(target, false)) {
|
||||
if (options['browserTarget'] && !options['buildTarget']) {
|
||||
options['buildTarget'] = options['browserTarget'];
|
||||
}
|
||||
|
||||
delete options['browserTarget'];
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the target uses application-related builders
|
||||
if (
|
||||
target.builder !== Builders.BuildApplication &&
|
||||
target.builder !== Builders.Application &&
|
||||
target.builder !== Builders.BrowserEsbuild
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if polyfills include '@angular/localize/init'
|
||||
const polyfills = target.options?.['polyfills'];
|
||||
if (
|
||||
Array.isArray(polyfills) &&
|
||||
polyfills.some(
|
||||
(polyfill) => typeof polyfill === 'string' && polyfill.startsWith('@angular/localize'),
|
||||
)
|
||||
) {
|
||||
// Skip if the polyfill is already present
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add '@angular/localize/init' polyfill if localize option is enabled
|
||||
for (const [, options] of allTargetOptions(target, false)) {
|
||||
if (options['localize']) {
|
||||
target.options ??= {};
|
||||
((target.options['polyfills'] ??= []) as string[]).push('@angular/localize/init');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
import { EmptyTree } from '@angular-devkit/schematics';
|
||||
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
|
||||
import { ProjectType } from '../../utility/workspace-models';
|
||||
|
||||
function createWorkSpaceConfig(tree: UnitTestTree) {
|
||||
const angularConfig = {
|
||||
version: 1,
|
||||
projects: {
|
||||
app: {
|
||||
root: '/project/app',
|
||||
sourceRoot: '/project/app/src',
|
||||
projectType: ProjectType.Application,
|
||||
prefix: 'app',
|
||||
architect: {
|
||||
build: {
|
||||
builder: '@angular/build:application',
|
||||
options: {
|
||||
localize: true,
|
||||
polyfills: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
tree.create('/angular.json', JSON.stringify(angularConfig, undefined, 2));
|
||||
}
|
||||
|
||||
describe(`Migration to update the workspace configuration`, () => {
|
||||
const schematicName = 'update-workspace-config';
|
||||
const schematicRunner = new SchematicTestRunner(
|
||||
'migrations',
|
||||
require.resolve('../migration-collection.json'),
|
||||
);
|
||||
|
||||
let tree: UnitTestTree;
|
||||
beforeEach(() => {
|
||||
tree = new UnitTestTree(new EmptyTree());
|
||||
createWorkSpaceConfig(tree);
|
||||
});
|
||||
|
||||
it(`should add '@angular/localize/init' to polyfills if localize is enabled`, async () => {
|
||||
const newTree = await schematicRunner.runSchematic(schematicName, {}, tree);
|
||||
const {
|
||||
projects: { app },
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} = newTree.readJson('/angular.json') as any;
|
||||
|
||||
expect(app.architect.build.options.polyfills).toContain('@angular/localize/init');
|
||||
});
|
||||
|
||||
it(`should not add '@angular/localize/init' to polyfills if it already exists`, async () => {
|
||||
// Add '@angular/localize/init' manually
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const config = tree.readJson('/angular.json') as any;
|
||||
config.projects.app.architect.build.options.polyfills.push('@angular/localize/init');
|
||||
tree.overwrite('/angular.json', JSON.stringify(config, undefined, 2));
|
||||
|
||||
const newTree = await schematicRunner.runSchematic(schematicName, {}, tree);
|
||||
const {
|
||||
projects: { app },
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} = newTree.readJson('/angular.json') as any;
|
||||
|
||||
const polyfills = app.architect.build.options.polyfills;
|
||||
expect(polyfills.filter((p: string) => p === '@angular/localize/init').length).toBe(1);
|
||||
});
|
||||
|
||||
it(`should not add polyfills if localize is not enabled`, async () => {
|
||||
// Disable 'localize'
|
||||
const config = JSON.parse(tree.readContent('/angular.json'));
|
||||
config.projects.app.architect.build.options.localize = false;
|
||||
tree.overwrite('/angular.json', JSON.stringify(config, undefined, 2));
|
||||
|
||||
const newTree = await schematicRunner.runSchematic(schematicName, {}, tree);
|
||||
const {
|
||||
projects: { app },
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} = newTree.readJson('/angular.json') as any;
|
||||
|
||||
expect(app.architect.build.options.polyfills).not.toContain('@angular/localize/init');
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user