diff --git a/.gitignore b/.gitignore index ab47a01..4d428e9 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,6 @@ jasmine-config/**/*.js.map # IDEs .idea/ jsconfig.json -.vscode/ .history # Misc diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..bda8381 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Test", + "program": "${workspaceFolder}/node_modules/jasmine/bin/jasmine.js", + "args": [ + "--config=jasmine-config/jasmine.json" + ], + "outFiles": [ + "${workspaceFolder}/**/*.js" + ] + } + ] +} \ No newline at end of file diff --git a/src/ast-utils.ts b/src/ast-utils.ts index e77630e..1a8fa37 100644 --- a/src/ast-utils.ts +++ b/src/ast-utils.ts @@ -22,22 +22,6 @@ class RemoveContent implements Node { } } -export function addSymbolToComponentMetadata( - source: ts.SourceFile, - componentPath: string, - metadataField: string, - symbolName: string, -): Change[] { - return addSymbolToDecoratorMetadata( - source, - componentPath, - metadataField, - symbolName, - 'Component', - '@angular/core' - ); -} - // Almost identical to addSymbolToNgModuleMetadata from @schematics/angular/utility/ast-utils // the method can be refactored so that it can be used with custom decorators export function addSymbolToDecoratorMetadata( @@ -630,19 +614,6 @@ export function findImportPath(source: ts.Node, name) { return moduleSpecifier.text; } -export const insertModuleId = (tree: Tree, component: string) => { - const componentSource = getSourceFile(tree, component); - const recorder = tree.beginUpdate(component); - - const metadataChange = addSymbolToComponentMetadata( - componentSource, component, 'moduleId', 'module.id'); - - metadataChange.forEach((change: InsertChange) => - recorder.insertRight(change.pos, change.toAdd) - ); - tree.commitUpdate(recorder); - -}; export const updateNodeText = (tree: Tree, node: ts.Node, newText: string) => { const recorder = tree.beginUpdate(node.getSourceFile().fileName); diff --git a/src/generate/component/ast-utils.ts b/src/generate/component/ast-utils.ts new file mode 100644 index 0000000..0d9a461 --- /dev/null +++ b/src/generate/component/ast-utils.ts @@ -0,0 +1,87 @@ +import * as ts from 'typescript'; + +import { SchematicsException, Tree } from '@angular-devkit/schematics'; +import { classify } from '@angular-devkit/core/src/utils/strings'; +import { buildRelativePath } from '@schematics/angular/utility/find-module'; +import { InsertChange, Change } from '@schematics/angular/utility/change'; +import { addEntryComponentToModule, addExportToModule, addDeclarationToModule } from '@schematics/angular/utility/ast-utils'; +import { Schema as ComponentOptions } from './schema'; +import { getSourceFile } from '../../utils'; +import { addSymbolToDecoratorMetadata } from '../../ast-utils'; + +export const insertModuleId = (tree: Tree, component: string) => { + const componentSource = getSourceFile(tree, component); + const recorder = tree.beginUpdate(component); + + const metadataChange = addSymbolToComponentMetadata( + componentSource, component, 'moduleId', 'module.id'); + + metadataChange.forEach((change: InsertChange) => + recorder.insertRight(change.pos, change.toAdd) + ); + tree.commitUpdate(recorder); +}; + +function addSymbolToComponentMetadata( + source: ts.SourceFile, + componentPath: string, + metadataField: string, + symbolName: string, +): Change[] { + return addSymbolToDecoratorMetadata( + source, + componentPath, + metadataField, + symbolName, + 'Component', + '@angular/core' + ); +} + +export function addDeclarationToNgModule(tree: Tree, options: ComponentOptions, componentPath: string, modulePath: string) { + const source = readIntoSourceFile(tree, modulePath); + const relativePath = buildRelativePath(modulePath, componentPath); + const classifiedName = classify(`${options.name}Component`); + const declarationChanges = addDeclarationToModule(source, modulePath, classifiedName, relativePath); + const declarationRecorder = tree.beginUpdate(modulePath); + for (const change of declarationChanges) { + if (change instanceof InsertChange) { + declarationRecorder.insertLeft(change.pos, change.toAdd); + } + } + tree.commitUpdate(declarationRecorder); + if (options.export) { + // Need to refresh the AST because we overwrote the file in the host. + const source = readIntoSourceFile(tree, modulePath); + const exportRecorder = tree.beginUpdate(modulePath); + const exportChanges = addExportToModule(source, modulePath, classify(`${options.name}Component`), relativePath); + for (const change of exportChanges) { + if (change instanceof InsertChange) { + exportRecorder.insertLeft(change.pos, change.toAdd); + } + } + tree.commitUpdate(exportRecorder); + } + if (options.entryComponent) { + // Need to refresh the AST because we overwrote the file in the host. + const source = readIntoSourceFile(tree, modulePath); + const entryComponentRecorder = tree.beginUpdate(modulePath); + const entryComponentChanges = addEntryComponentToModule(source, modulePath, classify(`${options.name}Component`), relativePath); + for (const change of entryComponentChanges) { + if (change instanceof InsertChange) { + entryComponentRecorder.insertLeft(change.pos, change.toAdd); + } + } + tree.commitUpdate(entryComponentRecorder); + } +} + +function readIntoSourceFile(host: Tree, modulePath: string): ts.SourceFile { + const text = host.read(modulePath); + if (text === null) { + throw new SchematicsException(`File ${modulePath} does not exist.`); + } + const sourceText = text.toString('utf-8'); + + return ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true); +} \ No newline at end of file diff --git a/src/generate/component/find-module.ts b/src/generate/component/find-module.ts new file mode 100644 index 0000000..7f38f0c --- /dev/null +++ b/src/generate/component/find-module.ts @@ -0,0 +1,60 @@ +import { dirname } from 'path'; + +import { Tree, DirEntry } from "@angular-devkit/schematics"; +import { join, normalize } from '@angular-devkit/core'; +import { dasherize } from '@angular-devkit/core/src/utils/strings'; + +import { Schema as ComponentOptions } from './schema'; + +export function findModule(tree: Tree, options: ComponentOptions, path: string, extension: string) { + if (options.module) { + return findExplicitModule(tree, path, extension, options.module); + } else { + const pathToCheck = (path || '') + + (options.flat ? '' : '/' + dasherize(options.name)); + + return findImplicitModule(tree, pathToCheck, extension); + } +} + +function findExplicitModule(tree: Tree, path: string, extension: string, moduleName: string) { + while (path) { + const modulePath = normalize(`/${path}/${moduleName}`); + const moduleBaseName = normalize(modulePath).split('/').pop(); + + if (tree.exists(modulePath)) { + return normalize(modulePath); + } else if (tree.exists(modulePath + extension + '.ts')) { + return normalize(modulePath + extension + '.ts'); + } else if (tree.exists(modulePath + '.module' + extension + '.ts')) { + return normalize(modulePath + '.module' + extension + '.ts'); + } else if (tree.exists(modulePath + '/' + moduleBaseName + '.module' + extension + '.ts')) { + return normalize(modulePath + '/' + moduleBaseName + '.module' + extension + '.ts'); + } + + path = dirname(path); + } + + throw new Error('Specified module does not exist'); +} + +function findImplicitModule(tree: Tree, path: string, extension: string) { + let dir: DirEntry | null = tree.getDir(`/${path}`); + + const moduleRe = new RegExp(`.module${extension}.ts`); + const routingModuleRe = new RegExp(`-routing.module${extension}.ts`); + + while (dir) { + const matches = dir.subfiles.filter(p => moduleRe.test(p) && !routingModuleRe.test(p)); + if (matches.length == 1) { + return join(dir.path, matches[0]); + } else if (matches.length > 1) { + throw new Error('More than one module matches. Use skip-import option to skip importing ' + + 'the component into the closest module.'); + } + + dir = dir.parent; + } + throw new Error('Could not find an NgModule. Use the skip-import ' + + 'option to skip importing in NgModule.'); +} diff --git a/src/generate/component/index.ts b/src/generate/component/index.ts index d2ac6c1..fd20ac2 100644 --- a/src/generate/component/index.ts +++ b/src/generate/component/index.ts @@ -1,3 +1,5 @@ +import { dirname } from 'path'; + import { Rule, SchematicContext, @@ -11,14 +13,17 @@ import { mergeWith, TemplateOptions, filter, + DirEntry, } from '@angular-devkit/schematics'; -import { insertModuleId } from '../../ast-utils'; -import { Schema as ComponentOptions } from './schema'; import { dasherize } from '@angular-devkit/core/src/utils/strings'; +import { Path } from '@angular-devkit/core'; import { parseName } from '@schematics/angular/utility/parse-name'; + import { Extensions, getExtensions, removeNsSchemaOptions, PlatformUse, getPlatformUse, validateGenerateOptions } from '../utils'; -import { Path } from '@angular-devkit/core'; +import { addDeclarationToNgModule, insertModuleId } from './ast-utils'; +import { Schema as ComponentOptions } from './schema'; +import { findModule } from './find-module'; class ComponentInfo { classPath: string; @@ -48,14 +53,32 @@ export default function (options: ComponentOptions): Rule { return tree; }, - () => { - return externalSchematic('@schematics/angular', 'component', removeNsSchemaOptions(options)); - }, + () => externalSchematic('@schematics/angular', 'component', removeNsSchemaOptions({ ...options, skipImport: true })), (tree: Tree) => { extensions = getExtensions(tree, options); componentInfo = parseComponentInfo(tree, options); }, + + (tree: Tree) => { + if (options.skipImport) { + return tree; + } + + const componentPath = componentInfo.classPath; + const componentDir = dirname(componentPath); + if (platformUse.useWeb) { + const webModule = findModule(tree, options, componentDir, extensions.web); + addDeclarationToNgModule(tree, options, componentPath, webModule); + } + + if (platformUse.useNs) { + const nsModule = findModule(tree, options, componentDir, extensions.ns); + addDeclarationToNgModule(tree, options, componentPath, nsModule); + } + + return tree; + }, (tree: Tree) => { if (platformUse.nsOnly) { @@ -86,7 +109,6 @@ const validateGenerateComponentOptions = (platformUse: PlatformUse, options: Com }; const parseComponentInfo = (tree: Tree, options: ComponentOptions): ComponentInfo => { - // const path = `/${projectSettings.root}/${projectSettings.sourceRoot}/app`; const component = new ComponentInfo(); const parsedPath = parseName(options.path || '', options.name); @@ -139,5 +161,4 @@ const addNativeScriptFiles = (component: ComponentInfo) => { ]); return mergeWith(templateSource); - }; diff --git a/src/generate/component/index_spec.ts b/src/generate/component/index_spec.ts index 4bcac71..eabfecc 100644 --- a/src/generate/component/index_spec.ts +++ b/src/generate/component/index_spec.ts @@ -3,10 +3,12 @@ import { join } from 'path'; import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; import { getFileContent } from '@schematics/angular/utility/test'; -import { createEmptyNsOnlyProject, createEmptySharedProject, toComponentClassName } from '../../utils'; +import { createEmptyNsOnlyProject, createEmptySharedProject, toComponentClassName, callRuleSync } from '../../utils'; import { DEFAULT_SHARED_EXTENSIONS } from '../utils'; -import { isInComponentMetadata } from '../../test-utils'; +import { isInComponentMetadata, isInModuleMetadata } from '../../test-utils'; import { Schema as ComponentOptions } from './schema'; +import { Schema as ApplicationOptions } from '../../ng-new/shared/schema'; +import { move } from '@angular-devkit/schematics'; describe('Component Schematic', () => { const name = 'foo'; @@ -20,6 +22,8 @@ describe('Component Schematic', () => { ); const componentPath = `src/app/${name}/${name}.component.ts`; + const rootModulePath = `src/app/app.module.ts`; + const rootNsModulePath = `src/app/app.module.tns.ts`; const getTemplatePath = (extension: string) => `src/app/${name}/${name}.component${extension}.html`; @@ -63,6 +67,11 @@ describe('Component Schematic', () => { expect(appTree.exists(nsTemplatePath)).toBeFalsy()); it('should add {N}-specific markup in template', () => ensureNsTemplate(appTree, noExtensionTemplatePath)); it('should add module id', () => expect(hasModuleId()).toBeTruthy()); + + it('should declare the component in the root NgModule for {N}', () => { + const nsModuleContent = getFileContent(appTree, rootModulePath); + expect(nsModuleContent).toMatch(isInModuleMetadata('AppModule', 'declarations', componentClassName, true)); + }); }); describe('when in ns+web project', () => { @@ -77,6 +86,16 @@ describe('Component Schematic', () => { it('should add web-specific markup file', () => ensureWebTemplate(appTree, webTemplatePath)); it('should add {N}-specific markup file', () => ensureNsTemplate(appTree, nsTemplatePath)); it('should add module id', () => expect(hasModuleId()).toBeFalsy()); + + it('should declare the component in the the root NgModule for web', () => { + const webModuleContent = getFileContent(appTree, rootModulePath); + expect(webModuleContent).toMatch(isInModuleMetadata('AppModule', 'declarations', componentClassName, true)); + }); + + it('should declare the component in the root NgModule for {N}', () => { + const nsModuleContent = getFileContent(appTree, rootNsModulePath); + expect(nsModuleContent).toMatch(isInModuleMetadata('AppModule', 'declarations', componentClassName, true)); + }); }) describe('executing ns-only schematic', () => { @@ -89,6 +108,16 @@ describe('Component Schematic', () => { it('should add {N}-specific markup file', () => ensureNsTemplate(appTree, nsTemplatePath)); it('should add module id', () => expect(hasModuleId()).toBeFalsy()); + + it('should not declare the component in the the root NgModule for web', () => { + const webModuleContent = getFileContent(appTree, rootModulePath); + expect(webModuleContent).not.toMatch(isInModuleMetadata('AppModule', 'declarations', componentClassName, true)); + }); + + it('should declare the component in the root NgModule for {N}', () => { + const nsModuleContent = getFileContent(appTree, rootNsModulePath); + expect(nsModuleContent).toMatch(isInModuleMetadata('AppModule', 'declarations', componentClassName, true)); + }); }) describe('executing web-only schematic', () => { @@ -101,13 +130,23 @@ describe('Component Schematic', () => { it('should add web-specific markup file', () => ensureWebTemplate(appTree, webTemplatePath)); it('should add module id', () => expect(hasModuleId()).toBeFalsy()); + + it('should declare the component in the the root NgModule for web', () => { + const webModuleContent = getFileContent(appTree, rootModulePath); + expect(webModuleContent).toMatch(isInModuleMetadata('AppModule', 'declarations', componentClassName, true)); + }); + + it('should not declare the component in the root NgModule for {N}', () => { + const nsModuleContent = getFileContent(appTree, rootNsModulePath); + expect(nsModuleContent).not.toMatch(isInModuleMetadata('AppModule', 'declarations', componentClassName, true)); + }); }) }); describe('specifying custom extension', () => { describe('in ns only project', () => { beforeEach(() => { - appTree = createEmptyNsOnlyProject(project); + appTree = createEmptyNsOnlyProject(project, '.mobile'); }); it('should respect specified {N} extension', () => { @@ -118,42 +157,174 @@ describe('Component Schematic', () => { const componentTemplatePath = getTemplatePath(customExtension); expect(appTree.exists(componentTemplatePath)).toBeTruthy(); }); - }) + }); + describe('in ns+web project', () => { - beforeEach(() => { - appTree = createEmptySharedProject(project); + describe('when a custom web extension is specified', () => { + const customExtension = '.web'; + const componentOptions = { ...defaultOptions, webExtension: customExtension, web: true }; + + beforeEach(() => { + appTree = createEmptySharedProject(project, customExtension, '.tns'); + }); + + it('should create the files with this extension', () => { + const options = { ...componentOptions }; + appTree = schematicRunner.runSchematic('component', options, appTree); + + const componentTemplatePath = getTemplatePath(customExtension); + expect(appTree.exists(componentTemplatePath)).toBeTruthy(); + }); + + it('should declare in NgModule', () => { + const options = { ...componentOptions }; + appTree = schematicRunner.runSchematic('component', options, appTree); + + const webModulePath = `src/app/app.module${customExtension}.ts`; + const nsModulePath = `src/app/app.module.tns.ts`; + const matcher = isInModuleMetadata('AppModule', 'declarations', componentClassName, true); + + const webModuleContent = getFileContent(appTree, webModulePath); + expect(webModuleContent).toMatch(matcher); + + const nsModuleContent = getFileContent(appTree, nsModulePath); + expect(nsModuleContent).toMatch(matcher); + }); + + it('should respect the module option', () => { + const moduleName = 'random'; + const webModulePath = `src/app/${moduleName}/${moduleName}.module${customExtension}.ts`; + const nsModulePath = `src/app/${moduleName}/${moduleName}.module.tns.ts`; + appTree = schematicRunner.runSchematic('module', { + project, + name: moduleName, + webExtension: customExtension, + }, appTree); + + const options = { ...componentOptions, module: moduleName }; + appTree = schematicRunner.runSchematic('component', options, appTree); + + const matcher = isInModuleMetadata('RandomModule', 'declarations', componentClassName, true); + + const webModuleContent = getFileContent(appTree, webModulePath); + expect(webModuleContent).toMatch(matcher); + + const nsModuleContent = getFileContent(appTree, nsModulePath); + expect(nsModuleContent).toMatch(matcher); + }); }); - it('should respect specified {N} extension', () => { + describe('when a custon {N} extension is specified', () => { const customExtension = '.mobile'; - const options = { ...defaultOptions, nsExtension: customExtension, nativescript: true }; - appTree = schematicRunner.runSchematic('component', options, appTree); + const componentOptions = { ...defaultOptions, nsExtension: customExtension, nativescript: true }; - const componentTemplatePath = getTemplatePath(customExtension); - expect(appTree.exists(componentTemplatePath)).toBeTruthy(); - }); + beforeEach(() => { + appTree = createEmptySharedProject(project, '', customExtension); + }); - it('should respect specified web extension', () => { - const customExtension = '.web'; - const options = { ...defaultOptions, webExtension: customExtension, web: true }; - appTree = schematicRunner.runSchematic('component', options, appTree); + it('should create the files with this extension', () => { + const options = { ...componentOptions }; + appTree = schematicRunner.runSchematic('component', options, appTree); - const componentTemplatePath = getTemplatePath(customExtension); - expect(appTree.exists(componentTemplatePath)).toBeTruthy(); + const componentTemplatePath = getTemplatePath(customExtension); + expect(appTree.exists(componentTemplatePath)).toBeTruthy(); + }); + + it('should declare in NgModule', () => { + const options = { ...componentOptions }; + appTree = schematicRunner.runSchematic('component', options, appTree); + + const webModulePath = `src/app/app.module.ts`; + const nsModulePath = `src/app/app.module${customExtension}.ts`; + const matcher = isInModuleMetadata('AppModule', 'declarations', componentClassName, true); + + const webModuleContent = getFileContent(appTree, webModulePath); + expect(webModuleContent).toMatch(matcher); + + const nsModuleContent = getFileContent(appTree, nsModulePath); + expect(nsModuleContent).toMatch(matcher); + }); + + it('should respect the module option', () => { + const moduleName = 'random'; + const webModulePath = `src/app/${moduleName}/${moduleName}.module.ts`; + const nsModulePath = `src/app/${moduleName}/${moduleName}.module${customExtension}.ts`; + appTree = schematicRunner.runSchematic('module', { + project, + name: moduleName, + nsExtension: customExtension, + }, appTree); + + const options = { ...componentOptions, module: moduleName }; + appTree = schematicRunner.runSchematic('component', options, appTree); + + const matcher = isInModuleMetadata('RandomModule', 'declarations', componentClassName, true); + + const webModuleContent = getFileContent(appTree, webModulePath); + expect(webModuleContent).toMatch(matcher); + + const nsModuleContent = getFileContent(appTree, nsModulePath); + expect(nsModuleContent).toMatch(matcher); + }); }); - it('should respect both web and {N} extensions', () => { + describe('when custom web and {N} extensions are specified', () => { const nsExtension = '.mobile'; const webExtension = '.web'; - const options = { ...defaultOptions, nsExtension, webExtension, web: true, nativescript: true }; - appTree = schematicRunner.runSchematic('component', options, appTree); - - const nsTemplate = getTemplatePath(nsExtension); - const webTemplate = getTemplatePath(webExtension); - expect(appTree.exists(nsTemplate)).toBeTruthy(); - expect(appTree.exists(webTemplate)).toBeTruthy(); + const componentOptions = { ...defaultOptions, nsExtension, webExtension, web: true, nativescript: true }; + + beforeEach(() => { + appTree = createEmptySharedProject(project, webExtension, nsExtension); + }); + + it('should create the files with these extensions', () => { + const options = { ...componentOptions }; + appTree = schematicRunner.runSchematic('component', options, appTree); + + const nsTemplate = getTemplatePath(nsExtension); + const webTemplate = getTemplatePath(webExtension); + expect(appTree.exists(nsTemplate)).toBeTruthy(); + expect(appTree.exists(webTemplate)).toBeTruthy(); + }); + + it('should declare in NgModule', () => { + const options = { ...componentOptions }; + appTree = schematicRunner.runSchematic('component', options, appTree); + + const webModulePath = `src/app/app.module${webExtension}.ts`; + const nsModulePath = `src/app/app.module${nsExtension}.ts`; + const matcher = isInModuleMetadata('AppModule', 'declarations', componentClassName, true); + + const webModuleContent = getFileContent(appTree, webModulePath); + expect(webModuleContent).toMatch(matcher); + + const nsModuleContent = getFileContent(appTree, nsModulePath); + expect(nsModuleContent).toMatch(matcher); + }); + + it('should respect the module option', () => { + const moduleName = 'random'; + const webModulePath = `src/app/${moduleName}/${moduleName}.module${webExtension}.ts`; + const nsModulePath = `src/app/${moduleName}/${moduleName}.module${nsExtension}.ts`; + appTree = schematicRunner.runSchematic('module', { + project, + name: moduleName, + webExtension, + nsExtension, + }, appTree); + + const options = { ...componentOptions, module: moduleName }; + appTree = schematicRunner.runSchematic('component', options, appTree); + + const matcher = isInModuleMetadata('RandomModule', 'declarations', componentClassName, true); + + const webModuleContent = getFileContent(appTree, webModulePath); + expect(webModuleContent).toMatch(matcher); + + const nsModuleContent = getFileContent(appTree, nsModulePath); + expect(nsModuleContent).toMatch(matcher); + }); }); - }) }); }); diff --git a/src/migrate-component/component-info-utils.ts b/src/migrate-component/component-info-utils.ts index 1c0c0a4..ad7805e 100644 --- a/src/migrate-component/component-info-utils.ts +++ b/src/migrate-component/component-info-utils.ts @@ -27,7 +27,7 @@ export const parseComponentInfo = (options: MigrateComponentSchema) => (tree: Tr ? options.name : classify(`${options.name}Component`); - // if no module provided and skipModule flag is on, then don't search for module path + // if no module is provided and the skipModule flag is on, then don't search for module path const modulePath = (!options.module && options.skipModule) ? '' : findModulePath(options, tree); const componentPath = findComponentPath(className, modulePath, options, tree); @@ -123,7 +123,11 @@ const findComponentPath = (componentClassName: string, modulePath: string, optio const componentImportPath = findImportPath(source, componentClassName); console.log(`${componentClassName} import found in its module at: ${componentImportPath}`); - componentPath = join(dirname(modulePath), componentImportPath + '.ts') + componentPath = join(dirname(modulePath), componentImportPath); + if (!componentPath.endsWith('.ts')) { + componentPath = componentPath + '.ts'; + } + if (tree.exists(componentPath)) { console.log(`${componentClassName} file found at: ${componentPath}`); } else { diff --git a/src/migrate-component/index.ts b/src/migrate-component/index.ts index 42daa93..9882528 100644 --- a/src/migrate-component/index.ts +++ b/src/migrate-component/index.ts @@ -85,8 +85,8 @@ const addComponentToNsModuleProviders = (componentInfo: ComponentInfo, options: // check if the {N} version of the @NgModule exists if (!tree.exists(nsModulePath)) { throw new SchematicsException(`Module file [${nsModulePath}] doesn't exist. -Create it if you want the schematic to add ${componentInfo.className} to its' module declarations, -or if you just want to update the component without updating its' module, then rerun this command with --skip-module flag`); +Create it if you want the schematic to add ${componentInfo.className} to its module declarations, +or if you just want to update the component without updating its module, then rerun this command with --skip-module flag`); } // Get the changes required to update the @NgModule diff --git a/src/utils.ts b/src/utils.ts index 917891b..f898719 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -153,10 +153,10 @@ export const renameFilesForce = (paths: FromTo[]) => tree.delete(from); }); -export function createEmptyNsOnlyProject(projectName: string): UnitTestTree { +export function createEmptyNsOnlyProject(projectName: string, extension: string = ''): UnitTestTree { let appTree = schematicRunner.runSchematic("angular-json", { name: projectName, sourceRoot: "src" }); - appTree = createAppModule(appTree, `/src/app/app.module.ts`); + appTree = createAppModule(appTree, `/src/app/app.module${extension}.ts`); appTree.create('/package.json', JSON.stringify({ nativescript: { id: "proj" }, @@ -171,8 +171,9 @@ export function createEmptyNsOnlyProject(projectName: string): UnitTestTree { return appTree; } -export function createEmptySharedProject(projectName: string): UnitTestTree { - let appTree = createEmptyNsOnlyProject(projectName); +export function createEmptySharedProject(projectName: string, webExtension: string = '', nsExtension: string = '.tns'): UnitTestTree { + let appTree = createEmptyNsOnlyProject(projectName, nsExtension); + appTree = createAppModule(appTree, `/src/app/app.module${webExtension}.ts`); appTree.create('/nsconfig.json', JSON.stringify({ "appResourcesPath": "App_Resources",