Skip to content

Commit

Permalink
feat: add ng-add schematics support (#19)
Browse files Browse the repository at this point in the history
  • Loading branch information
damingerdai authored Jun 2, 2023
1 parent a8b7747 commit c9aa42a
Show file tree
Hide file tree
Showing 8 changed files with 238 additions and 5 deletions.
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@
"scripts": {
"ng": "ng",
"start": "ng serve",
"build-pkg": "ng build ngx-apexcharts",
"build-schematics": "tsc -p ./projects/ngx-apexcharts/schematics/tsconfig.json --outDir dist/ngx-apexcharts/schematics",
"build": "ng build",
"test": "ng test",
"lint": "ng lint ngx-apexcharts && ng lint ngx-apexcharts-demo",
"e2e": "ng e2e",
"package": "ng build ngx-apexcharts",
"package": "yarn build-pkg && yarn build-schematics",
"copyfile": "copyfiles ./LICENSE ./dist/ngx-apexcharts ",
"release": "cd ./projects/ngx-apexcharts && standard-version",
"release:patch": "cd ./projects/ngx-apexcharts && standard-version --release-as patch",
"release:minor": "cd ./projects/ngx-apexcharts && standard-version --release-as minor",
"release:major": "cd ./projects/ngx-apexcharts && standard-version --release-as major",
"publish": "ng build ngx-apexcharts && copyfiles ./LICENSE ./dist/ngx-apexcharts && npm publish dist/ngx-apexcharts",
"publish": "yarn package && copyfiles ./LICENSE ./dist/ngx-apexcharts && npm publish dist/ngx-apexcharts/",
"prepare": "is-ci || husky install"
},
"private": true,
Expand All @@ -27,6 +29,7 @@
"@angular/platform-browser": "^16.0.3",
"@angular/platform-browser-dynamic": "^16.0.3",
"@angular/router": "^16.0.3",
"@schematics/angular": "^16.0.4",
"apexcharts": "^3.36.3",
"rxjs": "~6.5.5",
"tslib": "^2.0.0",
Expand All @@ -53,11 +56,11 @@
"eslint": "^8.39.0",
"husky": "^7.0.0",
"is-ci": "^3.0.1",
"karma-coverage": "^2.1.0",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~5.0.0",
"karma": "~6.3.11",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "^2.1.0",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "~1.5.0",
"lint-staged": "^13.0.3",
Expand All @@ -67,4 +70,4 @@
"ts-node": "~8.10.1",
"typescript": "~5.0.4"
}
}
}
3 changes: 2 additions & 1 deletion projects/ngx-apexcharts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@
"repository": {
"type": "git",
"url": "https://github.com/damingerdai/ngx-apexcharts.git"
}
},
"schematics": "./schematics/collection.json"
}
11 changes: 11 additions & 0 deletions projects/ngx-apexcharts/schematics/collection.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "./node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
"ng-add": {
"description": "Adds ngx-apexcharts to the application",
"factory": "./ng-add/index",
"schema": "./ng-add/schema.json",
"aliases": ["ngx-apexcharts-shell", "install"]
}
}
}
128 changes: 128 additions & 0 deletions projects/ngx-apexcharts/schematics/ng-add/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
import { getAppModulePath } from '@schematics/angular/utility/ng-ast-utils';
import { ProjectDefinition, WorkspaceDefinition, getWorkspace } from '@schematics/angular/utility/workspace';
import { SchematicsException } from '@angular-devkit/schematics';
import { addSymbolToNgModuleMetadata, insertImport } from '@schematics/angular/utility/ast-utils';
import { ProjectType } from '@schematics/angular/utility/workspace-models';
import { InsertChange } from '@schematics/angular/utility/change';

import * as ts from '@schematics/angular/third_party/github.com/Microsoft/TypeScript/lib/typescript';

