sdnext 0.0.24 → 0.0.26
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/README.md +111 -1
- package/dist/index.js +145 -14
- package/dist/utils/build.js +5 -8
- package/dist/utils/createAction.js +10 -17
- package/dist/utils/createRoute.d.ts +9 -0
- package/dist/utils/createRoute.js +64 -0
- package/dist/utils/dev.js +22 -9
- package/dist/utils/hook.d.ts +11 -1
- package/dist/utils/hook.js +101 -65
- package/dist/utils/readSdNextSetting.d.ts +3 -0
- package/dist/utils/readSdNextSetting.js +8 -3
- package/dist/utils/runCommand.d.ts +7 -0
- package/dist/utils/runCommand.js +25 -0
- package/dist/utils/sharedArtifact.d.ts +23 -0
- package/dist/utils/sharedArtifact.js +67 -0
- package/dist/utils/syncSharedArtifacts.d.ts +3 -0
- package/dist/utils/syncSharedArtifacts.js +28 -0
- package/dist/utils/watch.js +5 -21
- package/package.json +1 -1
- package/src/index.ts +5 -4
- package/src/utils/build.ts +4 -10
- package/src/utils/createAction.ts +12 -19
- package/src/utils/createRoute.ts +86 -0
- package/src/utils/dev.ts +24 -10
- package/src/utils/hook.ts +125 -74
- package/src/utils/readSdNextSetting.ts +14 -4
- package/src/utils/runCommand.ts +35 -0
- package/src/utils/sharedArtifact.ts +90 -0
- package/src/utils/syncSharedArtifacts.ts +38 -0
- package/src/utils/watch.ts +5 -16
- package/dist/utils/excludeActions.d.ts +0 -1
- package/dist/utils/excludeActions.js +0 -9
- package/dist/utils/writeVsCodeSetting.d.ts +0 -1
- package/dist/utils/writeVsCodeSetting.js +0 -18
- package/src/utils/excludeActions.ts +0 -9
- package/src/utils/writeVsCodeSetting.ts +0 -22
package/dist/utils/hook.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFile, readdir, stat } from "fs/promises";
|
|
2
2
|
import { join, parse, relative } from "path";
|
|
3
3
|
import { cwd } from "process";
|
|
4
4
|
import { checkbox as prompts_checkbox, select as prompts_select } from "@inquirer/prompts";
|
|
5
5
|
import { readSdNextSetting } from "./readSdNextSetting.js";
|
|
6
|
+
import { isScriptModule, normalizePathSeparator, writeGeneratedFile } from "./sharedArtifact.js";
|
|
6
7
|
import { writeSdNextSetting } from "./writeSdNextSetting.js";
|
|
7
8
|
function getHookTypeFromName(name) {
|
|
8
9
|
if (/^get[^a-z]/.test(name)) return "get";
|
|
@@ -19,37 +20,57 @@ async function getHookTypeFromContent(path, content) {
|
|
|
19
20
|
const type = setting.hook?.[path];
|
|
20
21
|
if (void 0 !== type && "skip" !== type) return type;
|
|
21
22
|
if (content.includes("useMutation")) return "mutation";
|
|
22
|
-
if (content.includes("
|
|
23
|
+
if (content.includes("createUse") && content.includes("@/presets/")) return "mutation";
|
|
24
|
+
if (content.includes("ClientOptional")) return "get";
|
|
23
25
|
if (content.includes("useQuery")) return "query";
|
|
24
26
|
}
|
|
27
|
+
async function getGeneratedFileState(path) {
|
|
28
|
+
try {
|
|
29
|
+
const content = await readFile(path, "utf-8");
|
|
30
|
+
return {
|
|
31
|
+
content,
|
|
32
|
+
overwrite: !content.trim()
|
|
33
|
+
};
|
|
34
|
+
} catch (error) {
|
|
35
|
+
return {
|
|
36
|
+
content: "",
|
|
37
|
+
overwrite: true
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
25
41
|
async function createHook(path, hookMap) {
|
|
26
42
|
path = relative("actions", path).replace(/\\/g, "/");
|
|
27
|
-
const { dir, name,
|
|
28
|
-
if (
|
|
29
|
-
const serverContent = await readFile(join("shared", path), "utf-8");
|
|
30
|
-
const match = serverContent.match(new RegExp(`export async function ${name}\\(.+?: (.+?)Params\\)`, "s"));
|
|
31
|
-
const hasSchema = !!match;
|
|
43
|
+
const { dir, name, base } = parse(path);
|
|
44
|
+
if (!isScriptModule(path)) return;
|
|
32
45
|
const upName = name.replace(/^./, (char)=>char.toUpperCase());
|
|
33
46
|
const key = name.replace(/[A-Z]/g, (char)=>`-${char.toLowerCase()}`);
|
|
34
|
-
const
|
|
47
|
+
const actionImportPath = normalizePathSeparator(join(dir, name));
|
|
48
|
+
const hookName = base.replace(/^./, (char)=>`use${char.toUpperCase()}`);
|
|
49
|
+
const hookPath = join("hooks", dir, hookName);
|
|
50
|
+
const mutationPresetName = `createUse${upName}.ts`;
|
|
51
|
+
const mutationPresetPath = join("presets", dir, mutationPresetName);
|
|
52
|
+
const mutationPresetImportPath = normalizePathSeparator(join(dir, `createUse${upName}`));
|
|
53
|
+
const clientInputType = `${upName}ClientInput`;
|
|
54
|
+
const mutationHook = `import { createRequestFn } from "deepsea-tools"
|
|
35
55
|
|
|
36
|
-
import {
|
|
37
|
-
import { createRequestFn } from "deepsea-tools"
|
|
56
|
+
import { ${name}Action } from "@/actions/${actionImportPath}"
|
|
38
57
|
|
|
39
|
-
import { ${
|
|
58
|
+
import { createUse${upName} } from "@/presets/${mutationPresetImportPath}"
|
|
40
59
|
|
|
41
60
|
export const ${name}Client = createRequestFn(${name}Action)
|
|
42
61
|
|
|
43
|
-
export
|
|
44
|
-
|
|
45
|
-
"
|
|
46
|
-
|
|
62
|
+
export const use${upName} = createUse${upName}(${name}Client)
|
|
63
|
+
`;
|
|
64
|
+
const mutationPreset = `import { useId } from "react"
|
|
65
|
+
|
|
66
|
+
import { withUseMutationDefaults } from "soda-tanstack-query"
|
|
67
|
+
|
|
68
|
+
import { ${name} } from "@/shared/${actionImportPath}"
|
|
47
69
|
|
|
48
|
-
export
|
|
70
|
+
export const createUse${upName} = withUseMutationDefaults<typeof ${name}>(() => {
|
|
49
71
|
const key = useId()
|
|
50
72
|
|
|
51
|
-
return
|
|
52
|
-
mutationFn: ${name}Client,
|
|
73
|
+
return {
|
|
53
74
|
onMutate(variables, context) {
|
|
54
75
|
message.open({
|
|
55
76
|
key,
|
|
@@ -57,8 +78,6 @@ export function use${upName}<TOnMutateResult = unknown>({ onMutate, onSuccess, o
|
|
|
57
78
|
content: "中...",
|
|
58
79
|
duration: 0,
|
|
59
80
|
})
|
|
60
|
-
|
|
61
|
-
return onMutate?.(variables, context) as TOnMutateResult | Promise<TOnMutateResult>
|
|
62
81
|
},
|
|
63
82
|
onSuccess(data, variables, onMutateResult, context) {
|
|
64
83
|
context.client.invalidateQueries({ queryKey: ["query-${key.replace(/^.+?-/, "")}"] })
|
|
@@ -69,29 +88,24 @@ export function use${upName}<TOnMutateResult = unknown>({ onMutate, onSuccess, o
|
|
|
69
88
|
type: "success",
|
|
70
89
|
content: "成功",
|
|
71
90
|
})
|
|
72
|
-
|
|
73
|
-
return onSuccess?.(data, variables, onMutateResult, context)
|
|
74
91
|
},
|
|
75
92
|
onError(error, variables, onMutateResult, context) {
|
|
76
93
|
message.destroy(key)
|
|
77
|
-
|
|
78
|
-
return onError?.(error, variables, onMutateResult, context)
|
|
79
|
-
},
|
|
80
|
-
onSettled(data, error, variables, onMutateResult, context) {
|
|
81
|
-
return onSettled?.(data, error, variables, onMutateResult, context)
|
|
82
94
|
},
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
}
|
|
95
|
+
onSettled(data, error, variables, onMutateResult, context) {},
|
|
96
|
+
}
|
|
97
|
+
})
|
|
86
98
|
`;
|
|
87
99
|
const getHook = `import { createRequestFn, isNonNullable } from "deepsea-tools"
|
|
88
100
|
import { createUseQuery } from "soda-tanstack-query"
|
|
89
101
|
|
|
90
|
-
import { ${name}Action } from "@/actions/${
|
|
102
|
+
import { ${name}Action } from "@/actions/${actionImportPath}"
|
|
91
103
|
|
|
92
104
|
export const ${name}Client = createRequestFn(${name}Action)
|
|
93
105
|
|
|
94
|
-
export
|
|
106
|
+
export type ${clientInputType} = Parameters<typeof ${name}Client> extends [] ? undefined : Parameters<typeof ${name}Client>[0]
|
|
107
|
+
|
|
108
|
+
export function ${name}ClientOptional(id?: ${clientInputType} | null) {
|
|
95
109
|
return isNonNullable(id) ? ${name}Client(id) : null
|
|
96
110
|
}
|
|
97
111
|
|
|
@@ -103,7 +117,7 @@ export const use${upName} = createUseQuery({
|
|
|
103
117
|
const queryHook = `import { createRequestFn } from "deepsea-tools"
|
|
104
118
|
import { createUseQuery } from "soda-tanstack-query"
|
|
105
119
|
|
|
106
|
-
import { ${name}Action } from "@/actions/${
|
|
120
|
+
import { ${name}Action } from "@/actions/${actionImportPath}"
|
|
107
121
|
|
|
108
122
|
export const ${name}Client = createRequestFn(${name}Action)
|
|
109
123
|
|
|
@@ -117,49 +131,62 @@ export const use${upName} = createUseQuery({
|
|
|
117
131
|
query: queryHook,
|
|
118
132
|
mutation: mutationHook
|
|
119
133
|
};
|
|
120
|
-
const hookName = base.replace(/^./, (char)=>`use${char.toUpperCase()}`);
|
|
121
|
-
const hookPath = join("hooks", dir, hookName);
|
|
122
134
|
let hookType = getHookTypeFromName(name);
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
135
|
+
const hookState = await getGeneratedFileState(hookPath);
|
|
136
|
+
const contentType = await getHookTypeFromContent(join(cwd(), hookPath), hookState.content);
|
|
137
|
+
if (contentType) hookType = contentType;
|
|
138
|
+
if ("mutation" === hookType) {
|
|
139
|
+
const mutationPresetState = await getGeneratedFileState(mutationPresetPath);
|
|
140
|
+
if (map[hookType] === hookState.content && mutationPreset === mutationPresetState.content) return;
|
|
141
|
+
hookMap[path] = {
|
|
142
|
+
hookPath,
|
|
143
|
+
mutationPreset,
|
|
144
|
+
mutationPresetPath,
|
|
145
|
+
overwrite: hookState.overwrite && mutationPresetState.overwrite,
|
|
146
|
+
type: hookType,
|
|
147
|
+
...map
|
|
148
|
+
};
|
|
149
|
+
return;
|
|
132
150
|
}
|
|
151
|
+
if (map[hookType] === hookState.content) return;
|
|
133
152
|
hookMap[path] = {
|
|
134
|
-
|
|
153
|
+
hookPath,
|
|
154
|
+
mutationPreset,
|
|
155
|
+
mutationPresetPath,
|
|
156
|
+
overwrite: hookState.overwrite,
|
|
135
157
|
type: hookType,
|
|
136
158
|
...map
|
|
137
159
|
};
|
|
138
160
|
}
|
|
139
|
-
async function
|
|
161
|
+
async function createHookFromFolder() {
|
|
140
162
|
const map = {};
|
|
141
|
-
async function
|
|
163
|
+
async function _createHookFromFolder(dir) {
|
|
142
164
|
const content = await readdir(dir);
|
|
143
165
|
for (const item of content){
|
|
144
166
|
const path = join(dir, item);
|
|
145
167
|
const stats = await stat(path);
|
|
146
|
-
if (stats.isDirectory()) await
|
|
168
|
+
if (stats.isDirectory()) await _createHookFromFolder(path);
|
|
147
169
|
if (stats.isFile()) await createHook(path, map);
|
|
148
170
|
}
|
|
149
171
|
}
|
|
150
|
-
|
|
172
|
+
try {
|
|
173
|
+
await _createHookFromFolder("actions");
|
|
174
|
+
} catch (error) {
|
|
175
|
+
if (isNodeError(error) && "ENOENT" === error.code) return map;
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
151
178
|
return map;
|
|
152
179
|
}
|
|
153
180
|
async function hook(options, { args }) {
|
|
154
|
-
const map = await
|
|
181
|
+
const map = await createHookFromFolder();
|
|
155
182
|
const entires = Object.entries(map);
|
|
156
183
|
if (0 === entires.length) return void console.log("All hooks are the latest.");
|
|
157
184
|
const newEntires = entires.filter(([path, { overwrite }])=>overwrite);
|
|
158
185
|
const oldEntires = entires.filter(([path, { overwrite }])=>!overwrite);
|
|
159
186
|
const root = cwd();
|
|
160
187
|
const setting = await getSetting();
|
|
161
|
-
for
|
|
162
|
-
const resolved = join(root,
|
|
188
|
+
for (const [path, { hookPath, mutationPresetPath, mutationPreset, overwrite, type, ...map }] of newEntires){
|
|
189
|
+
const resolved = join(root, hookPath);
|
|
163
190
|
const answer = await prompts_select({
|
|
164
191
|
message: path,
|
|
165
192
|
choices: [
|
|
@@ -172,25 +199,34 @@ async function hook(options, { args }) {
|
|
|
172
199
|
});
|
|
173
200
|
setting.hook ??= {};
|
|
174
201
|
setting.hook[resolved] = answer;
|
|
175
|
-
if ("skip"
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
202
|
+
if ("skip" !== answer) {
|
|
203
|
+
await writeGeneratedFile({
|
|
204
|
+
path: hookPath,
|
|
205
|
+
content: map[answer]
|
|
206
|
+
});
|
|
207
|
+
if ("mutation" === answer) await writeGeneratedFile({
|
|
208
|
+
path: mutationPresetPath,
|
|
209
|
+
content: mutationPreset
|
|
210
|
+
});
|
|
211
|
+
}
|
|
181
212
|
}
|
|
182
213
|
await writeSdNextSetting(setting);
|
|
183
214
|
const overwrites = await prompts_checkbox({
|
|
184
215
|
message: "Please check the hooks you want to overwrite",
|
|
185
216
|
choices: oldEntires.map(([key])=>key)
|
|
186
217
|
});
|
|
187
|
-
for (const [path, { overwrite, type, ...map }] of oldEntires){
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
218
|
+
for (const [path, { hookPath, mutationPresetPath, mutationPreset, overwrite, type, ...map }] of oldEntires)if (overwrites.includes(path)) {
|
|
219
|
+
await writeGeneratedFile({
|
|
220
|
+
path: hookPath,
|
|
221
|
+
content: map[type]
|
|
222
|
+
});
|
|
223
|
+
if ("mutation" === type) await writeGeneratedFile({
|
|
224
|
+
path: mutationPresetPath,
|
|
225
|
+
content: mutationPreset
|
|
192
226
|
});
|
|
193
|
-
await writeFile(join("hooks", dir, base.replace(/^./, (char)=>`use${char.toUpperCase()}`)), map[type]);
|
|
194
227
|
}
|
|
195
228
|
}
|
|
196
|
-
|
|
229
|
+
function isNodeError(error) {
|
|
230
|
+
return "object" == typeof error && null !== error;
|
|
231
|
+
}
|
|
232
|
+
export { createHook, createHookFromFolder, hook };
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
1
|
import { readFile } from "node:fs/promises";
|
|
3
2
|
import { homedir } from "node:os";
|
|
4
3
|
import { join } from "node:path";
|
|
5
4
|
async function readSdNextSetting() {
|
|
6
5
|
const userDir = homedir();
|
|
7
6
|
const settingPath = join(userDir, ".sdnext.json");
|
|
8
|
-
|
|
7
|
+
try {
|
|
9
8
|
const setting = JSON.parse(await readFile(settingPath, "utf-8"));
|
|
10
9
|
return setting;
|
|
10
|
+
} catch (error) {
|
|
11
|
+
if (isNodeError(error) && "ENOENT" === error.code) return {};
|
|
12
|
+
console.warn(`Failed to read ${settingPath}, fallback to default setting.`);
|
|
13
|
+
return {};
|
|
11
14
|
}
|
|
12
|
-
|
|
15
|
+
}
|
|
16
|
+
function isNodeError(error) {
|
|
17
|
+
return "object" == typeof error && null !== error;
|
|
13
18
|
}
|
|
14
19
|
export { readSdNextSetting };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ChildProcess } from "child_process";
|
|
2
|
+
export interface SpawnCommandParams {
|
|
3
|
+
args: string[];
|
|
4
|
+
}
|
|
5
|
+
export declare function spawnCommand({ args }: SpawnCommandParams): ChildProcess;
|
|
6
|
+
export declare function runCommand({ args }: SpawnCommandParams): Promise<number>;
|
|
7
|
+
export declare function waitForChild(child: ChildProcess): Promise<number>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { spawn } from "child_process";
|
|
2
|
+
function spawnCommand({ args }) {
|
|
3
|
+
const [command, ...commandArgs] = args;
|
|
4
|
+
return spawn(command, commandArgs, {
|
|
5
|
+
shell: true,
|
|
6
|
+
stdio: "inherit"
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
async function runCommand({ args }) {
|
|
10
|
+
if (0 === args.length) return 0;
|
|
11
|
+
const child = spawnCommand({
|
|
12
|
+
args
|
|
13
|
+
});
|
|
14
|
+
return waitForChild(child);
|
|
15
|
+
}
|
|
16
|
+
async function waitForChild(child) {
|
|
17
|
+
return await new Promise((resolve, reject)=>{
|
|
18
|
+
child.once("error", reject);
|
|
19
|
+
child.once("close", (code, signal)=>{
|
|
20
|
+
if ("number" == typeof code) return void resolve(code);
|
|
21
|
+
resolve(signal ? 1 : 0);
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
export { runCommand, spawnCommand, waitForChild };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface SharedModuleInfo {
|
|
2
|
+
dir: string;
|
|
3
|
+
ext: string;
|
|
4
|
+
importPath: string;
|
|
5
|
+
name: string;
|
|
6
|
+
relativePath: string;
|
|
7
|
+
}
|
|
8
|
+
export interface GeneratedFileParams {
|
|
9
|
+
content: string;
|
|
10
|
+
path: string;
|
|
11
|
+
}
|
|
12
|
+
export interface RemoveGeneratedFileParams {
|
|
13
|
+
path: string;
|
|
14
|
+
stopPath?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare const scriptModuleExtensions: string[];
|
|
17
|
+
export declare function normalizePathSeparator(path: string): string;
|
|
18
|
+
export declare function isScriptModule(path: string): boolean;
|
|
19
|
+
export declare function normalizeSharedPath(path: string): string;
|
|
20
|
+
export declare function getSharedModuleInfo(path: string): SharedModuleInfo;
|
|
21
|
+
export declare function toKebabCase(name: string): string;
|
|
22
|
+
export declare function writeGeneratedFile({ content, path }: GeneratedFileParams): Promise<void>;
|
|
23
|
+
export declare function removeGeneratedFile({ path, stopPath }: RemoveGeneratedFileParams): Promise<void>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { mkdir, readFile, readdir, rm, writeFile } from "fs/promises";
|
|
2
|
+
import { dirname, join, parse, relative } from "path";
|
|
3
|
+
const scriptModuleExtensions = [
|
|
4
|
+
".ts",
|
|
5
|
+
".tsx",
|
|
6
|
+
".js",
|
|
7
|
+
".jsx"
|
|
8
|
+
];
|
|
9
|
+
function normalizePathSeparator(path) {
|
|
10
|
+
return path.replace(/\\/g, "/");
|
|
11
|
+
}
|
|
12
|
+
function isScriptModule(path) {
|
|
13
|
+
const { ext } = parse(path);
|
|
14
|
+
return scriptModuleExtensions.includes(ext);
|
|
15
|
+
}
|
|
16
|
+
function normalizeSharedPath(path) {
|
|
17
|
+
return normalizePathSeparator(relative("shared", path));
|
|
18
|
+
}
|
|
19
|
+
function getSharedModuleInfo(path) {
|
|
20
|
+
const relativePath = normalizeSharedPath(path);
|
|
21
|
+
const { dir, name, ext } = parse(relativePath);
|
|
22
|
+
return {
|
|
23
|
+
dir,
|
|
24
|
+
ext,
|
|
25
|
+
importPath: normalizePathSeparator(join(dir, name)),
|
|
26
|
+
name,
|
|
27
|
+
relativePath
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function toKebabCase(name) {
|
|
31
|
+
return name.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/([A-Z])([A-Z][a-z])/g, "$1-$2").toLowerCase();
|
|
32
|
+
}
|
|
33
|
+
async function writeGeneratedFile({ content, path }) {
|
|
34
|
+
try {
|
|
35
|
+
const current = await readFile(path, "utf-8");
|
|
36
|
+
if (current === content) return;
|
|
37
|
+
} catch (error) {}
|
|
38
|
+
await mkdir(dirname(path), {
|
|
39
|
+
recursive: true
|
|
40
|
+
});
|
|
41
|
+
await writeFile(path, content);
|
|
42
|
+
}
|
|
43
|
+
async function removeGeneratedFile({ path, stopPath }) {
|
|
44
|
+
await rm(path, {
|
|
45
|
+
force: true,
|
|
46
|
+
recursive: true
|
|
47
|
+
});
|
|
48
|
+
if (!stopPath) return;
|
|
49
|
+
await removeEmptyDirectories(dirname(path), stopPath);
|
|
50
|
+
}
|
|
51
|
+
async function removeEmptyDirectories(path, stopPath) {
|
|
52
|
+
let currentPath = path;
|
|
53
|
+
while(currentPath !== stopPath && "." !== currentPath && currentPath !== dirname(currentPath)){
|
|
54
|
+
try {
|
|
55
|
+
const content = await readdir(currentPath);
|
|
56
|
+
if (content.length > 0) return;
|
|
57
|
+
} catch (error) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
await rm(currentPath, {
|
|
61
|
+
force: true,
|
|
62
|
+
recursive: true
|
|
63
|
+
});
|
|
64
|
+
currentPath = dirname(currentPath);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export { getSharedModuleInfo, isScriptModule, normalizePathSeparator, normalizeSharedPath, removeGeneratedFile, scriptModuleExtensions, toKebabCase, writeGeneratedFile };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { join } from "path";
|
|
2
|
+
import { createAction } from "./createAction.js";
|
|
3
|
+
import { createRoute } from "./createRoute.js";
|
|
4
|
+
import { getSharedModuleInfo, isScriptModule, normalizeSharedPath, removeGeneratedFile } from "./sharedArtifact.js";
|
|
5
|
+
async function syncSharedArtifacts(path) {
|
|
6
|
+
const info = getSharedModuleInfo(path);
|
|
7
|
+
if (!isScriptModule(info.relativePath)) return;
|
|
8
|
+
await createAction(path);
|
|
9
|
+
await createRoute(path);
|
|
10
|
+
}
|
|
11
|
+
async function removeSharedArtifacts(path) {
|
|
12
|
+
const info = getSharedModuleInfo(path);
|
|
13
|
+
if (!isScriptModule(info.relativePath)) return;
|
|
14
|
+
await removeGeneratedFile({
|
|
15
|
+
path: join("actions", info.relativePath),
|
|
16
|
+
stopPath: "actions"
|
|
17
|
+
});
|
|
18
|
+
await createRoute();
|
|
19
|
+
}
|
|
20
|
+
async function removeSharedArtifactDirectory(path) {
|
|
21
|
+
const relativePath = normalizeSharedPath(path);
|
|
22
|
+
await removeGeneratedFile({
|
|
23
|
+
path: join("actions", relativePath),
|
|
24
|
+
stopPath: "actions"
|
|
25
|
+
});
|
|
26
|
+
await createRoute();
|
|
27
|
+
}
|
|
28
|
+
export { removeSharedArtifactDirectory, removeSharedArtifacts, syncSharedArtifacts };
|
package/dist/utils/watch.js
CHANGED
|
@@ -1,26 +1,10 @@
|
|
|
1
|
-
import { rm } from "fs/promises";
|
|
2
|
-
import { join, relative } from "path";
|
|
3
1
|
import { watch } from "chokidar";
|
|
4
|
-
import {
|
|
2
|
+
import { removeSharedArtifactDirectory, removeSharedArtifacts, syncSharedArtifacts } from "./syncSharedArtifacts.js";
|
|
5
3
|
const watcher = watch("shared", {
|
|
6
4
|
awaitWriteFinish: true,
|
|
7
5
|
persistent: true
|
|
8
6
|
});
|
|
9
|
-
watcher.on("add",
|
|
10
|
-
watcher.on("change",
|
|
11
|
-
watcher.on("unlink",
|
|
12
|
-
|
|
13
|
-
const actionPath = join("actions", path);
|
|
14
|
-
await rm(actionPath, {
|
|
15
|
-
recursive: true,
|
|
16
|
-
force: true
|
|
17
|
-
});
|
|
18
|
-
});
|
|
19
|
-
watcher.on("unlinkDir", async (path)=>{
|
|
20
|
-
path = relative("shared", path).replace(/\\/g, "/");
|
|
21
|
-
const actionPath = join("actions", path);
|
|
22
|
-
await rm(actionPath, {
|
|
23
|
-
recursive: true,
|
|
24
|
-
force: true
|
|
25
|
-
});
|
|
26
|
-
});
|
|
7
|
+
watcher.on("add", syncSharedArtifacts);
|
|
8
|
+
watcher.on("change", syncSharedArtifacts);
|
|
9
|
+
watcher.on("unlink", removeSharedArtifacts);
|
|
10
|
+
watcher.on("unlinkDir", removeSharedArtifactDirectory);
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { readFile } from "fs/promises"
|
|
4
4
|
import { join } from "path"
|
|
5
|
+
import { fileURLToPath } from "url"
|
|
5
6
|
|
|
6
7
|
import { Command } from "commander"
|
|
7
8
|
|
|
@@ -11,11 +12,11 @@ import { hook } from "./utils/hook"
|
|
|
11
12
|
|
|
12
13
|
const program = new Command()
|
|
13
14
|
|
|
14
|
-
const path =
|
|
15
|
+
const path = fileURLToPath(new URL("../", import.meta.url))
|
|
15
16
|
|
|
16
|
-
const
|
|
17
|
+
const packageJson = JSON.parse(await readFile(join(path, "package.json"), "utf-8"))
|
|
17
18
|
|
|
18
|
-
program.name("soda next").version(
|
|
19
|
+
program.name("soda next").version(packageJson.version)
|
|
19
20
|
|
|
20
21
|
program.command("build").allowUnknownOption(true).allowExcessArguments(true).action(build)
|
|
21
22
|
|
package/src/utils/build.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { spawn } from "child_process"
|
|
2
1
|
import { readdir, stat } from "fs/promises"
|
|
3
2
|
import { join } from "path"
|
|
4
3
|
|
|
5
4
|
import { Command } from "commander"
|
|
6
5
|
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
6
|
+
import { runCommand } from "./runCommand"
|
|
7
|
+
import { syncSharedArtifacts } from "./syncSharedArtifacts"
|
|
9
8
|
|
|
10
9
|
export async function buildFolder(dir: string) {
|
|
11
10
|
const content = await readdir(dir)
|
|
@@ -15,19 +14,14 @@ export async function buildFolder(dir: string) {
|
|
|
15
14
|
const stats = await stat(path)
|
|
16
15
|
|
|
17
16
|
if (stats.isDirectory()) await buildFolder(path)
|
|
18
|
-
else await
|
|
17
|
+
else await syncSharedArtifacts(path)
|
|
19
18
|
}
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
export async function build(options: Record<string, string>, { args }: Command) {
|
|
23
|
-
await excludeActions()
|
|
24
|
-
|
|
25
22
|
await buildFolder("shared")
|
|
26
23
|
|
|
27
24
|
if (args.length === 0) return
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
stdio: "inherit",
|
|
31
|
-
shell: true,
|
|
32
|
-
})
|
|
26
|
+
process.exitCode = await runCommand({ args })
|
|
33
27
|
}
|
|
@@ -1,28 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { join } from "path"
|
|
2
|
+
|
|
3
|
+
import { getSharedModuleInfo, isScriptModule, writeGeneratedFile } from "./sharedArtifact"
|
|
3
4
|
|
|
4
5
|
export async function createAction(path: string) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
if (
|
|
6
|
+
const info = getSharedModuleInfo(path)
|
|
7
|
+
|
|
8
|
+
if (!isScriptModule(info.relativePath)) return
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
await writeGeneratedFile({
|
|
11
|
+
path: join("actions", info.relativePath),
|
|
12
|
+
content: `"use server"
|
|
10
13
|
|
|
11
14
|
import { createResponseFn } from "@/server/createResponseFn"
|
|
12
15
|
|
|
13
|
-
import { ${name} } from "@/shared/${
|
|
16
|
+
import { ${info.name} } from "@/shared/${info.importPath}"
|
|
14
17
|
|
|
15
|
-
export const ${name}Action = createResponseFn(${name})
|
|
18
|
+
export const ${info.name}Action = createResponseFn(${info.name})
|
|
16
19
|
`
|
|
17
|
-
|
|
18
|
-
const actionPath = join("actions", path)
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
const current = await readFile(actionPath, "utf-8")
|
|
22
|
-
if (current === content) return
|
|
23
|
-
} catch (error) {}
|
|
24
|
-
|
|
25
|
-
await mkdir(join("actions", dir), { recursive: true })
|
|
26
|
-
|
|
27
|
-
await writeFile(actionPath, content)
|
|
20
|
+
})
|
|
28
21
|
}
|