From a76a75fe4d136cbc199ac129d89f8dd0c9c5293f Mon Sep 17 00:00:00 2001 From: Dmitriy Stepanenko Date: Mon, 14 Aug 2023 11:33:22 +0300 Subject: [PATCH] refactor: cleanup schematics --- integrations/tempreponx | 1 + packages/store/schematics/collection.json | 22 +-- .../factories/actions/actions.factory.ts | 8 - .../factories/ng-add/ng-add.factory.spec.ts | 76 --------- .../starter-kit/starter-kit.factory.ts | 8 - .../factories/state/state.factory.ts | 8 - .../factories/store/store.factory.ts | 8 - .../src/actions/actions.factory.spec.ts | 30 ++++ .../schematics/src/actions/actions.factory.ts | 21 +++ .../actions/actions.schema.d.ts | 4 +- .../files}/__name__.actions.ts__template__ | 0 .../{factories => src}/actions/schema.json | 8 +- .../src/ng-add/ng-add.factory.spec.ts | 152 ++++++++++++++++++ .../ng-add/ng-add.factory.ts | 61 ++++--- .../ng-add/ng-add.schema.d.ts | 2 +- .../{factories => src}/ng-add/schema.json | 2 +- .../store/auth/auth.actions.ts__template__ | 0 .../store/auth/auth.state.spec.ts__template__ | 0 .../store/auth/auth.state.ts__template__ | 0 .../store/dashboard/index.ts__template__ | 0 .../dictionary.actions.ts__template__ | 0 .../dictionary.state.spec.ts__template__ | 0 .../dictionary.state.ts__template__ | 0 .../states/user/user.actions.ts__template__ | 0 .../user/user.state.spec.ts__template__ | 0 .../states/user/user.state.ts__template__ | 0 .../files}/store/store.config.ts__template__ | 0 .../files}/store/store.module.ts__template__ | 0 .../starter-kit/schema.json | 8 +- .../starter-kit/starter-kit.factory.spec.ts} | 16 +- .../src/starter-kit/starter-kit.factory.ts | 10 ++ .../starter-kit/starter-kit.schema.d.ts | 4 - .../files}/__name__.state.spec.ts__template__ | 0 .../files}/__name__.state.ts__template__ | 0 .../{factories => src}/state/schema.json | 10 +- .../src/state/state.factory.spec.ts | 50 ++++++ .../schematics/src/state/state.factory.ts | 19 +++ .../state/state.schema.d.ts | 8 +- .../files}/__name__.actions.ts__template__ | 0 .../files}/__name__.state.spec.ts__template__ | 0 .../files}/__name__.state.ts__template__ | 0 .../{factories => src}/store/schema.json | 10 +- .../src/store/store.factory.spec.ts | 57 +++++++ .../schematics/src/store/store.factory.ts | 19 +++ .../store/store.schema.d.ts | 8 +- .../schematics/src/utils/common/lib.config.ts | 10 ++ .../utils/common/project-files.config.ts | 0 .../{ => src}/utils/common/properties.ts | 0 .../schematics/{ => src}/utils/config.ts | 0 .../schematics/src/utils/generate-utils.ts | 32 ++++ .../utils/interfaces/package.interface.ts | 0 .../src/utils/normalize-options.spec.ts | 30 ++++ .../schematics/src/utils/normalize-options.ts | 33 ++++ .../schematics/{ => src}/utils/project.ts | 0 .../store/schematics/src/utils/versions.json | 3 + .../factories/actions/actions.factory.test.ts | 29 ---- .../test/factories/common/properties.ts | 22 --- .../test/factories/ng-add/common/package.json | 15 -- .../factories/ng-add/ng-add.factory.test.ts | 36 ----- .../factories/state/state.factory.test.ts | 53 ------ .../factories/store/store.factory.test.ts | 61 ------- .../store/schematics/test/jest.config.json | 11 -- .../store/schematics/test/tsconfig.test.json | 8 - .../schematics/test/utils/parser.test.ts | 51 ------ .../schematics/utils/common/factories.enum.ts | 6 - .../schematics/utils/common/lib.config.ts | 63 -------- .../store/schematics/utils/factory-loader.ts | 17 -- .../schematics/utils/generate-factory.ts | 22 --- .../store/schematics/utils/get-library.ts | 9 -- packages/store/schematics/utils/index.ts | 3 - .../interfaces/generate-factory.interface.ts | 12 -- .../utils/interfaces/parser.interface.ts | 17 -- packages/store/schematics/utils/parser.ts | 20 --- .../schematics/utils/transform-options.ts | 27 ---- tools/build-schematics.mjs | 36 +++-- 75 files changed, 571 insertions(+), 685 deletions(-) create mode 160000 integrations/tempreponx delete mode 100644 packages/store/schematics/factories/actions/actions.factory.ts delete mode 100644 packages/store/schematics/factories/ng-add/ng-add.factory.spec.ts delete mode 100644 packages/store/schematics/factories/starter-kit/starter-kit.factory.ts delete mode 100644 packages/store/schematics/factories/state/state.factory.ts delete mode 100644 packages/store/schematics/factories/store/store.factory.ts create mode 100644 packages/store/schematics/src/actions/actions.factory.spec.ts create mode 100644 packages/store/schematics/src/actions/actions.factory.ts rename packages/store/schematics/{factories => src}/actions/actions.schema.d.ts (73%) rename packages/store/schematics/{templates/actions => src/actions/files}/__name__.actions.ts__template__ (100%) rename packages/store/schematics/{factories => src}/actions/schema.json (81%) create mode 100644 packages/store/schematics/src/ng-add/ng-add.factory.spec.ts rename packages/store/schematics/{factories => src}/ng-add/ng-add.factory.ts (63%) rename packages/store/schematics/{factories => src}/ng-add/ng-add.schema.d.ts (94%) rename packages/store/schematics/{factories => src}/ng-add/schema.json (97%) rename packages/store/schematics/{templates/starter-kit => src/starter-kit/files}/store/auth/auth.actions.ts__template__ (100%) rename packages/store/schematics/{templates/starter-kit => src/starter-kit/files}/store/auth/auth.state.spec.ts__template__ (100%) rename packages/store/schematics/{templates/starter-kit => src/starter-kit/files}/store/auth/auth.state.ts__template__ (100%) rename packages/store/schematics/{templates/starter-kit => src/starter-kit/files}/store/dashboard/index.ts__template__ (100%) rename packages/store/schematics/{templates/starter-kit => src/starter-kit/files}/store/dashboard/states/dictionary/dictionary.actions.ts__template__ (100%) rename packages/store/schematics/{templates/starter-kit => src/starter-kit/files}/store/dashboard/states/dictionary/dictionary.state.spec.ts__template__ (100%) rename packages/store/schematics/{templates/starter-kit => src/starter-kit/files}/store/dashboard/states/dictionary/dictionary.state.ts__template__ (100%) rename packages/store/schematics/{templates/starter-kit => src/starter-kit/files}/store/dashboard/states/user/user.actions.ts__template__ (100%) rename packages/store/schematics/{templates/starter-kit => src/starter-kit/files}/store/dashboard/states/user/user.state.spec.ts__template__ (100%) rename packages/store/schematics/{templates/starter-kit => src/starter-kit/files}/store/dashboard/states/user/user.state.ts__template__ (100%) rename packages/store/schematics/{templates/starter-kit => src/starter-kit/files}/store/store.config.ts__template__ (100%) rename packages/store/schematics/{templates/starter-kit => src/starter-kit/files}/store/store.module.ts__template__ (100%) rename packages/store/schematics/{factories => src}/starter-kit/schema.json (71%) rename packages/store/schematics/{test/factories/starter-kit/starter-kit.factory.test.ts => src/starter-kit/starter-kit.factory.spec.ts} (83%) create mode 100644 packages/store/schematics/src/starter-kit/starter-kit.factory.ts rename packages/store/schematics/{factories => src}/starter-kit/starter-kit.schema.d.ts (72%) rename packages/store/schematics/{templates/state => src/state/files}/__name__.state.spec.ts__template__ (100%) rename packages/store/schematics/{templates/state => src/state/files}/__name__.state.ts__template__ (100%) rename packages/store/schematics/{factories => src}/state/schema.json (84%) create mode 100644 packages/store/schematics/src/state/state.factory.spec.ts create mode 100644 packages/store/schematics/src/state/state.factory.ts rename packages/store/schematics/{factories => src}/state/state.schema.d.ts (77%) rename packages/store/schematics/{templates/store => src/store/files}/__name__.actions.ts__template__ (100%) rename packages/store/schematics/{templates/store => src/store/files}/__name__.state.spec.ts__template__ (100%) rename packages/store/schematics/{templates/store => src/store/files}/__name__.state.ts__template__ (100%) rename packages/store/schematics/{factories => src}/store/schema.json (84%) create mode 100644 packages/store/schematics/src/store/store.factory.spec.ts create mode 100644 packages/store/schematics/src/store/store.factory.ts rename packages/store/schematics/{factories => src}/store/store.schema.d.ts (77%) create mode 100644 packages/store/schematics/src/utils/common/lib.config.ts rename packages/store/schematics/{ => src}/utils/common/project-files.config.ts (100%) rename packages/store/schematics/{ => src}/utils/common/properties.ts (100%) rename packages/store/schematics/{ => src}/utils/config.ts (100%) create mode 100644 packages/store/schematics/src/utils/generate-utils.ts rename packages/store/schematics/{ => src}/utils/interfaces/package.interface.ts (100%) create mode 100644 packages/store/schematics/src/utils/normalize-options.spec.ts create mode 100644 packages/store/schematics/src/utils/normalize-options.ts rename packages/store/schematics/{ => src}/utils/project.ts (100%) create mode 100644 packages/store/schematics/src/utils/versions.json delete mode 100644 packages/store/schematics/test/factories/actions/actions.factory.test.ts delete mode 100644 packages/store/schematics/test/factories/common/properties.ts delete mode 100644 packages/store/schematics/test/factories/ng-add/common/package.json delete mode 100644 packages/store/schematics/test/factories/ng-add/ng-add.factory.test.ts delete mode 100644 packages/store/schematics/test/factories/state/state.factory.test.ts delete mode 100644 packages/store/schematics/test/factories/store/store.factory.test.ts delete mode 100644 packages/store/schematics/test/jest.config.json delete mode 100644 packages/store/schematics/test/tsconfig.test.json delete mode 100644 packages/store/schematics/test/utils/parser.test.ts delete mode 100644 packages/store/schematics/utils/common/factories.enum.ts delete mode 100644 packages/store/schematics/utils/common/lib.config.ts delete mode 100644 packages/store/schematics/utils/factory-loader.ts delete mode 100644 packages/store/schematics/utils/generate-factory.ts delete mode 100644 packages/store/schematics/utils/get-library.ts delete mode 100644 packages/store/schematics/utils/index.ts delete mode 100644 packages/store/schematics/utils/interfaces/generate-factory.interface.ts delete mode 100644 packages/store/schematics/utils/interfaces/parser.interface.ts delete mode 100644 packages/store/schematics/utils/parser.ts delete mode 100644 packages/store/schematics/utils/transform-options.ts diff --git a/integrations/tempreponx b/integrations/tempreponx new file mode 160000 index 000000000..ba31de146 --- /dev/null +++ b/integrations/tempreponx @@ -0,0 +1 @@ +Subproject commit ba31de146d0cac4b056296e89660435076a72d07 diff --git a/packages/store/schematics/collection.json b/packages/store/schematics/collection.json index 531d06b67..0a845da8a 100644 --- a/packages/store/schematics/collection.json +++ b/packages/store/schematics/collection.json @@ -3,34 +3,34 @@ "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json", "schematics": { "store": { - "factory": "./factories/store/store.factory#store", + "factory": "./src/store/store.factory#store", "description": "Create a NGXS full store", "aliases": ["ngxs-store"], - "schema": "./factories/store/schema.json" + "schema": "./src/store/schema.json" }, "state": { - "factory": "./factories/state/state.factory#state", + "factory": "./src/state/state.factory#state", "description": "Create a NGXS state", "aliases": ["ngxs-state"], - "schema": "./factories/state/schema.json" + "schema": "./src/state/schema.json" }, "actions": { - "factory": "./factories/actions/actions.factory#actions", + "factory": "./src/actions/actions.factory#actions", "description": "Create a NGXS actions", "aliases": ["ngxs-actions"], - "schema": "./factories/actions/schema.json" + "schema": "./src/actions/schema.json" }, "starter-kit": { - "factory": "./factories/starter-kit/starter-kit.factory#starterKit", - "description": "Create a NGXS starter kit with simple or best practise type", + "factory": "./src/starter-kit/starter-kit.factory#starterKit", + "description": "Create a NGXS starter kit with simple or best practice type", "aliases": ["ngxs-sk"], - "schema": "./factories/starter-kit/schema.json" + "schema": "./src/starter-kit/schema.json" }, "ng-add": { - "factory": "./factories/ng-add/ng-add.factory#ngAdd", + "factory": "./src/ng-add/ng-add.factory#ngAdd", "description": "Add Ngxs Store and plugins in package.json", "aliases": ["ngxs-init"], - "schema": "./factories/ng-add/schema.json" + "schema": "./src/ng-add/schema.json" } } } diff --git a/packages/store/schematics/factories/actions/actions.factory.ts b/packages/store/schematics/factories/actions/actions.factory.ts deleted file mode 100644 index a48ff7079..000000000 --- a/packages/store/schematics/factories/actions/actions.factory.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Rule } from '@angular-devkit/schematics'; -import { ActionsSchema } from './actions.schema'; -import { FACTORIES } from '../../utils'; -import { factoryLoader } from '../../utils/factory-loader'; - -export function actions(options: ActionsSchema): Rule { - return factoryLoader(options, FACTORIES.ACTIONS); -} diff --git a/packages/store/schematics/factories/ng-add/ng-add.factory.spec.ts b/packages/store/schematics/factories/ng-add/ng-add.factory.spec.ts deleted file mode 100644 index ac89c8e2f..000000000 --- a/packages/store/schematics/factories/ng-add/ng-add.factory.spec.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; -import { Schema as ApplicationOptions } from '@schematics/angular/application/schema'; -import { Schema as WorkspaceOptions } from '@schematics/angular/workspace/schema'; -import { NgxsPackageSchema } from './ng-add.schema'; - -describe('Ngxs ng-add Schematic', () => { - const schematicRunner = new SchematicTestRunner( - '@schematics/angular', - require.resolve('../../../../../node_modules/@schematics/angular/collection.json') - ); - - const ngxsSchematicRunner = new SchematicTestRunner( - '@ngxs/store/schematics', - require.resolve('../../collection.json') - ); - - const defaultOptions: NgxsPackageSchema = { - skipInstall: false, - packages: [], - name: '' - }; - - const workspaceOptions: WorkspaceOptions = { - name: 'workspace', - newProjectRoot: 'projects', - version: '1.0.0' - }; - - const appOptions: ApplicationOptions = { - name: 'foo', - inlineStyle: false, - inlineTemplate: false, - routing: true, - skipTests: false, - skipPackageJson: false - }; - - let appTree: UnitTestTree; - beforeEach(async () => { - appTree = await schematicRunner - .runSchematicAsync('workspace', workspaceOptions) - .toPromise(); - appTree = await schematicRunner - .runSchematicAsync('application', appOptions, appTree) - .toPromise(); - }); - - it('should not import Ngxs module into the application module if a project name is not provided', async () => { - // Arrange - const options: NgxsPackageSchema = { ...defaultOptions }; - // Act - const tree = await ngxsSchematicRunner - .runSchematicAsync('ngxs-init', options, appTree) - .toPromise(); - // Assert - const content = tree.readContent('/projects/foo/src/app/app.module.ts'); - expect(content).not.toMatch(/import { NgxsModule } from '@ngxs\/store'/); - expect(content).not.toMatch(/imports: \[[^\]]*NgxsModule[^\]]*\]/m); - }); - - it('should import Ngxs module into the application module if a project name is provided', async () => { - // Arrange - const options: NgxsPackageSchema = { ...defaultOptions, name: 'foo' }; - // Act - const tree = await ngxsSchematicRunner - .runSchematicAsync('ngxs-init', options, appTree) - .toPromise(); - // Assert - const content = tree.readContent('/projects/foo/src/app/app.module.ts'); - expect(content).toMatch(/import { NgxsModule } from '@ngxs\/store'/); - expect(content).toMatch(/imports: \[[^\]]*NgxsModule.forRoot\(\[\],[^\]]*\]/m); - expect(content).toMatch( - /imports: \[[^\]]*NgxsModule.forRoot\(\[\], \{ developmentMode\: \!environment\.production, selectorOptions\: \{ suppressErrors\: false, injectContainerState\: false \} \}\)[^\]]*\]/m - ); - }); -}); diff --git a/packages/store/schematics/factories/starter-kit/starter-kit.factory.ts b/packages/store/schematics/factories/starter-kit/starter-kit.factory.ts deleted file mode 100644 index aec986815..000000000 --- a/packages/store/schematics/factories/starter-kit/starter-kit.factory.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Rule } from '@angular-devkit/schematics'; -import { StarterKitSchema } from './starter-kit.schema'; -import { FACTORIES } from '../../utils'; -import { factoryLoader } from '../../utils/factory-loader'; - -export function starterKit(options: StarterKitSchema): Rule { - return factoryLoader(options, FACTORIES.STARTER_KIT); -} diff --git a/packages/store/schematics/factories/state/state.factory.ts b/packages/store/schematics/factories/state/state.factory.ts deleted file mode 100644 index e3404dc05..000000000 --- a/packages/store/schematics/factories/state/state.factory.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Rule } from '@angular-devkit/schematics'; -import { StateSchema } from './state.schema'; -import { FACTORIES } from '../../utils'; -import { factoryLoader } from '../../utils/factory-loader'; - -export function state(options: StateSchema): Rule { - return factoryLoader(options, FACTORIES.STATE); -} diff --git a/packages/store/schematics/factories/store/store.factory.ts b/packages/store/schematics/factories/store/store.factory.ts deleted file mode 100644 index 7ded9a0bc..000000000 --- a/packages/store/schematics/factories/store/store.factory.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Rule } from '@angular-devkit/schematics'; -import { StoreSchema } from './store.schema'; -import { FACTORIES } from '../../utils'; -import { factoryLoader } from '../../utils/factory-loader'; - -export function store(options: StoreSchema): Rule { - return factoryLoader(options, FACTORIES.STORE); -} diff --git a/packages/store/schematics/src/actions/actions.factory.spec.ts b/packages/store/schematics/src/actions/actions.factory.spec.ts new file mode 100644 index 000000000..3a61cb7b0 --- /dev/null +++ b/packages/store/schematics/src/actions/actions.factory.spec.ts @@ -0,0 +1,30 @@ +import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; +import { workspaceRoot } from '@nrwl/devkit'; + +import * as path from 'path'; + +import { ActionsSchema } from './actions.schema'; + +describe('NGXS Actions', () => { + const runner: SchematicTestRunner = new SchematicTestRunner( + '.', + path.join(workspaceRoot, 'packages/store/schematics/collection.json') + ); + it('should create action in a folder by default', async () => { + const options: ActionsSchema = { + name: 'todos' + }; + const tree: UnitTestTree = await runner.runSchematicAsync('actions', options).toPromise(); + const files: string[] = tree.files; + expect(files).toEqual(['/todos/todos.actions.ts']); + }); + it('should create action without folder if "flat" is set to "true"', async () => { + const options: ActionsSchema = { + name: 'todos', + flat: true + }; + const tree: UnitTestTree = await runner.runSchematicAsync('actions', options).toPromise(); + const files: string[] = tree.files; + expect(files).toEqual(['/todos.actions.ts']); + }); +}); diff --git a/packages/store/schematics/src/actions/actions.factory.ts b/packages/store/schematics/src/actions/actions.factory.ts new file mode 100644 index 000000000..ad82c399a --- /dev/null +++ b/packages/store/schematics/src/actions/actions.factory.ts @@ -0,0 +1,21 @@ +import { Rule, SchematicsException, url } from '@angular-devkit/schematics'; +import { ActionsSchema } from './actions.schema'; +import { generateFiles } from '../utils/generate-utils'; +import { isEmpty } from '../utils/common/properties'; +import { normalizeBaseOptions } from '../utils/normalize-options'; +import { join } from 'path'; + +export function actions(options: ActionsSchema): Rule { + if (isEmpty(options.name)) { + throw new SchematicsException('Invalid options, "name" is required.'); + } + + const normalizedOptions = normalizeBaseOptions(options); + const path = options.flat + ? normalizedOptions.path + : join(normalizedOptions.path, normalizedOptions.name); + + return generateFiles(url('./files'), path, { + name: normalizedOptions.name + }); +} diff --git a/packages/store/schematics/factories/actions/actions.schema.d.ts b/packages/store/schematics/src/actions/actions.schema.d.ts similarity index 73% rename from packages/store/schematics/factories/actions/actions.schema.d.ts rename to packages/store/schematics/src/actions/actions.schema.d.ts index ac34b69ba..b61359872 100644 --- a/packages/store/schematics/factories/actions/actions.schema.d.ts +++ b/packages/store/schematics/src/actions/actions.schema.d.ts @@ -8,7 +8,7 @@ export interface ActionsSchema { */ path?: string; /** - * The source root path + * Flag to indicate if a dir is created. */ - sourceRoot?: string; + flat?: boolean; } diff --git a/packages/store/schematics/templates/actions/__name__.actions.ts__template__ b/packages/store/schematics/src/actions/files/__name__.actions.ts__template__ similarity index 100% rename from packages/store/schematics/templates/actions/__name__.actions.ts__template__ rename to packages/store/schematics/src/actions/files/__name__.actions.ts__template__ diff --git a/packages/store/schematics/factories/actions/schema.json b/packages/store/schematics/src/actions/schema.json similarity index 81% rename from packages/store/schematics/factories/actions/schema.json rename to packages/store/schematics/src/actions/schema.json index 1351e942a..e67472e19 100644 --- a/packages/store/schematics/factories/actions/schema.json +++ b/packages/store/schematics/src/actions/schema.json @@ -18,10 +18,10 @@ "format": "path", "description": "The path to create the actions." }, - "sourceRoot": { - "type": "string", - "format": "path", - "description": "The source root path" + "flat": { + "type": "boolean", + "default": false, + "description": "Flag to indicate if a dir is created." } }, "required": ["name"] diff --git a/packages/store/schematics/src/ng-add/ng-add.factory.spec.ts b/packages/store/schematics/src/ng-add/ng-add.factory.spec.ts new file mode 100644 index 000000000..225d3a954 --- /dev/null +++ b/packages/store/schematics/src/ng-add/ng-add.factory.spec.ts @@ -0,0 +1,152 @@ +import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; +import { Tree } from '@angular-devkit/schematics'; +import { workspaceRoot } from '@nrwl/devkit'; +import { join } from 'path'; +import { Schema as ApplicationOptions } from '@schematics/angular/application/schema'; +import { Schema as WorkspaceOptions } from '@schematics/angular/workspace/schema'; + +import { LIBRARIES } from '../utils/common/lib.config'; +import { NgxsPackageSchema } from './ng-add.schema'; + +describe('Ngxs ng-add Schematic', () => { + const angularSchematicRunner = new SchematicTestRunner( + '@schematics/angular', + join(workspaceRoot, 'node_modules/@schematics/angular/collection.json') + ); + + const ngxsSchematicRunner = new SchematicTestRunner( + '@ngxs/store/schematics', + join(workspaceRoot, 'packages/store/schematics/collection.json') + ); + + const defaultOptions: NgxsPackageSchema = { + skipInstall: false, + packages: [], + name: '' + }; + + const workspaceOptions: WorkspaceOptions = { + name: 'workspace', + newProjectRoot: 'projects', + version: '1.0.0' + }; + + const appOptions: ApplicationOptions = { + name: 'foo', + inlineStyle: false, + inlineTemplate: false, + routing: true, + skipTests: false, + skipPackageJson: false + }; + + let appTree: UnitTestTree; + beforeEach(async () => { + appTree = await angularSchematicRunner + .runSchematicAsync('workspace', workspaceOptions) + .toPromise(); + appTree = await angularSchematicRunner + .runSchematicAsync('application', appOptions, appTree) + .toPromise(); + }); + + it('should not import Ngxs module into the application module if a project name is not provided', async () => { + // Arrange + const options: NgxsPackageSchema = { ...defaultOptions }; + // Act + const tree = await ngxsSchematicRunner + .runSchematicAsync('ngxs-init', options, appTree) + .toPromise(); + // Assert + const content = tree.readContent('/projects/foo/src/app/app.module.ts'); + expect(content).not.toMatch(/import { NgxsModule } from '@ngxs\/store'/); + expect(content).not.toMatch(/imports: \[[^\]]*NgxsModule[^\]]*\]/m); + }); + + it('should import Ngxs module into the application module if a project name is provided', async () => { + // Arrange + const options: NgxsPackageSchema = { ...defaultOptions, name: 'foo' }; + // Act + const tree = await ngxsSchematicRunner + .runSchematicAsync('ngxs-init', options, appTree) + .toPromise(); + // Assert + const content = tree.readContent('/projects/foo/src/app/app.module.ts'); + expect(content).toMatch(/import { NgxsModule } from '@ngxs\/store'/); + expect(content).toMatch(/imports: \[[^\]]*NgxsModule.forRoot\(\[\],[^\]]*\]/m); + expect(content).toMatch( + /imports: \[[^\]]*NgxsModule.forRoot\(\[\], \{ developmentMode\: \!environment\.production, selectorOptions\: \{ suppressErrors\: false, injectContainerState\: false \} \}\)[^\]]*\]/m + ); + }); +}); + +describe('ng-add package in package.json', () => { + const runner: SchematicTestRunner = new SchematicTestRunner( + 'schematics', + join(workspaceRoot, 'packages/store/schematics/collection.json') + ); + let testTree: UnitTestTree; + let inputTree: Tree; + + beforeEach(() => { + inputTree = Tree.empty(); + inputTree.create( + '/package.json', + JSON.stringify({ + name: 'test', + version: '0.0.0', + license: 'MIT', + scripts: { + ng: 'ng', + start: 'ng serve', + build: 'ng build', + test: 'ng test', + lint: 'ng lint', + e2e: 'ng e2e' + }, + private: true, + dependencies: {} + }) + ); + }); + + it('should add ngxs store in package.json', async () => { + testTree = await runner.runSchematicAsync('ng-add', {}, inputTree).toPromise(); + const packageJsonText = testTree.readContent('/package.json'); + const packageJson = JSON.parse(packageJsonText); + expect(Object.keys(packageJson.dependencies)).toEqual([LIBRARIES.STORE]); + expect(packageJson.devDependencies).toBeUndefined(); + }); + + it('should add ngxs store with provided plugins in package.json', async () => { + const packages = [LIBRARIES.DEVTOOLS, LIBRARIES.LOGGER]; + const options: NgxsPackageSchema = { packages }; + testTree = await runner.runSchematicAsync('ng-add', options, inputTree).toPromise(); + const packageJsonText = testTree.readContent('/package.json'); + const packageJson = JSON.parse(packageJsonText); + expect(Object.keys(packageJson.dependencies).sort()).toEqual( + packages.concat(LIBRARIES.STORE).sort() + ); + expect(packageJson.devDependencies).toBeUndefined(); + }); + + it('should add ngxs store with all plugins in package.json', async () => { + const packages = Object.values(LIBRARIES).filter(v => v !== LIBRARIES.STORE); + const options: NgxsPackageSchema = { packages }; + testTree = await runner.runSchematicAsync('ng-add', options, inputTree).toPromise(); + const packageJsonText = testTree.readContent('/package.json'); + const packageJson = JSON.parse(packageJsonText); + expect(Object.keys(packageJson.dependencies).sort()).toEqual( + packages.concat(LIBRARIES.STORE).sort() + ); + expect(packageJson.devDependencies).toBeUndefined(); + }); + + it('should not attempt to add non-existent package', async () => { + const packages = ['who-am-i']; + const options: NgxsPackageSchema = { packages }; + await expect( + runner.runSchematicAsync('ng-add', options, inputTree).toPromise() + ).rejects.toThrow(); + }); +}); diff --git a/packages/store/schematics/factories/ng-add/ng-add.factory.ts b/packages/store/schematics/src/ng-add/ng-add.factory.ts similarity index 63% rename from packages/store/schematics/factories/ng-add/ng-add.factory.ts rename to packages/store/schematics/src/ng-add/ng-add.factory.ts index 4af8e9939..ab298f020 100644 --- a/packages/store/schematics/factories/ng-add/ng-add.factory.ts +++ b/packages/store/schematics/src/ng-add/ng-add.factory.ts @@ -10,46 +10,59 @@ import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'; import { addPackageJsonDependency, getPackageJsonDependency, - NodeDependency + NodeDependencyType } from '@schematics/angular/utility/dependencies'; import { addImportToModule } from '@schematics/angular/utility/ast-utils'; import { getAppModulePath } from '@schematics/angular/utility/ng-ast-utils'; -import { LIBRARIES, LIB_CONFIG } from '../../utils/common/lib.config'; +import { LIBRARIES } from '../utils/common/lib.config'; import { NgxsPackageSchema } from './ng-add.schema'; import { InsertChange } from '@schematics/angular/utility/change'; -import * as ts from '../../../../../node_modules/@schematics/angular/third_party/github.com/Microsoft/TypeScript/lib/typescript'; -import { getProject } from '../../utils/project'; +import * as ts from 'typescript'; +import { getProject } from '../utils/project'; +const versions = require('./../utils/versions.json'); export function ngAdd(options: NgxsPackageSchema): Rule { return chain([ addNgxsPackageToPackageJson(options), finallyLog(), - options.skipInstall ? noop() : runNpmPackageInstall(), - options.skipInstall ? noop() : addDeclarationToNgModule(options) + addDeclarationToNgModule(options), + options.skipInstall ? noop() : runNpmPackageInstall() ]); } -function addNgxsPackageToPackageJson(options: NgxsPackageSchema) { +function addNgxsPackageToPackageJson(options: NgxsPackageSchema): Rule { return (host: Tree, context: SchematicContext) => { context.logger.info('Adding npm dependencies'); - LIB_CONFIG.filter( - lib => lib.name === LIBRARIES.STORE || options.packages?.includes(lib.name) - ).forEach(({ type, version, name, overwrite }: NodeDependency) => { - const packageExists = getPackageJsonDependency(host, name); - if (packageExists === null) { - addPackageJsonDependency(host, { type, version, name, overwrite }); - context.logger.info(`✅️ Added "${name}" into ${type}`); - } else { - context.logger.warn(`✅️ "${name}" already exists in the ${type}`); - } - }); + const ngxsStoreVersion: string = versions['@ngxs/store']; + if (!ngxsStoreVersion) { + throw new SchematicsException('Could not resolve the version of "@ngxs/store"'); + } + + Object.values(LIBRARIES) + .filter(lib => options.packages?.includes(lib)) + .forEach(name => { + const packageExists = getPackageJsonDependency(host, name); + if (packageExists === null) { + addPackageJsonDependency(host, { + type: NodeDependencyType.Default, + name, + version: ngxsStoreVersion + }); + context.logger.info(`✅️ Added "${name}" into ${NodeDependencyType.Default}`); + } + { + context.logger.warn( + `✅️ "${name}" already exists in the ${NodeDependencyType.Default}` + ); + } + }); return host; }; } -function runNpmPackageInstall() { +function runNpmPackageInstall(): Rule { return (_: Tree, context: SchematicContext) => { context.addTask(new NodePackageInstallTask()); context.logger.info(`🔍 Installing packages...`); @@ -67,23 +80,19 @@ function finallyLog(): Rule { } function addDeclarationToNgModule(options: NgxsPackageSchema): Rule { - return (host: Tree, context: SchematicContext) => { + return (host: Tree) => { if (typeof options.name === 'undefined' || options.name === '') { return host; } const project = getProject(host, { project: options.name }); - context.logger.info(JSON.stringify(project)); - if (typeof project === 'undefined' || project === null) { throw new SchematicsException(`Project "${options.name}" does not exist.`); } const modulePath = getAppModulePath(host, `${project.root}/src/main.ts`); - context.logger.info(`module path, ${modulePath}`); - if (typeof modulePath === 'undefined') { throw new SchematicsException( `Module path for project "${options.name}" does not exist.` @@ -93,7 +102,7 @@ function addDeclarationToNgModule(options: NgxsPackageSchema): Rule { const importPath = '@ngxs/store'; const moduleImport = - 'NgxsModule.forRoot([], { developmentMode: !environment.production, selectorOptions: { suppressErrors: false, injectContainerState: false } })'; + 'NgxsModule.forRoot([], { developmentMode: /** !environment.production */ false, selectorOptions: { suppressErrors: false, injectContainerState: false } })'; const sourceBuffer = host.read(modulePath); @@ -101,7 +110,7 @@ function addDeclarationToNgModule(options: NgxsPackageSchema): Rule { const sourceText = sourceBuffer.toString(); const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true); - const changes = addImportToModule(source, modulePath, moduleImport, importPath); + const changes = addImportToModule(source as any, modulePath, moduleImport, importPath); const recorder = host.beginUpdate(modulePath); for (const change of changes) { diff --git a/packages/store/schematics/factories/ng-add/ng-add.schema.d.ts b/packages/store/schematics/src/ng-add/ng-add.schema.d.ts similarity index 94% rename from packages/store/schematics/factories/ng-add/ng-add.schema.d.ts rename to packages/store/schematics/src/ng-add/ng-add.schema.d.ts index 54ca8fbfc..05eec9f66 100644 --- a/packages/store/schematics/factories/ng-add/ng-add.schema.d.ts +++ b/packages/store/schematics/src/ng-add/ng-add.schema.d.ts @@ -10,5 +10,5 @@ export interface NgxsPackageSchema { /** * The application project name to add the Ngxs module import to. */ - name: string; + name?: string; } diff --git a/packages/store/schematics/factories/ng-add/schema.json b/packages/store/schematics/src/ng-add/schema.json similarity index 97% rename from packages/store/schematics/factories/ng-add/schema.json rename to packages/store/schematics/src/ng-add/schema.json index 630ed616a..6dc54c15f 100644 --- a/packages/store/schematics/factories/ng-add/schema.json +++ b/packages/store/schematics/src/ng-add/schema.json @@ -58,7 +58,7 @@ }, { "value": "@ngxs/websocket-plugin", - "label": "Ngxs websockt plugin" + "label": "Ngxs websocket plugin" } ] } diff --git a/packages/store/schematics/templates/starter-kit/store/auth/auth.actions.ts__template__ b/packages/store/schematics/src/starter-kit/files/store/auth/auth.actions.ts__template__ similarity index 100% rename from packages/store/schematics/templates/starter-kit/store/auth/auth.actions.ts__template__ rename to packages/store/schematics/src/starter-kit/files/store/auth/auth.actions.ts__template__ diff --git a/packages/store/schematics/templates/starter-kit/store/auth/auth.state.spec.ts__template__ b/packages/store/schematics/src/starter-kit/files/store/auth/auth.state.spec.ts__template__ similarity index 100% rename from packages/store/schematics/templates/starter-kit/store/auth/auth.state.spec.ts__template__ rename to packages/store/schematics/src/starter-kit/files/store/auth/auth.state.spec.ts__template__ diff --git a/packages/store/schematics/templates/starter-kit/store/auth/auth.state.ts__template__ b/packages/store/schematics/src/starter-kit/files/store/auth/auth.state.ts__template__ similarity index 100% rename from packages/store/schematics/templates/starter-kit/store/auth/auth.state.ts__template__ rename to packages/store/schematics/src/starter-kit/files/store/auth/auth.state.ts__template__ diff --git a/packages/store/schematics/templates/starter-kit/store/dashboard/index.ts__template__ b/packages/store/schematics/src/starter-kit/files/store/dashboard/index.ts__template__ similarity index 100% rename from packages/store/schematics/templates/starter-kit/store/dashboard/index.ts__template__ rename to packages/store/schematics/src/starter-kit/files/store/dashboard/index.ts__template__ diff --git a/packages/store/schematics/templates/starter-kit/store/dashboard/states/dictionary/dictionary.actions.ts__template__ b/packages/store/schematics/src/starter-kit/files/store/dashboard/states/dictionary/dictionary.actions.ts__template__ similarity index 100% rename from packages/store/schematics/templates/starter-kit/store/dashboard/states/dictionary/dictionary.actions.ts__template__ rename to packages/store/schematics/src/starter-kit/files/store/dashboard/states/dictionary/dictionary.actions.ts__template__ diff --git a/packages/store/schematics/templates/starter-kit/store/dashboard/states/dictionary/dictionary.state.spec.ts__template__ b/packages/store/schematics/src/starter-kit/files/store/dashboard/states/dictionary/dictionary.state.spec.ts__template__ similarity index 100% rename from packages/store/schematics/templates/starter-kit/store/dashboard/states/dictionary/dictionary.state.spec.ts__template__ rename to packages/store/schematics/src/starter-kit/files/store/dashboard/states/dictionary/dictionary.state.spec.ts__template__ diff --git a/packages/store/schematics/templates/starter-kit/store/dashboard/states/dictionary/dictionary.state.ts__template__ b/packages/store/schematics/src/starter-kit/files/store/dashboard/states/dictionary/dictionary.state.ts__template__ similarity index 100% rename from packages/store/schematics/templates/starter-kit/store/dashboard/states/dictionary/dictionary.state.ts__template__ rename to packages/store/schematics/src/starter-kit/files/store/dashboard/states/dictionary/dictionary.state.ts__template__ diff --git a/packages/store/schematics/templates/starter-kit/store/dashboard/states/user/user.actions.ts__template__ b/packages/store/schematics/src/starter-kit/files/store/dashboard/states/user/user.actions.ts__template__ similarity index 100% rename from packages/store/schematics/templates/starter-kit/store/dashboard/states/user/user.actions.ts__template__ rename to packages/store/schematics/src/starter-kit/files/store/dashboard/states/user/user.actions.ts__template__ diff --git a/packages/store/schematics/templates/starter-kit/store/dashboard/states/user/user.state.spec.ts__template__ b/packages/store/schematics/src/starter-kit/files/store/dashboard/states/user/user.state.spec.ts__template__ similarity index 100% rename from packages/store/schematics/templates/starter-kit/store/dashboard/states/user/user.state.spec.ts__template__ rename to packages/store/schematics/src/starter-kit/files/store/dashboard/states/user/user.state.spec.ts__template__ diff --git a/packages/store/schematics/templates/starter-kit/store/dashboard/states/user/user.state.ts__template__ b/packages/store/schematics/src/starter-kit/files/store/dashboard/states/user/user.state.ts__template__ similarity index 100% rename from packages/store/schematics/templates/starter-kit/store/dashboard/states/user/user.state.ts__template__ rename to packages/store/schematics/src/starter-kit/files/store/dashboard/states/user/user.state.ts__template__ diff --git a/packages/store/schematics/templates/starter-kit/store/store.config.ts__template__ b/packages/store/schematics/src/starter-kit/files/store/store.config.ts__template__ similarity index 100% rename from packages/store/schematics/templates/starter-kit/store/store.config.ts__template__ rename to packages/store/schematics/src/starter-kit/files/store/store.config.ts__template__ diff --git a/packages/store/schematics/templates/starter-kit/store/store.module.ts__template__ b/packages/store/schematics/src/starter-kit/files/store/store.module.ts__template__ similarity index 100% rename from packages/store/schematics/templates/starter-kit/store/store.module.ts__template__ rename to packages/store/schematics/src/starter-kit/files/store/store.module.ts__template__ diff --git a/packages/store/schematics/factories/starter-kit/schema.json b/packages/store/schematics/src/starter-kit/schema.json similarity index 71% rename from packages/store/schematics/factories/starter-kit/schema.json rename to packages/store/schematics/src/starter-kit/schema.json index 47e8ba0d8..879afa8ce 100644 --- a/packages/store/schematics/factories/starter-kit/schema.json +++ b/packages/store/schematics/src/starter-kit/schema.json @@ -6,19 +6,13 @@ "properties": { "path": { "type": "string", - "format": "path", "description": "The path to create the starter kit." }, - "sourceRoot": { - "type": "string", - "format": "path", - "description": "The source root path" - }, "spec": { "type": "boolean", "description": "Specifies if a spec file is generated.", "default": true } }, - "required": [] + "required": ["path"] } diff --git a/packages/store/schematics/test/factories/starter-kit/starter-kit.factory.test.ts b/packages/store/schematics/src/starter-kit/starter-kit.factory.spec.ts similarity index 83% rename from packages/store/schematics/test/factories/starter-kit/starter-kit.factory.test.ts rename to packages/store/schematics/src/starter-kit/starter-kit.factory.spec.ts index a2080c385..7b609a50c 100644 --- a/packages/store/schematics/test/factories/starter-kit/starter-kit.factory.test.ts +++ b/packages/store/schematics/src/starter-kit/starter-kit.factory.spec.ts @@ -1,19 +1,20 @@ import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; import * as path from 'path'; -import { FACTORIES } from '../../../utils'; -import { StarterKitSchema } from '../../../factories/starter-kit/starter-kit.schema'; +import { workspaceRoot } from '@nrwl/devkit'; +import { StarterKitSchema } from './starter-kit.schema'; describe('Generate ngxs starter kit', () => { const runner: SchematicTestRunner = new SchematicTestRunner( '.', - path.join(process.cwd(), 'src/collection.json') + path.join(workspaceRoot, 'packages/store/schematics/collection.json') ); it('should generate store in default root folder', async () => { const options: StarterKitSchema = { - spec: true + spec: true, + path: './src' }; const tree: UnitTestTree = await runner - .runSchematicAsync(FACTORIES.STARTER_KIT, options) + .runSchematicAsync('starter-kit', options) .toPromise(); const files: string[] = tree.files; expect(files).toEqual([ @@ -34,10 +35,11 @@ describe('Generate ngxs starter kit', () => { it('should generate store in default root folder with spec false', async () => { const options: StarterKitSchema = { - spec: false + spec: false, + path: './src' }; const tree: UnitTestTree = await runner - .runSchematicAsync(FACTORIES.STARTER_KIT, options) + .runSchematicAsync('starter-kit', options) .toPromise(); const files: string[] = tree.files; expect(files).toEqual([ diff --git a/packages/store/schematics/src/starter-kit/starter-kit.factory.ts b/packages/store/schematics/src/starter-kit/starter-kit.factory.ts new file mode 100644 index 000000000..7734d6a2b --- /dev/null +++ b/packages/store/schematics/src/starter-kit/starter-kit.factory.ts @@ -0,0 +1,10 @@ +import { Rule, url } from '@angular-devkit/schematics'; +import { StarterKitSchema } from './starter-kit.schema'; +import { normalizePath } from '../utils/normalize-options'; +import { generateFiles } from '../utils/generate-utils'; + +export function starterKit(options: StarterKitSchema): Rule { + const normalizedPath = normalizePath(options.path); + + return generateFiles(url('./files'), normalizedPath, options, options.spec); +} diff --git a/packages/store/schematics/factories/starter-kit/starter-kit.schema.d.ts b/packages/store/schematics/src/starter-kit/starter-kit.schema.d.ts similarity index 72% rename from packages/store/schematics/factories/starter-kit/starter-kit.schema.d.ts rename to packages/store/schematics/src/starter-kit/starter-kit.schema.d.ts index 609a8d587..39c99ac68 100644 --- a/packages/store/schematics/factories/starter-kit/starter-kit.schema.d.ts +++ b/packages/store/schematics/src/starter-kit/starter-kit.schema.d.ts @@ -3,10 +3,6 @@ export interface StarterKitSchema { * The path to create the starter kit. */ path?: string; - /** - * The source root path - */ - sourceRoot?: string; /** * The spec flag */ diff --git a/packages/store/schematics/templates/state/__name__.state.spec.ts__template__ b/packages/store/schematics/src/state/files/__name__.state.spec.ts__template__ similarity index 100% rename from packages/store/schematics/templates/state/__name__.state.spec.ts__template__ rename to packages/store/schematics/src/state/files/__name__.state.spec.ts__template__ diff --git a/packages/store/schematics/templates/state/__name__.state.ts__template__ b/packages/store/schematics/src/state/files/__name__.state.ts__template__ similarity index 100% rename from packages/store/schematics/templates/state/__name__.state.ts__template__ rename to packages/store/schematics/src/state/files/__name__.state.ts__template__ diff --git a/packages/store/schematics/factories/state/schema.json b/packages/store/schematics/src/state/schema.json similarity index 84% rename from packages/store/schematics/factories/state/schema.json rename to packages/store/schematics/src/state/schema.json index d8919afb0..d53d99e73 100644 --- a/packages/store/schematics/factories/state/schema.json +++ b/packages/store/schematics/src/state/schema.json @@ -18,15 +18,15 @@ "format": "path", "description": "The path to create the state." }, - "sourceRoot": { - "type": "string", - "format": "path", - "description": "The source root path" - }, "spec": { "type": "boolean", "description": "Specifies if a spec file is generated.", "default": true + }, + "flat": { + "type": "boolean", + "default": false, + "description": "Flag to indicate if a dir is created." } }, "required": ["name"] diff --git a/packages/store/schematics/src/state/state.factory.spec.ts b/packages/store/schematics/src/state/state.factory.spec.ts new file mode 100644 index 000000000..6da81da02 --- /dev/null +++ b/packages/store/schematics/src/state/state.factory.spec.ts @@ -0,0 +1,50 @@ +import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; +import { workspaceRoot } from '@nrwl/devkit'; + +import * as path from 'path'; +import { StateSchema } from './state.schema'; + +describe('Generate ngxs state', () => { + const runner: SchematicTestRunner = new SchematicTestRunner( + '.', + path.join(workspaceRoot, 'packages/store/schematics/collection.json') + ); + it('should manage name only', async () => { + const options: StateSchema = { + name: 'todos' + }; + const tree: UnitTestTree = await runner.runSchematicAsync('state', options).toPromise(); + const files: string[] = tree.files; + expect(files).toEqual(['/todos/todos.state.spec.ts', '/todos/todos.state.ts']); + }); + + it('should not create a separate folder if "flat" is set to "true"', async () => { + const options: StateSchema = { + name: 'todos', + flat: true + }; + const tree: UnitTestTree = await runner.runSchematicAsync('state', options).toPromise(); + const files: string[] = tree.files; + expect(files).toEqual(['/todos.state.spec.ts', '/todos.state.ts']); + }); + + it('should manage name with spec true', async () => { + const options: StateSchema = { + name: 'auth', + spec: true + }; + const tree: UnitTestTree = await runner.runSchematicAsync('state', options).toPromise(); + const files: string[] = tree.files; + expect(files).toEqual(['/auth/auth.state.spec.ts', '/auth/auth.state.ts']); + }); + + it('should manage name with spec false', async () => { + const options: StateSchema = { + name: 'users', + spec: false + }; + const tree: UnitTestTree = await runner.runSchematicAsync('state', options).toPromise(); + const files: string[] = tree.files; + expect(files).toEqual(['/users/users.state.ts']); + }); +}); diff --git a/packages/store/schematics/src/state/state.factory.ts b/packages/store/schematics/src/state/state.factory.ts new file mode 100644 index 000000000..aed49da97 --- /dev/null +++ b/packages/store/schematics/src/state/state.factory.ts @@ -0,0 +1,19 @@ +import { Rule, SchematicsException, url } from '@angular-devkit/schematics'; +import { StateSchema } from './state.schema'; +import { isEmpty } from '../utils/common/properties'; +import { normalizeBaseOptions } from '../utils/normalize-options'; +import { generateFiles } from '../utils/generate-utils'; +import { join } from 'path'; + +export function state(options: StateSchema): Rule { + if (isEmpty(options.name)) { + throw new SchematicsException('Invalid options, "name" is required.'); + } + + const normalizedOptions = normalizeBaseOptions(options); + const path = options.flat + ? normalizedOptions.path + : join(normalizedOptions.path, normalizedOptions.name); + + return generateFiles(url('./files'), path, options, options.spec); +} diff --git a/packages/store/schematics/factories/state/state.schema.d.ts b/packages/store/schematics/src/state/state.schema.d.ts similarity index 77% rename from packages/store/schematics/factories/state/state.schema.d.ts rename to packages/store/schematics/src/state/state.schema.d.ts index 6de9a9a8c..441a1319c 100644 --- a/packages/store/schematics/factories/state/state.schema.d.ts +++ b/packages/store/schematics/src/state/state.schema.d.ts @@ -7,12 +7,12 @@ export interface StateSchema { * The path to create the state. */ path?: string; - /** - * The source root path - */ - sourceRoot?: string; /** * The spec flag */ spec?: boolean; + /** + * Flag to indicate if a dir is created. + */ + flat?: boolean; } diff --git a/packages/store/schematics/templates/store/__name__.actions.ts__template__ b/packages/store/schematics/src/store/files/__name__.actions.ts__template__ similarity index 100% rename from packages/store/schematics/templates/store/__name__.actions.ts__template__ rename to packages/store/schematics/src/store/files/__name__.actions.ts__template__ diff --git a/packages/store/schematics/templates/store/__name__.state.spec.ts__template__ b/packages/store/schematics/src/store/files/__name__.state.spec.ts__template__ similarity index 100% rename from packages/store/schematics/templates/store/__name__.state.spec.ts__template__ rename to packages/store/schematics/src/store/files/__name__.state.spec.ts__template__ diff --git a/packages/store/schematics/templates/store/__name__.state.ts__template__ b/packages/store/schematics/src/store/files/__name__.state.ts__template__ similarity index 100% rename from packages/store/schematics/templates/store/__name__.state.ts__template__ rename to packages/store/schematics/src/store/files/__name__.state.ts__template__ diff --git a/packages/store/schematics/factories/store/schema.json b/packages/store/schematics/src/store/schema.json similarity index 84% rename from packages/store/schematics/factories/store/schema.json rename to packages/store/schematics/src/store/schema.json index f0b2b67ed..b136a1437 100644 --- a/packages/store/schematics/factories/store/schema.json +++ b/packages/store/schematics/src/store/schema.json @@ -18,15 +18,15 @@ "format": "path", "description": "The path to create the store." }, - "sourceRoot": { - "type": "string", - "format": "path", - "description": "The source root path" - }, "spec": { "type": "boolean", "description": "Specifies if a spec file is generated.", "default": true + }, + "flat": { + "type": "boolean", + "default": false, + "description": "Flag to indicate if a dir is created." } }, "required": ["name"] diff --git a/packages/store/schematics/src/store/store.factory.spec.ts b/packages/store/schematics/src/store/store.factory.spec.ts new file mode 100644 index 000000000..ac1a6fe18 --- /dev/null +++ b/packages/store/schematics/src/store/store.factory.spec.ts @@ -0,0 +1,57 @@ +import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; +import { workspaceRoot } from '@nrwl/devkit'; + +import * as path from 'path'; +import { StoreSchema } from './store.schema'; + +describe('NGXS Store', () => { + const runner: SchematicTestRunner = new SchematicTestRunner( + '.', + path.join(workspaceRoot, 'packages/store/schematics/collection.json') + ); + it('should manage name only', async () => { + const options: StoreSchema = { + name: 'todos' + }; + const tree: UnitTestTree = await runner.runSchematicAsync('store', options).toPromise(); + const files: string[] = tree.files; + expect(files).toEqual([ + '/todos/todos.actions.ts', + '/todos/todos.state.spec.ts', + '/todos/todos.state.ts' + ]); + }); + it('should not create a separate folder if "flat" is set to "true"', async () => { + const options: StoreSchema = { + name: 'todos', + flat: true + }; + const tree: UnitTestTree = await runner.runSchematicAsync('store', options).toPromise(); + const files: string[] = tree.files; + expect(files).toEqual(['/todos.actions.ts', '/todos.state.spec.ts', '/todos.state.ts']); + }); + + it('should manage name with spec false', async () => { + const options: StoreSchema = { + name: 'auth', + spec: false + }; + const tree: UnitTestTree = await runner.runSchematicAsync('store', options).toPromise(); + const files: string[] = tree.files; + expect(files).toEqual(['/auth/auth.actions.ts', '/auth/auth.state.ts']); + }); + + it('should manage name with spec true', async () => { + const options: StoreSchema = { + name: 'users', + spec: true + }; + const tree: UnitTestTree = await runner.runSchematicAsync('store', options).toPromise(); + const files: string[] = tree.files; + expect(files).toEqual([ + '/users/users.actions.ts', + '/users/users.state.spec.ts', + '/users/users.state.ts' + ]); + }); +}); diff --git a/packages/store/schematics/src/store/store.factory.ts b/packages/store/schematics/src/store/store.factory.ts new file mode 100644 index 000000000..165e48bb0 --- /dev/null +++ b/packages/store/schematics/src/store/store.factory.ts @@ -0,0 +1,19 @@ +import { Rule, SchematicsException, url } from '@angular-devkit/schematics'; +import { StoreSchema } from './store.schema'; +import { isEmpty } from '../utils/common/properties'; +import { normalizeBaseOptions } from '../utils/normalize-options'; +import { generateFiles } from '../utils/generate-utils'; +import { join } from 'path'; + +export function store(options: StoreSchema): Rule { + if (isEmpty(options.name)) { + throw new SchematicsException('Invalid options, "name" is required.'); + } + + const normalizedOptions = normalizeBaseOptions(options); + const path = options.flat + ? normalizedOptions.path + : join(normalizedOptions.path, normalizedOptions.name); + + return generateFiles(url('./files'), path, options, options.spec); +} diff --git a/packages/store/schematics/factories/store/store.schema.d.ts b/packages/store/schematics/src/store/store.schema.d.ts similarity index 77% rename from packages/store/schematics/factories/store/store.schema.d.ts rename to packages/store/schematics/src/store/store.schema.d.ts index 0c3710752..7b7135c24 100644 --- a/packages/store/schematics/factories/store/store.schema.d.ts +++ b/packages/store/schematics/src/store/store.schema.d.ts @@ -7,12 +7,12 @@ export interface StoreSchema { * The path to create the store. */ path?: string; - /** - * The source root path - */ - sourceRoot?: string; /** * The spec flag */ spec?: boolean; + /** + * Flag to indicate if a dir is created. + */ + flat?: boolean; } diff --git a/packages/store/schematics/src/utils/common/lib.config.ts b/packages/store/schematics/src/utils/common/lib.config.ts new file mode 100644 index 000000000..2caf9e89c --- /dev/null +++ b/packages/store/schematics/src/utils/common/lib.config.ts @@ -0,0 +1,10 @@ +export enum LIBRARIES { + DEVTOOLS = '@ngxs/devtools-plugin', + FORM = '@ngxs/form-plugin', + HMR = '@ngxs/hmr-plugin', + LOGGER = '@ngxs/logger-plugin', + ROUTER = '@ngxs/router-plugin', + STORAGE = '@ngxs/storage-plugin', + STORE = '@ngxs/store', + WEBSOCKET = '@ngxs/websocket-plugin' +} diff --git a/packages/store/schematics/utils/common/project-files.config.ts b/packages/store/schematics/src/utils/common/project-files.config.ts similarity index 100% rename from packages/store/schematics/utils/common/project-files.config.ts rename to packages/store/schematics/src/utils/common/project-files.config.ts diff --git a/packages/store/schematics/utils/common/properties.ts b/packages/store/schematics/src/utils/common/properties.ts similarity index 100% rename from packages/store/schematics/utils/common/properties.ts rename to packages/store/schematics/src/utils/common/properties.ts diff --git a/packages/store/schematics/utils/config.ts b/packages/store/schematics/src/utils/config.ts similarity index 100% rename from packages/store/schematics/utils/config.ts rename to packages/store/schematics/src/utils/config.ts diff --git a/packages/store/schematics/src/utils/generate-utils.ts b/packages/store/schematics/src/utils/generate-utils.ts new file mode 100644 index 000000000..11303de1b --- /dev/null +++ b/packages/store/schematics/src/utils/generate-utils.ts @@ -0,0 +1,32 @@ +import { strings } from '@angular-devkit/core'; +import { + apply, + filter, + move, + noop, + template, + Rule, + mergeWith, + Source +} from '@angular-devkit/schematics'; + +export function generateFiles( + srcFolder: Source, + target: string, + substitutions: { + [k: string]: any; + }, + generateSpecs?: boolean +): Rule { + return mergeWith( + apply(srcFolder, [ + generateSpecs ? noop() : filter(path => !path.includes('.spec')), + template({ + template: '', + ...strings, + ...substitutions + }), + move(target) + ]) + ); +} diff --git a/packages/store/schematics/utils/interfaces/package.interface.ts b/packages/store/schematics/src/utils/interfaces/package.interface.ts similarity index 100% rename from packages/store/schematics/utils/interfaces/package.interface.ts rename to packages/store/schematics/src/utils/interfaces/package.interface.ts diff --git a/packages/store/schematics/src/utils/normalize-options.spec.ts b/packages/store/schematics/src/utils/normalize-options.spec.ts new file mode 100644 index 000000000..3f6720f6e --- /dev/null +++ b/packages/store/schematics/src/utils/normalize-options.spec.ts @@ -0,0 +1,30 @@ +import { normalizeBaseOptions, normalizeOptionalBoolean } from './normalize-options'; + +describe('normalizeBaseOptions', function () { + test.each` + options | expected + ${{ name: '' }} | ${{ name: '', path: '' }} + ${{ name: 'MyComponent', path: '' }} | ${{ name: 'my-component', path: '' }} + ${{ name: 'MyComponent', path: 'app/components', extraProp: 'value' }} | ${{ name: 'my-component', path: 'app/components', extraProp: 'value' }} + ${{ name: 'MyComponent', path: 'app/../invalid-path' }} | ${{ name: 'my-component', path: 'invalid-path' }} + `('should normalize options $options as $expected', function ({ options, expected }) { + var normalizedOptions = normalizeBaseOptions(options); + expect(normalizedOptions).toEqual(expected); + }); +}); + +describe('normalizeOptionalBoolean', function () { + test.each` + value | defaultValue | expected + ${true} | ${false} | ${true} + ${false} | ${true} | ${false} + ${undefined} | ${true} | ${true} + ${null} | ${false} | ${false} + `( + 'should return $expected when value is $value and default is $defaultValue', + function ({ value, defaultValue, expected }) { + var result = normalizeOptionalBoolean(value, defaultValue); + expect(result).toBe(expected); + } + ); +}); diff --git a/packages/store/schematics/src/utils/normalize-options.ts b/packages/store/schematics/src/utils/normalize-options.ts new file mode 100644 index 000000000..f2d088794 --- /dev/null +++ b/packages/store/schematics/src/utils/normalize-options.ts @@ -0,0 +1,33 @@ +import { normalize, strings } from '@angular-devkit/core'; + +interface BaseOptions { + name: string; + path?: string; +} + +export function normalizeBaseOptions( + options: T +): T & Required { + const name: string = strings.dasherize(options.name); + const path = normalizePath(options.path); + return { + ...options, + name, + path + }; +} + +export function normalizePath(path: string | undefined): string { + return path !== undefined ? normalize(path) : ''; +} + +/** Returns `value` if it's "true" | "false" and default value otherwise */ +export function normalizeOptionalBoolean( + value: boolean | undefined, + defaultValue: boolean +): boolean { + if (value === true || value === false) { + return value; + } + return defaultValue; +} diff --git a/packages/store/schematics/utils/project.ts b/packages/store/schematics/src/utils/project.ts similarity index 100% rename from packages/store/schematics/utils/project.ts rename to packages/store/schematics/src/utils/project.ts diff --git a/packages/store/schematics/src/utils/versions.json b/packages/store/schematics/src/utils/versions.json new file mode 100644 index 000000000..c0b690178 --- /dev/null +++ b/packages/store/schematics/src/utils/versions.json @@ -0,0 +1,3 @@ +{ + "@ngxs/store": "3.8.1" +} diff --git a/packages/store/schematics/test/factories/actions/actions.factory.test.ts b/packages/store/schematics/test/factories/actions/actions.factory.test.ts deleted file mode 100644 index e5e1f5f77..000000000 --- a/packages/store/schematics/test/factories/actions/actions.factory.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; - -import * as path from 'path'; - -import { FACTORIES } from '../../../utils'; -import { propertyNotEmpty } from '../common/properties'; - -import { ActionsSchema } from '../../../factories/actions/actions.schema'; - -describe('NGXS Actions', () => { - const runner: SchematicTestRunner = new SchematicTestRunner( - '.', - path.join(process.cwd(), 'src/collection.json') - ); - it('should manage name only', async () => { - const options: ActionsSchema = { - name: 'todos' - }; - const tree: UnitTestTree = await runner - .runSchematicAsync(FACTORIES.ACTIONS, options) - .toPromise(); - const files: string[] = tree.files; - expect(files).toEqual(['/src/todos/todos.actions.ts']); - }); - - it('should error when name is empty', async () => { - await propertyNotEmpty(runner, FACTORIES.ACTIONS, 'name'); - }); -}); diff --git a/packages/store/schematics/test/factories/common/properties.ts b/packages/store/schematics/test/factories/common/properties.ts deleted file mode 100644 index d3470526d..000000000 --- a/packages/store/schematics/test/factories/common/properties.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; - -/** - * Validate that a schema property is not empty or contains only spaces. - * - * @param runner SchematicsTestRunner configured in the test suite. - * @param factory Name of the factory being tested. - * @param property Property name being tested. - */ -export async function propertyNotEmpty( - runner: SchematicTestRunner, - factory: string, - property: string -) { - await expect(() => - runner.runSchematicAsync(factory, { [property]: '' }).toPromise() - ).rejects.toThrow(`Invalid options, "${property}" is required.`); - - await expect(() => - runner.runSchematicAsync(factory, { [property]: ' ' }).toPromise() - ).rejects.toThrow(`Invalid options, "${property}" is required.`); -} diff --git a/packages/store/schematics/test/factories/ng-add/common/package.json b/packages/store/schematics/test/factories/ng-add/common/package.json deleted file mode 100644 index 9f1f9e8ed..000000000 --- a/packages/store/schematics/test/factories/ng-add/common/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "test", - "version": "0.0.0", - "license": "MIT", - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build", - "test": "ng test", - "lint": "ng lint", - "e2e": "ng e2e" - }, - "private": true, - "dependencies": {} -} diff --git a/packages/store/schematics/test/factories/ng-add/ng-add.factory.test.ts b/packages/store/schematics/test/factories/ng-add/ng-add.factory.test.ts deleted file mode 100644 index 4cc0dc8ac..000000000 --- a/packages/store/schematics/test/factories/ng-add/ng-add.factory.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; -import { Tree } from '@angular-devkit/schematics'; -import { NodeDependencyType } from '@schematics/angular/utility/dependencies'; - -import * as path from 'path'; -import * as fs from 'fs'; -import { depsToAdd } from 'packages/store/schematics/utils/get-library'; - -describe('ng-add package in package.json', () => { - const runner: SchematicTestRunner = new SchematicTestRunner( - 'schematics', - path.join(process.cwd(), 'src/collection.json') - ); - let testTree: UnitTestTree; - let inputTree: Tree; - - beforeEach(() => { - inputTree = Tree.empty(); - inputTree.create( - '/package.json', - fs.readFileSync(path.join(__dirname, './common/package.json'), 'utf8') - ); - }); - - it('should add ngxs store with plugins in package.json', async () => { - testTree = await runner.runSchematicAsync('ng-add', {}, inputTree).toPromise(); - const packageJsonText = testTree.readContent('/package.json'); - const packageJson = JSON.parse(packageJsonText); - expect(Object.keys(packageJson.dependencies)).toEqual( - depsToAdd(NodeDependencyType.Default) - ); - expect(Object.keys(packageJson.devDependencies)).toEqual( - depsToAdd(NodeDependencyType.Dev) - ); - }); -}); diff --git a/packages/store/schematics/test/factories/state/state.factory.test.ts b/packages/store/schematics/test/factories/state/state.factory.test.ts deleted file mode 100644 index 4ce021b82..000000000 --- a/packages/store/schematics/test/factories/state/state.factory.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; - -import * as path from 'path'; - -import { FACTORIES } from '../../../utils'; -import { propertyNotEmpty } from '../common/properties'; - -import { StateSchema } from '../../../factories/state/state.schema'; - -describe('Generate ngxs state', () => { - const runner: SchematicTestRunner = new SchematicTestRunner( - '.', - path.join(process.cwd(), 'src/collection.json') - ); - it('should manage name only', async () => { - const options: StateSchema = { - name: 'todos' - }; - const tree: UnitTestTree = await runner - .runSchematicAsync(FACTORIES.STATE, options) - .toPromise(); - const files: string[] = tree.files; - expect(files).toEqual(['/src/todos/todos.state.spec.ts', '/src/todos/todos.state.ts']); - }); - - it('should manage name with spec true', async () => { - const options: StateSchema = { - name: 'auth', - spec: true - }; - const tree: UnitTestTree = await runner - .runSchematicAsync(FACTORIES.STATE, options) - .toPromise(); - const files: string[] = tree.files; - expect(files).toEqual(['/src/auth/auth.state.spec.ts', '/src/auth/auth.state.ts']); - }); - - it('should manage name with spec false', async () => { - const options: StateSchema = { - name: 'users', - spec: false - }; - const tree: UnitTestTree = await runner - .runSchematicAsync(FACTORIES.STATE, options) - .toPromise(); - const files: string[] = tree.files; - expect(files).toEqual(['/src/users/users.state.ts']); - }); - - it('should error when name is empty', async () => { - await propertyNotEmpty(runner, FACTORIES.STATE, 'name'); - }); -}); diff --git a/packages/store/schematics/test/factories/store/store.factory.test.ts b/packages/store/schematics/test/factories/store/store.factory.test.ts deleted file mode 100644 index 252451fc1..000000000 --- a/packages/store/schematics/test/factories/store/store.factory.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; - -import * as path from 'path'; - -import { FACTORIES } from '../../../utils'; -import { propertyNotEmpty } from '../common/properties'; - -import { StoreSchema } from '../../../factories/store/store.schema'; - -describe('NGXS Store', () => { - const runner: SchematicTestRunner = new SchematicTestRunner( - '.', - path.join(process.cwd(), 'src/collection.json') - ); - it('should manage name only', async () => { - const options: StoreSchema = { - name: 'todos' - }; - const tree: UnitTestTree = await runner - .runSchematicAsync(FACTORIES.STORE, options) - .toPromise(); - const files: string[] = tree.files; - expect(files).toEqual([ - '/src/todos/todos.actions.ts', - '/src/todos/todos.state.spec.ts', - '/src/todos/todos.state.ts' - ]); - }); - - it('should manage name with spec false', async () => { - const options: StoreSchema = { - name: 'auth', - spec: false - }; - const tree: UnitTestTree = await runner - .runSchematicAsync(FACTORIES.STORE, options) - .toPromise(); - const files: string[] = tree.files; - expect(files).toEqual(['/src/auth/auth.actions.ts', '/src/auth/auth.state.ts']); - }); - - it('should manage name with spec true', async () => { - const options: StoreSchema = { - name: 'users', - spec: true - }; - const tree: UnitTestTree = await runner - .runSchematicAsync(FACTORIES.STORE, options) - .toPromise(); - const files: string[] = tree.files; - expect(files).toEqual([ - '/src/users/users.actions.ts', - '/src/users/users.state.spec.ts', - '/src/users/users.state.ts' - ]); - }); - - it('should error when name is empty', async () => { - await propertyNotEmpty(runner, FACTORIES.STORE, 'name'); - }); -}); diff --git a/packages/store/schematics/test/jest.config.json b/packages/store/schematics/test/jest.config.json deleted file mode 100644 index 47b821664..000000000 --- a/packages/store/schematics/test/jest.config.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "moduleFileExtensions": ["js", "json", "ts"], - "rootDir": ".", - "testRegex": ".(test|spec).ts$", - "transform": { - "^.+\\.ts$": "ts-jest" - }, - "coverageDirectory": "../coverage", - "verbose": true, - "bail": true -} diff --git a/packages/store/schematics/test/tsconfig.test.json b/packages/store/schematics/test/tsconfig.test.json deleted file mode 100644 index 8caac86c4..000000000 --- a/packages/store/schematics/test/tsconfig.test.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../../tsconfig.app.json", - "compilerOptions": { - "typeRoots": ["../node_modules/@types"] - }, - "include": ["."], - "exclude": ["../node_modules", "../src"] -} diff --git a/packages/store/schematics/test/utils/parser.test.ts b/packages/store/schematics/test/utils/parser.test.ts deleted file mode 100644 index 43c6768eb..000000000 --- a/packages/store/schematics/test/utils/parser.test.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Parser } from '../../utils'; -import { Location, ParseOptions } from '../../utils/interfaces/parser.interface'; - -describe('Name Parser', () => { - let parser: Parser; - beforeAll(() => (parser = new Parser())); - it('should handle no path', () => { - const options: ParseOptions = { - name: 'foo' - }; - const location: Location = parser.nameParser(options); - expect(location.name).toEqual('foo'); - expect(location.path).toEqual('/'); - }); - it('should handle just the name', () => { - const options: ParseOptions = { - name: 'foo', - path: 'baz' - }; - const location: Location = parser.nameParser(options); - expect(location.name).toEqual('foo'); - expect(location.path).toEqual('/baz'); - }); - it('should handle name has a path (sub-dir)', () => { - const options: ParseOptions = { - name: 'bar/foo', - path: 'baz' - }; - const location: Location = parser.nameParser(options); - expect(location.name).toEqual('foo'); - expect(location.path).toEqual('/baz/bar'); - }); - - it('should handle name has a higher path', () => { - const options: ParseOptions = { - name: '../foo', - path: 'bar/baz' - }; - const location: Location = parser.nameParser(options); - expect(location.name).toEqual('foo'); - expect(location.path).toEqual('/bar'); - }); - - it('should handle name has a higher path above root', () => { - const options: ParseOptions = { - name: '../../../foo', - path: 'baz' - }; - expect(() => parser.nameParser(options)).toThrow(); - }); -}); diff --git a/packages/store/schematics/utils/common/factories.enum.ts b/packages/store/schematics/utils/common/factories.enum.ts deleted file mode 100644 index e8db737b8..000000000 --- a/packages/store/schematics/utils/common/factories.enum.ts +++ /dev/null @@ -1,6 +0,0 @@ -export enum FACTORIES { - STATE = 'state', - STORE = 'store', - ACTIONS = 'actions', - STARTER_KIT = 'starter-kit' -} diff --git a/packages/store/schematics/utils/common/lib.config.ts b/packages/store/schematics/utils/common/lib.config.ts deleted file mode 100644 index 546c03f99..000000000 --- a/packages/store/schematics/utils/common/lib.config.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { NodeDependency, NodeDependencyType } from '@schematics/angular/utility/dependencies'; - -export enum LIBRARIES { - DEVTOOLS = '@ngxs/devtools-plugin', - FORM = '@ngxs/form-plugin', - HMR = '@ngxs/hmr-plugin', - LOGGER = '@ngxs/logger-plugin', - ROUTER = '@ngxs/router-plugin', - STORAGE = '@ngxs/storage-plugin', - STORE = '@ngxs/store', - WEBSOCKET = '@ngxs/websocket-plugin' -} - -/** - * Common library configuration options. - */ -const configOptions = { - version: '3.7.3', - overwrite: true -}; - -export const LIB_CONFIG: NodeDependency[] = [ - { - type: NodeDependencyType.Default, - name: LIBRARIES.DEVTOOLS, - ...configOptions - }, - { - type: NodeDependencyType.Default, - name: LIBRARIES.FORM, - ...configOptions - }, - { - type: NodeDependencyType.Default, - name: LIBRARIES.HMR, - ...configOptions - }, - { - type: NodeDependencyType.Default, - name: LIBRARIES.LOGGER, - ...configOptions - }, - { - type: NodeDependencyType.Default, - name: LIBRARIES.ROUTER, - ...configOptions - }, - { - type: NodeDependencyType.Default, - name: LIBRARIES.STORAGE, - ...configOptions - }, - { - type: NodeDependencyType.Default, - name: LIBRARIES.STORE, - ...configOptions - }, - { - type: NodeDependencyType.Default, - name: LIBRARIES.WEBSOCKET, - ...configOptions - } -]; diff --git a/packages/store/schematics/utils/factory-loader.ts b/packages/store/schematics/utils/factory-loader.ts deleted file mode 100644 index 94f4cd3ac..000000000 --- a/packages/store/schematics/utils/factory-loader.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { mergeWith, Rule, SchematicsException } from '@angular-devkit/schematics'; - -import { FACTORIES } from './common/factories.enum'; -import { isEmpty } from './common/properties'; -import { StarterKitSchema } from '../factories/starter-kit/starter-kit.schema'; - -import { transform } from './transform-options'; -import { generate } from './generate-factory'; - -export function factoryLoader(options: T | any, factory: FACTORIES): Rule { - if (isEmpty(options.name)) { - throw new SchematicsException('Invalid options, "name" is required.'); - } - - options = transform(options); - return mergeWith(generate({ options, factory })); -} diff --git a/packages/store/schematics/utils/generate-factory.ts b/packages/store/schematics/utils/generate-factory.ts deleted file mode 100644 index 2897e42e7..000000000 --- a/packages/store/schematics/utils/generate-factory.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { apply, move, Source, template, url } from '@angular-devkit/schematics'; -import { join, Path } from '@angular-devkit/core'; -import * as strings from '@angular-devkit/core/src/utils/strings'; -import { GenerateFactoryInterface } from './interfaces/generate-factory.interface'; -import { Parser } from './parser'; - -export function generate({ options, factory }: Partial): Source { - const parser: Parser = new Parser(); - if (!factory || !options || !options.spec || !options.path) { - throw new Error('Required arguments missing'); - } - - return apply(url(join('../../templates' as Path, factory)), [ - parser.specParser(options.spec), - template({ - template: '', - ...strings, - ...options - }), - move(options.path) - ]); -} diff --git a/packages/store/schematics/utils/get-library.ts b/packages/store/schematics/utils/get-library.ts deleted file mode 100644 index c933550d3..000000000 --- a/packages/store/schematics/utils/get-library.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { NodeDependencyType, NodeDependency } from '@schematics/angular/utility/dependencies'; - -import { LIB_CONFIG } from './common/lib.config'; - -export function depsToAdd(type: NodeDependencyType): string[] { - return LIB_CONFIG.filter((pkg: NodeDependency) => pkg.type === type) - .reduce((acc, pkg) => [...acc, pkg.name], []) - .sort(); -} diff --git a/packages/store/schematics/utils/index.ts b/packages/store/schematics/utils/index.ts deleted file mode 100644 index 22ec41d40..000000000 --- a/packages/store/schematics/utils/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './parser'; -export * from './generate-factory'; -export * from './common/factories.enum'; diff --git a/packages/store/schematics/utils/interfaces/generate-factory.interface.ts b/packages/store/schematics/utils/interfaces/generate-factory.interface.ts deleted file mode 100644 index ca8e2a6e3..000000000 --- a/packages/store/schematics/utils/interfaces/generate-factory.interface.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { FACTORIES } from '../common/factories.enum'; - -export interface SchemaOptions { - path: string; - spec: boolean; -} - -export interface GenerateFactoryInterface { - options: Partial; - factory: FACTORIES; - isSpec: boolean; -} diff --git a/packages/store/schematics/utils/interfaces/parser.interface.ts b/packages/store/schematics/utils/interfaces/parser.interface.ts deleted file mode 100644 index 389236fdc..000000000 --- a/packages/store/schematics/utils/interfaces/parser.interface.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Rule } from '@angular-devkit/schematics'; -import { Path } from '@angular-devkit/core'; - -export interface ParserInterface { - nameParser(option: ParseOptions): Location; - specParser(option: boolean): Rule; -} - -export interface ParseOptions { - name: string; - path?: string; -} - -export interface Location { - name: string; - path: Path; -} diff --git a/packages/store/schematics/utils/parser.ts b/packages/store/schematics/utils/parser.ts deleted file mode 100644 index 62dbc1592..000000000 --- a/packages/store/schematics/utils/parser.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { basename, dirname, normalize, Path } from '@angular-devkit/core'; -import { filter, noop, Rule } from '@angular-devkit/schematics'; -import { ParserInterface, ParseOptions, Location } from './interfaces/parser.interface'; - -export class Parser implements ParserInterface { - public nameParser(options: ParseOptions): Location { - const nameWithoutPath: string = basename(options.name as Path); - const namePath: string = dirname( - (options.path === undefined ? '' : options.path).concat('/').concat(options.name) as Path - ); - return { - name: nameWithoutPath, - path: normalize('/'.concat(namePath)) - }; - } - - public specParser(option: boolean): Rule { - return option ? noop() : filter(path => !path.includes('spec')); - } -} diff --git a/packages/store/schematics/utils/transform-options.ts b/packages/store/schematics/utils/transform-options.ts deleted file mode 100644 index b9d84de5a..000000000 --- a/packages/store/schematics/utils/transform-options.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { join, normalize, Path } from '@angular-devkit/core'; -import { Location } from './interfaces/parser.interface'; -import { Parser } from './parser'; -import * as strings from '@angular-devkit/core/src/utils/strings'; - -export function transform(options: T | any) { - const target: T = Object.assign({}, options); - const defaultSourceRoot = options.sourceRoot !== undefined ? options.sourceRoot : 'src'; - setOptionsValue(target, defaultSourceRoot); - - return target; -} - -function setOptionsValue(target: any, defaultSourceRoot: string) { - target.path = - target.path !== undefined - ? join(normalize(defaultSourceRoot), target.path) - : normalize(defaultSourceRoot); - - if (target.name) { - const location: Location = new Parser().nameParser(target); - target.name = strings.dasherize(location.name); - target.path = join(strings.dasherize(location.path) as Path, target.name); - } - - return target; -} diff --git a/tools/build-schematics.mjs b/tools/build-schematics.mjs index d7e3503f2..bfd0ef83a 100644 --- a/tools/build-schematics.mjs +++ b/tools/build-schematics.mjs @@ -2,8 +2,6 @@ import yargs from 'yargs'; import { join } from 'path'; import { execSync } from 'child_process'; import fse from 'fs-extra'; -import fs from 'fs'; -import minimatch from 'minimatch'; const { projectRoot, distPath } = yargs(process.argv).argv; @@ -11,27 +9,37 @@ if (!distPath) { throw new Error('"distPath" is required.'); } +const schematicsSrc = join(projectRoot, 'schematics/src'); +assertSchematicsVersionIsUpToDate(schematicsSrc); + const tsConfigPath = join(projectRoot, 'tsconfig.schematics.json'); const cmd = `node_modules/.bin/tsc -p ${tsConfigPath}`; console.log(`Running "${cmd}"`); execSync(cmd, { stdio: 'inherit' }); -fse.copySync( - join(projectRoot, 'schematics/factories'), - join(distPath, 'schematics/factories'), - src => { - const willBeCopied = fs.statSync(src).isDirectory() || src.endsWith('schema.json'); - return willBeCopied; +fse.copySync(schematicsSrc, join(distPath, 'schematics/src'), src => { + // skip not compiled files + if (src.endsWith('.ts')) { + return false; } -); - -fse.copySync( - join(projectRoot, 'schematics/templates'), - join(distPath, 'schematics/templates') -); + return true; +}); fse.copySync( join(projectRoot, 'schematics/collection.json'), join(distPath, 'schematics/collection.json') ); + +function assertSchematicsVersionIsUpToDate(schematicsSrc) { + const rootPkg = JSON.parse(fse.readFileSync('package.json', { encoding: 'utf-8' })); + const schematicsVersionsFilePath = join(schematicsSrc, 'utils/versions.json'); + const schematicsVersionsFile = JSON.parse( + fse.readFileSync(schematicsVersionsFilePath, { encoding: 'utf-8' }) + ); + if (rootPkg.version !== schematicsVersionsFile['@ngxs/store']) { + throw new Error( + `Version of "@ngxs/store" in "${schematicsVersionsFilePath}" is not up to date with root package.json` + ); + } +}