milkio 0.8.2 → 1.0.0-alpha.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.
Files changed (47) hide show
  1. package/action/index.ts +19 -0
  2. package/command/index.ts +53 -0
  3. package/context/index.ts +18 -0
  4. package/exception/index.ts +45 -0
  5. package/execute/execute-id-generator.ts +7 -0
  6. package/execute/index.ts +160 -0
  7. package/index.ts +11 -36
  8. package/listener/index.ts +199 -0
  9. package/logger/index.ts +67 -0
  10. package/meta/index.ts +12 -0
  11. package/middleware/index.ts +19 -0
  12. package/package.json +9 -13
  13. package/stream/index.ts +19 -0
  14. package/test/index.ts +21 -0
  15. package/types/index.ts +74 -0
  16. package/utils/create-id.ts +3 -0
  17. package/world/index.ts +65 -0
  18. package/api-test/index.ts +0 -122
  19. package/c.ts +0 -50
  20. package/defines/define-api-test.ts +0 -69
  21. package/defines/define-api.ts +0 -11
  22. package/defines/define-command-handler.ts +0 -47
  23. package/defines/define-config.ts +0 -32
  24. package/defines/define-http-handler.ts +0 -291
  25. package/defines/define-middleware.ts +0 -9
  26. package/defines/define-use.ts +0 -12
  27. package/kernel/context.ts +0 -55
  28. package/kernel/execute.ts +0 -194
  29. package/kernel/fail.ts +0 -20
  30. package/kernel/logger.ts +0 -131
  31. package/kernel/meta.ts +0 -9
  32. package/kernel/middleware.ts +0 -51
  33. package/kernel/milkio.ts +0 -87
  34. package/kernel/runtime.ts +0 -11
  35. package/kernel/validate.ts +0 -16
  36. package/scripts/gen-insignificant.ts +0 -258
  37. package/scripts/gen-significant.ts +0 -186
  38. package/types.ts +0 -101
  39. package/utils/create-ulid.ts +0 -5
  40. package/utils/env-to-boolean.ts +0 -11
  41. package/utils/env-to-number.ts +0 -5
  42. package/utils/env-to-string.ts +0 -5
  43. package/utils/exec.ts +0 -26
  44. package/utils/handle-catch-error.ts +0 -52
  45. package/utils/header-to-plain-object.ts +0 -8
  46. package/utils/remove-dir.ts +0 -22
  47. package/utils/tson.ts +0 -3
