Skip to content

Commit

Permalink
feat(migrations): schematic to remove deprecated CompilerOptions prop…
Browse files Browse the repository at this point in the history
…erties (#49672)

`useJit` and `missingTranslation` have been deprecated since v13 and  are unused in Ivy. They can be safely removed.

PR Close #49672
  • Loading branch information
JeanMeche authored and atscott committed Oct 10, 2023
1 parent 40113f6 commit f0da7c2
Show file tree
Hide file tree
Showing 11 changed files with 370 additions and 2 deletions.
2 changes: 0 additions & 2 deletions goldens/public-api/core/index.md
Expand Up @@ -212,10 +212,8 @@ export abstract class CompilerFactory {

// @public
export type CompilerOptions = {
useJit?: boolean;
defaultEncapsulation?: ViewEncapsulation;
providers?: StaticProvider[];
missingTranslation?: MissingTranslationStrategy;
preserveWhitespaces?: boolean;
};

Expand Down
1 change: 1 addition & 0 deletions packages/core/schematics/BUILD.bazel
Expand Up @@ -18,6 +18,7 @@ pkg_npm(
visibility = ["//packages/core:__pkg__"],
deps = [
"//packages/core/schematics/migrations/block-template-entities:bundle",
"//packages/core/schematics/migrations/compiler-options:bundle",
"//packages/core/schematics/ng-generate/standalone-migration:bundle",
],
)
5 changes: 5 additions & 0 deletions packages/core/schematics/migrations.json
Expand Up @@ -4,6 +4,11 @@
"version": "17.0.0",
"description": "Angular v17 introduces a new control flow syntax that uses the @ and } characters. This migration replaces the existing usages with their corresponding HTML entities.",
"factory": "./migrations/block-template-entities/bundle"
},
"migration-v17-compiler-options": {
"version": "17.0.0",
"description": "CompilerOption.useJit and CompilerOption.missingTranslation are unused under Ivy. This migration removes their usage",
"factory": "./migrations/compiler-options/bundle"
}
}
}
33 changes: 33 additions & 0 deletions packages/core/schematics/migrations/compiler-options/BUILD.bazel
@@ -0,0 +1,33 @@
load("//tools:defaults.bzl", "esbuild", "ts_library")

package(
default_visibility = [
"//packages/core/schematics:__pkg__",
"//packages/core/schematics/migrations/google3:__pkg__",
"//packages/core/schematics/test:__pkg__",
],
)

ts_library(
name = "compiler-options",
srcs = glob(["**/*.ts"]),
tsconfig = "//packages/core/schematics:tsconfig.json",
deps = [
"//packages/core/schematics/utils",
"@npm//@angular-devkit/schematics",
"@npm//@types/node",
"@npm//typescript",
],
)

esbuild(
name = "bundle",
entry_point = ":index.ts",
external = [
"@angular-devkit/*",
"typescript",
],
format = "cjs",
platform = "node",
deps = [":compiler-options"],
)
28 changes: 28 additions & 0 deletions packages/core/schematics/migrations/compiler-options/README.md
@@ -0,0 +1,28 @@
## Compiler Options migrations

`CompilerOptions.useJit` and `CompilerOptions.missingTranslation` config options are unused in Ivy and have no effects. They can be safely removed.

#### Before

```ts
import {ViewEncapsulation, MissingTranslationStrategy, CompilerOptions} from '@angular/core';

const compilerOptions: CompilerOptions = {
defaultEncapsulation: ViewEncapsulation.None,
preserveWhitespaces: true,
useJit: true,
missingTranslation: MissingTranslationStrategy.Ignore,
};
```

#### After

```ts
import {ViewEncapsulation, CompilerOptions} from '@angular/core';


const compilerOptions: CompilerOptions = {
defaultEncapsulation: ViewEncapsulation.None,
preserveWhitespaces: true,
};
```
58 changes: 58 additions & 0 deletions packages/core/schematics/migrations/compiler-options/index.ts
@@ -0,0 +1,58 @@
/**
* @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.io/license
*/

import {Rule, SchematicsException, Tree, UpdateRecorder} from '@angular-devkit/schematics';
import {relative} from 'path';

import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths';
import {canMigrateFile, createMigrationProgram} from '../../utils/typescript/compiler_host';

import {migrateFile} from './util';

export default function(): Rule {
return async (tree: Tree) => {
const {buildPaths, testPaths} = await getProjectTsConfigPaths(tree);
const basePath = process.cwd();
const allPaths = [...buildPaths, ...testPaths];

if (!allPaths.length) {
throw new SchematicsException(
'Could not find any tsconfig file. Cannot run the guard and resolve interfaces migration.');
}

for (const tsconfigPath of allPaths) {
runGuardAndResolveInterfacesMigration(tree, tsconfigPath, basePath);
}
};
}

