UNPKG

@yolkai/nx-workspace

Version:

Extensible Dev Tools for Monorepos

262 lines (242 loc) 9.07 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const schematics_1 = require("@angular-devkit/schematics"); const ast_utils_1 = require("../../utils/ast-utils"); const format_files_1 = require("../../utils/rules/format-files"); const ts = require("typescript"); const name_utils_1 = require("@yolkai/nx-workspace/src/utils/name-utils"); function default_1(options) { options = normalizeOptions(options); return (host, context) => { return schematics_1.chain([createPreset(options), format_files_1.formatFiles()])(host, context); }; } exports.default = default_1; function createPreset(options) { const linter = options.cli === 'angular' ? 'tslint' : 'eslint'; if (options.preset === 'empty') { return schematics_1.noop(); } else if (options.preset === 'angular') { return schematics_1.chain([ schematics_1.externalSchematic('@yolkai/nx-angular', 'application', { name: options.name, style: options.style }, { interactive: false }), setDefaultCollection('@yolkai/nx-angular') ]); } else if (options.preset === 'react') { return schematics_1.chain([ schematics_1.externalSchematic('@yolkai/nx-react', 'application', { name: options.name, style: options.style, linter }, { interactive: false }), setDefaultCollection('@yolkai/nx-react') ]); } else if (options.preset === 'next') { return schematics_1.chain([ schematics_1.externalSchematic('@yolkai/nx-next', 'application', { name: options.name, style: options.style, linter }, { interactive: false }), setDefaultCollection('@yolkai/nx-next') ]); } else if (options.preset === 'web-components') { return schematics_1.chain([ schematics_1.externalSchematic('@yolkai/nx-web', 'application', { name: options.name, style: options.style, linter }, { interactive: false }), setDefaultCollection('@yolkai/nx-web') ]); } else if (options.preset === 'angular-nest') { return schematics_1.chain([ schematics_1.externalSchematic('@yolkai/nx-angular', 'application', { name: options.name, style: options.style }, { interactive: false }), schematics_1.externalSchematic('@yolkai/nx-nest', 'application', { name: 'api', frontendProject: options.name }, { interactive: false }), schematics_1.schematic('library', { name: 'api-interfaces' }, { interactive: false }), setDefaultCollection('@yolkai/nx-angular'), connectAngularAndNest(options) ]); } else if (options.preset === 'react-express') { return schematics_1.chain([ schematics_1.externalSchematic('@yolkai/nx-react', 'application', { name: options.name, style: options.style, linter }, { interactive: false }), schematics_1.externalSchematic('@yolkai/nx-express', 'application', { name: 'api', frontendProject: options.name, linter }, { interactive: false }), schematics_1.schematic('library', { name: 'api-interfaces', linter }, { interactive: false }), setDefaultCollection('@yolkai/nx-react'), connectReactAndExpress(options) ]); } else { throw new Error(`Invalid preset ${options.preset}`); } } function connectAngularAndNest(options) { const addImportToModule = require('@yolkai/nx-angular/src/utils/ast-utils') .addImportToModule; return (host) => { host.overwrite('libs/api-interfaces/src/lib/api-interfaces.ts', `export interface Message { message: string }`); const modulePath = `apps/${options.name}/src/app/app.module.ts`; const moduleFile = ts.createSourceFile(modulePath, host.read(modulePath).toString(), ts.ScriptTarget.Latest, true); ast_utils_1.insert(host, modulePath, [ ast_utils_1.insertImport(moduleFile, modulePath, 'HttpClientModule', `@angular/common/http`), ...addImportToModule(moduleFile, `@angular/common/http`, `HttpClientModule`) ]); const scope = options.npmScope; const style = options.style ? options.style : 'css'; host.overwrite(`apps/${options.name}/src/app/app.component.ts`, `import { Component } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Message } from '@${scope}/api-interfaces'; @Component({ selector: '${scope}-root', templateUrl: './app.component.html', styleUrls: ['./app.component.${style}'] }) export class AppComponent { hello$ = this.http.get<Message>('/api/hello') constructor(private http: HttpClient) {} } `); host.overwrite(`apps/${options.name}/src/app/app.component.spec.ts`, `import { Component } from '@angular/core'; import { TestBed, async } from '@angular/core/testing'; import { HttpClientModule } from '@angular/common/http'; import { AppComponent } from './app.component'; describe('AppComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [AppComponent], imports: [HttpClientModule] }).compileComponents(); })); it('should create the app', () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.debugElement.componentInstance; expect(app).toBeTruthy(); }); }); `); host.overwrite(`apps/${options.name}/src/app/app.component.html`, `<div style="text-align:center"> <h1>Welcome to ${options.name}!</h1> <img width="450" src="https://raw.githubusercontent.com/nrwl/nx/master/nx-logo.png" /> </div> <div>Message: {{ (hello$|async)|json }}</div> `); host.overwrite(`apps/api/src/app/app.controller.ts`, `import { Controller, Get } from '@nestjs/common'; import { Message } from '@${scope}/api-interfaces'; import { AppService } from './app.service'; @Controller() export class AppController { constructor(private readonly appService: AppService) {} @Get('hello') getData(): Message { return this.appService.getData(); } } `); host.overwrite(`apps/api/src/app/app.service.ts`, `import { Injectable } from '@nestjs/common'; import { Message } from '@${scope}/api-interfaces'; @Injectable() export class AppService { getData(): Message { return { message: 'Welcome to api!' }; } } `); }; } function connectReactAndExpress(options) { return (host) => { const scope = options.npmScope; host.overwrite('libs/api-interfaces/src/lib/api-interfaces.ts', `export interface Message { message: string }`); host.overwrite(`apps/${options.name}/src/app/app.tsx`, `import React, { useEffect, useState } from 'react'; import { Message } from '@${scope}/api-interfaces'; export const App = () => { const [m, setMessage] = useState<Message>({ message: '' }); useEffect(() => { fetch('/api') .then(r => r.json()) .then(setMessage); }, []); return ( <> <div style={{ textAlign: 'center' }}> <h1>Welcome to ${options.name}!</h1> <img width="450" src="https://raw.githubusercontent.com/nrwl/nx/master/nx-logo.png" /> </div> <div>{m.message}</div> </> ); }; export default App; `); host.overwrite(`apps/${options.name}/src/app/app.spec.tsx`, `import { cleanup, getByText, render, wait } from '@testing-library/react'; import React from 'react'; import App from './app'; describe('App', () => { afterEach(() => { delete global['fetch']; cleanup(); }); it('should render successfully', async () => { global['fetch'] = jest.fn().mockResolvedValueOnce({ json: () => ({ message: 'my message' }) }); const { baseElement } = render(<App />); await wait(() => getByText(baseElement, 'my message')); }); }); `); host.overwrite(`apps/api/src/main.ts`, `import * as express from 'express'; import { Message } from '@${scope}/api-interfaces'; const app = express(); const greeting: Message = { message: 'Welcome to api!' }; app.get('/api', (req, res) => { res.send(greeting); }); const port = process.env.port || 3333; const server = app.listen(port, () => { console.log('Listening at http://localhost:' + port + '/api'); }); server.on('error', console.error); `); }; } function setDefaultCollection(defaultCollection) { return ast_utils_1.updateWorkspaceInTree(json => { if (!json.cli) { json.cli = {}; } json.cli.defaultCollection = defaultCollection; return json; }); } function normalizeOptions(options) { options.name = name_utils_1.toFileName(options.name); return options; }