diff --git a/.eslintignore b/.eslintignore index 97b5773d7b..a54016de7e 100644 --- a/.eslintignore +++ b/.eslintignore @@ -23,3 +23,4 @@ tmp/ **/*.snap **/.nvmrc **/.browserslistrc +**/schematics/ diff --git a/.prettierignore b/.prettierignore index d112e2dce7..e9c77fe3db 100644 --- a/.prettierignore +++ b/.prettierignore @@ -24,3 +24,4 @@ tmp/ **/*.sh **/*.snap **/.nvmrc +**/schematics/ \ No newline at end of file diff --git a/libs/ng-mocks/schematics/src/.gitignore b/libs/ng-mocks/schematics/src/.gitignore new file mode 100644 index 0000000000..de70204f31 --- /dev/null +++ b/libs/ng-mocks/schematics/src/.gitignore @@ -0,0 +1,10 @@ + +# Outputs +**/*.js +**/*.js.map +**/*.d.ts +package-lock.json + +# Misc +node_modules/ + diff --git a/libs/ng-mocks/schematics/src/README.md b/libs/ng-mocks/schematics/src/README.md new file mode 100644 index 0000000000..1784a81768 --- /dev/null +++ b/libs/ng-mocks/schematics/src/README.md @@ -0,0 +1,28 @@ +# Getting Started With Schematics + +This repository is a basic Schematic implementation that serves as a starting point to create and publish Schematics to NPM. + +### Testing + +To test locally, install `@angular-devkit/schematics-cli` globally and use the `schematics` command line tool. That tool acts the same as the `generate` command of the Angular CLI, but also has a debug mode. + +Check the documentation with + +```bash +schematics --help +``` + +### Unit Testing + +`npm run test` will run the unit tests, using Jasmine as a runner and test framework. + +### Publishing + +To publish, simply do: + +```bash +npm run build +npm publish +``` + +That's it! diff --git a/libs/ng-mocks/schematics/src/collection.json b/libs/ng-mocks/schematics/src/collection.json new file mode 100644 index 0000000000..1619d5040a --- /dev/null +++ b/libs/ng-mocks/schematics/src/collection.json @@ -0,0 +1,11 @@ +{ + "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json", + "extends": ["@schematics/angular"], + "schematics": { + "ng-mocks-service": { + "description": "ngMocks service schematic", + "factory": "./ng-mocks/index#ngMocksServiceSchematic", + "schema": "./ng-mocks/service-schema.json" + } + } +} \ No newline at end of file diff --git a/libs/ng-mocks/schematics/src/ng-mocks/files/service/__name@dasherize__.service.spec.ts b/libs/ng-mocks/schematics/src/ng-mocks/files/service/__name@dasherize__.service.spec.ts new file mode 100644 index 0000000000..7ba39fa835 --- /dev/null +++ b/libs/ng-mocks/schematics/src/ng-mocks/files/service/__name@dasherize__.service.spec.ts @@ -0,0 +1,21 @@ +import { MockBuilder,MockedComponentFixture, MockInstance, MockRender, } from 'ng-mocks'; + +import { <%= classify(name)%>Service } from './<%= dasherize(name)%>.service'; + +describe('<%= classify(name)%>Service', () => { + let service: <%= classify(name)%>Service; + let fixture: MockedComponentFixture<<%= classify(name)%>Service>; + + MockInstance.scope(); + + beforeEach(() => MockBuilder(<%= classify(name)%>Service)); + + beforeEach(() => { + fixture = MockRender(<%= classify(name)%>Service); + service = fixture.point.componentInstance; + }) + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); \ No newline at end of file diff --git a/libs/ng-mocks/schematics/src/ng-mocks/index.ts b/libs/ng-mocks/schematics/src/ng-mocks/index.ts new file mode 100644 index 0000000000..47bcb04ed7 --- /dev/null +++ b/libs/ng-mocks/schematics/src/ng-mocks/index.ts @@ -0,0 +1,45 @@ +import { + apply, + chain, + externalSchematic, + mergeWith, + move, + template, + url, + MergeStrategy, + Rule, + SchematicContext, + Tree, + noop, +} from '@angular-devkit/schematics'; +import {strings, normalize } from '@angular-devkit/core'; + +import { ServiceOptions } from './schema'; +import { ensurePath } from './utils/ensure-path.helper'; + +export function ngMocksServiceSchematic(options: ServiceOptions): Rule { + return chain([ + externalSchematic( + '@schematics/angular', + 'service', + { ...options, skipTests: true } + ), + async(tree: Tree, _context: SchematicContext): Promise => { + if (options.skipTests) { + return noop; + } + + await ensurePath(tree, options); + const movePath = normalize(options.path || ''); + const specTemplateRule = apply(url('./files/service'), [ + template({ + ...strings, + ...options, + }), + move(movePath), + ]); + + return mergeWith(specTemplateRule, MergeStrategy.Default); + } + ]); +} \ No newline at end of file diff --git a/libs/ng-mocks/schematics/src/ng-mocks/index_spec.ts b/libs/ng-mocks/schematics/src/ng-mocks/index_spec.ts new file mode 100644 index 0000000000..1b7bd91f3a --- /dev/null +++ b/libs/ng-mocks/schematics/src/ng-mocks/index_spec.ts @@ -0,0 +1,14 @@ +import { Tree } from '@angular-devkit/schematics'; +import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; +import * as path from 'path'; + +const collectionPath = path.join(__dirname, '../collection.json'); + +describe('ng-mocks-service', () => { + it('works', async () => { + const runner = new SchematicTestRunner('schematics', collectionPath); + const tree = await runner.runSchematic('ng-mocks-service', {}, Tree.empty()); + + expect(tree.files).toEqual([]); + }); +}); diff --git a/libs/ng-mocks/schematics/src/ng-mocks/schema.ts b/libs/ng-mocks/schematics/src/ng-mocks/schema.ts new file mode 100644 index 0000000000..d6705d626b --- /dev/null +++ b/libs/ng-mocks/schematics/src/ng-mocks/schema.ts @@ -0,0 +1,9 @@ +export interface ServiceOptions { + // -------------------- START of Angular schematics default options -------------------- + name: string; + path?: string; + project?: string; + skipTests?: boolean; + flat?: boolean; + // -------------------- END of Angular schematics default options -------------------- +} \ No newline at end of file diff --git a/libs/ng-mocks/schematics/src/ng-mocks/service-schema.json b/libs/ng-mocks/schematics/src/ng-mocks/service-schema.json new file mode 100644 index 0000000000..5811fdc773 --- /dev/null +++ b/libs/ng-mocks/schematics/src/ng-mocks/service-schema.json @@ -0,0 +1,39 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ngMocksSchematicsAngularService", + "title": "Angular Service with ngMocks schema", + "type": "object", + "description": "Creates a new generic service in the given or default project", + "properties": { + "name": { + "description": "The name of the service.", + "type": "string" + }, + "path": { + "type": "string", + "format": "path", + "description": "The path to create the service.", + "visible": false + }, + "project": { + "type": "string", + "description": "The name of the project.", + "$default": { + "$source": "projectName" + } + }, + "skipTests": { + "type": "boolean", + "description": "When true, does not create \"spec.ts\" test files for the new service.", + "default": false + }, + "flat": { + "type": "boolean", + "default": true, + "description": "When true (the default), creates files at the top level of the project." + } + }, + "required": [ + "name" + ] +} \ No newline at end of file diff --git a/libs/ng-mocks/schematics/src/ng-mocks/utils/ensure-path.helper.ts b/libs/ng-mocks/schematics/src/ng-mocks/utils/ensure-path.helper.ts new file mode 100644 index 0000000000..82ab7ff3a3 --- /dev/null +++ b/libs/ng-mocks/schematics/src/ng-mocks/utils/ensure-path.helper.ts @@ -0,0 +1,21 @@ +import { Tree } from '@angular-devkit/schematics'; +import { buildDefaultPath, getWorkspace } from '@schematics/angular/utility/workspace'; +import { parseName } from '@schematics/angular/utility/parse-name'; + +export async function ensurePath(tree: Tree, options: any): Promise { + const workspace = await getWorkspace(tree); + + if (!options.project) { + options.project = workspace.projects.keys().next().value; + } + + const project = workspace.projects.get(options.project as string); + + if (options.path === undefined && project) { + options.path = buildDefaultPath(project); + } + + const parsedPath = parseName(options.path as string, options.name); + options.name = parsedPath.name; + options.path = parsedPath.path; +} \ No newline at end of file diff --git a/libs/ng-mocks/schematics/src/package.json b/libs/ng-mocks/schematics/src/package.json new file mode 100644 index 0000000000..8ab4f1d270 --- /dev/null +++ b/libs/ng-mocks/schematics/src/package.json @@ -0,0 +1,27 @@ +{ + "name": "ng-mocks-schematics", + "version": "0.0.0", + "description": "A blank schematics", + "scripts": { + "build": "tsc -p tsconfig.json", + "build:watch": "tsc -p tsconfig.json --watch", + "test": "npm run build && jasmine src/**/*_spec.js" + }, + "keywords": [ + "schematics" + ], + "author": "", + "license": "MIT", + "schematics": "./src/collection.json", + "dependencies": { + "@angular-devkit/core": "^18.2.3", + "@angular-devkit/schematics": "^18.2.3", + "@schematics/angular": "^18.2.3", + "typescript": "~5.5.2" + }, + "devDependencies": { + "@types/jasmine": "~5.1.0", + "@types/node": "^18.18.0", + "jasmine": "^5.0.0" + } +} diff --git a/libs/ng-mocks/schematics/src/tsconfig.json b/libs/ng-mocks/schematics/src/tsconfig.json new file mode 100644 index 0000000000..75cf15fa8e --- /dev/null +++ b/libs/ng-mocks/schematics/src/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "baseUrl": "tsconfig", + "lib": ["es2018", "dom"], + "declaration": true, + "module": "commonjs", + "moduleResolution": "node", + "noEmitOnError": true, + "noFallthroughCasesInSwitch": true, + "noImplicitAny": true, + "noImplicitThis": true, + "noUnusedParameters": true, + "noUnusedLocals": true, + "rootDir": "src/", + "skipDefaultLibCheck": true, + "skipLibCheck": true, + "sourceMap": true, + "strictNullChecks": true, + "target": "es6", + "types": ["jasmine", "node"] + }, + "include": ["src/**/*"], + "exclude": ["src/*/files/**/*"] +}