Skip to content

Commit

Permalink
feat(core): Add schematic to migrate control flow syntax (#52035)
Browse files Browse the repository at this point in the history
This adds the migration to run to migrate to the block control flow syntax. It includes ngIf, ngFor, and ngSwitch.

PR Close #52035
  • Loading branch information
thePunderWoman authored and atscott committed Oct 10, 2023
1 parent 9bf6495 commit 50275e5
Show file tree
Hide file tree
Showing 9 changed files with 1,644 additions and 2 deletions.
2 changes: 2 additions & 0 deletions packages/core/schematics/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ pkg_npm(
"collection.json",
"migrations.json",
"package.json",
"//packages/core/schematics/ng-generate/control-flow-migration:static_files",
"//packages/core/schematics/ng-generate/standalone-migration:static_files",
],
validate = False,
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/control-flow-migration:bundle",
"//packages/core/schematics/ng-generate/standalone-migration:bundle",
],
)
14 changes: 12 additions & 2 deletions packages/core/schematics/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@
"description": "Converts the entire application or a part of it to standalone",
"factory": "./ng-generate/standalone-migration/bundle",
"schema": "./ng-generate/standalone-migration/schema.json",
"aliases": ["standalone"]
"aliases": [
"standalone"
]
},
"control-flow-migration": {
"description": "Converts the entire application to block control flow syntax",
"factory": "./ng-generate/control-flow-migration/bundle",
"schema": "./ng-generate/control-flow-migration/schema.json",
"aliases": [
"control-flow"
]
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
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__",
],
)

filegroup(
name = "static_files",
srcs = ["schema.json"],
)

ts_library(
name = "control-flow-migration",
srcs = glob(["**/*.ts"]),
tsconfig = "//packages/core/schematics:tsconfig.json",
deps = [
"//packages/compiler",
"//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 = [":control-flow-migration"],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## Control Flow Syntax migration

Angular v17 introduces a new control flow syntax. This migration replaces the
existing usages of `*ngIf`, `*ngFor`, and `*ngSwitch` to their equivalent block
syntax. Existing ng-templates are preserved in case they are used elsewhere in
the template.

NOTE: This is a developer preview migration

#### Before
```ts
import {Component} from '@angular/core';

@Component({
template: `<div><span *ngIf="show">Content here</span></div>`
})
export class MyComp {
show = false;
}
```


#### After
```ts
import {Component} from '@angular/core';

@Component({
template: `<div>@if (show) {<span>Content here</span>}</div>`
})
export class MyComp {
show = false
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* @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} from '@angular-devkit/schematics';
import {relative} from 'path';

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

import {analyze, AnalyzedFile, migrateTemplate} 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 control flow migration.');
}

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

function runControlFlowMigration(tree: Tree, tsconfigPath: string, basePath: string) {
const program = createMigrationProgram(tree, tsconfigPath, basePath);
const sourceFiles =
program.getSourceFiles().filter(sourceFile => canMigrateFile(basePath, sourceFile, program));
const analysis = new Map<string, AnalyzedFile>();

for (const sourceFile of sourceFiles) {
analyze(sourceFile, analysis);
}

for (const [path, file] of analysis) {
const ranges = file.getSortedRanges();
const relativePath = relative(basePath, path);
const content = tree.readText(relativePath);
const update = tree.beginUpdate(relativePath);

for (const [start, end] of ranges) {
const template = content.slice(start, end);
const length = (end ?? content.length) - start;
const migrated = migrateTemplate(template);

if (migrated !== null) {
update.remove(start, length);
update.insertLeft(start, migrated);
}
}

tree.commitUpdate(update);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "AngularControlFlowMigration",
"title": "Angular Control Flow Migration Schema",
"type": "object",
"properties": {}
}
Loading

0 comments on commit 50275e5

Please sign in to comment.