From 929f637ae53b736524b2bccee2ef280ca578678c Mon Sep 17 00:00:00 2001 From: Masum ULU Date: Mon, 25 Sep 2023 17:02:12 +0300 Subject: [PATCH 1/2] Refactor change-theme command --- .../src/commands/change-theme/index.ts | 83 ++++++++----------- 1 file changed, 36 insertions(+), 47 deletions(-) diff --git a/npm/ng-packs/packages/schematics/src/commands/change-theme/index.ts b/npm/ng-packs/packages/schematics/src/commands/change-theme/index.ts index 30a29ed7dc..43d7750751 100644 --- a/npm/ng-packs/packages/schematics/src/commands/change-theme/index.ts +++ b/npm/ng-packs/packages/schematics/src/commands/change-theme/index.ts @@ -4,7 +4,14 @@ import { ProjectDefinition } from '@angular-devkit/core/src/workspace'; import * as ts from 'typescript'; import { allStyles, importMap, styleMap } from './style-map'; import { ChangeThemeOptions } from './model'; -import { Change, InsertChange, isLibrary, updateWorkspace, WorkspaceDefinition } from '../../utils'; +import { + Change, + createDefaultPath, + InsertChange, + isLibrary, + updateWorkspace, + WorkspaceDefinition, +} from '../../utils'; import { ThemeOptionsEnum } from './theme-options.enum'; import { addImportToModule, @@ -59,20 +66,8 @@ function updateProjectStyle( } function updateAppModule(selectedProject: string, targetThemeName: ThemeOptionsEnum): Rule { - return (host: Tree) => { - const angularJSON = host.read('angular.json'); - if (!angularJSON) { - throw new SchematicsException('The angular.json does not found'); - } - - const workspace = JSON.parse(angularJSON.toString()); - const project = workspace.projects[selectedProject]; - - if (!project || !project.sourceRoot) { - throw new SchematicsException('The target project does not found'); - } - - const appModulePath = project.sourceRoot + '/app/app.module.ts'; + return async (host: Tree) => { + const appModulePath = (await createDefaultPath(host, selectedProject)) + '/app.module.ts'; return chain([ removeImportPath(appModulePath, targetThemeName), @@ -85,21 +80,13 @@ function updateAppModule(selectedProject: string, targetThemeName: ThemeOptionsE function removeImportPath(appModulePath: string, selectedTheme: ThemeOptionsEnum): Rule { return (host: Tree) => { const recorder = host.beginUpdate(appModulePath); - const sourceText = host.read(appModulePath)?.toString('utf-8'); - const source = ts.createSourceFile( - appModulePath, - sourceText!, - ts.ScriptTarget.Latest, - true, - ts.ScriptKind.TS, - ); - const impMap = Array.from(importMap.values()) - .filter(f => f !== importMap.get(selectedTheme)) - .reduce((acc, val) => [...acc, ...val], []); + const source = getSource(host, appModulePath); + const impMap = getImportPaths(selectedTheme); const nodes = findNodes(source, ts.isImportDeclaration); + const filteredNodes = nodes.filter(n => impMap.some(f => n.getFullText().match(f.path))); - if (!filteredNodes || filteredNodes.length < 1) { + if (filteredNodes?.length < 1) { return; } @@ -118,17 +105,8 @@ function removeImportFromNgModuleMetadata( ): Rule { return (host: Tree) => { const recorder = host.beginUpdate(appModulePath); - const sourceText = host.read(appModulePath)?.toString('utf-8'); - const source = ts.createSourceFile( - appModulePath, - sourceText!, - ts.ScriptTarget.Latest, - true, - ts.ScriptKind.TS, - ); - const impMap = Array.from(importMap.values()) - .filter(f => f !== importMap.get(selectedTheme)) - .reduce((acc, val) => [...acc, ...val], []); + const source = getSource(host, appModulePath); + const impMap = getImportPaths(selectedTheme); const node = getDecoratorMetadata(source, 'NgModule', '@angular/core')[0] || {}; if (!node) { @@ -136,7 +114,6 @@ function removeImportFromNgModuleMetadata( } const matchingProperties = getMetadataField(node as ts.ObjectLiteralExpression, 'imports'); - const assignment = matchingProperties[0] as ts.PropertyAssignment; const assignmentInit = assignment.initializer as ts.ArrayLiteralExpression; @@ -163,14 +140,7 @@ function removeImportFromNgModuleMetadata( function insertImports(appModulePath: string, selectedTheme: ThemeOptionsEnum): Rule { return (host: Tree) => { const recorder = host.beginUpdate(appModulePath); - const sourceText = host.read(appModulePath)?.toString('utf-8'); - const source = ts.createSourceFile( - appModulePath, - sourceText!, - ts.ScriptTarget.Latest, - true, - ts.ScriptKind.TS, - ); + const source = getSource(host, appModulePath); const selected = importMap.get(selectedTheme); const changes: Change[] = []; @@ -190,6 +160,25 @@ function insertImports(appModulePath: string, selectedTheme: ThemeOptionsEnum): }; } +function getSource(host: Tree, appModulePath: string): ts.SourceFile { + const sourceText = host.read(appModulePath)?.toString('utf-8'); + const source = ts.createSourceFile( + appModulePath, + sourceText!, + ts.ScriptTarget.Latest, + true, + ts.ScriptKind.TS, + ); + + return source; +} + +function getImportPaths(selectedTheme: ThemeOptionsEnum) { + return Array.from(importMap.values()) + .filter(f => f !== importMap.get(selectedTheme)) + .reduce((acc, val) => [...acc, ...val], []); +} + export function getProjectTargetOptions( project: ProjectDefinition, buildTarget: string, From 900c2de61bbb52181d87f5551834e0133e46c521 Mon Sep 17 00:00:00 2001 From: Masum ULU Date: Tue, 26 Sep 2023 10:33:46 +0300 Subject: [PATCH 2/2] Improve change-theme command --- .../src/commands/change-theme/index.ts | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/npm/ng-packs/packages/schematics/src/commands/change-theme/index.ts b/npm/ng-packs/packages/schematics/src/commands/change-theme/index.ts index 43d7750751..d3a28876ba 100644 --- a/npm/ng-packs/packages/schematics/src/commands/change-theme/index.ts +++ b/npm/ng-packs/packages/schematics/src/commands/change-theme/index.ts @@ -77,10 +77,10 @@ function updateAppModule(selectedProject: string, targetThemeName: ThemeOptionsE }; } -function removeImportPath(appModulePath: string, selectedTheme: ThemeOptionsEnum): Rule { +export function removeImportPath(appModulePath: string, selectedTheme: ThemeOptionsEnum): Rule { return (host: Tree) => { const recorder = host.beginUpdate(appModulePath); - const source = getSource(host, appModulePath); + const source = createSourceFile(host, appModulePath); const impMap = getImportPaths(selectedTheme); const nodes = findNodes(source, ts.isImportDeclaration); @@ -99,13 +99,13 @@ function removeImportPath(appModulePath: string, selectedTheme: ThemeOptionsEnum }; } -function removeImportFromNgModuleMetadata( +export function removeImportFromNgModuleMetadata( appModulePath: string, selectedTheme: ThemeOptionsEnum, ): Rule { return (host: Tree) => { const recorder = host.beginUpdate(appModulePath); - const source = getSource(host, appModulePath); + const source = createSourceFile(host, appModulePath); const impMap = getImportPaths(selectedTheme); const node = getDecoratorMetadata(source, 'NgModule', '@angular/core')[0] || {}; @@ -119,12 +119,13 @@ function removeImportFromNgModuleMetadata( const elements = assignmentInit.elements; if (!elements || elements.length < 1) { - return; + throw new SchematicsException(`Elements could not found: ${elements}`); } const filteredElements = elements.filter(f => impMap.some(s => f.getText().match(s.importName)), ); + if (!filteredElements || filteredElements.length < 1) { return; } @@ -137,10 +138,10 @@ function removeImportFromNgModuleMetadata( }; } -function insertImports(appModulePath: string, selectedTheme: ThemeOptionsEnum): Rule { +export function insertImports(appModulePath: string, selectedTheme: ThemeOptionsEnum): Rule { return (host: Tree) => { const recorder = host.beginUpdate(appModulePath); - const source = getSource(host, appModulePath); + const source = createSourceFile(host, appModulePath); const selected = importMap.get(selectedTheme); const changes: Change[] = []; @@ -160,11 +161,16 @@ function insertImports(appModulePath: string, selectedTheme: ThemeOptionsEnum): }; } -function getSource(host: Tree, appModulePath: string): ts.SourceFile { - const sourceText = host.read(appModulePath)?.toString('utf-8'); +export function createSourceFile(host: Tree, appModulePath: string): ts.SourceFile { + const buffer = host.read(appModulePath); + if (!buffer || buffer.length === 0) { + throw new SchematicsException(`${appModulePath} file could not be read.`); + } + + const sourceText = buffer.toString('utf-8'); const source = ts.createSourceFile( appModulePath, - sourceText!, + sourceText, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS, @@ -173,7 +179,7 @@ function getSource(host: Tree, appModulePath: string): ts.SourceFile { return source; } -function getImportPaths(selectedTheme: ThemeOptionsEnum) { +export function getImportPaths(selectedTheme: ThemeOptionsEnum) { return Array.from(importMap.values()) .filter(f => f !== importMap.get(selectedTheme)) .reduce((acc, val) => [...acc, ...val], []);