diff --git a/src/feature/index.ts b/src/feature/index.ts index 7cfeb355..8f644077 100644 --- a/src/feature/index.ts +++ b/src/feature/index.ts @@ -7,7 +7,7 @@ import { mergeWith, Tree, SchematicContext, - // SchematicsException, + SchematicsException, branchAndMerge, // schematic, Rule, @@ -27,21 +27,26 @@ import { generatorError, optionsMissingError, unsupportedPlatformError, - formatFiles + formatFiles, + supportedSandboxPlatforms, + PlatformTypes, + createOrUpdate } from "../utils"; import { Schema as featureOptions } from "./schema"; import * as ts from "typescript"; +import { getFileContent } from "@schematics/angular/utility/test"; +import { capitalize } from "@angular-devkit/core/src/utils/strings"; let featureName: string; let projectNames: Array; export default function(options: featureOptions) { if (!options.name) { - throw new Error( + throw new SchematicsException( `You did not specify the name of the feature you'd like to generate. For example: ng g feature my-feature` ); } if (options.routing && !options.onlyProject) { - throw new Error( + throw new SchematicsException( `When generating a feature with the --routing option, please also specify --onlyProject. Support for shared code routing is under development and will be available in the future.` ); } @@ -66,17 +71,15 @@ export default function(options: featureOptions) { platforms = options.platforms.split(","); } if (platforms.length === 0) { - let error = projects - ? platformAppPrefixError() - : generatorError('feature'); - throw new Error(optionsMissingError(error)); + let error = projects ? platformAppPrefixError() : generatorError("feature"); + throw new SchematicsException(optionsMissingError(error)); } const targetPlatforms: ITargetPlatforms = {}; for (const t of platforms) { if (supportedPlatforms.includes(t)) { targetPlatforms[t] = true; } else { - throw new Error(unsupportedPlatformError(t)); + throw new SchematicsException(unsupportedPlatformError(t)); } } @@ -87,11 +90,9 @@ export default function(options: featureOptions) { let srcDir = platPrefix !== "nativescript" ? "src/" : ""; // check for 2 different naming conventions on routing modules const routingModulePathOptions = []; - const routingModulePath = `apps/${projectName}/${srcDir}app/`; - routingModulePathOptions.push(`${routingModulePath}app.routing.ts`); - routingModulePathOptions.push( - `${routingModulePath}app-routing.module.ts` - ); + const appDirectory = `apps/${projectName}/${srcDir}app/`; + routingModulePathOptions.push(`${appDirectory}app.routing.ts`); + routingModulePathOptions.push(`${appDirectory}app-routing.module.ts`); projectChains.push((tree: Tree, context: SchematicContext) => { return addFiles(options, platPrefix, projectName)(tree, context); @@ -103,6 +104,14 @@ export default function(options: featureOptions) { context ); }); + if (options.adjustSandbox) { + projectChains.push((tree: Tree, context: SchematicContext) => { + return adjustSandbox(platPrefix, appDirectory)( + tree, + context + ); + }); + } } if (!options.onlyModule) { projectChains.push((tree: Tree, context: SchematicContext) => { @@ -164,7 +173,9 @@ export default function(options: featureOptions) { : noop()(tree, context), // add starting component unless onlyModule (tree: Tree, context: SchematicContext) => - !options.onlyProject && !options.onlyModule && targetPlatforms.nativescript + !options.onlyProject && + !options.onlyModule && + targetPlatforms.nativescript ? addFiles(options, "nativescript", null, "_component")(tree, context) : noop()(tree, context), // ionic @@ -184,9 +195,7 @@ export default function(options: featureOptions) { : noop()(tree, context), // project handling ...projectChains, - options.skipFormat - ? noop() - : formatFiles(options) + options.skipFormat ? noop() : formatFiles(options) ]); } @@ -303,3 +312,36 @@ function adjustRouting( return host; }; } + +function adjustSandbox(platform: PlatformTypes, appDirectory: string): Rule { + return (tree: Tree) => { + if (supportedSandboxPlatforms.includes(platform)) { + const homeCmpPath = `${appDirectory}/features/home/components/home.component.html`; + let homeTemplate = getFileContent(tree, homeCmpPath); + switch (platform) { + case "nativescript": + let buttonEndIndex = homeTemplate.indexOf(""); + if (buttonEndIndex === -1) { + // check for lowercase + buttonEndIndex = homeTemplate.indexOf(""); + } + const featureNameParts = featureName.split("-"); + let routeName = featureName; + if (featureNameParts.length > 1) { + routeName = capitalize(featureNameParts[featureNameParts.length - 1]); + } + homeTemplate = + homeTemplate.slice(0, buttonEndIndex + 9) + + `` + + homeTemplate.slice(buttonEndIndex + 9); + break; + } + createOrUpdate(tree, homeCmpPath, homeTemplate); + } else { + throw new SchematicsException( + `The --adjustSandbox option is only supported on the following at the moment: ${supportedSandboxPlatforms}` + ); + } + return tree; + }; +} diff --git a/src/feature/index_spec.ts b/src/feature/index_spec.ts index 95edbea7..4bb23cbd 100644 --- a/src/feature/index_spec.ts +++ b/src/feature/index_spec.ts @@ -4,7 +4,7 @@ import { getFileContent } from '@schematics/angular/utility/test'; import * as path from 'path'; import { Schema as FeatureOptions } from './schema'; -import { createXplatWithApps, isInModuleMetadata } from '../utils'; +import { createXplatWithApps, isInModuleMetadata, createOrUpdate } from '../utils'; describe('feature schematic', () => { const schematicRunner = new SchematicTestRunner( @@ -348,4 +348,48 @@ describe('feature schematic', () => { expect(featureModule).toMatch(`export const FOOWITHDASH_COMPONENTS`); }); + + it('should create feature module for specified project WITH Routing and adjustSandbox', () => { + const options: FeatureOptions = { + ...defaultOptions, + projects: 'nativescript-viewer' + }; + let tree = schematicRunner.runSchematic('xplat', { + prefix: 'tt', + sample: true, + platforms: 'nativescript' + }, appTree); + tree = schematicRunner.runSchematic('app.nativescript', { + name: 'viewer', + prefix: 'tt', + routing: true + }, tree); + + // manually update home.component to prep for sandobx + const homeCmpPath = `/apps/nativescript-viewer/app/features/home/components/home.component.html`; + createOrUpdate(tree, homeCmpPath, sandboxHomeSetup()); + // console.log('homecmp:', getFileContent(tree, homeCmpPath)); + + options.onlyProject = true; + options.adjustSandbox = true; + options.routing = true; + options.name = 'foo-with-dash'; + tree = schematicRunner.runSchematic('feature', options, tree); + // console.log('---------') + // console.log('homecmp:', getFileContent(tree, homeCmpPath)); + + }); }); + +export function sandboxHomeSetup() { + return ` + + + + + + + + +`; +} diff --git a/src/feature/schema.d.ts b/src/feature/schema.d.ts index f0add441..0d3014f1 100644 --- a/src/feature/schema.d.ts +++ b/src/feature/schema.d.ts @@ -24,6 +24,10 @@ export interface Schema { * Configure routing */ routing?: boolean; + /** + * Add link to route for sandbox + */ + adjustSandbox?: boolean; /** * Skip formatting */ diff --git a/src/feature/schema.json b/src/feature/schema.json index b3bba40f..f333e6c8 100644 --- a/src/feature/schema.json +++ b/src/feature/schema.json @@ -39,6 +39,11 @@ "type": "boolean", "default": false }, + "adjustSandbox": { + "type": "boolean", + "description": "Automatically add a button to link to the feature route. Supported on NativeScript only right now. Requires flags: --onlyProject --routing", + "default": false + }, "skipFormat": { "description": "Skip formatting files", "type": "boolean", diff --git a/src/utils/general.ts b/src/utils/general.ts index fcc477bf..371b9272 100644 --- a/src/utils/general.ts +++ b/src/utils/general.ts @@ -56,6 +56,8 @@ export interface NodeDependency { // list of all supported helpers // TODO: add more convenient helpers (like firebase or Travis ci support files) export const supportedHelpers = ['imports', 'applitools']; +// list of platforms that support adjustSandbox flag +export const supportedSandboxPlatforms: Array = ['nativescript']; let npmScope: string; // selector prefix to use when generating various boilerplate for xplat support