export default function(options: NgxApexchartNgAddSchema): Rule {
return async (_host: Tree, _context: SchematicContext) => {
const workspace = await getWorkspace(_host);
const project = getProjectFromWorkspace(workspace, options.project);

if (!project) {
throw new Error(`can not find ${options.project} angular project`);
}
if (project.extensions.projectType === ProjectType.Application) {
addNgxPendoModule(project as ProjectDefinition, _host);
}
addPackageToPackageJson(_host, 'ngx-apexcharts', '~0.2.0');
addPackageToPackageJson(_host, 'apexcharts', '~3.36.3');
_context.logger.log('info', '✅️ Added "ngx-apexcharts"');
_context.addTask(new NodePackageInstallTask());
};
}

function addNgxPendoModule(project: ProjectDefinition, _host: Tree): void {
if (!project) {
return;
}
const appModulePath = getAppModulePath(_host, getProjectMainFile(project));
const sourceFile = readIntoSourceFile(_host, appModulePath);
const importPath = 'ngx-apexcharts';
const recorder = _host.beginUpdate(appModulePath);
const moduleName = 'NgxApexchartsModule';
const importChange = insertImport(sourceFile, appModulePath, moduleName, importPath);
if (importChange instanceof InsertChange) {
recorder.insertLeft(importChange.pos, importChange.toAdd);
}
const ngModuleName = 'NgxApexchartsModule';
const ngModuleChanges = addSymbolToNgModuleMetadata(sourceFile, appModulePath, 'imports', ngModuleName, null);
for (const change of ngModuleChanges) {
if (change instanceof InsertChange) {
recorder.insertLeft(change.pos, change.toAdd);
}
}
_host.commitUpdate(recorder);
}


function readIntoSourceFile(host: Tree, modulePath: string): ts.SourceFile {
const text = host.read(modulePath);
if (text === null) {
throw new SchematicsException(`File ${modulePath} does noot exist`);
}

const sourceText = text.toString('utf-8');
return ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);
}

function addPackageToPackageJson(host: Tree, pkg: string, version: string): Tree {
if (host.exists('package.json')) {
const sourceText = host.read('package.json')!.toString('utf-8');


const json = JSON.parse(sourceText);

if (!json.dependencies) {
json.dependencies = {};
}

if (!json.dependencies[pkg]) {
json.dependencies[pkg] = version;
json.dependencies = sortObjectByKeys(json.dependencies);
}

host.overwrite('package.json', JSON.stringify(json, null, 2));
}

return host;
}

function sortObjectByKeys(obj: any): any {
return Object.keys(obj)
.sort()
.reduce((result: any, key: any) => (result[key] = obj[key]) && result, {});
}

// eslint-disable-next-line
function getProjectTargetOptions(project: ProjectDefinition, buildTarget: string) {
if (project?.targets?.get(buildTarget)?.options) {
return project!.targets!.get(buildTarget)!.options;
}

throw new Error(`Cannot determine project target configuration for: ${buildTarget}.`);
}

function getProjectMainFile(project: ProjectDefinition): string {
const buildOptions = getProjectTargetOptions(project, 'build');
if (!buildOptions || !buildOptions.main) {
throw new SchematicsException(`Could not find the project main file inside of the ` +
`workspace config (${project.sourceRoot})`);
}

return buildOptions.main.toString();
}

