milkio 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,74 @@
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(), "generate", "raw-tmp", "apps", partialPath);
43
+ const dirPathTmp = join(cwd(), "generate", "raw-tmp", "apps", partialPath).split("/").slice(0, -1).join("/");
44
+ const filePath = join(cwd(), "generate", "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 "loongbao";
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(), "generate", "products", "apps", partialPath), (await readFile(join(cwd(), "generate", "products-tmp", "apps", partialPath))).toString())]);
74
+ }
@@ -0,0 +1,153 @@
1
+ /* eslint-disable no-console */
2
+
3
+ import ejs from "ejs";
4
+ import { join } from "node:path";
5
+ import walkSync from "walk-sync";
6
+ import { existsSync, mkdirSync } from "node:fs";
7
+ import { cwd, exit } from "node:process";
8
+ import { unlink, writeFile } from "node:fs/promises";
9
+ import { exec as nodeExec } from "node:child_process";
10
+ import { camel, hyphen } from "@poech/camel-hump-under";
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(), "generate", "api-schema.ts"));
21
+ } catch (error) {} // Maybe the file does not exist
22
+
23
+ if (!existsSync(join("generate", "README.md"))) {
24
+ await writeFile(join("generate", "README.md"), "⚠️ All files in this directory are generated by Loongbao. 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(), "generate", "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 appFiles = walkSync(join(cwd(), "src", "apps"), {
45
+ directories: false
46
+ });
47
+
48
+ for (const path of appFiles) {
49
+ if (!path.endsWith(".ts")) continue;
50
+ const module = await import(/* @vite-ignore */ `../../../../src/apps/${path}`);
51
+ if (module?.api?.isApi === true) {
52
+ // Exclude disallowed characters
53
+ if (path.includes("_")) {
54
+ console.error(`\n\nPath: ` + `"${path}"`);
55
+ console.error(`Do not use "_" in the path. If you want to add a separator between words, please use "-".\n`);
56
+ exit(1);
57
+ }
58
+ if (!/^[a-z0-9/-]+$/.test(path.slice(0, -3))) {
59
+ console.error(`\n\nPath: ` + `"${path}"`);
60
+ console.error(`The path can only contain lowercase letters, numbers, and "-".\n`);
61
+ exit(1);
62
+ }
63
+
64
+ templateVars.apiPaths.push(path);
65
+
66
+ if (module?.test?.isApiTest === true) {
67
+ templateVars.apiTestPaths.push(path);
68
+ }
69
+
70
+ // typia
71
+ const filePath = join(cwd(), "generate", "raw", "apps", path);
72
+ const dirPath = join(cwd(), "generate", "raw", "apps", path).split("/").slice(0, -1).join("/");
73
+ if (!existsSync(dirPath)) {
74
+ mkdirSync(dirPath, { recursive: true });
75
+ }
76
+ let importPath = "../../../";
77
+
78
+ for (let i = 0; i < path.split("/").length - 1; i++) {
79
+ importPath = importPath + "../";
80
+ }
81
+ importPath = importPath + "src/apps";
82
+ const template = `
83
+ import typia from "typia";
84
+ import { _validate, type ExecuteResultSuccess } from "loongbao";
85
+ import { type TSONEncode } from "@southern-aurora/tson";
86
+ import type * as <%= utils.camel(path.slice(0, -3).replaceAll('/', '$')) %> from '${importPath}/<%= path.slice(0, -3) %>';
87
+
88
+ type ParamsT = Parameters<typeof <%= utils.camel(path.replaceAll('/', '$').slice(0, -${3})) %>['api']['action']>[0];
89
+ export const params = async (params: any) => typia.misc.validatePrune<ParamsT>(params);
90
+ type ResultsT = Awaited<ReturnType<typeof <%= utils.camel(path.replaceAll('/', '$').slice(0, -${3})) %>['api']['action']>>;
91
+ export const results = async (results: any) => { _validate(typia.validate<TSONEncode<ExecuteResultSuccess<ResultsT>>>(results)); return typia.json.stringify<TSONEncode<ExecuteResultSuccess<ResultsT>>>(results); };
92
+
93
+ `.trim();
94
+ // export const paramsSchema = typia.json.application<[{ data: ParamsT }], "swagger">();
95
+
96
+ await writeFile(filePath, ejs.render(template, { ...templateVars, path }));
97
+ }
98
+ }
99
+
100
+ await writeFile(
101
+ join(cwd(), "generate", "api-schema.ts"),
102
+ ejs.render(
103
+ `
104
+ /**
105
+ * ⚠️ This file is generated and modifications will be overwritten
106
+ */
107
+
108
+ // api
109
+ <% for (const path of ${"apiPaths"}) { %>import type * as <%= utils.camel(path.slice(0, -3).replaceAll('/', '$')) %> from '${"../src/apps"}/<%= path.slice(0, -3) %>'
110
+ <% } %>
111
+ import _apiValidator from './products/api-validator.ts'
112
+
113
+ export default {
114
+ apiValidator: _apiValidator,
115
+ ${"apiMethodsSchema"}: {
116
+ <% for (const path of apiPaths) { %>'<%= utils.hyphen(path.slice(0, -${3})) %>': () => ({ module: import('../src/apps/<%= path.slice(0, -${3}) %>') }),
117
+ <% } %>
118
+ },
119
+ ${"apiMethodsTypeSchema"}: {
120
+ <% for (const path of apiPaths) { %>'<%= utils.hyphen(path.slice(0, -${3})) %>': undefined as unknown as typeof <%= utils.camel(path.slice(0, -${3}).replaceAll('/', '$')) %>,
121
+ <% } %>
122
+ },
123
+ ${"apiTestsSchema"}: {
124
+ <% for (const path of apiTestPaths) { %>'<%= utils.hyphen(path.slice(0, -${3})) %>': () => ({ module: import('../src/apps/<%= path.slice(0, -${3}) %>') }),
125
+ <% } %>
126
+ },
127
+ }
128
+ `.trim(),
129
+ templateVars
130
+ )
131
+ );
132
+
133
+ // api
134
+ const apiValidatorTemplate = `/**
135
+ * ⚠️This file is generated and modifications will be overwritten
136
+ */
137
+
138
+ export default {
139
+ generatedAt: ${new Date().getTime()},
140
+ ${"validate"}: {
141
+ <% for (const path of apiPaths) { %>'<%= utils.hyphen(path.slice(0, -${3})) %>': () => import('./apps/<%= utils.hyphen(path) %>'),
142
+ <% } %>
143
+ },
144
+ }
145
+ `.trim();
146
+ await writeFile(join(cwd(), "generate", "raw", "api-validator.ts"), ejs.render(apiValidatorTemplate, templateVars));
147
+
148
+ await new Promise((resolve) =>
149
+ nodeExec("bun run ./node_modules/typia/lib/executable/typia.js generate --input generate/raw --output generate/products --project tsconfig.json", (e) => {
150
+ resolve(e);
151
+ })
152
+ );
153
+ }
@@ -0,0 +1,23 @@
1
+ /* eslint-disable no-console */
2
+
3
+ import ejs from "ejs";
4
+ import { join } from "node:path";
5
+ import walkSync from "walk-sync";
6
+ import { existsSync } from "node:fs";
7
+ import { cwd } from "node:process";
8
+ import { writeFile } from "node:fs/promises";
9
+
10
+ export async function generateDatabase() {
11
+ if (existsSync(join(cwd(), "src", "databases"))) {
12
+ if (!existsSync(join("generate", "database-schema.ts"))) {
13
+ await writeFile(join("generate", "database-schema.ts"), ``);
14
+ }
15
+ const filePath = join(cwd(), "generate", "database-schema.ts");
16
+ const databaseFiles = walkSync(join(cwd(), "src", "databases"), {
17
+ directories: false
18
+ }).filter((file) => file.endsWith(".ts"));
19
+ const template = `<% for (const path of ${"databaseFiles"}) { %>export * from '${"../src/databases"}/<%= path.slice(0, -3) %>'
20
+ <% } %>`;
21
+ await writeFile(filePath, ejs.render(template, { databaseFiles }));
22
+ }
23
+ }
@@ -0,0 +1,23 @@
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 { generateDatabase } from "./generate/generate-database";
7
+
8
+ export async function generate() {
9
+ // Make sure that the existing directories are all present
10
+ existsSync(join("generate")) || mkdirSync(join("generate"));
11
+ existsSync(join("generate", "raw")) || mkdirSync(join("generate", "raw"));
12
+ existsSync(join("generate", "raw", "apps")) || mkdirSync(join("generate", "raw", "apps"));
13
+
14
+ await generateDatabase();
15
+ }
16
+
17
+ console.log("Loongbao Database Generating..");
18
+
19
+ await generate();
20
+
21
+ console.log("\n✅ Loongbao Database Generated!\n");
22
+
23
+ exit(0);
@@ -0,0 +1,15 @@
1
+ /* eslint-disable no-console, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument */
2
+
3
+ import { argv, exit } from "node:process";
4
+ import { generateApp } from "./generate/generate-app";
5
+ console.log("Loongbao Quick Generating..");
6
+
7
+ export async function generatePartial(path?: string) {
8
+ await generateApp();
9
+ }
10
+
11
+ await generatePartial(...(argv.slice(3) as any));
12
+
13
+ console.log("\n✅ Loongbao Generated!");
14
+
15
+ exit(0);
@@ -0,0 +1,23 @@
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 "./generate/generate-app";
7
+
8
+ export async function generate() {
9
+ // Make sure that the existing directories are all present
10
+ existsSync(join("generate")) || mkdirSync(join("generate"));
11
+ existsSync(join("generate", "raw")) || mkdirSync(join("generate", "raw"));
12
+ existsSync(join("generate", "raw", "apps")) || mkdirSync(join("generate", "raw", "apps"));
13
+
14
+ await generateApp();
15
+ }
16
+
17
+ console.log("Loongbao Generating..");
18
+
19
+ await generate();
20
+
21
+ console.log("\n✅ Loongbao Generated!");
22
+
23
+ exit(0);
@@ -0,0 +1,49 @@
1
+ import { createTemplate } from "../utils/create-template";
2
+ import { join } from "path";
3
+
4
+ await createTemplate(async (tools) => {
5
+ return {
6
+ path: join(tools.directory, `${tools.hyphen(tools.name)}.ts`),
7
+ content: `
8
+ import { defineApi, defineApiTest } from "loongbao";
9
+
10
+ /**
11
+ * ${tools.hyphen(tools.name)}
12
+ */
13
+ export const api = defineApi({
14
+ meta: {
15
+ //
16
+ },
17
+ async action(
18
+ params: {
19
+ //
20
+ },
21
+ context
22
+ ) {
23
+ const message = \`hello world!\`;
24
+
25
+ // ..
26
+
27
+ return {
28
+ say: message
29
+ };
30
+ }
31
+ });
32
+
33
+ export const test = defineApiTest(api, [
34
+ {
35
+ name: "Basic",
36
+ handler: async (test) => {
37
+ const result = await test.execute({
38
+ //
39
+ });
40
+
41
+ // ..
42
+
43
+ if (!result.success) return test.reject(\`The result was not success\`);
44
+ }
45
+ }
46
+ ]);
47
+ `.trim()
48
+ };
49
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "compilerOptions": {
3
+ "rootDir": "./../../../",
4
+ "lib": [
5
+ "ESNext"
6
+ ],
7
+ "module": "esnext",
8
+ "target": "esnext",
9
+ "moduleResolution": "bundler",
10
+ "moduleDetection": "force",
11
+ "allowImportingTsExtensions": true,
12
+ "noEmit": true,
13
+ "composite": true,
14
+ "strict": true,
15
+ "downlevelIteration": true,
16
+ "skipLibCheck": true,
17
+ "jsx": "react-jsx",
18
+ "allowSyntheticDefaultImports": true,
19
+ "forceConsistentCasingInFileNames": true,
20
+ "allowJs": true,
21
+ "types": [
22
+ "bun-types"
23
+ ],
24
+ "paths": {
25
+ "../../*": [
26
+ "../../*"
27
+ ]
28
+ }
29
+ },
30
+ "include": [
31
+ "../../../**/*"
32
+ ]
33
+ }
package/types.ts ADDED
@@ -0,0 +1,42 @@
1
+ /* eslint-disable @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any */
2
+
3
+ import { type createLoongbaoApp } from ".";
4
+ import type { failCode } from "../../src/fail-code";
5
+
6
+ export type LoongbaoApp = Awaited<ReturnType<typeof createLoongbaoApp>>;
7
+
8
+ export type ExecuteId = string | "global";
9
+
10
+ export type FailEnumerates = typeof failCode;
11
+
12
+ export type HTTPRequest = Request;
13
+
14
+ export type HTTPResponse = Override<ResponseInit & { body: string | null | undefined }, { headers: NonNullable<ResponseInit["headers"]> }>;
15
+
16
+ export type Fail<FailCode extends keyof FailEnumerates> = {
17
+ code: FailCode;
18
+ message: string;
19
+ data: Parameters<FailEnumerates[FailCode]>[0];
20
+ };
21
+
22
+ export type LoongbaoMeta = {
23
+ //
24
+ };
25
+
26
+ export type Cookbook = Record<string, CookbookItem>;
27
+
28
+ export type CookbookItem = {
29
+ title?: string;
30
+ desc?: string;
31
+ params: string;
32
+ cases: Array<{
33
+ name: string;
34
+ handler: string;
35
+ }>;
36
+ };
37
+
38
+ export type DatabaseType<Table extends { findFirst: () => unknown }, Override = {}> = Mixin<NonNullable<Awaited<ReturnType<Table["findFirst"]>>>, Override>;
39
+
40
+ export type Override<P, S> = Omit<P, keyof S> & S;
41
+
42
+ export type Mixin<T, U> = U & Omit<T, keyof U>;
@@ -0,0 +1,32 @@
1
+ import { argv } from "bun";
2
+ import { camel, hump, hyphen } from "@poech/camel-hump-under";
3
+
4
+ export type CreateTemplateTools = {
5
+ name: string;
6
+ directory: string;
7
+ camel: (str: string) => string;
8
+ hump: (str: string) => string;
9
+ hyphen: (str: string) => string;
10
+ };
11
+
12
+ export type CreateTemplateFn = (tools: CreateTemplateTools) =>
13
+ | {
14
+ path: string;
15
+ content: string;
16
+ }
17
+ | Promise<{
18
+ path: string;
19
+ content: string;
20
+ }>;
21
+
22
+ export async function createTemplate(fn: CreateTemplateFn) {
23
+ const tools = {
24
+ name: argv[2],
25
+ directory: argv[3],
26
+ camel: (str: string) => camel(str).replaceAll("-", "").replaceAll("_", ""),
27
+ hump: (str: string) => hump(str).replaceAll("-", "").replaceAll("_", ""),
28
+ hyphen: (str: string) => hyphen(str).replaceAll("_", "")
29
+ };
30
+ const file = await fn(tools);
31
+ await Bun.write(file.path, file.content);
32
+ }
@@ -0,0 +1,5 @@
1
+ import { monotonicFactory } from "ulidx";
2
+
3
+ const ulid = monotonicFactory();
4
+
5
+ export const createUlid = () => ulid();
@@ -0,0 +1,11 @@
1
+ export function envToBoolean(value: string | number | undefined, defaultValue: boolean) {
2
+ if (value === "true") return true;
3
+
4
+ if (value === "false") return false;
5
+
6
+ if (value === "") return false;
7
+
8
+ if (undefined === value) return defaultValue;
9
+
10
+ return Boolean(value);
11
+ }
@@ -0,0 +1,5 @@
1
+ export function envToNumber(value: string | undefined, defaultValue: number) {
2
+ if (value === undefined) return defaultValue;
3
+
4
+ return Number.parseInt(value, 10);
5
+ }
@@ -0,0 +1,5 @@
1
+ export function envToString(value: string | number | undefined, defaultValue: string) {
2
+ if (value === undefined) return defaultValue;
3
+
4
+ return `${value}`;
5
+ }
package/utils/exec.ts ADDED
@@ -0,0 +1,27 @@
1
+ import { env, type SpawnOptions } from "bun";
2
+
3
+ /**
4
+ * This is a legacy wrapper that was written before $ Shell was created.
5
+ * All relevant code should be replaced with $ Shell in the future.
6
+ */
7
+
8
+ export const exec = async (cwd: string, command: Array<string>, options: Partial<SpawnOptions.OptionsObject> = {}) => {
9
+ return new Promise((resolve, reject) => {
10
+ if (!("cwd" in options)) options.cwd = cwd;
11
+ if (!("stdin" in options)) options.stdin = "inherit";
12
+ if (!("stdout" in options)) options.stdout = "inherit";
13
+ if (!("env" in options)) options.env = { ...env };
14
+
15
+ options.onExit = (proc, exitCode, signalCode, error) => {
16
+ // eslint-disable-next-line prefer-promise-reject-errors
17
+ if (exitCode !== 0) reject({ proc, exitCode, signalCode, error });
18
+ else resolve({ proc, exitCode, signalCode, error });
19
+ };
20
+
21
+ try {
22
+ Bun.spawn(command, options);
23
+ } catch (error) {
24
+ reject(error);
25
+ }
26
+ });
27
+ };
@@ -0,0 +1,37 @@
1
+ import { failCode } from "../../../src/fail-code";
2
+ import { useLogger, type ExecuteId, type ExecuteResult } from "..";
3
+
4
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
+ export function hanldeCatchError(error: any, executeId: ExecuteId): ExecuteResult<any> {
6
+ const logger = useLogger(executeId);
7
+
8
+ logger.error("\nError Data: " + JSON.stringify(error));
9
+ if (error.stack) logger.error("\nError Stack: ", error.stack);
10
+ else logger.error("\nError Stack: ", error);
11
+
12
+ if (error.name !== "LoongbaoReject") {
13
+ // If it is not LoongbaoReject, it is considered an internal server error that should not be exposed
14
+ logger.error(`FailCode: internal-server-error`);
15
+
16
+ return {
17
+ executeId,
18
+ success: false,
19
+ fail: {
20
+ code: "internal-server-error",
21
+ message: failCode["internal-server-error"](),
22
+ data: undefined
23
+ }
24
+ };
25
+ } else {
26
+ logger.error(`FailCode: ${error.code}`);
27
+ return {
28
+ executeId,
29
+ success: false,
30
+ fail: {
31
+ code: error.code,
32
+ message: error.message,
33
+ data: error.data
34
+ }
35
+ };
36
+ }
37
+ }
@@ -0,0 +1,22 @@
1
+ import { existsSync, lstatSync, readdirSync, rmdirSync, unlinkSync } from "node:fs";
2
+ import path from "node:path";
3
+
4
+ export function removeDir(pathstr: string, skips: Array<string> = []) {
5
+ if (!existsSync(pathstr)) return;
6
+ const files = readdirSync(pathstr);
7
+ files.forEach((file) => {
8
+ const dirname = path.resolve(pathstr, file);
9
+ const stats = lstatSync(dirname);
10
+ for (const skip of skips) {
11
+ if (dirname.startsWith(skip)) return;
12
+ }
13
+ if (stats.isDirectory()) {
14
+ removeDir(dirname);
15
+ } else {
16
+ unlinkSync(dirname);
17
+ }
18
+ });
19
+ try {
20
+ rmdirSync(pathstr);
21
+ } catch (error) {}
22
+ }
package/utils/tson.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { TSON as _TSON } from "@southern-aurora/tson";
2
+
3
+ export const TSON = _TSON;