UNPKG

ohayolibs

Version:

Ohayo is a set of essential modules for ohayojp.

484 lines (444 loc) 16.5 kB
import { strings } from '@angular-devkit/core'; import { apply, chain, filter, MergeStrategy, mergeWith, move, noop, Rule, SchematicContext, template, Tree, url, } from '@angular-devkit/schematics'; import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'; import * as path from 'path'; import { getLangData } from '../core/lang.config'; import { tryAddFile } from '../utils/ohayo'; import { HMR_CONTENT } from '../utils/contents'; import { addFiles } from '../utils/file'; import { addHeadStyle, addHtmlToBody } from '../utils/html'; import { addAllowedCommonJsDependencies, addPackageToPackageJson, getAngular, getJSON, getPackage, overwriteAngular, overwriteJSON, overwritePackage, scriptsToAngularJson, } from '../utils/json'; import { VERSION, ZORROVERSION } from '../utils/lib-versions'; import { getProject, getProjectFromWorkspace, Project } from '../utils/project'; import { Schema as ApplicationOptions } from './schema'; const overwriteDataFileRoot = path.join(__dirname, 'overwrites'); let project: Project; /** Remove files to be overwrite */ function removeOrginalFiles(): (host: Tree) => void { return (host: Tree) => { [ `${project.root}/README.md`, `${project.root}/tslint.json`, `${project.sourceRoot}/main.ts`, `${project.sourceRoot}/environments/environment.prod.ts`, `${project.sourceRoot}/environments/environment.ts`, `${project.sourceRoot}/styles.less`, `${project.sourceRoot}/app/app.module.ts`, `${project.sourceRoot}/app/app.component.spec.ts`, `${project.sourceRoot}/app/app.component.ts`, `${project.sourceRoot}/app/app.component.html`, `${project.sourceRoot}/app/app.component.less`, ] .filter(p => host.exists(p)) .forEach(p => host.delete(p)); }; } function fixMain(): (host: Tree) => void { return (host: Tree) => { // fix: main.ts using no hmr file tryAddFile(host, `${project.sourceRoot}/main.ts`, HMR_CONTENT.NO_HMR_MAIN_DOT_TS); }; } function fixAngularJson(options: ApplicationOptions): (host: Tree) => void { return (host: Tree) => { const json = getAngular(host); const _project = getProjectFromWorkspace(json, options.project); // Add proxy.conf.json (_project.targets || _project.architect)!.serve!.options.proxyConfig = 'proxy.conf.json'; overwriteAngular(host, json); return host; }; } function addDependenciesToPackageJson(options: ApplicationOptions): (host: Tree) => void { return (host: Tree) => { // 3rd addPackageToPackageJson(host, [ // allow ignore ng-zorro-antd becauce of @ohayo/theme dependency `ng-zorro-antd@${ZORROVERSION}`, // ng-zorro-antd need 'screenfull@DEP-0.0.0-PLACEHOLDER', 'ajv@DEP-0.0.0-PLACEHOLDER', ]); // add ajv scriptsToAngularJson(host, ['node_modules/ajv/dist/ajv.bundle.js'], 'add', ['build', 'test']); // @ohayo/* addPackageToPackageJson( host, ['components', 'acl', 'auth', 'cache', 'form', 'mock', 'theme', 'util', 'chart'].map(pkg => `@ohayo/${pkg}@${VERSION}`), ); // ohayojp addPackageToPackageJson( host, [ `ohayojp@${VERSION}`, `ohayojp-codelyzer@DEP-0.0.0-PLACEHOLDER`, `ng-alain-plugin-theme@DEP-0.0.0-PLACEHOLDER`, `@ohayo/testing@${VERSION}`, ], 'devDependencies', ); // i18n if (options.i18n) { addPackageToPackageJson(host, [`@ngx-translate/core@DEP-0.0.0-PLACEHOLDER`, `@ngx-translate/http-loader@DEP-0.0.0-PLACEHOLDER`]); } // Configuring CommonJS dependencies // https://angular.io/guide/build#configuring-commonjs-dependencies addAllowedCommonJsDependencies(host); return host; }; } function addRunScriptToPackageJson(): (host: Tree) => void { return (host: Tree) => { const json = getPackage(host, 'scripts'); if (json == null) return host; json.scripts.start = `ng s -o`; json.scripts.build = `node --max_old_space_size=5120 ./node_modules/@angular/cli/bin/ng build --prod`; json.scripts.analyze = `node --max_old_space_size=5120 ./node_modules/@angular/cli/bin/ng build --prod --stats-json`; json.scripts['test-coverage'] = `ng test --code-coverage --watch=false`; json.scripts['color-less'] = `ng-alain-plugin-theme -t=colorLess`; json.scripts.theme = `ng-alain-plugin-theme -t=themeCss`; json.scripts.icon = `ng g ohayojp:plugin icon`; overwritePackage(host, json); return host; }; } function addPathsToTsConfig(): (host: Tree) => Tree { return (host: Tree) => { const json = getJSON(host, 'tsconfig.json', 'compilerOptions'); if (json == null) return host; if (!json.compilerOptions) json.compilerOptions = {}; if (!json.compilerOptions.paths) json.compilerOptions.paths = {}; const paths = json.compilerOptions.paths; paths['@shared'] = ['src/app/shared/index']; paths['@core'] = ['src/app/core/index']; paths['@env/*'] = ['src/environments/*']; overwriteJSON(host, 'tsconfig.json', json); return host; }; } function addCodeStylesToPackageJson(): (host: Tree) => Tree { return (host: Tree) => { const json = getPackage(host); if (json == null) return host; json.scripts.lint = `npm run lint:ts && npm run lint:style`; json.scripts['lint:ts'] = `ng lint --fix`; json.scripts['lint:style'] = `stylelint \"src/**/*.less\" --syntax less --fix`; json.scripts['pretty-quick'] = `pretty-quick`; json.scripts['tslint-check'] = `tslint-config-prettier-check ./tslint.json`; overwritePackage(host, json); // dependencies addPackageToPackageJson( host, [ `tslint-config-prettier@DEP-0.0.0-PLACEHOLDER`, `tslint-language-service@DEP-0.0.0-PLACEHOLDER`, `pretty-quick@DEP-0.0.0-PLACEHOLDER`, `husky@DEP-0.0.0-PLACEHOLDER`, `prettier@DEP-0.0.0-PLACEHOLDER`, `stylelint@DEP-0.0.0-PLACEHOLDER`, `stylelint-config-prettier@DEP-0.0.0-PLACEHOLDER`, `stylelint-config-rational-order@DEP-0.0.0-PLACEHOLDER`, `stylelint-config-standard@DEP-0.0.0-PLACEHOLDER`, `stylelint-declaration-block-no-ignored-properties@DEP-0.0.0-PLACEHOLDER`, `stylelint-order@DEP-0.0.0-PLACEHOLDER`, ], 'devDependencies', ); return host; }; } function addSchematics(): (host: Tree) => Tree { return (host: Tree) => { const angularJsonFile = 'angular.json'; const json = getJSON(host, angularJsonFile, 'schematics'); if (json == null) return host; json.schematics['ohayojp:module'] = { routing: true, spec: false, }; json.schematics['ohayojp:list'] = { spec: false, }; json.schematics['ohayojp:edit'] = { spec: false, modal: true, }; json.schematics['ohayojp:view'] = { spec: false, modal: true, }; json.schematics['ohayojp:curd'] = { spec: false, }; json.schematics['@schematics/angular:module'] = { routing: true, spec: false, }; json.schematics['@schematics/angular:component'] = { spec: false, flat: false, inlineStyle: true, inlineTemplate: false, }; json.schematics['@schematics/angular:directive'] = { spec: false, }; json.schematics['@schematics/angular:service'] = { spec: false, }; overwriteJSON(host, angularJsonFile, json); }; } function addNzLintRules(): (host: Tree) => void { return (host: Tree) => { addPackageToPackageJson(host, ['nz-tslint-rules@DEP-0.0.0-PLACEHOLDER'], 'devDependencies'); const json = getJSON(host, 'tslint.json'); if (json == null) return host; json.rulesDirectory.push(`nz-tslint-rules`); json.rules['nz-secondary-entry-imports'] = true; overwriteJSON(host, 'tslint.json', json); return host; }; } function forceLess(): (host: Tree) => void { return (host: Tree) => { scriptsToAngularJson(host, ['src/styles.less'], 'add', ['build'], null!, true); }; } function addStyle(): (host: Tree) => Tree { return (host: Tree) => { addHeadStyle( host, project, ` <style type="text/css">.preloader{position:fixed;top:0;left:0;width:100%;height:100%;overflow:hidden;background:#49a9ee;z-index:9999;transition:opacity .65s}.preloader-hidden-add{opacity:1;display:block}.preloader-hidden-add-active{opacity:0}.preloader-hidden{display:none}.cs-loader{position:absolute;top:0;left:0;height:100%;width:100%}.cs-loader-inner{transform:translateY(-50%);top:50%;position:absolute;width:100%;color:#fff;text-align:center}.cs-loader-inner label{font-size:20px;opacity:0;display:inline-block}@keyframes lol{0%{opacity:0;transform:translateX(-300px)}33%{opacity:1;transform:translateX(0)}66%{opacity:1;transform:translateX(0)}100%{opacity:0;transform:translateX(300px)}}.cs-loader-inner label:nth-child(6){animation:lol 3s infinite ease-in-out}.cs-loader-inner label:nth-child(5){animation:lol 3s .1s infinite ease-in-out}.cs-loader-inner label:nth-child(4){animation:lol 3s .2s infinite ease-in-out}.cs-loader-inner label:nth-child(3){animation:lol 3s .3s infinite ease-in-out}.cs-loader-inner label:nth-child(2){animation:lol 3s .4s infinite ease-in-out}.cs-loader-inner label:nth-child(1){animation:lol 3s .5s infinite ease-in-out}</style>`, ); addHtmlToBody( host, project, ` <div class="preloader"><div class="cs-loader"><div class="cs-loader-inner"><label> ●</label><label> ●</label><label> ●</label><label> ●</label><label> ●</label><label> ●</label></div></div></div>\n`, ); // add styles addFiles(host, [`${project.sourceRoot}/styles/index.less`, `${project.sourceRoot}/styles/theme.less`], overwriteDataFileRoot); return host; }; } function mergeFiles(options: ApplicationOptions, from: string, to: string): Rule { return mergeWith( apply(url(from), [ options.i18n ? noop() : filter(p => p.indexOf('i18n') === -1), options.form ? noop() : filter(p => p.indexOf('json-schema') === -1), template({ utils: strings, ...options, dot: '.', VERSION, ZORROVERSION, }), move(to), ]), ); } function addCliTpl(): (host: Tree) => void { const TPLS = { '__name@dasherize__.component.html': `<page-header></page-header>`, '__name@dasherize__.component.ts': `import { Component, OnInit<% if(!!viewEncapsulation) { %>, ViewEncapsulation<% }%><% if(changeDetection !== 'Default') { %>, ChangeDetectionStrategy<% }%> } from '@angular/core'; import { _HttpClient } from '@ohayo/theme'; import { NzMessageService } from 'ng-zorro-antd/message'; @Component({ selector: '<%= selector %>', templateUrl: './<%= dasherize(name) %>.component.html',<% if(!inlineStyle) { %><% } else { %> styleUrls: ['./<%= dasherize(name) %>.component.<%= style %>']<% } %><% if(!!viewEncapsulation) { %>, encapsulation: ViewEncapsulation.<%= viewEncapsulation %><% } if (changeDetection !== 'Default') { %>, changeDetection: ChangeDetectionStrategy.<%= changeDetection %><% } %> }) export class <%= componentName %> implements OnInit { constructor(private http: _HttpClient, private msg: NzMessageService) { } ngOnInit() { } } `, '__name@dasherize__.component.spec.ts': `import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { <%= componentName %> } from './<%= dasherize(name) %>.component'; describe('<%= componentName %>', () => { let component: <%= componentName %>; let fixture: ComponentFixture<<%= componentName %>>; beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ <%= componentName %> ] }) .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(<%= componentName %>); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); }); `, }; return (host: Tree) => { const prefix = `${project.root}/_cli-tpl/test/__path__/__name@dasherize@if-flat__/`; Object.keys(TPLS).forEach(name => { const realPath = prefix + name; if (host.exists(realPath)) { host.overwrite(realPath, TPLS[name]); } else { host.create(realPath, TPLS[name]); } }); }; } function addFilesToRoot(options: ApplicationOptions): Rule { return chain([ mergeWith( apply(url('./files/src'), [ options.i18n ? noop() : filter(p => p.indexOf('i18n') === -1), options.form ? noop() : filter(p => p.indexOf('json-schema') === -1), template({ utils: strings, ...options, dot: '.', VERSION, ZORROVERSION, }), move(project.sourceRoot), ]), ), mergeWith( apply(url('./files/root'), [ options.i18n ? noop() : filter(p => p.indexOf('i18n') === -1), options.form ? noop() : filter(p => p.indexOf('json-schema') === -1), template({ utils: strings, ...options, dot: '.', VERSION, ZORROVERSION, }), // move('/') ]), MergeStrategy.Overwrite, ), ]); } function fixLang(options: ApplicationOptions): (host: Tree) => void { return (host: Tree) => { if (options.i18n) return; const langs = getLangData(options.defaultLanguage!); if (!langs) return; console.log(`Translating, please wait...`); host.visit(p => { if (~p.indexOf(`/node_modules/`)) return; fixLangInHtml(host, p, langs); }); }; } function fixLangInHtml(host: Tree, p: string, langs: {}): void { let html = host.get(p)!.content.toString('utf8'); let matchCount = 0; // {{(status ? 'menu.fullscreen.exit' : 'menu.fullscreen') | translate }} // {{ (status ? 'menu.fullscreen.exit' : 'menu.fullscreen') | translate }} html = html.replace(/\{\{[ ]?\(status \? '([^']+)' : '([^']+)'\) \| translate \}\}/g, (_word, key1, key2) => { ++matchCount; return `{{ status ? '${langs[key1] || key1}' : '${langs[key2] || key2}' }}`; }); // {{ 'app.register-result.msg' | translate: params }} html = html.replace(/\{\{[ ]?'([^']+)'[ ]? \| translate: [^ ]+ \}\}/g, (_word, key) => { ++matchCount; return langs[key] || key; }); // {{ 'Please enter mobile number!' | translate }} html = html.replace(/\{\{[ ]?'([^']+)' \| translate[ ]?\}\}/g, (_word, key) => { ++matchCount; return langs[key] || key; }); // [nzTitle]="'app.login.tab-login-credentials' | translate" html = html.replace(/'([^']+)' \| translate[ ]?/g, (_word, key) => { ++matchCount; const value = langs[key] || key; return `'${value}'`; }); // 'app.register.get-verification-code' | translate html = html.replace(/'([^']+)' \| translate/g, (_word, key) => { ++matchCount; return langs[key] || key; }); // removed `header-i18n` if (~html.indexOf(`<header-i18n [showLang]="false" class="langs"></header-i18n>`)) { ++matchCount; html = html.replace(`<header-i18n [showLang]="false" class="langs"></header-i18n>`, ``); } if (matchCount > 0) { host.overwrite(p, html); } } function fixVsCode(): (host: Tree) => void { return (host: Tree) => { const filePath = '.vscode/extensions.json'; let json = getJSON(host, filePath); if (json == null) { host.create(filePath, ''); json = {}; } json.recommendations = ['cipchk.ohayojp-extension-pack']; overwriteJSON(host, filePath, json); }; } function installPackages(): (_host: Tree, context: SchematicContext) => void { return (_host: Tree, context: SchematicContext) => { context.addTask(new NodePackageInstallTask()); }; } export default function (options: ApplicationOptions): Rule { return (host: Tree, context: SchematicContext) => { project = getProject(host, options.project); return chain([ // @ohayo/* dependencies addDependenciesToPackageJson(options), // ci addRunScriptToPackageJson(), addPathsToTsConfig(), // code style addCodeStylesToPackageJson(), addSchematics(), addNzLintRules(), // files removeOrginalFiles(), addFilesToRoot(options), addCliTpl(), fixMain(), forceLess(), addStyle(), fixLang(options), fixVsCode(), fixAngularJson(options), installPackages(), // applyLintFix(), ])(host, context); }; }