@simitgroup/simpleapp-generator 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc +6 -0
- package/LICENSE +201 -0
- package/README.md +668 -0
- package/definations/person.pes.jsonschema.json +84 -0
- package/definations/salesinvoice.si.jsonschema.json +84 -0
- package/dist/app.module.ts +14 -0
- package/dist/constant.js +6 -0
- package/dist/constant.js.map +1 -0
- package/dist/createproject.js +123 -0
- package/dist/createproject.js.map +1 -0
- package/dist/generate.js +225 -0
- package/dist/generate.js.map +1 -0
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -0
- package/dist/libs.js +15 -0
- package/dist/libs.js.map +1 -0
- package/dist/processors/jsonschemabuilder.js +116 -0
- package/dist/processors/jsonschemabuilder.js.map +1 -0
- package/dist/type.js +13 -0
- package/dist/type.js.map +1 -0
- package/package.json +44 -0
- package/sampleconfig.json +6 -0
- package/src/constant.ts +2 -0
- package/src/createproject.ts +96 -0
- package/src/generate.ts +254 -0
- package/src/index.ts +73 -0
- package/src/libs.ts +14 -0
- package/src/processors/jsonschemabuilder.ts +137 -0
- package/src/type.ts +42 -0
- package/templates/SimpleAppClient.eta +111 -0
- package/templates/SimpleAppController.eta +66 -0
- package/templates/SimpleAppService.eta +134 -0
- package/templates/app.module.eta +15 -0
- package/templates/app.vue.eta +21 -0
- package/templates/basic/apiclient.eta +56 -0
- package/templates/basic/apischema.eta +29 -0
- package/templates/basic/backend.config.eta +1 -0
- package/templates/basic/beforesave.eta +7 -0
- package/templates/basic/controller.eta +103 -0
- package/templates/basic/controller2.eta +86 -0
- package/templates/basic/frontend.config.eta +1 -0
- package/templates/basic/jsonschema.eta +6 -0
- package/templates/basic/model-converter.etabackup +21 -0
- package/templates/basic/model.eta +35 -0
- package/templates/basic/module.eta +20 -0
- package/templates/basic/readme.eta +3 -0
- package/templates/basic/service.eta +32 -0
- package/templates/basic/service.etabackupe +106 -0
- package/templates/basic/type.eta +27 -0
- package/templates/basic/type.etabackup +23 -0
- package/templates/basic/uischema.eta +13 -0
- package/templates/nest.env.eta +5 -0
- package/templates/nest.main.eta +20 -0
- package/templates/nuxt.env.eta +2 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readJsonSchemaBuilder = void 0;
|
|
4
|
+
const libs_1 = require("../libs");
|
|
5
|
+
// import { ConflictException } from '@nestjs/common';
|
|
6
|
+
const type_1 = require("../type");
|
|
7
|
+
let allmodels = {};
|
|
8
|
+
const readJsonSchemaBuilder = (doctype, docname, jsondata) => {
|
|
9
|
+
allmodels = {};
|
|
10
|
+
const validateddata = Object.assign({}, jsondata);
|
|
11
|
+
let schema;
|
|
12
|
+
if (jsondata && jsondata.type == 'object') {
|
|
13
|
+
//no _id then need add
|
|
14
|
+
// console.log(jsondata)
|
|
15
|
+
schema = processObject(doctype, docname, jsondata);
|
|
16
|
+
// console.log("schema",schema)
|
|
17
|
+
}
|
|
18
|
+
else if (jsondata.type == 'array') {
|
|
19
|
+
throw (`unsupport array type for ${docname}.${doctype}`);
|
|
20
|
+
}
|
|
21
|
+
return allmodels;
|
|
22
|
+
};
|
|
23
|
+
exports.readJsonSchemaBuilder = readJsonSchemaBuilder;
|
|
24
|
+
const processObject = (doctype, docname, jsondata) => {
|
|
25
|
+
if (!jsondata['properties']) {
|
|
26
|
+
throw ("Invalid json schema {doctype}.{docname}, no 'properties' defined");
|
|
27
|
+
}
|
|
28
|
+
//ensure some field exists, also override it
|
|
29
|
+
jsondata.properties['_id'] = { type: 'string', description: 'Control value, dont edit it', };
|
|
30
|
+
jsondata.properties['doctype'] = { type: 'string', default: doctype, examples: [doctype], description: 'Control value, dont edit it', };
|
|
31
|
+
return genSchema((0, libs_1.capitalizeFirstLetter)(docname), 'object', jsondata.properties, jsondata['required'] ? jsondata['required'] : []);
|
|
32
|
+
};
|
|
33
|
+
const genSchema = (docname, schematype, jsondata, //JSONSchema7,//|JsonSchemaProperties|JSONSchema7Definition,
|
|
34
|
+
requiredlist) => {
|
|
35
|
+
var _a, _b;
|
|
36
|
+
const newmodel = {};
|
|
37
|
+
const props = Object.getOwnPropertyNames(jsondata);
|
|
38
|
+
// console.log('==== requirelist', requiredlist);
|
|
39
|
+
for (let i = 0; i < props.length; i++) {
|
|
40
|
+
const key = props[i];
|
|
41
|
+
//below is Object.assign use for force datatype compatibility
|
|
42
|
+
const obj = {};
|
|
43
|
+
Object.assign(obj, jsondata[key]);
|
|
44
|
+
const objectitem = {};
|
|
45
|
+
Object.assign(objectitem, obj.items);
|
|
46
|
+
// Object.assign(objtmp,jsondata?[key]:{});
|
|
47
|
+
const isrequired = requiredlist && requiredlist.includes(key);
|
|
48
|
+
// console.log('----', key, isrequired, obj);
|
|
49
|
+
const newName = docname + (0, libs_1.capitalizeFirstLetter)(key);
|
|
50
|
+
// console.log(key);
|
|
51
|
+
//need create sub model
|
|
52
|
+
// console.log("----",key,obj.type,objectitem.type)
|
|
53
|
+
if (obj.type == 'object') {
|
|
54
|
+
genSchema(newName, obj.type, obj.properties, obj.required);
|
|
55
|
+
newmodel[key] = newName;
|
|
56
|
+
}
|
|
57
|
+
else if (obj.type == 'array' && obj.items && (objectitem === null || objectitem === void 0 ? void 0 : objectitem.type) == 'object') {
|
|
58
|
+
//array need submodel
|
|
59
|
+
// console.log("======",newName,key)
|
|
60
|
+
genSchema(newName, obj.type, objectitem === null || objectitem === void 0 ? void 0 : objectitem.properties, obj.required);
|
|
61
|
+
newmodel[key] = [newName];
|
|
62
|
+
}
|
|
63
|
+
else if (obj.type == 'array' && (objectitem === null || objectitem === void 0 ? void 0 : objectitem.type) != 'object') {
|
|
64
|
+
//array need submodel
|
|
65
|
+
// genSchema(newName, obj.type, obj.items.properties);
|
|
66
|
+
const objecttype = (_b = (_a = objectitem.type) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : 'string';
|
|
67
|
+
newmodel[key] = [objecttype];
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
newmodel[key] = getField(key, obj, isrequired);
|
|
71
|
+
// console.log('--------newmodel', newmodel[key]);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
allmodels[docname] = { type: schematype, model: newmodel };
|
|
75
|
+
return newmodel;
|
|
76
|
+
};
|
|
77
|
+
const getField = (fieldname, obj, isrequired) => {
|
|
78
|
+
let datatype = type_1.Fieldtypes.string;
|
|
79
|
+
let format = obj.format;
|
|
80
|
+
if (obj.type == 'integer') {
|
|
81
|
+
datatype = type_1.Fieldtypes.number;
|
|
82
|
+
format = 'integer';
|
|
83
|
+
}
|
|
84
|
+
const f = {
|
|
85
|
+
type: datatype,
|
|
86
|
+
// oritype: obj.type,
|
|
87
|
+
required: isrequired,
|
|
88
|
+
};
|
|
89
|
+
if (obj.title)
|
|
90
|
+
f.title = obj.title;
|
|
91
|
+
if (obj.description)
|
|
92
|
+
f.description = obj.description;
|
|
93
|
+
if (obj.format)
|
|
94
|
+
f.format = obj.format;
|
|
95
|
+
if (obj.example)
|
|
96
|
+
f.example = obj.example;
|
|
97
|
+
if (obj.examples)
|
|
98
|
+
f.examples = obj.examples;
|
|
99
|
+
if (obj.default) {
|
|
100
|
+
f.default = obj.default;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
if (f.type == 'string')
|
|
104
|
+
f.default = '';
|
|
105
|
+
else if (f.type == 'number' || f.type == 'integer')
|
|
106
|
+
f.default = 0;
|
|
107
|
+
else if (f.type == 'boolean')
|
|
108
|
+
f.default = false;
|
|
109
|
+
else if (f.type == 'array')
|
|
110
|
+
f.default = [];
|
|
111
|
+
else
|
|
112
|
+
f.default = {};
|
|
113
|
+
}
|
|
114
|
+
return f;
|
|
115
|
+
};
|
|
116
|
+
//# sourceMappingURL=jsonschemabuilder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonschemabuilder.js","sourceRoot":"","sources":["../../src/processors/jsonschemabuilder.ts"],"names":[],"mappings":"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"}
|
package/dist/type.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Fieldtypes = void 0;
|
|
4
|
+
var Fieldtypes;
|
|
5
|
+
(function (Fieldtypes) {
|
|
6
|
+
Fieldtypes["string"] = "string";
|
|
7
|
+
Fieldtypes["object"] = "object";
|
|
8
|
+
Fieldtypes["array"] = "array";
|
|
9
|
+
Fieldtypes["boolean"] = "boolean";
|
|
10
|
+
Fieldtypes["integer"] = "integer";
|
|
11
|
+
Fieldtypes["number"] = "number";
|
|
12
|
+
})(Fieldtypes || (exports.Fieldtypes = Fieldtypes = {}));
|
|
13
|
+
//# sourceMappingURL=type.js.map
|
package/dist/type.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type.js","sourceRoot":"","sources":["../src/type.ts"],"names":[],"mappings":";;;AAIA,IAAY,UAOX;AAPD,WAAY,UAAU;IACpB,+BAAmB,CAAA;IACnB,+BAAmB,CAAA;IACnB,6BAAiB,CAAA;IACjB,iCAAqB,CAAA;IACrB,iCAAqB,CAAA;IACrB,+BAAmB,CAAA;AACrB,CAAC,EAPW,UAAU,0BAAV,UAAU,QAOrB"}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@simitgroup/simpleapp-generator",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "frontend nuxtjs and backend nests code generator using jsonschema",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"generate": "ts-node src/index.ts -c ../sampleconfig.json; pnpm exec prettier ./backend --write;pnpm exec prettier ./frontend --write",
|
|
8
|
+
"build": "npx tsc",
|
|
9
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [],
|
|
12
|
+
"author": "Ks Tan",
|
|
13
|
+
"license": "ISC",
|
|
14
|
+
"repository": {"type": "git", "url": "git://github.com/SIMITGROUP/simpleapp-generator.git"},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@nestjs/config": "^3.0.0",
|
|
20
|
+
"@nestjs/mongoose": "^10.0.1",
|
|
21
|
+
"@nestjs/swagger": "^7.1.8",
|
|
22
|
+
"ajv": "^8.12.0",
|
|
23
|
+
"ajv-formats": "^2.1.1",
|
|
24
|
+
"axios": "^1.4.0",
|
|
25
|
+
"child_process": "^1.0.2",
|
|
26
|
+
"cli-color": "^2.0.3",
|
|
27
|
+
"commander": "^11.0.0",
|
|
28
|
+
"eta": "^3.1.0",
|
|
29
|
+
"figlet": "^1.6.0",
|
|
30
|
+
"fs": "0.0.1-security",
|
|
31
|
+
"json-schema": "^0.4.0",
|
|
32
|
+
"mongoose": "^7.4.4",
|
|
33
|
+
"path": "^0.12.7",
|
|
34
|
+
"tslog": "^4.9.1"
|
|
35
|
+
},
|
|
36
|
+
"bin": {
|
|
37
|
+
"simpleapp-generator": "./dist/index.js"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^20.5.2",
|
|
41
|
+
"prettier": "^3.0.2",
|
|
42
|
+
"typescript": "^5.1.6"
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/constant.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { exec } from "child_process";
|
|
2
|
+
import {writeFileSync} from 'fs'
|
|
3
|
+
import * as constants from './constant'
|
|
4
|
+
import { Logger, ILogObj } from "tslog";
|
|
5
|
+
const log: Logger<ILogObj> = new Logger();
|
|
6
|
+
|
|
7
|
+
const { Eta } = require('eta');
|
|
8
|
+
|
|
9
|
+
const checkNodeJS= (callback)=>{
|
|
10
|
+
return exec(`npx -v`,(error, stdout, stderr)=>{
|
|
11
|
+
if(error){
|
|
12
|
+
throw ("Nodejs not exists")
|
|
13
|
+
}else{
|
|
14
|
+
callback()
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const checkNestCli = (callback)=>{
|
|
20
|
+
log.info("setting up nest backend")
|
|
21
|
+
return exec(`npx -v`, (error, stdout, stderr)=>{
|
|
22
|
+
if(error){
|
|
23
|
+
return exec(`npm i -g @nestjs/cli`, (error, stdout, stderr)=>{
|
|
24
|
+
callback()
|
|
25
|
+
})
|
|
26
|
+
}else{
|
|
27
|
+
callback()
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
export const createNuxt= (targetfolder:string,callback)=>{
|
|
32
|
+
log.info("setting up nuxt frontend")
|
|
33
|
+
checkNodeJS( ()=>{
|
|
34
|
+
log.info("Nodejs ok")
|
|
35
|
+
exec(`npx nuxi@latest init ${targetfolder}`, (error, stdout, stderr)=>{
|
|
36
|
+
log.info(`frontend nuxt project "${targetfolder}" created, installing module`)
|
|
37
|
+
exec(`cd ${targetfolder};pnpm install`, (error, stdout, stderr)=>{
|
|
38
|
+
//;pnpm install
|
|
39
|
+
if(!error){
|
|
40
|
+
exec(`pnpm install ajv ajv-formats axios json-schema`, (error, stdout, stderr)=>{
|
|
41
|
+
const eta = new Eta({views: constants.templatedir});
|
|
42
|
+
const variables=[]
|
|
43
|
+
const txtEnv = eta.render('./nuxt.env.eta', variables);
|
|
44
|
+
writeFileSync(`${targetfolder}/.env`, txtEnv);
|
|
45
|
+
log.info("nuxt project completed")
|
|
46
|
+
callback()
|
|
47
|
+
})
|
|
48
|
+
}else{
|
|
49
|
+
throw error
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
})
|
|
53
|
+
if(error){
|
|
54
|
+
log.error(stderr)
|
|
55
|
+
throw error
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export const createNest= (targetfolder:string,callback)=>{
|
|
63
|
+
checkNestCli(()=>{
|
|
64
|
+
exec(`nest new -p pnpm ${targetfolder}`,(error, stdout, stderr)=>{
|
|
65
|
+
if(error)throw stderr
|
|
66
|
+
|
|
67
|
+
log.info(`creating backend project ${targetfolder}`)
|
|
68
|
+
exec(`cd ${targetfolder};pnpm install --save @nestjs/swagger @nestjs/mongoose mongoose ajv ajv-formats @nestjs/config`,async (error, stdout, stderr)=>{
|
|
69
|
+
// log.info(`dependency installed`)
|
|
70
|
+
if(!error){
|
|
71
|
+
exec(`pnpm install ajv ajv-formats axios json-schema`, (error, stdout, stderr)=>{
|
|
72
|
+
const eta = new Eta({views: constants.templatedir});
|
|
73
|
+
const variables=[]
|
|
74
|
+
const txtEnv = eta.render('./nest.env.eta', variables);
|
|
75
|
+
const txtMain = eta.render('./nest.main.eta', variables);
|
|
76
|
+
writeFileSync(`${targetfolder}/.env`, txtEnv);
|
|
77
|
+
writeFileSync(`${targetfolder}/src/main.ts`, txtMain);
|
|
78
|
+
log.info("nest project completed")
|
|
79
|
+
callback()
|
|
80
|
+
})
|
|
81
|
+
} else{
|
|
82
|
+
log.error(stderr)
|
|
83
|
+
throw error
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
//
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
//install nestjs cli
|
|
90
|
+
//create nest project
|
|
91
|
+
//install dependency
|
|
92
|
+
//create empty .env
|
|
93
|
+
//swap nestjs src/main.ts file
|
|
94
|
+
//try edit the configuration files
|
|
95
|
+
//console log http server how to start
|
|
96
|
+
}
|
package/src/generate.ts
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// import { readFormBuilder } from './processors/formbuilder.tsa';
|
|
2
|
+
// import { readJsonSchemaBuilder } from './processors/jsonschemabuilder';
|
|
3
|
+
import * as constants from './constant'
|
|
4
|
+
import {readJsonSchemaBuilder} from './processors/jsonschemabuilder'
|
|
5
|
+
// import { compile } from 'json-schema-to-typescript';
|
|
6
|
+
// import { Fieldtypes, SchemaModel, ChildModels } from './type';
|
|
7
|
+
import { Fieldtypes, SchemaModel, ChildModels,ModuleObject } from './type'
|
|
8
|
+
import { Logger, ILogObj } from "tslog";
|
|
9
|
+
const log: Logger<ILogObj> = new Logger();
|
|
10
|
+
const clc = require("cli-color");
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const path = require('path');
|
|
14
|
+
import {mkdirSync,readdir,readFileSync,writeFileSync,existsSync,copyFileSync, readdirSync} from 'fs'
|
|
15
|
+
const { Eta } = require('eta');
|
|
16
|
+
const { capitalizeFirstLetter }= require('./libs');
|
|
17
|
+
const extFb = '.xfb.json';
|
|
18
|
+
const extHfb = '.xhfb.json';
|
|
19
|
+
const extjsonschema = '.jsonschema.json';
|
|
20
|
+
let jsonschemas = {};
|
|
21
|
+
const docs = [];
|
|
22
|
+
|
|
23
|
+
export const initialize = (defFolder:string,backendfolder:string,frontendfolder:string) => {
|
|
24
|
+
prepareEnvironments(backendfolder,frontendfolder)
|
|
25
|
+
let activatemodules:ModuleObject[]=[]
|
|
26
|
+
const files = readdirSync(defFolder)
|
|
27
|
+
// readdir(defFolder, (err, files) => {
|
|
28
|
+
// files.forEach((file) => {
|
|
29
|
+
for(let j = 0; j< files.length;j++){
|
|
30
|
+
const file = files[j]
|
|
31
|
+
const filearr = file.split('.');
|
|
32
|
+
let rendertype = 'basic';
|
|
33
|
+
const docname = filearr[0].toLowerCase();
|
|
34
|
+
const doctype = filearr[1].toLowerCase();
|
|
35
|
+
const jsonstring = readFileSync(defFolder +path.sep+ file, 'utf-8');
|
|
36
|
+
const jsondata = JSON.parse(jsonstring);
|
|
37
|
+
let allmodels: ChildModels = {} as ChildModels;
|
|
38
|
+
|
|
39
|
+
if (file.endsWith(extjsonschema)) {
|
|
40
|
+
log.info(`Load `+clc.green(file))
|
|
41
|
+
rendertype = 'basic';
|
|
42
|
+
jsonschemas[docname] = jsondata;
|
|
43
|
+
allmodels = readJsonSchemaBuilder(doctype, docname, jsondata);
|
|
44
|
+
generate(docname, doctype, rendertype, allmodels,backendfolder,frontendfolder);
|
|
45
|
+
activatemodules.push({doctype:doctype,docname:capitalizeFirstLetter(docname)})
|
|
46
|
+
} else {
|
|
47
|
+
log.warn(`Load `+clc.yellow(file) + ` but it is not supported`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
}
|
|
51
|
+
log.info("Activated backend modules: ")
|
|
52
|
+
log.info(activatemodules)
|
|
53
|
+
loadSimpleAppModules(activatemodules,backendfolder)
|
|
54
|
+
return Promise.resolve(true)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
const generate = (
|
|
60
|
+
docname: string,
|
|
61
|
+
doctype: string,
|
|
62
|
+
rendertype: string,
|
|
63
|
+
allmodels: ChildModels,
|
|
64
|
+
backendfolder:string,
|
|
65
|
+
frontendfolder:string
|
|
66
|
+
) => {
|
|
67
|
+
const targetfolder = `${backendfolder}/src/docs/${doctype}`;
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
|
|
71
|
+
mkdirSync(targetfolder,{ recursive: true });
|
|
72
|
+
mkdirSync(`${frontendfolder}/server/docs/`,{ recursive: true });
|
|
73
|
+
|
|
74
|
+
} catch (err) {
|
|
75
|
+
//do nothing if folder exists
|
|
76
|
+
} finally {
|
|
77
|
+
const templatefolder = `${constants.templatedir}/${rendertype}`
|
|
78
|
+
log.info(`- Generate ${docname}, ${doctype}, ${templatefolder}`)
|
|
79
|
+
const eta = new Eta({
|
|
80
|
+
views: templatefolder,
|
|
81
|
+
functionHeader:
|
|
82
|
+
'const capitalizeFirstLetter = (str) => str.slice(0, 1).toUpperCase() + str.slice(1);' +
|
|
83
|
+
'const initType=(str)=>{return ["string","number","boolean","array","object"].includes(str) ? capitalizeFirstLetter(str) : str;}',
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const variables = {
|
|
87
|
+
name: docname,
|
|
88
|
+
doctype: doctype,
|
|
89
|
+
models: allmodels,
|
|
90
|
+
schema: allmodels[capitalizeFirstLetter(docname)].model,
|
|
91
|
+
apiSchemaName: capitalizeFirstLetter(docname), //capitalizeFirstLetter(doctype) + 'ApiSchema',
|
|
92
|
+
typename: capitalizeFirstLetter(docname),
|
|
93
|
+
fullApiSchemaName:
|
|
94
|
+
doctype + 'apischema.' + capitalizeFirstLetter(docname),
|
|
95
|
+
fullTypeName: doctype + 'type.' + capitalizeFirstLetter(docname),
|
|
96
|
+
jsonschema: jsonschemas[docname],
|
|
97
|
+
bothEndCode: '',
|
|
98
|
+
frontEndCode: '',
|
|
99
|
+
backEndCode: '',
|
|
100
|
+
controllerCode:''
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// console.log('generate 2', JSON.stringify(variables));
|
|
104
|
+
|
|
105
|
+
// // const txtUISchema = eta.render('./uischema', variables);
|
|
106
|
+
|
|
107
|
+
// console.log('generate 4');
|
|
108
|
+
// console.log('generate 2', variables);
|
|
109
|
+
const txtType = eta.render('./type', variables);
|
|
110
|
+
writeFileSync(`${targetfolder}/${doctype}.type.ts`, txtType);
|
|
111
|
+
// compile(jsonschemas[docname], docname).then((txtType: string) => {
|
|
112
|
+
// writeFileSync(`${targetfolder}/${doctype}.type.ts`, txtType);
|
|
113
|
+
// });
|
|
114
|
+
|
|
115
|
+
// generate jsonschema object, use for data validation
|
|
116
|
+
const txtJsonSchema = eta.render('./jsonschema', variables);
|
|
117
|
+
writeFileSync(`${targetfolder}/${doctype}.jsonschema.ts`, txtJsonSchema);
|
|
118
|
+
|
|
119
|
+
// generate before save source code, wont override after regenerate
|
|
120
|
+
const customizefilename = `${targetfolder}/${doctype}.beforesave.ts`;
|
|
121
|
+
if (!existsSync(customizefilename)) {
|
|
122
|
+
const txtBeforeSave = eta.render('./beforesave', variables);
|
|
123
|
+
writeFileSync(
|
|
124
|
+
`${targetfolder}/${doctype}.beforesave.ts`,
|
|
125
|
+
txtBeforeSave,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
// write mongoose model file
|
|
129
|
+
const txtModel = eta.render('./model', variables);
|
|
130
|
+
writeFileSync(`${targetfolder}/${doctype}.model.ts`, txtModel);
|
|
131
|
+
|
|
132
|
+
// prepare openapi schema
|
|
133
|
+
const txtApiSchema = eta.render('./apischema', variables);
|
|
134
|
+
writeFileSync(`${targetfolder}/${doctype}.apischema.ts`, txtApiSchema);
|
|
135
|
+
|
|
136
|
+
// prepare backend classes
|
|
137
|
+
// prepare frontend api client
|
|
138
|
+
|
|
139
|
+
const servicefile = `${targetfolder}/${doctype}.service.ts`;
|
|
140
|
+
let bothEndCode = '';
|
|
141
|
+
let backEndCode = '';
|
|
142
|
+
if (existsSync(servicefile)) {
|
|
143
|
+
const servicecodes = readFileSync(servicefile).toString();
|
|
144
|
+
|
|
145
|
+
/* extract string bothend and backend, put in back */
|
|
146
|
+
const regex1 =
|
|
147
|
+
/\/\/<begin-bothend-code>([\s\S]*?)\/\/<end-bothend-code>/g;
|
|
148
|
+
const regex2 =
|
|
149
|
+
/\/\/<begin-backend-code>([\s\S]*?)\/\/<end-backend-code>/g;
|
|
150
|
+
const bothendresult = servicecodes.match(regex1);
|
|
151
|
+
const backendresult = servicecodes.match(regex2);
|
|
152
|
+
if (bothendresult) {
|
|
153
|
+
bothEndCode = bothendresult[0];
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (backendresult) {
|
|
157
|
+
backEndCode = backendresult[0];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
variables.bothEndCode = bothEndCode ?? "//<begin-bothend-code>\n//<end-bothend-code>";
|
|
162
|
+
variables.backEndCode = backEndCode ?? "//<begin-backend-code>\n//<end-backend-code>";
|
|
163
|
+
const txtService = eta.render('./service', variables);
|
|
164
|
+
writeFileSync(`${targetfolder}/${doctype}.service.ts`, txtService);
|
|
165
|
+
|
|
166
|
+
// prepare api router, allow add more api and wont override after regenerate
|
|
167
|
+
const controllerfile = `${targetfolder}/${doctype}.controller.ts`;
|
|
168
|
+
let controllerCode = ''
|
|
169
|
+
if (existsSync(controllerfile)) {
|
|
170
|
+
/* extract customized controller, put in back */
|
|
171
|
+
const controllersourcecodes = readFileSync(controllerfile).toString();
|
|
172
|
+
const controllerregex = /\/\/<begin-controller-code>([\s\S]*?)\/\/<end-controller-code>/g;
|
|
173
|
+
const controllerresult = controllersourcecodes.match(controllerregex);
|
|
174
|
+
if (controllerresult) {
|
|
175
|
+
controllerCode = controllerresult[0];
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
variables.controllerCode = controllerCode!='' ? controllerCode : "\n//<begin-controller-code>\n//<end-controller-code>";
|
|
179
|
+
const txtController = eta.render('./controller', variables);
|
|
180
|
+
writeFileSync(controllerfile, txtController);
|
|
181
|
+
|
|
182
|
+
// prepare module
|
|
183
|
+
const txtModule = eta.render('./module', variables);
|
|
184
|
+
writeFileSync(`${targetfolder}/${doctype}.module.ts`, txtModule);
|
|
185
|
+
|
|
186
|
+
// prepare readme
|
|
187
|
+
const txtReadme = eta.render('./readme', variables);
|
|
188
|
+
writeFileSync(`${targetfolder}/README.md`, txtReadme);
|
|
189
|
+
|
|
190
|
+
const frontendfile = `${frontendfolder}/server/docs/${variables.typename}Doc.ts`;
|
|
191
|
+
let frontEndCode = '';
|
|
192
|
+
if (existsSync(frontendfile)) {
|
|
193
|
+
const clientcodes = readFileSync(frontendfile).toString();
|
|
194
|
+
|
|
195
|
+
/* extract string frontend code, put in back */
|
|
196
|
+
const regex3 =
|
|
197
|
+
/\/\/<begin-frontend-code>([\s\S]*?)\/\/<end-frontend-code>/g;
|
|
198
|
+
|
|
199
|
+
const frontendresult = clientcodes.match(regex3);
|
|
200
|
+
|
|
201
|
+
if (frontendresult) {
|
|
202
|
+
frontEndCode = frontendresult[0];
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
variables.frontEndCode = frontEndCode ?? '';
|
|
206
|
+
const txtDocClient = eta.render('./apiclient', variables);
|
|
207
|
+
writeFileSync(frontendfile, txtDocClient);
|
|
208
|
+
|
|
209
|
+
// // fs.writeFileSync(`${targetfolder}/${doctype}.uischema.ts`, txtUISchema);
|
|
210
|
+
log.info(`- write completed: `+clc.green(doctype))
|
|
211
|
+
|
|
212
|
+
//create type
|
|
213
|
+
//create service
|
|
214
|
+
//create controller
|
|
215
|
+
//create module
|
|
216
|
+
//create apischema
|
|
217
|
+
//create beforesave if not exists
|
|
218
|
+
// console.log(schema, res);
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const prepareEnvironments = (backendfolder:string,frontendfolder:string)=>{
|
|
223
|
+
const targetfolder = `${backendfolder}/src/class`
|
|
224
|
+
const targetfrontendfolder = `${frontendfolder}/server/class`
|
|
225
|
+
try{
|
|
226
|
+
mkdirSync(targetfolder,{recursive:true});
|
|
227
|
+
mkdirSync(targetfrontendfolder);
|
|
228
|
+
}catch(error){
|
|
229
|
+
//do nothing
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
//copy over backend service class
|
|
233
|
+
|
|
234
|
+
copyFileSync(`${constants.templatedir}/SimpleAppService.eta`,`${targetfolder}/SimpleAppService.ts`)
|
|
235
|
+
|
|
236
|
+
//copy over backend controller
|
|
237
|
+
copyFileSync(`${constants.templatedir}/SimpleAppController.eta`,`${targetfolder}/SimpleAppController.ts`)
|
|
238
|
+
|
|
239
|
+
//copy over frontend apiabstract class
|
|
240
|
+
copyFileSync(`${constants.templatedir}/SimpleAppClient.eta`,`${targetfrontendfolder}/SimpleAppClient.ts`)
|
|
241
|
+
|
|
242
|
+
//prepare backend config.ts
|
|
243
|
+
|
|
244
|
+
//copy over frontend config.ts
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
const loadSimpleAppModules=(modules:ModuleObject[],targetfolder:string)=>{
|
|
249
|
+
|
|
250
|
+
const eta = new Eta({views:constants.templatedir});
|
|
251
|
+
const txtMainModule = eta.render('app.module.eta', modules);
|
|
252
|
+
writeFileSync(`${targetfolder}/src/app.module.ts`, txtMainModule);
|
|
253
|
+
|
|
254
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
const program = require("commander") // add this line
|
|
3
|
+
const Fieldtypes= require( './type')
|
|
4
|
+
const generator= require( './generate')
|
|
5
|
+
const fs = require( 'fs')
|
|
6
|
+
const {createNuxt,createNest} =require( './createproject')
|
|
7
|
+
const {exec} = require( "child_process")
|
|
8
|
+
|
|
9
|
+
const capitalizeFirstLetter= require( './libs')
|
|
10
|
+
// const {Logger, ILogObj} = require( "tslog");
|
|
11
|
+
|
|
12
|
+
// const log: Logger = new Logger();
|
|
13
|
+
const figlet = require("figlet");
|
|
14
|
+
// const program = new Command();
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
program
|
|
19
|
+
.version("1.0.0")
|
|
20
|
+
.description("An simpleapp CLI tool for generate frontend (vuejs) and backend(nestjs) codes")
|
|
21
|
+
.option("-c, --config-file <value>", 'configuration file content such as:{"definationsFolder":"./definations", "backendFolder":"./nestproject/src/docs", "frontendFolder":"./nuxt/server"}')
|
|
22
|
+
.option("-s, --definations-folder <value>", "load defination files from which folder")
|
|
23
|
+
.option("-b, --backend-folder <value>", "Create backend code at which folder")
|
|
24
|
+
.option("-f, --frontend-folder <value>", "Create frontend code at which folder")
|
|
25
|
+
.option("-i, --openapi3-yaml <value>", 'openapi3.yaml generated by backend server')
|
|
26
|
+
.parse(process.argv);
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
const options = program.opts();
|
|
30
|
+
console.log(figlet.textSync("SimpleApp Generator 1"));
|
|
31
|
+
// console.log(options)
|
|
32
|
+
const configs = require(options.configFile)
|
|
33
|
+
console.log("configurations: ",configs)
|
|
34
|
+
const definationsFolder = configs.definationsFolder ?? options.definationsFolder
|
|
35
|
+
const backendFolder = configs.backendFolder ?? options.backendFolder
|
|
36
|
+
const frontendFolder = configs.frontendFolder ?? options.frontendFolder
|
|
37
|
+
const openapi3Yaml:string = configs.openapi3Yaml ?? options.openapi3Yaml
|
|
38
|
+
|
|
39
|
+
const runGenNext = (callback)=>{
|
|
40
|
+
if(!fs.existsSync(backendFolder)){
|
|
41
|
+
createNest(backendFolder,callback)
|
|
42
|
+
}else{
|
|
43
|
+
callback()
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const runGenNuxt = (callback)=>{
|
|
47
|
+
if(!fs.existsSync(frontendFolder)){
|
|
48
|
+
createNuxt(frontendFolder,callback)
|
|
49
|
+
}else{
|
|
50
|
+
callback()
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
runGenNuxt(()=>{
|
|
54
|
+
console.log("runGenNuxt done")
|
|
55
|
+
runGenNext(()=>{
|
|
56
|
+
console.log("runGenNext done")
|
|
57
|
+
generator.initialize(definationsFolder,backendFolder,frontendFolder)
|
|
58
|
+
if(openapi3Yaml !=''){
|
|
59
|
+
|
|
60
|
+
exec(`openapi-generator generate -i ${openapi3Yaml} -o ${frontendFolder}/server/openapi -g typescript-axios --skip-validate-spec`,(error, stdout, stderr)=>{
|
|
61
|
+
if(error){
|
|
62
|
+
console.error(stderr);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
// pnpm exec prettier ./src/docs --write
|
|
73
|
+
// pnpm exec prettier ./apiclients --write
|
package/src/libs.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// const clc = require("cli-color");
|
|
2
|
+
|
|
3
|
+
export const capitalizeFirstLetter = (str: string) => {
|
|
4
|
+
const res = str == '' ? '' : str.slice(0, 1).toUpperCase() + str.slice(1);
|
|
5
|
+
// const res = str;
|
|
6
|
+
return res;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
// export const logsuccess = (data:any)=>console.log(clc.green(data))
|
|
10
|
+
// export const logerror = (data:any)=>console.log(clc.error(data))
|
|
11
|
+
// export const logwarn = (data:any)=>console.log(clc.yellow(data))
|
|
12
|
+
// export const logdefault = (data:any)=>console.log(data)
|
|
13
|
+
|
|
14
|
+
|