milkio 0.0.12 → 0.0.14
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/api-test/index.ts +5 -1
- package/c.ts +0 -8
- package/defines/define-api-test.ts +4 -3
- package/kernel/milkio.ts +11 -5
- package/kernel/validate.ts +4 -2
- package/package.json +1 -1
- package/scripts/gen-insignificant.ts +5 -5
- package/scripts/gen-significant.ts +3 -3
- package/scripts-del/build-cookbook.ts +0 -233
- package/scripts-del/build-dto.ts +0 -65
- package/scripts-del/generate/generate-app-partial.ts +0 -74
- package/scripts-del/generate/generate-app.ts +0 -152
- package/scripts-del/generate/generate-database.ts +0 -22
- package/scripts-del/generate-partial.ts +0 -15
- package/scripts-del/generate.ts +0 -23
package/api-test/index.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/* eslint-disable no-constant-condition, @typescript-eslint/no-unsafe-argument, no-console, @typescript-eslint/no-explicit-any */
|
|
2
2
|
|
|
3
3
|
import schema from "../../../generated/api-schema"
|
|
4
|
-
import { type MilkioApp } from ".."
|
|
4
|
+
import { useLogger, type MilkioApp } from ".."
|
|
5
5
|
|
|
6
6
|
export const executeApiTests = async <Path extends Array<keyof (typeof schema)["apiTestsSchema"]>>(app: MilkioApp, path: Path | string | true | 1 | undefined) => {
|
|
7
7
|
console.log(`🥛 Milkio Api Testing..\n`)
|
|
8
8
|
|
|
9
|
+
const logger = useLogger('global')
|
|
9
10
|
let pathArr = [] as Array<string>
|
|
10
11
|
if (!path || path === "1" || path === 1 || path === true) {
|
|
11
12
|
pathArr = Object.keys(schema.apiTestsSchema) as unknown as Path
|
|
@@ -37,9 +38,12 @@ export const executeApiTests = async <Path extends Array<keyof (typeof schema)["
|
|
|
37
38
|
throw new Error("")
|
|
38
39
|
}, cs.timeout ?? 8192)
|
|
39
40
|
await cs.handler({
|
|
41
|
+
log: (...args: Array<unknown>) => console.log(...args),
|
|
40
42
|
// @ts-ignore
|
|
41
43
|
execute: async (params: any, headers?: any, options?: any) => app.execute(path, params, headers ?? {}, options),
|
|
42
44
|
executeOther: async (path: any, params: any, headers?: any, options?: any) => app.execute(path, params, headers ?? {}, options),
|
|
45
|
+
randParams: () => app.randParams(path as any),
|
|
46
|
+
randOtherParams: (path: any) => app.randParams(path),
|
|
43
47
|
reject: (message?: string) => {
|
|
44
48
|
console.error(`------`)
|
|
45
49
|
console.error(`❌ REJECT -- ${message ?? "Test not satisfied"}`)
|
package/c.ts
CHANGED
|
@@ -26,14 +26,6 @@ const commands = {
|
|
|
26
26
|
await (await import('./scripts/gen-insignificant')).default()
|
|
27
27
|
console.log("\n✅ Milkio Insignificant Generated!")
|
|
28
28
|
},
|
|
29
|
-
// async "build:cookbook"() {
|
|
30
|
-
// await exec(rootPath, ["bun", "./node_modules/milkio/scripts/build-cookbook.ts"])
|
|
31
|
-
// },
|
|
32
|
-
// async "build:dto"() {
|
|
33
|
-
// await exec(join(rootPath, "packages", "dto"), ["bun", "i"])
|
|
34
|
-
// await exec(rootPath, ["bun", "./node_modules/milkio/scripts/generate.ts"])
|
|
35
|
-
// await exec(rootPath, ["bun", "./node_modules/milkio/scripts/build-dto.ts"])
|
|
36
|
-
// },
|
|
37
29
|
async EAR(commandBase64ed: string) {
|
|
38
30
|
try { await $`clear` } catch (e) {}
|
|
39
31
|
const command = Buffer.from(commandBase64ed, 'base64').toString('utf-8')
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Logger } from ".."
|
|
1
2
|
import { type Api, type ExecuteResult, type ExecuteOptions } from ".."
|
|
2
3
|
import type schema from "../../../generated/api-schema"
|
|
3
4
|
|
|
@@ -10,11 +11,11 @@ export function defineApiTest<ApiT extends Api>(_api: ApiT, cases: Array<ApiTest
|
|
|
10
11
|
|
|
11
12
|
export type ApiTestCases<ApiT extends Api> = {
|
|
12
13
|
handler: (test: {
|
|
13
|
-
|
|
14
|
+
log: (...params: Array<unknown>) => void;
|
|
14
15
|
execute: (params: Parameters<ApiT["action"]>[0], headers?: Record<string, string>, options?: ExecuteOptions) => Promise<ExecuteResult<Awaited<ReturnType<ApiT["action"]>>>>;
|
|
15
|
-
// execute other
|
|
16
16
|
executeOther: <Path extends keyof (typeof schema)["apiMethodsTypeSchema"], Result extends Awaited<ReturnType<(typeof schema)["apiMethodsTypeSchema"][Path]["api"]["action"]>>>(path: Path, params: Parameters<(typeof schema)["apiMethodsTypeSchema"][Path]["api"]["action"]>[0] | string, headers?: Record<string, string>, options?: ExecuteOptions) => Promise<ExecuteResult<Result>>;
|
|
17
|
-
|
|
17
|
+
randParams: () => Promise<Parameters<ApiT["action"]>[0]>;
|
|
18
|
+
randOtherParams: <Path extends keyof (typeof schema)["apiMethodsTypeSchema"]>(path: Path) => Promise<Parameters<(typeof schema)["apiMethodsTypeSchema"][Path]['api']['action']>[0]>;
|
|
18
19
|
reject: (message?: string) => void;
|
|
19
20
|
}) => Promise<void> | void;
|
|
20
21
|
name: string;
|
package/kernel/milkio.ts
CHANGED
|
@@ -43,7 +43,8 @@ export async function createMilkioApp(MilkioAppOptions: MilkioAppOptions = {}) {
|
|
|
43
43
|
execute: _execute,
|
|
44
44
|
executeToJson: _executeToJson,
|
|
45
45
|
_executeCore,
|
|
46
|
-
_executeCoreToJson
|
|
46
|
+
_executeCoreToJson,
|
|
47
|
+
randParams: _randParams
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
if (MilkioAppOptions.bootstraps) {
|
|
@@ -163,7 +164,7 @@ async function _executeCore<Path extends keyof (typeof schema)["apiMethodsTypeSc
|
|
|
163
164
|
// check type
|
|
164
165
|
// @ts-ignore
|
|
165
166
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
166
|
-
_validate(await (await schema.apiValidator.validate[path]()).
|
|
167
|
+
params = _validate(await (await schema.apiValidator.validate[path]()).validateParams(params))
|
|
167
168
|
|
|
168
169
|
// execute api
|
|
169
170
|
let api: any
|
|
@@ -197,16 +198,21 @@ async function _executeCore<Path extends keyof (typeof schema)["apiMethodsTypeSc
|
|
|
197
198
|
|
|
198
199
|
async function _executeToJson<Path extends keyof (typeof schema)["apiMethodsTypeSchema"]>(path: Path, params: Parameters<(typeof schema)["apiMethodsTypeSchema"][Path]["api"]["action"]>[0] | string, headersInit: Record<string, string> | Headers = {}, options?: ExecuteOptions): Promise<string> {
|
|
199
200
|
const resultsRaw = await _execute(path, params, headersInit, options)
|
|
200
|
-
const results = await (await schema.apiValidator.validate[path]()).
|
|
201
|
+
const results = await (await schema.apiValidator.validate[path]()).validateResults(TSON.encode(resultsRaw))
|
|
201
202
|
return results
|
|
202
203
|
}
|
|
203
204
|
|
|
204
205
|
async function _executeCoreToJson<Path extends keyof (typeof schema)["apiMethodsTypeSchema"]>(path: Path, params: Parameters<(typeof schema)["apiMethodsTypeSchema"][Path]["api"]["action"]>[0] | string, headersInit: Record<string, string> | Headers = {}, options: ExecuteCoreOptions): Promise<string> {
|
|
205
206
|
const resultsRaw = await _executeCore(path, params, headersInit, options)
|
|
206
|
-
const results = await (await schema.apiValidator.validate[path]()).
|
|
207
|
+
const results = await (await schema.apiValidator.validate[path]()).validateResults(TSON.encode(resultsRaw))
|
|
207
208
|
return results
|
|
208
209
|
}
|
|
209
210
|
|
|
211
|
+
|
|
212
|
+
export async function _randParams<Path extends keyof (typeof schema)["apiMethodsTypeSchema"]>(path: Path): Promise<Parameters<(typeof schema)["apiMethodsTypeSchema"][Path]['api']['action']>[0]> {
|
|
213
|
+
return await (await schema.apiValidator.validate[path]()).randParams()
|
|
214
|
+
}
|
|
215
|
+
|
|
210
216
|
const apis = new Map<string, any>()
|
|
211
217
|
|
|
212
218
|
export type ExecuteResult<Result> = ExecuteResultSuccess<Result> | ExecuteResultFail;
|
|
@@ -244,4 +250,4 @@ export type ExecuteCoreOptions = Mixin<
|
|
|
244
250
|
logger: Logger;
|
|
245
251
|
onAfterHeaders?: (headers: Headers) => void | Promise<void>;
|
|
246
252
|
}
|
|
247
|
-
>;
|
|
253
|
+
>;
|
package/kernel/validate.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
|
|
1
3
|
import type { IValidation } from "typia"
|
|
2
4
|
import { reject } from "../kernel/fail"
|
|
3
5
|
|
|
4
|
-
export function _validate(validator: IValidation.IFailure | IValidation.ISuccess):
|
|
5
|
-
if (validator.success) return
|
|
6
|
+
export function _validate(validator: IValidation.IFailure | IValidation.ISuccess): any {
|
|
7
|
+
if (validator.success) return validator.data
|
|
6
8
|
const error = validator.errors[0]
|
|
7
9
|
|
|
8
10
|
throw reject("TYPE_SAFE_ERROR", {
|
package/package.json
CHANGED
|
@@ -237,15 +237,15 @@ export default async () => {
|
|
|
237
237
|
console.timeEnd(`🧊 Cookbook Stage`)
|
|
238
238
|
console.log(``)
|
|
239
239
|
|
|
240
|
-
console.time(`🧊
|
|
241
|
-
await $`bun run ./node_modules/typescript/bin/tsc --outDir "./packages/
|
|
240
|
+
console.time(`🧊 Client Stage`)
|
|
241
|
+
await $`bun run ./node_modules/typescript/bin/tsc --outDir "./packages/client/project"`.quiet()
|
|
242
242
|
await Bun.build({
|
|
243
|
-
entrypoints: ["./packages/
|
|
244
|
-
outdir: "./packages/
|
|
243
|
+
entrypoints: ["./packages/client/index.ts"],
|
|
244
|
+
outdir: "./packages/client/dist",
|
|
245
245
|
target: 'browser',
|
|
246
246
|
minify: true
|
|
247
247
|
})
|
|
248
|
-
console.timeEnd(`🧊
|
|
248
|
+
console.timeEnd(`🧊 Client Stage`)
|
|
249
249
|
console.log(``)
|
|
250
250
|
|
|
251
251
|
if (!existsSync(join(cwd(), "milkio.toml"))) return
|
|
@@ -95,10 +95,10 @@ import { type TSONEncode } from "@southern-aurora/tson";
|
|
|
95
95
|
import type * as <%= utils.camel(path.slice(0, -3).replaceAll('/', '$')) %> from '${importPath}/<%= path.slice(0, -3) %>';
|
|
96
96
|
|
|
97
97
|
type ParamsT = Parameters<typeof <%= utils.camel(path.replaceAll('/', '$').slice(0, -${3})) %>['api']['action']>[0];
|
|
98
|
-
export const
|
|
98
|
+
export const validateParams = async (params: any) => typia.misc.validatePrune<ParamsT>(params);
|
|
99
99
|
type ResultsT = Awaited<ReturnType<typeof <%= utils.camel(path.replaceAll('/', '$').slice(0, -${3})) %>['api']['action']>>;
|
|
100
|
-
export const
|
|
101
|
-
|
|
100
|
+
export const validateResults = async (results: any) => { _validate(typia.validate<TSONEncode<ExecuteResultSuccess<ResultsT>>>(results)); return typia.json.stringify<TSONEncode<ExecuteResultSuccess<ResultsT>>>(results); };
|
|
101
|
+
export const randParams = async () => typia.random<ParamsT>();
|
|
102
102
|
`.trim()
|
|
103
103
|
// export const paramsSchema = typia.json.application<[{ data: ParamsT }], "swagger">();
|
|
104
104
|
|
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console, @typescript-eslint/no-dynamic-delete */
|
|
2
|
-
|
|
3
|
-
import { TSON, type Cookbook } from ".."
|
|
4
|
-
import { join } from "node:path"
|
|
5
|
-
import { cwd } from "node:process"
|
|
6
|
-
import { writeFile, readFile } from "node:fs/promises"
|
|
7
|
-
|
|
8
|
-
export async function buildCookbook() {
|
|
9
|
-
const schema = await import("../../../generated/api-schema")
|
|
10
|
-
const paths = Object.keys(schema.default.apiMethodsSchema)
|
|
11
|
-
|
|
12
|
-
const cookbook: Cookbook = {}
|
|
13
|
-
for (const path of paths) {
|
|
14
|
-
// const module = await import(/* @vite-ignore */ join(`../../../src/apps/${path}`));
|
|
15
|
-
const code = (await readFile(join(cwd(), `./src/apps/${path}.ts`))).toString()
|
|
16
|
-
const codeLines = code.split("\n")
|
|
17
|
-
let title
|
|
18
|
-
let desc
|
|
19
|
-
const descRaw = /\n\/\*\*\n[\s\S]+?\*\//.exec(code)?.[0] ?? ""
|
|
20
|
-
|
|
21
|
-
if (descRaw) {
|
|
22
|
-
const descRawLines = descRaw.split("\n")
|
|
23
|
-
if (descRawLines.at(0)?.trim() === "") descRawLines.shift()
|
|
24
|
-
if (descRawLines.at(-1)?.trim() === "") descRawLines.pop()
|
|
25
|
-
let first = true
|
|
26
|
-
for (let index = 0; index < descRawLines.length; index++) {
|
|
27
|
-
const descRawLine = descRawLines[index].replace(/^[/ ]+?[*]*/, "").replace(/[*]*\/$/, "")
|
|
28
|
-
|
|
29
|
-
if (!descRawLine) continue
|
|
30
|
-
if (first) {
|
|
31
|
-
title = descRawLine.replace(/#/g, "").trim()
|
|
32
|
-
// Originally the title was in the first line, desc is the rest of it, now desc contains complete markdown content.
|
|
33
|
-
// continue;
|
|
34
|
-
}
|
|
35
|
-
first = false
|
|
36
|
-
desc = (desc ?? "") + "\n" + descRawLine.trim()
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
let apiParams = /action\([\s\S]+?\)/.exec(code)?.[0] ?? "" // The intention of the following code is to extract the parameter part of the action.
|
|
41
|
-
apiParams = /\([\s\S]*,/.exec(apiParams)?.[0] ?? ""
|
|
42
|
-
apiParams = apiParams.slice(0, -1)
|
|
43
|
-
apiParams = apiParams.slice(/[\s\S]+?:/.exec(apiParams)?.[0].length)
|
|
44
|
-
const apiParamsLines = apiParams.split("\n") // The intention of the following code is to remove extra spaces, which will make the code look more beautiful.
|
|
45
|
-
if (apiParamsLines.at(-1)?.trim() === "") apiParamsLines.pop()
|
|
46
|
-
if (apiParamsLines.at(-1)?.trim() === "") apiParamsLines.pop()
|
|
47
|
-
let spaceNumber = 0
|
|
48
|
-
for (const char of apiParamsLines.at(-1) ?? "") {
|
|
49
|
-
if (char === " ") spaceNumber++
|
|
50
|
-
else break
|
|
51
|
-
}
|
|
52
|
-
for (let index = 0; index < apiParamsLines.length; index++) {
|
|
53
|
-
const line = apiParamsLines[index]
|
|
54
|
-
let spaceNumberForThisLine = 0
|
|
55
|
-
for (const char of line) {
|
|
56
|
-
if (char === " ") spaceNumberForThisLine++
|
|
57
|
-
else break
|
|
58
|
-
}
|
|
59
|
-
if (spaceNumberForThisLine >= spaceNumber) {
|
|
60
|
-
apiParamsLines[index] = line.slice(spaceNumber)
|
|
61
|
-
} else {
|
|
62
|
-
apiParamsLines[index] = line.slice(spaceNumberForThisLine)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
apiParams = apiParamsLines.join("\n")
|
|
66
|
-
|
|
67
|
-
// Find the code for the API testing section.
|
|
68
|
-
const apiTestsCodeChars = []
|
|
69
|
-
let apiTestsStartIndex = undefined as undefined | number
|
|
70
|
-
let semicolonMatch = 0
|
|
71
|
-
let semicolonMax = 0
|
|
72
|
-
for (let index = 0; index < codeLines.length; index++) {
|
|
73
|
-
const codeLine = codeLines[index]
|
|
74
|
-
if (apiTestsStartIndex === undefined && !codeLine.includes("defineApiTest(")) continue
|
|
75
|
-
if (apiTestsStartIndex === undefined) apiTestsStartIndex = index
|
|
76
|
-
const codeChars = codeLine.split("")
|
|
77
|
-
for (const codeChar of codeChars) {
|
|
78
|
-
if (codeChar === "[") {
|
|
79
|
-
semicolonMatch++
|
|
80
|
-
semicolonMax++
|
|
81
|
-
}
|
|
82
|
-
if (semicolonMatch !== 0) apiTestsCodeChars.push(codeChar)
|
|
83
|
-
if (codeChar === "]") semicolonMatch--
|
|
84
|
-
}
|
|
85
|
-
if (semicolonMatch === 0 && semicolonMax >= 1) {
|
|
86
|
-
break
|
|
87
|
-
}
|
|
88
|
-
apiTestsCodeChars.push("\n")
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// Find the code for each API test case.
|
|
92
|
-
const apiCaseCodes: Array<string> = []
|
|
93
|
-
let currentApiCaseCode = undefined as undefined | Array<string>
|
|
94
|
-
let apiTestCaseStartIndex = undefined as undefined | number
|
|
95
|
-
let apiTestCaseMatch = 0
|
|
96
|
-
for (let index = 0; index < apiTestsCodeChars.length; index++) {
|
|
97
|
-
const apiTestsCodeChar = apiTestsCodeChars[index]
|
|
98
|
-
if (apiTestCaseStartIndex === undefined && apiTestsCodeChar === "{") {
|
|
99
|
-
currentApiCaseCode = []
|
|
100
|
-
apiTestCaseStartIndex = index
|
|
101
|
-
}
|
|
102
|
-
if (apiTestsCodeChar === "{") {
|
|
103
|
-
apiTestCaseMatch++
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (apiTestCaseMatch !== 0) currentApiCaseCode!.push(apiTestsCodeChar)
|
|
107
|
-
|
|
108
|
-
if (apiTestsCodeChar === "}") {
|
|
109
|
-
apiTestCaseMatch--
|
|
110
|
-
if (apiTestCaseMatch === 0) {
|
|
111
|
-
apiCaseCodes.push(currentApiCaseCode!.join(""))
|
|
112
|
-
currentApiCaseCode = undefined
|
|
113
|
-
apiTestCaseStartIndex = undefined
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const apiCases: Array<{
|
|
119
|
-
name: string;
|
|
120
|
-
handler: string;
|
|
121
|
-
}> = []
|
|
122
|
-
|
|
123
|
-
for (let index = 0; index < apiCaseCodes.length; index++) {
|
|
124
|
-
const code = apiCaseCodes[index]
|
|
125
|
-
const name = /name:[\s\S]+?,/.exec(code)?.[0]?.slice(5, -1)?.trim().slice(1, -1) ?? ""
|
|
126
|
-
const handlerChars = /handler:[\s\S]*/.exec(code)?.[0]?.split("") ?? []
|
|
127
|
-
let handler = "" // Find the main code of the handler.
|
|
128
|
-
let handlerStartIndex = undefined as undefined | number
|
|
129
|
-
let handlerMatch = 0
|
|
130
|
-
for (let index = 0; index < handlerChars.length; index++) {
|
|
131
|
-
const handlerChar = handlerChars[index]
|
|
132
|
-
if (handlerStartIndex !== undefined && handlerChar === "{") handlerStartIndex = index
|
|
133
|
-
if (handlerChar === "{") handlerMatch++
|
|
134
|
-
if (handlerMatch !== 0) handler = handler + handlerChar
|
|
135
|
-
if (handlerChar === "}") handlerMatch--
|
|
136
|
-
if (handlerStartIndex !== undefined && handlerMatch === 0) break
|
|
137
|
-
}
|
|
138
|
-
handler = handler.slice(1, -1)
|
|
139
|
-
|
|
140
|
-
const handlerLines = handler.split("\n") // The intention of the following code is to remove extra spaces, which will make the code look more beautiful.
|
|
141
|
-
if (handlerLines.at(-1)?.trim() === "") handlerLines.pop()
|
|
142
|
-
if (handlerLines.at(-1)?.trim() === "") handlerLines.pop()
|
|
143
|
-
if (handlerLines.at(0)?.trim() === "") handlerLines.shift()
|
|
144
|
-
if (handlerLines.at(0)?.trim() === "") handlerLines.shift()
|
|
145
|
-
let spaceNumber = 0
|
|
146
|
-
for (const char of handlerLines.at(-1) ?? "") {
|
|
147
|
-
if (char === " ") spaceNumber++
|
|
148
|
-
else break
|
|
149
|
-
}
|
|
150
|
-
for (let index = 0; index < handlerLines.length; index++) {
|
|
151
|
-
const line = handlerLines[index]
|
|
152
|
-
let spaceNumberForThisLine = 0
|
|
153
|
-
for (const char of line) {
|
|
154
|
-
if (char === " ") spaceNumberForThisLine++
|
|
155
|
-
else break
|
|
156
|
-
}
|
|
157
|
-
if (spaceNumberForThisLine >= spaceNumber) {
|
|
158
|
-
handlerLines[index] = line.slice(spaceNumber)
|
|
159
|
-
} else {
|
|
160
|
-
handlerLines[index] = line.slice(spaceNumberForThisLine)
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
handler = handlerLines.join("\n")
|
|
164
|
-
|
|
165
|
-
apiCases.push({
|
|
166
|
-
name,
|
|
167
|
-
handler
|
|
168
|
-
})
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// This value has been deprecated because TypeScript types can already replace it well
|
|
172
|
-
// let paramsSchema;
|
|
173
|
-
// try {
|
|
174
|
-
// const moduleGenerated = await import(/* @vite-ignore */ `../../../generated/products/apps/${path}`);
|
|
175
|
-
// paramsSchema = moduleGenerated.paramsSchema.schemas[0]?.properties?.data;
|
|
176
|
-
// } catch (error) {}
|
|
177
|
-
|
|
178
|
-
cookbook[path] = {
|
|
179
|
-
title,
|
|
180
|
-
desc,
|
|
181
|
-
params: apiParams,
|
|
182
|
-
cases: apiCases
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* -- indexes
|
|
188
|
-
*/
|
|
189
|
-
|
|
190
|
-
const indexes: Record<string, Array<string>> = {}
|
|
191
|
-
const folderIndexes: Record<string, Array<string>> = {}
|
|
192
|
-
indexes["(root)"] = []
|
|
193
|
-
folderIndexes["(root)"] = []
|
|
194
|
-
for (const path in cookbook) {
|
|
195
|
-
if (!path.includes("/")) indexes["(root)"].push(path)
|
|
196
|
-
}
|
|
197
|
-
for (const path in cookbook) {
|
|
198
|
-
const dirnames = path.split("/")
|
|
199
|
-
for (let index = 0; index < dirnames.length - 1; index++) {
|
|
200
|
-
const dirpath = dirnames.slice(0, index + 1).join("/")
|
|
201
|
-
if (!indexes[dirpath]) indexes[dirpath] = []
|
|
202
|
-
if (!folderIndexes[dirpath]) folderIndexes[dirpath] = []
|
|
203
|
-
if (index + 1 === dirnames.length - 1) {
|
|
204
|
-
indexes[dirpath].push(path)
|
|
205
|
-
} else {
|
|
206
|
-
const childDirpath = dirnames.slice(0, index + 2).join("/")
|
|
207
|
-
if (folderIndexes[dirpath].includes(childDirpath)) continue
|
|
208
|
-
folderIndexes[dirpath].push(childDirpath)
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
for (const path in folderIndexes) {
|
|
213
|
-
if (path.includes("/") || path === "(root)") continue
|
|
214
|
-
folderIndexes["(root)"].push(path)
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const readme = (await readFile(join(cwd(), "src", "apps", "README.md"))).toString()
|
|
218
|
-
Object.keys(indexes).forEach((key) => indexes[key].length === 0 && delete indexes[key])
|
|
219
|
-
const generatedAt = new Date()
|
|
220
|
-
|
|
221
|
-
await writeFile(
|
|
222
|
-
join(cwd(), `./generated/cookbook.json`),
|
|
223
|
-
TSON.stringify({
|
|
224
|
-
cookbook,
|
|
225
|
-
readme,
|
|
226
|
-
indexes,
|
|
227
|
-
folderIndexes,
|
|
228
|
-
generatedAt
|
|
229
|
-
})
|
|
230
|
-
)
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
void buildCookbook()
|
package/scripts-del/build-dto.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
import { cwd, platform } from "node:process"
|
|
3
|
-
import { exec as nodeExec } from "node:child_process"
|
|
4
|
-
import { removeDir } from "../utils/remove-dir"
|
|
5
|
-
import { join } from "node:path"
|
|
6
|
-
import { copyFile, mkdir } from "node:fs/promises"
|
|
7
|
-
|
|
8
|
-
export async function buildDTO() {
|
|
9
|
-
console.log("🥛 Milkio DTO Building..")
|
|
10
|
-
|
|
11
|
-
removeDir(join(cwd(), "packages", "dto", "dist"))
|
|
12
|
-
removeDir(join(cwd(), "packages", "dto", "generated"))
|
|
13
|
-
await mkdir(join(cwd(), "packages", "dto", "dist"))
|
|
14
|
-
await mkdir(join(cwd(), "packages", "dto", "generated"))
|
|
15
|
-
|
|
16
|
-
// Generate the corresponding types for the files in the project and output them to the /packages/dto/generate directory.
|
|
17
|
-
await new Promise((resolve) =>
|
|
18
|
-
nodeExec("bun ./node_modules/typescript/bin/tsc --project tsconfig.build-dto.json", (e, stdout) => {
|
|
19
|
-
resolve(e)
|
|
20
|
-
})
|
|
21
|
-
)
|
|
22
|
-
await copyFile(join(cwd(), "src", "fail-code.ts"), join(cwd(), "packages", "dto", "generated", "src", "fail-code.ts"))
|
|
23
|
-
|
|
24
|
-
// Packaging type for the dto
|
|
25
|
-
await new Promise((resolve) =>
|
|
26
|
-
nodeExec("cd ./packages/dto && bunx tsc", (e) => {
|
|
27
|
-
resolve(e)
|
|
28
|
-
})
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
// build /src/dto/index.ts to js
|
|
32
|
-
await Bun.build({
|
|
33
|
-
entrypoints: ["./packages/dto/index.ts"],
|
|
34
|
-
outdir: "./packages/dto"
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
const root = join(cwd(), "packages", "dto")
|
|
38
|
-
|
|
39
|
-
console.log("🥛 Milkio DTO Build Finished")
|
|
40
|
-
console.log("\x1B[2m")
|
|
41
|
-
console.log("Now, your latest code (including changes to your interface) is built to the latest version and waiting for your release!")
|
|
42
|
-
console.log("")
|
|
43
|
-
console.log("If you want to publish it to NPM, you can use a command similar to the following.")
|
|
44
|
-
console.log(`(But before that, you may need to modify the package name (${join(cwd(), "packages", "dto", "package.json")}) and login to your NPM account or private NPM repository)`)
|
|
45
|
-
|
|
46
|
-
if (platform !== "win32") {
|
|
47
|
-
console.log("You can publish it to npm by running this commands:\n")
|
|
48
|
-
console.log("\u001B[0m---")
|
|
49
|
-
console.log(`cd ${join(root)} \\`)
|
|
50
|
-
console.log(" && npm version major \\")
|
|
51
|
-
console.log(" && npm publish --access public \\")
|
|
52
|
-
console.log(` && cd ${join(cwd())}`)
|
|
53
|
-
} else {
|
|
54
|
-
console.log("You can publish it to npm by running this commands (use \x1B[42mPowerShell\x1B[0m):")
|
|
55
|
-
console.log("\u001B[0m---")
|
|
56
|
-
console.log('$ErrorActionPreference = "Stop";')
|
|
57
|
-
console.log(`Set-Location ${join(root)};`)
|
|
58
|
-
console.log("npm version major;")
|
|
59
|
-
console.log("npm publish --access public;")
|
|
60
|
-
console.log(`Set-Location ${join(cwd())};`)
|
|
61
|
-
}
|
|
62
|
-
console.log("---")
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
await buildDTO()
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
|
|
3
|
-
import ejs from "ejs"
|
|
4
|
-
import { join } from "node:path"
|
|
5
|
-
import { existsSync, mkdirSync } from "node:fs"
|
|
6
|
-
import { cwd, env, exit } from "node:process"
|
|
7
|
-
import { writeFile, readFile } from "node:fs/promises"
|
|
8
|
-
import { exec as nodeExec } from "node:child_process"
|
|
9
|
-
import { camel, hump, hyphen } from "@poech/camel-hump-under"
|
|
10
|
-
|
|
11
|
-
const utils = {
|
|
12
|
-
camel: (str: string) => camel(str).replaceAll("-", "").replaceAll("_", ""),
|
|
13
|
-
hump: (str: string) => hump(str).replaceAll("-", "").replaceAll("_", ""),
|
|
14
|
-
hyphen: (str: string) => hyphen(str).replaceAll("_", "")
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export async function generateAppPartial(path?: string) {
|
|
18
|
-
const partialPath = path ?? env.GENERATE_PARTIAL_PATH!
|
|
19
|
-
const partialDir = partialPath.split("/").slice(0, -1).join("/")
|
|
20
|
-
// Generate api-schema.ts file through templates
|
|
21
|
-
const templateVars = {
|
|
22
|
-
utils
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (!partialPath.endsWith(".ts")) return
|
|
26
|
-
const module = await import(/* @vite-ignore */ `../../../../src/apps/${partialPath}`)
|
|
27
|
-
if (module?.api?.isApi === true) {
|
|
28
|
-
// Exclude disallowed characters
|
|
29
|
-
if (partialPath.includes("_")) {
|
|
30
|
-
console.error(`\n\nPath: ` + partialPath)
|
|
31
|
-
console.error(`Do not use "_" in the path. If you want to add a separator between words, please use "-".\n`)
|
|
32
|
-
exit(1)
|
|
33
|
-
}
|
|
34
|
-
if (/^[a-z0-9/-]+$/.test(partialPath)) {
|
|
35
|
-
console.error(`\n\nPath: ` + partialPath)
|
|
36
|
-
console.error(`The path can only contain lowercase letters, numbers, and "-".\n`)
|
|
37
|
-
exit(1)
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// typia
|
|
42
|
-
const filePathTmp = join(cwd(), "generated", "raw-tmp", "apps", partialPath)
|
|
43
|
-
const dirPathTmp = join(cwd(), "generated", "raw-tmp", "apps", partialPath).split("/").slice(0, -1).join("/")
|
|
44
|
-
const filePath = join(cwd(), "generated", "raw", "apps", partialPath)
|
|
45
|
-
if (!existsSync(dirPathTmp)) {
|
|
46
|
-
mkdirSync(dirPathTmp, { recursive: true })
|
|
47
|
-
}
|
|
48
|
-
let importPath = "../../../"
|
|
49
|
-
|
|
50
|
-
for (let i = 0; i < partialPath.split("/").length - 1; i++) {
|
|
51
|
-
importPath = importPath + "../"
|
|
52
|
-
}
|
|
53
|
-
importPath = importPath + "src/apps"
|
|
54
|
-
const template = `
|
|
55
|
-
import typia from "typia";
|
|
56
|
-
import { _validate, type ExecuteResultSuccess } from "milkio";
|
|
57
|
-
import { type TSONEncode } from "@southern-aurora/tson";
|
|
58
|
-
import type * as <%= utils.camel(path.slice(0, -3).replaceAll('/', '$')) %> from '${importPath}/<%= path.slice(0, -3) %>';
|
|
59
|
-
|
|
60
|
-
type ParamsT = Parameters<typeof <%= utils.camel(path.replaceAll('/', '$').slice(0, -${3})) %>['api']['action']>[0];
|
|
61
|
-
export const params = async (params: any) => typia.misc.validatePrune<ParamsT>(params);
|
|
62
|
-
type ResultsT = Awaited<ReturnType<typeof <%= utils.camel(path.replaceAll('/', '$').slice(0, -${3})) %>['api']['action']>>;
|
|
63
|
-
export const results = async (results: any) => { _validate(typia.validate<TSONEncode<ExecuteResultSuccess<ResultsT>>>(results)); return typia.json.stringify<TSONEncode<ExecuteResultSuccess<ResultsT>>>(results); };
|
|
64
|
-
`.trim()
|
|
65
|
-
|
|
66
|
-
await writeFile(filePathTmp, ejs.render(template, { ...templateVars, path: partialPath }))
|
|
67
|
-
|
|
68
|
-
await new Promise((resolve) =>
|
|
69
|
-
nodeExec(`bun run ./node_modules/typia/lib/executable/typia.js generate --input generate/raw-tmp/apps/${partialDir} --output generate/products-tmp/apps/${partialDir} --project tsconfig.json`, (e) => {
|
|
70
|
-
resolve(e)
|
|
71
|
-
})
|
|
72
|
-
)
|
|
73
|
-
await Promise.all([writeFile(filePath, ejs.render(template, { ...templateVars, path: partialPath })), writeFile(join(cwd(), "generated", "products", "apps", partialPath), (await readFile(join(cwd(), "generated", "products-tmp", "apps", partialPath))).toString())])
|
|
74
|
-
}
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
|
|
3
|
-
import ejs from "ejs"
|
|
4
|
-
import { join } from "node:path"
|
|
5
|
-
import { existsSync, mkdirSync } from "node:fs"
|
|
6
|
-
import { cwd, exit } from "node:process"
|
|
7
|
-
import { unlink, writeFile } from "node:fs/promises"
|
|
8
|
-
import { exec as nodeExec } from "node:child_process"
|
|
9
|
-
import { camel, hyphen } from "@poech/camel-hump-under"
|
|
10
|
-
import { Glob } from "bun"
|
|
11
|
-
|
|
12
|
-
const utils = {
|
|
13
|
-
camel: (str: string) => camel(str).replaceAll("-", "").replaceAll("_", ""),
|
|
14
|
-
hyphen: (str: string) => hyphen(str).replaceAll("_", "")
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export async function generateApp() {
|
|
18
|
-
// Delete the files generated in the past and regenerate them
|
|
19
|
-
try {
|
|
20
|
-
await unlink(join(cwd(), "generated", "api-schema.ts"))
|
|
21
|
-
} catch (error) {} // Maybe the file does not exist
|
|
22
|
-
|
|
23
|
-
if (!existsSync(join("generated", "README.md"))) {
|
|
24
|
-
await writeFile(join("generated", "README.md"), "⚠️ All files in this directory are generated by milkio. Please do not modify the content, otherwise your modifications will be overwritten in the next generation.")
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Write a basic framework to ensure that there are no errors when reading later
|
|
28
|
-
const apiSchemaSkeleton = `
|
|
29
|
-
export default {
|
|
30
|
-
apiValidator: {},
|
|
31
|
-
apiMethodsSchema: {},
|
|
32
|
-
apiMethodsTypeSchema: {},
|
|
33
|
-
}
|
|
34
|
-
`
|
|
35
|
-
await writeFile(join(cwd(), "generated", "api-schema.ts"), ejs.render(apiSchemaSkeleton, { utils }))
|
|
36
|
-
|
|
37
|
-
// Generate api-schema.ts file through templates
|
|
38
|
-
const templateVars = {
|
|
39
|
-
utils,
|
|
40
|
-
apiPaths: [] as Array<string>,
|
|
41
|
-
apiTestPaths: [] as Array<string>
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const glob = new Glob("**/*.ts")
|
|
45
|
-
const appFiles = await Array.fromAsync(glob.scan({ cwd: join(cwd(), "src", "apps") }))
|
|
46
|
-
|
|
47
|
-
for (const path of appFiles) {
|
|
48
|
-
if (!path.endsWith(".ts")) continue
|
|
49
|
-
const module = await import(/* @vite-ignore */ `../../../../src/apps/${path}`)
|
|
50
|
-
if (module?.api?.isApi === true) {
|
|
51
|
-
// Exclude disallowed characters
|
|
52
|
-
if (path.includes("_")) {
|
|
53
|
-
console.error(`\n\nPath: ` + `"${path}"`)
|
|
54
|
-
console.error(`Do not use "_" in the path. If you want to add a separator between words, please use "-".\n`)
|
|
55
|
-
exit(1)
|
|
56
|
-
}
|
|
57
|
-
if (!/^[a-z0-9/-]+$/.test(path.slice(0, -3))) {
|
|
58
|
-
console.error(`\n\nPath: ` + `"${path}"`)
|
|
59
|
-
console.error(`The path can only contain lowercase letters, numbers, and "-".\n`)
|
|
60
|
-
exit(1)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
templateVars.apiPaths.push(path)
|
|
64
|
-
|
|
65
|
-
if (module?.test?.isApiTest === true) {
|
|
66
|
-
templateVars.apiTestPaths.push(path)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// typia
|
|
70
|
-
const filePath = join(cwd(), "generated", "raw", "apps", path)
|
|
71
|
-
const dirPath = join(cwd(), "generated", "raw", "apps", path).split("/").slice(0, -1).join("/")
|
|
72
|
-
if (!existsSync(dirPath)) {
|
|
73
|
-
mkdirSync(dirPath, { recursive: true })
|
|
74
|
-
}
|
|
75
|
-
let importPath = "../../../"
|
|
76
|
-
|
|
77
|
-
for (let i = 0; i < path.split("/").length - 1; i++) {
|
|
78
|
-
importPath = importPath + "../"
|
|
79
|
-
}
|
|
80
|
-
importPath = importPath + "src/apps"
|
|
81
|
-
const template = `
|
|
82
|
-
import typia from "typia";
|
|
83
|
-
import { _validate, type ExecuteResultSuccess } from "milkio";
|
|
84
|
-
import { type TSONEncode } from "@southern-aurora/tson";
|
|
85
|
-
import type * as <%= utils.camel(path.slice(0, -3).replaceAll('/', '$')) %> from '${importPath}/<%= path.slice(0, -3) %>';
|
|
86
|
-
|
|
87
|
-
type ParamsT = Parameters<typeof <%= utils.camel(path.replaceAll('/', '$').slice(0, -${3})) %>['api']['action']>[0];
|
|
88
|
-
export const params = async (params: any) => typia.misc.validatePrune<ParamsT>(params);
|
|
89
|
-
type ResultsT = Awaited<ReturnType<typeof <%= utils.camel(path.replaceAll('/', '$').slice(0, -${3})) %>['api']['action']>>;
|
|
90
|
-
export const results = async (results: any) => { _validate(typia.validate<TSONEncode<ExecuteResultSuccess<ResultsT>>>(results)); return typia.json.stringify<TSONEncode<ExecuteResultSuccess<ResultsT>>>(results); };
|
|
91
|
-
|
|
92
|
-
`.trim()
|
|
93
|
-
// export const paramsSchema = typia.json.application<[{ data: ParamsT }], "swagger">();
|
|
94
|
-
|
|
95
|
-
await writeFile(filePath, ejs.render(template, { ...templateVars, path }))
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
await writeFile(
|
|
100
|
-
join(cwd(), "generated", "api-schema.ts"),
|
|
101
|
-
ejs.render(
|
|
102
|
-
`
|
|
103
|
-
/**
|
|
104
|
-
* ⚠️ This file is generated and modifications will be overwritten
|
|
105
|
-
*/
|
|
106
|
-
|
|
107
|
-
// api
|
|
108
|
-
<% for (const path of ${"apiPaths"}) { %>import type * as <%= utils.camel(path.slice(0, -3).replaceAll('/', '$')) %> from '${"../src/apps"}/<%= path.slice(0, -3) %>'
|
|
109
|
-
<% } %>
|
|
110
|
-
import _apiValidator from './products/api-validator.ts'
|
|
111
|
-
|
|
112
|
-
export default {
|
|
113
|
-
apiValidator: _apiValidator,
|
|
114
|
-
${"apiMethodsSchema"}: {
|
|
115
|
-
<% for (const path of apiPaths) { %>'<%= utils.hyphen(path.slice(0, -${3})) %>': () => ({ module: import('../src/apps/<%= path.slice(0, -${3}) %>') }),
|
|
116
|
-
<% } %>
|
|
117
|
-
},
|
|
118
|
-
${"apiMethodsTypeSchema"}: {
|
|
119
|
-
<% for (const path of apiPaths) { %>'<%= utils.hyphen(path.slice(0, -${3})) %>': undefined as unknown as typeof <%= utils.camel(path.slice(0, -${3}).replaceAll('/', '$')) %>,
|
|
120
|
-
<% } %>
|
|
121
|
-
},
|
|
122
|
-
${"apiTestsSchema"}: {
|
|
123
|
-
<% for (const path of apiTestPaths) { %>'<%= utils.hyphen(path.slice(0, -${3})) %>': () => ({ module: import('../src/apps/<%= path.slice(0, -${3}) %>') }),
|
|
124
|
-
<% } %>
|
|
125
|
-
},
|
|
126
|
-
}
|
|
127
|
-
`.trim(),
|
|
128
|
-
templateVars
|
|
129
|
-
)
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
// api
|
|
133
|
-
const apiValidatorTemplate = `/**
|
|
134
|
-
* ⚠️This file is generated and modifications will be overwritten
|
|
135
|
-
*/
|
|
136
|
-
|
|
137
|
-
export default {
|
|
138
|
-
generatedAt: ${new Date().getTime()},
|
|
139
|
-
${"validate"}: {
|
|
140
|
-
<% for (const path of apiPaths) { %>'<%= utils.hyphen(path.slice(0, -${3})) %>': () => import('./apps/<%= utils.hyphen(path) %>'),
|
|
141
|
-
<% } %>
|
|
142
|
-
},
|
|
143
|
-
}
|
|
144
|
-
`.trim()
|
|
145
|
-
await writeFile(join(cwd(), "generated", "raw", "api-validator.ts"), ejs.render(apiValidatorTemplate, templateVars))
|
|
146
|
-
|
|
147
|
-
await new Promise((resolve) =>
|
|
148
|
-
nodeExec("bun run ./node_modules/typia/lib/executable/typia.js generate --input generate/raw --output generate/products --project tsconfig.json", (e) => {
|
|
149
|
-
resolve(e)
|
|
150
|
-
})
|
|
151
|
-
)
|
|
152
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
|
|
3
|
-
import ejs from "ejs"
|
|
4
|
-
import { join } from "node:path"
|
|
5
|
-
import { existsSync } from "node:fs"
|
|
6
|
-
import { cwd } from "node:process"
|
|
7
|
-
import { writeFile } from "node:fs/promises"
|
|
8
|
-
import { Glob } from "bun"
|
|
9
|
-
|
|
10
|
-
export async function generateDatabase() {
|
|
11
|
-
if (existsSync(join(cwd(), "src", "databases"))) {
|
|
12
|
-
if (!existsSync(join("generated", "database-schema.ts"))) {
|
|
13
|
-
await writeFile(join("generated", "database-schema.ts"), ``)
|
|
14
|
-
}
|
|
15
|
-
const filePath = join(cwd(), "generated", "database-schema.ts")
|
|
16
|
-
const glob = new Glob("**/*.ts")
|
|
17
|
-
const databaseFiles = await Array.fromAsync(glob.scan({ cwd: join(cwd(), "src", "databases") }))
|
|
18
|
-
const template = `<% for (const path of ${"databaseFiles"}) { %>export * from '${"../src/databases"}/<%= path.slice(0, -3) %>'
|
|
19
|
-
<% } %>`
|
|
20
|
-
await writeFile(filePath, ejs.render(template, { databaseFiles }))
|
|
21
|
-
}
|
|
22
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument */
|
|
2
|
-
|
|
3
|
-
import { exit } from "node:process"
|
|
4
|
-
import { generateApp } from "./generated/generate-app"
|
|
5
|
-
console.log("Milkio Quick Generating..")
|
|
6
|
-
|
|
7
|
-
export async function generatePartial() {
|
|
8
|
-
await generateApp()
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
await generatePartial()
|
|
12
|
-
|
|
13
|
-
console.log("\n✅ Milkio Generated!")
|
|
14
|
-
|
|
15
|
-
exit(0)
|
package/scripts-del/generate.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
|
|
3
|
-
import { join } from "node:path"
|
|
4
|
-
import { existsSync, mkdirSync } from "node:fs"
|
|
5
|
-
import { exit } from "node:process"
|
|
6
|
-
import { generateApp } from "./generated/generate-app"
|
|
7
|
-
|
|
8
|
-
export async function generate() {
|
|
9
|
-
// Make sure that the existing directories are all present
|
|
10
|
-
existsSync(join("generated")) || mkdirSync(join("generated"))
|
|
11
|
-
existsSync(join("generated", "raw")) || mkdirSync(join("generated", "raw"))
|
|
12
|
-
existsSync(join("generated", "raw", "apps")) || mkdirSync(join("generated", "raw", "apps"))
|
|
13
|
-
|
|
14
|
-
await generateApp()
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
console.log("Milkio Generating..")
|
|
18
|
-
|
|
19
|
-
await generate()
|
|
20
|
-
|
|
21
|
-
console.log("\n✅ Milkio Generated!")
|
|
22
|
-
|
|
23
|
-
exit(0)
|