Skip to content

Commit

Permalink
feat(core): Add schematic to migrate control flow syntax
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.
  • Loading branch information
thePunderWoman committed Oct 6, 2023
1 parent 5b88d13 commit fd31a93
Show file tree
Hide file tree
Showing 9 changed files with 1,294 additions and 2 deletions.
2 changes: 2 additions & 0 deletions packages/core/schematics/BUILD.bazel
Expand Up @@ -12,12 +12,14 @@ 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/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
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"
]
}
}
}
}
@@ -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"],
)
@@ -0,0 +1,32 @@
## Control Flow Syntax migration

Angular v17 introduces a new control flow syntax that uses the `@` and `}` characters.
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.


#### 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
}
```
@@ -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);
}
}
@@ -0,0 +1,7 @@
{
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "AngularControlFlowMigration",
"title": "Angular Control Flow Migration Schema",
"type": "object",
"properties": {}
}

0 comments on commit fd31a93

Please sign in to comment.