From ccb48fdf3cf85f76657b4205e85aaeb7288bc6c0 Mon Sep 17 00:00:00 2001 From: Emerson Jair <emerson@zoocha.com> Date: Sun, 17 Mar 2019 03:28:50 -0300 Subject: [PATCH] feat(generators): add angularJson option to app.nest Add the project to angular.json along with a couple of targets. It still misses the test target close #94 --- .../{tsconfig.json => tsconfig__ext__.json} | 0 src/app.nest/index.ts | 73 ++++++++++++++++--- src/app.nest/index_spec.ts | 55 +++++++++++++- src/app.nest/schema.d.ts | 4 + src/app.nest/schema.json | 5 ++ src/utils/general.ts | 15 +++- 6 files changed, 138 insertions(+), 14 deletions(-) rename src/app.nest/_files/{tsconfig.json => tsconfig__ext__.json} (100%) diff --git a/src/app.nest/_files/tsconfig.json b/src/app.nest/_files/tsconfig__ext__.json similarity index 100% rename from src/app.nest/_files/tsconfig.json rename to src/app.nest/_files/tsconfig__ext__.json diff --git a/src/app.nest/index.ts b/src/app.nest/index.ts index dd93eba3..2937aa91 100644 --- a/src/app.nest/index.ts +++ b/src/app.nest/index.ts @@ -11,7 +11,8 @@ import { template, move, Rule, - noop + noop, + externalSchematic } from "@angular-devkit/schematics"; import { NodePackageInstallTask } from "@angular-devkit/schematics/tasks"; import { @@ -27,10 +28,11 @@ import { prerun, applyAppNamingConvention, getAppName, - missingNameArgument + missingNameArgument, + updateJsonInTree } from "../utils"; -export default function(options: ApplicationOptions) { +export default function (options: ApplicationOptions) { if (!options.name) { throw new SchematicsException( missingNameArgument('Provide a name for your Nest app.', 'ng g app.nest sample') @@ -43,6 +45,7 @@ export default function(options: ApplicationOptions) { prerun(options), // adjust naming convention applyAppNamingConvention(options, 'nest'), + options.angularJson ? (tree: Tree) => updateAngularJson(options, tree) : noop(), // create app files (tree: Tree, context: SchematicContext) => addAppFiles(options, appPath)(tree, context), @@ -53,30 +56,31 @@ export default function(options: ApplicationOptions) { const platformApp = options.name.replace('-', '.'); const packageConfig = getJsonFromFile(tree, "package.json"); const scripts = packageConfig.scripts || {}; + const tsConfig = `tsconfig${options.angularJson ? ".app" : ""}.json`; scripts[`serve.${platformApp}`] = `ts-node -P apps/${ options.name - }/tsconfig.json apps/${options.name}/src/main.ts`; + }/${tsConfig} apps/${options.name}/src/main.ts`; scripts[`start.${platformApp}`] = `npm-run-all -p serve.${ platformApp - }`; + }`; scripts[`build.${platformApp}`] = `tsc -p apps/${ options.name - }`; + }/${tsConfig}`; scripts[`test.${platformApp}`] = `jest --config=apps/${ options.name - }/jest.json`; + }/jest.json`; scripts[ `test.${platformApp}.coverage` ] = `jest --config=apps/${ options.name - }/jest.json --coverage --coverageDirectory=coverage`; + }/jest.json --coverage --coverageDirectory=coverage`; scripts[`test.${platformApp}.watch`] = `jest --config=apps/${ options.name - }/jest.json --watch`; + }/jest.json --watch`; scripts[`test.${platformApp}.e2e`] = `jest --config=apps/${ options.name - }/e2e/jest-e2e.json --forceExit`; + }/e2e/jest-e2e.json --forceExit`; scripts[ `test.${platformApp}.e2e.watch` ] = `jest --config=apps/${options.name}/e2e/jest-e2e.json --watch`; @@ -118,10 +122,57 @@ function addAppFiles( utils: stringUtils, npmScope: getNpmScope(), prefix: getPrefix(), - dot: "." + dot: ".", + ext: options.angularJson ? ".app" : "" }), move(`apps/${appPath}`) ]) ) ); } + +type AngularProject = { architect: { build: { options: { assets: any[] } }, test: {}, lint: { options: { tsConfig: string[] } } } } + +/** + * Remove assets option (not created), test target because it does not work + * and spec tsConfig. + * @todo fix the test target + * @param nestProject Project configuration from angular.json + */ +function tweakNxNestArchitect(nestProject: AngularProject) { + delete nestProject.architect.build.options.assets; + delete nestProject.architect.test; + nestProject.architect.lint.options.tsConfig.pop(); + + return nestProject; +} + +/** + * Add Nest project to angular.json along with the architects targets + * @param options + * @param host + */ +function updateAngularJson(options: ApplicationOptions, host: Tree): Rule { + let nestProject: AngularProject; + + return chain( + [ + externalSchematic("@nrwl/schematics", "node-application", { + ...options, + skipInstall: true, + skipFormat: true, + skipPackageJson: true, + framework: "nestjs" + }), + (tree: Tree) => { + const nxAngular: { projects: {} } = JSON.parse(tree.read("/angular.json").toString()); + nestProject = tweakNxNestArchitect(nxAngular.projects[options.name]); + return host; + }, + updateJsonInTree("angular.json", angularJson => { + angularJson.projects[options.name] = nestProject; + return angularJson; + }) + ] + ); +} diff --git a/src/app.nest/index_spec.ts b/src/app.nest/index_spec.ts index b106cb51..c7076ffa 100644 --- a/src/app.nest/index_spec.ts +++ b/src/app.nest/index_spec.ts @@ -3,7 +3,7 @@ import { Schema as ApplicationOptions } from "./schema"; import { SchematicTestRunner } from "@angular-devkit/schematics/testing"; import * as path from "path"; -import { createEmptyWorkspace, getFileContent, jsonParse } from "../utils"; +import { createEmptyWorkspace, getFileContent, jsonParse, getPlatformName } from "../utils"; describe("app.nest schematic", () => { const schematicRunner = new SchematicTestRunner( @@ -62,4 +62,57 @@ describe("app.nest schematic", () => { expect(packageData.scripts["serve.nest.foo"]).toBeDefined(); expect(packageData.scripts["start.nest.foo"]).toBeDefined(); }); + + it("should update angular.json file if angularJson is true", () => { + const options: ApplicationOptions = { ...defaultOptions, angularJson: true }; + const tree = schematicRunner.runSchematic("app.nest", options, appTree); + const files = tree.files; + const projectName = getPlatformName(options.name, "nest"); + + expect( + files.indexOf(`/apps/${projectName}/src/main.ts`) + ).toBeGreaterThanOrEqual(0); + expect( + files.indexOf(`/apps/${projectName}/src/app.service.ts`) + ).toBeGreaterThanOrEqual(0); + expect( + files.indexOf(`/apps/${projectName}/src/app.module.ts`) + ).toBeGreaterThanOrEqual(0); + expect( + files.indexOf(`/apps/${projectName}/src/app.controller.ts`) + ).toBeGreaterThanOrEqual(0); + + let checkPath = `/apps/${projectName}/package.json`; + expect(files.indexOf(checkPath)).toBeGreaterThanOrEqual(0); + + let checkFile = getFileContent(tree, checkPath); + expect(checkFile.indexOf(`"name": "foo"`)).toBeGreaterThanOrEqual(0); + + expect( + files.indexOf("/tools/electron/postinstall.js") + ).toBeGreaterThanOrEqual(0); + expect(files.indexOf("/tools/web/postinstall.js")).toBeGreaterThanOrEqual( + 0 + ); + + checkPath = "/package.json"; + expect(files.indexOf(checkPath)).toBeGreaterThanOrEqual(0); + + checkFile = getFileContent(tree, checkPath); + + const packageData: any = jsonParse(checkFile); + expect(packageData.scripts["serve.nest.foo"]).toBeDefined(); + expect(packageData.scripts["start.nest.foo"]).toBeDefined(); + + expect( + files.indexOf(`/apps/${projectName}/tsconfig.app.json`) + ).toBeGreaterThanOrEqual(0); + + checkPath = "/angular.json"; + expect(files.indexOf(checkPath)).toBeGreaterThanOrEqual(0); + + checkFile = getFileContent(tree, checkPath); + const angularData: { projects: {} } = jsonParse(checkFile); + expect(angularData.projects[projectName]).toBeDefined(); + }) }); diff --git a/src/app.nest/schema.d.ts b/src/app.nest/schema.d.ts index 7cbcd10b..b5a27635 100644 --- a/src/app.nest/schema.d.ts +++ b/src/app.nest/schema.d.ts @@ -19,4 +19,8 @@ export interface Schema { * Skip formatting files */ skipFormat?: boolean; + /** + * Add project to angular.json + */ + angularJson?: boolean; } diff --git a/src/app.nest/schema.json b/src/app.nest/schema.json index bee83b7d..95b2ed2f 100644 --- a/src/app.nest/schema.json +++ b/src/app.nest/schema.json @@ -37,6 +37,11 @@ "description": "Skip formatting files", "type": "boolean", "default": false + }, + "angularJson": { + "description": "Add project to angular.json", + "type": "boolean", + "default": false } }, "required": [] diff --git a/src/utils/general.ts b/src/utils/general.ts index 01e065fa..57d52836 100644 --- a/src/utils/general.ts +++ b/src/utils/general.ts @@ -165,10 +165,21 @@ export function getNxWorkspaceConfig(tree: Tree): any { ); } +/** + * Returns a name with the platform. + * + * @example (app, nest) => web-app or app-web + * @param name + * @param platform + */ +export function getPlatformName(name: string, platform: PlatformTypes) { + const nameSanitized = toFileName(name); + return groupByName ? `${nameSanitized}-${platform}` : `${platform}-${nameSanitized}`; +} + export function applyAppNamingConvention(options: any, platform: PlatformTypes) { return (tree: Tree, context: SchematicContext) => { - const nameSanitized = toFileName(options.name); - options.name = groupByName ? `${nameSanitized}-${platform}` : `${platform}-${nameSanitized}`; + options.name = getPlatformName(options.name, platform); // if command line argument, make sure it's persisted to xplat settings if (options.groupByName) { return updatePackageForXplat(tree, null, {