package/kernel/logger.ts DELETED
@@ -1,131 +0,0 @@
1
- import { ExecuteResultFail, runtime, type ExecuteId } from "..";
2
- import { loggerOptions, LoggerTags } from "../../../src/logger";
3
-
4
- export type LoggerItem = {
5
- executeId: ExecuteId;
6
- loggerLevel: LoggerLevel;
7
- description: string;
8
- params: Array<unknown>;
9
- };
10
-
11
- export type MilkioLoggerTags = {
12
- executeId: string;
13
- from?: "http-server" | "execute";
14
- method?: "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "OPTIONS" | string;
15
- ip?: string;
16
- path?: string;
17
- status?: number;
18
- url?: string;
19
- params?: any;
20
- body?: string;
21
- fail?: ExecuteResultFail;
22
- timein?: number;
23
- timeout?: number;
24
- result?: unknown;
25
- requestHeaders?: Record<string, string>;
26
- responseHeaders?: Record<string, string>;
27
- };
28
-
29
- export type LoggerOptions = {
30
- onInsert: (options: LoggerItem) => boolean;
31
- onSubmit: (tags: MilkioLoggerTags & LoggerTags, logs: Array<LoggerItem>) => Promise<void> | void;
32
- };
33
-
34
- export type Logger = {
35
- debug: (description: string, ...params: Array<unknown>) => void;
36
- log: (description: string, ...params: Array<unknown>) => void;
37
- info: (description: string, ...params: Array<unknown>) => void;
38
- warn: (description: string, ...params: Array<unknown>) => void;
39
- error: (description: string, ...params: Array<unknown>) => void;
40
- };
41
-
42
- export const loggerController = (() => {
43
- const logs = new Map<ExecuteId, { __LOG_DETAIL__: Array<LoggerItem>; [key: string]: any }>();
44
-
45
- const loggerPushTags = (executeId: ExecuteId, tags: Partial<MilkioLoggerTags & LoggerTags>) => {
46
- if (!logs.has(executeId)) logs.set(executeId, { __LOG_DETAIL__: [] });
47
- const logItem = logs.get(executeId);
48
- for (const key in tags) {
49
- logItem![key] = (tags as any)[key];
50
- }
51
- };
52
-
53
- const loggerSubmit = async (executeId: ExecuteId) => {
54
- if (!logs.has(executeId)) return;
55
- if (executeId === "global") return;
56
- const loggerSubmitOptions: any = {
57
- executeId,
58
- };
59
- const log = logs.get(executeId)!;
60
- for (const key in log) {
61
- if (key === "__LOG_DETAIL__") continue;
62
- loggerSubmitOptions[key] = log[key];
63
- }
64
- logs.delete(executeId);
65
- loggerOptions.onSubmit(loggerSubmitOptions, log.__LOG_DETAIL__);
66
- };
67
-
68
- const loggerSubmitAll = async () => {
69
- for (const executeId of logs.keys()) {
70
- await loggerSubmit(executeId);
71
- }
72
- };
73
-
74
- const insertItem = (executeId: ExecuteId, level: LoggerLevel, description: string, params: Array<unknown>): void => {
75
- let executeIds: Array<string> = [];
76
- if (executeId === "global") {
77
- executeIds = Array.from(new Set([...Array.from(runtime.execute.executeIds), ...Array.from(runtime.execute.executeIds)]));
78
- } else {
79
- executeIds = [executeId];
80
- }
81
-
82
- for (const executeId of executeIds) {
83
- if (!logs.has(executeId as ExecuteId)) logs.set(executeId as ExecuteId, { __LOG_DETAIL__: [] });
84
- const loggerItem = {
85
- executeId: executeId as ExecuteId,
86
- loggerLevel: level,
87
- description,
88
- params,
89
- } satisfies LoggerItem;
90
- if (!loggerOptions.onInsert(loggerItem)) return;
91
- logs.get(executeId as ExecuteId)!.__LOG_DETAIL__.push(loggerItem);
92
- }
93
- };
94
-
95
- const useLogger = (executeId: ExecuteId) => {
96
- return {
97
- debug(description: string, ...params: Array<unknown>) {
98
- insertItem(executeId, "debug", description, params);
99
- },
100
- log(description: string, ...params: Array<unknown>) {
101
- insertItem(executeId, "log", description, params);
102
- },
103
- info(description: string, ...params: Array<unknown>) {
104
- insertItem(executeId, "log", description, params);
105
- },
106
- warn(description: string, ...params: Array<unknown>) {
107
- insertItem(executeId, "warn", description, params);
108
- },
109
- error(description: string, ...params: Array<unknown>) {
110
- insertItem(executeId, "error", description, params);
111
- },
112
- } satisfies Logger;
113
- };
114
-
115
- return {
116
- loggerPushTags,
117
- loggerSubmit,
118
- loggerSubmitAll,
119
- useLogger,
120
- };
121
- })();
122
-
123
- export const useLogger = loggerController.useLogger;
124
-
125
- export const loggerPushTags = loggerController.loggerPushTags;
126
-
127
- export const loggerSubmit = loggerController.loggerSubmit;
128
-
129
- export const loggerSubmitAll = loggerController.loggerSubmitAll;
130
-
131
- export type LoggerLevel = "debug" | "log" | "warn" | "error";
package/kernel/meta.ts DELETED
@@ -1,9 +0,0 @@
1
- import type { Meta } from "../../../src/meta";
2
- import schema from "../../../generated/api-schema";
3
-
4
- export async function useMeta(path: string): Promise<Meta> {
5
- // @ts-ignore
6
- const api = schema.apiMethodsSchema[path as keyof (typeof schema)["apiMethodsTypeSchema"]]();
7
- const module = await api.module;
8
- return module.api.meta;
9
- }
@@ -1,51 +0,0 @@
1
- import type { Context } from "../../../src/context";
2
- import type { FrameworkHttpDetail } from "./context";
3
- import type { MilkioApp } from "milkio";
4
-
5
- export type BootstrapMiddleware = (milkio: MilkioApp) => Promise<void> | void;
6
- export type BeforeExecuteMiddleware = (context: Context) => Promise<void> | void;
7
- export type AfterExecuteMiddleware = (context: Context, response: { value: unknown }) => Promise<void> | void;
8
- export type AfterHttpRequestMiddleware = (headers: Headers, detail: FrameworkHttpDetail) => Promise<void> | void;
9
- export type BeforeHttpResponseMiddleware = (response: { value: string }, detail: FrameworkHttpDetail) => Promise<void> | void;
10
- export type HttpNotFoundMiddleware = (detail: FrameworkHttpDetail) => Promise<void> | void;
11
-
12
- export type MiddlewareOptions = {
13
- bootstrap?: BootstrapMiddleware;
14
- beforeExecute?: BeforeExecuteMiddleware;
15
- afterExecute?: AfterExecuteMiddleware;
16
- afterHttpRequest?: AfterHttpRequestMiddleware;
17
- beforeHttpResponse?: BeforeHttpResponseMiddleware;
18
- httpNotFound?: HttpNotFoundMiddleware;
19
- } & Record<string, (...args: Array<any>) => Promise<void> | void>;
20
- export type MiddlewareFn = (...args: Array<any>) => Promise<void> | void;
21
- export type MiddlewareT<T extends MiddlewareFn = MiddlewareFn> = { id: string; index: number; middleware: T };
22
-
23
- export const _middlewareEvents = new Map<string, (a: MiddlewareT, b: MiddlewareT) => number>();
24
- export const _middlewares = new Map<string, Array<MiddlewareT>>();
25
-
26
- export const MiddlewareEvent = (() => {
27
- const defineMiddlewareEvent = (name: string, sortFn: (a: MiddlewareT, b: MiddlewareT) => number) => {
28
- _middlewareEvents.set(name, sortFn);
29
- };
30
-
31
- const sortMiddlewareEvent = () => {
32
- for (const [key, middleware] of _middlewares) {
33
- const sort = _middlewareEvents.get(key);
34
- if (sort) middleware.sort(sort);
35
- }
36
- };
37
-
38
- const handleMiddleware = async (name: string, args: Array<any> /* Parameters<MiddlewareOptions[Name]> */) => {
39
- const mds = _middlewares.get(name);
40
- if (!mds) return;
41
- for (const md of mds) {
42
- await md.middleware(...args);
43
- }
44
- };
45
-
46
- return {
47
- define: defineMiddlewareEvent,
48
- handle: handleMiddleware,
49
- _sort: sortMiddlewareEvent,
50
- };
51
- })();
package/kernel/milkio.ts DELETED
@@ -1,87 +0,0 @@
1
- import { type MiddlewareOptions, _middlewares, MiddlewareEvent } from "./middleware";
2
- import schema from "../../../generated/api-schema";
3
- import { runtime } from "..";
4
- import { createUlid } from "../utils/create-ulid";
5
- import { _validate } from "./validate";
6
- import { _execute, _call, _executeToJson, _executeStream } from "./execute";
7
-
8
- export type MilkioAppOptions = {
9
- /**
10
- * bootstraps
11
- * @description
12
- * When Milkio is launched, all methods in this array will run **in parallel**.
13
- */
14
- bootstraps?: () => Array<
15
- /* This type is long, and its intention is to prevent someone from forgetting to add parentheses when adding bootstraps. Therefore, it allows all types except methods */ Promise<unknown> | void | string | number | boolean | null | undefined | Record<string | number | symbol, unknown> | Array<unknown>
16
- >;
17
- /**
18
- * middlewares
19
- * @description
20
- * When Milkio is launched, the closer it is to the front of the array, the more it is on the outer layer of the "onion".
21
- */
22
- middlewares?: () => Array<MiddlewareOptions>;
23
- /**
24
- * maxRunningTime (minutes)
25
- * @description
26
- * When the function runs for a long time, it is possible that the memory will continuously expand (not necessarily due to memory leaks, but also possibly due to having a large number of routes).
27
- * Set the maximum running time (in minutes). When milkio's running time reaches this value, terminate the process and automatically restart it from outside (K8S or other means).
28
- */
29
- enableMaxRunningTimeoutLimit?: number | null | undefined;
30
- };
31
-
32
- export async function createMilkioApp(MilkioAppOptions: MilkioAppOptions = {}) {
33
- if (MilkioAppOptions.enableMaxRunningTimeoutLimit && MilkioAppOptions.enableMaxRunningTimeoutLimit >= 1) {
34
- setTimeout(
35
- () => {
36
- throw new Error('Milkio reached the limit of "maxRunningTimeout" in the options and automatically exited.');
37
- },
38
- MilkioAppOptions.enableMaxRunningTimeoutLimit * 60 * 1000,
39
- );
40
- runtime.maxRunningTimeout.enable = true;
41
- }
42
-
43
- const MilkioApp = {
44
- randParams: _randParams,
45
- execute: _execute,
46
- executeToJson: _executeToJson,
47
- executeStream: _executeStream,
48
- _call,
49
- };
50
-
51
- if (MilkioAppOptions.bootstraps) {
52
- await Promise.all(MilkioAppOptions.bootstraps());
53
- }
54
-
55
- if (MilkioAppOptions.middlewares) {
56
- MiddlewareEvent.define("bootstrap", (a, b) => a.index - b.index);
57
- MiddlewareEvent.define("beforeExecute", (a, b) => a.index - b.index);
58
- MiddlewareEvent.define("afterExecute", (a, b) => b.index - a.index);
59
- MiddlewareEvent.define("afterHttpRequest", (a, b) => a.index - b.index);
60
- MiddlewareEvent.define("beforeHttpResponse", (a, b) => b.index - a.index);
61
- MiddlewareEvent.define("httpNotFound", (a, b) => a.index - b.index);
62
-
63
- const middlewares = MilkioAppOptions.middlewares();
64
-
65
- for (let index = 0; index < middlewares.length; index++) {
66
- const middlewareOptions = middlewares[index];
67
- for (const name in middlewareOptions) {
68
- let middleware = _middlewares.get(name);
69
- if (middleware === undefined) {
70
- middleware = [];
71
- _middlewares.set(name, middleware);
72
- }
73
- const id = createUlid();
74
- middleware.push({ id, index, middleware: middlewareOptions[name] });
75
- }
76
- }
77
- MiddlewareEvent._sort();
78
-
79
- await MiddlewareEvent.handle("bootstrap", [MilkioApp]);
80
- }
81
-
82
- return MilkioApp;
83
- }
84
-
85
- export async function _randParams<Path extends keyof (typeof schema)["apiMethodsTypeSchema"]>(path: Path): Promise<Parameters<(typeof schema)["apiMethodsTypeSchema"][Path]["api"]["action"]>[0]> {
86
- return await (await schema.apiValidator.validate[path]()).randParams();
87
- }
package/kernel/runtime.ts DELETED
@@ -1,11 +0,0 @@
1
- import type { ExecuteId } from "..";
2
-
3
- export const runtime = {
4
- execute: {
5
- executeIds: new Set<ExecuteId>(),
6
- },
7
- maxRunningTimeout: {
8
- enable: false,
9
- expectedEndedAt: 0,
10
- },
11
- };
@@ -1,16 +0,0 @@
1
- import type { IValidation } from "typia";
2
- import { reject } from "../kernel/fail";
3
-
4
- export function _validate(validator: IValidation.IFailure | IValidation.ISuccess): any {
5
- if (validator.success) return validator.data;
6
- const error = validator.errors[0];
7
-
8
- if (error.value === undefined) error.value === "undefined";
9
- if (error.value === null) error.value === "null";
10
-
11
- throw reject("TYPE_SAFE_ERROR", {
12
- path: error.path,
13
- expected: error.expected,
14
- value: error.value,
15
- });
16
- }
@@ -1,258 +0,0 @@
1
- import { $ } from "bun";
2
- import { join } from "node:path";
3
- import { cwd } from "node:process";
4
- import { existsSync } from "node:fs";
5
- import { writeFile, readFile, copyFile } from "node:fs/promises";
6
- import { type MilkioConfig, TSON, type Cookbook } from "..";
7
-
8
- export default async () => {
9
- const schema = await import("../../../generated/api-schema");
10
- const paths = Object.keys(schema.default.apiMethodsSchema);
11
-
12
- console.log("");
13
- console.time(`Cookbook Stage`);
14
-
15
- const cookbook: Cookbook = {};
16
- for (const path of paths) {
17
- // const module = await import(/* @vite-ignore */ join(`../../../src/apps/${path}`));
18
- const code = (await readFile(join(cwd(), `./src/apps/${path}.ts`))).toString();
19
- const codeLines = code.split("\n");
20
- let title;
21
- let desc;
22
- const descRaw = /\n\/\*\*\n[\s\S]+?\*\//.exec(code)?.[0] ?? "";
23
-
24
- if (descRaw) {
25
- const descRawLines = descRaw.split("\n");
26
- if (descRawLines.at(0)?.trim() === "") descRawLines.shift();
27
- if (descRawLines.at(-1)?.trim() === "") descRawLines.pop();
28
- let first = true;
29
- for (let index = 0; index < descRawLines.length; index++) {
30
- const descRawLine = descRawLines[index].replace(/^[/ ]+?[*]*/, "").replace(/[*]*\/$/, "");
31
-
32
- if (!descRawLine) continue;
33
- if (first) {
34
- title = descRawLine.replace(/#/g, "").trim();
35
- // Originally the title was in the first line, desc is the rest of it, now desc contains complete markdown content.
36
- // continue;
37
- }
38
- first = false;
39
- desc = `${desc ?? ""}\n${descRawLine.trim()}`;
40
- }
41
- }
42
-
43
- let apiParams = /action\([\s\S]+?\)/.exec(code)?.[0] ?? ""; // The intention of the following code is to extract the parameter part of the action.
44
- apiParams = /\([\s\S]*,/.exec(apiParams)?.[0] ?? "";
45
- apiParams = apiParams.slice(0, -1);
46
- apiParams = apiParams.slice(/[\s\S]+?:/.exec(apiParams)?.[0].length);
47
- const apiParamsLines = apiParams.split("\n"); // The intention of the following code is to remove extra spaces, which will make the code look more beautiful.
48
- if (apiParamsLines.at(-1)?.trim() === "") apiParamsLines.pop();
49
- if (apiParamsLines.at(-1)?.trim() === "") apiParamsLines.pop();
50
- let spaceNumber = 0;
51
- for (const char of apiParamsLines.at(-1) ?? "") {
52
- if (char === " ") spaceNumber++;
53
- else break;
54
- }
55
- for (let index = 0; index < apiParamsLines.length; index++) {
56
- const line = apiParamsLines[index];
57
- let spaceNumberForThisLine = 0;
58
- for (const char of line) {
59
- if (char === " ") spaceNumberForThisLine++;
60
- else break;
61
- }
62
- if (spaceNumberForThisLine >= spaceNumber) {
63
- apiParamsLines[index] = line.slice(spaceNumber);
64
- } else {
65
- apiParamsLines[index] = line.slice(spaceNumberForThisLine);
66
- }
67
- }
68
- apiParams = apiParamsLines.join("\n");
69
-
70
- // Find the code for the API testing section.
71
- const apiTestsCodeChars = [];
72
- let apiTestsStartIndex = undefined as undefined | number;
73
- let semicolonMatch = 0;
74
- let semicolonMax = 0;
75
- for (let index = 0; index < codeLines.length; index++) {
76
- const codeLine = codeLines[index];
77
- if (apiTestsStartIndex === undefined && !codeLine.includes("defineApiTest(")) continue;
78
- if (apiTestsStartIndex === undefined) apiTestsStartIndex = index;
79
- const codeChars = codeLine.split("");
80
- for (const codeChar of codeChars) {
81
- if (codeChar === "[") {
82
- semicolonMatch++;
83
- semicolonMax++;
84
- }
85
- if (semicolonMatch !== 0) apiTestsCodeChars.push(codeChar);
86
- if (codeChar === "]") semicolonMatch--;
87
- }
88
- if (semicolonMatch === 0 && semicolonMax >= 1) {
89
- break;
90
- }
91
- apiTestsCodeChars.push("\n");
92
- }
93
-
94
- // Find the code for each API test case.
95
- const apiCaseCodes: Array<string> = [];
96
- let currentApiCaseCode = undefined as undefined | Array<string>;
97
- let apiTestCaseStartIndex = undefined as undefined | number;
98
- let apiTestCaseMatch = 0;
99
- for (let index = 0; index < apiTestsCodeChars.length; index++) {
100
- const apiTestsCodeChar = apiTestsCodeChars[index];
101
- if (apiTestCaseStartIndex === undefined && apiTestsCodeChar === "{") {
102
- currentApiCaseCode = [];
103
- apiTestCaseStartIndex = index;
104
- }
105
- if (apiTestsCodeChar === "{") {
106
- apiTestCaseMatch++;
107
- }
108
-
109
- if (apiTestCaseMatch !== 0) currentApiCaseCode!.push(apiTestsCodeChar);
110
-
111
- if (apiTestsCodeChar === "}") {
112
- apiTestCaseMatch--;
113
- if (apiTestCaseMatch === 0) {
114
- apiCaseCodes.push(currentApiCaseCode!.join(""));
115
- currentApiCaseCode = undefined;
116
- apiTestCaseStartIndex = undefined;
117
- }
118
- }
119
- }
120
-
121
- const apiCases: Array<{
122
- name: string;
123
- handler: string;
124
- }> = [];
125
-
126
- for (let index = 0; index < apiCaseCodes.length; index++) {
127
- const code = apiCaseCodes[index];
128
- const name = /name:[\s\S]+?,/.exec(code)?.[0]?.slice(5, -1)?.trim().slice(1, -1) ?? "";
129
- const handlerChars = /handler:[\s\S]*/.exec(code)?.[0]?.split("") ?? [];
130
- let handler = ""; // Find the main code of the handler.
131
- let handlerStartIndex = undefined as undefined | number;
132
- let handlerMatch = 0;
133
- for (let index = 0; index < handlerChars.length; index++) {
134
- const handlerChar = handlerChars[index];
135
- if (handlerStartIndex !== undefined && handlerChar === "{") handlerStartIndex = index;
136
- if (handlerChar === "{") handlerMatch++;
137
- if (handlerMatch !== 0) handler = handler + handlerChar;
138
- if (handlerChar === "}") handlerMatch--;
139
- if (handlerStartIndex !== undefined && handlerMatch === 0) break;
140
- }
141
- handler = handler.slice(1, -1);
142
-
143
- const handlerLines = handler.split("\n"); // The intention of the following code is to remove extra spaces, which will make the code look more beautiful.
144
- if (handlerLines.at(-1)?.trim() === "") handlerLines.pop();
145
- if (handlerLines.at(-1)?.trim() === "") handlerLines.pop();
146
- if (handlerLines.at(0)?.trim() === "") handlerLines.shift();
147
- if (handlerLines.at(0)?.trim() === "") handlerLines.shift();
148
- let spaceNumber = 0;
149
- for (const char of handlerLines.at(-1) ?? "") {
150
- if (char === " ") spaceNumber++;
151
- else break;
152
- }
153
- for (let index = 0; index < handlerLines.length; index++) {
154
- const line = handlerLines[index];
155
- let spaceNumberForThisLine = 0;
156
- for (const char of line) {
157
- if (char === " ") spaceNumberForThisLine++;
158
- else break;
159
- }
160
- if (spaceNumberForThisLine >= spaceNumber) {
161
- handlerLines[index] = line.slice(spaceNumber);
162
- } else {
163
- handlerLines[index] = line.slice(spaceNumberForThisLine);
164
- }
165
- }
166
- handler = handlerLines.join("\n");
167
-
168
- apiCases.push({
169
- name,
170
- handler,
171
- });
172
- }
173
-
174
- // This value has been deprecated because TypeScript types can already replace it well
175
- // let paramsSchema;
176
- // try {
177
- // const moduleGenerated = await import(/* @vite-ignore */ `../../../generated/products/apps/${path}`);
178
- // paramsSchema = moduleGenerated.paramsSchema.schemas[0]?.properties?.data;
179
- // } catch (error) {}
180
-
181
- cookbook[path] = {
182
- title,
183
- desc,
184
- params: apiParams,
185
- cases: apiCases,
186
- };
187
- }
188
-
189
- /**
190
- * -- indexes
191
- */
192
-
193
- const indexes: Record<string, Array<string>> = {};
194
- const folderIndexes: Record<string, Array<string>> = {};
195
- indexes["(root)"] = [];
196
- folderIndexes["(root)"] = [];
197
- for (const path in cookbook) {
198
- if (!path.includes("/")) indexes["(root)"].push(path);
199
- }
200
- for (const path in cookbook) {
201
- const dirnames = path.split("/");
202
- for (let index = 0; index < dirnames.length - 1; index++) {
203
- const dirpath = dirnames.slice(0, index + 1).join("/");
204
- if (!indexes[dirpath]) indexes[dirpath] = [];
205
- if (!folderIndexes[dirpath]) folderIndexes[dirpath] = [];
206
- if (index + 1 === dirnames.length - 1) {
207
- indexes[dirpath].push(path);
208
- } else {
209
- const childDirpath = dirnames.slice(0, index + 2).join("/");
210
- if (folderIndexes[dirpath].includes(childDirpath)) continue;
211
- folderIndexes[dirpath].push(childDirpath);
212
- }
213
- }
214
- }
215
- for (const path in folderIndexes) {
216
- if (path.includes("/") || path === "(root)") continue;
217
- folderIndexes["(root)"].push(path);
218
- }
219
-
220
- const readme = (await readFile(join(cwd(), "src", "apps", "README.md"))).toString();
221
- Object.keys(indexes).forEach((key) => indexes[key].length === 0 && delete indexes[key]);
222
- const generatedAt = new Date();
223
-
224
- await writeFile(
225
- join(cwd(), `./generated/cookbook.json`),
226
- TSON.stringify({
227
- cookbook,
228
- readme,
229
- indexes,
230
- folderIndexes,
231
- generatedAt,
232
- }),
233
- );
234
-
235
- console.timeEnd(`Cookbook Stage`);
236
- console.log(``);
237
-
238
- console.time(`Client Stage`);
239
- try {
240
- if (process.platform !== "win32") await $`bun run ./node_modules/typescript/bin/tsc --outDir './packages/client/project'`.quiet();
241
- else await $`powershell.exe -command "bun run ./node_modules/typescript/bin/tsc --outDir './packages/client/project'"`.quiet();
242
- } catch (error) {}
243
- await copyFile(join(cwd(), "src", "fail-code.ts"), join(cwd(), "packages", "client", "project", "src", "fail-code.ts"));
244
- await $`bun i`.cwd(join(cwd(), "packages", "client"));
245
- console.timeEnd(`Client Stage`);
246
- console.log(``);
247
-
248
- if (!existsSync(join(cwd(), "milkio.toml"))) return;
249
- const milkioConfig = (await import(join(cwd(), "milkio.toml"))).default as MilkioConfig;
250
- if (!milkioConfig?.generate?.significant) return;
251
- let i = 0;
252
- for (const command of milkioConfig.generate.significant) {
253
- ++i;
254
- console.time(`Insignificant Stage (LINE ${i})`);
255
- await $`${{ raw: command }}`;
256
- console.timeEnd(`Insignificant Stage (LINE ${i})`);
257
- }
258
- };