From 2958f503f707310ac3319f38dc34dd015ffc110d Mon Sep 17 00:00:00 2001 From: Jason Jean Date: Sun, 26 May 2019 12:09:10 -0400 Subject: [PATCH] fix(frontend): fix react component for apps --- packages/react/collection.json | 3 +- .../schematics/component/component.spec.ts | 58 ++++----- .../src/schematics/component/component.ts | 116 +++++++++++------- packages/react/src/utils/testing.ts | 38 ++++++ 4 files changed, 140 insertions(+), 75 deletions(-) diff --git a/packages/react/collection.json b/packages/react/collection.json index 665363abeb992..b21da006c3953 100644 --- a/packages/react/collection.json +++ b/packages/react/collection.json @@ -27,7 +27,8 @@ "component": { "factory": "./src/schematics/component/component", "schema": "./src/schematics/component/schema.json", - "description": "Create a component" + "description": "Create a component", + "aliases": "c" } } } diff --git a/packages/react/src/schematics/component/component.spec.ts b/packages/react/src/schematics/component/component.spec.ts index 0e11e11739ec7..e684076af6682 100644 --- a/packages/react/src/schematics/component/component.spec.ts +++ b/packages/react/src/schematics/component/component.spec.ts @@ -1,18 +1,18 @@ import { Tree } from '@angular-devkit/schematics'; import { createEmptyWorkspace } from '@nrwl/workspace/testing'; -import { runSchematic } from '../../utils/testing'; -import { names } from '@nrwl/workspace/src/utils/name-utils'; +import { runSchematic, createApp, createLib } from '../../utils/testing'; import { readJsonInTree } from '@nrwl/workspace/src/utils/ast-utils'; describe('component', () => { let appTree: Tree; let projectName: string; - beforeEach(() => { + beforeEach(async () => { projectName = 'my-lib'; appTree = Tree.empty(); appTree = createEmptyWorkspace(appTree); - appTree = createLib(appTree, projectName); + appTree = await createApp(appTree, 'my-app'); + appTree = await createLib(appTree, projectName); }); it('should generate files', async () => { @@ -29,6 +29,20 @@ describe('component', () => { expect(tree.exists('libs/my-lib/src/lib/hello/hello.css')).toBeTruthy(); }); + it('should generate files for an app', async () => { + const tree = await runSchematic( + 'component', + { name: 'hello', project: 'my-app' }, + appTree + ); + + expect(tree.exists('apps/my-app/src/app/hello/hello.tsx')).toBeTruthy(); + expect( + tree.exists('apps/my-app/src/app/hello/hello.spec.tsx') + ).toBeTruthy(); + expect(tree.exists('apps/my-app/src/app/hello/hello.css')).toBeTruthy(); + }); + describe('--export', () => { it('should add to index.ts barrel', async () => { const tree = await runSchematic( @@ -41,6 +55,18 @@ describe('component', () => { expect(indexContent).toMatch(/lib\/hello\/hello/); }); + + it('should not export from an app', async () => { + const tree = await runSchematic( + 'component', + { name: 'hello', project: 'my-app', export: true }, + appTree + ); + + const indexContent = tree.read('libs/my-lib/src/index.ts').toString(); + + expect(indexContent).not.toMatch(/lib\/hello\/hello/); + }); }); describe('--pascalCaseFiles', () => { @@ -123,27 +149,3 @@ describe('component', () => { }); }); }); - -export function createLib(tree: Tree, libName: string): Tree { - const { fileName } = names(libName); - - tree.create(`/libs/${fileName}/src/index.ts`, `\n`); - - tree.overwrite( - '/angular.json', - ` -{ - "projects": { - "${libName}": { - "root": "libs/${fileName}", - "sourceRoot": "libs/${fileName}/src", - "projectType": "library", - "schematics": {} - } - } -} -` - ); - - return tree; -} diff --git a/packages/react/src/schematics/component/component.ts b/packages/react/src/schematics/component/component.ts index 7a85fdff03002..150ed3d09770c 100644 --- a/packages/react/src/schematics/component/component.ts +++ b/packages/react/src/schematics/component/component.ts @@ -8,12 +8,13 @@ import { move, noop, Rule, + SchematicContext, template, Tree, url } from '@angular-devkit/schematics'; import { Schema } from './schema'; -import { names } from '@nrwl/workspace'; +import { getWorkspace, names, formatFiles } from '@nrwl/workspace'; import { addDepsToPackageJson, addGlobal, @@ -21,7 +22,6 @@ import { insert } from '@nrwl/workspace/src/utils/ast-utils'; import { CSS_IN_JS_DEPENDENCIES } from '../../utils/styled'; -import { formatFiles } from '@nrwl/workspace'; interface NormalizedSchema extends Schema { projectSourceRoot: Path; @@ -31,8 +31,8 @@ interface NormalizedSchema extends Schema { } export default function(schema: Schema): Rule { - return (host: Tree) => { - const options = normalizeOptions(host, schema); + return (host: Tree, context: SchematicContext) => { + const options = normalizeOptions(host, schema, context); return chain([ createComponentFiles(options), addStyledModuleDependencies(options), @@ -43,19 +43,29 @@ export default function(schema: Schema): Rule { } function createComponentFiles(options: NormalizedSchema): Rule { - return mergeWith( - apply(url(`./files`), [ - template({ - ...options, - tmpl: '' - }), - options.skipTests ? filter(file => !/.*spec.tsx/.test(file)) : noop(), - options.styledModule - ? filter(file => !file.endsWith(`.${options.style}`)) - : noop(), - move(join(options.projectSourceRoot, 'lib')) - ]) - ); + return async (host: Tree, context: SchematicContext) => { + const workspace = await getWorkspace(host); + const directory = join( + options.projectSourceRoot, + workspace.projects.get(options.project).extensions.projectType === + 'application' + ? 'app' + : 'lib' + ); + return mergeWith( + apply(url(`./files`), [ + template({ + ...options, + tmpl: '' + }), + options.skipTests ? filter(file => !/.*spec.tsx/.test(file)) : noop(), + options.styledModule + ? filter(file => !file.endsWith(`.${options.style}`)) + : noop(), + move(directory) + ]) + ); + }; } function addStyledModuleDependencies(options: NormalizedSchema): Rule { @@ -70,48 +80,62 @@ function addStyledModuleDependencies(options: NormalizedSchema): Rule { } function addExportsToBarrel(options: NormalizedSchema): Rule { - return options.export - ? (host: Tree) => { - const indexFilePath = join(options.projectSourceRoot, 'index.ts'); - const buffer = host.read(indexFilePath); - - if (!!buffer) { - const indexSource = buffer!.toString('utf-8'); - const indexSourceFile = ts.createSourceFile( - indexFilePath, - indexSource, - ts.ScriptTarget.Latest, - true - ); + return async (host: Tree) => { + const workspace = await getWorkspace(host); + const isApp = + workspace.projects.get(options.project).extensions.type === 'application'; + return options.export && !isApp + ? (host: Tree) => { + const indexFilePath = join(options.projectSourceRoot, 'index.ts'); + const buffer = host.read(indexFilePath); + if (!!buffer) { + const indexSource = buffer!.toString('utf-8'); + const indexSourceFile = ts.createSourceFile( + indexFilePath, + indexSource, + ts.ScriptTarget.Latest, + true + ); - insert( - host, - indexFilePath, - addGlobal( - indexSourceFile, + insert( + host, indexFilePath, - `export { default as ${options.className}, ${ - options.className - }Props } from './lib/${options.name}/${options.fileName}';` - ) - ); - } + addGlobal( + indexSourceFile, + indexFilePath, + `export { default as ${options.className}, ${ + options.className + }Props } from './lib/${options.name}/${options.fileName}';` + ) + ); + } - return host; - } - : noop(); + return host; + } + : noop(); + }; } -function normalizeOptions(host: Tree, options: Schema): NormalizedSchema { +function normalizeOptions( + host: Tree, + options: Schema, + context: SchematicContext +): NormalizedSchema { const { className, fileName } = names(options.name); const componentFileName = options.pascalCaseFiles ? className : fileName; - const { sourceRoot: projectSourceRoot } = getProjectConfig( + const { sourceRoot: projectSourceRoot, projectType } = getProjectConfig( host, options.project ); + if (options.export && projectType === 'application') { + context.logger.warn( + `The "--export" option should not be used with applications and will do nothing.` + ); + } + const styledModule = /^(css|scss|less|styl)$/.test(options.style) ? null : options.style; diff --git a/packages/react/src/utils/testing.ts b/packages/react/src/utils/testing.ts index 5f4d715322c13..04eceb869a52e 100644 --- a/packages/react/src/utils/testing.ts +++ b/packages/react/src/utils/testing.ts @@ -1,6 +1,8 @@ import { join } from 'path'; import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; import { Rule, Tree } from '@angular-devkit/schematics'; +import { names } from '@nrwl/workspace/src/utils/name-utils'; +import { updateWorkspace } from '@nrwl/workspace/src/utils/workspace'; const testRunner = new SchematicTestRunner( '@nrwl/react', @@ -14,3 +16,39 @@ export function runSchematic(schematicName: string, options: any, tree: Tree) { export function callRule(rule: Rule, tree: Tree) { return testRunner.callRule(rule, tree).toPromise(); } + +export function createApp(tree: Tree, appName: string): Promise { + const { fileName } = names(appName); + + return callRule( + updateWorkspace(workspace => { + workspace.projects.add({ + name: fileName, + root: `apps/${fileName}`, + projectType: 'application', + sourceRoot: `apps/${fileName}/src`, + targets: {} + }); + }), + tree + ); +} + +export function createLib(tree: Tree, libName: string): Promise { + const { fileName } = names(libName); + + tree.create(`/libs/${fileName}/src/index.ts`, `\n`); + + return callRule( + updateWorkspace(workspace => { + workspace.projects.add({ + name: fileName, + root: `libs/${fileName}`, + projectType: 'library', + sourceRoot: `libs/${fileName}/src`, + targets: {} + }); + }), + tree + ); +}