@kithinji/pod 1.0.43 → 1.0.48
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/index.js +1087 -343
- package/dist/index.js.map +3 -3
- package/dist/types/macros/expand_macros.d.ts.map +1 -1
- package/dist/types/plugins/analyzers/graph.d.ts.map +1 -1
- package/dist/types/plugins/generators/generate_controller.d.ts +5 -1
- package/dist/types/plugins/generators/generate_controller.d.ts.map +1 -1
- package/dist/types/plugins/generators/generate_rpc.d.ts.map +1 -1
- package/dist/types/plugins/generators/utils.d.ts +46 -4
- package/dist/types/plugins/generators/utils.d.ts.map +1 -1
- package/dist/types/plugins/my.d.ts.map +1 -1
- package/dist/types/plugins/transformers/j2d.d.ts.map +1 -1
- package/package.json +6 -6
- package/dist/types/cli.d.ts +0 -3
- package/dist/types/cli.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -500,7 +500,7 @@ function resolveImportFullPath(symbolName, sourceFile, compilerOptions) {
|
|
|
500
500
|
};
|
|
501
501
|
}
|
|
502
502
|
function isNpmPackage(importPath) {
|
|
503
|
-
return !importPath.startsWith(".") && !importPath.startsWith("/") && !path3.isAbsolute(importPath);
|
|
503
|
+
return !importPath.startsWith(".") && !importPath.startsWith("/") && !importPath.startsWith("@/") && !path3.isAbsolute(importPath);
|
|
504
504
|
}
|
|
505
505
|
function findVariableDeclarationInFile(variableName, sourceFile) {
|
|
506
506
|
let found;
|
|
@@ -930,6 +930,7 @@ async function expandMacros(source, filePath, projectRoot = process.cwd()) {
|
|
|
930
930
|
|
|
931
931
|
// src/plugins/generators/generate_controller.ts
|
|
932
932
|
import * as path4 from "path";
|
|
933
|
+
import { printSync } from "@swc/core";
|
|
933
934
|
|
|
934
935
|
// src/plugins/generators/utils.ts
|
|
935
936
|
import {
|
|
@@ -964,8 +965,20 @@ function hasInjectableDecorator(decorators) {
|
|
|
964
965
|
return expr.type === "Identifier" && expr.value === "Injectable" || expr.type === "CallExpression" && expr.callee.type === "Identifier" && expr.callee.value === "Injectable";
|
|
965
966
|
});
|
|
966
967
|
}
|
|
968
|
+
function isClassMethod(member) {
|
|
969
|
+
return member.type === "ClassMethod";
|
|
970
|
+
}
|
|
971
|
+
function isClassProperty(member) {
|
|
972
|
+
return member.type === "ClassProperty";
|
|
973
|
+
}
|
|
974
|
+
function isConstructor(member) {
|
|
975
|
+
return member.type === "Constructor";
|
|
976
|
+
}
|
|
967
977
|
function isPublicMethod(member) {
|
|
968
|
-
return member.type === "ClassMethod" && (member.accessibility === "public" ||
|
|
978
|
+
return member.type === "ClassMethod" && (member.accessibility === "public" || member.accessibility === void 0);
|
|
979
|
+
}
|
|
980
|
+
function isPrivateMethod(member) {
|
|
981
|
+
return member.type === "ClassMethod" && member.accessibility === "private";
|
|
969
982
|
}
|
|
970
983
|
function getMethodName(method) {
|
|
971
984
|
if (method.key.type === "Identifier") {
|
|
@@ -1027,23 +1040,36 @@ function analyzeReturnType(method) {
|
|
|
1027
1040
|
isSubjectLike: false
|
|
1028
1041
|
};
|
|
1029
1042
|
}
|
|
1043
|
+
function stringifyEntityName(node) {
|
|
1044
|
+
if (!node) return "any";
|
|
1045
|
+
switch (node.type) {
|
|
1046
|
+
case "Identifier":
|
|
1047
|
+
return node.value;
|
|
1048
|
+
case "TsQualifiedName":
|
|
1049
|
+
return `${stringifyEntityName(node.left)}.${stringifyEntityName(
|
|
1050
|
+
node.right
|
|
1051
|
+
)}`;
|
|
1052
|
+
default:
|
|
1053
|
+
return "any";
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1030
1056
|
function stringifyType(node) {
|
|
1031
1057
|
if (!node) return "any";
|
|
1032
1058
|
switch (node.type) {
|
|
1033
1059
|
case "TsKeywordType":
|
|
1034
1060
|
return node.kind;
|
|
1035
|
-
case "TsTypeReference":
|
|
1036
|
-
|
|
1037
|
-
const base = node.typeName.value;
|
|
1061
|
+
case "TsTypeReference": {
|
|
1062
|
+
const base = stringifyEntityName(node.typeName);
|
|
1038
1063
|
const args = node.typeParams?.params ? `<${node.typeParams.params.map(stringifyType).join(", ")}>` : "";
|
|
1039
1064
|
return base + args;
|
|
1065
|
+
}
|
|
1040
1066
|
case "TsArrayType":
|
|
1041
1067
|
return `${stringifyType(node.elemType)}[]`;
|
|
1042
1068
|
case "TsUnionType":
|
|
1043
1069
|
return node.types.map(stringifyType).join(" | ");
|
|
1044
1070
|
case "TsIntersectionType":
|
|
1045
1071
|
return node.types.map(stringifyType).join(" & ");
|
|
1046
|
-
case "TsTypeLiteral":
|
|
1072
|
+
case "TsTypeLiteral": {
|
|
1047
1073
|
const props = node.members.map((member) => {
|
|
1048
1074
|
if (member.type === "TsPropertySignature") {
|
|
1049
1075
|
const key = member.key.type === "Identifier" ? member.key.value : "";
|
|
@@ -1053,10 +1079,55 @@ function stringifyType(node) {
|
|
|
1053
1079
|
return "";
|
|
1054
1080
|
}).filter(Boolean);
|
|
1055
1081
|
return `{ ${props.join("; ")} }`;
|
|
1082
|
+
}
|
|
1056
1083
|
default:
|
|
1057
1084
|
return "any";
|
|
1058
1085
|
}
|
|
1059
1086
|
}
|
|
1087
|
+
function stringifyDecorator(decorator) {
|
|
1088
|
+
const expr = decorator.expression;
|
|
1089
|
+
if (expr.type === "Identifier") {
|
|
1090
|
+
return `@${expr.value}`;
|
|
1091
|
+
}
|
|
1092
|
+
if (expr.type === "CallExpression" && expr.callee.type === "Identifier") {
|
|
1093
|
+
const args = expr.arguments.map((arg) => stringifyExpression(arg.expression)).join(", ");
|
|
1094
|
+
return args ? `@${expr.callee.value}(${args})` : `@${expr.callee.value}()`;
|
|
1095
|
+
}
|
|
1096
|
+
return "@Unknown";
|
|
1097
|
+
}
|
|
1098
|
+
function shouldLiftDecorator(decoratorString) {
|
|
1099
|
+
const match = decoratorString.match(/^@(_)?([A-Za-z0-9]+)/);
|
|
1100
|
+
if (!match) return false;
|
|
1101
|
+
const prefix = match[1];
|
|
1102
|
+
return !prefix;
|
|
1103
|
+
}
|
|
1104
|
+
function extractMethodDecorators(method) {
|
|
1105
|
+
const decorators = [];
|
|
1106
|
+
if (method.function.decorators) {
|
|
1107
|
+
for (const decorator of method.function.decorators) {
|
|
1108
|
+
decorators.push(stringifyDecorator(decorator));
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
return decorators;
|
|
1112
|
+
}
|
|
1113
|
+
function extractParamDecorators(param) {
|
|
1114
|
+
const decorators = [];
|
|
1115
|
+
if (param.decorators) {
|
|
1116
|
+
for (const decorator of param.decorators) {
|
|
1117
|
+
decorators.push(stringifyDecorator(decorator));
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
return decorators;
|
|
1121
|
+
}
|
|
1122
|
+
function extractPropertyDecorators(property) {
|
|
1123
|
+
const decorators = [];
|
|
1124
|
+
if (property.decorators) {
|
|
1125
|
+
for (const decorator of property.decorators) {
|
|
1126
|
+
decorators.push(stringifyDecorator(decorator));
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
return decorators;
|
|
1130
|
+
}
|
|
1060
1131
|
function extractMethodParams(params) {
|
|
1061
1132
|
return params.map((p) => {
|
|
1062
1133
|
const pat = p.pat;
|
|
@@ -1064,17 +1135,222 @@ function extractMethodParams(params) {
|
|
|
1064
1135
|
return {
|
|
1065
1136
|
name: "param",
|
|
1066
1137
|
type: "any",
|
|
1067
|
-
decorators:
|
|
1138
|
+
decorators: extractParamDecorators(p)
|
|
1068
1139
|
};
|
|
1069
1140
|
}
|
|
1070
1141
|
return {
|
|
1071
1142
|
name: pat.value,
|
|
1072
1143
|
type: pat.typeAnnotation ? stringifyType(pat.typeAnnotation.typeAnnotation) : "any",
|
|
1073
|
-
decorators:
|
|
1144
|
+
decorators: extractParamDecorators(p)
|
|
1074
1145
|
};
|
|
1075
1146
|
});
|
|
1076
1147
|
}
|
|
1077
|
-
function
|
|
1148
|
+
function extractIdentifiersFromQualifiedName(node) {
|
|
1149
|
+
const identifiers = [];
|
|
1150
|
+
if (node.type === "Identifier") {
|
|
1151
|
+
identifiers.push(node.value);
|
|
1152
|
+
} else if (node.type === "TsQualifiedName") {
|
|
1153
|
+
identifiers.push(...extractIdentifiersFromQualifiedName(node.left));
|
|
1154
|
+
identifiers.push(...extractIdentifiersFromQualifiedName(node.right));
|
|
1155
|
+
}
|
|
1156
|
+
return identifiers;
|
|
1157
|
+
}
|
|
1158
|
+
function extractIdentifiersFromType(node) {
|
|
1159
|
+
if (!node) return [];
|
|
1160
|
+
const identifiers = [];
|
|
1161
|
+
switch (node.type) {
|
|
1162
|
+
case "TsKeywordType":
|
|
1163
|
+
return [];
|
|
1164
|
+
case "TsTypeReference": {
|
|
1165
|
+
if (node.typeName.type === "Identifier") {
|
|
1166
|
+
identifiers.push(node.typeName.value);
|
|
1167
|
+
} else if (node.typeName.type === "TsQualifiedName") {
|
|
1168
|
+
identifiers.push(...extractIdentifiersFromQualifiedName(node.typeName));
|
|
1169
|
+
}
|
|
1170
|
+
if (node.typeParams?.params) {
|
|
1171
|
+
for (const param of node.typeParams.params) {
|
|
1172
|
+
identifiers.push(...extractIdentifiersFromType(param));
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
break;
|
|
1176
|
+
}
|
|
1177
|
+
case "TsArrayType":
|
|
1178
|
+
identifiers.push(...extractIdentifiersFromType(node.elemType));
|
|
1179
|
+
break;
|
|
1180
|
+
case "TsUnionType":
|
|
1181
|
+
case "TsIntersectionType":
|
|
1182
|
+
for (const type of node.types) {
|
|
1183
|
+
identifiers.push(...extractIdentifiersFromType(type));
|
|
1184
|
+
}
|
|
1185
|
+
break;
|
|
1186
|
+
case "TsTypeLiteral":
|
|
1187
|
+
for (const member of node.members) {
|
|
1188
|
+
if (member.type === "TsPropertySignature" && member.typeAnnotation) {
|
|
1189
|
+
identifiers.push(
|
|
1190
|
+
...extractIdentifiersFromType(member.typeAnnotation.typeAnnotation)
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
break;
|
|
1195
|
+
case "TsTupleType":
|
|
1196
|
+
if (node.elemTypes) {
|
|
1197
|
+
for (const elem of node.elemTypes) {
|
|
1198
|
+
identifiers.push(...extractIdentifiersFromType(elem));
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
break;
|
|
1202
|
+
}
|
|
1203
|
+
return identifiers;
|
|
1204
|
+
}
|
|
1205
|
+
function extractIdentifiersFromDecorator(decorator) {
|
|
1206
|
+
const identifiers = [];
|
|
1207
|
+
const expr = decorator.expression;
|
|
1208
|
+
if (expr.type === "Identifier") {
|
|
1209
|
+
identifiers.push(expr.value);
|
|
1210
|
+
} else if (expr.type === "CallExpression") {
|
|
1211
|
+
if (expr.callee.type === "Identifier") {
|
|
1212
|
+
identifiers.push(expr.callee.value);
|
|
1213
|
+
}
|
|
1214
|
+
for (const arg of expr.arguments) {
|
|
1215
|
+
identifiers.push(...extractIdentifiersFromExpression(arg.expression));
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
return identifiers;
|
|
1219
|
+
}
|
|
1220
|
+
function extractIdentifiersFromExpression(expr) {
|
|
1221
|
+
if (!expr) return [];
|
|
1222
|
+
const identifiers = [];
|
|
1223
|
+
switch (expr.type) {
|
|
1224
|
+
case "Identifier":
|
|
1225
|
+
identifiers.push(expr.value);
|
|
1226
|
+
break;
|
|
1227
|
+
case "MemberExpression":
|
|
1228
|
+
identifiers.push(...extractIdentifiersFromExpression(expr.object));
|
|
1229
|
+
if (expr.property.type === "Identifier") {
|
|
1230
|
+
identifiers.push(expr.property.value);
|
|
1231
|
+
}
|
|
1232
|
+
break;
|
|
1233
|
+
case "CallExpression":
|
|
1234
|
+
identifiers.push(...extractIdentifiersFromExpression(expr.callee));
|
|
1235
|
+
for (const arg of expr.arguments) {
|
|
1236
|
+
identifiers.push(...extractIdentifiersFromExpression(arg.expression));
|
|
1237
|
+
}
|
|
1238
|
+
break;
|
|
1239
|
+
}
|
|
1240
|
+
return identifiers;
|
|
1241
|
+
}
|
|
1242
|
+
function resolveImports(identifiers, importMap) {
|
|
1243
|
+
const imports = [];
|
|
1244
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1245
|
+
for (const identifier of identifiers) {
|
|
1246
|
+
if (seen.has(identifier)) continue;
|
|
1247
|
+
const source = importMap[identifier];
|
|
1248
|
+
if (source) {
|
|
1249
|
+
imports.push({ identifier, source });
|
|
1250
|
+
seen.add(identifier);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
return imports;
|
|
1254
|
+
}
|
|
1255
|
+
function extractClassProperties(classDecl, importMap) {
|
|
1256
|
+
const properties = [];
|
|
1257
|
+
if (!classDecl.body || !Array.isArray(classDecl.body)) {
|
|
1258
|
+
return properties;
|
|
1259
|
+
}
|
|
1260
|
+
for (const member of classDecl.body) {
|
|
1261
|
+
if (!isClassProperty(member)) continue;
|
|
1262
|
+
const property = member;
|
|
1263
|
+
if (property.key.type !== "Identifier") continue;
|
|
1264
|
+
const propertyName = property.key.value;
|
|
1265
|
+
const propertyType = property.typeAnnotation ? stringifyType(property.typeAnnotation.typeAnnotation) : "any";
|
|
1266
|
+
const identifiers = [];
|
|
1267
|
+
if (property.typeAnnotation) {
|
|
1268
|
+
identifiers.push(
|
|
1269
|
+
...extractIdentifiersFromType(property.typeAnnotation.typeAnnotation)
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
if (property.decorators) {
|
|
1273
|
+
for (const decorator of property.decorators) {
|
|
1274
|
+
identifiers.push(...extractIdentifiersFromDecorator(decorator));
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
const imports = resolveImports(identifiers, importMap);
|
|
1278
|
+
properties.push({
|
|
1279
|
+
name: propertyName,
|
|
1280
|
+
type: propertyType,
|
|
1281
|
+
isReadonly: property.readonly || false,
|
|
1282
|
+
isStatic: property.isStatic || false,
|
|
1283
|
+
accessibility: property.accessibility,
|
|
1284
|
+
decorators: extractPropertyDecorators(property),
|
|
1285
|
+
hasInitializer: !!property.value,
|
|
1286
|
+
imports
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1289
|
+
return properties;
|
|
1290
|
+
}
|
|
1291
|
+
function extractConstructorParams(classDecl, importMap) {
|
|
1292
|
+
const params = [];
|
|
1293
|
+
if (!classDecl.body || !Array.isArray(classDecl.body)) {
|
|
1294
|
+
return params;
|
|
1295
|
+
}
|
|
1296
|
+
for (const member of classDecl.body) {
|
|
1297
|
+
if (!isConstructor(member)) continue;
|
|
1298
|
+
const constructor = member;
|
|
1299
|
+
for (const param of constructor.params) {
|
|
1300
|
+
if (param.type === "TsParameterProperty") {
|
|
1301
|
+
const tsParam = param;
|
|
1302
|
+
const pat = tsParam.param;
|
|
1303
|
+
if (pat.type !== "Identifier") continue;
|
|
1304
|
+
const identifiers = [];
|
|
1305
|
+
if (pat.typeAnnotation) {
|
|
1306
|
+
identifiers.push(
|
|
1307
|
+
...extractIdentifiersFromType(pat.typeAnnotation.typeAnnotation)
|
|
1308
|
+
);
|
|
1309
|
+
}
|
|
1310
|
+
if (tsParam.decorators) {
|
|
1311
|
+
for (const decorator of tsParam.decorators) {
|
|
1312
|
+
identifiers.push(...extractIdentifiersFromDecorator(decorator));
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
const imports = resolveImports(identifiers, importMap);
|
|
1316
|
+
params.push({
|
|
1317
|
+
name: pat.value,
|
|
1318
|
+
type: pat.typeAnnotation ? stringifyType(pat.typeAnnotation.typeAnnotation) : "any",
|
|
1319
|
+
accessibility: tsParam.accessibility,
|
|
1320
|
+
isReadonly: tsParam.readonly || false,
|
|
1321
|
+
decorators: extractParamDecorators(tsParam),
|
|
1322
|
+
imports
|
|
1323
|
+
});
|
|
1324
|
+
} else if (param.type === "Parameter") {
|
|
1325
|
+
const regularParam = param;
|
|
1326
|
+
const pat = regularParam.pat;
|
|
1327
|
+
if (pat.type !== "Identifier") continue;
|
|
1328
|
+
const identifiers = [];
|
|
1329
|
+
if (pat.typeAnnotation) {
|
|
1330
|
+
identifiers.push(
|
|
1331
|
+
...extractIdentifiersFromType(pat.typeAnnotation.typeAnnotation)
|
|
1332
|
+
);
|
|
1333
|
+
}
|
|
1334
|
+
if (regularParam.decorators) {
|
|
1335
|
+
for (const decorator of regularParam.decorators) {
|
|
1336
|
+
identifiers.push(...extractIdentifiersFromDecorator(decorator));
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
const imports = resolveImports(identifiers, importMap);
|
|
1340
|
+
params.push({
|
|
1341
|
+
name: pat.value,
|
|
1342
|
+
type: pat.typeAnnotation ? stringifyType(pat.typeAnnotation.typeAnnotation) : "any",
|
|
1343
|
+
accessibility: void 0,
|
|
1344
|
+
isReadonly: false,
|
|
1345
|
+
decorators: extractParamDecorators(regularParam),
|
|
1346
|
+
imports
|
|
1347
|
+
});
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
return params;
|
|
1352
|
+
}
|
|
1353
|
+
function extractSignature(decorators, paramCount, className, methodName, filePath) {
|
|
1078
1354
|
if (!decorators) return { paramSchemas: [] };
|
|
1079
1355
|
for (const decorator of decorators) {
|
|
1080
1356
|
const expr = decorator.expression;
|
|
@@ -1084,6 +1360,14 @@ function extractSignature(decorators, paramCount) {
|
|
|
1084
1360
|
const schemaStrings = args.map(
|
|
1085
1361
|
(arg) => stringifyExpression(arg.expression)
|
|
1086
1362
|
);
|
|
1363
|
+
if (paramCount === 0 && args.length === 1) {
|
|
1364
|
+
return { paramSchemas: [], returnSchema: schemaStrings[0] };
|
|
1365
|
+
}
|
|
1366
|
+
if (args.length !== paramCount + 1) {
|
|
1367
|
+
console.warn(
|
|
1368
|
+
`Warning: Method ${className}.${methodName} has ${paramCount} parameter(s) but @Signature has ${args.length} argument(s). Expected ${paramCount + 1} (${paramCount} param schema(s) + 1 return schema).`
|
|
1369
|
+
);
|
|
1370
|
+
}
|
|
1087
1371
|
if (args.length === 1) {
|
|
1088
1372
|
return { paramSchemas: [], returnSchema: schemaStrings[0] };
|
|
1089
1373
|
}
|
|
@@ -1111,15 +1395,36 @@ function stringifyExpression(expr) {
|
|
|
1111
1395
|
}
|
|
1112
1396
|
return "any";
|
|
1113
1397
|
}
|
|
1114
|
-
function extractMethods(classDecl, filePath, includeSignatures = true) {
|
|
1398
|
+
function extractMethods(classDecl, filePath, includeSignatures = true, includeHeaders = false) {
|
|
1115
1399
|
const methods = [];
|
|
1116
1400
|
const className = classDecl.identifier?.value || "UnknownClass";
|
|
1401
|
+
if (!classDecl.body || !Array.isArray(classDecl.body)) {
|
|
1402
|
+
return methods;
|
|
1403
|
+
}
|
|
1117
1404
|
for (const member of classDecl.body) {
|
|
1118
|
-
if (!
|
|
1405
|
+
if (!isClassMethod(member)) continue;
|
|
1119
1406
|
const method = member;
|
|
1120
1407
|
const methodName = getMethodName(method);
|
|
1121
1408
|
if (!methodName) continue;
|
|
1409
|
+
const endsWithHeaders = methodName.endsWith("Headers");
|
|
1122
1410
|
const returnTypeInfo = analyzeReturnType(method);
|
|
1411
|
+
if (isPrivateMethod(member) && includeHeaders && endsWithHeaders) {
|
|
1412
|
+
methods.push({
|
|
1413
|
+
name: methodName,
|
|
1414
|
+
params: extractMethodParams(method.function.params),
|
|
1415
|
+
returnType: returnTypeInfo.type,
|
|
1416
|
+
isAsync: method.function.async,
|
|
1417
|
+
isStreamable: returnTypeInfo.isStreamable,
|
|
1418
|
+
streamType: returnTypeInfo.streamType,
|
|
1419
|
+
paramSchemas: [],
|
|
1420
|
+
returnSchema: void 0,
|
|
1421
|
+
decorators: void 0,
|
|
1422
|
+
lift: true,
|
|
1423
|
+
ast: method
|
|
1424
|
+
});
|
|
1425
|
+
continue;
|
|
1426
|
+
}
|
|
1427
|
+
if (!isPublicMethod(member)) continue;
|
|
1123
1428
|
if (!returnTypeInfo.isStreamable && !method.function.async) {
|
|
1124
1429
|
throw {
|
|
1125
1430
|
type: "validation",
|
|
@@ -1132,7 +1437,10 @@ function extractMethods(classDecl, filePath, includeSignatures = true) {
|
|
|
1132
1437
|
}
|
|
1133
1438
|
const signatures = includeSignatures ? extractSignature(
|
|
1134
1439
|
method.function.decorators,
|
|
1135
|
-
method.function.params.length
|
|
1440
|
+
method.function.params.length,
|
|
1441
|
+
className,
|
|
1442
|
+
methodName,
|
|
1443
|
+
filePath
|
|
1136
1444
|
) : { paramSchemas: [] };
|
|
1137
1445
|
methods.push({
|
|
1138
1446
|
name: methodName,
|
|
@@ -1142,11 +1450,41 @@ function extractMethods(classDecl, filePath, includeSignatures = true) {
|
|
|
1142
1450
|
isStreamable: returnTypeInfo.isStreamable,
|
|
1143
1451
|
streamType: returnTypeInfo.streamType,
|
|
1144
1452
|
paramSchemas: signatures.paramSchemas,
|
|
1145
|
-
returnSchema: signatures.returnSchema
|
|
1453
|
+
returnSchema: signatures.returnSchema,
|
|
1454
|
+
decorators: extractMethodDecorators(method),
|
|
1455
|
+
lift: false,
|
|
1456
|
+
ast: method
|
|
1146
1457
|
});
|
|
1147
1458
|
}
|
|
1148
1459
|
return methods;
|
|
1149
1460
|
}
|
|
1461
|
+
function removeLiftedDecoratorsFromAST(ast) {
|
|
1462
|
+
const clonedAst = JSON.parse(JSON.stringify(ast));
|
|
1463
|
+
for (const item of clonedAst.body) {
|
|
1464
|
+
if (item.type === "ExportDeclaration" && item.declaration?.type === "ClassDeclaration") {
|
|
1465
|
+
const classDecl = item.declaration;
|
|
1466
|
+
if (hasInjectableDecorator(classDecl.decorators)) {
|
|
1467
|
+
for (const member of classDecl.body) {
|
|
1468
|
+
if (member.type === "ClassMethod" && (member.accessibility === "public" || member.accessibility === void 0)) {
|
|
1469
|
+
const method = member;
|
|
1470
|
+
if (method.function.decorators) {
|
|
1471
|
+
method.function.decorators = method.function.decorators.filter(
|
|
1472
|
+
(decorator) => {
|
|
1473
|
+
const decoratorStr = stringifyDecorator(decorator);
|
|
1474
|
+
return !shouldLiftDecorator(decoratorStr);
|
|
1475
|
+
}
|
|
1476
|
+
);
|
|
1477
|
+
if (method.function.decorators.length === 0) {
|
|
1478
|
+
delete method.function.decorators;
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
return clonedAst;
|
|
1487
|
+
}
|
|
1150
1488
|
function serviceNameToPath(serviceName) {
|
|
1151
1489
|
return serviceName.replace(/Service$/, "").replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
1152
1490
|
}
|
|
@@ -1170,23 +1508,43 @@ function validateServiceInfo(serviceInfo, filePath) {
|
|
|
1170
1508
|
);
|
|
1171
1509
|
}
|
|
1172
1510
|
serviceInfo.methods.forEach((method) => {
|
|
1173
|
-
if (method.params.length > 0 && method.paramSchemas?.length === 0) {
|
|
1511
|
+
if (method.params.length > 0 && method.paramSchemas?.length === 0 && !method.returnSchema) {
|
|
1174
1512
|
console.warn(
|
|
1175
|
-
`Warning: Method ${serviceInfo.className}.${method.name} has
|
|
1513
|
+
`Warning: Method ${serviceInfo.className}.${method.name} has ${method.params.length} parameter(s) but no @Signature validation`
|
|
1176
1514
|
);
|
|
1177
1515
|
}
|
|
1178
1516
|
});
|
|
1179
1517
|
}
|
|
1180
|
-
function extractServiceInfo(ast, filePath, includeSignatures = true) {
|
|
1518
|
+
function extractServiceInfo(ast, filePath, includeSignatures = true, includeHeaders = false, includeFields = false) {
|
|
1181
1519
|
try {
|
|
1182
1520
|
const serviceClass = findInjectableClass(ast);
|
|
1183
1521
|
const importMap = extractImportMap(ast);
|
|
1184
1522
|
if (!serviceClass?.identifier) {
|
|
1185
1523
|
return null;
|
|
1186
1524
|
}
|
|
1525
|
+
if (!serviceClass.body) {
|
|
1526
|
+
console.warn(
|
|
1527
|
+
`Warning: Service class ${serviceClass.identifier.value} has no body`
|
|
1528
|
+
);
|
|
1529
|
+
return {
|
|
1530
|
+
className: serviceClass.identifier.value,
|
|
1531
|
+
methods: [],
|
|
1532
|
+
properties: [],
|
|
1533
|
+
constructorParams: [],
|
|
1534
|
+
hasInjectable: true,
|
|
1535
|
+
importMap
|
|
1536
|
+
};
|
|
1537
|
+
}
|
|
1187
1538
|
return {
|
|
1188
1539
|
className: serviceClass.identifier.value,
|
|
1189
|
-
methods: extractMethods(
|
|
1540
|
+
methods: extractMethods(
|
|
1541
|
+
serviceClass,
|
|
1542
|
+
filePath,
|
|
1543
|
+
includeSignatures,
|
|
1544
|
+
includeHeaders
|
|
1545
|
+
),
|
|
1546
|
+
properties: includeFields ? extractClassProperties(serviceClass, importMap) : [],
|
|
1547
|
+
constructorParams: includeFields ? extractConstructorParams(serviceClass, importMap) : [],
|
|
1190
1548
|
hasInjectable: true,
|
|
1191
1549
|
importMap
|
|
1192
1550
|
};
|
|
@@ -1204,12 +1562,18 @@ function extractServiceInfo(ast, filePath, includeSignatures = true) {
|
|
|
1204
1562
|
function generateController(filePath, code) {
|
|
1205
1563
|
try {
|
|
1206
1564
|
const ast = parseTypeScript(filePath, code);
|
|
1207
|
-
const serviceInfo = extractServiceInfo(ast, filePath, true);
|
|
1565
|
+
const serviceInfo = extractServiceInfo(ast, filePath, true, false);
|
|
1208
1566
|
if (!serviceInfo || !serviceInfo.hasInjectable) {
|
|
1209
1567
|
return null;
|
|
1210
1568
|
}
|
|
1211
1569
|
validateServiceInfo(serviceInfo, filePath);
|
|
1212
|
-
|
|
1570
|
+
const transformedAst = removeLiftedDecoratorsFromAST(ast);
|
|
1571
|
+
const transformedServiceCode = printSync(transformedAst).code;
|
|
1572
|
+
const controllerCode = generateControllerCode(serviceInfo, filePath);
|
|
1573
|
+
return {
|
|
1574
|
+
controllerCode,
|
|
1575
|
+
transformedServiceCode
|
|
1576
|
+
};
|
|
1213
1577
|
} catch (error) {
|
|
1214
1578
|
if (error.type) {
|
|
1215
1579
|
throw error;
|
|
@@ -1232,7 +1596,7 @@ function generateControllerCode(serviceInfo, filePath) {
|
|
|
1232
1596
|
const serviceInstance = toInstanceName(serviceName);
|
|
1233
1597
|
return `${imports}
|
|
1234
1598
|
|
|
1235
|
-
@Controller("/${controllerPath}", {
|
|
1599
|
+
@Controller("/api/${controllerPath}", {
|
|
1236
1600
|
providedIn: "root",
|
|
1237
1601
|
})
|
|
1238
1602
|
export class ${controllerName} {
|
|
@@ -1277,16 +1641,40 @@ function generateImports(serviceInfo, serviceName, serviceImportPath) {
|
|
|
1277
1641
|
const hasStreamableWithParams = serviceInfo.methods.some(
|
|
1278
1642
|
(m) => m.isStreamable && m.params.length > 0
|
|
1279
1643
|
);
|
|
1280
|
-
const
|
|
1644
|
+
const hasFileUpload = serviceInfo.methods.some((m) => hasMulterFileParams(m));
|
|
1645
|
+
const hasSingleFileUpload = serviceInfo.methods.some(
|
|
1646
|
+
(m) => getFileParams(m).length === 1 && !isArrayFileParam(getFileParams(m)[0])
|
|
1647
|
+
);
|
|
1648
|
+
const hasMultipleFilesUpload = serviceInfo.methods.some(
|
|
1649
|
+
(m) => getFileParams(m).length === 1 && isArrayFileParam(getFileParams(m)[0])
|
|
1650
|
+
);
|
|
1651
|
+
const hasMultipleFileFields = serviceInfo.methods.some(
|
|
1652
|
+
(m) => getFileParams(m).length > 1
|
|
1653
|
+
);
|
|
1654
|
+
const decorators = ["Controller", "Req"];
|
|
1281
1655
|
if (hasPost) decorators.push("Post");
|
|
1282
1656
|
if (hasGet) decorators.push("Get");
|
|
1283
1657
|
if (hasPost) decorators.push("Body");
|
|
1284
1658
|
if (hasSse) decorators.push("Sse");
|
|
1285
1659
|
if (hasStreamableWithParams) decorators.push("Query");
|
|
1660
|
+
if (hasFileUpload) decorators.push("UseInterceptors");
|
|
1661
|
+
if (hasSingleFileUpload) decorators.push("UploadedFile");
|
|
1662
|
+
if (hasMultipleFilesUpload || hasMultipleFileFields)
|
|
1663
|
+
decorators.push("UploadedFiles");
|
|
1286
1664
|
let importStrings = `import { ${decorators.join(
|
|
1287
1665
|
", "
|
|
1288
1666
|
)} } from "@kithinji/orca";
|
|
1289
1667
|
`;
|
|
1668
|
+
if (hasFileUpload) {
|
|
1669
|
+
const interceptors = [];
|
|
1670
|
+
if (hasSingleFileUpload) interceptors.push("FileInterceptor");
|
|
1671
|
+
if (hasMultipleFilesUpload) interceptors.push("FilesInterceptor");
|
|
1672
|
+
if (hasMultipleFileFields) interceptors.push("FileFieldsInterceptor");
|
|
1673
|
+
importStrings += `import { ${interceptors.join(
|
|
1674
|
+
", "
|
|
1675
|
+
)} } from "@kithinji/express";
|
|
1676
|
+
`;
|
|
1677
|
+
}
|
|
1290
1678
|
importGroups.forEach((ids, source) => {
|
|
1291
1679
|
const filteredIds = Array.from(ids).filter((id) => id !== serviceName);
|
|
1292
1680
|
if (filteredIds.length > 0) {
|
|
@@ -1298,32 +1686,175 @@ function generateImports(serviceInfo, serviceName, serviceImportPath) {
|
|
|
1298
1686
|
});
|
|
1299
1687
|
return importStrings;
|
|
1300
1688
|
}
|
|
1689
|
+
function hasMulterFileParams(method) {
|
|
1690
|
+
return method.params.some((param) => {
|
|
1691
|
+
return param.type === "Array<Express.Multer.File>" || param.type === "Express.Multer.File[]" || param.type === "Express.Multer.File";
|
|
1692
|
+
});
|
|
1693
|
+
}
|
|
1694
|
+
function getFileParams(method) {
|
|
1695
|
+
return method.params.filter(
|
|
1696
|
+
(p) => p.type === "Array<Express.Multer.File>" || p.type === "Express.Multer.File[]" || p.type === "Express.Multer.File"
|
|
1697
|
+
).map((p) => ({
|
|
1698
|
+
name: p.name,
|
|
1699
|
+
type: p.type,
|
|
1700
|
+
isArray: p.type.includes("Array") || p.type.includes("[]")
|
|
1701
|
+
}));
|
|
1702
|
+
}
|
|
1703
|
+
function isArrayFileParam(param) {
|
|
1704
|
+
return param.isArray;
|
|
1705
|
+
}
|
|
1706
|
+
function getNonFileParams(method) {
|
|
1707
|
+
return method.params.filter(
|
|
1708
|
+
(p) => p.type !== "Array<Express.Multer.File>" && p.type !== "Express.Multer.File[]" && p.type !== "Express.Multer.File"
|
|
1709
|
+
);
|
|
1710
|
+
}
|
|
1301
1711
|
function generateMethods(serviceInfo) {
|
|
1302
1712
|
return serviceInfo.methods.map((m) => generateMethod(m, serviceInfo.className)).join("\n\n");
|
|
1303
1713
|
}
|
|
1304
1714
|
function generateMethod(method, serviceName) {
|
|
1305
1715
|
const hasParams = method.params.length > 0;
|
|
1306
1716
|
const serviceInstance = toInstanceName(serviceName);
|
|
1717
|
+
const fileParams = getFileParams(method);
|
|
1718
|
+
const hasFileParams = fileParams.length > 0;
|
|
1719
|
+
const liftedDecorators = method.decorators?.filter(shouldLiftDecorator).map((d) => ` ${d}`).join("\n") || "";
|
|
1307
1720
|
if (method.isStreamable) {
|
|
1721
|
+
if (hasFileParams) {
|
|
1722
|
+
throw new Error(
|
|
1723
|
+
`Method '${method.name}' cannot have file parameters for streaming endpoints`
|
|
1724
|
+
);
|
|
1725
|
+
}
|
|
1726
|
+
const reqParam2 = `@Req() request: Request`;
|
|
1308
1727
|
const queryParams = hasParams ? method.params.map((p) => `@Query('${p.name}') ${p.name}: ${p.type}`).join(", ") : "";
|
|
1728
|
+
const allParams2 = [reqParam2, queryParams].filter(Boolean).join(", ");
|
|
1309
1729
|
const body2 = generateMethodBody(method, serviceInstance, false);
|
|
1310
1730
|
const returnTypeName = method.streamType || "Observable";
|
|
1311
|
-
|
|
1312
|
-
|
|
1731
|
+
const decoratorPrefix2 = liftedDecorators ? `${liftedDecorators}
|
|
1732
|
+
` : "";
|
|
1733
|
+
return `${decoratorPrefix2} @Sse("${method.name}")
|
|
1734
|
+
${method.name}(${allParams2}): ${returnTypeName}<${method.returnType}> {
|
|
1313
1735
|
${body2}
|
|
1314
1736
|
}`;
|
|
1315
1737
|
}
|
|
1738
|
+
if (hasFileParams) {
|
|
1739
|
+
return generateFileUploadMethod(
|
|
1740
|
+
method,
|
|
1741
|
+
serviceInstance,
|
|
1742
|
+
fileParams,
|
|
1743
|
+
liftedDecorators
|
|
1744
|
+
);
|
|
1745
|
+
}
|
|
1316
1746
|
const decorator = hasParams ? "Post" : "Get";
|
|
1747
|
+
const reqParam = `@Req() request: Request`;
|
|
1317
1748
|
const bodyParam = hasParams ? `@Body() body: any` : "";
|
|
1749
|
+
const allParams = [reqParam, bodyParam].filter(Boolean).join(", ");
|
|
1318
1750
|
const body = generateMethodBody(method, serviceInstance, true);
|
|
1319
|
-
|
|
1320
|
-
|
|
1751
|
+
const decoratorPrefix = liftedDecorators ? `${liftedDecorators}
|
|
1752
|
+
` : "";
|
|
1753
|
+
return `${decoratorPrefix} @${decorator}("${method.name}")
|
|
1754
|
+
async ${method.name}(${allParams}): Promise<${method.returnType}> {
|
|
1321
1755
|
${body}
|
|
1322
1756
|
}`;
|
|
1323
1757
|
}
|
|
1758
|
+
function generateFileUploadMethod(method, serviceInstance, fileParams, liftedDecorators) {
|
|
1759
|
+
const nonFileParams = getNonFileParams(method);
|
|
1760
|
+
const interceptorDecorator = generateInterceptorDecorator(fileParams);
|
|
1761
|
+
const methodParams = generateFileMethodParams(fileParams, nonFileParams);
|
|
1762
|
+
const allParams = [`@Req() request: Request`, methodParams].filter(Boolean).join(", ");
|
|
1763
|
+
const body = generateFileMethodBody(
|
|
1764
|
+
method,
|
|
1765
|
+
serviceInstance,
|
|
1766
|
+
fileParams,
|
|
1767
|
+
nonFileParams
|
|
1768
|
+
);
|
|
1769
|
+
const decoratorPrefix = liftedDecorators ? `${liftedDecorators}
|
|
1770
|
+
` : "";
|
|
1771
|
+
return `${decoratorPrefix}${interceptorDecorator} @Post("${method.name}")
|
|
1772
|
+
async ${method.name}(${allParams}): Promise<${method.returnType}> {
|
|
1773
|
+
${body}
|
|
1774
|
+
}`;
|
|
1775
|
+
}
|
|
1776
|
+
function generateInterceptorDecorator(fileParams) {
|
|
1777
|
+
if (fileParams.length === 1) {
|
|
1778
|
+
const param = fileParams[0];
|
|
1779
|
+
if (param.isArray) {
|
|
1780
|
+
return ` @UseInterceptors(FilesInterceptor("${param.name}"))
|
|
1781
|
+
`;
|
|
1782
|
+
} else {
|
|
1783
|
+
return ` @UseInterceptors(FileInterceptor("${param.name}"))
|
|
1784
|
+
`;
|
|
1785
|
+
}
|
|
1786
|
+
} else {
|
|
1787
|
+
const fields = fileParams.map((p) => `{ name: "${p.name}" }`).join(", ");
|
|
1788
|
+
return ` @UseInterceptors(FileFieldsInterceptor([${fields}]))
|
|
1789
|
+
`;
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
function generateFileMethodParams(fileParams, nonFileParams) {
|
|
1793
|
+
const params = [];
|
|
1794
|
+
if (fileParams.length === 1) {
|
|
1795
|
+
const param = fileParams[0];
|
|
1796
|
+
const decorator = param.isArray ? "@UploadedFiles()" : "@UploadedFile()";
|
|
1797
|
+
params.push(`${decorator} ${param.name}: ${param.type}`);
|
|
1798
|
+
} else if (fileParams.length > 1) {
|
|
1799
|
+
params.push(
|
|
1800
|
+
`@UploadedFiles() files: Record<string, Express.Multer.File[]>`
|
|
1801
|
+
);
|
|
1802
|
+
}
|
|
1803
|
+
if (nonFileParams.length > 0) {
|
|
1804
|
+
params.push(`@Body() body: any`);
|
|
1805
|
+
}
|
|
1806
|
+
return params.join(", ");
|
|
1807
|
+
}
|
|
1808
|
+
function generateFileMethodBody(method, serviceInstance, fileParams, nonFileParams) {
|
|
1809
|
+
const lines = [];
|
|
1810
|
+
lines.push(` this.${serviceInstance}.request = request;`);
|
|
1811
|
+
if (fileParams.length > 1) {
|
|
1812
|
+
fileParams.forEach((p) => {
|
|
1813
|
+
if (p.isArray) {
|
|
1814
|
+
lines.push(` const ${p.name} = files["${p.name}"] || [];`);
|
|
1815
|
+
} else {
|
|
1816
|
+
lines.push(
|
|
1817
|
+
` const ${p.name} = files["${p.name}"]?.[0] || files["${p.name}"];`
|
|
1818
|
+
);
|
|
1819
|
+
}
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1822
|
+
if (nonFileParams.length > 0) {
|
|
1823
|
+
const nonFileSchemas = method.paramSchemas.filter((_, i) => {
|
|
1824
|
+
const param = method.params[i];
|
|
1825
|
+
return !fileParams.some((fp) => fp.name === param.name);
|
|
1826
|
+
});
|
|
1827
|
+
if (nonFileSchemas.length > 0 && nonFileSchemas.some((s) => s)) {
|
|
1828
|
+
lines.push(
|
|
1829
|
+
` const b = typeof body === 'object' && body !== null ? body : {};`
|
|
1830
|
+
);
|
|
1831
|
+
nonFileParams.forEach((p) => {
|
|
1832
|
+
const schemaIndex = method.params.findIndex((mp) => mp.name === p.name);
|
|
1833
|
+
if (method.paramSchemas[schemaIndex]) {
|
|
1834
|
+
lines.push(
|
|
1835
|
+
` const ${p.name} = ${method.paramSchemas[schemaIndex]}.parse(b.${p.name});`
|
|
1836
|
+
);
|
|
1837
|
+
}
|
|
1838
|
+
});
|
|
1839
|
+
} else {
|
|
1840
|
+
const paramNames = nonFileParams.map((p) => p.name).join(", ");
|
|
1841
|
+
lines.push(` const { ${paramNames} } = body || {};`);
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
const callArgs = method.params.map((p) => p.name).join(", ");
|
|
1845
|
+
const serviceCall = `${serviceInstance}.${method.name}(${callArgs})`;
|
|
1846
|
+
if (method.returnSchema) {
|
|
1847
|
+
lines.push(` const res = await this.${serviceCall};`);
|
|
1848
|
+
lines.push(` return ${method.returnSchema}.parse(res);`);
|
|
1849
|
+
} else {
|
|
1850
|
+
lines.push(` return this.${serviceCall};`);
|
|
1851
|
+
}
|
|
1852
|
+
return lines.join("\n");
|
|
1853
|
+
}
|
|
1324
1854
|
function generateMethodBody(method, serviceInstance, isAsync) {
|
|
1325
1855
|
const lines = [];
|
|
1326
1856
|
const hasParams = method.params.length > 0;
|
|
1857
|
+
lines.push(` this.${serviceInstance}.request = request;`);
|
|
1327
1858
|
if (hasParams && method.isStreamable && method.paramSchemas.length > 0) {
|
|
1328
1859
|
method.params.forEach((p, i) => {
|
|
1329
1860
|
lines.push(
|
|
@@ -1367,7 +1898,7 @@ function generateMethodBody(method, serviceInstance, isAsync) {
|
|
|
1367
1898
|
// src/plugins/generators/tsx_server_stub.ts
|
|
1368
1899
|
import * as path5 from "path";
|
|
1369
1900
|
import { createHash } from "crypto";
|
|
1370
|
-
import { parseSync as parseSync2, printSync } from "@swc/core";
|
|
1901
|
+
import { parseSync as parseSync2, printSync as printSync2 } from "@swc/core";
|
|
1371
1902
|
function generateServerStub(filePath, code) {
|
|
1372
1903
|
const hash = createHash("md5").update(filePath).digest("hex").slice(0, 8);
|
|
1373
1904
|
const relativeFromSrc = filePath.split("/src/")[1];
|
|
@@ -1413,7 +1944,7 @@ function generateServerStub(filePath, code) {
|
|
|
1413
1944
|
preservedNodes.push(item);
|
|
1414
1945
|
}
|
|
1415
1946
|
}
|
|
1416
|
-
const preservedCode = preservedNodes.length > 0 ?
|
|
1947
|
+
const preservedCode = preservedNodes.length > 0 ? printSync2({
|
|
1417
1948
|
type: "Module",
|
|
1418
1949
|
span: ast.span,
|
|
1419
1950
|
body: preservedNodes,
|
|
@@ -1446,7 +1977,7 @@ function extractClassStub(classDecl) {
|
|
|
1446
1977
|
const constructorParams = [];
|
|
1447
1978
|
if (classDecl.decorators) {
|
|
1448
1979
|
for (const dec of classDecl.decorators) {
|
|
1449
|
-
const str =
|
|
1980
|
+
const str = stringifyDecorator2(dec);
|
|
1450
1981
|
if (str) decorators.push(str);
|
|
1451
1982
|
}
|
|
1452
1983
|
}
|
|
@@ -1469,8 +2000,8 @@ function extractClassStub(classDecl) {
|
|
|
1469
2000
|
constructorParams
|
|
1470
2001
|
};
|
|
1471
2002
|
}
|
|
1472
|
-
function
|
|
1473
|
-
const exprCode =
|
|
2003
|
+
function stringifyDecorator2(decorator) {
|
|
2004
|
+
const exprCode = printSync2({
|
|
1474
2005
|
type: "Module",
|
|
1475
2006
|
span: { start: 0, end: 0, ctxt: 0 },
|
|
1476
2007
|
body: [
|
|
@@ -1505,7 +2036,7 @@ function stringifyParam(param) {
|
|
|
1505
2036
|
let decorators = [];
|
|
1506
2037
|
if (param.decorators) {
|
|
1507
2038
|
for (const d of param.decorators) {
|
|
1508
|
-
const str =
|
|
2039
|
+
const str = stringifyDecorator2(d);
|
|
1509
2040
|
if (str) decorators.push(str);
|
|
1510
2041
|
}
|
|
1511
2042
|
}
|
|
@@ -1608,9 +2139,6 @@ var NodeTypeGuards = class {
|
|
|
1608
2139
|
isSignalMember(expr) {
|
|
1609
2140
|
return this.t.isMemberExpression(expr) && this.t.isIdentifier(expr.property, { name: "value" });
|
|
1610
2141
|
}
|
|
1611
|
-
isBehaviorSubjectMember(expr) {
|
|
1612
|
-
return this.t.isMemberExpression(expr) && this.t.isIdentifier(expr.property, { name: "$value" });
|
|
1613
|
-
}
|
|
1614
2142
|
};
|
|
1615
2143
|
var ASTUtilities = class {
|
|
1616
2144
|
constructor(t, guards) {
|
|
@@ -1618,7 +2146,7 @@ var ASTUtilities = class {
|
|
|
1618
2146
|
this.guards = guards;
|
|
1619
2147
|
}
|
|
1620
2148
|
getObject(expr) {
|
|
1621
|
-
if (this.guards.isSignalMember(expr)
|
|
2149
|
+
if (this.guards.isSignalMember(expr)) {
|
|
1622
2150
|
return expr.object;
|
|
1623
2151
|
}
|
|
1624
2152
|
return expr;
|
|
@@ -1656,24 +2184,12 @@ var ASTUtilities = class {
|
|
|
1656
2184
|
}
|
|
1657
2185
|
return expr;
|
|
1658
2186
|
}
|
|
1659
|
-
insertBeforeReturn(body, statements) {
|
|
1660
|
-
const returnIndex = body.findIndex(
|
|
1661
|
-
(stmt) => this.t.isReturnStatement(stmt)
|
|
1662
|
-
);
|
|
1663
|
-
if (returnIndex !== -1) {
|
|
1664
|
-
body.splice(returnIndex, 0, ...statements);
|
|
1665
|
-
} else {
|
|
1666
|
-
body.push(...statements);
|
|
1667
|
-
}
|
|
1668
|
-
}
|
|
1669
2187
|
addEffectCleanup(scope, effectCall) {
|
|
1670
2188
|
const cleanupId = scope.generateUidIdentifier("cleanup");
|
|
1671
2189
|
return [
|
|
1672
|
-
// const _cleanup1 = $effect(...)
|
|
1673
2190
|
this.t.variableDeclaration("const", [
|
|
1674
2191
|
this.t.variableDeclarator(cleanupId, effectCall)
|
|
1675
2192
|
]),
|
|
1676
|
-
// self.__cleanup = [...(self.__cleanup || []), _cleanup1]
|
|
1677
2193
|
this.t.expressionStatement(
|
|
1678
2194
|
this.t.assignmentExpression(
|
|
1679
2195
|
"=",
|
|
@@ -1786,81 +2302,12 @@ var JSXUtilities = class {
|
|
|
1786
2302
|
return svgTags.has(tag);
|
|
1787
2303
|
}
|
|
1788
2304
|
};
|
|
1789
|
-
var ObservableManager = class {
|
|
1790
|
-
constructor(t, guards) {
|
|
1791
|
-
this.t = t;
|
|
1792
|
-
this.guards = guards;
|
|
1793
|
-
}
|
|
1794
|
-
getObservableKey(expr) {
|
|
1795
|
-
return this.stringifyNode(expr);
|
|
1796
|
-
}
|
|
1797
|
-
stringifyNode(node) {
|
|
1798
|
-
if (!node) return "";
|
|
1799
|
-
if (this.t.isThisExpression(node)) return "this";
|
|
1800
|
-
if (this.t.isIdentifier(node)) return node.name;
|
|
1801
|
-
if (this.t.isMemberExpression(node)) {
|
|
1802
|
-
const obj = this.stringifyNode(node.object);
|
|
1803
|
-
const prop = node.computed ? `[${this.stringifyNode(node.property)}]` : `.${node.property.name}`;
|
|
1804
|
-
return obj + prop;
|
|
1805
|
-
}
|
|
1806
|
-
if (this.t.isCallExpression(node)) {
|
|
1807
|
-
const callee = this.stringifyNode(node.callee);
|
|
1808
|
-
const args = node.arguments.map((arg) => this.stringifyNode(arg)).join(",");
|
|
1809
|
-
return `${callee}(${args})`;
|
|
1810
|
-
}
|
|
1811
|
-
if (this.t.isStringLiteral(node)) return `"${node.value}"`;
|
|
1812
|
-
if (this.t.isNumericLiteral(node)) return String(node.value);
|
|
1813
|
-
return node.type + JSON.stringify(node.name || node.value || "");
|
|
1814
|
-
}
|
|
1815
|
-
collectObservables(node, observables, astUtils) {
|
|
1816
|
-
this.walkNode(node, (n) => {
|
|
1817
|
-
if (this.guards.isBehaviorSubjectMember(n)) {
|
|
1818
|
-
const observable = astUtils.replaceThisWithSelf(
|
|
1819
|
-
n.object
|
|
1820
|
-
);
|
|
1821
|
-
const key = this.getObservableKey(observable);
|
|
1822
|
-
if (!observables.has(key)) {
|
|
1823
|
-
observables.set(key, observable);
|
|
1824
|
-
}
|
|
1825
|
-
}
|
|
1826
|
-
});
|
|
1827
|
-
}
|
|
1828
|
-
replaceObservablesWithSignals(node, observableSignals, astUtils) {
|
|
1829
|
-
const cloned = this.t.cloneNode(node, true);
|
|
1830
|
-
this.walkNode(cloned, (n) => {
|
|
1831
|
-
if (this.guards.isBehaviorSubjectMember(n)) {
|
|
1832
|
-
const observable = astUtils.replaceThisWithSelf(n.object);
|
|
1833
|
-
const key = this.getObservableKey(observable);
|
|
1834
|
-
const signalId = observableSignals.get(key);
|
|
1835
|
-
if (signalId) {
|
|
1836
|
-
n.object = signalId;
|
|
1837
|
-
n.property = this.t.identifier("value");
|
|
1838
|
-
}
|
|
1839
|
-
}
|
|
1840
|
-
});
|
|
1841
|
-
return cloned;
|
|
1842
|
-
}
|
|
1843
|
-
walkNode(node, callback) {
|
|
1844
|
-
if (!node || typeof node !== "object") return;
|
|
1845
|
-
callback(node);
|
|
1846
|
-
for (const key in node) {
|
|
1847
|
-
if (["loc", "start", "end", "extra"].includes(key)) continue;
|
|
1848
|
-
const value = node[key];
|
|
1849
|
-
if (Array.isArray(value)) {
|
|
1850
|
-
value.forEach((item) => this.walkNode(item, callback));
|
|
1851
|
-
} else if (value && typeof value === "object") {
|
|
1852
|
-
this.walkNode(value, callback);
|
|
1853
|
-
}
|
|
1854
|
-
}
|
|
1855
|
-
}
|
|
1856
|
-
};
|
|
1857
2305
|
var ElementTransformer = class {
|
|
1858
|
-
constructor(t, guards, astUtils, jsxUtils
|
|
2306
|
+
constructor(t, guards, astUtils, jsxUtils) {
|
|
1859
2307
|
this.t = t;
|
|
1860
2308
|
this.guards = guards;
|
|
1861
2309
|
this.astUtils = astUtils;
|
|
1862
2310
|
this.jsxUtils = jsxUtils;
|
|
1863
|
-
this.observableManager = observableManager;
|
|
1864
2311
|
}
|
|
1865
2312
|
transformElement(path17, scope, context2) {
|
|
1866
2313
|
if (this.t.isJSXFragment(path17.node)) {
|
|
@@ -2031,18 +2478,10 @@ var ElementTransformer = class {
|
|
|
2031
2478
|
processComponentAttributes(attributes, props, context2) {
|
|
2032
2479
|
for (const attr of attributes) {
|
|
2033
2480
|
if (this.t.isJSXSpreadAttribute(attr)) {
|
|
2034
|
-
this.observableManager.collectObservables(
|
|
2035
|
-
attr.argument,
|
|
2036
|
-
context2.observables,
|
|
2037
|
-
this.astUtils
|
|
2038
|
-
);
|
|
2039
|
-
const replaced = this.observableManager.replaceObservablesWithSignals(
|
|
2040
|
-
attr.argument,
|
|
2041
|
-
context2.observableSignals,
|
|
2042
|
-
this.astUtils
|
|
2043
|
-
);
|
|
2044
2481
|
props.push(
|
|
2045
|
-
this.t.spreadElement(
|
|
2482
|
+
this.t.spreadElement(
|
|
2483
|
+
this.astUtils.replaceThisWithSelf(attr.argument)
|
|
2484
|
+
)
|
|
2046
2485
|
);
|
|
2047
2486
|
continue;
|
|
2048
2487
|
}
|
|
@@ -2051,39 +2490,22 @@ var ElementTransformer = class {
|
|
|
2051
2490
|
props.push(this.t.objectProperty(this.t.identifier(key), attr.value));
|
|
2052
2491
|
} else if (this.t.isJSXExpressionContainer(attr.value)) {
|
|
2053
2492
|
const expr = attr.value.expression;
|
|
2054
|
-
this.
|
|
2055
|
-
expr,
|
|
2056
|
-
context2.observables,
|
|
2057
|
-
this.astUtils
|
|
2058
|
-
);
|
|
2059
|
-
if (this.guards.isSignalMember(expr) || this.guards.isBehaviorSubjectMember(expr)) {
|
|
2060
|
-
const replaced = this.observableManager.replaceObservablesWithSignals(
|
|
2061
|
-
expr,
|
|
2062
|
-
context2.observableSignals,
|
|
2063
|
-
this.astUtils
|
|
2064
|
-
);
|
|
2493
|
+
if (this.guards.isSignalMember(expr)) {
|
|
2065
2494
|
props.push(
|
|
2066
2495
|
this.t.objectMethod(
|
|
2067
2496
|
"get",
|
|
2068
2497
|
this.t.identifier(key),
|
|
2069
2498
|
[],
|
|
2070
2499
|
this.t.blockStatement([
|
|
2071
|
-
this.t.returnStatement(
|
|
2072
|
-
this.astUtils.replaceThisWithSelf(replaced)
|
|
2073
|
-
)
|
|
2500
|
+
this.t.returnStatement(this.astUtils.replaceThisWithSelf(expr))
|
|
2074
2501
|
])
|
|
2075
2502
|
)
|
|
2076
2503
|
);
|
|
2077
2504
|
} else {
|
|
2078
|
-
const replaced = this.observableManager.replaceObservablesWithSignals(
|
|
2079
|
-
expr,
|
|
2080
|
-
context2.observableSignals,
|
|
2081
|
-
this.astUtils
|
|
2082
|
-
);
|
|
2083
2505
|
props.push(
|
|
2084
2506
|
this.t.objectProperty(
|
|
2085
2507
|
this.t.identifier(key),
|
|
2086
|
-
this.astUtils.replaceThisWithSelf(
|
|
2508
|
+
this.astUtils.replaceThisWithSelf(expr)
|
|
2087
2509
|
)
|
|
2088
2510
|
);
|
|
2089
2511
|
}
|
|
@@ -2106,22 +2528,12 @@ var ElementTransformer = class {
|
|
|
2106
2528
|
let hrefValue = null;
|
|
2107
2529
|
for (const attr of attributes) {
|
|
2108
2530
|
if (this.t.isJSXSpreadAttribute(attr)) {
|
|
2109
|
-
this.observableManager.collectObservables(
|
|
2110
|
-
attr.argument,
|
|
2111
|
-
context2.observables,
|
|
2112
|
-
this.astUtils
|
|
2113
|
-
);
|
|
2114
|
-
const replaced = this.observableManager.replaceObservablesWithSignals(
|
|
2115
|
-
attr.argument,
|
|
2116
|
-
context2.observableSignals,
|
|
2117
|
-
this.astUtils
|
|
2118
|
-
);
|
|
2119
2531
|
const effectCall = this.t.callExpression(this.t.identifier("$effect"), [
|
|
2120
2532
|
this.t.arrowFunctionExpression(
|
|
2121
2533
|
[],
|
|
2122
2534
|
this.t.callExpression(this.t.identifier("$spread"), [
|
|
2123
2535
|
elId,
|
|
2124
|
-
this.astUtils.replaceThisWithSelf(
|
|
2536
|
+
this.astUtils.replaceThisWithSelf(attr.argument)
|
|
2125
2537
|
])
|
|
2126
2538
|
)
|
|
2127
2539
|
]);
|
|
@@ -2136,34 +2548,18 @@ var ElementTransformer = class {
|
|
|
2136
2548
|
if (key === "ref") {
|
|
2137
2549
|
hasRef = true;
|
|
2138
2550
|
if (this.t.isJSXExpressionContainer(attr.value)) {
|
|
2139
|
-
this.
|
|
2140
|
-
attr.value.expression
|
|
2141
|
-
context2.observables,
|
|
2142
|
-
this.astUtils
|
|
2143
|
-
);
|
|
2144
|
-
const replaced = this.observableManager.replaceObservablesWithSignals(
|
|
2145
|
-
attr.value.expression,
|
|
2146
|
-
context2.observableSignals,
|
|
2147
|
-
this.astUtils
|
|
2551
|
+
refValue = this.astUtils.replaceThisWithSelf(
|
|
2552
|
+
attr.value.expression
|
|
2148
2553
|
);
|
|
2149
|
-
refValue = this.astUtils.replaceThisWithSelf(replaced);
|
|
2150
2554
|
}
|
|
2151
2555
|
continue;
|
|
2152
2556
|
}
|
|
2153
2557
|
if (key === "dangerouslySetInnerHTML") {
|
|
2154
2558
|
hasDangerousHTML = true;
|
|
2155
2559
|
if (this.t.isJSXExpressionContainer(attr.value)) {
|
|
2156
|
-
this.
|
|
2157
|
-
attr.value.expression
|
|
2158
|
-
context2.observables,
|
|
2159
|
-
this.astUtils
|
|
2560
|
+
dangerousHTMLValue = this.astUtils.replaceThisWithSelf(
|
|
2561
|
+
attr.value.expression
|
|
2160
2562
|
);
|
|
2161
|
-
const replaced = this.observableManager.replaceObservablesWithSignals(
|
|
2162
|
-
attr.value.expression,
|
|
2163
|
-
context2.observableSignals,
|
|
2164
|
-
this.astUtils
|
|
2165
|
-
);
|
|
2166
|
-
dangerousHTMLValue = this.astUtils.replaceThisWithSelf(replaced);
|
|
2167
2563
|
}
|
|
2168
2564
|
continue;
|
|
2169
2565
|
}
|
|
@@ -2181,9 +2577,9 @@ var ElementTransformer = class {
|
|
|
2181
2577
|
this.processStyleAttribute(attr, elId, statements, scope, context2);
|
|
2182
2578
|
continue;
|
|
2183
2579
|
}
|
|
2184
|
-
this.processRegularAttribute(key, attr, elId, statements, context2);
|
|
2580
|
+
this.processRegularAttribute(key, attr, elId, statements, scope, context2);
|
|
2185
2581
|
}
|
|
2186
|
-
if (tag === "a" && !hasClickHandler
|
|
2582
|
+
if (tag === "a" && !hasClickHandler) {
|
|
2187
2583
|
statements.push(
|
|
2188
2584
|
this.t.expressionStatement(
|
|
2189
2585
|
this.t.callExpression(
|
|
@@ -2194,13 +2590,25 @@ var ElementTransformer = class {
|
|
|
2194
2590
|
[
|
|
2195
2591
|
this.t.stringLiteral("click"),
|
|
2196
2592
|
this.t.arrowFunctionExpression(
|
|
2197
|
-
[this.t.identifier("
|
|
2593
|
+
[this.t.identifier("e")],
|
|
2198
2594
|
this.t.callExpression(
|
|
2199
2595
|
this.t.memberExpression(
|
|
2200
2596
|
this.t.identifier("Orca"),
|
|
2201
2597
|
this.t.identifier("navigate")
|
|
2202
2598
|
),
|
|
2203
|
-
[
|
|
2599
|
+
[
|
|
2600
|
+
this.t.identifier("e"),
|
|
2601
|
+
this.t.callExpression(
|
|
2602
|
+
this.t.memberExpression(
|
|
2603
|
+
this.t.memberExpression(
|
|
2604
|
+
this.t.identifier("e"),
|
|
2605
|
+
this.t.identifier("currentTarget")
|
|
2606
|
+
),
|
|
2607
|
+
this.t.identifier("getAttribute")
|
|
2608
|
+
),
|
|
2609
|
+
[this.t.stringLiteral("href")]
|
|
2610
|
+
)
|
|
2611
|
+
]
|
|
2204
2612
|
)
|
|
2205
2613
|
)
|
|
2206
2614
|
]
|
|
@@ -2225,17 +2633,9 @@ var ElementTransformer = class {
|
|
|
2225
2633
|
const eventName = key.slice(2).toLowerCase();
|
|
2226
2634
|
let handler = this.t.nullLiteral();
|
|
2227
2635
|
if (this.t.isJSXExpressionContainer(attr.value)) {
|
|
2228
|
-
this.
|
|
2229
|
-
attr.value.expression
|
|
2230
|
-
context2.observables,
|
|
2231
|
-
this.astUtils
|
|
2232
|
-
);
|
|
2233
|
-
const replaced = this.observableManager.replaceObservablesWithSignals(
|
|
2234
|
-
attr.value.expression,
|
|
2235
|
-
context2.observableSignals,
|
|
2236
|
-
this.astUtils
|
|
2636
|
+
handler = this.astUtils.replaceThisWithSelf(
|
|
2637
|
+
attr.value.expression
|
|
2237
2638
|
);
|
|
2238
|
-
handler = this.astUtils.replaceThisWithSelf(replaced);
|
|
2239
2639
|
}
|
|
2240
2640
|
statements.push(
|
|
2241
2641
|
this.t.expressionStatement(
|
|
@@ -2248,56 +2648,63 @@ var ElementTransformer = class {
|
|
|
2248
2648
|
}
|
|
2249
2649
|
processStyleAttribute(attr, elId, statements, scope, context2) {
|
|
2250
2650
|
if (!this.t.isJSXExpressionContainer(attr.value)) return;
|
|
2251
|
-
this.observableManager.collectObservables(
|
|
2252
|
-
attr.value.expression,
|
|
2253
|
-
context2.observables,
|
|
2254
|
-
this.astUtils
|
|
2255
|
-
);
|
|
2256
|
-
const replaced = this.observableManager.replaceObservablesWithSignals(
|
|
2257
|
-
attr.value.expression,
|
|
2258
|
-
context2.observableSignals,
|
|
2259
|
-
this.astUtils
|
|
2260
|
-
);
|
|
2261
2651
|
const effectCall = this.t.callExpression(this.t.identifier("$effect"), [
|
|
2262
2652
|
this.t.arrowFunctionExpression(
|
|
2263
2653
|
[],
|
|
2264
2654
|
this.t.callExpression(this.t.identifier("$style"), [
|
|
2265
2655
|
elId,
|
|
2266
|
-
this.astUtils.replaceThisWithSelf(
|
|
2656
|
+
this.astUtils.replaceThisWithSelf(
|
|
2657
|
+
attr.value.expression
|
|
2658
|
+
)
|
|
2267
2659
|
])
|
|
2268
2660
|
)
|
|
2269
2661
|
]);
|
|
2270
2662
|
const cleanupStatements = this.astUtils.addEffectCleanup(scope, effectCall);
|
|
2271
2663
|
statements.push(...cleanupStatements);
|
|
2272
2664
|
}
|
|
2273
|
-
processRegularAttribute(key, attr, elId, statements, context2) {
|
|
2665
|
+
processRegularAttribute(key, attr, elId, statements, scope, context2) {
|
|
2274
2666
|
const attrName = key === "className" ? "class" : key;
|
|
2275
2667
|
let value;
|
|
2668
|
+
let isReactive = false;
|
|
2276
2669
|
if (this.t.isStringLiteral(attr.value)) {
|
|
2277
2670
|
value = attr.value;
|
|
2278
2671
|
} else if (this.t.isJSXExpressionContainer(attr.value)) {
|
|
2279
|
-
this.
|
|
2280
|
-
attr.value.expression
|
|
2281
|
-
context2.observables,
|
|
2282
|
-
this.astUtils
|
|
2672
|
+
const expr = this.astUtils.replaceThisWithSelf(
|
|
2673
|
+
attr.value.expression
|
|
2283
2674
|
);
|
|
2284
|
-
|
|
2285
|
-
attr.value.expression
|
|
2286
|
-
context2.observableSignals,
|
|
2287
|
-
this.astUtils
|
|
2675
|
+
isReactive = this.guards.isSignalMember(
|
|
2676
|
+
attr.value.expression
|
|
2288
2677
|
);
|
|
2289
|
-
value =
|
|
2678
|
+
value = expr;
|
|
2290
2679
|
} else {
|
|
2291
2680
|
value = this.t.booleanLiteral(true);
|
|
2292
2681
|
}
|
|
2293
|
-
|
|
2294
|
-
this.t.
|
|
2295
|
-
this.t.
|
|
2296
|
-
|
|
2297
|
-
|
|
2682
|
+
if (isReactive) {
|
|
2683
|
+
const effectCall = this.t.callExpression(this.t.identifier("$effect"), [
|
|
2684
|
+
this.t.arrowFunctionExpression(
|
|
2685
|
+
[],
|
|
2686
|
+
this.t.assignmentExpression(
|
|
2687
|
+
"=",
|
|
2688
|
+
this.t.memberExpression(elId, this.t.identifier(attrName)),
|
|
2689
|
+
value
|
|
2690
|
+
)
|
|
2298
2691
|
)
|
|
2299
|
-
)
|
|
2300
|
-
|
|
2692
|
+
]);
|
|
2693
|
+
const cleanupStatements = this.astUtils.addEffectCleanup(
|
|
2694
|
+
scope,
|
|
2695
|
+
effectCall
|
|
2696
|
+
);
|
|
2697
|
+
statements.push(...cleanupStatements);
|
|
2698
|
+
} else {
|
|
2699
|
+
statements.push(
|
|
2700
|
+
this.t.expressionStatement(
|
|
2701
|
+
this.t.callExpression(
|
|
2702
|
+
this.t.memberExpression(elId, this.t.identifier("setAttribute")),
|
|
2703
|
+
[this.t.stringLiteral(attrName), value]
|
|
2704
|
+
)
|
|
2705
|
+
)
|
|
2706
|
+
);
|
|
2707
|
+
}
|
|
2301
2708
|
}
|
|
2302
2709
|
processChildren(children, childExpressions, statements, scope, context2) {
|
|
2303
2710
|
for (const child of children) {
|
|
@@ -2307,17 +2714,9 @@ var ElementTransformer = class {
|
|
|
2307
2714
|
} else if (this.t.isJSXExpressionContainer(child)) {
|
|
2308
2715
|
const expr = child.expression;
|
|
2309
2716
|
if (!this.t.isJSXEmptyExpression(expr)) {
|
|
2310
|
-
|
|
2311
|
-
expr
|
|
2312
|
-
context2.observables,
|
|
2313
|
-
this.astUtils
|
|
2717
|
+
childExpressions.push(
|
|
2718
|
+
this.astUtils.replaceThisWithSelf(expr)
|
|
2314
2719
|
);
|
|
2315
|
-
const replaced = this.observableManager.replaceObservablesWithSignals(
|
|
2316
|
-
expr,
|
|
2317
|
-
context2.observableSignals,
|
|
2318
|
-
this.astUtils
|
|
2319
|
-
);
|
|
2320
|
-
childExpressions.push(this.astUtils.replaceThisWithSelf(replaced));
|
|
2321
2720
|
}
|
|
2322
2721
|
} else if (this.t.isJSXElement(child) || this.t.isJSXFragment(child)) {
|
|
2323
2722
|
const childEl = this.transformElement({ node: child }, scope, context2);
|
|
@@ -2342,42 +2741,43 @@ var ElementTransformer = class {
|
|
|
2342
2741
|
} else if (this.t.isJSXExpressionContainer(child)) {
|
|
2343
2742
|
const expr = child.expression;
|
|
2344
2743
|
if (this.t.isJSXEmptyExpression(expr)) continue;
|
|
2345
|
-
this.
|
|
2346
|
-
|
|
2347
|
-
context2.observables,
|
|
2348
|
-
this.astUtils
|
|
2349
|
-
);
|
|
2350
|
-
let insertedValue;
|
|
2351
|
-
if (this.guards.isSignalMember(expr)) {
|
|
2352
|
-
insertedValue = this.astUtils.getObject(
|
|
2353
|
-
expr
|
|
2354
|
-
);
|
|
2355
|
-
} else if (this.guards.isBehaviorSubjectMember(expr)) {
|
|
2356
|
-
const replaced = this.observableManager.replaceObservablesWithSignals(
|
|
2744
|
+
if (this.t.isLogicalExpression(expr, { operator: "&&" })) {
|
|
2745
|
+
this.processConditionalAnd(
|
|
2357
2746
|
expr,
|
|
2358
|
-
|
|
2359
|
-
|
|
2747
|
+
parentId,
|
|
2748
|
+
statements,
|
|
2749
|
+
scope,
|
|
2750
|
+
context2
|
|
2360
2751
|
);
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
const replaced = this.observableManager.replaceObservablesWithSignals(
|
|
2752
|
+
} else if (this.t.isConditionalExpression(expr)) {
|
|
2753
|
+
this.processConditionalTernary(
|
|
2364
2754
|
expr,
|
|
2365
|
-
|
|
2366
|
-
|
|
2755
|
+
parentId,
|
|
2756
|
+
statements,
|
|
2757
|
+
scope,
|
|
2758
|
+
context2
|
|
2367
2759
|
);
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2760
|
+
} else {
|
|
2761
|
+
let insertedValue;
|
|
2762
|
+
if (this.guards.isSignalMember(expr)) {
|
|
2763
|
+
insertedValue = this.astUtils.getObject(
|
|
2764
|
+
expr
|
|
2765
|
+
);
|
|
2766
|
+
} else {
|
|
2767
|
+
insertedValue = this.t.arrowFunctionExpression(
|
|
2768
|
+
[],
|
|
2769
|
+
this.astUtils.replaceThisWithSelf(expr)
|
|
2770
|
+
);
|
|
2771
|
+
}
|
|
2772
|
+
statements.push(
|
|
2773
|
+
this.t.expressionStatement(
|
|
2774
|
+
this.t.callExpression(this.t.identifier("$insert"), [
|
|
2775
|
+
parentId,
|
|
2776
|
+
insertedValue
|
|
2777
|
+
])
|
|
2778
|
+
)
|
|
2371
2779
|
);
|
|
2372
2780
|
}
|
|
2373
|
-
statements.push(
|
|
2374
|
-
this.t.expressionStatement(
|
|
2375
|
-
this.t.callExpression(this.t.identifier("$insert"), [
|
|
2376
|
-
parentId,
|
|
2377
|
-
insertedValue
|
|
2378
|
-
])
|
|
2379
|
-
)
|
|
2380
|
-
);
|
|
2381
2781
|
} else if (this.t.isJSXElement(child) || this.t.isJSXFragment(child)) {
|
|
2382
2782
|
const childEl = this.transformElement({ node: child }, scope, context2);
|
|
2383
2783
|
statements.push(...childEl.statements);
|
|
@@ -2392,18 +2792,137 @@ var ElementTransformer = class {
|
|
|
2392
2792
|
}
|
|
2393
2793
|
}
|
|
2394
2794
|
}
|
|
2795
|
+
processConditionalAnd(expr, parentId, statements, scope, context2) {
|
|
2796
|
+
const condition = expr.left;
|
|
2797
|
+
const consequent = expr.right;
|
|
2798
|
+
const computedId = scope.generateUidIdentifier("c");
|
|
2799
|
+
const branchExpr = this.transformExpressionToBranch(
|
|
2800
|
+
consequent,
|
|
2801
|
+
scope,
|
|
2802
|
+
context2
|
|
2803
|
+
);
|
|
2804
|
+
statements.push(
|
|
2805
|
+
this.t.expressionStatement(
|
|
2806
|
+
this.t.callExpression(this.t.identifier("$insert"), [
|
|
2807
|
+
parentId,
|
|
2808
|
+
this.t.callExpression(
|
|
2809
|
+
this.t.arrowFunctionExpression(
|
|
2810
|
+
[],
|
|
2811
|
+
this.t.blockStatement([
|
|
2812
|
+
this.t.variableDeclaration("var", [
|
|
2813
|
+
this.t.variableDeclarator(
|
|
2814
|
+
computedId,
|
|
2815
|
+
this.t.callExpression(this.t.identifier("$computed"), [
|
|
2816
|
+
this.t.arrowFunctionExpression(
|
|
2817
|
+
[],
|
|
2818
|
+
this.astUtils.replaceThisWithSelf(condition)
|
|
2819
|
+
)
|
|
2820
|
+
])
|
|
2821
|
+
)
|
|
2822
|
+
]),
|
|
2823
|
+
this.t.returnStatement(
|
|
2824
|
+
this.t.arrowFunctionExpression(
|
|
2825
|
+
[],
|
|
2826
|
+
this.t.logicalExpression(
|
|
2827
|
+
"&&",
|
|
2828
|
+
this.t.memberExpression(
|
|
2829
|
+
computedId,
|
|
2830
|
+
this.t.identifier("value")
|
|
2831
|
+
),
|
|
2832
|
+
this.t.callExpression(branchExpr, [])
|
|
2833
|
+
)
|
|
2834
|
+
)
|
|
2835
|
+
)
|
|
2836
|
+
])
|
|
2837
|
+
),
|
|
2838
|
+
[]
|
|
2839
|
+
)
|
|
2840
|
+
])
|
|
2841
|
+
)
|
|
2842
|
+
);
|
|
2843
|
+
}
|
|
2844
|
+
processConditionalTernary(expr, parentId, statements, scope, context2) {
|
|
2845
|
+
const condition = expr.test;
|
|
2846
|
+
const consequent = expr.consequent;
|
|
2847
|
+
const alternate = expr.alternate;
|
|
2848
|
+
const computedId = scope.generateUidIdentifier("c");
|
|
2849
|
+
const trueBranchExpr = this.transformExpressionToBranch(
|
|
2850
|
+
consequent,
|
|
2851
|
+
scope,
|
|
2852
|
+
context2
|
|
2853
|
+
);
|
|
2854
|
+
const falseBranchExpr = this.transformExpressionToBranch(
|
|
2855
|
+
alternate,
|
|
2856
|
+
scope,
|
|
2857
|
+
context2
|
|
2858
|
+
);
|
|
2859
|
+
statements.push(
|
|
2860
|
+
this.t.expressionStatement(
|
|
2861
|
+
this.t.callExpression(this.t.identifier("$insert"), [
|
|
2862
|
+
parentId,
|
|
2863
|
+
this.t.callExpression(
|
|
2864
|
+
this.t.arrowFunctionExpression(
|
|
2865
|
+
[],
|
|
2866
|
+
this.t.blockStatement([
|
|
2867
|
+
this.t.variableDeclaration("var", [
|
|
2868
|
+
this.t.variableDeclarator(
|
|
2869
|
+
computedId,
|
|
2870
|
+
this.t.callExpression(this.t.identifier("$computed"), [
|
|
2871
|
+
this.t.arrowFunctionExpression(
|
|
2872
|
+
[],
|
|
2873
|
+
this.astUtils.replaceThisWithSelf(condition)
|
|
2874
|
+
)
|
|
2875
|
+
])
|
|
2876
|
+
)
|
|
2877
|
+
]),
|
|
2878
|
+
this.t.returnStatement(
|
|
2879
|
+
this.t.arrowFunctionExpression(
|
|
2880
|
+
[],
|
|
2881
|
+
this.t.conditionalExpression(
|
|
2882
|
+
this.t.memberExpression(
|
|
2883
|
+
computedId,
|
|
2884
|
+
this.t.identifier("value")
|
|
2885
|
+
),
|
|
2886
|
+
this.t.callExpression(trueBranchExpr, []),
|
|
2887
|
+
this.t.callExpression(falseBranchExpr, [])
|
|
2888
|
+
)
|
|
2889
|
+
)
|
|
2890
|
+
)
|
|
2891
|
+
])
|
|
2892
|
+
),
|
|
2893
|
+
[]
|
|
2894
|
+
)
|
|
2895
|
+
])
|
|
2896
|
+
)
|
|
2897
|
+
);
|
|
2898
|
+
}
|
|
2899
|
+
transformExpressionToBranch(node, scope, context2) {
|
|
2900
|
+
if (this.t.isJSXElement(node) || this.t.isJSXFragment(node)) {
|
|
2901
|
+
const { id, statements } = this.transformElement(
|
|
2902
|
+
{ node },
|
|
2903
|
+
scope,
|
|
2904
|
+
context2
|
|
2905
|
+
);
|
|
2906
|
+
return this.t.arrowFunctionExpression(
|
|
2907
|
+
[],
|
|
2908
|
+
this.t.blockStatement([...statements, this.t.returnStatement(id)])
|
|
2909
|
+
);
|
|
2910
|
+
}
|
|
2911
|
+
return this.t.arrowFunctionExpression(
|
|
2912
|
+
[],
|
|
2913
|
+
this.astUtils.replaceThisWithSelf(node)
|
|
2914
|
+
);
|
|
2915
|
+
}
|
|
2395
2916
|
};
|
|
2396
2917
|
function j2d({ types: t }) {
|
|
2397
2918
|
const guards = new NodeTypeGuards(t);
|
|
2398
2919
|
const astUtils = new ASTUtilities(t, guards);
|
|
2399
2920
|
const jsxUtils = new JSXUtilities(t);
|
|
2400
|
-
const observableManager = new ObservableManager(t, guards);
|
|
2401
2921
|
const elementTransformer = new ElementTransformer(
|
|
2402
2922
|
t,
|
|
2403
2923
|
guards,
|
|
2404
2924
|
astUtils,
|
|
2405
|
-
jsxUtils
|
|
2406
|
-
observableManager
|
|
2925
|
+
jsxUtils
|
|
2407
2926
|
);
|
|
2408
2927
|
return {
|
|
2409
2928
|
name: "jsx-to-dom",
|
|
@@ -2416,8 +2935,8 @@ function j2d({ types: t }) {
|
|
|
2416
2935
|
{ local: "$createComponent", imported: "createComponent" },
|
|
2417
2936
|
{ local: "$style", imported: "style" },
|
|
2418
2937
|
{ local: "$spread", imported: "spread" },
|
|
2419
|
-
{ local: "$
|
|
2420
|
-
{ local: "$
|
|
2938
|
+
{ local: "$effect", imported: "effect" },
|
|
2939
|
+
{ local: "$computed", imported: "computed" }
|
|
2421
2940
|
];
|
|
2422
2941
|
for (const helper of helpers) {
|
|
2423
2942
|
path17.unshiftContainer(
|
|
@@ -2451,49 +2970,12 @@ function j2d({ types: t }) {
|
|
|
2451
2970
|
path17.setData("processed", true);
|
|
2452
2971
|
const body = path17.node.body;
|
|
2453
2972
|
if (!t.isBlockStatement(body)) return;
|
|
2454
|
-
const observables = /* @__PURE__ */ new Map();
|
|
2455
|
-
path17.traverse({
|
|
2456
|
-
JSXElement(jsxPath) {
|
|
2457
|
-
observableManager.collectObservables(
|
|
2458
|
-
jsxPath.node,
|
|
2459
|
-
observables,
|
|
2460
|
-
astUtils
|
|
2461
|
-
);
|
|
2462
|
-
},
|
|
2463
|
-
JSXFragment(jsxPath) {
|
|
2464
|
-
observableManager.collectObservables(
|
|
2465
|
-
jsxPath.node,
|
|
2466
|
-
observables,
|
|
2467
|
-
astUtils
|
|
2468
|
-
);
|
|
2469
|
-
}
|
|
2470
|
-
});
|
|
2471
2973
|
body.body.unshift(
|
|
2472
2974
|
t.variableDeclaration("const", [
|
|
2473
2975
|
t.variableDeclarator(t.identifier("self"), t.thisExpression())
|
|
2474
2976
|
])
|
|
2475
2977
|
);
|
|
2476
|
-
const
|
|
2477
|
-
const signalDeclarations = [];
|
|
2478
|
-
for (const [key, observable] of observables) {
|
|
2479
|
-
const signalId = path17.scope.generateUidIdentifier("sig");
|
|
2480
|
-
observableSignals.set(key, signalId);
|
|
2481
|
-
signalDeclarations.push(
|
|
2482
|
-
t.variableDeclaration("const", [
|
|
2483
|
-
t.variableDeclarator(
|
|
2484
|
-
signalId,
|
|
2485
|
-
t.callExpression(t.identifier("$toSignal"), [
|
|
2486
|
-
observable,
|
|
2487
|
-
t.identifier("self")
|
|
2488
|
-
])
|
|
2489
|
-
)
|
|
2490
|
-
])
|
|
2491
|
-
);
|
|
2492
|
-
}
|
|
2493
|
-
if (signalDeclarations.length > 0) {
|
|
2494
|
-
astUtils.insertBeforeReturn(body.body, signalDeclarations);
|
|
2495
|
-
}
|
|
2496
|
-
const context2 = { observables, observableSignals };
|
|
2978
|
+
const context2 = { signals: /* @__PURE__ */ new Map() };
|
|
2497
2979
|
path17.traverse({
|
|
2498
2980
|
JSXElement(jsxPath) {
|
|
2499
2981
|
if (jsxPath.getData("processed")) return;
|
|
@@ -2538,7 +3020,7 @@ function j2d({ types: t }) {
|
|
|
2538
3020
|
}
|
|
2539
3021
|
|
|
2540
3022
|
// src/plugins/generators/generate_server_component.ts
|
|
2541
|
-
import { parseSync as parseSync3, printSync as
|
|
3023
|
+
import { parseSync as parseSync3, printSync as printSync3 } from "@swc/core";
|
|
2542
3024
|
function generateServerComponent(filePath, code) {
|
|
2543
3025
|
const ast = parseSync3(code, {
|
|
2544
3026
|
syntax: "typescript",
|
|
@@ -2580,7 +3062,7 @@ function generateServerComponent(filePath, code) {
|
|
|
2580
3062
|
preservedNodes.push(item);
|
|
2581
3063
|
}
|
|
2582
3064
|
}
|
|
2583
|
-
const preservedCode = preservedNodes.length > 0 ?
|
|
3065
|
+
const preservedCode = preservedNodes.length > 0 ? printSync3({
|
|
2584
3066
|
type: "Module",
|
|
2585
3067
|
span: ast.span,
|
|
2586
3068
|
body: preservedNodes,
|
|
@@ -2615,7 +3097,7 @@ function extractClassStub2(classDecl) {
|
|
|
2615
3097
|
const constructorParams = [];
|
|
2616
3098
|
if (classDecl.decorators) {
|
|
2617
3099
|
for (const dec of classDecl.decorators) {
|
|
2618
|
-
const str =
|
|
3100
|
+
const str = stringifyDecorator3(dec);
|
|
2619
3101
|
if (str) decorators.push(str);
|
|
2620
3102
|
}
|
|
2621
3103
|
}
|
|
@@ -2640,8 +3122,8 @@ function extractClassStub2(classDecl) {
|
|
|
2640
3122
|
methods
|
|
2641
3123
|
};
|
|
2642
3124
|
}
|
|
2643
|
-
function
|
|
2644
|
-
const exprCode =
|
|
3125
|
+
function stringifyDecorator3(decorator) {
|
|
3126
|
+
const exprCode = printSync3({
|
|
2645
3127
|
type: "Module",
|
|
2646
3128
|
span: { start: 0, end: 0, ctxt: 0 },
|
|
2647
3129
|
body: [
|
|
@@ -2676,7 +3158,7 @@ function stringifyParam2(param) {
|
|
|
2676
3158
|
let decorators = [];
|
|
2677
3159
|
if (param.decorators) {
|
|
2678
3160
|
for (const d of param.decorators) {
|
|
2679
|
-
const str =
|
|
3161
|
+
const str = stringifyDecorator3(d);
|
|
2680
3162
|
if (str) decorators.push(str);
|
|
2681
3163
|
}
|
|
2682
3164
|
}
|
|
@@ -2871,10 +3353,11 @@ ${decoratorsStr}export class ${className} extends _OrcaComponent {
|
|
|
2871
3353
|
}
|
|
2872
3354
|
|
|
2873
3355
|
// src/plugins/generators/generate_rpc.ts
|
|
3356
|
+
import { printSync as printSync4 } from "@swc/core";
|
|
2874
3357
|
function generateRpcStub(filePath, code) {
|
|
2875
3358
|
try {
|
|
2876
3359
|
const ast = parseTypeScript(filePath, code);
|
|
2877
|
-
const serviceInfo = extractServiceInfo(ast, filePath, false);
|
|
3360
|
+
const serviceInfo = extractServiceInfo(ast, filePath, false, true, true);
|
|
2878
3361
|
if (!serviceInfo) {
|
|
2879
3362
|
throw {
|
|
2880
3363
|
type: "validation",
|
|
@@ -2882,7 +3365,6 @@ function generateRpcStub(filePath, code) {
|
|
|
2882
3365
|
filePath
|
|
2883
3366
|
};
|
|
2884
3367
|
}
|
|
2885
|
-
validateServiceInfo(serviceInfo, filePath);
|
|
2886
3368
|
return generateStubCode2(serviceInfo);
|
|
2887
3369
|
} catch (error) {
|
|
2888
3370
|
if (error.type) {
|
|
@@ -2896,32 +3378,143 @@ function generateRpcStub(filePath, code) {
|
|
|
2896
3378
|
};
|
|
2897
3379
|
}
|
|
2898
3380
|
}
|
|
3381
|
+
function hasMulterFileParams2(method) {
|
|
3382
|
+
return method.params.some((param) => {
|
|
3383
|
+
return param.type === "Array<Express.Multer.File>" || param.type === "Express.Multer.File[]" || param.type === "Express.Multer.File";
|
|
3384
|
+
});
|
|
3385
|
+
}
|
|
3386
|
+
function getFileParams2(method) {
|
|
3387
|
+
return method.params.filter(
|
|
3388
|
+
(p) => p.type === "Array<Express.Multer.File>" || p.type === "Express.Multer.File[]" || p.type === "Express.Multer.File"
|
|
3389
|
+
).map((p) => ({
|
|
3390
|
+
name: p.name,
|
|
3391
|
+
type: p.type,
|
|
3392
|
+
isArray: p.type.includes("Array") || p.type.includes("[]")
|
|
3393
|
+
}));
|
|
3394
|
+
}
|
|
3395
|
+
function getNonFileParams2(method) {
|
|
3396
|
+
return method.params.filter(
|
|
3397
|
+
(p) => p.type !== "Array<Express.Multer.File>" && p.type !== "Express.Multer.File[]" && p.type !== "Express.Multer.File"
|
|
3398
|
+
);
|
|
3399
|
+
}
|
|
3400
|
+
function collectSharedImports(serviceInfo) {
|
|
3401
|
+
const allImports = [];
|
|
3402
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3403
|
+
const sharedParams = serviceInfo.constructorParams.filter(
|
|
3404
|
+
(c) => c.decorators?.some((d) => d === "@Shared()")
|
|
3405
|
+
);
|
|
3406
|
+
for (const param of sharedParams) {
|
|
3407
|
+
if (param.imports) {
|
|
3408
|
+
for (const imp of param.imports) {
|
|
3409
|
+
const key = `${imp.identifier}:${imp.source}`;
|
|
3410
|
+
if (!seen.has(key)) {
|
|
3411
|
+
allImports.push(imp);
|
|
3412
|
+
seen.add(key);
|
|
3413
|
+
}
|
|
3414
|
+
}
|
|
3415
|
+
}
|
|
3416
|
+
}
|
|
3417
|
+
return allImports;
|
|
3418
|
+
}
|
|
3419
|
+
function generateImportStatements(imports) {
|
|
3420
|
+
const importsBySource = /* @__PURE__ */ new Map();
|
|
3421
|
+
for (const imp of imports) {
|
|
3422
|
+
if (!importsBySource.has(imp.source)) {
|
|
3423
|
+
importsBySource.set(imp.source, /* @__PURE__ */ new Set());
|
|
3424
|
+
}
|
|
3425
|
+
importsBySource.get(imp.source).add(imp.identifier);
|
|
3426
|
+
}
|
|
3427
|
+
const statements = [];
|
|
3428
|
+
for (const [source, identifiers] of importsBySource) {
|
|
3429
|
+
const identifierList = Array.from(identifiers).sort().join(", ");
|
|
3430
|
+
statements.push(`import { ${identifierList} } from "${source}";`);
|
|
3431
|
+
}
|
|
3432
|
+
return statements.sort().join("\n");
|
|
3433
|
+
}
|
|
2899
3434
|
function generateStubCode2(serviceInfo) {
|
|
2900
3435
|
const className = serviceInfo.className;
|
|
2901
3436
|
const basePath = serviceNameToPath(className);
|
|
2902
3437
|
const methods = serviceInfo.methods.map((method) => generateMethod2(method, basePath, className)).join("\n\n");
|
|
2903
3438
|
const hasStreamable = serviceInfo.methods.some((m) => m.isStreamable);
|
|
2904
|
-
const
|
|
3439
|
+
const sharedImports = collectSharedImports(serviceInfo);
|
|
3440
|
+
const imports = generateImports2(hasStreamable, sharedImports);
|
|
3441
|
+
let clientConstructorFields = serviceInfo.constructorParams.filter((c) => c.decorators?.some((d) => d === "@Shared()")).map((c) => {
|
|
3442
|
+
const filteredDecorators = c.decorators?.filter((d) => d !== "@Shared()") || [];
|
|
3443
|
+
const decoratorStr = filteredDecorators.length > 0 ? filteredDecorators.join("\n") + "\n" : "";
|
|
3444
|
+
return `${decoratorStr}${c.accessibility}${c.isReadonly ? " readonly " : " "}${c.name}: ${c.type},`;
|
|
3445
|
+
}).join("\n");
|
|
2905
3446
|
return `${imports}
|
|
2906
3447
|
|
|
2907
3448
|
@Injectable()
|
|
2908
3449
|
export class ${className} {
|
|
3450
|
+
constructor(
|
|
3451
|
+
${clientConstructorFields}
|
|
3452
|
+
) {}
|
|
3453
|
+
|
|
2909
3454
|
${methods}
|
|
2910
3455
|
}`;
|
|
2911
3456
|
}
|
|
2912
|
-
function generateImports2(hasStreamable) {
|
|
3457
|
+
function generateImports2(hasStreamable, sharedImports) {
|
|
2913
3458
|
let imports = `import { Injectable } from "@kithinji/orca";
|
|
2914
3459
|
`;
|
|
2915
3460
|
if (hasStreamable) {
|
|
2916
|
-
imports += `import { Observable } from "
|
|
3461
|
+
imports += `import { Observable } from "rxjs";
|
|
2917
3462
|
`;
|
|
2918
3463
|
}
|
|
3464
|
+
if (sharedImports.length > 0) {
|
|
3465
|
+
const sharedImportStatements = generateImportStatements(sharedImports);
|
|
3466
|
+
if (sharedImportStatements) {
|
|
3467
|
+
imports += sharedImportStatements + "\n";
|
|
3468
|
+
}
|
|
3469
|
+
}
|
|
2919
3470
|
return imports;
|
|
2920
3471
|
}
|
|
2921
3472
|
function generateMethod2(method, basePath, serviceName) {
|
|
3473
|
+
if (method.lift) {
|
|
3474
|
+
const classWrapper = {
|
|
3475
|
+
type: "Module",
|
|
3476
|
+
span: { start: 0, end: 0 },
|
|
3477
|
+
body: [
|
|
3478
|
+
{
|
|
3479
|
+
type: "ClassDeclaration",
|
|
3480
|
+
span: { start: 0, end: 0 },
|
|
3481
|
+
declare: false,
|
|
3482
|
+
ctxt: 0,
|
|
3483
|
+
identifier: {
|
|
3484
|
+
type: "Identifier",
|
|
3485
|
+
value: "",
|
|
3486
|
+
optional: false,
|
|
3487
|
+
span: { start: 0, end: 0 },
|
|
3488
|
+
ctxt: 0
|
|
3489
|
+
},
|
|
3490
|
+
body: [JSON.parse(JSON.stringify(method.ast))],
|
|
3491
|
+
decorators: [],
|
|
3492
|
+
superClass: null
|
|
3493
|
+
}
|
|
3494
|
+
],
|
|
3495
|
+
shebang: null
|
|
3496
|
+
};
|
|
3497
|
+
let { code } = printSync4(classWrapper);
|
|
3498
|
+
const lines = code.split("\n");
|
|
3499
|
+
lines.shift();
|
|
3500
|
+
lines.pop();
|
|
3501
|
+
lines.pop();
|
|
3502
|
+
const methodCode = lines.join("\n");
|
|
3503
|
+
return methodCode;
|
|
3504
|
+
}
|
|
2922
3505
|
if (method.isStreamable) {
|
|
3506
|
+
if (hasMulterFileParams2(method)) {
|
|
3507
|
+
throw new Error(
|
|
3508
|
+
`Method '${method.name}' cannot have file parameters for streaming endpoints`
|
|
3509
|
+
);
|
|
3510
|
+
}
|
|
2923
3511
|
return generateSseMethod(method, basePath);
|
|
2924
3512
|
}
|
|
3513
|
+
const fileParams = getFileParams2(method);
|
|
3514
|
+
const hasFileParams = fileParams.length > 0;
|
|
3515
|
+
if (hasFileParams) {
|
|
3516
|
+
return generateFileUploadMethod2(method, basePath, fileParams);
|
|
3517
|
+
}
|
|
2925
3518
|
const params = method.params.map((p) => `${p.name}: ${p.type}`).join(", ");
|
|
2926
3519
|
const hasParams = method.params.length > 0;
|
|
2927
3520
|
if (!hasParams) {
|
|
@@ -2929,36 +3522,130 @@ function generateMethod2(method, basePath, serviceName) {
|
|
|
2929
3522
|
}
|
|
2930
3523
|
return generatePostMethod(method, basePath, params);
|
|
2931
3524
|
}
|
|
3525
|
+
function generateFileUploadMethod2(method, basePath, fileParams) {
|
|
3526
|
+
const allParams = method.params.map((p) => `${p.name}: ${p.type}`).join(", ");
|
|
3527
|
+
const nonFileParams = getNonFileParams2(method);
|
|
3528
|
+
const returnType = `Promise<${method.returnType}>`;
|
|
3529
|
+
const lines = [];
|
|
3530
|
+
lines.push(` const formData = new FormData();`);
|
|
3531
|
+
lines.push(``);
|
|
3532
|
+
fileParams.forEach((fp) => {
|
|
3533
|
+
if (fp.isArray) {
|
|
3534
|
+
lines.push(` if (${fp.name} && Array.isArray(${fp.name})) {`);
|
|
3535
|
+
lines.push(` ${fp.name}.forEach((file) => {`);
|
|
3536
|
+
lines.push(` formData.append('${fp.name}', file);`);
|
|
3537
|
+
lines.push(` });`);
|
|
3538
|
+
lines.push(` }`);
|
|
3539
|
+
} else {
|
|
3540
|
+
lines.push(` if (${fp.name}) {`);
|
|
3541
|
+
lines.push(` formData.append('${fp.name}', ${fp.name});`);
|
|
3542
|
+
lines.push(` }`);
|
|
3543
|
+
}
|
|
3544
|
+
});
|
|
3545
|
+
if (nonFileParams.length > 0) {
|
|
3546
|
+
lines.push(``);
|
|
3547
|
+
nonFileParams.forEach((p) => {
|
|
3548
|
+
lines.push(` if (${p.name} !== undefined) {`);
|
|
3549
|
+
lines.push(
|
|
3550
|
+
` formData.append('${p.name}', typeof ${p.name} === 'object' ? JSON.stringify(${p.name}) : String(${p.name}));`
|
|
3551
|
+
);
|
|
3552
|
+
lines.push(` }`);
|
|
3553
|
+
});
|
|
3554
|
+
}
|
|
3555
|
+
lines.push(``);
|
|
3556
|
+
lines.push(` let headers = this.${method.name}Headers?.() || {};`);
|
|
3557
|
+
lines.push(``);
|
|
3558
|
+
lines.push(` if(headers instanceof Promise) {`);
|
|
3559
|
+
lines.push(` headers = await headers;`);
|
|
3560
|
+
lines.push(` }`);
|
|
3561
|
+
lines.push(``);
|
|
3562
|
+
lines.push(
|
|
3563
|
+
` const response = await fetch(\`/api/${basePath}/${method.name}\`, {`
|
|
3564
|
+
);
|
|
3565
|
+
lines.push(` method: 'POST',`);
|
|
3566
|
+
lines.push(` headers: {`);
|
|
3567
|
+
lines.push(` ...headers`);
|
|
3568
|
+
lines.push(` },`);
|
|
3569
|
+
lines.push(` body: formData,`);
|
|
3570
|
+
lines.push(` });`);
|
|
3571
|
+
lines.push(``);
|
|
3572
|
+
lines.push(` if (!response.ok) {`);
|
|
3573
|
+
lines.push(
|
|
3574
|
+
` throw new Error(\`HTTP error! status: \${response.status}\`);`
|
|
3575
|
+
);
|
|
3576
|
+
lines.push(` }`);
|
|
3577
|
+
lines.push(``);
|
|
3578
|
+
lines.push(` return response.json();`);
|
|
3579
|
+
return ` async ${method.name}(${allParams}): ${returnType} {
|
|
3580
|
+
${lines.join("\n")}
|
|
3581
|
+
}`;
|
|
3582
|
+
}
|
|
2932
3583
|
function generateSseMethod(method, basePath) {
|
|
2933
3584
|
const params = method.params.map((p) => `${p.name}: ${p.type}`).join(", ");
|
|
2934
3585
|
const hasParams = method.params.length > 0;
|
|
2935
3586
|
let urlBuilder;
|
|
3587
|
+
const headerCheck = `this.${method.name}Headers`;
|
|
2936
3588
|
if (hasParams) {
|
|
2937
3589
|
const queryParams = method.params.map((p) => `${p.name}=\${encodeURIComponent(${p.name})}`).join("&");
|
|
2938
|
-
urlBuilder =
|
|
3590
|
+
urlBuilder = `\`/api/${basePath}/${method.name}?${queryParams}\``;
|
|
2939
3591
|
} else {
|
|
2940
|
-
urlBuilder =
|
|
3592
|
+
urlBuilder = `\`/api/${basePath}/${method.name}\``;
|
|
2941
3593
|
}
|
|
2942
3594
|
return ` ${method.name}(${params}): Observable<${method.returnType}> {
|
|
2943
3595
|
return new Observable((observer) => {
|
|
2944
|
-
|
|
3596
|
+
let url = ${urlBuilder};
|
|
2945
3597
|
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
3598
|
+
// Get headers and append them as query parameters for SSE
|
|
3599
|
+
const getHeaders = async () => {
|
|
3600
|
+
let headers = ${headerCheck}?.() || {};
|
|
3601
|
+
|
|
3602
|
+
if (headers instanceof Promise) {
|
|
3603
|
+
headers = await headers;
|
|
3604
|
+
}
|
|
3605
|
+
|
|
3606
|
+
// Convert headers to query parameters for EventSource
|
|
3607
|
+
const headerParams = new URLSearchParams();
|
|
3608
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
3609
|
+
headerParams.append(key, String(value));
|
|
2952
3610
|
}
|
|
3611
|
+
|
|
3612
|
+
const headerString = headerParams.toString();
|
|
3613
|
+
if (headerString) {
|
|
3614
|
+
url += ${hasParams ? "`&${headerString}`" : "`?${headerString}`"};
|
|
3615
|
+
}
|
|
3616
|
+
|
|
3617
|
+
const eventSource = new EventSource(url);
|
|
3618
|
+
|
|
3619
|
+
eventSource.onmessage = (event) => {
|
|
3620
|
+
try {
|
|
3621
|
+
const data = JSON.parse(event.data);
|
|
3622
|
+
observer.next(data);
|
|
3623
|
+
} catch (error) {
|
|
3624
|
+
observer.error?.(error);
|
|
3625
|
+
}
|
|
3626
|
+
};
|
|
3627
|
+
|
|
3628
|
+
eventSource.onerror = (error) => {
|
|
3629
|
+
observer.error?.(error);
|
|
3630
|
+
eventSource.close();
|
|
3631
|
+
};
|
|
3632
|
+
|
|
3633
|
+
return () => {
|
|
3634
|
+
eventSource.close();
|
|
3635
|
+
};
|
|
2953
3636
|
};
|
|
2954
3637
|
|
|
2955
|
-
|
|
3638
|
+
getHeaders().then((cleanup) => {
|
|
3639
|
+
// Store cleanup function for unsubscribe
|
|
3640
|
+
if (cleanup) {
|
|
3641
|
+
observer.add(cleanup);
|
|
3642
|
+
}
|
|
3643
|
+
}).catch((error) => {
|
|
2956
3644
|
observer.error?.(error);
|
|
2957
|
-
|
|
2958
|
-
};
|
|
3645
|
+
});
|
|
2959
3646
|
|
|
2960
3647
|
return () => {
|
|
2961
|
-
|
|
3648
|
+
// Cleanup handled in getHeaders
|
|
2962
3649
|
};
|
|
2963
3650
|
});
|
|
2964
3651
|
}`;
|
|
@@ -2967,10 +3654,17 @@ function generateGetMethod(method, basePath) {
|
|
|
2967
3654
|
const params = method.params.map((p) => `${p.name}: ${p.type}`).join(", ");
|
|
2968
3655
|
const returnType = `Promise<${method.returnType}>`;
|
|
2969
3656
|
return ` async ${method.name}(${params}): ${returnType} {
|
|
2970
|
-
|
|
3657
|
+
let headers = this.${method.name}Headers?.() || {};
|
|
3658
|
+
|
|
3659
|
+
if(headers instanceof Promise) {
|
|
3660
|
+
headers = await headers;
|
|
3661
|
+
}
|
|
3662
|
+
|
|
3663
|
+
const response = await fetch(\`/api/${basePath}/${method.name}\`, {
|
|
2971
3664
|
method: 'GET',
|
|
2972
3665
|
headers: {
|
|
2973
3666
|
'Content-Type': 'application/json',
|
|
3667
|
+
...headers
|
|
2974
3668
|
}
|
|
2975
3669
|
});
|
|
2976
3670
|
|
|
@@ -2985,10 +3679,17 @@ function generatePostMethod(method, basePath, params) {
|
|
|
2985
3679
|
const paramNames = method.params.map((p) => p.name).join(", ");
|
|
2986
3680
|
const returnType = `Promise<${method.returnType}>`;
|
|
2987
3681
|
return ` async ${method.name}(${params}): ${returnType} {
|
|
2988
|
-
|
|
3682
|
+
let headers = this.${method.name}Headers?.() || {};
|
|
3683
|
+
|
|
3684
|
+
if(headers instanceof Promise) {
|
|
3685
|
+
headers = await headers;
|
|
3686
|
+
}
|
|
3687
|
+
|
|
3688
|
+
const response = await fetch(\`/api/${basePath}/${method.name}\`, {
|
|
2989
3689
|
method: 'POST',
|
|
2990
3690
|
headers: {
|
|
2991
3691
|
'Content-Type': 'application/json',
|
|
3692
|
+
...headers
|
|
2992
3693
|
},
|
|
2993
3694
|
body: JSON.stringify({ ${paramNames} }),
|
|
2994
3695
|
});
|
|
@@ -3045,11 +3746,11 @@ function parseFileMetadata(source, path17) {
|
|
|
3045
3746
|
}
|
|
3046
3747
|
var ServerBuildTransformer = class {
|
|
3047
3748
|
async transformPublicFile(source, path17) {
|
|
3048
|
-
const
|
|
3049
|
-
if (
|
|
3050
|
-
source = `${
|
|
3749
|
+
const result = generateController(path17, source);
|
|
3750
|
+
if (result) {
|
|
3751
|
+
source = `${result.transformedServiceCode}
|
|
3051
3752
|
|
|
3052
|
-
${controllerCode}
|
|
3753
|
+
${result.controllerCode}
|
|
3053
3754
|
`;
|
|
3054
3755
|
}
|
|
3055
3756
|
return swcTransform(source, path17);
|
|
@@ -3184,7 +3885,48 @@ function useMyPlugin(options) {
|
|
|
3184
3885
|
import { parseSync as parseSync4 } from "@swc/core";
|
|
3185
3886
|
import * as fs3 from "fs";
|
|
3186
3887
|
import * as path7 from "path";
|
|
3888
|
+
function findProjectRoot(startPath) {
|
|
3889
|
+
let currentDir = path7.dirname(startPath);
|
|
3890
|
+
while (currentDir !== path7.parse(currentDir).root) {
|
|
3891
|
+
const packageJsonPath = path7.join(currentDir, "package.json");
|
|
3892
|
+
if (fs3.existsSync(packageJsonPath)) {
|
|
3893
|
+
return currentDir;
|
|
3894
|
+
}
|
|
3895
|
+
currentDir = path7.dirname(currentDir);
|
|
3896
|
+
}
|
|
3897
|
+
return process.cwd();
|
|
3898
|
+
}
|
|
3899
|
+
function resolvePathAlias(importPath, projectRoot) {
|
|
3900
|
+
if (importPath.startsWith("@/")) {
|
|
3901
|
+
const possiblePaths = [
|
|
3902
|
+
path7.join(projectRoot, "src", importPath.slice(2)),
|
|
3903
|
+
path7.join(projectRoot, importPath.slice(2))
|
|
3904
|
+
];
|
|
3905
|
+
for (const possiblePath of possiblePaths) {
|
|
3906
|
+
const extensions = ["", ".ts", ".tsx", ".js", ".jsx"];
|
|
3907
|
+
for (const ext of extensions) {
|
|
3908
|
+
const fullPath = possiblePath + ext;
|
|
3909
|
+
if (fs3.existsSync(fullPath) && fs3.statSync(fullPath).isFile()) {
|
|
3910
|
+
return fullPath;
|
|
3911
|
+
}
|
|
3912
|
+
}
|
|
3913
|
+
const indexFiles = ["/index.ts", "/index.tsx", "/index.js", "/index.jsx"];
|
|
3914
|
+
for (const indexFile of indexFiles) {
|
|
3915
|
+
const fullPath = possiblePath + indexFile;
|
|
3916
|
+
if (fs3.existsSync(fullPath) && fs3.statSync(fullPath).isFile()) {
|
|
3917
|
+
return fullPath;
|
|
3918
|
+
}
|
|
3919
|
+
}
|
|
3920
|
+
}
|
|
3921
|
+
}
|
|
3922
|
+
return null;
|
|
3923
|
+
}
|
|
3187
3924
|
function resolveFilePath(fromFile, importPath) {
|
|
3925
|
+
if (importPath.startsWith("@/")) {
|
|
3926
|
+
const projectRoot = findProjectRoot(fromFile);
|
|
3927
|
+
const aliasResolved = resolvePathAlias(importPath, projectRoot);
|
|
3928
|
+
if (aliasResolved) return aliasResolved;
|
|
3929
|
+
}
|
|
3188
3930
|
if (!importPath.startsWith(".")) return null;
|
|
3189
3931
|
const dir = path7.dirname(fromFile);
|
|
3190
3932
|
const basePath = path7.resolve(dir, importPath);
|
|
@@ -3607,7 +4349,7 @@ export async function navigate(event, url) {
|
|
|
3607
4349
|
const injector = getCurrentInjector();
|
|
3608
4350
|
|
|
3609
4351
|
if (injector) {
|
|
3610
|
-
const navigate = injector.resolve(Navigate);
|
|
4352
|
+
const navigate = await injector.resolve(Navigate);
|
|
3611
4353
|
navigate.go(url);
|
|
3612
4354
|
} else {
|
|
3613
4355
|
window.location.href = url;
|
|
@@ -3670,7 +4412,7 @@ var HotReloadManager = class {
|
|
|
3670
4412
|
});
|
|
3671
4413
|
});
|
|
3672
4414
|
this.logger.info(
|
|
3673
|
-
`Hot
|
|
4415
|
+
`Hot reloads servers listening on ws://localhost:${this.port}`
|
|
3674
4416
|
);
|
|
3675
4417
|
}
|
|
3676
4418
|
reload() {
|
|
@@ -4892,7 +5634,7 @@ function createPage(name) {
|
|
|
4892
5634
|
import { ${listComponent} } from "./components/${name}-list.component";
|
|
4893
5635
|
|
|
4894
5636
|
@Component({
|
|
4895
|
-
|
|
5637
|
+
inject: [${listComponent}]
|
|
4896
5638
|
})
|
|
4897
5639
|
export class ${pageName} {
|
|
4898
5640
|
build() {
|
|
@@ -4988,7 +5730,8 @@ function genPackageJson(name) {
|
|
|
4988
5730
|
"reflect-metadata": "latest",
|
|
4989
5731
|
zod: "^4.2.1",
|
|
4990
5732
|
"@kithinji/orca": "latest",
|
|
4991
|
-
"@kithinji/arcane": "latest"
|
|
5733
|
+
"@kithinji/arcane": "latest",
|
|
5734
|
+
rxjs: "latest"
|
|
4992
5735
|
},
|
|
4993
5736
|
devDependencies: {
|
|
4994
5737
|
"@types/node": "^20.19.27",
|
|
@@ -5011,6 +5754,7 @@ function gentsconfig() {
|
|
|
5011
5754
|
jsxImportSource: "@kithinji/orca",
|
|
5012
5755
|
experimentalDecorators: true,
|
|
5013
5756
|
emitDecoratorMetadata: true,
|
|
5757
|
+
strictPropertyInitialization: false,
|
|
5014
5758
|
baseUrl: ".",
|
|
5015
5759
|
paths: {
|
|
5016
5760
|
"@/*": ["src/*"]
|
|
@@ -5057,7 +5801,7 @@ function genIndexHtml(name) {
|
|
|
5057
5801
|
<meta charset="UTF-8" />
|
|
5058
5802
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
5059
5803
|
<title>${name} app</title>
|
|
5060
|
-
<link rel="stylesheet" href="index.css" />
|
|
5804
|
+
<link rel="stylesheet" href="/index.css" />
|
|
5061
5805
|
</head>
|
|
5062
5806
|
<body>
|
|
5063
5807
|
<div id="root"></div>
|
|
@@ -5079,7 +5823,7 @@ import {
|
|
|
5079
5823
|
} from "@kithinji/orca";
|
|
5080
5824
|
|
|
5081
5825
|
@Component({
|
|
5082
|
-
|
|
5826
|
+
inject: [RouterOutlet],
|
|
5083
5827
|
})
|
|
5084
5828
|
class AppComponent {
|
|
5085
5829
|
build() {
|
|
@@ -5094,8 +5838,8 @@ class AppComponent {
|
|
|
5094
5838
|
})
|
|
5095
5839
|
class AppModule {}
|
|
5096
5840
|
|
|
5097
|
-
export function bootstrap() {
|
|
5098
|
-
BrowserFactory.create(AppModule, document.getElementById("root")!);
|
|
5841
|
+
export async function bootstrap() {
|
|
5842
|
+
await BrowserFactory.create(AppModule, document.getElementById("root")!);
|
|
5099
5843
|
}
|
|
5100
5844
|
|
|
5101
5845
|
bootstrap();
|
|
@@ -6770,7 +7514,7 @@ async function compileFiles(entryPoints) {
|
|
|
6770
7514
|
|
|
6771
7515
|
// src/index.ts
|
|
6772
7516
|
var program = new Command();
|
|
6773
|
-
program.name("pod").description("Pod cli tool").version("1.0.
|
|
7517
|
+
program.name("pod").description("Pod cli tool").version("1.0.46");
|
|
6774
7518
|
program.command("new <name> [type]").description("Start a new Orca Project").action(async (name, type) => {
|
|
6775
7519
|
const orca = async () => {
|
|
6776
7520
|
await addNew(name);
|