@mxpicture/gcp-functions-generator 0.2.0
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/dist/4testing/index.d.ts +1 -0
- package/dist/4testing/index.js +2 -0
- package/dist/4testing/templates/index.d.ts +2 -0
- package/dist/4testing/templates/index.js +3 -0
- package/dist/4testing/templates/template.medication.d.ts +35 -0
- package/dist/4testing/templates/template.medication.js +134 -0
- package/dist/4testing/templates/template.settings.d.ts +23 -0
- package/dist/4testing/templates/template.settings.js +73 -0
- package/dist/4testing/utils.d.ts +5 -0
- package/dist/4testing/utils.js +14 -0
- package/dist/common/Barrel.d.ts +24 -0
- package/dist/common/Barrel.js +80 -0
- package/dist/common/Collector.d.ts +22 -0
- package/dist/common/Collector.js +37 -0
- package/dist/common/Directories.d.ts +36 -0
- package/dist/common/Directories.js +69 -0
- package/dist/common/Evaluate.d.ts +12 -0
- package/dist/common/Evaluate.js +120 -0
- package/dist/common/Extractor.d.ts +33 -0
- package/dist/common/Extractor.js +201 -0
- package/dist/common/GenChangeDetector.d.ts +19 -0
- package/dist/common/GenChangeDetector.js +33 -0
- package/dist/common/generator.common.d.ts +21 -0
- package/dist/common/generator.common.js +86 -0
- package/dist/common/index.d.ts +7 -0
- package/dist/common/index.js +8 -0
- package/dist/generator/Generator.d.ts +41 -0
- package/dist/generator/Generator.js +132 -0
- package/dist/generator/GeneratorAnnotations.d.ts +9 -0
- package/dist/generator/GeneratorAnnotations.js +65 -0
- package/dist/generator/GeneratorBackend.d.ts +13 -0
- package/dist/generator/GeneratorBackend.js +134 -0
- package/dist/generator/GeneratorDoc.d.ts +9 -0
- package/dist/generator/GeneratorDoc.js +22 -0
- package/dist/generator/GeneratorFrontend.d.ts +12 -0
- package/dist/generator/GeneratorFrontend.js +94 -0
- package/dist/generator/GeneratorRoutes.d.ts +11 -0
- package/dist/generator/GeneratorRoutes.js +52 -0
- package/dist/generator/GeneratorZod.d.ts +25 -0
- package/dist/generator/GeneratorZod.js +149 -0
- package/dist/generator/index.d.ts +7 -0
- package/dist/generator/index.js +8 -0
- package/dist/meta/index.d.ts +3 -0
- package/dist/meta/index.js +4 -0
- package/dist/meta/meta.decorators.d.ts +26 -0
- package/dist/meta/meta.decorators.js +17 -0
- package/dist/meta/meta.imports.d.ts +11 -0
- package/dist/meta/meta.imports.js +54 -0
- package/dist/meta/meta.names.d.ts +13 -0
- package/dist/meta/meta.names.js +93 -0
- package/package.json +48 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { basename, dirname } from "node:path";
|
|
2
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import { MetaFileExtension, MetaTargetType, } from "@mxpicture/gcp-functions-common/meta";
|
|
4
|
+
import { directories } from "../common/Directories.js";
|
|
5
|
+
import { toFilename, formatCode, formatJson, } from "@mxpicture/gcp-functions-code/common";
|
|
6
|
+
import { metaBasenameAsync, metaBackendNamesAsync, metaFrontendNamesAsync, metaNamesAsync, } from "../meta/meta.names.js";
|
|
7
|
+
const importToCode = (imp) => imp.props.length > 0
|
|
8
|
+
? `import ${imp.isType ? "type " : ""}{ ${[...imp.props].join(", ")} } from "${imp.path}"`
|
|
9
|
+
: null;
|
|
10
|
+
const importToCodeAsync = async (imp) => Promise.resolve().then(() => importToCode(imp));
|
|
11
|
+
export const importsToCode = (imports) => imports.map(importToCode).filter((imp) => imp !== null);
|
|
12
|
+
export const importsToCodeAsync = async (imports) => (await Promise.all(imports.map(importToCodeAsync))).filter((imp) => imp !== null);
|
|
13
|
+
export class Generator {
|
|
14
|
+
type;
|
|
15
|
+
ext;
|
|
16
|
+
targetType;
|
|
17
|
+
collector;
|
|
18
|
+
useAdditionalImports;
|
|
19
|
+
constructor(type, ext, targetType, collector, useAdditionalImports = false) {
|
|
20
|
+
this.type = type;
|
|
21
|
+
this.ext = ext;
|
|
22
|
+
this.targetType = targetType;
|
|
23
|
+
this.collector = collector;
|
|
24
|
+
this.useAdditionalImports = useAdditionalImports;
|
|
25
|
+
}
|
|
26
|
+
async run(file) {
|
|
27
|
+
let result = null;
|
|
28
|
+
const interfaceResults = await Promise.all(file.headers.map((header) => this.processHeader(header)));
|
|
29
|
+
for (const interfaceResult of interfaceResults) {
|
|
30
|
+
if (!interfaceResult)
|
|
31
|
+
continue;
|
|
32
|
+
if (!result) {
|
|
33
|
+
const targetFilename = toFilename({
|
|
34
|
+
filename: basename(interfaceResult.inputFilePath),
|
|
35
|
+
type: this.type,
|
|
36
|
+
ext: this.ext,
|
|
37
|
+
generated: true,
|
|
38
|
+
});
|
|
39
|
+
result = {
|
|
40
|
+
inputFilePath: interfaceResult.inputFilePath,
|
|
41
|
+
targetFilePath: directories.toTargetPath(this.type, targetFilename, this.targetType),
|
|
42
|
+
targetType: this.targetType,
|
|
43
|
+
imports: [],
|
|
44
|
+
importsCode: [],
|
|
45
|
+
code: [],
|
|
46
|
+
ext: this.ext,
|
|
47
|
+
type: this.type,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
this.addCode(result, interfaceResult.code);
|
|
51
|
+
this.addImports(result, interfaceResult.imports);
|
|
52
|
+
}
|
|
53
|
+
if (!result)
|
|
54
|
+
throw new Error(`Generator ${this.type}, file ${file.templateRepoFilePath}: no headers provided`);
|
|
55
|
+
result.importsCode = await importsToCodeAsync(result.imports);
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
static async write(...files) {
|
|
59
|
+
const promises = [];
|
|
60
|
+
for (const file of files) {
|
|
61
|
+
const preCode = [...file.importsCode, "", ...file.code].join("\n");
|
|
62
|
+
promises.push((async () => {
|
|
63
|
+
let code;
|
|
64
|
+
if (file.ext === MetaFileExtension.ts)
|
|
65
|
+
code = await formatCode(preCode);
|
|
66
|
+
else if (file.ext === MetaFileExtension.json)
|
|
67
|
+
code = await formatJson(preCode);
|
|
68
|
+
else
|
|
69
|
+
code = preCode;
|
|
70
|
+
await mkdir(dirname(file.targetFilePath), { recursive: true });
|
|
71
|
+
return writeFile(file.targetFilePath, code);
|
|
72
|
+
})());
|
|
73
|
+
}
|
|
74
|
+
await Promise.all(promises);
|
|
75
|
+
}
|
|
76
|
+
resolveImport(targetType, fileType) {
|
|
77
|
+
return directories.resolveImport({ targetType, fileType }, { targetType: this.targetType, fileType: this.type });
|
|
78
|
+
}
|
|
79
|
+
importCommon(fileType) {
|
|
80
|
+
return this.resolveImport(MetaTargetType.common, fileType);
|
|
81
|
+
}
|
|
82
|
+
importFrontend(fileType) {
|
|
83
|
+
return this.resolveImport(MetaTargetType.frontend, fileType);
|
|
84
|
+
}
|
|
85
|
+
importBackend(fileType) {
|
|
86
|
+
return this.resolveImport(MetaTargetType.backend, fileType);
|
|
87
|
+
}
|
|
88
|
+
addCode(res, code) {
|
|
89
|
+
if (res.code.length > 0)
|
|
90
|
+
res.code.push("");
|
|
91
|
+
res.code.push(...code);
|
|
92
|
+
}
|
|
93
|
+
addImport(res, imp) {
|
|
94
|
+
let foundImp = res.imports.find((i) => i.path === imp.path && i.isType === imp.isType);
|
|
95
|
+
if (!foundImp) {
|
|
96
|
+
foundImp = {
|
|
97
|
+
...imp,
|
|
98
|
+
props: [],
|
|
99
|
+
};
|
|
100
|
+
res.imports.push(foundImp);
|
|
101
|
+
}
|
|
102
|
+
for (const prop of imp.props)
|
|
103
|
+
if (!foundImp.props.find((p) => p === prop))
|
|
104
|
+
foundImp.props.push(prop);
|
|
105
|
+
}
|
|
106
|
+
addImports(res, imports) {
|
|
107
|
+
for (const imp of imports)
|
|
108
|
+
this.addImport(res, imp);
|
|
109
|
+
}
|
|
110
|
+
async processHeader(header) {
|
|
111
|
+
const extrName = await metaBasenameAsync(header.templateName);
|
|
112
|
+
const names = this.targetType === MetaTargetType.backend
|
|
113
|
+
? await metaBackendNamesAsync(extrName, header.prefix)
|
|
114
|
+
: this.targetType === MetaTargetType.frontend
|
|
115
|
+
? await metaFrontendNamesAsync(extrName, header.prefix)
|
|
116
|
+
: await metaNamesAsync(extrName, header.prefix);
|
|
117
|
+
this.collector.add(names.basename, this.targetType, { names });
|
|
118
|
+
const result = await this.runHeader(header, names);
|
|
119
|
+
if (!result)
|
|
120
|
+
return result;
|
|
121
|
+
return {
|
|
122
|
+
name: result.name,
|
|
123
|
+
inputFilePath: header.inputFilePath,
|
|
124
|
+
code: [...result.code],
|
|
125
|
+
imports: this.useAdditionalImports &&
|
|
126
|
+
header.additionalImports &&
|
|
127
|
+
header.additionalImports.length > 0
|
|
128
|
+
? [...result.imports, ...header.additionalImports]
|
|
129
|
+
: [...result.imports],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { MetaHeadData } from "@mxpicture/gcp-functions-common/meta";
|
|
2
|
+
import { MetaNames } from "@mxpicture/gcp-functions-common/types";
|
|
3
|
+
import { Generator, GeneratorCode } from "./Generator.js";
|
|
4
|
+
export declare class GeneratorAnnotations extends Generator {
|
|
5
|
+
constructor();
|
|
6
|
+
protected runHeader(mainData: MetaHeadData, names: MetaNames): Promise<GeneratorCode | null>;
|
|
7
|
+
}
|
|
8
|
+
declare const _default: GeneratorAnnotations;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { MetaFileType, MetaFileExtension, MetaTargetType, mapAnnotationsHeader, } from "@mxpicture/gcp-functions-common/meta";
|
|
2
|
+
import { Generator } from "./Generator.js";
|
|
3
|
+
import { Collector } from "../common/Collector.js";
|
|
4
|
+
import { formatJson2Spaces } from "@mxpicture/gcp-functions-code/common";
|
|
5
|
+
const typeRegex = /\"type\": \"([a-zA-Z][a-zA-Z0-9]*)\"/;
|
|
6
|
+
const itemTypeRegex = /\"itemType\": \"(MetaPropertyType\.|)([a-zA-Z][a-zA-Z0-9]*)\"/;
|
|
7
|
+
const propertyRefRegex = /\"propertyRef\": \"([a-zA-Z][a-zA-Z0-9]*)\"/;
|
|
8
|
+
export class GeneratorAnnotations extends Generator {
|
|
9
|
+
constructor() {
|
|
10
|
+
super(MetaFileType.annotations, MetaFileExtension.ts, MetaTargetType.common, Collector.instance());
|
|
11
|
+
}
|
|
12
|
+
async runHeader(mainData, names) {
|
|
13
|
+
const res = {
|
|
14
|
+
code: [],
|
|
15
|
+
imports: [
|
|
16
|
+
{
|
|
17
|
+
path: "@mxpicture/gcp-functions-common/types",
|
|
18
|
+
props: ["AnnotationsHeader"],
|
|
19
|
+
isType: true,
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
path: "@mxpicture/gcp-functions-common/meta",
|
|
23
|
+
props: ["MetaPropertyType"],
|
|
24
|
+
isType: false,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
path: "@mxpicture/gcp-functions-common/meta",
|
|
28
|
+
props: ["MetaPropertyDataWoType"],
|
|
29
|
+
isType: true,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
name: mainData.templateName,
|
|
33
|
+
};
|
|
34
|
+
const header = mapAnnotationsHeader(mainData);
|
|
35
|
+
const json = await formatJson2Spaces(JSON.stringify(header));
|
|
36
|
+
const lines = json.split("\n");
|
|
37
|
+
res.code.push(`export const ${names.annotations}: AnnotationsHeader = `);
|
|
38
|
+
// replace enums and types
|
|
39
|
+
for (let line of lines) {
|
|
40
|
+
// type
|
|
41
|
+
let match = null;
|
|
42
|
+
match = line.match(typeRegex);
|
|
43
|
+
while (match && match.length > 1) {
|
|
44
|
+
line = line.replace(typeRegex, `type: MetaPropertyType.${match[1]}`);
|
|
45
|
+
match = line.match(typeRegex);
|
|
46
|
+
}
|
|
47
|
+
// itemType
|
|
48
|
+
match = line.match(itemTypeRegex);
|
|
49
|
+
while (match && match.length > 2) {
|
|
50
|
+
line = line.replace(itemTypeRegex, `itemType: MetaPropertyType.${match[2]}`);
|
|
51
|
+
match = line.match(itemTypeRegex);
|
|
52
|
+
}
|
|
53
|
+
// propertyRef
|
|
54
|
+
match = line.match(propertyRefRegex);
|
|
55
|
+
while (match && match.length > 1) {
|
|
56
|
+
line = line.replace(propertyRefRegex, `propertyRef: "${match[1]}" as keyof MetaPropertyDataWoType`);
|
|
57
|
+
match = line.match(propertyRefRegex);
|
|
58
|
+
}
|
|
59
|
+
res.code.push(line);
|
|
60
|
+
}
|
|
61
|
+
res.code.push(";");
|
|
62
|
+
return res;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export default new GeneratorAnnotations();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { MetaNames } from "@mxpicture/gcp-functions-common/types";
|
|
2
|
+
import { MetaHeadData, MetaRoutes } from "@mxpicture/gcp-functions-common/meta";
|
|
3
|
+
import { Generator, GeneratorCode } from "./Generator.js";
|
|
4
|
+
export declare class GeneratorBackend extends Generator {
|
|
5
|
+
constructor();
|
|
6
|
+
protected runHeader(mainData: MetaHeadData, names: MetaNames): Promise<GeneratorCode | null>;
|
|
7
|
+
protected buildApi(routes: MetaRoutes, names: MetaNames): string[];
|
|
8
|
+
protected buildFunction(names: MetaNames): string[];
|
|
9
|
+
protected buildStore(names: MetaNames): string[];
|
|
10
|
+
protected buildCreate(names: MetaNames): string[];
|
|
11
|
+
}
|
|
12
|
+
declare const _default: GeneratorBackend;
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { hasCrudRoute, isCrudRoute, MetaFileExtension, MetaFileType, MetaTargetType, } from "@mxpicture/gcp-functions-common/meta";
|
|
2
|
+
import { Generator } from "./Generator.js";
|
|
3
|
+
import { Collector } from "../common/Collector.js";
|
|
4
|
+
import { lowerFirstLetter } from "@mxpicture/gcp-functions-code/common";
|
|
5
|
+
export class GeneratorBackend extends Generator {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(MetaFileType.backend, MetaFileExtension.ts, MetaTargetType.backend, Collector.instance(), true);
|
|
8
|
+
}
|
|
9
|
+
async runHeader(mainData, names) {
|
|
10
|
+
if (Object.keys(mainData.routes).length === 0)
|
|
11
|
+
return null;
|
|
12
|
+
return {
|
|
13
|
+
code: [
|
|
14
|
+
...this.buildFunction(names),
|
|
15
|
+
"",
|
|
16
|
+
...this.buildApi(mainData.routes, names),
|
|
17
|
+
"",
|
|
18
|
+
...this.buildStore(names),
|
|
19
|
+
"",
|
|
20
|
+
...this.buildCreate(names),
|
|
21
|
+
],
|
|
22
|
+
imports: [
|
|
23
|
+
{
|
|
24
|
+
path: "@mxpicture/gcp-functions-common/types",
|
|
25
|
+
props: ["ApiFromRoutes", "FunctionRequest", "FunctionResponse"],
|
|
26
|
+
isType: true,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
path: "@mxpicture/gcp-functions-backend/store",
|
|
30
|
+
props: ["Store"],
|
|
31
|
+
isType: false,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
path: "@mxpicture/gcp-functions-backend/validation",
|
|
35
|
+
props: ["Validation"],
|
|
36
|
+
isType: false,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
path: "@mxpicture/gcp-functions-backend/api",
|
|
40
|
+
props: ["BackendApi"],
|
|
41
|
+
isType: false,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
path: "firebase-admin/firestore",
|
|
45
|
+
props: ["FirestoreDataConverter"],
|
|
46
|
+
isType: true,
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
path: "firebase-functions/v2/https",
|
|
50
|
+
props: ["CallableFunction"],
|
|
51
|
+
isType: true,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
path: this.importCommon(MetaFileType.routes),
|
|
55
|
+
props: [names.routes],
|
|
56
|
+
isType: true,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
path: this.importCommon(MetaFileType.doc),
|
|
60
|
+
props: [names.doc],
|
|
61
|
+
isType: true,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
path: "@mxpicture/gcp-functions-backend/function",
|
|
65
|
+
props: ["IBackendFunction"],
|
|
66
|
+
isType: false,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
path: this.importCommon(MetaFileType.routes),
|
|
70
|
+
props: [`${names.routes}Name`],
|
|
71
|
+
isType: false,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
path: this.importBackend(MetaFileType.zod),
|
|
75
|
+
props: [names.shape],
|
|
76
|
+
isType: false,
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
name: mainData.templateName,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
buildApi(routes, names) {
|
|
83
|
+
const code = [];
|
|
84
|
+
const superClassName = hasCrudRoute(Object.keys(routes))
|
|
85
|
+
? "BackendApi"
|
|
86
|
+
: "IBackendApi";
|
|
87
|
+
code.push(`export abstract class I${names.api} extends ${superClassName}<${names.doc}, ${names.store}, Validation<${names.doc}>>`, `implements ApiFromRoutes<${names.routes}>`, "{", ` public constructor() { super("${lowerFirstLetter(names.basename)}"); }`, "");
|
|
88
|
+
for (const [routeName, params] of Object.entries(routes)) {
|
|
89
|
+
if (isCrudRoute(routeName))
|
|
90
|
+
continue; // ignore crud --> provided by super class
|
|
91
|
+
let definition = routeName;
|
|
92
|
+
if (params.requestType !== "never" && params.requestType !== "void")
|
|
93
|
+
definition += `(request: ${params.requestType})`;
|
|
94
|
+
else
|
|
95
|
+
definition += `()`;
|
|
96
|
+
definition += `: Promise<${params.responseType}>`;
|
|
97
|
+
code.push(` public abstract ${definition};`);
|
|
98
|
+
}
|
|
99
|
+
code.push("}");
|
|
100
|
+
return code;
|
|
101
|
+
}
|
|
102
|
+
buildFunction(names) {
|
|
103
|
+
return [
|
|
104
|
+
`export class ${names.func} extends IBackendFunction<${names.doc}, I${names.api}> {`,
|
|
105
|
+
` public constructor(api?: I${names.api}) { super("${names.functionName}"); this.useRoutes(${names.routes}Name); if (api) this.useApi(api); }`,
|
|
106
|
+
"}",
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
buildStore(names) {
|
|
110
|
+
return [
|
|
111
|
+
`export class ${names.store} extends Store<${names.doc}> {`,
|
|
112
|
+
` public constructor(converter?: FirestoreDataConverter<${names.doc}>) { super("${lowerFirstLetter(names.basename)}", converter); }`,
|
|
113
|
+
"}",
|
|
114
|
+
];
|
|
115
|
+
}
|
|
116
|
+
buildCreate(names) {
|
|
117
|
+
return [
|
|
118
|
+
`export const create${names.basename}Function = (api: I${names.api}): CallableFunction<FunctionRequest<unknown>,Promise<FunctionResponse<unknown>>,unknown> => {`,
|
|
119
|
+
` const store = new ${names.store}();`,
|
|
120
|
+
"",
|
|
121
|
+
` const val = new Validation<${names.doc}>("${lowerFirstLetter(names.basename)}");`,
|
|
122
|
+
` val.useShape(${names.shape});`,
|
|
123
|
+
"",
|
|
124
|
+
` const func = new ${names.func}(api);`,
|
|
125
|
+
"",
|
|
126
|
+
" api.useStore(store);",
|
|
127
|
+
" api.useValidation(val);",
|
|
128
|
+
"",
|
|
129
|
+
" return func.buildFunction();",
|
|
130
|
+
"};",
|
|
131
|
+
];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
export default new GeneratorBackend();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { MetaHeadData } from "@mxpicture/gcp-functions-common/meta";
|
|
2
|
+
import { MetaNames } from "@mxpicture/gcp-functions-common/types";
|
|
3
|
+
import { Generator, GeneratorCode } from "./Generator.js";
|
|
4
|
+
export declare class GeneratorDoc extends Generator {
|
|
5
|
+
constructor();
|
|
6
|
+
protected runHeader(mainData: MetaHeadData, names: MetaNames): Promise<GeneratorCode | null>;
|
|
7
|
+
}
|
|
8
|
+
declare const _default: GeneratorDoc;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { MetaFileExtension, MetaFileType, MetaTargetType, } from "@mxpicture/gcp-functions-common/meta";
|
|
2
|
+
import { Generator } from "./Generator.js";
|
|
3
|
+
import { Collector } from "../common/Collector.js";
|
|
4
|
+
import { metaBasename, isMetaNameType } from "../meta/meta.names.js";
|
|
5
|
+
export class GeneratorDoc extends Generator {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(MetaFileType.doc, MetaFileExtension.ts, MetaTargetType.common, Collector.instance());
|
|
8
|
+
}
|
|
9
|
+
async runHeader(mainData, names) {
|
|
10
|
+
const res = {
|
|
11
|
+
code: [],
|
|
12
|
+
imports: [],
|
|
13
|
+
name: mainData.templateName,
|
|
14
|
+
};
|
|
15
|
+
res.code.push(`export interface ${names.doc} {`);
|
|
16
|
+
for (const prop of mainData.properties)
|
|
17
|
+
res.code.push(` ${prop.propertyKey}${prop.optional ? "?" : ""}: `, `${metaBasename(prop.propertyType)}${isMetaNameType(prop.propertyType, MetaFileType.template) ? "Doc" : ""};`);
|
|
18
|
+
res.code.push("}");
|
|
19
|
+
return res;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export default new GeneratorDoc();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { MetaHeadData, MetaRoutes } from "@mxpicture/gcp-functions-common/meta";
|
|
2
|
+
import { MetaNames } from "@mxpicture/gcp-functions-common/types";
|
|
3
|
+
import { Generator, GeneratorCode } from "./Generator.js";
|
|
4
|
+
export declare class GeneratorFrontend extends Generator {
|
|
5
|
+
constructor();
|
|
6
|
+
protected runHeader(mainData: MetaHeadData, names: MetaNames): Promise<GeneratorCode | null>;
|
|
7
|
+
protected buildApi(routes: MetaRoutes, names: MetaNames): string[];
|
|
8
|
+
protected buildFunction(names: MetaNames): string[];
|
|
9
|
+
protected buildCreate(names: MetaNames): string[];
|
|
10
|
+
}
|
|
11
|
+
declare const _default: GeneratorFrontend;
|
|
12
|
+
export default _default;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { hasCrudRoute, isCrudRoute, MetaFileExtension, MetaFileType, MetaTargetType, } from "@mxpicture/gcp-functions-common/meta";
|
|
2
|
+
import { Generator } from "./Generator.js";
|
|
3
|
+
import { Collector } from "../common/Collector.js";
|
|
4
|
+
import { lowerFirstLetter } from "@mxpicture/gcp-functions-code/common";
|
|
5
|
+
export class GeneratorFrontend extends Generator {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(MetaFileType.frontend, MetaFileExtension.ts, MetaTargetType.frontend, Collector.instance(), true);
|
|
8
|
+
}
|
|
9
|
+
async runHeader(mainData, names) {
|
|
10
|
+
if (Object.keys(mainData.routes).length === 0)
|
|
11
|
+
return null;
|
|
12
|
+
return {
|
|
13
|
+
code: [
|
|
14
|
+
...this.buildFunction(names),
|
|
15
|
+
"",
|
|
16
|
+
...this.buildApi(mainData.routes, names),
|
|
17
|
+
"",
|
|
18
|
+
...this.buildCreate(names),
|
|
19
|
+
],
|
|
20
|
+
imports: [
|
|
21
|
+
{
|
|
22
|
+
path: "@mxpicture/gcp-functions-frontend/function",
|
|
23
|
+
props: ["IFrontendFunction"],
|
|
24
|
+
isType: false,
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
path: this.importCommon(MetaFileType.routes),
|
|
28
|
+
props: [`${names.routes}Name`],
|
|
29
|
+
isType: false,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
path: "@mxpicture/gcp-functions-frontend/api",
|
|
33
|
+
props: ["FrontendApi"],
|
|
34
|
+
isType: false,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
path: "@mxpicture/gcp-functions-common/types",
|
|
38
|
+
props: ["ApiFromRoutes"],
|
|
39
|
+
isType: true,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
path: this.importCommon(MetaFileType.routes),
|
|
43
|
+
props: [names.routes],
|
|
44
|
+
isType: true,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
path: this.importCommon(MetaFileType.doc),
|
|
48
|
+
props: [names.doc],
|
|
49
|
+
isType: true,
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
name: mainData.templateName,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
buildApi(routes, names) {
|
|
56
|
+
const code = [];
|
|
57
|
+
const superClassName = hasCrudRoute(Object.keys(routes))
|
|
58
|
+
? `FrontendApi<${names.doc}, ${names.func}>`
|
|
59
|
+
: `IFrontendApi<${names.func}>`;
|
|
60
|
+
code.push(`export class ${names.api} extends ${superClassName}`, `implements ApiFromRoutes<${names.routes}>`, "{", `public constructor(func?: ${names.func}) { super("${names.functionName}"); if (func) this.useFunc(func); }`, "");
|
|
61
|
+
for (const [routeName, params] of Object.entries(routes)) {
|
|
62
|
+
if (isCrudRoute(routeName))
|
|
63
|
+
continue; // ignore crud --> provided by super class
|
|
64
|
+
let definition = routeName;
|
|
65
|
+
if (params.requestType !== "never" && params.requestType !== "void")
|
|
66
|
+
definition += `(request: ${params.requestType})`;
|
|
67
|
+
else
|
|
68
|
+
definition += `()`;
|
|
69
|
+
definition += `: Promise<${params.responseType}>`;
|
|
70
|
+
code.push(` public async ${definition} {`, ` return (await this.func().outgress({ route: "${routeName}", data: request })).data as ${params.responseType};`, " }", "");
|
|
71
|
+
}
|
|
72
|
+
code.push("}");
|
|
73
|
+
return code;
|
|
74
|
+
}
|
|
75
|
+
buildFunction(names) {
|
|
76
|
+
return [
|
|
77
|
+
`export class ${names.func} extends IFrontendFunction {`,
|
|
78
|
+
` public constructor() { super("${lowerFirstLetter(names.basename)}"); this.useRoutes(${names.routes}Name); }`,
|
|
79
|
+
"}",
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
buildCreate(names) {
|
|
83
|
+
return [
|
|
84
|
+
`export const create${names.basename}Api = () => {`,
|
|
85
|
+
` const func = new ${names.func}();`,
|
|
86
|
+
` const api = new ${names.api}(func);`,
|
|
87
|
+
" return api;",
|
|
88
|
+
"};",
|
|
89
|
+
"",
|
|
90
|
+
`export const ${lowerFirstLetter(names.basename)}Api = create${names.basename}Api();`,
|
|
91
|
+
];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export default new GeneratorFrontend();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { MetaHeadData } from "@mxpicture/gcp-functions-common/meta";
|
|
2
|
+
import { MetaNames } from "@mxpicture/gcp-functions-common/types";
|
|
3
|
+
import { Generator, GeneratorCode } from "./Generator.js";
|
|
4
|
+
export declare class GeneratorRoutes extends Generator {
|
|
5
|
+
constructor();
|
|
6
|
+
protected runHeader(mainData: MetaHeadData, names: MetaNames): Promise<GeneratorCode | null>;
|
|
7
|
+
protected buildType(res: GeneratorCode, names: MetaNames, mainData: MetaHeadData): void;
|
|
8
|
+
protected buildEnum(res: GeneratorCode, names: MetaNames, mainData: MetaHeadData): void;
|
|
9
|
+
}
|
|
10
|
+
declare const _default: GeneratorRoutes;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { MetaFileExtension, MetaFileType, MetaTargetType, } from "@mxpicture/gcp-functions-common/meta";
|
|
2
|
+
import { Generator } from "./Generator.js";
|
|
3
|
+
import { Collector } from "../common/Collector.js";
|
|
4
|
+
export class GeneratorRoutes extends Generator {
|
|
5
|
+
constructor() {
|
|
6
|
+
super(MetaFileType.routes, MetaFileExtension.ts, MetaTargetType.common, Collector.instance());
|
|
7
|
+
}
|
|
8
|
+
async runHeader(mainData, names) {
|
|
9
|
+
if (Object.keys(mainData.routes).length === 0)
|
|
10
|
+
return null;
|
|
11
|
+
const res = {
|
|
12
|
+
code: [],
|
|
13
|
+
imports: [
|
|
14
|
+
{
|
|
15
|
+
path: "@mxpicture/gcp-functions-common/types",
|
|
16
|
+
isType: true,
|
|
17
|
+
props: [
|
|
18
|
+
"ApiFilter",
|
|
19
|
+
"DocumentKey",
|
|
20
|
+
"RouteDef",
|
|
21
|
+
"WithKey",
|
|
22
|
+
"WithoutKey",
|
|
23
|
+
"WithRoutes",
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
path: this.importCommon(MetaFileType.doc),
|
|
28
|
+
isType: true,
|
|
29
|
+
props: [names.doc],
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
name: mainData.templateName,
|
|
33
|
+
};
|
|
34
|
+
this.buildType(res, names, mainData);
|
|
35
|
+
res.code.push("");
|
|
36
|
+
this.buildEnum(res, names, mainData);
|
|
37
|
+
return res;
|
|
38
|
+
}
|
|
39
|
+
buildType(res, names, mainData) {
|
|
40
|
+
res.code.push(`export type ${names.routes} = WithRoutes<{`);
|
|
41
|
+
for (const [routeName, params] of Object.entries(mainData.routes))
|
|
42
|
+
res.code.push(` ${routeName}: RouteDef<${params.requestType}, ${params.responseType}>;`);
|
|
43
|
+
res.code.push("}>;");
|
|
44
|
+
}
|
|
45
|
+
buildEnum(res, names, mainData) {
|
|
46
|
+
res.code.push(`export enum ${names.routes}Name {`);
|
|
47
|
+
for (const routeName of Object.keys(mainData.routes))
|
|
48
|
+
res.code.push(` ${routeName} = "${routeName}",`);
|
|
49
|
+
res.code.push("}");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export default new GeneratorRoutes();
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { MetaHeadData, MetaPropertyData } from "@mxpicture/gcp-functions-common/meta";
|
|
2
|
+
import { MetaImport, MetaNames } from "@mxpicture/gcp-functions-common/types";
|
|
3
|
+
import { Generator, GeneratorCode } from "./Generator.js";
|
|
4
|
+
export declare class GeneratorZod extends Generator {
|
|
5
|
+
protected zImports: Set<string>;
|
|
6
|
+
constructor();
|
|
7
|
+
protected runHeader(mainData: MetaHeadData, names: MetaNames): Promise<GeneratorCode | null>;
|
|
8
|
+
protected startZ(): void;
|
|
9
|
+
protected endZ(): MetaImport[];
|
|
10
|
+
protected z(name: string, params?: string): string;
|
|
11
|
+
protected buildShape(properties: MetaPropertyData[], names: MetaNames): string[];
|
|
12
|
+
protected buildSchema(names: MetaNames): string[];
|
|
13
|
+
protected buildProperty(prop: MetaPropertyData): string | null;
|
|
14
|
+
protected buildNumber(_prop: MetaPropertyData): string | null;
|
|
15
|
+
protected buildKey(_prop: MetaPropertyData): string | null;
|
|
16
|
+
protected buildCreateTime(_prop: MetaPropertyData): string | null;
|
|
17
|
+
protected buildUpdateTime(_prop: MetaPropertyData): string | null;
|
|
18
|
+
protected buildString(_prop: MetaPropertyData): string | null;
|
|
19
|
+
protected buildArray(_prop: MetaPropertyData): string | null;
|
|
20
|
+
protected buildObject(_prop: MetaPropertyData): string | null;
|
|
21
|
+
protected buildDate(_prop: MetaPropertyData): string | null;
|
|
22
|
+
protected buildBoolean(_prop: MetaPropertyData): string | null;
|
|
23
|
+
}
|
|
24
|
+
declare const _default: GeneratorZod;
|
|
25
|
+
export default _default;
|