export function getProjectFromWorkspace(
workspace: WorkspaceDefinition,
projectName: string | undefined,
): ProjectDefinition {
if (!projectName) {
// TODO(crisbeto): some schematics APIs have the project name as optional so for now it's
// simpler to allow undefined and checking it at runtime. Eventually we should clean this up.
throw new SchematicsException('Project name is required.');
}

const project = workspace.projects.get(projectName);

if (!project) {
throw new SchematicsException(`Could not find project in workspace: ${projectName}`);
}

return project;
}
10 changes: 10 additions & 0 deletions projects/ngx-apexcharts/schematics/ng-add/schema.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Ngx apexchart ng-add schematic
* Generate a file of JavaScript
*/
declare interface NgxApexchartNgAddSchema {
/**
* Name of the project.
*/
project?: string;
}
16 changes: 16 additions & 0 deletions projects/ngx-apexcharts/schematics/ng-add/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "http://json-schema.org/schema",
"$id": "ngx-apexcharts-ng-add-schema",
"title": "Ngx Apexcharts ng-add schematic",
"description": "Generate a file of JavaScript",
"type": "object",
"properties": {
"project": {
"type": "string",
"description": "Name of the project.",
"$default": {
"$source": "projectName"
}
}
}
}
33 changes: 33 additions & 0 deletions projects/ngx-apexcharts/schematics/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"compilerOptions": {
"baseUrl": "tsconfig",
"lib": [
"es2018",
"dom"
],
"declaration": true,
"module": "commonjs",
"moduleResolution": "node",
"noEmitOnError": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitThis": true,
"noUnusedParameters": true,
"noUnusedLocals": false,
"rootDir": "./",
"outDir": "dist",
"skipDefaultLibCheck": true,
"skipLibCheck": true,
"sourceMap": false,
"strictNullChecks": true,
"target": "es6",
"types": [
"jasmine",
"node"
]
},
"include": [
"./**/*",
"**.json"
]
}
31 changes: 31 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@
rxjs "7.8.1"
source-map "0.7.4"

"@angular-devkit/core@16.0.4":
version "16.0.4"
resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-16.0.4.tgz#931be431fba9f310647e73133943218b8146fdf8"
integrity sha512-RK8+W+BVQcD2RHyQcy4iKSIFO1BexVUU2htu3+A9SY7VN/szoMgHIP/sx7Pj+LIJfDrvyve57aIOv0KPWk3WOg==
dependencies:
ajv "8.12.0"
ajv-formats "2.1.1"
jsonc-parser "3.2.0"
rxjs "7.8.1"
source-map "0.7.4"

"@angular-devkit/schematics@16.0.1":
version "16.0.1"
resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-16.0.1.tgz#d49387e9e41c9cce98b155da51b0e193333dd178"
Expand All @@ -120,6 +131,17 @@
ora "5.4.1"
rxjs "7.8.1"

"@angular-devkit/schematics@16.0.4":
version "16.0.4"
resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-16.0.4.tgz#0abe3555567baf1150f8cb182e976f251a2b6df5"
integrity sha512-ASr9bGRuTTAAgHsr/ltBBl4CTyZETmuzS/boVMNDVLvjDDFr0aY/F/FW/QRFbJsxgxM2VAJn7NpY64Rl9fQz/g==
dependencies:
"@angular-devkit/core" "16.0.4"
jsonc-parser "3.2.0"
magic-string "0.30.0"
ora "5.4.1"
rxjs "7.8.1"

"@angular-eslint/builder@16.0.2":
version "16.0.2"
resolved "https://registry.yarnpkg.com/@angular-eslint/builder/-/builder-16.0.2.tgz#013d8d8e509d071eeab7aaaf5198f27e96a3745e"
Expand Down Expand Up @@ -1995,6 +2017,15 @@
"@angular-devkit/schematics" "16.0.1"
jsonc-parser "3.2.0"

"@schematics/angular@^16.0.4":
version "16.0.4"
resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-16.0.4.tgz#3321a34dd0c51dd0f4f3178f9c0f694f68b7d7c8"
integrity sha512-3uu5xq136broqVKCGwYKENZYF8SO4EU15FHRV2EFY/PqU2sU5QBlsGG2Z1JYAVE3aevsk9ORkPb1tRh6yP28Rw==
dependencies:
"@angular-devkit/core" "16.0.4"
"@angular-devkit/schematics" "16.0.4"
jsonc-parser "3.2.0"

"@sigstore/protobuf-specs@^0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@sigstore/protobuf-specs/-/protobuf-specs-0.1.0.tgz#957cb64ea2f5ce527cc9cf02a096baeb0d2b99b4"
Expand Down

0 comments on commit c9aa42a

Please sign in to comment.