Skip to content

Conversation

@mistrykaran91
Copy link
Member

  • Split monolithic element-migration.ts into individual rule files
  • Move template/symbol manipulation utilities to respective rule files

Describe in detail what your merge request does and why. Add relevant
screenshots and reference related issues via Closes #XY or Related to #XY.


- Split monolithic element-migration.ts into individual rule files
- Move template/symbol manipulation utilities to respective rule files
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the monolithic element migration schematic into smaller, more manageable rule files. This is a great step towards improving the maintainability and readability of the schematics code.

However, I've identified a few issues with the current implementation:

  • There's a significant performance regression due to the way the new rules are chained, causing project files to be parsed multiple times.
  • Some utility interfaces and functions have been moved to locations that create unnecessary coupling between different migrations.
  • A minor issue with a duplicated copyright header.

Please see my detailed comments for suggestions on how to address these points.

Comment on lines +33 to +40
return chain([
componentPropertyNameMigrationRule(path, componentPropertyNameChanges),
symbolRenamingMigrationRule(path, symbolRenamingChanges),
attributeSelectorMigrationRule(path, attributeSelectorChanges),
elementSelectorMigrationRule(path, elementSelectorChanges),
symbolRemovalMigrationRule(path, symbolRemovalChanges),
classMemberReplacementMigrationRule(path, classMemberReplacementChanges)
])(tree, context);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This refactoring is great for organizing the migration logic into separate files. However, using chain this way introduces a significant performance issue. Each rule in the chain calls discoverSourceFiles independently, which is an expensive operation as it involves creating a TypeScript program. This means the project's files will be parsed multiple times (once for each rule in the chain).

A more performant approach would be to loop through the source files once and apply all migration rules for each file. This would be similar to the original implementation but with the logic for each migration type extracted into its own function.

For example, you could have a structure like this:

export const elementMigrationRule = (
  options: { path: string },
  migrationData: ElementMigrationData
): Rule => {
  return async (tree: Tree, context: SchematicContext) => {
    for await (const { path: filePath, sourceFile, typeChecker } of discoverSourceFiles(
      tree,
      context,
      options.path
    )) {
      // Apply all migrations for the current file
      applyComponentPropertyNameMigration(tree, filePath, sourceFile, migrationData.componentPropertyNameChanges);
      applySymbolRenamingMigration(tree, filePath, sourceFile, typeChecker, migrationData.symbolRenamingChanges);
      // ... and so on for other migrations
    }
    return tree;
  };
};

This would retain the code organization benefits while avoiding the performance overhead of repeatedly parsing the project files.

Comment on lines +8 to +11
/**
* Copyright (c) Siemens 2016 - 2025
* SPDX-License-Identifier: MIT
*/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is a duplicated copyright header here. Please remove it.

Comment on lines +22 to +40
export interface Replacement {
start: number;
end: number;
text: string;
}

export interface ChangeInstruction {
start: number;
width: number;
newNode: ts.Node;
}

export interface VisitFunctionCallOptions {
sourceFile: ts.SourceFile;
moduleSpecifier: string | RegExp;
className?: string;
functionName: string;
visitor: (node: ts.CallExpression) => void;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The VisitFunctionCallOptions interface and its related visitStaticFunctionCalls function (which has been moved to ngx-translate/index.ts) are general-purpose utilities. Placing the interface here within the element-migration rules creates an unnecessary coupling, as seen with the ngx-translate migration now depending on this file.

To improve modularity and reusability, consider moving VisitFunctionCallOptions and other shared interfaces like ChangeInstruction and Replacement to a more central location, like a new interfaces.ts file under schematics/utils. Similarly, the visitStaticFunctionCalls function should probably be moved back to ts-utils.ts.

@github-actions
Copy link

Code Coverage

@github-actions
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant