@kithinji/pod 1.0.23 → 1.0.25
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/dist/main.js +868 -388
- package/dist/main.js.map +4 -4
- package/dist/types/config/config.d.ts +2 -0
- package/dist/types/config/config.d.ts.map +1 -1
- package/dist/types/dev/server.d.ts.map +1 -1
- package/dist/types/html/index.d.ts +22 -0
- package/dist/types/html/index.d.ts.map +1 -0
- package/dist/types/plugins/generators/generate_controller.d.ts.map +1 -1
- package/dist/types/plugins/generators/generate_rpc.d.ts +2 -0
- package/dist/types/plugins/generators/generate_rpc.d.ts.map +1 -0
- package/dist/types/plugins/generators/generate_rsc.d.ts +7 -0
- package/dist/types/plugins/generators/generate_rsc.d.ts.map +1 -1
- package/dist/types/plugins/generators/utils.d.ts +68 -0
- package/dist/types/plugins/generators/utils.d.ts.map +1 -0
- package/dist/types/plugins/transformers/j2d.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -11,7 +11,8 @@ import { Command } from "commander";
|
|
|
11
11
|
// src/dev/server.ts
|
|
12
12
|
import * as esbuild2 from "esbuild";
|
|
13
13
|
import { spawn } from "child_process";
|
|
14
|
-
import * as
|
|
14
|
+
import * as fs6 from "fs/promises";
|
|
15
|
+
import { WebSocketServer, WebSocket } from "ws";
|
|
15
16
|
|
|
16
17
|
// src/config/config.ts
|
|
17
18
|
import * as path from "path";
|
|
@@ -926,20 +927,50 @@ async function expandMacros(source, filePath, projectRoot = process.cwd()) {
|
|
|
926
927
|
|
|
927
928
|
// src/plugins/generators/generate_controller.ts
|
|
928
929
|
import * as path4 from "path";
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
930
|
+
|
|
931
|
+
// src/plugins/generators/utils.ts
|
|
932
|
+
import {
|
|
933
|
+
parseSync
|
|
934
|
+
} from "@swc/core";
|
|
935
|
+
var RETURN_TYPE_CONFIGS = [
|
|
936
|
+
{
|
|
937
|
+
typeName: "Observable",
|
|
938
|
+
isStreamable: true,
|
|
939
|
+
streamType: "Observable" /* Observable */,
|
|
940
|
+
decoratorName: "Sse",
|
|
941
|
+
isSubjectLike: false
|
|
942
|
+
},
|
|
943
|
+
{
|
|
944
|
+
typeName: "Promise",
|
|
945
|
+
isStreamable: false,
|
|
946
|
+
decoratorName: "Post",
|
|
947
|
+
isSubjectLike: false
|
|
948
|
+
}
|
|
949
|
+
];
|
|
950
|
+
function parseTypeScript(filePath, code) {
|
|
951
|
+
return parseSync(code, {
|
|
932
952
|
syntax: "typescript",
|
|
933
|
-
tsx: filePath.endsWith("x"),
|
|
953
|
+
tsx: filePath.endsWith("x") || filePath.endsWith(".tsx"),
|
|
934
954
|
decorators: true
|
|
935
955
|
});
|
|
936
|
-
const serviceInfo = extractServiceInfo(ast);
|
|
937
|
-
if (!serviceInfo || !serviceInfo.hasInjectable) return null;
|
|
938
|
-
return generateControllerCode(serviceInfo, filePath);
|
|
939
956
|
}
|
|
940
|
-
function
|
|
941
|
-
|
|
942
|
-
|
|
957
|
+
function hasInjectableDecorator(decorators) {
|
|
958
|
+
if (!decorators) return false;
|
|
959
|
+
return decorators.some((d) => {
|
|
960
|
+
const expr = d.expression;
|
|
961
|
+
return expr.type === "Identifier" && expr.value === "Injectable" || expr.type === "CallExpression" && expr.callee.type === "Identifier" && expr.callee.value === "Injectable";
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
function isPublicMethod(member) {
|
|
965
|
+
return member.type === "ClassMethod" && (member.accessibility === "public" || !member.accessibility);
|
|
966
|
+
}
|
|
967
|
+
function getMethodName(method) {
|
|
968
|
+
if (method.key.type === "Identifier") {
|
|
969
|
+
return method.key.value;
|
|
970
|
+
}
|
|
971
|
+
return null;
|
|
972
|
+
}
|
|
973
|
+
function extractImportMap(ast) {
|
|
943
974
|
const importMap = {};
|
|
944
975
|
for (const item of ast.body) {
|
|
945
976
|
if (item.type === "ImportDeclaration") {
|
|
@@ -951,55 +982,94 @@ function extractServiceInfo(ast) {
|
|
|
951
982
|
}
|
|
952
983
|
});
|
|
953
984
|
}
|
|
954
|
-
|
|
985
|
+
}
|
|
986
|
+
return importMap;
|
|
987
|
+
}
|
|
988
|
+
function findInjectableClass(ast) {
|
|
989
|
+
for (const item of ast.body) {
|
|
990
|
+
if (item.type === "ExportDeclaration" && item.declaration?.type === "ClassDeclaration") {
|
|
955
991
|
const classDecl = item.declaration;
|
|
956
992
|
if (hasInjectableDecorator(classDecl.decorators)) {
|
|
957
|
-
|
|
958
|
-
hasInjectable = true;
|
|
993
|
+
return classDecl;
|
|
959
994
|
}
|
|
960
995
|
}
|
|
961
996
|
}
|
|
962
|
-
|
|
997
|
+
return null;
|
|
998
|
+
}
|
|
999
|
+
function analyzeReturnType(method) {
|
|
1000
|
+
const returnType = method.function.returnType?.typeAnnotation;
|
|
1001
|
+
if (!returnType) {
|
|
1002
|
+
return {
|
|
1003
|
+
type: "any",
|
|
1004
|
+
isStreamable: false,
|
|
1005
|
+
isSubjectLike: false
|
|
1006
|
+
};
|
|
1007
|
+
}
|
|
1008
|
+
if (returnType.type === "TsTypeReference" && returnType.typeName.type === "Identifier") {
|
|
1009
|
+
const typeName = returnType.typeName.value;
|
|
1010
|
+
const config = RETURN_TYPE_CONFIGS.find((c) => c.typeName === typeName);
|
|
1011
|
+
if (config) {
|
|
1012
|
+
const innerType = returnType.typeParams?.params[0];
|
|
1013
|
+
return {
|
|
1014
|
+
type: innerType ? stringifyType(innerType) : "any",
|
|
1015
|
+
isStreamable: config.isStreamable,
|
|
1016
|
+
streamType: config.streamType,
|
|
1017
|
+
isSubjectLike: config.isSubjectLike
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
963
1021
|
return {
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
importMap
|
|
1022
|
+
type: stringifyType(returnType),
|
|
1023
|
+
isStreamable: false,
|
|
1024
|
+
isSubjectLike: false
|
|
968
1025
|
};
|
|
969
1026
|
}
|
|
970
|
-
function
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1027
|
+
function stringifyType(node) {
|
|
1028
|
+
if (!node) return "any";
|
|
1029
|
+
switch (node.type) {
|
|
1030
|
+
case "TsKeywordType":
|
|
1031
|
+
return node.kind;
|
|
1032
|
+
case "TsTypeReference":
|
|
1033
|
+
if (node.typeName.type !== "Identifier") return "any";
|
|
1034
|
+
const base = node.typeName.value;
|
|
1035
|
+
const args = node.typeParams?.params ? `<${node.typeParams.params.map(stringifyType).join(", ")}>` : "";
|
|
1036
|
+
return base + args;
|
|
1037
|
+
case "TsArrayType":
|
|
1038
|
+
return `${stringifyType(node.elemType)}[]`;
|
|
1039
|
+
case "TsUnionType":
|
|
1040
|
+
return node.types.map(stringifyType).join(" | ");
|
|
1041
|
+
case "TsIntersectionType":
|
|
1042
|
+
return node.types.map(stringifyType).join(" & ");
|
|
1043
|
+
case "TsTypeLiteral":
|
|
1044
|
+
const props = node.members.map((member) => {
|
|
1045
|
+
if (member.type === "TsPropertySignature") {
|
|
1046
|
+
const key = member.key.type === "Identifier" ? member.key.value : "";
|
|
1047
|
+
const type = member.typeAnnotation ? stringifyType(member.typeAnnotation.typeAnnotation) : "any";
|
|
1048
|
+
return `${key}: ${type}`;
|
|
1049
|
+
}
|
|
1050
|
+
return "";
|
|
1051
|
+
}).filter(Boolean);
|
|
1052
|
+
return `{ ${props.join("; ")} }`;
|
|
1053
|
+
default:
|
|
1054
|
+
return "any";
|
|
1055
|
+
}
|
|
975
1056
|
}
|
|
976
|
-
function
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
if (
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
`Server action ${classDecl.identifier.value}.${methodName} must be async.`
|
|
986
|
-
);
|
|
987
|
-
}
|
|
988
|
-
const { paramSchemas, returnSchema } = extractSignature(
|
|
989
|
-
method.function.decorators,
|
|
990
|
-
method.function.params.length
|
|
991
|
-
);
|
|
992
|
-
methods.push({
|
|
993
|
-
name: methodName,
|
|
994
|
-
params: extractMethodParams(method.function.params),
|
|
995
|
-
returnType: extractReturnType(method.function.returnType),
|
|
996
|
-
isAsync: true,
|
|
997
|
-
paramSchemas,
|
|
998
|
-
returnSchema
|
|
999
|
-
});
|
|
1057
|
+
function extractMethodParams(params) {
|
|
1058
|
+
return params.map((p) => {
|
|
1059
|
+
const pat = p.pat;
|
|
1060
|
+
if (pat.type !== "Identifier") {
|
|
1061
|
+
return {
|
|
1062
|
+
name: "param",
|
|
1063
|
+
type: "any",
|
|
1064
|
+
decorators: []
|
|
1065
|
+
};
|
|
1000
1066
|
}
|
|
1001
|
-
|
|
1002
|
-
|
|
1067
|
+
return {
|
|
1068
|
+
name: pat.value,
|
|
1069
|
+
type: pat.typeAnnotation ? stringifyType(pat.typeAnnotation.typeAnnotation) : "any",
|
|
1070
|
+
decorators: []
|
|
1071
|
+
};
|
|
1072
|
+
});
|
|
1003
1073
|
}
|
|
1004
1074
|
function extractSignature(decorators, paramCount) {
|
|
1005
1075
|
if (!decorators) return { paramSchemas: [] };
|
|
@@ -1023,9 +1093,14 @@ function extractSignature(decorators, paramCount) {
|
|
|
1023
1093
|
return { paramSchemas: [] };
|
|
1024
1094
|
}
|
|
1025
1095
|
function stringifyExpression(expr) {
|
|
1026
|
-
if (expr
|
|
1096
|
+
if (!expr) return "any";
|
|
1097
|
+
if (expr.type === "Identifier") {
|
|
1098
|
+
return expr.value;
|
|
1099
|
+
}
|
|
1027
1100
|
if (expr.type === "MemberExpression") {
|
|
1028
|
-
|
|
1101
|
+
const object = stringifyExpression(expr.object);
|
|
1102
|
+
const property = expr.property.value || stringifyExpression(expr.property);
|
|
1103
|
+
return `${object}.${property}`;
|
|
1029
1104
|
}
|
|
1030
1105
|
if (expr.type === "CallExpression") {
|
|
1031
1106
|
const args = expr.arguments.map((a) => stringifyExpression(a.expression)).join(", ");
|
|
@@ -1033,107 +1108,257 @@ function stringifyExpression(expr) {
|
|
|
1033
1108
|
}
|
|
1034
1109
|
return "any";
|
|
1035
1110
|
}
|
|
1036
|
-
function
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1111
|
+
function extractMethods(classDecl, filePath, includeSignatures = true) {
|
|
1112
|
+
const methods = [];
|
|
1113
|
+
const className = classDecl.identifier?.value || "UnknownClass";
|
|
1114
|
+
for (const member of classDecl.body) {
|
|
1115
|
+
if (!isPublicMethod(member)) continue;
|
|
1116
|
+
const method = member;
|
|
1117
|
+
const methodName = getMethodName(method);
|
|
1118
|
+
if (!methodName) continue;
|
|
1119
|
+
const returnTypeInfo = analyzeReturnType(method);
|
|
1120
|
+
if (!returnTypeInfo.isStreamable && !method.function.async) {
|
|
1121
|
+
throw {
|
|
1122
|
+
type: "validation",
|
|
1123
|
+
message: `Method ${className}.${methodName} must be async or return a streamable type (${RETURN_TYPE_CONFIGS.filter(
|
|
1124
|
+
(c) => c.isStreamable
|
|
1125
|
+
).map((c) => c.typeName).join(", ")})`,
|
|
1126
|
+
filePath,
|
|
1127
|
+
details: { className, methodName }
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
const signatures = includeSignatures ? extractSignature(
|
|
1131
|
+
method.function.decorators,
|
|
1132
|
+
method.function.params.length
|
|
1133
|
+
) : { paramSchemas: [] };
|
|
1134
|
+
methods.push({
|
|
1135
|
+
name: methodName,
|
|
1136
|
+
params: extractMethodParams(method.function.params),
|
|
1137
|
+
returnType: returnTypeInfo.type,
|
|
1138
|
+
isAsync: method.function.async,
|
|
1139
|
+
isStreamable: returnTypeInfo.isStreamable,
|
|
1140
|
+
streamType: returnTypeInfo.streamType,
|
|
1141
|
+
paramSchemas: signatures.paramSchemas,
|
|
1142
|
+
returnSchema: signatures.returnSchema
|
|
1143
|
+
});
|
|
1144
|
+
}
|
|
1145
|
+
return methods;
|
|
1146
|
+
}
|
|
1147
|
+
function serviceNameToPath(serviceName) {
|
|
1148
|
+
return serviceName.replace(/Service$/, "").replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
1149
|
+
}
|
|
1150
|
+
function toInstanceName(className) {
|
|
1151
|
+
return className.charAt(0).toLowerCase() + className.slice(1);
|
|
1152
|
+
}
|
|
1153
|
+
function capitalize(str) {
|
|
1154
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
1155
|
+
}
|
|
1156
|
+
function validateServiceInfo(serviceInfo, filePath) {
|
|
1157
|
+
if (!serviceInfo.className) {
|
|
1158
|
+
throw {
|
|
1159
|
+
type: "validation",
|
|
1160
|
+
message: "Service class must have a valid name",
|
|
1161
|
+
filePath
|
|
1043
1162
|
};
|
|
1163
|
+
}
|
|
1164
|
+
if (serviceInfo.methods.length === 0) {
|
|
1165
|
+
console.warn(
|
|
1166
|
+
`Warning: Service ${serviceInfo.className} has no public methods`
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
1169
|
+
serviceInfo.methods.forEach((method) => {
|
|
1170
|
+
if (method.params.length > 0 && method.paramSchemas?.length === 0) {
|
|
1171
|
+
console.warn(
|
|
1172
|
+
`Warning: Method ${serviceInfo.className}.${method.name} has parameters but no @Signature validation`
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1044
1175
|
});
|
|
1045
1176
|
}
|
|
1046
|
-
function
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1177
|
+
function extractServiceInfo(ast, filePath, includeSignatures = true) {
|
|
1178
|
+
try {
|
|
1179
|
+
const serviceClass = findInjectableClass(ast);
|
|
1180
|
+
const importMap = extractImportMap(ast);
|
|
1181
|
+
if (!serviceClass?.identifier) {
|
|
1182
|
+
return null;
|
|
1183
|
+
}
|
|
1184
|
+
return {
|
|
1185
|
+
className: serviceClass.identifier.value,
|
|
1186
|
+
methods: extractMethods(serviceClass, filePath, includeSignatures),
|
|
1187
|
+
hasInjectable: true,
|
|
1188
|
+
importMap
|
|
1189
|
+
};
|
|
1190
|
+
} catch (error) {
|
|
1191
|
+
throw {
|
|
1192
|
+
type: "parse",
|
|
1193
|
+
message: `Failed to extract service info: ${error.message}`,
|
|
1194
|
+
filePath,
|
|
1195
|
+
details: error
|
|
1196
|
+
};
|
|
1051
1197
|
}
|
|
1052
|
-
return stringifyType(type);
|
|
1053
1198
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1199
|
+
|
|
1200
|
+
// src/plugins/generators/generate_controller.ts
|
|
1201
|
+
function generateController(filePath, code) {
|
|
1202
|
+
try {
|
|
1203
|
+
const ast = parseTypeScript(filePath, code);
|
|
1204
|
+
const serviceInfo = extractServiceInfo(ast, filePath, true);
|
|
1205
|
+
if (!serviceInfo || !serviceInfo.hasInjectable) {
|
|
1206
|
+
return null;
|
|
1207
|
+
}
|
|
1208
|
+
validateServiceInfo(serviceInfo, filePath);
|
|
1209
|
+
return generateControllerCode(serviceInfo, filePath);
|
|
1210
|
+
} catch (error) {
|
|
1211
|
+
if (error.type) {
|
|
1212
|
+
throw error;
|
|
1213
|
+
}
|
|
1214
|
+
throw {
|
|
1215
|
+
type: "parse",
|
|
1216
|
+
message: `Failed to parse TypeScript file: ${error.message}`,
|
|
1217
|
+
filePath,
|
|
1218
|
+
details: error
|
|
1219
|
+
};
|
|
1067
1220
|
}
|
|
1068
1221
|
}
|
|
1069
1222
|
function generateControllerCode(serviceInfo, filePath) {
|
|
1070
1223
|
const serviceName = serviceInfo.className;
|
|
1071
|
-
const controllerName = serviceName.replace(/Service$/, "
|
|
1072
|
-
const serviceImportPath =
|
|
1224
|
+
const controllerName = serviceName.replace(/Service$/, "GenController");
|
|
1225
|
+
const serviceImportPath = getImportPath(filePath);
|
|
1226
|
+
const controllerPath = serviceNameToPath(serviceName);
|
|
1227
|
+
const imports = generateImports(serviceInfo, serviceName, serviceImportPath);
|
|
1228
|
+
const methods = generateMethods(serviceInfo);
|
|
1229
|
+
const serviceInstance = toInstanceName(serviceName);
|
|
1230
|
+
return `${imports}
|
|
1231
|
+
|
|
1232
|
+
@Controller("/${controllerPath}", {
|
|
1233
|
+
providedIn: "root",
|
|
1234
|
+
})
|
|
1235
|
+
export class ${controllerName} {
|
|
1236
|
+
constructor(
|
|
1237
|
+
private readonly ${serviceInstance}: ${serviceName}
|
|
1238
|
+
) {}
|
|
1239
|
+
|
|
1240
|
+
${methods}
|
|
1241
|
+
}`;
|
|
1242
|
+
}
|
|
1243
|
+
function getImportPath(filePath) {
|
|
1244
|
+
const basename3 = path4.basename(filePath);
|
|
1245
|
+
return `./${basename3.replace(/\.tsx?$/, "")}`;
|
|
1246
|
+
}
|
|
1247
|
+
function generateImports(serviceInfo, serviceName, serviceImportPath) {
|
|
1073
1248
|
const importGroups = /* @__PURE__ */ new Map();
|
|
1074
1249
|
const registerIdentifier = (id) => {
|
|
1075
1250
|
const source = serviceInfo.importMap[id] || serviceImportPath;
|
|
1076
|
-
if (!importGroups.has(source))
|
|
1251
|
+
if (!importGroups.has(source)) {
|
|
1252
|
+
importGroups.set(source, /* @__PURE__ */ new Set());
|
|
1253
|
+
}
|
|
1077
1254
|
importGroups.get(source).add(id);
|
|
1078
1255
|
};
|
|
1079
1256
|
serviceInfo.methods.forEach((m) => {
|
|
1080
1257
|
[...m.paramSchemas, m.returnSchema].filter(Boolean).forEach((s) => {
|
|
1081
1258
|
const matches = s.match(/[A-Z][a-zA-Z0-9]*/g);
|
|
1082
1259
|
matches?.forEach(registerIdentifier);
|
|
1083
|
-
if (s.includes("z."))
|
|
1260
|
+
if (s.includes("z.")) {
|
|
1261
|
+
registerIdentifier("z");
|
|
1262
|
+
}
|
|
1084
1263
|
});
|
|
1085
1264
|
});
|
|
1086
|
-
|
|
1265
|
+
const hasPost = serviceInfo.methods.some(
|
|
1266
|
+
(m) => !m.isStreamable && m.params.length > 0
|
|
1267
|
+
);
|
|
1268
|
+
const hasGet = serviceInfo.methods.some(
|
|
1269
|
+
(m) => !m.isStreamable && m.params.length === 0
|
|
1270
|
+
);
|
|
1271
|
+
const hasSse = serviceInfo.methods.some(
|
|
1272
|
+
(m) => m.isStreamable && m.streamType == "Observable" /* Observable */
|
|
1273
|
+
);
|
|
1274
|
+
const hasStreamableWithParams = serviceInfo.methods.some(
|
|
1275
|
+
(m) => m.isStreamable && m.params.length > 0
|
|
1276
|
+
);
|
|
1277
|
+
const decorators = ["Controller"];
|
|
1278
|
+
if (hasPost) decorators.push("Post");
|
|
1279
|
+
if (hasGet) decorators.push("Get");
|
|
1280
|
+
if (hasPost) decorators.push("Body");
|
|
1281
|
+
if (hasSse) decorators.push("Sse");
|
|
1282
|
+
if (hasStreamableWithParams) decorators.push("Query");
|
|
1283
|
+
let importStrings = `import { ${decorators.join(
|
|
1284
|
+
", "
|
|
1285
|
+
)} } from "@kithinji/orca";
|
|
1087
1286
|
`;
|
|
1088
1287
|
importGroups.forEach((ids, source) => {
|
|
1089
1288
|
const filteredIds = Array.from(ids).filter((id) => id !== serviceName);
|
|
1090
1289
|
if (filteredIds.length > 0) {
|
|
1091
|
-
importStrings += `
|
|
1092
|
-
import { ${filteredIds.join(
|
|
1290
|
+
importStrings += `import { ${filteredIds.join(
|
|
1093
1291
|
", "
|
|
1094
|
-
)} } from "${source}"
|
|
1095
|
-
}
|
|
1096
|
-
});
|
|
1097
|
-
const methods = serviceInfo.methods.map((m) => {
|
|
1098
|
-
const hasParams = m.params.length > 0;
|
|
1099
|
-
const bodyParam = hasParams ? `@Body() body: any` : "";
|
|
1100
|
-
let body = "";
|
|
1101
|
-
if (hasParams) {
|
|
1102
|
-
if (m.paramSchemas.length > 0) {
|
|
1103
|
-
body += ` const b = typeof body === 'object' && body !== null ? body : {};
|
|
1104
|
-
`;
|
|
1105
|
-
m.params.forEach((p, i) => {
|
|
1106
|
-
body += ` const ${p.name} = ${m.paramSchemas[i]}.parse(b.${p.name});
|
|
1292
|
+
)} } from "${source}";
|
|
1107
1293
|
`;
|
|
1108
|
-
});
|
|
1109
|
-
} else {
|
|
1110
|
-
body += ` const { ${m.params.map((p) => p.name).join(", ")} } = body;
|
|
1111
|
-
`;
|
|
1112
|
-
}
|
|
1113
1294
|
}
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1295
|
+
});
|
|
1296
|
+
return importStrings;
|
|
1297
|
+
}
|
|
1298
|
+
function generateMethods(serviceInfo) {
|
|
1299
|
+
return serviceInfo.methods.map((m) => generateMethod(m, serviceInfo.className)).join("\n\n");
|
|
1300
|
+
}
|
|
1301
|
+
function generateMethod(method, serviceName) {
|
|
1302
|
+
const hasParams = method.params.length > 0;
|
|
1303
|
+
const serviceInstance = toInstanceName(serviceName);
|
|
1304
|
+
if (method.isStreamable) {
|
|
1305
|
+
const queryParams = hasParams ? method.params.map((p) => `@Query('${p.name}') ${p.name}: ${p.type}`).join(", ") : "";
|
|
1306
|
+
const body2 = generateMethodBody(method, serviceInstance, false);
|
|
1307
|
+
const returnTypeName = method.streamType || "Observable";
|
|
1308
|
+
return ` @Sse("${method.name}")
|
|
1309
|
+
${method.name}(${queryParams}): ${returnTypeName}<${method.returnType}> {
|
|
1310
|
+
${body2}
|
|
1311
|
+
}`;
|
|
1312
|
+
}
|
|
1313
|
+
const decorator = hasParams ? "Post" : "Get";
|
|
1314
|
+
const bodyParam = hasParams ? `@Body() body: any` : "";
|
|
1315
|
+
const body = generateMethodBody(method, serviceInstance, true);
|
|
1316
|
+
return ` @${decorator}("${method.name}")
|
|
1317
|
+
async ${method.name}(${bodyParam}): Promise<${method.returnType}> {
|
|
1124
1318
|
${body}
|
|
1125
1319
|
}`;
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
}
|
|
1320
|
+
}
|
|
1321
|
+
function generateMethodBody(method, serviceInstance, isAsync) {
|
|
1322
|
+
const lines = [];
|
|
1323
|
+
const hasParams = method.params.length > 0;
|
|
1324
|
+
if (hasParams && method.isStreamable && method.paramSchemas.length > 0) {
|
|
1325
|
+
method.params.forEach((p, i) => {
|
|
1326
|
+
lines.push(
|
|
1327
|
+
` const validated${capitalize(p.name)} = ${method.paramSchemas[i]}.parse(${p.name});`
|
|
1328
|
+
);
|
|
1329
|
+
});
|
|
1330
|
+
}
|
|
1331
|
+
if (hasParams && !method.isStreamable) {
|
|
1332
|
+
if (method.paramSchemas.length > 0) {
|
|
1333
|
+
lines.push(
|
|
1334
|
+
` const b = typeof body === 'object' && body !== null ? body : {};`
|
|
1335
|
+
);
|
|
1336
|
+
method.params.forEach((p, i) => {
|
|
1337
|
+
lines.push(
|
|
1338
|
+
` const ${p.name} = ${method.paramSchemas[i]}.parse(b.${p.name});`
|
|
1339
|
+
);
|
|
1340
|
+
});
|
|
1341
|
+
} else {
|
|
1342
|
+
const paramNames = method.params.map((p) => p.name).join(", ");
|
|
1343
|
+
lines.push(` const { ${paramNames} } = body || {};`);
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
let callArgs;
|
|
1347
|
+
if (hasParams && method.isStreamable && method.paramSchemas.length > 0) {
|
|
1348
|
+
callArgs = method.params.map((p) => `validated${capitalize(p.name)}`).join(", ");
|
|
1349
|
+
} else {
|
|
1350
|
+
callArgs = method.params.map((p) => p.name).join(", ");
|
|
1351
|
+
}
|
|
1352
|
+
const serviceCall = `${serviceInstance}.${method.name}(${callArgs})`;
|
|
1353
|
+
if (method.returnSchema && isAsync) {
|
|
1354
|
+
lines.push(` const res = await this.${serviceCall};`);
|
|
1355
|
+
lines.push(` return ${method.returnSchema}.parse(res);`);
|
|
1356
|
+
} else if (isAsync) {
|
|
1357
|
+
lines.push(` return this.${serviceCall};`);
|
|
1358
|
+
} else {
|
|
1359
|
+
lines.push(` return this.${serviceCall};`);
|
|
1360
|
+
}
|
|
1361
|
+
return lines.join("\n");
|
|
1137
1362
|
}
|
|
1138
1363
|
|
|
1139
1364
|
// src/plugins/generators/tsx_server_stub.ts
|
|
@@ -1380,7 +1605,7 @@ var NodeTypeGuards = class {
|
|
|
1380
1605
|
isSignalMember(expr) {
|
|
1381
1606
|
return this.t.isMemberExpression(expr) && this.t.isIdentifier(expr.property, { name: "value" });
|
|
1382
1607
|
}
|
|
1383
|
-
|
|
1608
|
+
isBehaviorSubjectMember(expr) {
|
|
1384
1609
|
return this.t.isMemberExpression(expr) && this.t.isIdentifier(expr.property, { name: "$value" });
|
|
1385
1610
|
}
|
|
1386
1611
|
};
|
|
@@ -1390,7 +1615,7 @@ var ASTUtilities = class {
|
|
|
1390
1615
|
this.guards = guards;
|
|
1391
1616
|
}
|
|
1392
1617
|
getObject(expr) {
|
|
1393
|
-
if (this.guards.isSignalMember(expr) || this.guards.
|
|
1618
|
+
if (this.guards.isSignalMember(expr) || this.guards.isBehaviorSubjectMember(expr)) {
|
|
1394
1619
|
return expr.object;
|
|
1395
1620
|
}
|
|
1396
1621
|
return expr;
|
|
@@ -1525,7 +1750,7 @@ var ObservableManager = class {
|
|
|
1525
1750
|
}
|
|
1526
1751
|
collectObservables(node, observables, astUtils) {
|
|
1527
1752
|
this.walkNode(node, (n) => {
|
|
1528
|
-
if (this.guards.
|
|
1753
|
+
if (this.guards.isBehaviorSubjectMember(n)) {
|
|
1529
1754
|
const observable = astUtils.replaceThisWithSelf(
|
|
1530
1755
|
n.object
|
|
1531
1756
|
);
|
|
@@ -1539,7 +1764,7 @@ var ObservableManager = class {
|
|
|
1539
1764
|
replaceObservablesWithSignals(node, observableSignals, astUtils) {
|
|
1540
1765
|
const cloned = this.t.cloneNode(node, true);
|
|
1541
1766
|
this.walkNode(cloned, (n) => {
|
|
1542
|
-
if (this.guards.
|
|
1767
|
+
if (this.guards.isBehaviorSubjectMember(n)) {
|
|
1543
1768
|
const observable = astUtils.replaceThisWithSelf(n.object);
|
|
1544
1769
|
const key = this.getObservableKey(observable);
|
|
1545
1770
|
const signalId = observableSignals.get(key);
|
|
@@ -1662,7 +1887,8 @@ var ElementTransformer = class {
|
|
|
1662
1887
|
elId,
|
|
1663
1888
|
statements,
|
|
1664
1889
|
scope,
|
|
1665
|
-
context2
|
|
1890
|
+
context2,
|
|
1891
|
+
tag
|
|
1666
1892
|
);
|
|
1667
1893
|
if (hasRef && refValue) {
|
|
1668
1894
|
statements.push(
|
|
@@ -1756,7 +1982,7 @@ var ElementTransformer = class {
|
|
|
1756
1982
|
context2.observables,
|
|
1757
1983
|
this.astUtils
|
|
1758
1984
|
);
|
|
1759
|
-
if (this.guards.isSignalMember(expr) || this.guards.
|
|
1985
|
+
if (this.guards.isSignalMember(expr) || this.guards.isBehaviorSubjectMember(expr)) {
|
|
1760
1986
|
const replaced = this.observableManager.replaceObservablesWithSignals(
|
|
1761
1987
|
expr,
|
|
1762
1988
|
context2.observableSignals,
|
|
@@ -1797,11 +2023,13 @@ var ElementTransformer = class {
|
|
|
1797
2023
|
}
|
|
1798
2024
|
}
|
|
1799
2025
|
}
|
|
1800
|
-
processDOMAttributes(attributes, elId, statements, scope, context2) {
|
|
2026
|
+
processDOMAttributes(attributes, elId, statements, scope, context2, tag) {
|
|
1801
2027
|
let hasRef = false;
|
|
1802
2028
|
let refValue = null;
|
|
1803
2029
|
let hasDangerousHTML = false;
|
|
1804
2030
|
let dangerousHTMLValue = null;
|
|
2031
|
+
let hasClickHandler = false;
|
|
2032
|
+
let hrefValue = null;
|
|
1805
2033
|
for (const attr of attributes) {
|
|
1806
2034
|
if (this.t.isJSXSpreadAttribute(attr)) {
|
|
1807
2035
|
this.observableManager.collectObservables(
|
|
@@ -1866,17 +2094,59 @@ var ElementTransformer = class {
|
|
|
1866
2094
|
continue;
|
|
1867
2095
|
}
|
|
1868
2096
|
if (/^on[A-Z]/.test(key)) {
|
|
2097
|
+
if (key === "onClick") {
|
|
2098
|
+
hasClickHandler = true;
|
|
2099
|
+
}
|
|
1869
2100
|
this.processEventListener(key, attr, elId, statements, context2);
|
|
1870
2101
|
continue;
|
|
1871
2102
|
}
|
|
2103
|
+
if (key === "href" && this.t.isStringLiteral(attr.value)) {
|
|
2104
|
+
hrefValue = attr.value.value;
|
|
2105
|
+
}
|
|
1872
2106
|
if (key === "style" && this.t.isJSXExpressionContainer(attr.value)) {
|
|
1873
2107
|
this.processStyleAttribute(attr, elId, statements, scope, context2);
|
|
1874
2108
|
continue;
|
|
1875
2109
|
}
|
|
1876
2110
|
this.processRegularAttribute(key, attr, elId, statements, context2);
|
|
1877
2111
|
}
|
|
2112
|
+
if (tag === "a" && !hasClickHandler && hrefValue && this.isRelativeUrl(hrefValue)) {
|
|
2113
|
+
statements.push(
|
|
2114
|
+
this.t.expressionStatement(
|
|
2115
|
+
this.t.callExpression(
|
|
2116
|
+
this.t.memberExpression(
|
|
2117
|
+
elId,
|
|
2118
|
+
this.t.identifier("addEventListener")
|
|
2119
|
+
),
|
|
2120
|
+
[
|
|
2121
|
+
this.t.stringLiteral("click"),
|
|
2122
|
+
this.t.arrowFunctionExpression(
|
|
2123
|
+
[this.t.identifier("event")],
|
|
2124
|
+
this.t.callExpression(
|
|
2125
|
+
this.t.memberExpression(
|
|
2126
|
+
this.t.identifier("Orca"),
|
|
2127
|
+
this.t.identifier("navigate")
|
|
2128
|
+
),
|
|
2129
|
+
[this.t.identifier("event"), this.t.stringLiteral(hrefValue)]
|
|
2130
|
+
)
|
|
2131
|
+
)
|
|
2132
|
+
]
|
|
2133
|
+
)
|
|
2134
|
+
)
|
|
2135
|
+
);
|
|
2136
|
+
}
|
|
1878
2137
|
return { hasRef, refValue, hasDangerousHTML, dangerousHTMLValue };
|
|
1879
2138
|
}
|
|
2139
|
+
isRelativeUrl(url) {
|
|
2140
|
+
try {
|
|
2141
|
+
new URL(url);
|
|
2142
|
+
return false;
|
|
2143
|
+
} catch {
|
|
2144
|
+
if (url.startsWith("#") || url.startsWith("mailto:") || url.startsWith("tel:")) {
|
|
2145
|
+
return false;
|
|
2146
|
+
}
|
|
2147
|
+
return true;
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
1880
2150
|
processEventListener(key, attr, elId, statements, context2) {
|
|
1881
2151
|
const eventName = key.slice(2).toLowerCase();
|
|
1882
2152
|
let handler = this.t.nullLiteral();
|
|
@@ -2008,7 +2278,7 @@ var ElementTransformer = class {
|
|
|
2008
2278
|
insertedValue = this.astUtils.getObject(
|
|
2009
2279
|
expr
|
|
2010
2280
|
);
|
|
2011
|
-
} else if (this.guards.
|
|
2281
|
+
} else if (this.guards.isBehaviorSubjectMember(expr)) {
|
|
2012
2282
|
const replaced = this.observableManager.replaceObservablesWithSignals(
|
|
2013
2283
|
expr,
|
|
2014
2284
|
context2.observableSignals,
|
|
@@ -2378,7 +2648,7 @@ function extractMethods2(classDecl) {
|
|
|
2378
2648
|
continue;
|
|
2379
2649
|
}
|
|
2380
2650
|
const params = extractMethodParams2(method.function.params || []);
|
|
2381
|
-
const returnType =
|
|
2651
|
+
const returnType = extractReturnType(method.function.returnType);
|
|
2382
2652
|
const isAsync = method.function.async || false;
|
|
2383
2653
|
methods.push({
|
|
2384
2654
|
name: methodName,
|
|
@@ -2407,7 +2677,7 @@ function extractMethodParams2(params) {
|
|
|
2407
2677
|
}
|
|
2408
2678
|
return result;
|
|
2409
2679
|
}
|
|
2410
|
-
function
|
|
2680
|
+
function extractReturnType(returnType) {
|
|
2411
2681
|
if (!returnType || !returnType.typeAnnotation) {
|
|
2412
2682
|
return "any";
|
|
2413
2683
|
}
|
|
@@ -2526,159 +2796,104 @@ ${decoratorsStr}export class ${className} extends _OrcaComponent {
|
|
|
2526
2796
|
}`;
|
|
2527
2797
|
}
|
|
2528
2798
|
|
|
2529
|
-
// src/plugins/generators/
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
}
|
|
2540
|
-
function extractServiceInfo2(ast) {
|
|
2541
|
-
let serviceClass = null;
|
|
2542
|
-
for (const item of ast.body) {
|
|
2543
|
-
if (item.type === "ExportDeclaration" && item.declaration.type === "ClassDeclaration") {
|
|
2544
|
-
const classDecl = item.declaration;
|
|
2545
|
-
if (hasInjectableDecorator2(classDecl.decorators)) {
|
|
2546
|
-
serviceClass = classDecl;
|
|
2547
|
-
break;
|
|
2548
|
-
}
|
|
2549
|
-
}
|
|
2550
|
-
}
|
|
2551
|
-
if (!serviceClass || !serviceClass.identifier) {
|
|
2552
|
-
throw new Error("Service class is undefined");
|
|
2553
|
-
}
|
|
2554
|
-
const className = serviceClass.identifier.value;
|
|
2555
|
-
const methods = extractMethods3(serviceClass);
|
|
2556
|
-
return {
|
|
2557
|
-
className,
|
|
2558
|
-
methods
|
|
2559
|
-
};
|
|
2560
|
-
}
|
|
2561
|
-
function hasInjectableDecorator2(decorators) {
|
|
2562
|
-
if (!decorators) return false;
|
|
2563
|
-
return decorators.some((decorator) => {
|
|
2564
|
-
const expr = decorator.expression;
|
|
2565
|
-
if (expr.type === "CallExpression") {
|
|
2566
|
-
if (expr.callee.type === "Identifier" && expr.callee.value === "Injectable") {
|
|
2567
|
-
return true;
|
|
2568
|
-
}
|
|
2569
|
-
}
|
|
2570
|
-
if (expr.type === "Identifier" && expr.value === "Injectable") {
|
|
2571
|
-
return true;
|
|
2799
|
+
// src/plugins/generators/generate_rpc.ts
|
|
2800
|
+
function generateRpcStub(filePath, code) {
|
|
2801
|
+
try {
|
|
2802
|
+
const ast = parseTypeScript(filePath, code);
|
|
2803
|
+
const serviceInfo = extractServiceInfo(ast, filePath, false);
|
|
2804
|
+
if (!serviceInfo) {
|
|
2805
|
+
throw {
|
|
2806
|
+
type: "validation",
|
|
2807
|
+
message: "No exported class with @Injectable decorator found",
|
|
2808
|
+
filePath
|
|
2809
|
+
};
|
|
2572
2810
|
}
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
}
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
for (const member of classDecl.body) {
|
|
2579
|
-
if (member.type === "ClassMethod" && member.accessibility === "public") {
|
|
2580
|
-
const method = member;
|
|
2581
|
-
const methodName = method.key.type === "Identifier" ? method.key.value : "";
|
|
2582
|
-
if (!methodName) {
|
|
2583
|
-
continue;
|
|
2584
|
-
}
|
|
2585
|
-
if (!method.function.async) {
|
|
2586
|
-
throw new Error(
|
|
2587
|
-
`Server action ${classDecl.identifier.value}.${methodName} must be async.`
|
|
2588
|
-
);
|
|
2589
|
-
}
|
|
2590
|
-
const params = extractMethodParams3(method.function.params || []);
|
|
2591
|
-
const returnType = extractReturnType3(method.function.returnType);
|
|
2592
|
-
const isAsync = method.function.async || false;
|
|
2593
|
-
methods.push({
|
|
2594
|
-
name: methodName,
|
|
2595
|
-
params,
|
|
2596
|
-
returnType,
|
|
2597
|
-
isAsync
|
|
2598
|
-
});
|
|
2811
|
+
validateServiceInfo(serviceInfo, filePath);
|
|
2812
|
+
return generateStubCode2(serviceInfo);
|
|
2813
|
+
} catch (error) {
|
|
2814
|
+
if (error.type) {
|
|
2815
|
+
throw error;
|
|
2599
2816
|
}
|
|
2817
|
+
throw {
|
|
2818
|
+
type: "parse",
|
|
2819
|
+
message: `Failed to parse TypeScript file: ${error.message}`,
|
|
2820
|
+
filePath,
|
|
2821
|
+
details: error
|
|
2822
|
+
};
|
|
2600
2823
|
}
|
|
2601
|
-
return methods;
|
|
2602
2824
|
}
|
|
2603
|
-
function
|
|
2604
|
-
const
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2825
|
+
function generateStubCode2(serviceInfo) {
|
|
2826
|
+
const className = serviceInfo.className;
|
|
2827
|
+
const basePath = serviceNameToPath(className);
|
|
2828
|
+
const methods = serviceInfo.methods.map((method) => generateMethod2(method, basePath, className)).join("\n\n");
|
|
2829
|
+
const hasStreamable = serviceInfo.methods.some((m) => m.isStreamable);
|
|
2830
|
+
const imports = generateImports2(hasStreamable);
|
|
2831
|
+
return `${imports}
|
|
2832
|
+
|
|
2833
|
+
@Injectable()
|
|
2834
|
+
export class ${className} {
|
|
2835
|
+
${methods}
|
|
2836
|
+
}`;
|
|
2837
|
+
}
|
|
2838
|
+
function generateImports2(hasStreamable) {
|
|
2839
|
+
let imports = `import { Injectable } from "@kithinji/orca";
|
|
2840
|
+
`;
|
|
2841
|
+
if (hasStreamable) {
|
|
2842
|
+
imports += `import { Observable } from "@kithinji/orca";
|
|
2843
|
+
`;
|
|
2617
2844
|
}
|
|
2618
|
-
return
|
|
2845
|
+
return imports;
|
|
2619
2846
|
}
|
|
2620
|
-
function
|
|
2621
|
-
if (
|
|
2622
|
-
return
|
|
2847
|
+
function generateMethod2(method, basePath, serviceName) {
|
|
2848
|
+
if (method.isStreamable) {
|
|
2849
|
+
return generateSseMethod(method, basePath);
|
|
2623
2850
|
}
|
|
2624
|
-
const
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
if (type.typeParams && type.typeParams.params.length > 0) {
|
|
2629
|
-
return stringifyType4(type.typeParams.params[0]);
|
|
2630
|
-
}
|
|
2631
|
-
}
|
|
2851
|
+
const params = method.params.map((p) => `${p.name}: ${p.type}`).join(", ");
|
|
2852
|
+
const hasParams = method.params.length > 0;
|
|
2853
|
+
if (!hasParams) {
|
|
2854
|
+
return generateGetMethod(method, basePath);
|
|
2632
2855
|
}
|
|
2633
|
-
return
|
|
2856
|
+
return generatePostMethod(method, basePath, params);
|
|
2634
2857
|
}
|
|
2635
|
-
function
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
return typeNode.types.map(stringifyType4).join(" & ");
|
|
2656
|
-
case "TsTypeLiteral":
|
|
2657
|
-
const props = typeNode.members.map((member) => {
|
|
2658
|
-
if (member.type === "TsPropertySignature") {
|
|
2659
|
-
const key = member.key.type === "Identifier" ? member.key.value : "";
|
|
2660
|
-
const type = member.typeAnnotation ? stringifyType4(member.typeAnnotation.typeAnnotation) : "any";
|
|
2661
|
-
return `${key}: ${type}`;
|
|
2858
|
+
function generateSseMethod(method, basePath) {
|
|
2859
|
+
const params = method.params.map((p) => `${p.name}: ${p.type}`).join(", ");
|
|
2860
|
+
const hasParams = method.params.length > 0;
|
|
2861
|
+
let urlBuilder;
|
|
2862
|
+
if (hasParams) {
|
|
2863
|
+
const queryParams = method.params.map((p) => `${p.name}=\${encodeURIComponent(${p.name})}`).join("&");
|
|
2864
|
+
urlBuilder = `\`/${basePath}/${method.name}?${queryParams}\``;
|
|
2865
|
+
} else {
|
|
2866
|
+
urlBuilder = `\`/${basePath}/${method.name}\``;
|
|
2867
|
+
}
|
|
2868
|
+
return ` ${method.name}(${params}): Observable<${method.returnType}> {
|
|
2869
|
+
return new Observable((observer) => {
|
|
2870
|
+
const eventSource = new EventSource(${urlBuilder});
|
|
2871
|
+
|
|
2872
|
+
eventSource.onmessage = (event) => {
|
|
2873
|
+
try {
|
|
2874
|
+
const data = JSON.parse(event.data);
|
|
2875
|
+
observer.next(data);
|
|
2876
|
+
} catch (error) {
|
|
2877
|
+
observer.error?.(error);
|
|
2662
2878
|
}
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2879
|
+
};
|
|
2880
|
+
|
|
2881
|
+
eventSource.onerror = (error) => {
|
|
2882
|
+
observer.error?.(error);
|
|
2883
|
+
eventSource.close();
|
|
2884
|
+
};
|
|
2885
|
+
|
|
2886
|
+
return () => {
|
|
2887
|
+
eventSource.close();
|
|
2888
|
+
};
|
|
2889
|
+
});
|
|
2890
|
+
}`;
|
|
2669
2891
|
}
|
|
2670
|
-
function
|
|
2671
|
-
const
|
|
2672
|
-
const
|
|
2673
|
-
|
|
2674
|
-
const
|
|
2675
|
-
const asyncKeyword = method.isAsync ? "async " : "";
|
|
2676
|
-
const returnType = method.isAsync ? `Promise<${method.returnType}>` : method.returnType;
|
|
2677
|
-
const hasParams = method.params.length > 0;
|
|
2678
|
-
const bodyParam = hasParams ? `{ ${paramNames} }` : "{}";
|
|
2679
|
-
if (!hasParams) {
|
|
2680
|
-
return ` ${asyncKeyword}${method.name}(${params}): ${returnType} {
|
|
2681
|
-
const response = await fetch(\`/${className}/${method.name}\`, {
|
|
2892
|
+
function generateGetMethod(method, basePath) {
|
|
2893
|
+
const params = method.params.map((p) => `${p.name}: ${p.type}`).join(", ");
|
|
2894
|
+
const returnType = `Promise<${method.returnType}>`;
|
|
2895
|
+
return ` async ${method.name}(${params}): ${returnType} {
|
|
2896
|
+
const response = await fetch(\`/${basePath}/${method.name}\`, {
|
|
2682
2897
|
method: 'GET',
|
|
2683
2898
|
headers: {
|
|
2684
2899
|
'Content-Type': 'application/json',
|
|
@@ -2691,14 +2906,17 @@ function generateStubCode2(serviceInfo) {
|
|
|
2691
2906
|
|
|
2692
2907
|
return response.json();
|
|
2693
2908
|
}`;
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2909
|
+
}
|
|
2910
|
+
function generatePostMethod(method, basePath, params) {
|
|
2911
|
+
const paramNames = method.params.map((p) => p.name).join(", ");
|
|
2912
|
+
const returnType = `Promise<${method.returnType}>`;
|
|
2913
|
+
return ` async ${method.name}(${params}): ${returnType} {
|
|
2914
|
+
const response = await fetch(\`/${basePath}/${method.name}\`, {
|
|
2697
2915
|
method: 'POST',
|
|
2698
2916
|
headers: {
|
|
2699
2917
|
'Content-Type': 'application/json',
|
|
2700
2918
|
},
|
|
2701
|
-
body: JSON.stringify(${
|
|
2919
|
+
body: JSON.stringify({ ${paramNames} }),
|
|
2702
2920
|
});
|
|
2703
2921
|
|
|
2704
2922
|
if (!response.ok) {
|
|
@@ -2707,13 +2925,6 @@ function generateStubCode2(serviceInfo) {
|
|
|
2707
2925
|
|
|
2708
2926
|
return response.json();
|
|
2709
2927
|
}`;
|
|
2710
|
-
}).join("\n\n");
|
|
2711
|
-
return `import { Injectable } from "@kithinji/orca";
|
|
2712
|
-
|
|
2713
|
-
@Injectable()
|
|
2714
|
-
export class ${className} {
|
|
2715
|
-
${methods}
|
|
2716
|
-
}`;
|
|
2717
2928
|
}
|
|
2718
2929
|
|
|
2719
2930
|
// src/plugins/my.ts
|
|
@@ -2830,8 +3041,8 @@ var ClientBuildTransformer = class {
|
|
|
2830
3041
|
const scSource = generateServerComponent(path15, source);
|
|
2831
3042
|
return swcTransform(scSource, path15);
|
|
2832
3043
|
}
|
|
2833
|
-
async
|
|
2834
|
-
const stubSource =
|
|
3044
|
+
async transformPublicFileRpc(node, source, path15) {
|
|
3045
|
+
const stubSource = generateRpcStub(path15, source);
|
|
2835
3046
|
return swcTransform(stubSource, path15);
|
|
2836
3047
|
}
|
|
2837
3048
|
async transformSharedCode(source, path15) {
|
|
@@ -2853,7 +3064,7 @@ var ClientBuildTransformer = class {
|
|
|
2853
3064
|
}
|
|
2854
3065
|
}
|
|
2855
3066
|
if (directive === "public") {
|
|
2856
|
-
return this.
|
|
3067
|
+
return this.transformPublicFileRpc(node, source, path15);
|
|
2857
3068
|
}
|
|
2858
3069
|
if (directive === null) {
|
|
2859
3070
|
return this.transformSharedCode(source, path15);
|
|
@@ -2896,7 +3107,7 @@ function useMyPlugin(options) {
|
|
|
2896
3107
|
}
|
|
2897
3108
|
|
|
2898
3109
|
// src/plugins/analyzers/graph.ts
|
|
2899
|
-
import { parseSync as
|
|
3110
|
+
import { parseSync as parseSync4 } from "@swc/core";
|
|
2900
3111
|
import * as fs3 from "fs";
|
|
2901
3112
|
import * as path7 from "path";
|
|
2902
3113
|
function resolveFilePath(fromFile, importPath) {
|
|
@@ -3044,7 +3255,7 @@ function buildGraph(entryPoints) {
|
|
|
3044
3255
|
const store = Store.getInstance();
|
|
3045
3256
|
const newCode = store.get(filePath);
|
|
3046
3257
|
const content = newCode ? newCode[0] : fs3.readFileSync(filePath, "utf-8");
|
|
3047
|
-
const ast =
|
|
3258
|
+
const ast = parseSync4(content, {
|
|
3048
3259
|
syntax: "typescript",
|
|
3049
3260
|
tsx: isTsx,
|
|
3050
3261
|
decorators: true
|
|
@@ -3112,30 +3323,247 @@ function stylePlugin(store) {
|
|
|
3112
3323
|
};
|
|
3113
3324
|
}
|
|
3114
3325
|
|
|
3326
|
+
// src/html/index.ts
|
|
3327
|
+
import * as fs5 from "fs/promises";
|
|
3328
|
+
var HtmlPreprocessor = class {
|
|
3329
|
+
constructor(options = {}) {
|
|
3330
|
+
this.options = options;
|
|
3331
|
+
}
|
|
3332
|
+
async processFile(inputPath, outputPath) {
|
|
3333
|
+
const html = await fs5.readFile(inputPath, "utf-8");
|
|
3334
|
+
const processed = await this.process(html);
|
|
3335
|
+
await fs5.writeFile(outputPath, processed, "utf-8");
|
|
3336
|
+
}
|
|
3337
|
+
async process(html) {
|
|
3338
|
+
let result = html;
|
|
3339
|
+
if (this.options.transformers) {
|
|
3340
|
+
for (const transformer of this.options.transformers) {
|
|
3341
|
+
result = await transformer(result);
|
|
3342
|
+
}
|
|
3343
|
+
}
|
|
3344
|
+
if (this.options.injectScripts && this.options.injectScripts.length > 0) {
|
|
3345
|
+
result = this.injectScripts(result, this.options.injectScripts);
|
|
3346
|
+
}
|
|
3347
|
+
if (this.options.injectStyles && this.options.injectStyles.length > 0) {
|
|
3348
|
+
result = this.injectStyles(result, this.options.injectStyles);
|
|
3349
|
+
}
|
|
3350
|
+
if (this.options.replaceVariables) {
|
|
3351
|
+
result = this.replaceVariables(result, this.options.replaceVariables);
|
|
3352
|
+
}
|
|
3353
|
+
if (this.options.minify) {
|
|
3354
|
+
result = this.minify(result);
|
|
3355
|
+
}
|
|
3356
|
+
return result;
|
|
3357
|
+
}
|
|
3358
|
+
injectScripts(html, scripts) {
|
|
3359
|
+
const scriptTags = scripts.map((src) => ` <script src="${src}"></script>`).join("\n");
|
|
3360
|
+
if (html.includes("</body>")) {
|
|
3361
|
+
return html.replace("</body>", `${scriptTags}
|
|
3362
|
+
</body>`);
|
|
3363
|
+
} else if (html.includes("</head>")) {
|
|
3364
|
+
return html.replace("</head>", `${scriptTags}
|
|
3365
|
+
</head>`);
|
|
3366
|
+
} else {
|
|
3367
|
+
return html + `
|
|
3368
|
+
${scriptTags}`;
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
injectStyles(html, styles) {
|
|
3372
|
+
const styleTags = styles.map((href) => ` <link rel="stylesheet" href="${href}">`).join("\n");
|
|
3373
|
+
if (html.includes("</head>")) {
|
|
3374
|
+
return html.replace("</head>", `${styleTags}
|
|
3375
|
+
</head>`);
|
|
3376
|
+
} else if (html.includes("<head>")) {
|
|
3377
|
+
return html.replace("<head>", `<head>
|
|
3378
|
+
${styleTags}`);
|
|
3379
|
+
} else {
|
|
3380
|
+
return styleTags + "\n" + html;
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
replaceVariables(html, variables) {
|
|
3384
|
+
let result = html;
|
|
3385
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
3386
|
+
result = result.replace(new RegExp(`\\{\\{${key}\\}\\}`, "g"), value);
|
|
3387
|
+
result = result.replace(new RegExp(`\\$\\{${key}\\}`, "g"), value);
|
|
3388
|
+
}
|
|
3389
|
+
return result;
|
|
3390
|
+
}
|
|
3391
|
+
minify(html) {
|
|
3392
|
+
return html.replace(/<!--[\s\S]*?-->/g, "").replace(/\s+/g, " ").replace(/>\s+</g, "><").trim();
|
|
3393
|
+
}
|
|
3394
|
+
};
|
|
3395
|
+
function createHotReloadTransformer(port) {
|
|
3396
|
+
return (html) => {
|
|
3397
|
+
const hotReloadScript = `
|
|
3398
|
+
<script>
|
|
3399
|
+
(function() {
|
|
3400
|
+
let ws;
|
|
3401
|
+
let reconnectAttempts = 0;
|
|
3402
|
+
const maxReconnectAttempts = 10;
|
|
3403
|
+
|
|
3404
|
+
function connect() {
|
|
3405
|
+
ws = new WebSocket('ws://localhost:${port}');
|
|
3406
|
+
|
|
3407
|
+
ws.onopen = () => {
|
|
3408
|
+
reconnectAttempts = 0;
|
|
3409
|
+
};
|
|
3410
|
+
|
|
3411
|
+
ws.onmessage = (event) => {
|
|
3412
|
+
if (event.data === 'reload') {
|
|
3413
|
+
window.location.reload();
|
|
3414
|
+
}
|
|
3415
|
+
};
|
|
3416
|
+
|
|
3417
|
+
ws.onclose = () => {
|
|
3418
|
+
if (reconnectAttempts < maxReconnectAttempts) {
|
|
3419
|
+
reconnectAttempts++;
|
|
3420
|
+
console.log(\`\u{1F504} Reconnecting... (attempt \${reconnectAttempts}/\${maxReconnectAttempts})\`);
|
|
3421
|
+
setTimeout(connect, 1000 * reconnectAttempts);
|
|
3422
|
+
} else {
|
|
3423
|
+
console.log('\u274C Max reconnection attempts reached');
|
|
3424
|
+
}
|
|
3425
|
+
};
|
|
3426
|
+
|
|
3427
|
+
ws.onerror = (error) => {
|
|
3428
|
+
console.error('\u{1F525} Hot reload error:', error);
|
|
3429
|
+
};
|
|
3430
|
+
}
|
|
3431
|
+
|
|
3432
|
+
connect();
|
|
3433
|
+
})();
|
|
3434
|
+
</script>`;
|
|
3435
|
+
if (html.includes("</body>")) {
|
|
3436
|
+
return html.replace("</body>", `${hotReloadScript}
|
|
3437
|
+
</body>`);
|
|
3438
|
+
}
|
|
3439
|
+
return html + hotReloadScript;
|
|
3440
|
+
};
|
|
3441
|
+
}
|
|
3442
|
+
|
|
3115
3443
|
// src/dev/server.ts
|
|
3116
|
-
|
|
3444
|
+
var virtualClientFiles = {
|
|
3445
|
+
"virtual:navigate": {
|
|
3446
|
+
output: "navigate",
|
|
3447
|
+
code: `
|
|
3448
|
+
export async function navigate(event, url) {
|
|
3449
|
+
event.preventDefault();
|
|
3450
|
+
|
|
3117
3451
|
try {
|
|
3118
|
-
|
|
3119
|
-
|
|
3452
|
+
const { Navigate, getCurrentInjector } = await import("./src/client/client.js");
|
|
3453
|
+
const injector = getCurrentInjector();
|
|
3454
|
+
|
|
3455
|
+
if (injector) {
|
|
3456
|
+
const navigate = injector.resolve(Navigate);
|
|
3457
|
+
navigate.go(url);
|
|
3458
|
+
} else {
|
|
3459
|
+
window.location.href = url;
|
|
3460
|
+
}
|
|
3120
3461
|
} catch (error) {
|
|
3121
|
-
console.error("
|
|
3462
|
+
console.error("Navigation error:", error);
|
|
3463
|
+
window.location.href = url;
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3466
|
+
`.trim()
|
|
3467
|
+
}
|
|
3468
|
+
};
|
|
3469
|
+
function createVirtualModulePlugin(virtualFiles) {
|
|
3470
|
+
return {
|
|
3471
|
+
name: "virtual-module",
|
|
3472
|
+
setup(build) {
|
|
3473
|
+
build.onResolve({ filter: /^virtual:/ }, (args) => {
|
|
3474
|
+
if (virtualFiles[args.path]) {
|
|
3475
|
+
return {
|
|
3476
|
+
path: args.path,
|
|
3477
|
+
namespace: "virtual"
|
|
3478
|
+
};
|
|
3479
|
+
}
|
|
3480
|
+
});
|
|
3481
|
+
build.onLoad({ filter: /.*/, namespace: "virtual" }, (args) => {
|
|
3482
|
+
const virtualFile = virtualFiles[args.path];
|
|
3483
|
+
if (virtualFile) {
|
|
3484
|
+
return {
|
|
3485
|
+
contents: virtualFile.code,
|
|
3486
|
+
loader: "js"
|
|
3487
|
+
};
|
|
3488
|
+
}
|
|
3489
|
+
});
|
|
3490
|
+
}
|
|
3491
|
+
};
|
|
3492
|
+
}
|
|
3493
|
+
var HotReloadManager = class {
|
|
3494
|
+
constructor(port = 3001) {
|
|
3495
|
+
this.wss = null;
|
|
3496
|
+
this.clients = /* @__PURE__ */ new Set();
|
|
3497
|
+
this.port = port;
|
|
3498
|
+
}
|
|
3499
|
+
start() {
|
|
3500
|
+
this.wss = new WebSocketServer({ port: this.port });
|
|
3501
|
+
this.wss.on("connection", (ws) => {
|
|
3502
|
+
this.clients.add(ws);
|
|
3503
|
+
ws.on("close", () => {
|
|
3504
|
+
this.clients.delete(ws);
|
|
3505
|
+
});
|
|
3506
|
+
ws.on("error", (error) => {
|
|
3507
|
+
console.error("WebSocket error:", error);
|
|
3508
|
+
this.clients.delete(ws);
|
|
3509
|
+
});
|
|
3510
|
+
});
|
|
3511
|
+
console.log(`Hot reload server listening on ws://localhost:${this.port}`);
|
|
3512
|
+
}
|
|
3513
|
+
reload() {
|
|
3514
|
+
const activeClients = Array.from(this.clients).filter(
|
|
3515
|
+
(client) => client.readyState === WebSocket.OPEN
|
|
3516
|
+
);
|
|
3517
|
+
if (activeClients.length === 0) {
|
|
3518
|
+
return;
|
|
3519
|
+
}
|
|
3520
|
+
activeClients.forEach((client) => {
|
|
3521
|
+
try {
|
|
3522
|
+
client.send("reload");
|
|
3523
|
+
} catch (error) {
|
|
3524
|
+
console.error("Failed to send reload signal:", error);
|
|
3525
|
+
this.clients.delete(client);
|
|
3526
|
+
}
|
|
3527
|
+
});
|
|
3528
|
+
}
|
|
3529
|
+
close() {
|
|
3530
|
+
if (this.wss) {
|
|
3531
|
+
this.clients.forEach((client) => client.close());
|
|
3532
|
+
this.wss.close();
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
};
|
|
3536
|
+
async function copyAndProcessHtml(hotReloadPort, preprocessorOptions) {
|
|
3537
|
+
try {
|
|
3538
|
+
await fs6.mkdir("public", { recursive: true });
|
|
3539
|
+
const preprocessor = new HtmlPreprocessor({
|
|
3540
|
+
transformers: [createHotReloadTransformer(hotReloadPort)],
|
|
3541
|
+
injectScripts: ["./navigate.js"],
|
|
3542
|
+
...preprocessorOptions
|
|
3543
|
+
});
|
|
3544
|
+
await preprocessor.processFile(
|
|
3545
|
+
"./src/client/index.html",
|
|
3546
|
+
"./public/index.html"
|
|
3547
|
+
);
|
|
3548
|
+
} catch (error) {
|
|
3549
|
+
console.error("Failed to copy and process index.html:", error);
|
|
3122
3550
|
throw error;
|
|
3123
3551
|
}
|
|
3124
3552
|
}
|
|
3125
3553
|
async function cleanDirectories() {
|
|
3126
3554
|
await Promise.all([
|
|
3127
|
-
|
|
3128
|
-
|
|
3555
|
+
fs6.rm("dist", { recursive: true, force: true }),
|
|
3556
|
+
fs6.rm("public", { recursive: true, force: true })
|
|
3129
3557
|
]);
|
|
3130
3558
|
}
|
|
3131
|
-
function createRestartServerPlugin(serverProcess, onServerBuildComplete) {
|
|
3559
|
+
function createRestartServerPlugin(serverProcess, onServerBuildComplete, hotReloadManager) {
|
|
3132
3560
|
return {
|
|
3133
3561
|
name: "restart-server",
|
|
3134
3562
|
setup(build) {
|
|
3135
3563
|
build.onEnd((result) => {
|
|
3136
3564
|
if (result.errors.length > 0) {
|
|
3137
3565
|
console.error(
|
|
3138
|
-
|
|
3566
|
+
`Server build failed with ${result.errors.length} error(s)`
|
|
3139
3567
|
);
|
|
3140
3568
|
return;
|
|
3141
3569
|
}
|
|
@@ -3146,8 +3574,11 @@ function createRestartServerPlugin(serverProcess, onServerBuildComplete) {
|
|
|
3146
3574
|
stdio: "inherit"
|
|
3147
3575
|
});
|
|
3148
3576
|
serverProcess.current.on("error", (err) => {
|
|
3149
|
-
console.error("
|
|
3577
|
+
console.error("Server process error:", err);
|
|
3150
3578
|
});
|
|
3579
|
+
setTimeout(() => {
|
|
3580
|
+
hotReloadManager.reload();
|
|
3581
|
+
}, 500);
|
|
3151
3582
|
onServerBuildComplete();
|
|
3152
3583
|
});
|
|
3153
3584
|
}
|
|
@@ -3157,15 +3588,48 @@ async function startDevServer() {
|
|
|
3157
3588
|
const store = Store.getInstance();
|
|
3158
3589
|
const userConfig = await loadConfig();
|
|
3159
3590
|
const config = mergeConfig(getDefaultConfig(), userConfig);
|
|
3591
|
+
const HOT_RELOAD_PORT = 3001;
|
|
3592
|
+
const hotReloadManager = new HotReloadManager(HOT_RELOAD_PORT);
|
|
3160
3593
|
await cleanDirectories();
|
|
3161
|
-
await
|
|
3594
|
+
await copyAndProcessHtml(HOT_RELOAD_PORT, config.htmlPreprocessor);
|
|
3595
|
+
hotReloadManager.start();
|
|
3162
3596
|
const entryPoints = ["src/main.ts"];
|
|
3163
3597
|
const clientFiles = /* @__PURE__ */ new Set(["src/client/client.tsx"]);
|
|
3164
3598
|
const serverProcessRef = { current: null };
|
|
3165
3599
|
let clientCtx = null;
|
|
3600
|
+
let virtualCtx = null;
|
|
3166
3601
|
let isShuttingDown = false;
|
|
3167
3602
|
let pendingClientFiles = /* @__PURE__ */ new Set();
|
|
3168
3603
|
let needsClientRebuild = false;
|
|
3604
|
+
async function buildVirtualFiles() {
|
|
3605
|
+
if (isShuttingDown) return;
|
|
3606
|
+
try {
|
|
3607
|
+
if (virtualCtx) {
|
|
3608
|
+
await virtualCtx.dispose();
|
|
3609
|
+
virtualCtx = null;
|
|
3610
|
+
}
|
|
3611
|
+
const virtualEntryPoints = {};
|
|
3612
|
+
Object.entries(virtualClientFiles).forEach(([key, value]) => {
|
|
3613
|
+
virtualEntryPoints[value.output] = key;
|
|
3614
|
+
});
|
|
3615
|
+
virtualCtx = await esbuild2.context({
|
|
3616
|
+
entryPoints: virtualEntryPoints,
|
|
3617
|
+
bundle: true,
|
|
3618
|
+
outdir: "public",
|
|
3619
|
+
platform: "browser",
|
|
3620
|
+
format: "iife",
|
|
3621
|
+
globalName: "Orca",
|
|
3622
|
+
sourcemap: config.build?.sourcemap ?? true,
|
|
3623
|
+
minify: config.build?.minify ?? false,
|
|
3624
|
+
plugins: [createVirtualModulePlugin(virtualClientFiles)],
|
|
3625
|
+
write: true
|
|
3626
|
+
});
|
|
3627
|
+
await virtualCtx.rebuild();
|
|
3628
|
+
} catch (error) {
|
|
3629
|
+
console.error("Failed to build virtual files:", error);
|
|
3630
|
+
throw error;
|
|
3631
|
+
}
|
|
3632
|
+
}
|
|
3169
3633
|
async function rebuildClient() {
|
|
3170
3634
|
if (isShuttingDown) return;
|
|
3171
3635
|
try {
|
|
@@ -3185,7 +3649,7 @@ async function startDevServer() {
|
|
|
3185
3649
|
format: "esm",
|
|
3186
3650
|
sourcemap: config.build?.sourcemap ?? true,
|
|
3187
3651
|
splitting: true,
|
|
3188
|
-
minify: config.build?.minify ??
|
|
3652
|
+
minify: config.build?.minify ?? false,
|
|
3189
3653
|
plugins: [
|
|
3190
3654
|
...config.plugins?.map((cb) => cb(store)) || [],
|
|
3191
3655
|
...config.client_plugins?.map((cb) => cb(store)) || [],
|
|
@@ -3201,8 +3665,11 @@ async function startDevServer() {
|
|
|
3201
3665
|
build.onEnd((result) => {
|
|
3202
3666
|
if (result.errors.length > 0) {
|
|
3203
3667
|
console.error(
|
|
3204
|
-
|
|
3668
|
+
`Client build failed with ${result.errors.length} error(s)`
|
|
3205
3669
|
);
|
|
3670
|
+
} else {
|
|
3671
|
+
console.log("Client build completed");
|
|
3672
|
+
hotReloadManager.reload();
|
|
3206
3673
|
}
|
|
3207
3674
|
});
|
|
3208
3675
|
}
|
|
@@ -3214,7 +3681,7 @@ async function startDevServer() {
|
|
|
3214
3681
|
pendingClientFiles.clear();
|
|
3215
3682
|
needsClientRebuild = false;
|
|
3216
3683
|
} catch (error) {
|
|
3217
|
-
console.error("
|
|
3684
|
+
console.error("Failed to rebuild client:", error);
|
|
3218
3685
|
throw error;
|
|
3219
3686
|
}
|
|
3220
3687
|
}
|
|
@@ -3245,13 +3712,18 @@ async function startDevServer() {
|
|
|
3245
3712
|
}
|
|
3246
3713
|
}
|
|
3247
3714
|
}),
|
|
3248
|
-
createRestartServerPlugin(
|
|
3715
|
+
createRestartServerPlugin(
|
|
3716
|
+
serverProcessRef,
|
|
3717
|
+
onServerBuildComplete,
|
|
3718
|
+
hotReloadManager
|
|
3719
|
+
)
|
|
3249
3720
|
],
|
|
3250
3721
|
write: true
|
|
3251
3722
|
});
|
|
3252
3723
|
async function shutdown() {
|
|
3253
3724
|
if (isShuttingDown) return;
|
|
3254
3725
|
isShuttingDown = true;
|
|
3726
|
+
console.log("\nShutting down dev server...");
|
|
3255
3727
|
try {
|
|
3256
3728
|
if (serverProcessRef.current) {
|
|
3257
3729
|
serverProcessRef.current.kill("SIGTERM");
|
|
@@ -3259,14 +3731,19 @@ async function startDevServer() {
|
|
|
3259
3731
|
}
|
|
3260
3732
|
await serverCtx.dispose();
|
|
3261
3733
|
if (clientCtx) await clientCtx.dispose();
|
|
3734
|
+
if (virtualCtx) await virtualCtx.dispose();
|
|
3735
|
+
hotReloadManager.close();
|
|
3736
|
+
console.log("Dev server shut down successfully");
|
|
3262
3737
|
process.exit(0);
|
|
3263
3738
|
} catch (error) {
|
|
3264
|
-
console.error("
|
|
3739
|
+
console.error("Error during shutdown:", error);
|
|
3265
3740
|
process.exit(1);
|
|
3266
3741
|
}
|
|
3267
3742
|
}
|
|
3268
3743
|
process.on("SIGINT", shutdown);
|
|
3269
3744
|
process.on("SIGTERM", shutdown);
|
|
3745
|
+
console.log("Starting dev server...");
|
|
3746
|
+
await buildVirtualFiles();
|
|
3270
3747
|
await serverCtx.watch();
|
|
3271
3748
|
}
|
|
3272
3749
|
|
|
@@ -3279,7 +3756,7 @@ __export(config_exports, {
|
|
|
3279
3756
|
});
|
|
3280
3757
|
|
|
3281
3758
|
// src/add/component/component.ts
|
|
3282
|
-
import * as
|
|
3759
|
+
import * as fs7 from "fs";
|
|
3283
3760
|
import * as path8 from "path";
|
|
3284
3761
|
import * as ts2 from "typescript";
|
|
3285
3762
|
var ComponentDefinition = class {
|
|
@@ -3456,35 +3933,35 @@ Processing dependencies for "${name}": [${component.dependencies.join(
|
|
|
3456
3933
|
);
|
|
3457
3934
|
const componentDir = path8.dirname(componentPath);
|
|
3458
3935
|
const appModulePath = path8.join(process.cwd(), "src/app/app.module.ts");
|
|
3459
|
-
if (!
|
|
3936
|
+
if (!fs7.existsSync(componentModulePath)) {
|
|
3460
3937
|
const moduleDir = path8.dirname(componentModulePath);
|
|
3461
|
-
if (!
|
|
3462
|
-
|
|
3938
|
+
if (!fs7.existsSync(moduleDir)) {
|
|
3939
|
+
fs7.mkdirSync(moduleDir, { recursive: true });
|
|
3463
3940
|
}
|
|
3464
|
-
|
|
3941
|
+
fs7.writeFileSync(componentModulePath, createModule(), "utf-8");
|
|
3465
3942
|
}
|
|
3466
|
-
if (!
|
|
3467
|
-
|
|
3943
|
+
if (!fs7.existsSync(componentDir)) {
|
|
3944
|
+
fs7.mkdirSync(componentDir, { recursive: true });
|
|
3468
3945
|
}
|
|
3469
|
-
if (!
|
|
3470
|
-
|
|
3946
|
+
if (!fs7.existsSync(componentPath)) {
|
|
3947
|
+
fs7.writeFileSync(componentPath, component.generate(), "utf-8");
|
|
3471
3948
|
console.log(`Created ${name}.component.tsx`);
|
|
3472
3949
|
} else {
|
|
3473
3950
|
console.log(`${name}.component.tsx already exists, skipping file creation`);
|
|
3474
3951
|
}
|
|
3475
|
-
const moduleContent =
|
|
3952
|
+
const moduleContent = fs7.readFileSync(componentModulePath, "utf-8");
|
|
3476
3953
|
const updatedModule = updateModuleWithComponent(moduleContent, name);
|
|
3477
|
-
|
|
3478
|
-
if (
|
|
3479
|
-
const appModuleContent =
|
|
3954
|
+
fs7.writeFileSync(componentModulePath, updatedModule, "utf-8");
|
|
3955
|
+
if (fs7.existsSync(appModulePath)) {
|
|
3956
|
+
const appModuleContent = fs7.readFileSync(appModulePath, "utf-8");
|
|
3480
3957
|
const updatedAppModule = ensureComponentModuleImported(appModuleContent);
|
|
3481
3958
|
if (updatedAppModule !== appModuleContent) {
|
|
3482
|
-
|
|
3959
|
+
fs7.writeFileSync(appModulePath, updatedAppModule, "utf-8");
|
|
3483
3960
|
}
|
|
3484
3961
|
}
|
|
3485
3962
|
}
|
|
3486
3963
|
function updateModuleWithComponent(moduleContent, componentName) {
|
|
3487
|
-
const className =
|
|
3964
|
+
const className = capitalize2(componentName);
|
|
3488
3965
|
const importPath = `./component/${componentName}.component`;
|
|
3489
3966
|
const sourceFile = ts2.createSourceFile(
|
|
3490
3967
|
"component.module.ts",
|
|
@@ -3640,7 +4117,7 @@ function ensureComponentModuleImported(appModuleContent) {
|
|
|
3640
4117
|
function ensureInImportsArray(content, sourceFile) {
|
|
3641
4118
|
return addToDecoratorArray(content, sourceFile, "imports", "ComponentModule");
|
|
3642
4119
|
}
|
|
3643
|
-
function
|
|
4120
|
+
function capitalize2(str) {
|
|
3644
4121
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
3645
4122
|
}
|
|
3646
4123
|
function createModule() {
|
|
@@ -3665,12 +4142,12 @@ function toPascalCase(str) {
|
|
|
3665
4142
|
}
|
|
3666
4143
|
|
|
3667
4144
|
// src/utils/create.ts
|
|
3668
|
-
import * as
|
|
4145
|
+
import * as fs8 from "fs";
|
|
3669
4146
|
import * as path9 from "path";
|
|
3670
4147
|
function createStructure(basePath, entry) {
|
|
3671
|
-
|
|
4148
|
+
fs8.mkdirSync(basePath, { recursive: true });
|
|
3672
4149
|
entry.files?.forEach((file) => {
|
|
3673
|
-
|
|
4150
|
+
fs8.writeFileSync(path9.join(basePath, file.name), file.content);
|
|
3674
4151
|
});
|
|
3675
4152
|
entry.dirs?.forEach((dir) => {
|
|
3676
4153
|
const dirPath = path9.join(basePath, dir.name || "");
|
|
@@ -3683,7 +4160,7 @@ import path11 from "path";
|
|
|
3683
4160
|
|
|
3684
4161
|
// src/add/module/module.ts
|
|
3685
4162
|
import * as path10 from "path";
|
|
3686
|
-
import * as
|
|
4163
|
+
import * as fs9 from "fs";
|
|
3687
4164
|
import * as ts3 from "typescript";
|
|
3688
4165
|
function addFeature(name) {
|
|
3689
4166
|
const featureDir = path10.join(process.cwd(), "src", "features", name);
|
|
@@ -3746,8 +4223,8 @@ function updateFeaturesIndex(featureName) {
|
|
|
3746
4223
|
);
|
|
3747
4224
|
const moduleName = toPascalCase(featureName + "_Module");
|
|
3748
4225
|
const importPath = `./${featureName}/${featureName}.module`;
|
|
3749
|
-
if (
|
|
3750
|
-
let content =
|
|
4226
|
+
if (fs9.existsSync(featuresIndexPath)) {
|
|
4227
|
+
let content = fs9.readFileSync(featuresIndexPath, "utf-8");
|
|
3751
4228
|
const sourceFile = ts3.createSourceFile(
|
|
3752
4229
|
"index.ts",
|
|
3753
4230
|
content,
|
|
@@ -3773,24 +4250,24 @@ function updateFeaturesIndex(featureName) {
|
|
|
3773
4250
|
}
|
|
3774
4251
|
const exportStatement = `export { ${moduleName} } from "${importPath}";
|
|
3775
4252
|
`;
|
|
3776
|
-
|
|
4253
|
+
fs9.appendFileSync(featuresIndexPath, exportStatement);
|
|
3777
4254
|
} else {
|
|
3778
4255
|
const featuresDir = path10.dirname(featuresIndexPath);
|
|
3779
|
-
if (!
|
|
3780
|
-
|
|
4256
|
+
if (!fs9.existsSync(featuresDir)) {
|
|
4257
|
+
fs9.mkdirSync(featuresDir, { recursive: true });
|
|
3781
4258
|
}
|
|
3782
4259
|
const exportStatement = `export { ${moduleName} } from "${importPath}";
|
|
3783
4260
|
`;
|
|
3784
|
-
|
|
4261
|
+
fs9.writeFileSync(featuresIndexPath, exportStatement, "utf-8");
|
|
3785
4262
|
}
|
|
3786
4263
|
}
|
|
3787
4264
|
function updateAppModule(featureName) {
|
|
3788
4265
|
const appModulePath = path10.join(process.cwd(), "src", "app", "app.module.ts");
|
|
3789
|
-
if (!
|
|
4266
|
+
if (!fs9.existsSync(appModulePath)) {
|
|
3790
4267
|
return;
|
|
3791
4268
|
}
|
|
3792
4269
|
const moduleName = toPascalCase(featureName + "_Module");
|
|
3793
|
-
let content =
|
|
4270
|
+
let content = fs9.readFileSync(appModulePath, "utf-8");
|
|
3794
4271
|
const sourceFile = ts3.createSourceFile(
|
|
3795
4272
|
"app.module.ts",
|
|
3796
4273
|
content,
|
|
@@ -3814,7 +4291,7 @@ function updateAppModule(featureName) {
|
|
|
3814
4291
|
});
|
|
3815
4292
|
if (hasImport) {
|
|
3816
4293
|
content = addToModuleImportsArray(content, sourceFile, moduleName);
|
|
3817
|
-
|
|
4294
|
+
fs9.writeFileSync(appModulePath, content, "utf-8");
|
|
3818
4295
|
return;
|
|
3819
4296
|
}
|
|
3820
4297
|
let lastImportEnd = 0;
|
|
@@ -3833,7 +4310,7 @@ function updateAppModule(featureName) {
|
|
|
3833
4310
|
true
|
|
3834
4311
|
);
|
|
3835
4312
|
content = addToModuleImportsArray(content, newSourceFile, moduleName);
|
|
3836
|
-
|
|
4313
|
+
fs9.writeFileSync(appModulePath, content, "utf-8");
|
|
3837
4314
|
}
|
|
3838
4315
|
function addToModuleImportsArray(content, sourceFile, moduleName) {
|
|
3839
4316
|
let decoratorNode;
|
|
@@ -4107,24 +4584,19 @@ export class ${serviceName} {
|
|
|
4107
4584
|
}
|
|
4108
4585
|
function createPage(name) {
|
|
4109
4586
|
const pageName = toPascalCase(name + "_Page");
|
|
4110
|
-
const serviceName = toPascalCase(name + "_Service");
|
|
4111
|
-
const serviceVar = toCamelCase(name + "_Service");
|
|
4112
4587
|
const listComponent = toPascalCase(name + "_List");
|
|
4113
4588
|
return `import { Component } from "@kithinji/orca";
|
|
4114
|
-
import { ${serviceName} } from "./${name}.service";
|
|
4115
4589
|
import { ${listComponent} } from "./components/${name}-list.component";
|
|
4116
4590
|
|
|
4117
|
-
@Component(
|
|
4591
|
+
@Component({
|
|
4592
|
+
deps: [${listComponent}]
|
|
4593
|
+
})
|
|
4118
4594
|
export class ${pageName} {
|
|
4119
|
-
constructor(
|
|
4120
|
-
public ${serviceVar}: ${serviceName}
|
|
4121
|
-
) {}
|
|
4122
|
-
|
|
4123
4595
|
build() {
|
|
4124
4596
|
return (
|
|
4125
4597
|
<div>
|
|
4126
4598
|
<h1>${toPascalCase(name)} Management</h1>
|
|
4127
|
-
<${listComponent}
|
|
4599
|
+
<${listComponent} name="hello" />
|
|
4128
4600
|
</div>
|
|
4129
4601
|
);
|
|
4130
4602
|
}
|
|
@@ -4134,6 +4606,7 @@ export class ${pageName} {
|
|
|
4134
4606
|
function createListComponent(name) {
|
|
4135
4607
|
const componentName = toPascalCase(name + "_List");
|
|
4136
4608
|
const serviceName = toPascalCase(name + "_Service");
|
|
4609
|
+
const serviceVar = toCamelCase(name + "_Service");
|
|
4137
4610
|
return `"use interactive";
|
|
4138
4611
|
|
|
4139
4612
|
import { Component } from "@kithinji/orca";
|
|
@@ -4142,9 +4615,13 @@ import { ${serviceName} } from "../${name}.service";
|
|
|
4142
4615
|
@Component()
|
|
4143
4616
|
export class ${componentName} {
|
|
4144
4617
|
props!: {
|
|
4145
|
-
|
|
4618
|
+
name: string;
|
|
4146
4619
|
};
|
|
4147
4620
|
|
|
4621
|
+
constructor(
|
|
4622
|
+
public readonly ${serviceVar}: ${serviceName}
|
|
4623
|
+
) {}
|
|
4624
|
+
|
|
4148
4625
|
build() {
|
|
4149
4626
|
return (
|
|
4150
4627
|
<div>
|
|
@@ -4318,6 +4795,9 @@ export function bootstrap() {
|
|
|
4318
4795
|
}
|
|
4319
4796
|
|
|
4320
4797
|
bootstrap();
|
|
4798
|
+
|
|
4799
|
+
/* Don't modify */
|
|
4800
|
+
export { Navigate, getCurrentInjector } from "@kithinji/orca";
|
|
4321
4801
|
`;
|
|
4322
4802
|
}
|
|
4323
4803
|
function genMainTs() {
|
|
@@ -4340,17 +4820,17 @@ import path14 from "path";
|
|
|
4340
4820
|
import { execSync } from "child_process";
|
|
4341
4821
|
|
|
4342
4822
|
// src/docker/docker.ts
|
|
4343
|
-
import
|
|
4823
|
+
import fs10 from "fs-extra";
|
|
4344
4824
|
import path12 from "path";
|
|
4345
4825
|
import prompts from "prompts";
|
|
4346
4826
|
import yaml from "js-yaml";
|
|
4347
4827
|
async function dockerize(env = "prod") {
|
|
4348
4828
|
const cwd = process.cwd();
|
|
4349
4829
|
const packageJsonPath = path12.join(cwd, "package.json");
|
|
4350
|
-
if (!
|
|
4830
|
+
if (!fs10.existsSync(packageJsonPath)) {
|
|
4351
4831
|
throw new Error("package.json not found. Are you in a Pod project?");
|
|
4352
4832
|
}
|
|
4353
|
-
const packageJson = await
|
|
4833
|
+
const packageJson = await fs10.readJSON(packageJsonPath);
|
|
4354
4834
|
const projectName = packageJson.name;
|
|
4355
4835
|
const detectedServices = detectServices(packageJson);
|
|
4356
4836
|
const selectedServices = await selectServices(detectedServices);
|
|
@@ -4391,30 +4871,30 @@ async function selectServices(detected) {
|
|
|
4391
4871
|
}
|
|
4392
4872
|
async function restructureProject(cwd, projectName) {
|
|
4393
4873
|
const nestedDir = path12.join(cwd, projectName);
|
|
4394
|
-
if (
|
|
4874
|
+
if (fs10.existsSync(nestedDir)) {
|
|
4395
4875
|
console.log("\u26A0\uFE0F Project already restructured, skipping...");
|
|
4396
4876
|
return;
|
|
4397
4877
|
}
|
|
4398
|
-
await
|
|
4399
|
-
const items = await
|
|
4878
|
+
await fs10.ensureDir(nestedDir);
|
|
4879
|
+
const items = await fs10.readdir(cwd);
|
|
4400
4880
|
const toMove = items.filter((item) => item !== projectName);
|
|
4401
4881
|
for (const item of toMove) {
|
|
4402
4882
|
const src = path12.join(cwd, item);
|
|
4403
4883
|
const dest = path12.join(nestedDir, item);
|
|
4404
|
-
await
|
|
4884
|
+
await fs10.move(src, dest, { overwrite: true });
|
|
4405
4885
|
}
|
|
4406
4886
|
const envSrc = path12.join(nestedDir, ".env");
|
|
4407
4887
|
const envDest = path12.join(cwd, ".env");
|
|
4408
|
-
if (
|
|
4409
|
-
await
|
|
4888
|
+
if (fs10.existsSync(envSrc)) {
|
|
4889
|
+
await fs10.move(envSrc, envDest, { overwrite: true });
|
|
4410
4890
|
}
|
|
4411
4891
|
}
|
|
4412
4892
|
async function writeEnvVars(cwd, services, env) {
|
|
4413
4893
|
const envPath = path12.join(cwd, ".env");
|
|
4414
4894
|
let existingEnv = {};
|
|
4415
4895
|
let existingContent = "";
|
|
4416
|
-
if (
|
|
4417
|
-
existingContent = await
|
|
4896
|
+
if (fs10.existsSync(envPath)) {
|
|
4897
|
+
existingContent = await fs10.readFile(envPath, "utf8");
|
|
4418
4898
|
existingEnv = parseEnvFile(existingContent);
|
|
4419
4899
|
}
|
|
4420
4900
|
const newVars = [];
|
|
@@ -4443,7 +4923,7 @@ async function writeEnvVars(cwd, services, env) {
|
|
|
4443
4923
|
if (newVars.length > 0) {
|
|
4444
4924
|
const separator = existingContent && !existingContent.endsWith("\n") ? "\n" : "";
|
|
4445
4925
|
const newContent = existingContent + separator + (existingContent ? "\n" : "") + newVars.join("\n") + "\n";
|
|
4446
|
-
await
|
|
4926
|
+
await fs10.writeFile(envPath, newContent);
|
|
4447
4927
|
console.log(
|
|
4448
4928
|
`\u2705 Added ${newVars.length} new environment variable(s) to .env`
|
|
4449
4929
|
);
|
|
@@ -4539,8 +5019,8 @@ docker-compose*.yml
|
|
|
4539
5019
|
tmp
|
|
4540
5020
|
temp
|
|
4541
5021
|
`;
|
|
4542
|
-
await
|
|
4543
|
-
await
|
|
5022
|
+
await fs10.writeFile(dockerfilePath, dockerfile);
|
|
5023
|
+
await fs10.writeFile(dockerignorePath, dockerignore);
|
|
4544
5024
|
}
|
|
4545
5025
|
async function createDeployfile(cwd, projectName) {
|
|
4546
5026
|
const deployFile = `name: ${projectName}
|
|
@@ -4665,7 +5145,7 @@ targets:
|
|
|
4665
5145
|
docker image prune -af --filter "until=24h"
|
|
4666
5146
|
`;
|
|
4667
5147
|
const deployFilePath = path12.join(cwd, "pod.deploy.yml");
|
|
4668
|
-
await
|
|
5148
|
+
await fs10.writeFile(deployFilePath, deployFile);
|
|
4669
5149
|
}
|
|
4670
5150
|
async function setupProduction(cwd, projectName, services) {
|
|
4671
5151
|
const compose = {
|
|
@@ -4736,7 +5216,7 @@ async function setupProduction(cwd, projectName, services) {
|
|
|
4736
5216
|
compose.services[projectName].depends_on.push(service.name);
|
|
4737
5217
|
}
|
|
4738
5218
|
const composePath = path12.join(cwd, "docker-compose.yml");
|
|
4739
|
-
await
|
|
5219
|
+
await fs10.writeFile(
|
|
4740
5220
|
composePath,
|
|
4741
5221
|
yaml.dump(compose, { indent: 2, lineWidth: -1 })
|
|
4742
5222
|
);
|
|
@@ -4744,8 +5224,8 @@ async function setupProduction(cwd, projectName, services) {
|
|
|
4744
5224
|
async function setupDevelopment(cwd, projectName, services) {
|
|
4745
5225
|
const existingCompose = path12.join(cwd, "docker-compose.yml");
|
|
4746
5226
|
let existingServices = [];
|
|
4747
|
-
if (
|
|
4748
|
-
const content = await
|
|
5227
|
+
if (fs10.existsSync(existingCompose)) {
|
|
5228
|
+
const content = await fs10.readFile(existingCompose, "utf8");
|
|
4749
5229
|
const existing = yaml.load(content);
|
|
4750
5230
|
if (existing.services) {
|
|
4751
5231
|
existingServices = Object.keys(existing.services).filter((s) => ["postgres", "mysql", "redis", "mongodb"].includes(s)).map((name) => ({ name }));
|
|
@@ -4815,14 +5295,14 @@ async function setupDevelopment(cwd, projectName, services) {
|
|
|
4815
5295
|
compose.services[projectName].depends_on.push(tunnelName);
|
|
4816
5296
|
}
|
|
4817
5297
|
const devComposePath = path12.join(cwd, "docker-compose.dev.yml");
|
|
4818
|
-
await
|
|
5298
|
+
await fs10.writeFile(
|
|
4819
5299
|
devComposePath,
|
|
4820
5300
|
yaml.dump(compose, { indent: 2, lineWidth: -1 })
|
|
4821
5301
|
);
|
|
4822
5302
|
}
|
|
4823
5303
|
async function createTunnelService(projectDir, serviceName) {
|
|
4824
5304
|
const tunnelDir = path12.join(projectDir, `${serviceName}-tunnel`);
|
|
4825
|
-
await
|
|
5305
|
+
await fs10.ensureDir(tunnelDir);
|
|
4826
5306
|
const dockerfile = `FROM alpine:latest
|
|
4827
5307
|
|
|
4828
5308
|
RUN apk add --no-cache openssh-client
|
|
@@ -4850,8 +5330,8 @@ ssh -i $SSH_KEY \\
|
|
|
4850
5330
|
-o ServerAliveInterval=60 \\
|
|
4851
5331
|
$REMOTE_HOST
|
|
4852
5332
|
`;
|
|
4853
|
-
await
|
|
4854
|
-
await
|
|
5333
|
+
await fs10.writeFile(path12.join(tunnelDir, "Dockerfile"), dockerfile);
|
|
5334
|
+
await fs10.writeFile(path12.join(tunnelDir, "tunnel.sh"), tunnelScript);
|
|
4855
5335
|
}
|
|
4856
5336
|
function getServiceConfig(serviceName) {
|
|
4857
5337
|
const configs = {
|
|
@@ -4961,7 +5441,7 @@ function printNextSteps(projectName, env, services) {
|
|
|
4961
5441
|
}
|
|
4962
5442
|
|
|
4963
5443
|
// src/deploy/deploy.ts
|
|
4964
|
-
import
|
|
5444
|
+
import fs11 from "fs-extra";
|
|
4965
5445
|
import yaml2 from "js-yaml";
|
|
4966
5446
|
import path13 from "path";
|
|
4967
5447
|
import os from "os";
|
|
@@ -5218,12 +5698,12 @@ STDERR: ${result.stderr}`);
|
|
|
5218
5698
|
}
|
|
5219
5699
|
async uploadContent(remotePath, content) {
|
|
5220
5700
|
const localTmp = path13.join(os.tmpdir(), `pod_tmp_${Date.now()}`);
|
|
5221
|
-
|
|
5701
|
+
fs11.writeFileSync(localTmp, content);
|
|
5222
5702
|
try {
|
|
5223
5703
|
await this.ssh.execCommand(`mkdir -p $(dirname ${remotePath})`);
|
|
5224
5704
|
await this.ssh.putFile(localTmp, remotePath);
|
|
5225
5705
|
} finally {
|
|
5226
|
-
if (
|
|
5706
|
+
if (fs11.existsSync(localTmp)) fs11.unlinkSync(localTmp);
|
|
5227
5707
|
}
|
|
5228
5708
|
}
|
|
5229
5709
|
async readJson(remotePath) {
|
|
@@ -5297,25 +5777,25 @@ STDERR: ${err.stderr || err.message}`
|
|
|
5297
5777
|
os.tmpdir(),
|
|
5298
5778
|
`pod_script_${name}_${Date.now()}.sh`
|
|
5299
5779
|
);
|
|
5300
|
-
|
|
5301
|
-
|
|
5780
|
+
fs11.writeFileSync(scriptPath, interpolated);
|
|
5781
|
+
fs11.chmodSync(scriptPath, "755");
|
|
5302
5782
|
try {
|
|
5303
5783
|
await this.runCommand(scriptPath);
|
|
5304
5784
|
} finally {
|
|
5305
|
-
if (
|
|
5785
|
+
if (fs11.existsSync(scriptPath)) fs11.unlinkSync(scriptPath);
|
|
5306
5786
|
}
|
|
5307
5787
|
}
|
|
5308
5788
|
async uploadContent(localPath, content) {
|
|
5309
5789
|
const dir = path13.dirname(localPath);
|
|
5310
|
-
if (!
|
|
5311
|
-
|
|
5790
|
+
if (!fs11.existsSync(dir)) {
|
|
5791
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
5312
5792
|
}
|
|
5313
|
-
|
|
5793
|
+
fs11.writeFileSync(localPath, content);
|
|
5314
5794
|
}
|
|
5315
5795
|
async readJson(localPath) {
|
|
5316
5796
|
try {
|
|
5317
|
-
if (!
|
|
5318
|
-
const content =
|
|
5797
|
+
if (!fs11.existsSync(localPath)) return null;
|
|
5798
|
+
const content = fs11.readFileSync(localPath, "utf8");
|
|
5319
5799
|
return JSON.parse(content);
|
|
5320
5800
|
} catch {
|
|
5321
5801
|
return null;
|
|
@@ -5323,8 +5803,8 @@ STDERR: ${err.stderr || err.message}`
|
|
|
5323
5803
|
}
|
|
5324
5804
|
async syncDirectory(source, destination, exclude) {
|
|
5325
5805
|
console.log(chalk.gray(` Copying ${source} \u2192 ${destination}`));
|
|
5326
|
-
if (!
|
|
5327
|
-
|
|
5806
|
+
if (!fs11.existsSync(destination)) {
|
|
5807
|
+
fs11.mkdirSync(destination, { recursive: true });
|
|
5328
5808
|
}
|
|
5329
5809
|
const shouldExclude = (relativePath) => {
|
|
5330
5810
|
if (!exclude?.length) return false;
|
|
@@ -5341,19 +5821,19 @@ STDERR: ${err.stderr || err.message}`
|
|
|
5341
5821
|
});
|
|
5342
5822
|
};
|
|
5343
5823
|
const copyRecursive = (src, dest) => {
|
|
5344
|
-
const entries =
|
|
5824
|
+
const entries = fs11.readdirSync(src, { withFileTypes: true });
|
|
5345
5825
|
for (const entry of entries) {
|
|
5346
5826
|
const srcPath = path13.join(src, entry.name);
|
|
5347
5827
|
const destPath = path13.join(dest, entry.name);
|
|
5348
5828
|
const relativePath = path13.relative(source, srcPath);
|
|
5349
5829
|
if (shouldExclude(relativePath)) continue;
|
|
5350
5830
|
if (entry.isDirectory()) {
|
|
5351
|
-
if (!
|
|
5352
|
-
|
|
5831
|
+
if (!fs11.existsSync(destPath)) {
|
|
5832
|
+
fs11.mkdirSync(destPath, { recursive: true });
|
|
5353
5833
|
}
|
|
5354
5834
|
copyRecursive(srcPath, destPath);
|
|
5355
5835
|
} else {
|
|
5356
|
-
|
|
5836
|
+
fs11.copyFileSync(srcPath, destPath);
|
|
5357
5837
|
}
|
|
5358
5838
|
}
|
|
5359
5839
|
};
|
|
@@ -5516,7 +5996,7 @@ var OperationHandler = class {
|
|
|
5516
5996
|
async function deploy(targetName, options) {
|
|
5517
5997
|
const cwd = process.cwd();
|
|
5518
5998
|
const rawConfig = yaml2.load(
|
|
5519
|
-
|
|
5999
|
+
fs11.readFileSync(path13.join(cwd, "pod.deploy.yml"), "utf8"),
|
|
5520
6000
|
{ schema: yaml2.DEFAULT_SCHEMA }
|
|
5521
6001
|
);
|
|
5522
6002
|
const rawTarget = rawConfig.targets?.[targetName];
|
|
@@ -5578,7 +6058,7 @@ Deployment Failed: ${err.message}`));
|
|
|
5578
6058
|
// src/main.ts
|
|
5579
6059
|
import chalk2 from "chalk";
|
|
5580
6060
|
var program = new Command();
|
|
5581
|
-
program.name("pod").description("Pod cli tool").version("1.0.
|
|
6061
|
+
program.name("pod").description("Pod cli tool").version("1.0.24");
|
|
5582
6062
|
program.command("new <name>").description("Start a new Orca Project").action(async (name) => {
|
|
5583
6063
|
await addNew(name);
|
|
5584
6064
|
const appDir = path14.resolve(process.cwd());
|