From ce94aeabb9c4a9b4ef557669b95d41eabe4e0932 Mon Sep 17 00:00:00 2001 From: muhammedaltug Date: Wed, 17 Aug 2022 08:44:57 +0300 Subject: [PATCH] add create lib command --- .../packages/schematics/src/collection.json | 5 + .../.eslintrc.json.template | 44 +++++ .../config/ng-package.json.template | 7 + ...raryName@kebab__-config.module.ts.template | 12 ++ .../config/src/enums/index.ts.template | 1 + .../config/src/enums/route-names.ts.template | 3 + .../config/src/providers/index.ts.template | 1 + .../src/providers/route.provider.ts.template | 26 +++ .../config/src/public-api.ts.template | 3 + .../karma.conf.js.template | 44 +++++ .../ng-package.json.template | 7 + .../package.json.template | 11 ++ ...aryName@kebab__-routing.module.ts.template | 18 ++ .../__libraryName@kebab__.module.ts.template | 22 +++ .../src/public-api.ts.template | 4 + .../src/test.ts.template | 26 +++ .../tsconfig.lib.json.template | 20 +++ .../tsconfig.lib.prod.json.template | 10 ++ .../tsconfig.spec.json.template | 17 ++ .../ng-package.json.template | 7 + ..._-__libraryName@kebab__.module.ts.template | 11 ++ .../src/lib/index.ts.template | 1 + .../src/public-api.ts.template | 1 + .../src/commands/create-lib/index.ts | 159 ++++++++++++++++++ .../create-lib/models/generate-lib-schema.ts | 17 ++ .../src/commands/create-lib/models/index.ts | 1 + .../src/commands/create-lib/schema.json | 36 ++++ .../schematics/src/constants/symbols.ts | 1 + .../schematics/src/enums/exception.ts | 1 + .../src/models/generate-proxy-schema.ts | 10 ++ .../utils/angular-schematic/generate-lib.ts | 52 ++++++ .../src/utils/angular-schematic/index.ts | 1 + .../packages/schematics/src/utils/index.ts | 1 + .../packages/schematics/src/utils/lib.ts | 9 + .../packages/schematics/src/utils/source.ts | 2 +- .../schematics/src/utils/workspace.ts | 34 +++- npm/ng-packs/scripts/build-schematics.ts | 6 + 37 files changed, 627 insertions(+), 4 deletions(-) create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/.eslintrc.json.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/ng-package.json.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/__libraryName@kebab__-config.module.ts.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/enums/index.ts.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/enums/route-names.ts.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/providers/index.ts.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/providers/route.provider.ts.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/public-api.ts.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/karma.conf.js.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/ng-package.json.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/package.json.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/lib/__libraryName@kebab__-routing.module.ts.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/lib/__libraryName@kebab__.module.ts.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/public-api.ts.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/test.ts.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/tsconfig.lib.json.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/tsconfig.lib.prod.json.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/tsconfig.spec.json.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/ng-package.json.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/src/lib/__target@kebab__-__libraryName@kebab__.module.ts.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/src/lib/index.ts.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/src/public-api.ts.template create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/index.ts create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/models/generate-lib-schema.ts create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/models/index.ts create mode 100644 npm/ng-packs/packages/schematics/src/commands/create-lib/schema.json create mode 100644 npm/ng-packs/packages/schematics/src/constants/symbols.ts create mode 100644 npm/ng-packs/packages/schematics/src/utils/angular-schematic/generate-lib.ts create mode 100644 npm/ng-packs/packages/schematics/src/utils/angular-schematic/index.ts create mode 100644 npm/ng-packs/packages/schematics/src/utils/lib.ts diff --git a/npm/ng-packs/packages/schematics/src/collection.json b/npm/ng-packs/packages/schematics/src/collection.json index 0b1b738e08..8441a786b0 100644 --- a/npm/ng-packs/packages/schematics/src/collection.json +++ b/npm/ng-packs/packages/schematics/src/collection.json @@ -24,6 +24,11 @@ "description": "ABP API Generator Schematics", "factory": "./commands/api", "schema": "./commands/api/schema.json" + }, + "create-lib": { + "description": "ABP Create Library Schematics", + "factory": "./commands/create-lib", + "schema": "./commands/create-lib/schema.json" } } } diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/.eslintrc.json.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/.eslintrc.json.template new file mode 100644 index 0000000000..de84cad019 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/.eslintrc.json.template @@ -0,0 +1,44 @@ +{ + "extends": "../../.eslintrc.json", + "ignorePatterns": [ + "!**/*" + ], + "overrides": [ + { + "files": [ + "*.ts" + ], + "parserOptions": { + "project": [ + "projects/<%= kebab(libraryName) %>/tsconfig.lib.json", + "projects/<%= kebab(libraryName) %>/tsconfig.spec.json" + ], + "createDefaultProgram": true + }, + "rules": { + "@angular-eslint/directive-selector": [ + "error", + { + "type": "attribute", + "prefix": "lib", + "style": "camelCase" + } + ], + "@angular-eslint/component-selector": [ + "error", + { + "type": "element", + "prefix": "lib", + "style": "kebab-case" + } + ] + } + }, + { + "files": [ + "*.html" + ], + "rules": {} + } + ] +} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/ng-package.json.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/ng-package.json.template new file mode 100644 index 0000000000..2e7019c90e --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/ng-package.json.template @@ -0,0 +1,7 @@ +{ + "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/<%= kebab(libraryName) %>/config", + "lib": { + "entryFile": "src/public-api.ts" + } +} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/__libraryName@kebab__-config.module.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/__libraryName@kebab__-config.module.ts.template new file mode 100644 index 0000000000..c39b4582b9 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/__libraryName@kebab__-config.module.ts.template @@ -0,0 +1,12 @@ +import { ModuleWithProviders, NgModule } from '@angular/core'; +import { <%= macro(libraryName) %>_ROUTE_PROVIDERS } from './providers/route.provider'; + +@NgModule() +export class <%= pascal(libraryName) %>ConfigModule { + static forRoot(): ModuleWithProviders<<%= pascal(libraryName) %>ConfigModule> { + return { + ngModule: <%= pascal(libraryName) %>ConfigModule, + providers: [<%= macro(libraryName) %>_ROUTE_PROVIDERS], + }; + } +} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/enums/index.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/enums/index.ts.template new file mode 100644 index 0000000000..3bda94b078 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/enums/index.ts.template @@ -0,0 +1 @@ +export * from './route-names'; diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/enums/route-names.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/enums/route-names.ts.template new file mode 100644 index 0000000000..3bbb75be52 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/enums/route-names.ts.template @@ -0,0 +1,3 @@ +export const enum e<%= pascal(libraryName) %>RouteNames { + <%= pascal(libraryName) %> = '<%= pascal(libraryName) %>', +} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/providers/index.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/providers/index.ts.template new file mode 100644 index 0000000000..fe08efba8c --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/providers/index.ts.template @@ -0,0 +1 @@ +export * from './route.provider'; diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/providers/route.provider.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/providers/route.provider.ts.template new file mode 100644 index 0000000000..5db50f7eaa --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/providers/route.provider.ts.template @@ -0,0 +1,26 @@ +import { eLayoutType, RoutesService } from '@abp/ng.core'; +import { APP_INITIALIZER } from '@angular/core'; +import { e<%= pascal(libraryName) %>RouteNames } from '../enums/route-names'; + +export const <%= macro(libraryName) %>_ROUTE_PROVIDERS = [ + { + provide: APP_INITIALIZER, + useFactory: configureRoutes, + deps: [RoutesService], + multi: true, + }, +]; + +export function configureRoutes(routesService: RoutesService) { + return () => { + routesService.add([ + { + path: '/<%= kebab(libraryName) %>', + name: e<%= pascal(libraryName) %>RouteNames.<%= pascal(libraryName) %>, + iconClass: 'fas fa-book', + layout: eLayoutType.application, + order: 3, + }, + ]); + }; +} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/public-api.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/public-api.ts.template new file mode 100644 index 0000000000..6a8953bca8 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/config/src/public-api.ts.template @@ -0,0 +1,3 @@ +export * from './enums'; +export * from './<%= kebab(libraryName) %>-config.module'; +export * from './providers'; diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/karma.conf.js.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/karma.conf.js.template new file mode 100644 index 0000000000..a56984ac5b --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/karma.conf.js.template @@ -0,0 +1,44 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + jasmine: { + // you can add configuration options for Jasmine here + // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html + // for example, you can disable the random execution with `random: false` + // or set a specific seed with `seed: 4321` + }, + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + jasmineHtmlReporter: { + suppressAll: true // removes the duplicated traces + }, + coverageReporter: { + dir: require('path').join(__dirname, '../../coverage/my-project-name'), + subdir: '.', + reporters: [ + { type: 'html' }, + { type: 'text-summary' } + ] + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/ng-package.json.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/ng-package.json.template new file mode 100644 index 0000000000..fd8e55d798 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/ng-package.json.template @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/<%= kebab(libraryName) %>", + "lib": { + "entryFile": "src/public-api.ts" + } +} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/package.json.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/package.json.template new file mode 100644 index 0000000000..c4d36a8576 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/package.json.template @@ -0,0 +1,11 @@ +{ + "name": "@<%= kebab(libraryName) %>/<%= kebab(libraryName) %>", + "version": "0.0.1", + "peerDependencies": { + "@abp/ng.core": "<%= abpVersion %>", + "@abp/ng.theme.shared": "<%= abpVersion %>" + }, + "dependencies": { + "tslib": "^2.1.0" + } +} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/lib/__libraryName@kebab__-routing.module.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/lib/__libraryName@kebab__-routing.module.ts.template new file mode 100644 index 0000000000..4b9517b211 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/lib/__libraryName@kebab__-routing.module.ts.template @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { DynamicLayoutComponent } from '@abp/ng.core'; +import { Routes, RouterModule } from '@angular/router'; + +const routes: Routes = [ + { + path: '', + pathMatch: 'full', + component: DynamicLayoutComponent, + children: [], + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class <%= pascal(libraryName) %>RoutingModule {} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/lib/__libraryName@kebab__.module.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/lib/__libraryName@kebab__.module.ts.template new file mode 100644 index 0000000000..3d04aca7fb --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/lib/__libraryName@kebab__.module.ts.template @@ -0,0 +1,22 @@ +import { NgModule, NgModuleFactory, ModuleWithProviders } from '@angular/core'; +import { CoreModule, LazyModuleFactory } from '@abp/ng.core'; +import { ThemeSharedModule } from '@abp/ng.theme.shared'; +import { <%= pascal(libraryName) %>RoutingModule } from './<%= kebab(libraryName) %>-routing.module'; + +@NgModule({ + declarations: [], + imports: [CoreModule, ThemeSharedModule, <%= pascal(libraryName) %>RoutingModule], + exports: [], +}) +export class <%= pascal(libraryName) %>Module { + static forChild(): ModuleWithProviders<<%= pascal(libraryName) %>Module> { + return { + ngModule: <%= pascal(libraryName) %>Module, + providers: [], + }; + } + + static forLazy(): NgModuleFactory<<%= pascal(libraryName) %>Module> { + return new LazyModuleFactory(<%= pascal(libraryName) %>Module.forChild()); + } +} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/public-api.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/public-api.ts.template new file mode 100644 index 0000000000..c09585ae58 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/public-api.ts.template @@ -0,0 +1,4 @@ +/* + * Public API Surface of my-project-name + */ +export * from './lib/<%= kebab(libraryName) %>.module'; diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/test.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/test.ts.template new file mode 100644 index 0000000000..52e55168eb --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/src/test.ts.template @@ -0,0 +1,26 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js'; +import 'zone.js/testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: { + context(path: string, deep?: boolean, filter?: RegExp): { + keys(): string[]; + (id: string): T; + }; +}; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/tsconfig.lib.json.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/tsconfig.lib.json.template new file mode 100644 index 0000000000..8da4414fb7 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/tsconfig.lib.json.template @@ -0,0 +1,20 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.prod.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "target": "es2015", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [], + "lib": [ + "dom", + "es2018" + ] + }, + "exclude": [ + "src/test.ts", + "**/*.spec.ts" + ] +} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/tsconfig.lib.prod.json.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/tsconfig.lib.prod.json.template new file mode 100644 index 0000000000..06de549e10 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/tsconfig.lib.prod.json.template @@ -0,0 +1,10 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/tsconfig.spec.json.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/tsconfig.spec.json.template new file mode 100644 index 0000000000..715dd0a5d2 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-package/__libraryName@kebab__/tsconfig.spec.json.template @@ -0,0 +1,17 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "files": [ + "src/test.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/ng-package.json.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/ng-package.json.template new file mode 100644 index 0000000000..4e2118d142 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/ng-package.json.template @@ -0,0 +1,7 @@ +{ + "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/<%= kebab(target) %>/<%= kebab(libraryName) %>", + "lib": { + "entryFile": "src/public-api.ts" + } +} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/src/lib/__target@kebab__-__libraryName@kebab__.module.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/src/lib/__target@kebab__-__libraryName@kebab__.module.ts.template new file mode 100644 index 0000000000..1165afb970 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/src/lib/__target@kebab__-__libraryName@kebab__.module.ts.template @@ -0,0 +1,11 @@ +import { ModuleWithProviders, NgModule } from '@angular/core'; + +@NgModule() +export class <%= pascal(target) %><%= pascal(libraryName) %>Module { + static forRoot(): ModuleWithProviders<<%= pascal(target) %><%= pascal(libraryName) %>Module> { + return { + ngModule:<%= pascal(target) %><%= pascal(libraryName) %>Module, + providers: [] + } + } +} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/src/lib/index.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/src/lib/index.ts.template new file mode 100644 index 0000000000..5631c60e6d --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/src/lib/index.ts.template @@ -0,0 +1 @@ +export * from './<%= kebab(target) %>-<%= kebab(libraryName) %>.module'; diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/src/public-api.ts.template b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/src/public-api.ts.template new file mode 100644 index 0000000000..11aece60c4 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/files-secondary-entrypoint/__libraryName@kebab__/src/public-api.ts.template @@ -0,0 +1 @@ +export * from './lib/index'; diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/index.ts b/npm/ng-packs/packages/schematics/src/commands/create-lib/index.ts new file mode 100644 index 0000000000..1bc4c7a905 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/index.ts @@ -0,0 +1,159 @@ +import { + applyTemplates, + chain, + move, + noop, + Rule, + SchematicContext, + SchematicsException, + Tree, + url, +} from '@angular-devkit/schematics'; +import { GenerateLibSchema } from './models/generate-lib-schema'; +import { + applyWithOverwrite, + getWorkspace, + interpolate, + isLibrary, + JSONFile, + kebab, + resolveProject, + updateWorkspace, +} from '../../utils'; +import * as cases from '../../utils/text'; +import { Exception } from '../../enums'; +import { join, normalize } from '@angular-devkit/core'; +import { + ProjectDefinition, + WorkspaceDefinition, +} from '@angular-devkit/core/src/workspace/definitions'; +import { addLibToWorkspaceFile } from '../../utils/angular-schematic/generate-lib'; + +export default function (schema: GenerateLibSchema) { + return async (tree: Tree) => { + if (schema.override || !(await checkLibExist(schema, tree))) { + return chain([createLibrary(schema)]); + } + }; +} + +async function checkLibExist(options: GenerateLibSchema, tree: Tree) { + const packageName = kebab(options.packageName); + if (options.isSecondaryEntrypoint) { + const lib = await resolveProject(tree, options.target); + const ngPackagePath = `${lib?.definition.root}/${packageName}/ng-package.json`; + const packageInfo = tree.read(ngPackagePath); + if (packageInfo) { + throw new SchematicsException( + interpolate(Exception.LibraryAlreadyExists, `${lib.name}/${packageName}`), + ); + } + return false; + } + + const target = await resolveProject(tree, options.packageName, null); + if (target) { + throw new SchematicsException(interpolate(Exception.LibraryAlreadyExists, packageName)); + } + return false; +} + +function createLibrary(options: GenerateLibSchema): Rule { + return async (tree: Tree, _context: SchematicContext) => { + const target = await resolveProject(tree, options.packageName, null); + if (!target || options.override) { + if (options.isModuleTemplate) { + return createLibFromModuleTemplate(tree, options); + } + if (options.isSecondaryEntrypoint) { + return createLibSecondaryEntry(tree, options); + } + } else { + throw new SchematicsException( + interpolate(Exception.LibraryAlreadyExists, options.packageName), + ); + } + }; +} +async function resolvePackagesDirFromAngularJson(host: Tree) { + const workspace = await getWorkspace(host); + const projectFolder = readFirstLibInAngularJson(workspace); + return projectFolder?.root?.split('/')?.[0] || 'projects'; +} + +function readFirstLibInAngularJson(workspace: WorkspaceDefinition): ProjectDefinition | undefined { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const [_, props] = + Array.from(workspace.projects.entries()).find(([_, value]) => isLibrary(value)) || []; + return props; +} + +async function createLibFromModuleTemplate(tree: Tree, options: GenerateLibSchema) { + const packagesDir = await resolvePackagesDirFromAngularJson(tree); + const packageJson = JSON.parse(tree.read('./package.json')!.toString()); + const abpVersion = packageJson.dependencies['@abp/ng.core']; + + return chain([ + applyWithOverwrite(url('./files-package'), [ + applyTemplates({ + ...cases, + libraryName: options.packageName, + abpVersion, + }), + move(normalize(packagesDir)), + ]), + addLibToWorkspaceIfNotExist(options.packageName, packagesDir), + ]); +} + +export function addLibToWorkspaceIfNotExist(name: string, packagesDir: string): Rule { + return async (tree: Tree, _: SchematicContext) => { + const workspace = await getWorkspace(tree); + const packageName = kebab(name); + const isProjectExist = workspace.projects.has(packageName); + + const projectRoot = join(normalize(packagesDir), packageName); + const pathImportLib = `${packagesDir}/${packageName}`; + + return chain([ + isProjectExist + ? updateWorkspace(w => { + w.projects.delete(packageName); + }) + : noop(), + addLibToWorkspaceFile(projectRoot, packageName), + updateTsConfig(packageName, pathImportLib), + ]); + }; +} + +export function updateTsConfig(packageName: string, path: string) { + return (host: Tree) => { + const files = ['tsconfig.json', 'tsconfig.app.json', 'tsconfig.base.json']; + const tsConfig = files.find(f => host.exists(f)); + if (!tsConfig) { + return host; + } + + const file = new JSONFile(host, tsConfig); + const jsonPath = ['compilerOptions', 'paths', packageName]; + file.modify(jsonPath, [`${path}/src/public-api.ts`]); + }; +} + +export async function createLibSecondaryEntry(tree: Tree, options: GenerateLibSchema) { + const targetLib = await resolveProject(tree, options.target); + const packageName = `${kebab(targetLib.name)}/${kebab(options.packageName)}`; + const importPath = `${targetLib.definition.root}/${kebab(options.packageName)}`; + return chain([ + applyWithOverwrite(url('./files-secondary-entrypoint'), [ + applyTemplates({ + ...cases, + libraryName: options.packageName, + target: targetLib.name, + }), + move(normalize(targetLib.definition.root)), + updateTsConfig(packageName, importPath), + ]), + ]); +} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/models/generate-lib-schema.ts b/npm/ng-packs/packages/schematics/src/commands/create-lib/models/generate-lib-schema.ts new file mode 100644 index 0000000000..f3c6e5b97f --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/models/generate-lib-schema.ts @@ -0,0 +1,17 @@ +export interface GenerateLibSchema { + /** + * Angular package name will create + */ + packageName: string; + + /** + * İs the package a library or a library module + */ + isSecondaryEntrypoint: boolean; + + isModuleTemplate: boolean; + + override: boolean; + + target: string; +} diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/models/index.ts b/npm/ng-packs/packages/schematics/src/commands/create-lib/models/index.ts new file mode 100644 index 0000000000..e84ddcba49 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/models/index.ts @@ -0,0 +1 @@ +export * from './generate-lib-schema'; diff --git a/npm/ng-packs/packages/schematics/src/commands/create-lib/schema.json b/npm/ng-packs/packages/schematics/src/commands/create-lib/schema.json new file mode 100644 index 0000000000..64d64c1d80 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/create-lib/schema.json @@ -0,0 +1,36 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "SchematicsABPModuleTemplateCreator", + "title": "ABP Module Template Generator API Schema", + "type": "object", + "properties": { + "packageName": { + "description": "The name of the package will create", + "type": "string", + "$default": { + "$source": "argv", + "index": 0 + }, + "x-prompt": "Please enter the package name will create" + }, + "isSecondaryEntrypoint": { + "description": "Is secondary entrypoint", + "type": "boolean", + "$default": false, + "x-prompt": "Is secondary entrypoint?" + }, + "isModuleTemplate": { + "description": "Is module template", + "type": "boolean", + "$default": true, + "x-prompt": "Is module template?" + }, + "override": { + "description": "Override existing files", + "type": "boolean", + "$default": false, + "x-prompt": "Override existing files?" + } + }, + "required": [] +} diff --git a/npm/ng-packs/packages/schematics/src/constants/symbols.ts b/npm/ng-packs/packages/schematics/src/constants/symbols.ts new file mode 100644 index 0000000000..f8280b84c4 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/constants/symbols.ts @@ -0,0 +1 @@ +export const NOT_FOUND_VALUE = Symbol('NOT_FOUND_VALUE'); diff --git a/npm/ng-packs/packages/schematics/src/enums/exception.ts b/npm/ng-packs/packages/schematics/src/enums/exception.ts index b7b206cbf6..88f5d1862b 100644 --- a/npm/ng-packs/packages/schematics/src/enums/exception.ts +++ b/npm/ng-packs/packages/schematics/src/enums/exception.ts @@ -13,4 +13,5 @@ export const enum Exception { NoEnvironment = '[Environment Not Found] An environment file cannot be located in "{0}" project.', NoApiUrl = '[API URL Not Found] Cannot resolve API URL for "{1}" remote service name from "{0}" project.', NoRootNamespace = '[Root Namespace Not Found] Cannot resolve root namespace for "{1}" api from "{0}" project.', + LibraryAlreadyExists = '[Library Already Exists] "{0}" already exists. Use --override to override.', } diff --git a/npm/ng-packs/packages/schematics/src/models/generate-proxy-schema.ts b/npm/ng-packs/packages/schematics/src/models/generate-proxy-schema.ts index 7b0c3701a2..b089305e17 100644 --- a/npm/ng-packs/packages/schematics/src/models/generate-proxy-schema.ts +++ b/npm/ng-packs/packages/schematics/src/models/generate-proxy-schema.ts @@ -23,4 +23,14 @@ export interface GenerateProxySchema { * Url to API definition */ url?: string; + + /** + * Create a lib for proxy generation + */ + createTarget?: boolean; + + /** + * Secondary entrypoint for proxy generation + */ + entryPoint?: string; } diff --git a/npm/ng-packs/packages/schematics/src/utils/angular-schematic/generate-lib.ts b/npm/ng-packs/packages/schematics/src/utils/angular-schematic/generate-lib.ts new file mode 100644 index 0000000000..f96b2b38ea --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/utils/angular-schematic/generate-lib.ts @@ -0,0 +1,52 @@ +import { Rule, Tree } from '@angular-devkit/schematics'; +import { Builders, JSONFile, ProjectType, updateWorkspace } from '../angular'; + +export function updateTsConfig(packageName: string, ...paths: string[]) { + return (host: Tree) => { + if (!host.exists('tsconfig.json')) { + return host; + } + + const file = new JSONFile(host, 'tsconfig.json'); + const jsonPath = ['compilerOptions', 'paths', packageName]; + const value = file.get(jsonPath); + file.modify(jsonPath, Array.isArray(value) ? [...value, ...paths] : paths); + }; +} + +export function addLibToWorkspaceFile(projectRoot: string, projectName: string): Rule { + return updateWorkspace(workspace => { + workspace.projects.add({ + name: projectName, + root: projectRoot, + sourceRoot: `${projectRoot}/src`, + projectType: ProjectType.Library, + prefix: 'lib', + targets: { + build: { + builder: Builders.NgPackagr, + defaultConfiguration: 'production', + options: { + project: `${projectRoot}/ng-package.json`, + }, + configurations: { + production: { + tsConfig: `${projectRoot}/tsconfig.lib.prod.json`, + }, + development: { + tsConfig: `${projectRoot}/tsconfig.lib.json`, + }, + }, + }, + test: { + builder: Builders.Karma, + options: { + main: `${projectRoot}/src/test.ts`, + tsConfig: `${projectRoot}/tsconfig.spec.json`, + karmaConfig: `${projectRoot}/karma.conf.js`, + }, + }, + }, + }); + }); +} diff --git a/npm/ng-packs/packages/schematics/src/utils/angular-schematic/index.ts b/npm/ng-packs/packages/schematics/src/utils/angular-schematic/index.ts new file mode 100644 index 0000000000..0d2dd109ca --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/utils/angular-schematic/index.ts @@ -0,0 +1 @@ +export * from './generate-lib'; diff --git a/npm/ng-packs/packages/schematics/src/utils/index.ts b/npm/ng-packs/packages/schematics/src/utils/index.ts index eeb12e6d9e..53950e8a87 100644 --- a/npm/ng-packs/packages/schematics/src/utils/index.ts +++ b/npm/ng-packs/packages/schematics/src/utils/index.ts @@ -7,6 +7,7 @@ export * from './enum'; export * from './file'; export * from './generics'; export * from './import'; +export * from './lib'; export * from './methods'; export * from './model'; export * from './namespace'; diff --git a/npm/ng-packs/packages/schematics/src/utils/lib.ts b/npm/ng-packs/packages/schematics/src/utils/lib.ts new file mode 100644 index 0000000000..d083c6c206 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/utils/lib.ts @@ -0,0 +1,9 @@ +import { Tree } from '@angular-devkit/schematics'; +import { resolveProject } from "./workspace"; +export async function createTargetLibIfNotExist(tree: Tree, target: string) { + const lib = await resolveProject(tree, target, null); + + if (!lib) { + + } +} diff --git a/npm/ng-packs/packages/schematics/src/utils/source.ts b/npm/ng-packs/packages/schematics/src/utils/source.ts index ad488b27be..be1156a775 100644 --- a/npm/ng-packs/packages/schematics/src/utils/source.ts +++ b/npm/ng-packs/packages/schematics/src/utils/source.ts @@ -23,7 +23,7 @@ export function createApiDefinitionGetter(params: GenerateProxySchema) { if (!sourceUrl) { sourceUrl = getSourceUrl(host, source, apiName); } - return await getApiDefinition(sourceUrl); + return await getApiDefinition(sourceUrl!); }; } diff --git a/npm/ng-packs/packages/schematics/src/utils/workspace.ts b/npm/ng-packs/packages/schematics/src/utils/workspace.ts index 81bfdc7307..54e8491d41 100644 --- a/npm/ng-packs/packages/schematics/src/utils/workspace.ts +++ b/npm/ng-packs/packages/schematics/src/utils/workspace.ts @@ -3,9 +3,11 @@ import { strings, workspaces } from '@angular-devkit/core'; import { SchematicsException, Tree } from '@angular-devkit/schematics'; import { Exception } from '../enums'; import { Project } from '../models'; -import { getWorkspace, getWorkspaceSchema, ProjectType, WorkspaceSchema } from './angular'; +import { getWorkspace, ProjectType, WorkspaceSchema } from './angular'; import { findEnvironmentExpression } from './ast'; import { readFileInTree } from './common'; +import { NOT_FOUND_VALUE } from '../constants/symbols'; +import { parseJson } from '@angular/cli/utilities/json-file'; export function isLibrary(project: workspaces.ProjectDefinition): boolean { return project.extensions['projectType'] === ProjectType.Library; @@ -33,8 +35,11 @@ export function readWorkspaceSchema(tree: Tree) { return workspaceSchema; } - -export async function resolveProject(tree: Tree, name: string): Promise { +export async function resolveProject( + tree: Tree, + name: string, + notFoundValue: T = NOT_FOUND_VALUE as unknown as any, +): Promise { name = name || readWorkspaceSchema(tree).defaultProject!; const workspace = await getWorkspace(tree); let definition: Project['definition'] | undefined; @@ -61,7 +66,30 @@ export async function resolveProject(tree: Tree, name: string): Promise definition = workspace.projects.get(name); } catch (_) {} + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + if (!definition && notFoundValue !== NOT_FOUND_VALUE) { + return notFoundValue; + } if (!definition) throw new SchematicsException(Exception.NoProject); return { name, definition }; } + +export function getWorkspaceSchema(host: Tree): WorkspaceSchema { + const path = getWorkspacePath(host); + const configBuffer = host.read(path); + if (configBuffer === null) { + throw new SchematicsException(`Could not find (${path})`); + } + const content = configBuffer.toString(); + + return parseJson(content) as Record as WorkspaceSchema; +} + +export function getWorkspacePath(host: Tree): string { + const possibleFiles = ['/angular.json', '/.angular.json']; + const path = possibleFiles.filter(path => host.exists(path))[0]; + + return path; +} diff --git a/npm/ng-packs/scripts/build-schematics.ts b/npm/ng-packs/scripts/build-schematics.ts index 64da4ac856..8884ca9571 100644 --- a/npm/ng-packs/scripts/build-schematics.ts +++ b/npm/ng-packs/scripts/build-schematics.ts @@ -20,6 +20,12 @@ class FileCopy { const PACKAGE_TO_BUILD = 'schematics'; const FILES_TO_COPY_AFTER_BUILD: (FileCopy | string)[] = [ + { src: 'src/commands/create-lib/schema.json', dest: 'commands/create-lib/schema.json' }, + { src: 'src/commands/create-lib/files-package', dest: 'commands/create-lib/files-package' }, + { + src: 'src/commands/create-lib/files-secondary-entrypoint', + dest: 'commands/create-lib/files-secondary-entrypoint', + }, { src: 'src/commands/proxy-add/schema.json', dest: 'commands/proxy-add/schema.json' }, { src: 'src/commands/proxy-index/schema.json', dest: 'commands/proxy-index/schema.json' }, { src: 'src/commands/proxy-refresh/schema.json', dest: 'commands/proxy-refresh/schema.json' },