This repository was archived by the owner on Sep 1, 2026. It is now read-only.
Repository navigation
feat!: update to Angular 22 #121
Merged
DRiFTy17
merged 8 commits into
tyler-technologies-oss:main
from
SriramaDanturthi:feat/angular-22
Jul 6, 2026
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
cd0726b
feat!: update to Angular 22
sriramasdanturthi a0a709b
fix: address PR review feedback
sriramasdanturthi 27a46bc
fix: resolve deprecation warnings
sriramasdanturthi b0acf7c
fix: support Angular 21 and 22 per current/current-1 policy
sriramasdanturthi a336fa0
fix: lower minimum supported Angular version back to v20
sriramasdanturthi 2572393
fix: sync package-lock.json with npm 10 for CI compatibility
sriramasdanturthi 9165417
fix: override ws to ^8.21.0 to resolve high-severity DoS advisory
sriramasdanturthi 919ec3a
fix: override vite and piscina to patched versions for dependency review
sriramasdanturthi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
|
SriramaDanturthi marked this conversation as resolved.
Resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
projects/forge-angular/schematics/migrations/migration.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| { | ||
| "$schema": "../../../../node_modules/@angular-devkit/schematics/collection-schema.json", | ||
| "schematics": { | ||
| "update-8-0-0": { | ||
| "version": "8.0.0", | ||
| "description": "Flags usages of DynamicComponentService.create() that rely on APIs removed in @tylertech/forge-angular v8: the ComponentFactory overload and the moduleRef argument.", | ||
| "factory": "./update-8-0-0/index" | ||
| } | ||
| } | ||
| } |
160 changes: 160 additions & 0 deletions
160
projects/forge-angular/schematics/migrations/update-8-0-0/index.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,160 @@ | ||
| import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics'; | ||
| import { getWorkspace } from '@schematics/angular/utility/workspace'; | ||
| import * as path from 'path'; | ||
| import * as ts from 'typescript'; | ||
|
|
||
| const SERVICE_NAME = 'DynamicComponentService'; | ||
| const LIBRARY_MARKER = 'forge-angular'; | ||
|
|
||
| interface Finding { | ||
| file: string; | ||
| line: number; | ||
| column: number; | ||
| message: string; | ||
| } | ||
|
|
||
| interface TargetLike { | ||
| options?: Record<string, unknown>; | ||
| configurations?: Record<string, Record<string, unknown> | undefined>; | ||
| } | ||
|
|
||
| /** | ||
| * Migration for @tylertech/forge-angular v8. | ||
| * | ||
| * `DynamicComponentService.create()` no longer accepts a `ComponentFactory` as its first argument, | ||
| * nor an `NgModuleRef` as its fourth argument — both rely on Angular's deprecated `ComponentFactory`/ | ||
| * `ComponentFactoryResolver` APIs (removed in Angular 22). Its signature is now: | ||
| * | ||
| * create<T>(component: Type<T>, target?: ViewContainerRef | HTMLElement, injector?: Injector) | ||
| * | ||
| * This migration does not auto-rewrite call sites (the correct replacement is app-specific — usually | ||
| * a direct dynamic `import()` of the standalone component). Instead it reports every affected call | ||
| * with its file and line so it can be addressed manually. | ||
| */ | ||
| export default function (): Rule { | ||
| return async (tree: Tree, context: SchematicContext) => { | ||
| const workspace = await getWorkspace(tree); | ||
| const findings: Finding[] = []; | ||
| const visited = new Set<string>(); | ||
|
|
||
| for (const [, project] of workspace.projects) { | ||
| for (const tsConfigPath of collectTsConfigPaths(project)) { | ||
| let program: ts.Program | undefined; | ||
| try { | ||
| program = createProgram(tsConfigPath); | ||
| } catch { | ||
| // Unparseable/missing tsconfig — skip rather than fail the whole update. | ||
| continue; | ||
| } | ||
| if (!program) { | ||
| continue; | ||
| } | ||
|
|
||
| const checker = program.getTypeChecker(); | ||
| for (const sourceFile of program.getSourceFiles()) { | ||
| if (sourceFile.isDeclarationFile || visited.has(sourceFile.fileName)) { | ||
| continue; | ||
| } | ||
| if (sourceFile.fileName.includes('node_modules')) { | ||
| continue; | ||
| } | ||
| visited.add(sourceFile.fileName); | ||
| collectFindings(sourceFile, checker, findings); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (findings.length === 0) { | ||
| context.logger.info( | ||
| `[forge-angular] No '${SERVICE_NAME}.create()' calls relying on removed APIs were found. Nothing to migrate.` | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| context.logger.warn( | ||
| `[forge-angular] Found ${findings.length} '${SERVICE_NAME}.create()' call(s) using APIs removed in v8. ` + | ||
| `Review each and migrate to 'create(component, target?, injector?)':` | ||
| ); | ||
| for (const finding of findings) { | ||
| context.logger.warn(` - ${finding.file}:${finding.line}:${finding.column} — ${finding.message}`); | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| function collectTsConfigPaths(project: { targets: Iterable<[string, TargetLike]> }): string[] { | ||
| const paths = new Set<string>(); | ||
| for (const [, target] of project.targets) { | ||
| const option = target.options?.['tsConfig']; | ||
| if (typeof option === 'string') { | ||
| paths.add(option); | ||
| } | ||
| for (const configuration of Object.values(target.configurations ?? {})) { | ||
| const configOption = configuration?.['tsConfig']; | ||
| if (typeof configOption === 'string') { | ||
| paths.add(configOption); | ||
| } | ||
| } | ||
| } | ||
| return [...paths]; | ||
| } | ||
|
|
||
| function createProgram(tsConfigPath: string): ts.Program | undefined { | ||
| const configPath = path.resolve(process.cwd(), tsConfigPath); | ||
| const host: ts.ParseConfigFileHost = { | ||
| ...ts.sys, | ||
| onUnRecoverableConfigFileDiagnostic: () => undefined | ||
| }; | ||
| const parsed = ts.getParsedCommandLineOfConfigFile(configPath, {}, host); | ||
| if (!parsed || parsed.fileNames.length === 0) { | ||
| return undefined; | ||
| } | ||
| return ts.createProgram({ rootNames: parsed.fileNames, options: parsed.options }); | ||
| } | ||
|
|
||
| function collectFindings(sourceFile: ts.SourceFile, checker: ts.TypeChecker, findings: Finding[]): void { | ||
| const visit = (node: ts.Node): void => { | ||
| if ( | ||
| ts.isCallExpression(node) && | ||
| ts.isPropertyAccessExpression(node.expression) && | ||
| node.expression.name.text === 'create' && | ||
| isDynamicComponentService(checker.getTypeAtLocation(node.expression.expression)) | ||
| ) { | ||
| const messages: string[] = []; | ||
|
|
||
| const firstArg = node.arguments[0]; | ||
| if (firstArg && symbolName(checker.getTypeAtLocation(firstArg)) === 'ComponentFactory') { | ||
| messages.push('first argument is a ComponentFactory (no longer supported — pass the component Type instead)'); | ||
| } | ||
| if (node.arguments.length >= 4) { | ||
| messages.push('the 4th "moduleRef" argument was removed (use a module-scoped Injector via the 3rd argument instead)'); | ||
| } | ||
|
|
||
| if (messages.length > 0) { | ||
| const { line, character } = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)); | ||
| findings.push({ | ||
| file: path.relative(process.cwd(), sourceFile.fileName).replace(/\\/g, '/'), | ||
| line: line + 1, | ||
| column: character + 1, | ||
| message: messages.join('; ') | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| ts.forEachChild(node, visit); | ||
| }; | ||
|
|
||
| visit(sourceFile); | ||
| } | ||
|
|
||
| function isDynamicComponentService(type: ts.Type): boolean { | ||
| const symbol = type.getSymbol() ?? type.aliasSymbol; | ||
| if (!symbol || symbol.getName() !== SERVICE_NAME) { | ||
| return false; | ||
| } | ||
| const declarations = symbol.getDeclarations() ?? []; | ||
| return declarations.some(declaration => declaration.getSourceFile().fileName.includes(LIBRARY_MARKER)); | ||
| } | ||
|
|
||
| function symbolName(type: ts.Type): string | undefined { | ||
| return (type.getSymbol() ?? type.aliasSymbol)?.getName(); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| { | ||
| "type": "commonjs" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| { | ||
| "compilerOptions": { | ||
| "lib": ["es2022"], | ||
| "target": "es2022", | ||
| "module": "node16", | ||
| "moduleResolution": "node16", | ||
| "declaration": false, | ||
| "sourceMap": false, | ||
| "strict": true, | ||
| "esModuleInterop": true, | ||
| "skipLibCheck": true, | ||
| "types": ["node"], | ||
| "rootDir": ".", | ||
| "outDir": "../../../dist/forge-angular/schematics" | ||
| }, | ||
| "include": ["**/*.ts"], | ||
| "exclude": ["**/*.spec.ts"] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.