milkio 0.0.10 → 0.0.12
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/.co.toml +0 -0
- package/api-test/index.ts +64 -0
- package/c.ts +39 -57
- package/defines/define-api-test.ts +3 -3
- package/defines/define-api.ts +3 -3
- package/defines/define-http-handler.ts +60 -69
- package/defines/define-middleware.ts +2 -2
- package/defines/define-use.ts +6 -6
- package/index.ts +23 -22
- package/kernel/context.ts +1 -2
- package/kernel/fail.ts +6 -6
- package/kernel/logger.ts +38 -38
- package/kernel/meta.ts +5 -5
- package/kernel/middleware.ts +16 -16
- package/kernel/milkio.ts +70 -95
- package/kernel/runtime.ts +2 -7
- package/kernel/validate.ts +5 -5
- package/package.json +4 -1
- package/scripts/gen-insignificant.ts +261 -0
- package/scripts/gen-significant.ts +176 -0
- package/{scripts → scripts-del}/build-cookbook.ts +119 -119
- package/scripts-del/build-dto.ts +65 -0
- package/{scripts → scripts-del}/generate/generate-app-partial.ts +31 -31
- package/{scripts → scripts-del}/generate/generate-app.ts +41 -41
- package/scripts-del/generate/generate-database.ts +22 -0
- package/scripts-del/generate-partial.ts +15 -0
- package/scripts-del/generate.ts +23 -0
- package/templates/api.ts +4 -4
- package/types.ts +29 -19
- package/utils/create-template.ts +5 -5
- package/utils/create-ulid.ts +3 -3
- package/utils/env-to-boolean.ts +5 -5
- package/utils/env-to-number.ts +2 -2
- package/utils/env-to-string.ts +2 -2
- package/utils/exec.ts +12 -12
- package/utils/handle-catch-error.ts +10 -10
- package/utils/remove-dir.ts +11 -11
- package/utils/tson.ts +2 -2
- package/defines/define-api-test-handler.ts +0 -71
- package/kernel/config.ts +0 -14
- package/scripts/build-dto.ts +0 -65
- package/scripts/generate/generate-database.ts +0 -22
- package/scripts/generate-database.ts +0 -23
- package/scripts/generate-partial.ts +0 -15
- package/scripts/generate.ts +0 -23
|
@@ -1,116 +1,116 @@
|
|
|
1
1
|
/* eslint-disable no-console, @typescript-eslint/no-dynamic-delete */
|
|
2
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"
|
|
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
7
|
|
|
8
8
|
export async function buildCookbook() {
|
|
9
|
-
const schema = await import("../../../
|
|
10
|
-
const paths = Object.keys(schema.default.apiMethodsSchema)
|
|
9
|
+
const schema = await import("../../../generated/api-schema")
|
|
10
|
+
const paths = Object.keys(schema.default.apiMethodsSchema)
|
|
11
11
|
|
|
12
|
-
const cookbook: Cookbook = {}
|
|
12
|
+
const cookbook: Cookbook = {}
|
|
13
13
|
for (const path of paths) {
|
|
14
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] ?? ""
|
|
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
20
|
|
|
21
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
|
|
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
26
|
for (let index = 0; index < descRawLines.length; index++) {
|
|
27
|
-
const descRawLine = descRawLines[index].replace(/^[/ ]+?[*]*/, "").replace(/[*]*\/$/, "")
|
|
27
|
+
const descRawLine = descRawLines[index].replace(/^[/ ]+?[*]*/, "").replace(/[*]*\/$/, "")
|
|
28
28
|
|
|
29
|
-
if (!descRawLine) continue
|
|
29
|
+
if (!descRawLine) continue
|
|
30
30
|
if (first) {
|
|
31
|
-
title = descRawLine.replace(/#/g, "").trim()
|
|
31
|
+
title = descRawLine.replace(/#/g, "").trim()
|
|
32
32
|
// Originally the title was in the first line, desc is the rest of it, now desc contains complete markdown content.
|
|
33
33
|
// continue;
|
|
34
34
|
}
|
|
35
|
-
first = false
|
|
36
|
-
desc = (desc ?? "") + "\n" + descRawLine.trim()
|
|
35
|
+
first = false
|
|
36
|
+
desc = (desc ?? "") + "\n" + descRawLine.trim()
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
let apiParams = /action\([\s\S]+?\)/.exec(code)?.[0] ?? ""
|
|
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")
|
|
45
|
-
if (apiParamsLines.at(-1)?.trim() === "") apiParamsLines.pop()
|
|
46
|
-
if (apiParamsLines.at(-1)?.trim() === "") apiParamsLines.pop()
|
|
47
|
-
let spaceNumber = 0
|
|
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
48
|
for (const char of apiParamsLines.at(-1) ?? "") {
|
|
49
|
-
if (char === " ") spaceNumber
|
|
50
|
-
else break
|
|
49
|
+
if (char === " ") spaceNumber++
|
|
50
|
+
else break
|
|
51
51
|
}
|
|
52
52
|
for (let index = 0; index < apiParamsLines.length; index++) {
|
|
53
|
-
const line = apiParamsLines[index]
|
|
54
|
-
let spaceNumberForThisLine = 0
|
|
53
|
+
const line = apiParamsLines[index]
|
|
54
|
+
let spaceNumberForThisLine = 0
|
|
55
55
|
for (const char of line) {
|
|
56
|
-
if (char === " ") spaceNumberForThisLine
|
|
57
|
-
else break
|
|
56
|
+
if (char === " ") spaceNumberForThisLine++
|
|
57
|
+
else break
|
|
58
58
|
}
|
|
59
59
|
if (spaceNumberForThisLine >= spaceNumber) {
|
|
60
|
-
apiParamsLines[index] = line.slice(spaceNumber)
|
|
60
|
+
apiParamsLines[index] = line.slice(spaceNumber)
|
|
61
61
|
} else {
|
|
62
|
-
apiParamsLines[index] = line.slice(spaceNumberForThisLine)
|
|
62
|
+
apiParamsLines[index] = line.slice(spaceNumberForThisLine)
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
apiParams = apiParamsLines.join("\n")
|
|
65
|
+
apiParams = apiParamsLines.join("\n")
|
|
66
66
|
|
|
67
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
|
|
68
|
+
const apiTestsCodeChars = []
|
|
69
|
+
let apiTestsStartIndex = undefined as undefined | number
|
|
70
|
+
let semicolonMatch = 0
|
|
71
|
+
let semicolonMax = 0
|
|
72
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("")
|
|
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
77
|
for (const codeChar of codeChars) {
|
|
78
78
|
if (codeChar === "[") {
|
|
79
|
-
semicolonMatch
|
|
80
|
-
semicolonMax
|
|
79
|
+
semicolonMatch++
|
|
80
|
+
semicolonMax++
|
|
81
81
|
}
|
|
82
|
-
if (semicolonMatch !== 0) apiTestsCodeChars.push(codeChar)
|
|
83
|
-
if (codeChar === "]") semicolonMatch
|
|
82
|
+
if (semicolonMatch !== 0) apiTestsCodeChars.push(codeChar)
|
|
83
|
+
if (codeChar === "]") semicolonMatch--
|
|
84
84
|
}
|
|
85
85
|
if (semicolonMatch === 0 && semicolonMax >= 1) {
|
|
86
|
-
break
|
|
86
|
+
break
|
|
87
87
|
}
|
|
88
|
-
apiTestsCodeChars.push("\n")
|
|
88
|
+
apiTestsCodeChars.push("\n")
|
|
89
89
|
}
|
|
90
90
|
|
|
91
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
|
|
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
96
|
for (let index = 0; index < apiTestsCodeChars.length; index++) {
|
|
97
|
-
const apiTestsCodeChar = apiTestsCodeChars[index]
|
|
97
|
+
const apiTestsCodeChar = apiTestsCodeChars[index]
|
|
98
98
|
if (apiTestCaseStartIndex === undefined && apiTestsCodeChar === "{") {
|
|
99
|
-
currentApiCaseCode = []
|
|
100
|
-
apiTestCaseStartIndex = index
|
|
99
|
+
currentApiCaseCode = []
|
|
100
|
+
apiTestCaseStartIndex = index
|
|
101
101
|
}
|
|
102
102
|
if (apiTestsCodeChar === "{") {
|
|
103
|
-
apiTestCaseMatch
|
|
103
|
+
apiTestCaseMatch++
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
if (apiTestCaseMatch !== 0) currentApiCaseCode!.push(apiTestsCodeChar)
|
|
106
|
+
if (apiTestCaseMatch !== 0) currentApiCaseCode!.push(apiTestsCodeChar)
|
|
107
107
|
|
|
108
108
|
if (apiTestsCodeChar === "}") {
|
|
109
|
-
apiTestCaseMatch
|
|
109
|
+
apiTestCaseMatch--
|
|
110
110
|
if (apiTestCaseMatch === 0) {
|
|
111
|
-
apiCaseCodes.push(currentApiCaseCode!.join(""))
|
|
112
|
-
currentApiCaseCode = undefined
|
|
113
|
-
apiTestCaseStartIndex = undefined
|
|
111
|
+
apiCaseCodes.push(currentApiCaseCode!.join(""))
|
|
112
|
+
currentApiCaseCode = undefined
|
|
113
|
+
apiTestCaseStartIndex = undefined
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
}
|
|
@@ -118,60 +118,60 @@ export async function buildCookbook() {
|
|
|
118
118
|
const apiCases: Array<{
|
|
119
119
|
name: string;
|
|
120
120
|
handler: string;
|
|
121
|
-
}> = []
|
|
121
|
+
}> = []
|
|
122
122
|
|
|
123
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 = ""
|
|
128
|
-
let handlerStartIndex = undefined as undefined | number
|
|
129
|
-
let handlerMatch = 0
|
|
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
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
|
|
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
137
|
}
|
|
138
|
-
handler = handler.slice(1, -1)
|
|
139
|
-
|
|
140
|
-
const handlerLines = handler.split("\n")
|
|
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
|
|
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
146
|
for (const char of handlerLines.at(-1) ?? "") {
|
|
147
|
-
if (char === " ") spaceNumber
|
|
148
|
-
else break
|
|
147
|
+
if (char === " ") spaceNumber++
|
|
148
|
+
else break
|
|
149
149
|
}
|
|
150
150
|
for (let index = 0; index < handlerLines.length; index++) {
|
|
151
|
-
const line = handlerLines[index]
|
|
152
|
-
let spaceNumberForThisLine = 0
|
|
151
|
+
const line = handlerLines[index]
|
|
152
|
+
let spaceNumberForThisLine = 0
|
|
153
153
|
for (const char of line) {
|
|
154
|
-
if (char === " ") spaceNumberForThisLine
|
|
155
|
-
else break
|
|
154
|
+
if (char === " ") spaceNumberForThisLine++
|
|
155
|
+
else break
|
|
156
156
|
}
|
|
157
157
|
if (spaceNumberForThisLine >= spaceNumber) {
|
|
158
|
-
handlerLines[index] = line.slice(spaceNumber)
|
|
158
|
+
handlerLines[index] = line.slice(spaceNumber)
|
|
159
159
|
} else {
|
|
160
|
-
handlerLines[index] = line.slice(spaceNumberForThisLine)
|
|
160
|
+
handlerLines[index] = line.slice(spaceNumberForThisLine)
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
|
-
handler = handlerLines.join("\n")
|
|
163
|
+
handler = handlerLines.join("\n")
|
|
164
164
|
|
|
165
165
|
apiCases.push({
|
|
166
166
|
name,
|
|
167
167
|
handler
|
|
168
|
-
})
|
|
168
|
+
})
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
// This value has been deprecated because TypeScript types can already replace it well
|
|
172
172
|
// let paramsSchema;
|
|
173
173
|
// try {
|
|
174
|
-
// const moduleGenerated = await import(/* @vite-ignore */ `../../../
|
|
174
|
+
// const moduleGenerated = await import(/* @vite-ignore */ `../../../generated/products/apps/${path}`);
|
|
175
175
|
// paramsSchema = moduleGenerated.paramsSchema.schemas[0]?.properties?.data;
|
|
176
176
|
// } catch (error) {}
|
|
177
177
|
|
|
@@ -180,46 +180,46 @@ export async function buildCookbook() {
|
|
|
180
180
|
desc,
|
|
181
181
|
params: apiParams,
|
|
182
182
|
cases: apiCases
|
|
183
|
-
}
|
|
183
|
+
}
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
/**
|
|
187
187
|
* -- indexes
|
|
188
188
|
*/
|
|
189
189
|
|
|
190
|
-
const indexes: Record<string, Array<string>> = {}
|
|
191
|
-
const folderIndexes: Record<string, Array<string>> = {}
|
|
192
|
-
indexes["(root)"] = []
|
|
193
|
-
folderIndexes["(root)"] = []
|
|
190
|
+
const indexes: Record<string, Array<string>> = {}
|
|
191
|
+
const folderIndexes: Record<string, Array<string>> = {}
|
|
192
|
+
indexes["(root)"] = []
|
|
193
|
+
folderIndexes["(root)"] = []
|
|
194
194
|
for (const path in cookbook) {
|
|
195
|
-
if (!path.includes("/")) indexes["(root)"].push(path)
|
|
195
|
+
if (!path.includes("/")) indexes["(root)"].push(path)
|
|
196
196
|
}
|
|
197
197
|
for (const path in cookbook) {
|
|
198
|
-
const dirnames = path.split("/")
|
|
198
|
+
const dirnames = path.split("/")
|
|
199
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] = []
|
|
200
|
+
const dirpath = dirnames.slice(0, index + 1).join("/")
|
|
201
|
+
if (!indexes[dirpath]) indexes[dirpath] = []
|
|
202
|
+
if (!folderIndexes[dirpath]) folderIndexes[dirpath] = []
|
|
203
203
|
if (index + 1 === dirnames.length - 1) {
|
|
204
|
-
indexes[dirpath].push(path)
|
|
204
|
+
indexes[dirpath].push(path)
|
|
205
205
|
} else {
|
|
206
|
-
const childDirpath = dirnames.slice(0, index + 2).join("/")
|
|
207
|
-
if (folderIndexes[dirpath].includes(childDirpath)) continue
|
|
208
|
-
folderIndexes[dirpath].push(childDirpath)
|
|
206
|
+
const childDirpath = dirnames.slice(0, index + 2).join("/")
|
|
207
|
+
if (folderIndexes[dirpath].includes(childDirpath)) continue
|
|
208
|
+
folderIndexes[dirpath].push(childDirpath)
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
for (const path in folderIndexes) {
|
|
213
|
-
if (path.includes("/") || path === "(root)") continue
|
|
214
|
-
folderIndexes["(root)"].push(path)
|
|
213
|
+
if (path.includes("/") || path === "(root)") continue
|
|
214
|
+
folderIndexes["(root)"].push(path)
|
|
215
215
|
}
|
|
216
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()
|
|
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
220
|
|
|
221
221
|
await writeFile(
|
|
222
|
-
join(cwd(), `./
|
|
222
|
+
join(cwd(), `./generated/cookbook.json`),
|
|
223
223
|
TSON.stringify({
|
|
224
224
|
cookbook,
|
|
225
225
|
readme,
|
|
@@ -227,7 +227,7 @@ export async function buildCookbook() {
|
|
|
227
227
|
folderIndexes,
|
|
228
228
|
generatedAt
|
|
229
229
|
})
|
|
230
|
-
)
|
|
230
|
+
)
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
-
void buildCookbook()
|
|
233
|
+
void buildCookbook()
|
|
@@ -0,0 +1,65 @@
|
|
|
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,56 +1,56 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
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"
|
|
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
10
|
|
|
11
11
|
const utils = {
|
|
12
12
|
camel: (str: string) => camel(str).replaceAll("-", "").replaceAll("_", ""),
|
|
13
13
|
hump: (str: string) => hump(str).replaceAll("-", "").replaceAll("_", ""),
|
|
14
14
|
hyphen: (str: string) => hyphen(str).replaceAll("_", "")
|
|
15
|
-
}
|
|
15
|
+
}
|
|
16
16
|
|
|
17
17
|
export async function generateAppPartial(path?: string) {
|
|
18
|
-
const partialPath = path ?? env.GENERATE_PARTIAL_PATH
|
|
19
|
-
const partialDir = partialPath.split("/").slice(0, -1).join("/")
|
|
18
|
+
const partialPath = path ?? env.GENERATE_PARTIAL_PATH!
|
|
19
|
+
const partialDir = partialPath.split("/").slice(0, -1).join("/")
|
|
20
20
|
// Generate api-schema.ts file through templates
|
|
21
21
|
const templateVars = {
|
|
22
22
|
utils
|
|
23
|
-
}
|
|
23
|
+
}
|
|
24
24
|
|
|
25
|
-
if (!partialPath.endsWith(".ts")) return
|
|
26
|
-
const module = await import(/* @vite-ignore */ `../../../../src/apps/${partialPath}`)
|
|
25
|
+
if (!partialPath.endsWith(".ts")) return
|
|
26
|
+
const module = await import(/* @vite-ignore */ `../../../../src/apps/${partialPath}`)
|
|
27
27
|
if (module?.api?.isApi === true) {
|
|
28
28
|
// Exclude disallowed characters
|
|
29
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)
|
|
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
33
|
}
|
|
34
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)
|
|
35
|
+
console.error(`\n\nPath: ` + partialPath)
|
|
36
|
+
console.error(`The path can only contain lowercase letters, numbers, and "-".\n`)
|
|
37
|
+
exit(1)
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// typia
|
|
42
|
-
const filePathTmp = join(cwd(), "
|
|
43
|
-
const dirPathTmp = join(cwd(), "
|
|
44
|
-
const filePath = join(cwd(), "
|
|
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
45
|
if (!existsSync(dirPathTmp)) {
|
|
46
|
-
mkdirSync(dirPathTmp, { recursive: true })
|
|
46
|
+
mkdirSync(dirPathTmp, { recursive: true })
|
|
47
47
|
}
|
|
48
|
-
let importPath = "../../../"
|
|
48
|
+
let importPath = "../../../"
|
|
49
49
|
|
|
50
50
|
for (let i = 0; i < partialPath.split("/").length - 1; i++) {
|
|
51
|
-
importPath = importPath + "../"
|
|
51
|
+
importPath = importPath + "../"
|
|
52
52
|
}
|
|
53
|
-
importPath = importPath + "src/apps"
|
|
53
|
+
importPath = importPath + "src/apps"
|
|
54
54
|
const template = `
|
|
55
55
|
import typia from "typia";
|
|
56
56
|
import { _validate, type ExecuteResultSuccess } from "milkio";
|
|
@@ -61,14 +61,14 @@ type ParamsT = Parameters<typeof <%= utils.camel(path.replaceAll('/', '$').slice
|
|
|
61
61
|
export const params = async (params: any) => typia.misc.validatePrune<ParamsT>(params);
|
|
62
62
|
type ResultsT = Awaited<ReturnType<typeof <%= utils.camel(path.replaceAll('/', '$').slice(0, -${3})) %>['api']['action']>>;
|
|
63
63
|
export const results = async (results: any) => { _validate(typia.validate<TSONEncode<ExecuteResultSuccess<ResultsT>>>(results)); return typia.json.stringify<TSONEncode<ExecuteResultSuccess<ResultsT>>>(results); };
|
|
64
|
-
`.trim()
|
|
64
|
+
`.trim()
|
|
65
65
|
|
|
66
|
-
await writeFile(filePathTmp, ejs.render(template, { ...templateVars, path: partialPath }))
|
|
66
|
+
await writeFile(filePathTmp, ejs.render(template, { ...templateVars, path: partialPath }))
|
|
67
67
|
|
|
68
68
|
await new Promise((resolve) =>
|
|
69
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)
|
|
70
|
+
resolve(e)
|
|
71
71
|
})
|
|
72
|
-
)
|
|
73
|
-
await Promise.all([writeFile(filePath, ejs.render(template, { ...templateVars, path: partialPath })), writeFile(join(cwd(), "
|
|
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
74
|
}
|