function runGuardAndResolveInterfacesMigration(tree: Tree, tsconfigPath: string, basePath: string) {
const program = createMigrationProgram(tree, tsconfigPath, basePath);
const sourceFiles = program.getSourceFiles().filter(
(sourceFile) => canMigrateFile(basePath, sourceFile, program));

for (const sourceFile of sourceFiles) {
let update: UpdateRecorder|null = null;

const rewriter = (startPos: number, width: number, text: string|null) => {
if (update === null) {
// Lazily initialize update, because most files will not require migration.
update = tree.beginUpdate(relative(basePath, sourceFile.fileName));
}
update.remove(startPos, width);
if (text !== null) {
update.insertLeft(startPos, text);
}
};
migrateFile(sourceFile, rewriter);

if (update !== null) {
tree.commitUpdate(update);
}
}
}
61 changes: 61 additions & 0 deletions packages/core/schematics/migrations/compiler-options/util.ts
@@ -0,0 +1,61 @@
/**
* @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.io/license
*/

import ts from 'typescript';

import {ChangeTracker} from '../../utils/change_tracker';
import {getImportSpecifier} from '../../utils/typescript/imports';
import {closestNode} from '../../utils/typescript/nodes';

const coreModule = '@angular/core';
const compilerOptionsType = 'CompilerOptions';
const deletedIdentifiers = new Set(['useJit', 'missingTranslation']);

export type RewriteFn = (startPos: number, width: number, text: string) => void;

export function migrateFile(sourceFile: ts.SourceFile, rewriteFn: RewriteFn) {
const compilerOptionsImport = getImportSpecifier(sourceFile, coreModule, compilerOptionsType);
if (compilerOptionsImport === null) {
return;
}

const changeTracker = new ChangeTracker(ts.createPrinter());

removeIdentifiers(sourceFile, changeTracker);

for (const changesInFile of changeTracker.recordChanges().values()) {
for (const change of changesInFile) {
rewriteFn(change.start, change.removeLength ?? 0, change.text);
}
}
}

function removeIdentifiers(sourceFile: ts.SourceFile, changeTracker: ChangeTracker) {
const missingTranslationStrategyImport =
getImportSpecifier(sourceFile, coreModule, 'MissingTranslationStrategy');
const namedImports = missingTranslationStrategyImport ?
closestNode(missingTranslationStrategyImport, ts.isNamedImports) :
null;

const visitNode = (node: ts.Node) => {
if (ts.isVariableDeclaration(node) && node.type?.getText() !== compilerOptionsType) {
return;
}

if (ts.isIdentifier(node) && deletedIdentifiers.has(node.text)) {
changeTracker.removeNode(node.parent);
if (node.text === 'missingTranslation') {
if (namedImports && missingTranslationStrategyImport) {
changeTracker.removeNode(missingTranslationStrategyImport);
}
}
}
ts.forEachChild(node, visitNode);
};
ts.forEachChild(sourceFile, visitNode);
}
10 changes: 10 additions & 0 deletions packages/core/schematics/migrations/google3/BUILD.bazel
Expand Up @@ -5,13 +5,23 @@ ts_library(
srcs = glob(["**/*.ts"]),
tsconfig = "//packages/core/schematics:tsconfig.json",
deps = [
"//packages/core/schematics/migrations/compiler-options",
"//packages/core/schematics/utils",
"//packages/core/schematics/utils/tslint",
"@npm//tslint",
"@npm//typescript",
],
)

esbuild(
name = "compiler_options_cjs",
entry_point = ":compilerOptionsRule.ts",
format = "cjs",
output = "compilerOptionsCjsRule.js",
platform = "node",
deps = [":google3"],
)

esbuild(
name = "wait_for_async_rule_cjs",
entry_point = ":waitForAsyncRule.ts",
Expand Down
31 changes: 31 additions & 0 deletions packages/core/schematics/migrations/google3/compilerOptionsRule.ts
@@ -0,0 +1,31 @@
/**
* @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.io/license
*/

import {Replacement, RuleFailure, Rules} from 'tslint';
import ts from 'typescript';

import {migrateFile} from '../compiler-options/util';

/** TSLint rule for the CompilerOptions migration. */
export class Rule extends Rules.TypedRule {
override applyWithProgram(sourceFile: ts.SourceFile, program: ts.Program): RuleFailure[] {
const failures: RuleFailure[] = [];

const rewriter = (startPos: number, origLength: number, text: string) => {
const failure = new RuleFailure(
sourceFile, startPos, startPos + origLength,
'CompilerOptions.useJit and CompilerOptions.missingTranslation are being removed.',
this.ruleName, new Replacement(startPos, origLength, text));
failures.push(failure);
};

migrateFile(sourceFile, rewriter);

return failures;
}
}
2 changes: 2 additions & 0 deletions packages/core/schematics/test/BUILD.bazel
Expand Up @@ -21,6 +21,8 @@ jasmine_node_test(
"//packages/core/schematics:migrations.json",
"//packages/core/schematics/migrations/block-template-entities",
"//packages/core/schematics/migrations/block-template-entities:bundle",
"//packages/core/schematics/migrations/compiler-options",
"//packages/core/schematics/migrations/compiler-options:bundle",
"//packages/core/schematics/ng-generate/standalone-migration",
"//packages/core/schematics/ng-generate/standalone-migration:bundle",
"//packages/core/schematics/ng-generate/standalone-migration:static_files",
Expand Down

0 comments on commit f0da7c2

Please sign in to comment.