@luckystack/devkit 0.10.2 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +9 -0
- package/CHANGELOG.md +20 -0
- package/README.md +2 -37
- package/dist/{chunk-IWGWJU4M.js → chunk-BJN4XIUX.js} +1 -1
- package/dist/{chunk-IWGWJU4M.js.map → chunk-BJN4XIUX.js.map} +1 -1
- package/dist/cli/validateDeploy.d.ts +2 -0
- package/dist/cli/validateDeploy.js +2 -2
- package/dist/cli/validateDeploy.js.map +1 -1
- package/dist/functionRegistry.d.ts +72 -0
- package/dist/hotReload.d.ts +1 -0
- package/dist/importDependencyGraph.d.ts +2 -0
- package/dist/index.d.ts +15 -280
- package/dist/index.js +558 -431
- package/dist/index.js.map +1 -1
- package/dist/internal/mapUtils.d.ts +2 -0
- package/dist/loader.d.ts +11 -0
- package/dist/prismaClientCheck.d.ts +19 -0
- package/dist/routeConventions.d.ts +20 -0
- package/dist/routeNamingValidation.d.ts +46 -0
- package/dist/routingRules.d.ts +62 -0
- package/dist/runtimeTypeResolver.d.ts +15 -0
- package/dist/supervisor.d.ts +25 -0
- package/dist/templateInjector.d.ts +60 -0
- package/dist/templateRegistry.d.ts +78 -0
- package/dist/typeMap/apiMeta.d.ts +42 -0
- package/dist/typeMap/discovery.d.ts +3 -0
- package/dist/typeMap/emitterArtifacts.d.ts +94 -0
- package/dist/typeMap/extractionDiagnostics.d.ts +16 -0
- package/dist/typeMap/extractors.d.ts +18 -0
- package/dist/typeMap/functionsMeta.d.ts +5 -0
- package/dist/typeMap/routeMeta.d.ts +6 -0
- package/dist/typeMap/tsApi.d.ts +12 -0
- package/dist/typeMap/tsProgram.d.ts +41 -0
- package/dist/typeMap/typeContext.d.ts +21 -0
- package/dist/typeMap/zodEmitter.d.ts +8 -0
- package/dist/typeMapGenerator.d.ts +5 -0
- package/dist/validateDeploy.d.ts +25 -0
- package/docs/cli.md +3 -243
- package/docs/hot-reload.md +4 -362
- package/docs/loader-pipeline.md +3 -322
- package/docs/runtime-type-resolver.md +3 -256
- package/docs/supervisor.md +3 -290
- package/docs/template-customization.md +2 -133
- package/docs/ts-program-cache.md +4 -197
- package/docs/type-map-generation.md +5 -418
- package/package.json +6 -6
- package/CLAUDE.md +0 -135
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
validateDeploy
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-BJN4XIUX.js";
|
|
4
4
|
|
|
5
5
|
// src/typeMap/discovery.ts
|
|
6
6
|
import fs2 from "fs";
|
|
@@ -567,34 +567,98 @@ var extractSyncVersion = (filePath) => {
|
|
|
567
567
|
};
|
|
568
568
|
|
|
569
569
|
// src/typeMap/apiMeta.ts
|
|
570
|
-
import
|
|
571
|
-
import
|
|
570
|
+
import fs4 from "fs";
|
|
571
|
+
import {
|
|
572
|
+
getJSDocTags,
|
|
573
|
+
SyntaxKind
|
|
574
|
+
} from "typescript-7-api/ast";
|
|
575
|
+
import {
|
|
576
|
+
isArrayLiteralExpression,
|
|
577
|
+
isAsExpression,
|
|
578
|
+
isIdentifier,
|
|
579
|
+
isNumericLiteral,
|
|
580
|
+
isObjectLiteralExpression,
|
|
581
|
+
isParenthesizedExpression,
|
|
582
|
+
isPropertyAssignment,
|
|
583
|
+
isSatisfiesExpression,
|
|
584
|
+
isStringLiteral,
|
|
585
|
+
isVariableStatement
|
|
586
|
+
} from "typescript-7-api/ast/is";
|
|
572
587
|
import { inferHttpMethod, tryCatchSync } from "@luckystack/core";
|
|
588
|
+
|
|
589
|
+
// src/typeMap/tsApi.ts
|
|
590
|
+
import fs3 from "fs";
|
|
591
|
+
import path4 from "path";
|
|
592
|
+
import { API } from "typescript-7-api/sync";
|
|
593
|
+
import { ROOT_DIR as ROOT_DIR3 } from "@luckystack/core";
|
|
594
|
+
var api = null;
|
|
595
|
+
var serverSnapshot = null;
|
|
596
|
+
var serverProject = null;
|
|
597
|
+
var getTsApi = () => {
|
|
598
|
+
api ??= new API({ cwd: ROOT_DIR3 });
|
|
599
|
+
return api;
|
|
600
|
+
};
|
|
601
|
+
var openTsconfigProject = (tsconfigPath) => {
|
|
602
|
+
const tsApi = getTsApi();
|
|
603
|
+
const { fileNames, options } = tsApi.parseConfigFile(tsconfigPath);
|
|
604
|
+
const snapshot = tsApi.createSnapshot({ createPrograms: [{ rootFiles: fileNames, compilerOptions: options }] });
|
|
605
|
+
const [program] = snapshot.operation.createdPrograms;
|
|
606
|
+
return { project: program.getProject(), snapshot };
|
|
607
|
+
};
|
|
608
|
+
var getServerProgram = () => {
|
|
609
|
+
if (serverProject) return serverProject;
|
|
610
|
+
const tsconfigPath = path4.join(ROOT_DIR3, "tsconfig.server.json");
|
|
611
|
+
if (!fs3.existsSync(tsconfigPath)) throw new Error("[TypeProgram] tsconfig.server.json not found");
|
|
612
|
+
const { project, snapshot } = openTsconfigProject(tsconfigPath);
|
|
613
|
+
serverSnapshot = snapshot;
|
|
614
|
+
serverProject = project;
|
|
615
|
+
return project;
|
|
616
|
+
};
|
|
617
|
+
var invalidateProgramCache = () => {
|
|
618
|
+
serverSnapshot?.dispose();
|
|
619
|
+
serverSnapshot = null;
|
|
620
|
+
serverProject = null;
|
|
621
|
+
};
|
|
622
|
+
var disposeTsApi = () => {
|
|
623
|
+
invalidateProgramCache();
|
|
624
|
+
api?.close();
|
|
625
|
+
api = null;
|
|
626
|
+
};
|
|
627
|
+
var parseSourceText = (fileName, text, scriptKind) => {
|
|
628
|
+
const retained = getTsApi().createSourceFile(fileName, text, scriptKind === void 0 ? void 0 : { scriptKind });
|
|
629
|
+
retained.dispose();
|
|
630
|
+
return retained.sourceFile;
|
|
631
|
+
};
|
|
632
|
+
var transpileSourceText = (fileName, text) => {
|
|
633
|
+
return getTsApi().transpileModule(text, { fileName, reportDiagnostics: true });
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
// src/typeMap/apiMeta.ts
|
|
573
637
|
var findExportedConst = (sourceFile, name) => {
|
|
574
638
|
for (const statement of sourceFile.statements) {
|
|
575
|
-
if (!
|
|
576
|
-
const hasExport = statement.modifiers?.some((m) => m.kind ===
|
|
639
|
+
if (!isVariableStatement(statement)) continue;
|
|
640
|
+
const hasExport = statement.modifiers?.some((m) => m.kind === SyntaxKind.ExportKeyword);
|
|
577
641
|
if (!hasExport) continue;
|
|
578
642
|
for (const decl of statement.declarationList.declarations) {
|
|
579
|
-
if (
|
|
643
|
+
if (isIdentifier(decl.name) && decl.name.text === name) return decl;
|
|
580
644
|
}
|
|
581
645
|
}
|
|
582
646
|
return null;
|
|
583
647
|
};
|
|
584
648
|
var unwrapExpression = (node) => {
|
|
585
649
|
let current = node;
|
|
586
|
-
while (
|
|
650
|
+
while (isAsExpression(current) || isSatisfiesExpression(current) || isParenthesizedExpression(current)) {
|
|
587
651
|
current = current.expression;
|
|
588
652
|
}
|
|
589
653
|
return current;
|
|
590
654
|
};
|
|
591
655
|
var extractHttpMethod = (filePath, apiName) => {
|
|
592
656
|
const [error, method] = tryCatchSync(() => {
|
|
593
|
-
const content =
|
|
594
|
-
const sourceFile =
|
|
657
|
+
const content = fs4.readFileSync(filePath, "utf8");
|
|
658
|
+
const sourceFile = parseSourceText(filePath, content);
|
|
595
659
|
const decl = findExportedConst(sourceFile, "httpMethod");
|
|
596
660
|
const initializer = decl?.initializer ? unwrapExpression(decl.initializer) : void 0;
|
|
597
|
-
if (initializer &&
|
|
661
|
+
if (initializer && isStringLiteral(initializer)) {
|
|
598
662
|
const candidate = initializer.text.toUpperCase();
|
|
599
663
|
if (["GET", "POST", "PUT", "DELETE"].includes(candidate)) return candidate;
|
|
600
664
|
}
|
|
@@ -607,13 +671,13 @@ var extractHttpMethod = (filePath, apiName) => {
|
|
|
607
671
|
};
|
|
608
672
|
var extractRateLimit = (filePath) => {
|
|
609
673
|
const [error, rateLimit] = tryCatchSync(() => {
|
|
610
|
-
const content =
|
|
611
|
-
const sourceFile =
|
|
674
|
+
const content = fs4.readFileSync(filePath, "utf8");
|
|
675
|
+
const sourceFile = parseSourceText(filePath, content);
|
|
612
676
|
const decl = findExportedConst(sourceFile, "rateLimit");
|
|
613
677
|
if (decl?.initializer) {
|
|
614
678
|
const initializer = unwrapExpression(decl.initializer);
|
|
615
|
-
if (initializer.kind ===
|
|
616
|
-
if (
|
|
679
|
+
if (initializer.kind === SyntaxKind.FalseKeyword) return false;
|
|
680
|
+
if (isNumericLiteral(initializer)) return Number(initializer.text);
|
|
617
681
|
}
|
|
618
682
|
return void 0;
|
|
619
683
|
});
|
|
@@ -624,16 +688,16 @@ var extractRateLimit = (filePath) => {
|
|
|
624
688
|
};
|
|
625
689
|
var readPrimitive = (rawNode) => {
|
|
626
690
|
const node = unwrapExpression(rawNode);
|
|
627
|
-
if (
|
|
628
|
-
if (
|
|
629
|
-
if (node.kind ===
|
|
630
|
-
if (node.kind ===
|
|
691
|
+
if (isStringLiteral(node)) return node.text;
|
|
692
|
+
if (isNumericLiteral(node)) return Number(node.text);
|
|
693
|
+
if (node.kind === SyntaxKind.TrueKeyword) return true;
|
|
694
|
+
if (node.kind === SyntaxKind.FalseKeyword) return false;
|
|
631
695
|
return void 0;
|
|
632
696
|
};
|
|
633
697
|
var parseAdditionalItem = (objectLiteral) => {
|
|
634
698
|
const item = {};
|
|
635
699
|
for (const prop of objectLiteral.properties) {
|
|
636
|
-
if (!
|
|
700
|
+
if (!isPropertyAssignment(prop) || !isIdentifier(prop.name)) continue;
|
|
637
701
|
const value = readPrimitive(prop.initializer);
|
|
638
702
|
if (value !== void 0) item[prop.name.text] = value;
|
|
639
703
|
}
|
|
@@ -653,8 +717,8 @@ var commentToString = (commentValue) => {
|
|
|
653
717
|
};
|
|
654
718
|
var extractDocsMeta = (filePath) => {
|
|
655
719
|
const [error, docsMeta] = tryCatchSync(() => {
|
|
656
|
-
const content =
|
|
657
|
-
const sourceFile =
|
|
720
|
+
const content = fs4.readFileSync(filePath, "utf8");
|
|
721
|
+
const sourceFile = parseSourceText(filePath, content);
|
|
658
722
|
const result = {};
|
|
659
723
|
const consumeTag = (tag) => {
|
|
660
724
|
if (tag.tagName.text !== "docs") return;
|
|
@@ -673,7 +737,7 @@ var extractDocsMeta = (filePath) => {
|
|
|
673
737
|
}
|
|
674
738
|
};
|
|
675
739
|
for (const statement of sourceFile.statements) {
|
|
676
|
-
for (const tag of
|
|
740
|
+
for (const tag of getJSDocTags(statement)) {
|
|
677
741
|
consumeTag(tag);
|
|
678
742
|
}
|
|
679
743
|
}
|
|
@@ -690,25 +754,25 @@ var extractDocsMeta = (filePath) => {
|
|
|
690
754
|
};
|
|
691
755
|
var extractAuth = (filePath) => {
|
|
692
756
|
const [, auth] = tryCatchSync(() => {
|
|
693
|
-
const content =
|
|
694
|
-
const sourceFile =
|
|
757
|
+
const content = fs4.readFileSync(filePath, "utf8");
|
|
758
|
+
const sourceFile = parseSourceText(filePath, content);
|
|
695
759
|
const decl = findExportedConst(sourceFile, "auth");
|
|
696
760
|
const authInitializer = decl?.initializer ? unwrapExpression(decl.initializer) : void 0;
|
|
697
|
-
if (!authInitializer || !
|
|
761
|
+
if (!authInitializer || !isObjectLiteralExpression(authInitializer)) return { login: false, hasAdditional: false };
|
|
698
762
|
let login = false;
|
|
699
763
|
let additional;
|
|
700
764
|
let hasAdditional = false;
|
|
701
765
|
for (const prop of authInitializer.properties) {
|
|
702
|
-
if (!
|
|
766
|
+
if (!isPropertyAssignment(prop) || !isIdentifier(prop.name)) continue;
|
|
703
767
|
const propInit = unwrapExpression(prop.initializer);
|
|
704
768
|
if (prop.name.text === "login") {
|
|
705
|
-
login = propInit.kind ===
|
|
769
|
+
login = propInit.kind === SyntaxKind.TrueKeyword;
|
|
706
770
|
}
|
|
707
|
-
if (prop.name.text === "additional" &&
|
|
771
|
+
if (prop.name.text === "additional" && isArrayLiteralExpression(propInit)) {
|
|
708
772
|
hasAdditional = propInit.elements.length > 0;
|
|
709
773
|
additional = [];
|
|
710
774
|
for (const element of propInit.elements) {
|
|
711
|
-
if (!
|
|
775
|
+
if (!isObjectLiteralExpression(element)) continue;
|
|
712
776
|
const item = parseAdditionalItem(element);
|
|
713
777
|
if (item) additional.push(item);
|
|
714
778
|
}
|
|
@@ -720,46 +784,78 @@ var extractAuth = (filePath) => {
|
|
|
720
784
|
};
|
|
721
785
|
|
|
722
786
|
// src/typeMap/emitterArtifacts.ts
|
|
723
|
-
import
|
|
724
|
-
import
|
|
725
|
-
import
|
|
787
|
+
import fs5 from "fs";
|
|
788
|
+
import path5 from "path";
|
|
789
|
+
import {
|
|
790
|
+
ScriptKind
|
|
791
|
+
} from "typescript-7-api/ast";
|
|
792
|
+
import {
|
|
793
|
+
isClassDeclaration,
|
|
794
|
+
isEnumDeclaration,
|
|
795
|
+
isFunctionDeclaration,
|
|
796
|
+
isIdentifier as isIdentifier3,
|
|
797
|
+
isImportDeclaration,
|
|
798
|
+
isInferTypeNode,
|
|
799
|
+
isInterfaceDeclaration,
|
|
800
|
+
isMappedTypeNode,
|
|
801
|
+
isNamedImports,
|
|
802
|
+
isNamespaceImport,
|
|
803
|
+
isQualifiedName,
|
|
804
|
+
isTypeAliasDeclaration as isTypeAliasDeclaration2,
|
|
805
|
+
isTypeReferenceNode as isTypeReferenceNode2
|
|
806
|
+
} from "typescript-7-api/ast/is";
|
|
726
807
|
import { getGeneratedApiDocsPath, getGeneratedApiSchemasPath, getGeneratedSocketTypesPath } from "@luckystack/core";
|
|
727
808
|
|
|
728
809
|
// src/typeMap/zodEmitter.ts
|
|
729
|
-
import
|
|
810
|
+
import { SyntaxKind as SyntaxKind2 } from "typescript-7-api/ast";
|
|
811
|
+
import {
|
|
812
|
+
isArrayTypeNode,
|
|
813
|
+
isIdentifier as isIdentifier2,
|
|
814
|
+
isIndexSignatureDeclaration,
|
|
815
|
+
isIntersectionTypeNode,
|
|
816
|
+
isLiteralTypeNode,
|
|
817
|
+
isNumericLiteral as isNumericLiteral2,
|
|
818
|
+
isParenthesizedTypeNode,
|
|
819
|
+
isPropertySignatureDeclaration,
|
|
820
|
+
isStringLiteral as isStringLiteral2,
|
|
821
|
+
isTypeAliasDeclaration,
|
|
822
|
+
isTypeLiteralNode,
|
|
823
|
+
isTypeReferenceNode,
|
|
824
|
+
isUnionTypeNode
|
|
825
|
+
} from "typescript-7-api/ast/is";
|
|
730
826
|
var wrapOptional = (inner) => `${inner}.optional()`;
|
|
731
827
|
var anyFallback = (reason) => `z.any() /* ${reason} */`;
|
|
732
828
|
var convertTypeNode = (node) => {
|
|
733
|
-
if (node.kind ===
|
|
734
|
-
if (node.kind ===
|
|
735
|
-
if (node.kind ===
|
|
736
|
-
if (node.kind ===
|
|
737
|
-
if (node.kind ===
|
|
738
|
-
if (node.kind ===
|
|
739
|
-
if (node.kind ===
|
|
740
|
-
if (node.kind ===
|
|
741
|
-
if (
|
|
829
|
+
if (node.kind === SyntaxKind2.StringKeyword) return "z.string()";
|
|
830
|
+
if (node.kind === SyntaxKind2.NumberKeyword) return "z.number()";
|
|
831
|
+
if (node.kind === SyntaxKind2.BooleanKeyword) return "z.boolean()";
|
|
832
|
+
if (node.kind === SyntaxKind2.NullKeyword) return "z.null()";
|
|
833
|
+
if (node.kind === SyntaxKind2.UndefinedKeyword) return "z.undefined()";
|
|
834
|
+
if (node.kind === SyntaxKind2.AnyKeyword) return "z.any()";
|
|
835
|
+
if (node.kind === SyntaxKind2.UnknownKeyword) return "z.unknown()";
|
|
836
|
+
if (node.kind === SyntaxKind2.NeverKeyword) return "z.never()";
|
|
837
|
+
if (isLiteralTypeNode(node)) {
|
|
742
838
|
const literal = node.literal;
|
|
743
|
-
if (
|
|
744
|
-
if (
|
|
745
|
-
if (literal.kind ===
|
|
746
|
-
if (literal.kind ===
|
|
747
|
-
if (literal.kind ===
|
|
839
|
+
if (isStringLiteral2(literal)) return `z.literal(${JSON.stringify(literal.text)})`;
|
|
840
|
+
if (isNumericLiteral2(literal)) return `z.literal(${literal.text})`;
|
|
841
|
+
if (literal.kind === SyntaxKind2.TrueKeyword) return "z.literal(true)";
|
|
842
|
+
if (literal.kind === SyntaxKind2.FalseKeyword) return "z.literal(false)";
|
|
843
|
+
if (literal.kind === SyntaxKind2.NullKeyword) return "z.null()";
|
|
748
844
|
return anyFallback("unknown literal");
|
|
749
845
|
}
|
|
750
|
-
if (
|
|
846
|
+
if (isArrayTypeNode(node)) {
|
|
751
847
|
return `z.array(${convertTypeNode(node.elementType)})`;
|
|
752
848
|
}
|
|
753
|
-
if (
|
|
849
|
+
if (isUnionTypeNode(node)) {
|
|
754
850
|
const members = node.types;
|
|
755
|
-
const hasUndefined = members.some((m) => m.kind ===
|
|
756
|
-
const nonUndef = members.filter((m) => m.kind !==
|
|
851
|
+
const hasUndefined = members.some((m) => m.kind === SyntaxKind2.UndefinedKeyword);
|
|
852
|
+
const nonUndef = members.filter((m) => m.kind !== SyntaxKind2.UndefinedKeyword);
|
|
757
853
|
if (nonUndef.length === 0) return "z.undefined()";
|
|
758
854
|
const firstNonUndef = nonUndef[0];
|
|
759
855
|
const innerSchema = nonUndef.length === 1 && firstNonUndef ? convertTypeNode(firstNonUndef) : `z.union([${nonUndef.map((m) => convertTypeNode(m)).join(", ")}])`;
|
|
760
856
|
return hasUndefined ? wrapOptional(innerSchema) : innerSchema;
|
|
761
857
|
}
|
|
762
|
-
if (
|
|
858
|
+
if (isTypeReferenceNode(node)) {
|
|
763
859
|
const name = node.typeName.getText();
|
|
764
860
|
const args = node.typeArguments ?? [];
|
|
765
861
|
switch (name) {
|
|
@@ -787,10 +883,10 @@ var convertTypeNode = (node) => {
|
|
|
787
883
|
}
|
|
788
884
|
}
|
|
789
885
|
}
|
|
790
|
-
if (
|
|
791
|
-
const indexSignatures = node.members.filter((m) =>
|
|
792
|
-
const propertySignatures = node.members.filter((m) =>
|
|
793
|
-
if (indexSignatures.length === 1 && propertySignatures.length === 0 && indexSignatures[0]?.type.kind ===
|
|
886
|
+
if (isTypeLiteralNode(node)) {
|
|
887
|
+
const indexSignatures = node.members.filter((m) => isIndexSignatureDeclaration(m));
|
|
888
|
+
const propertySignatures = node.members.filter((m) => isPropertySignatureDeclaration(m));
|
|
889
|
+
if (indexSignatures.length === 1 && propertySignatures.length === 0 && indexSignatures[0]?.type.kind === SyntaxKind2.NeverKeyword) {
|
|
794
890
|
return "z.object({}).strict()";
|
|
795
891
|
}
|
|
796
892
|
if (indexSignatures.length > 0 && propertySignatures.length === 0) {
|
|
@@ -802,21 +898,21 @@ var convertTypeNode = (node) => {
|
|
|
802
898
|
}
|
|
803
899
|
}
|
|
804
900
|
const entries = propertySignatures.map((prop) => {
|
|
805
|
-
if (!
|
|
901
|
+
if (!isIdentifier2(prop.name)) return null;
|
|
806
902
|
if (!prop.type) return null;
|
|
807
903
|
const name = prop.name.text;
|
|
808
904
|
let schema = convertTypeNode(prop.type);
|
|
809
|
-
if (prop.
|
|
905
|
+
if (prop.postfixToken?.kind === SyntaxKind2.QuestionToken && !schema.endsWith(".optional()")) {
|
|
810
906
|
schema = wrapOptional(schema);
|
|
811
907
|
}
|
|
812
908
|
return `${JSON.stringify(name)}: ${schema}`;
|
|
813
909
|
}).filter((entry) => entry !== null);
|
|
814
910
|
return `z.object({ ${entries.join(", ")} }).strict()`;
|
|
815
911
|
}
|
|
816
|
-
if (
|
|
912
|
+
if (isParenthesizedTypeNode(node)) {
|
|
817
913
|
return convertTypeNode(node.type);
|
|
818
914
|
}
|
|
819
|
-
if (
|
|
915
|
+
if (isIntersectionTypeNode(node)) {
|
|
820
916
|
return anyFallback("intersection not yet supported");
|
|
821
917
|
}
|
|
822
918
|
return anyFallback(`unsupported TypeNode kind=${String(node.kind)}`);
|
|
@@ -825,9 +921,9 @@ var typeTextToZodSource = (typeText) => {
|
|
|
825
921
|
const trimmed = typeText.trim();
|
|
826
922
|
if (!trimmed) return null;
|
|
827
923
|
const synthetic = `type __X = ${trimmed};`;
|
|
828
|
-
const source =
|
|
924
|
+
const source = parseSourceText("__zod.ts", synthetic);
|
|
829
925
|
const statement = source.statements[0];
|
|
830
|
-
if (!statement || !
|
|
926
|
+
if (!statement || !isTypeAliasDeclaration(statement)) return null;
|
|
831
927
|
return convertTypeNode(statement.type);
|
|
832
928
|
};
|
|
833
929
|
|
|
@@ -956,13 +1052,13 @@ var splitVersionedKey = (value) => {
|
|
|
956
1052
|
return { name: name ?? "", version: version ?? "v1" };
|
|
957
1053
|
};
|
|
958
1054
|
var writeFileIfChanged = (filePath, content) => {
|
|
959
|
-
if (
|
|
960
|
-
const currentContent =
|
|
1055
|
+
if (fs5.existsSync(filePath)) {
|
|
1056
|
+
const currentContent = fs5.readFileSync(filePath, "utf8");
|
|
961
1057
|
if (currentContent === content) {
|
|
962
1058
|
return false;
|
|
963
1059
|
}
|
|
964
1060
|
}
|
|
965
|
-
|
|
1061
|
+
fs5.writeFileSync(filePath, content, "utf8");
|
|
966
1062
|
return true;
|
|
967
1063
|
};
|
|
968
1064
|
var indentStr = (str, indentText) => {
|
|
@@ -1001,7 +1097,7 @@ var stripSymbolKeyedMembers = (text) => {
|
|
|
1001
1097
|
return result;
|
|
1002
1098
|
};
|
|
1003
1099
|
var validateGeneratedTypeIdentifiers = (content) => {
|
|
1004
|
-
const sourceFile =
|
|
1100
|
+
const sourceFile = parseSourceText("apiTypes.generated.ts", content, ScriptKind.TS);
|
|
1005
1101
|
const knownSymbols = /* @__PURE__ */ new Set();
|
|
1006
1102
|
const referencedSymbols = /* @__PURE__ */ new Set();
|
|
1007
1103
|
const builtIns = /* @__PURE__ */ new Set([
|
|
@@ -1058,38 +1154,38 @@ var validateGeneratedTypeIdentifiers = (content) => {
|
|
|
1058
1154
|
}
|
|
1059
1155
|
};
|
|
1060
1156
|
const collectKnownSymbols = (node) => {
|
|
1061
|
-
if (
|
|
1157
|
+
if (isInferTypeNode(node)) {
|
|
1062
1158
|
knownSymbols.add(node.typeParameter.name.text);
|
|
1063
1159
|
}
|
|
1064
|
-
if (
|
|
1160
|
+
if (isMappedTypeNode(node)) {
|
|
1065
1161
|
knownSymbols.add(node.typeParameter.name.text);
|
|
1066
1162
|
}
|
|
1067
|
-
if (
|
|
1163
|
+
if (isImportDeclaration(node)) {
|
|
1068
1164
|
const importClause = node.importClause;
|
|
1069
1165
|
if (importClause?.name) knownSymbols.add(importClause.name.text);
|
|
1070
|
-
if (importClause?.namedBindings &&
|
|
1166
|
+
if (importClause?.namedBindings && isNamedImports(importClause.namedBindings)) {
|
|
1071
1167
|
for (const importElement of importClause.namedBindings.elements) {
|
|
1072
1168
|
knownSymbols.add((importElement.propertyName ?? importElement.name).text);
|
|
1073
1169
|
}
|
|
1074
1170
|
}
|
|
1075
|
-
if (importClause?.namedBindings &&
|
|
1171
|
+
if (importClause?.namedBindings && isNamespaceImport(importClause.namedBindings)) {
|
|
1076
1172
|
knownSymbols.add(importClause.namedBindings.name.text);
|
|
1077
1173
|
}
|
|
1078
1174
|
}
|
|
1079
|
-
if (
|
|
1175
|
+
if (isInterfaceDeclaration(node) || isTypeAliasDeclaration2(node) || isClassDeclaration(node) || isEnumDeclaration(node) || isFunctionDeclaration(node)) {
|
|
1080
1176
|
addDeclaredName(node.name);
|
|
1081
1177
|
collectTypeParams(node);
|
|
1082
1178
|
}
|
|
1083
|
-
if (
|
|
1179
|
+
if (isTypeReferenceNode2(node)) {
|
|
1084
1180
|
const typeName = node.typeName;
|
|
1085
|
-
if (
|
|
1181
|
+
if (isIdentifier3(typeName)) {
|
|
1086
1182
|
referencedSymbols.add(typeName.text);
|
|
1087
1183
|
}
|
|
1088
|
-
if (
|
|
1184
|
+
if (isQualifiedName(typeName) && isIdentifier3(typeName.left)) {
|
|
1089
1185
|
referencedSymbols.add(typeName.left.text);
|
|
1090
1186
|
}
|
|
1091
1187
|
}
|
|
1092
|
-
|
|
1188
|
+
node.forEachChild(collectKnownSymbols);
|
|
1093
1189
|
};
|
|
1094
1190
|
collectKnownSymbols(sourceFile);
|
|
1095
1191
|
const unknown = [...referencedSymbols].filter((name) => !knownSymbols.has(name) && !builtIns.has(name)).toSorted();
|
|
@@ -1522,9 +1618,9 @@ var writeTypeMapArtifacts = ({
|
|
|
1522
1618
|
}
|
|
1523
1619
|
}
|
|
1524
1620
|
const docsPath = getGeneratedApiDocsPath();
|
|
1525
|
-
const docsDir =
|
|
1526
|
-
if (!
|
|
1527
|
-
|
|
1621
|
+
const docsDir = path5.dirname(docsPath);
|
|
1622
|
+
if (!fs5.existsSync(docsDir)) {
|
|
1623
|
+
fs5.mkdirSync(docsDir, { recursive: true });
|
|
1528
1624
|
}
|
|
1529
1625
|
const docsContent = JSON.stringify(docsData, null, 2);
|
|
1530
1626
|
const hasUpdatedDocs = writeFileIfChanged(docsPath, docsContent);
|
|
@@ -1532,7 +1628,7 @@ var writeTypeMapArtifacts = ({
|
|
|
1532
1628
|
console.log("[TypeMapGenerator] Generated apiDocs.generated.json");
|
|
1533
1629
|
}
|
|
1534
1630
|
if (diagnosticsData !== void 0) {
|
|
1535
|
-
const diagnosticsPath =
|
|
1631
|
+
const diagnosticsPath = path5.join(path5.dirname(docsPath), "apiTypeDiagnostics.generated.json");
|
|
1536
1632
|
const diagnosticsContent = JSON.stringify(diagnosticsData, null, 2);
|
|
1537
1633
|
const hasUpdatedDiagnostics = writeFileIfChanged(diagnosticsPath, diagnosticsContent);
|
|
1538
1634
|
if (hasUpdatedDiagnostics) {
|
|
@@ -1548,30 +1644,46 @@ var writeTypeMapArtifacts = ({
|
|
|
1548
1644
|
};
|
|
1549
1645
|
|
|
1550
1646
|
// src/typeMap/extractors.ts
|
|
1551
|
-
import
|
|
1552
|
-
import
|
|
1647
|
+
import path7 from "path";
|
|
1648
|
+
import { SymbolFlags as SymbolFlags2 } from "typescript-7-api/sync";
|
|
1649
|
+
import {
|
|
1650
|
+
ScriptKind as ScriptKind2
|
|
1651
|
+
} from "typescript-7-api/ast";
|
|
1652
|
+
import {
|
|
1653
|
+
isArrowFunction,
|
|
1654
|
+
isCallExpression,
|
|
1655
|
+
isFunctionDeclaration as isFunctionDeclaration2,
|
|
1656
|
+
isFunctionExpression,
|
|
1657
|
+
isIdentifier as isIdentifier5,
|
|
1658
|
+
isInterfaceDeclaration as isInterfaceDeclaration2,
|
|
1659
|
+
isObjectLiteralExpression as isObjectLiteralExpression2,
|
|
1660
|
+
isPropertySignatureDeclaration as isPropertySignatureDeclaration2,
|
|
1661
|
+
isReturnStatement,
|
|
1662
|
+
isTypeReferenceNode as isTypeReferenceNode3,
|
|
1663
|
+
isVariableStatement as isVariableStatement2
|
|
1664
|
+
} from "typescript-7-api/ast/is";
|
|
1553
1665
|
|
|
1554
1666
|
// src/typeMap/tsProgram.ts
|
|
1555
|
-
import
|
|
1556
|
-
import
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
};
|
|
1667
|
+
import path6 from "path";
|
|
1668
|
+
import {
|
|
1669
|
+
ObjectFlags,
|
|
1670
|
+
SymbolFlags,
|
|
1671
|
+
TypeFlags
|
|
1672
|
+
} from "typescript-7-api/sync";
|
|
1673
|
+
import { SyntaxKind as SyntaxKind3 } from "typescript-7-api/ast";
|
|
1674
|
+
import {
|
|
1675
|
+
isAsExpression as isAsExpression2,
|
|
1676
|
+
isIdentifier as isIdentifier4,
|
|
1677
|
+
isNoSubstitutionTemplateLiteral,
|
|
1678
|
+
isNumericLiteral as isNumericLiteral3,
|
|
1679
|
+
isParenthesizedExpression as isParenthesizedExpression2,
|
|
1680
|
+
isPrefixUnaryExpression,
|
|
1681
|
+
isPropertyAssignment as isPropertyAssignment2,
|
|
1682
|
+
isShorthandPropertyAssignment,
|
|
1683
|
+
isStringLiteral as isStringLiteral3,
|
|
1684
|
+
isTypeAssertion
|
|
1685
|
+
} from "typescript-7-api/ast/is";
|
|
1686
|
+
import { getGeneratedSocketTypesPath as getGeneratedSocketTypesPath2 } from "@luckystack/core";
|
|
1575
1687
|
var DEPTH_LIMIT = 14;
|
|
1576
1688
|
var JSON_TYPE_NAMES = /* @__PURE__ */ new Set([
|
|
1577
1689
|
"Json",
|
|
@@ -1621,35 +1733,35 @@ var UnsupportedWireTypeError = class extends Error {
|
|
|
1621
1733
|
}
|
|
1622
1734
|
};
|
|
1623
1735
|
var isJsonLikeType = (type, checker) => {
|
|
1624
|
-
const symbolName = type.
|
|
1625
|
-
const aliasName = type.
|
|
1736
|
+
const symbolName = type.getSymbol()?.name ?? "";
|
|
1737
|
+
const aliasName = type.getAliasSymbol()?.name ?? "";
|
|
1626
1738
|
if (JSON_TYPE_NAMES.has(symbolName) || JSON_TYPE_NAMES.has(aliasName)) return true;
|
|
1627
1739
|
const rendered = checker.typeToString(type).trim();
|
|
1628
1740
|
return /^(?:Prisma\.)?(?:Input)?Json(?:Value|Object|Array)$/.test(rendered);
|
|
1629
1741
|
};
|
|
1630
1742
|
var getLiteralTypeFromExpression = (expression, checker, depth) => {
|
|
1631
|
-
if (
|
|
1743
|
+
if (isParenthesizedExpression2(expression)) {
|
|
1632
1744
|
return getLiteralTypeFromExpression(expression.expression, checker, depth);
|
|
1633
1745
|
}
|
|
1634
|
-
if (
|
|
1746
|
+
if (isAsExpression2(expression) || isTypeAssertion(expression)) {
|
|
1635
1747
|
return getLiteralTypeFromExpression(expression.expression, checker, depth);
|
|
1636
1748
|
}
|
|
1637
|
-
if (expression.kind ===
|
|
1638
|
-
if (expression.kind ===
|
|
1639
|
-
if (expression.kind ===
|
|
1640
|
-
if (
|
|
1749
|
+
if (expression.kind === SyntaxKind3.TrueKeyword) return "true";
|
|
1750
|
+
if (expression.kind === SyntaxKind3.FalseKeyword) return "false";
|
|
1751
|
+
if (expression.kind === SyntaxKind3.NullKeyword) return "null";
|
|
1752
|
+
if (isStringLiteral3(expression) || isNoSubstitutionTemplateLiteral(expression)) {
|
|
1641
1753
|
return `'${expression.text.replaceAll("\\", "\\\\").replaceAll("'", String.raw`\'`)}'`;
|
|
1642
1754
|
}
|
|
1643
|
-
if (
|
|
1755
|
+
if (isNumericLiteral3(expression)) {
|
|
1644
1756
|
return expression.text;
|
|
1645
1757
|
}
|
|
1646
|
-
if (
|
|
1758
|
+
if (isPrefixUnaryExpression(expression) && expression.operator === SyntaxKind3.MinusToken && isNumericLiteral3(expression.operand)) {
|
|
1647
1759
|
return `-${expression.operand.text}`;
|
|
1648
1760
|
}
|
|
1649
|
-
if (
|
|
1761
|
+
if (isIdentifier4(expression)) {
|
|
1650
1762
|
const identifierType = checker.getTypeAtLocation(expression);
|
|
1651
|
-
const isLiteralType = (identifierType.flags & (
|
|
1652
|
-
if (isLiteralType || identifierType.
|
|
1763
|
+
const isLiteralType = (identifierType.flags & (TypeFlags.StringLiteral | TypeFlags.NumberLiteral | TypeFlags.BooleanLiteral | TypeFlags.Null | TypeFlags.Undefined)) !== 0;
|
|
1764
|
+
if (isLiteralType || identifierType.isUnionType()) {
|
|
1653
1765
|
const expanded = expandTypeDetailed(identifierType, checker, depth).text;
|
|
1654
1766
|
if (expanded.includes("'") || /\btrue\b|\bfalse\b|\bnull\b|\bundefined\b/.test(expanded)) {
|
|
1655
1767
|
return expanded;
|
|
@@ -1659,13 +1771,15 @@ var getLiteralTypeFromExpression = (expression, checker, depth) => {
|
|
|
1659
1771
|
return null;
|
|
1660
1772
|
};
|
|
1661
1773
|
var getLiteralTypeFromPropertySymbol = (symbol, checker, depth) => {
|
|
1662
|
-
const
|
|
1663
|
-
|
|
1664
|
-
|
|
1774
|
+
for (const handle of symbol.declarations) {
|
|
1775
|
+
if (handle.kind !== SyntaxKind3.PropertyAssignment && handle.kind !== SyntaxKind3.ShorthandPropertyAssignment) continue;
|
|
1776
|
+
const declaration = handle.resolve();
|
|
1777
|
+
if (!declaration) continue;
|
|
1778
|
+
if (isPropertyAssignment2(declaration)) {
|
|
1665
1779
|
const literal = getLiteralTypeFromExpression(declaration.initializer, checker, depth);
|
|
1666
1780
|
if (literal) return literal;
|
|
1667
1781
|
}
|
|
1668
|
-
if (
|
|
1782
|
+
if (isShorthandPropertyAssignment(declaration) && isIdentifier4(declaration.name)) {
|
|
1669
1783
|
const literal = getLiteralTypeFromExpression(declaration.name, checker, depth);
|
|
1670
1784
|
if (literal) return literal;
|
|
1671
1785
|
}
|
|
@@ -1673,10 +1787,10 @@ var getLiteralTypeFromPropertySymbol = (symbol, checker, depth) => {
|
|
|
1673
1787
|
return null;
|
|
1674
1788
|
};
|
|
1675
1789
|
var normalizeImportPath = (targetFilePath) => {
|
|
1676
|
-
const fromDir =
|
|
1790
|
+
const fromDir = path6.dirname(getGeneratedSocketTypesPath2());
|
|
1677
1791
|
const from = fromDir.replaceAll("\\", "/");
|
|
1678
1792
|
const to = targetFilePath.replaceAll("\\", "/");
|
|
1679
|
-
const normalized =
|
|
1793
|
+
const normalized = path6.posix.relative(from, to).replaceAll("\\", "/");
|
|
1680
1794
|
const withoutExtension = normalized.replace(/(\.d)?\.(ts|tsx|js|jsx)$/i, "");
|
|
1681
1795
|
if (withoutExtension.startsWith(".")) return withoutExtension;
|
|
1682
1796
|
return `./${withoutExtension}`;
|
|
@@ -1692,17 +1806,20 @@ var mergeUnresolvedSymbols = (left, right) => {
|
|
|
1692
1806
|
}
|
|
1693
1807
|
return merged;
|
|
1694
1808
|
};
|
|
1809
|
+
var isNodeModulesPath = (filePath) => filePath.includes("/node_modules/") || filePath.includes("\\node_modules\\");
|
|
1810
|
+
var getDeclarationFileName = (symbol) => {
|
|
1811
|
+
const handle = symbol.declarations[0];
|
|
1812
|
+
if (!handle || isNodeModulesPath(handle.path)) return void 0;
|
|
1813
|
+
const fileName = handle.resolve()?.getSourceFile().fileName;
|
|
1814
|
+
return fileName && !isNodeModulesPath(fileName) ? fileName : void 0;
|
|
1815
|
+
};
|
|
1695
1816
|
var collectTypeSymbolFallback = (type) => {
|
|
1696
|
-
const symbol = type.
|
|
1817
|
+
const symbol = type.getAliasSymbol() ?? type.getSymbol();
|
|
1697
1818
|
if (!symbol) return [];
|
|
1698
|
-
const name = symbol.
|
|
1819
|
+
const name = symbol.name;
|
|
1699
1820
|
if (!name || name.startsWith("__")) return [];
|
|
1700
|
-
const
|
|
1701
|
-
if (!
|
|
1702
|
-
const sourceFile = declaration.getSourceFile().fileName;
|
|
1703
|
-
if (!sourceFile || sourceFile.includes("/node_modules/") || sourceFile.includes("\\node_modules\\")) {
|
|
1704
|
-
return [{ name }];
|
|
1705
|
-
}
|
|
1821
|
+
const sourceFile = getDeclarationFileName(symbol);
|
|
1822
|
+
if (!sourceFile) return [{ name }];
|
|
1706
1823
|
return [{
|
|
1707
1824
|
name,
|
|
1708
1825
|
sourceFile,
|
|
@@ -1713,16 +1830,14 @@ var WIRE_PROJECTED_TYPES = /* @__PURE__ */ new Map([["Date", "string"]]);
|
|
|
1713
1830
|
var resolveToJsonReturnType = (type, checker) => {
|
|
1714
1831
|
const toJson = type.getProperty("toJSON");
|
|
1715
1832
|
if (!toJson) return null;
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
const signature = checker.getTypeOfSymbolAtLocation(toJson, declaration).getCallSignatures()[0];
|
|
1833
|
+
if (!toJson.valueDeclaration && toJson.declarations.length === 0) return null;
|
|
1834
|
+
const signature = checker.getNonMissingTypeOfSymbol(toJson).getCallSignatures()[0];
|
|
1719
1835
|
return signature ? signature.getReturnType() : null;
|
|
1720
1836
|
};
|
|
1721
1837
|
var isFunctionValueType = (type) => type.getCallSignatures().length > 0;
|
|
1722
1838
|
var typeNameOf = (type, checker) => {
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
const targetName = objectType.target.getSymbol()?.name;
|
|
1839
|
+
if (type.isTypeReference()) {
|
|
1840
|
+
const targetName = type.getTarget().getSymbol()?.name;
|
|
1726
1841
|
if (targetName) return targetName;
|
|
1727
1842
|
}
|
|
1728
1843
|
return type.getSymbol()?.name ?? checker.typeToString(type);
|
|
@@ -1732,13 +1847,13 @@ var assertSupportedWireType = (type, checker) => {
|
|
|
1732
1847
|
if (TRANSPORT_DEPENDENT_BINARY_TYPES.has(typeName)) {
|
|
1733
1848
|
throw new UnsupportedWireTypeError(typeName);
|
|
1734
1849
|
}
|
|
1735
|
-
if ((type.flags & (
|
|
1850
|
+
if ((type.flags & (TypeFlags.BigInt | TypeFlags.BigIntLiteral)) !== 0) {
|
|
1736
1851
|
throw new UnsupportedWireTypeError("bigint");
|
|
1737
1852
|
}
|
|
1738
1853
|
};
|
|
1739
|
-
var isJsonOmittedValueType = (type) => (type.flags & (
|
|
1854
|
+
var isJsonOmittedValueType = (type) => (type.flags & (TypeFlags.Undefined | TypeFlags.Void | TypeFlags.ESSymbol | TypeFlags.UniqueESSymbol)) !== 0 || isFunctionValueType(type);
|
|
1740
1855
|
var resolveWireConstituents = (type, checker) => {
|
|
1741
|
-
const queue = type.
|
|
1856
|
+
const queue = type.isUnionType() ? [...type.getTypes()] : [type];
|
|
1742
1857
|
const serializable = [];
|
|
1743
1858
|
let omitted = false;
|
|
1744
1859
|
let changed = false;
|
|
@@ -1750,9 +1865,9 @@ var resolveWireConstituents = (type, checker) => {
|
|
|
1750
1865
|
continue;
|
|
1751
1866
|
}
|
|
1752
1867
|
const jsonType = resolveToJsonReturnType(candidate, checker);
|
|
1753
|
-
const effective = jsonType && jsonType !== candidate ? jsonType : candidate;
|
|
1868
|
+
const effective = jsonType && jsonType.id !== candidate.id ? jsonType : candidate;
|
|
1754
1869
|
if (effective !== candidate) changed = true;
|
|
1755
|
-
const effectiveTypes = effective.
|
|
1870
|
+
const effectiveTypes = effective.isUnionType() ? effective.getTypes() : [effective];
|
|
1756
1871
|
for (const effectiveType of effectiveTypes) {
|
|
1757
1872
|
assertSupportedWireType(effectiveType, checker);
|
|
1758
1873
|
if (isJsonOmittedValueType(effectiveType)) {
|
|
@@ -1768,15 +1883,13 @@ var resolveWireConstituents = (type, checker) => {
|
|
|
1768
1883
|
var expandTypeDetailed = (type, checker, depth = 0, state, options) => {
|
|
1769
1884
|
const expandState = state ?? { stackTypeIds: /* @__PURE__ */ new Set(), wireProjection: options?.wireProjection ?? false };
|
|
1770
1885
|
const typeId = type.id;
|
|
1771
|
-
if (typeId
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
};
|
|
1777
|
-
}
|
|
1778
|
-
expandState.stackTypeIds.add(typeId);
|
|
1886
|
+
if (expandState.stackTypeIds.has(typeId)) {
|
|
1887
|
+
return {
|
|
1888
|
+
text: checker.typeToString(type),
|
|
1889
|
+
unresolvedSymbols: collectTypeSymbolFallback(type)
|
|
1890
|
+
};
|
|
1779
1891
|
}
|
|
1892
|
+
expandState.stackTypeIds.add(typeId);
|
|
1780
1893
|
try {
|
|
1781
1894
|
if (expandState.wireProjection) {
|
|
1782
1895
|
assertSupportedWireType(type, checker);
|
|
@@ -1791,14 +1904,14 @@ var expandTypeDetailed = (type, checker, depth = 0, state, options) => {
|
|
|
1791
1904
|
};
|
|
1792
1905
|
}
|
|
1793
1906
|
if (isJsonLikeType(type, checker)) return { text: "JsonValue", unresolvedSymbols: [] };
|
|
1794
|
-
if (type.
|
|
1795
|
-
if (type.
|
|
1796
|
-
if (type.flags & (
|
|
1907
|
+
if (type.isStringLiteralType()) return { text: `'${type.value.replaceAll("\\", "\\\\").replaceAll("'", String.raw`\'`)}'`, unresolvedSymbols: [] };
|
|
1908
|
+
if (type.isNumberLiteralType()) return { text: String(type.value), unresolvedSymbols: [] };
|
|
1909
|
+
if (type.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.Boolean | TypeFlags.BooleanLiteral | TypeFlags.Undefined | TypeFlags.Null | TypeFlags.Any | TypeFlags.Unknown | TypeFlags.Never | TypeFlags.Void)) {
|
|
1797
1910
|
return { text: checker.typeToString(type), unresolvedSymbols: [] };
|
|
1798
1911
|
}
|
|
1799
|
-
if (type.
|
|
1912
|
+
if (type.isUnionType()) {
|
|
1800
1913
|
let unresolvedSymbols = [];
|
|
1801
|
-
const expandedTypes = type.
|
|
1914
|
+
const expandedTypes = type.getTypes().map((innerType) => {
|
|
1802
1915
|
const expanded = expandTypeDetailed(innerType, checker, depth + 1, expandState);
|
|
1803
1916
|
unresolvedSymbols = mergeUnresolvedSymbols(unresolvedSymbols, expanded.unresolvedSymbols);
|
|
1804
1917
|
return expanded.text;
|
|
@@ -1806,20 +1919,19 @@ var expandTypeDetailed = (type, checker, depth = 0, state, options) => {
|
|
|
1806
1919
|
const uniqueTypes = [...new Set(expandedTypes)];
|
|
1807
1920
|
return { text: uniqueTypes.join(" | "), unresolvedSymbols };
|
|
1808
1921
|
}
|
|
1809
|
-
if (type.
|
|
1922
|
+
if (type.isIntersectionType()) {
|
|
1810
1923
|
let unresolvedSymbols = [];
|
|
1811
|
-
const expandedTypes = type.
|
|
1924
|
+
const expandedTypes = type.getTypes().map((innerType) => {
|
|
1812
1925
|
const expanded = expandTypeDetailed(innerType, checker, depth + 1, expandState);
|
|
1813
1926
|
unresolvedSymbols = mergeUnresolvedSymbols(unresolvedSymbols, expanded.unresolvedSymbols);
|
|
1814
1927
|
return expanded.text;
|
|
1815
1928
|
});
|
|
1816
1929
|
return { text: expandedTypes.join(" & "), unresolvedSymbols };
|
|
1817
1930
|
}
|
|
1818
|
-
if (type.
|
|
1819
|
-
const
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
const typeArgs = checker.getTypeArguments(objectType);
|
|
1931
|
+
if (type.isObjectType()) {
|
|
1932
|
+
const tupleTarget = type.isTypeReference() ? type.getTarget() : type;
|
|
1933
|
+
if (tupleTarget.objectFlags & ObjectFlags.Tuple) {
|
|
1934
|
+
const typeArgs = type.isTypeReference() ? checker.getTypeArguments(type) : [];
|
|
1823
1935
|
let unresolvedSymbols = [];
|
|
1824
1936
|
const tupleTypes = typeArgs.map((innerType) => {
|
|
1825
1937
|
const wire = expandState.wireProjection ? resolveWireConstituents(innerType, checker) : { serializable: [innerType], omitted: false };
|
|
@@ -1836,15 +1948,14 @@ var expandTypeDetailed = (type, checker, depth = 0, state, options) => {
|
|
|
1836
1948
|
}
|
|
1837
1949
|
if (expandState.wireProjection) {
|
|
1838
1950
|
const jsonType = resolveToJsonReturnType(type, checker);
|
|
1839
|
-
if (jsonType && jsonType !== type) {
|
|
1951
|
+
if (jsonType && jsonType.id !== type.id) {
|
|
1840
1952
|
return expandTypeDetailed(jsonType, checker, depth + 1, expandState);
|
|
1841
1953
|
}
|
|
1842
1954
|
}
|
|
1843
|
-
if (
|
|
1844
|
-
const
|
|
1845
|
-
const targetName = refType.target.symbol?.name ?? "";
|
|
1955
|
+
if (type.isTypeReference()) {
|
|
1956
|
+
const targetName = type.getTarget().getSymbol()?.name ?? "";
|
|
1846
1957
|
if (targetName === "Array" || targetName === "ReadonlyArray") {
|
|
1847
|
-
const typeArgs = checker.getTypeArguments(
|
|
1958
|
+
const typeArgs = checker.getTypeArguments(type);
|
|
1848
1959
|
const firstArg = typeArgs[0];
|
|
1849
1960
|
if (firstArg) {
|
|
1850
1961
|
const wire = expandState.wireProjection ? resolveWireConstituents(firstArg, checker) : { serializable: [firstArg], omitted: false };
|
|
@@ -1866,7 +1977,7 @@ var expandTypeDetailed = (type, checker, depth = 0, state, options) => {
|
|
|
1866
1977
|
return { text: projected ?? checker.typeToString(type), unresolvedSymbols: [] };
|
|
1867
1978
|
}
|
|
1868
1979
|
}
|
|
1869
|
-
const symbolName = type.
|
|
1980
|
+
const symbolName = (type.getSymbol()?.name ?? "") || (type.getAliasSymbol()?.name ?? "");
|
|
1870
1981
|
if (SKIP_EXPANSION.has(symbolName)) {
|
|
1871
1982
|
const projected = expandState.wireProjection ? WIRE_PROJECTED_TYPES.get(symbolName) : void 0;
|
|
1872
1983
|
return { text: projected ?? checker.typeToString(type), unresolvedSymbols: [] };
|
|
@@ -1877,12 +1988,12 @@ var expandTypeDetailed = (type, checker, depth = 0, state, options) => {
|
|
|
1877
1988
|
const fields = [];
|
|
1878
1989
|
let unresolvedSymbols = [];
|
|
1879
1990
|
for (const prop of props) {
|
|
1880
|
-
if (prop.
|
|
1991
|
+
if (prop.name.startsWith("__@")) continue;
|
|
1881
1992
|
const propType = checker.getTypeOfSymbol(prop);
|
|
1882
1993
|
const wire = expandState.wireProjection ? resolveWireConstituents(propType, checker) : { serializable: [propType], omitted: false };
|
|
1883
1994
|
if (wire.serializable.length === 0) continue;
|
|
1884
1995
|
const literalType = getLiteralTypeFromPropertySymbol(prop, checker, depth + 1);
|
|
1885
|
-
const isOptional = (prop.flags &
|
|
1996
|
+
const isOptional = (prop.flags & SymbolFlags.Optional) !== 0 || wire.omitted;
|
|
1886
1997
|
if (literalType && !wire.omitted) {
|
|
1887
1998
|
fields.push(`${prop.name}${isOptional ? "?" : ""}: ${literalType}`);
|
|
1888
1999
|
continue;
|
|
@@ -1897,7 +2008,7 @@ var expandTypeDetailed = (type, checker, depth = 0, state, options) => {
|
|
|
1897
2008
|
}
|
|
1898
2009
|
for (const indexInfo of indexInfos) {
|
|
1899
2010
|
const keyType = expandTypeDetailed(indexInfo.keyType, checker, depth + 1, expandState);
|
|
1900
|
-
const wire = expandState.wireProjection ? resolveWireConstituents(indexInfo.
|
|
2011
|
+
const wire = expandState.wireProjection ? resolveWireConstituents(indexInfo.valueType, checker) : { serializable: [indexInfo.valueType], omitted: false };
|
|
1901
2012
|
if (wire.serializable.length === 0) continue;
|
|
1902
2013
|
const valueTexts = [];
|
|
1903
2014
|
for (const serializableType of wire.serializable) {
|
|
@@ -1925,9 +2036,7 @@ ${outerIndent}}`,
|
|
|
1925
2036
|
unresolvedSymbols: collectTypeSymbolFallback(type)
|
|
1926
2037
|
};
|
|
1927
2038
|
} finally {
|
|
1928
|
-
|
|
1929
|
-
expandState.stackTypeIds.delete(typeId);
|
|
1930
|
-
}
|
|
2039
|
+
expandState.stackTypeIds.delete(typeId);
|
|
1931
2040
|
}
|
|
1932
2041
|
};
|
|
1933
2042
|
var expandType = (type, checker, depth = 0) => {
|
|
@@ -1969,10 +2078,10 @@ var KNOWN_GLOBAL_TYPE_NAMES = /* @__PURE__ */ new Set([
|
|
|
1969
2078
|
"JsonPrimitive"
|
|
1970
2079
|
]);
|
|
1971
2080
|
var normalizeImportPath2 = (targetFilePath) => {
|
|
1972
|
-
const fromDir =
|
|
2081
|
+
const fromDir = path7.dirname(getGeneratedSocketTypesPath3());
|
|
1973
2082
|
const from = fromDir.replaceAll("\\", "/");
|
|
1974
2083
|
const to = targetFilePath.replaceAll("\\", "/");
|
|
1975
|
-
const normalized =
|
|
2084
|
+
const normalized = path7.posix.relative(from, to).replaceAll("\\", "/");
|
|
1976
2085
|
const withoutExtension = normalized.replace(/(\.d)?\.(ts|tsx|js|jsx)$/i, "");
|
|
1977
2086
|
if (withoutExtension.startsWith(".")) return withoutExtension;
|
|
1978
2087
|
return `./${withoutExtension}`;
|
|
@@ -1992,22 +2101,19 @@ var collectFallbackSymbolsFromTypeText = (typeText, scopeNode, checker) => {
|
|
|
1992
2101
|
const names = new Set((typeText.match(TYPE_NAME_PATTERN) ?? []).filter((name) => !KNOWN_GLOBAL_TYPE_NAMES.has(name)));
|
|
1993
2102
|
const symbolsInScope = checker.getSymbolsInScope(
|
|
1994
2103
|
scopeNode,
|
|
1995
|
-
|
|
2104
|
+
SymbolFlags2.TypeAlias | SymbolFlags2.Interface | SymbolFlags2.Class | SymbolFlags2.Enum | SymbolFlags2.Alias
|
|
1996
2105
|
);
|
|
1997
2106
|
const unresolvedSymbols = [];
|
|
1998
2107
|
for (const name of names) {
|
|
1999
2108
|
const localSymbol = symbolsInScope.find((symbol) => symbol.name === name);
|
|
2000
2109
|
if (!localSymbol) continue;
|
|
2001
|
-
const targetSymbol = (localSymbol.flags &
|
|
2002
|
-
|
|
2003
|
-
if (!declaration) {
|
|
2110
|
+
const targetSymbol = (localSymbol.flags & SymbolFlags2.Alias) === 0 ? localSymbol : checker.getAliasedSymbol(localSymbol);
|
|
2111
|
+
if (targetSymbol.declarations.length === 0) {
|
|
2004
2112
|
unresolvedSymbols.push({ name });
|
|
2005
2113
|
continue;
|
|
2006
2114
|
}
|
|
2007
|
-
const sourceFile =
|
|
2008
|
-
if (!sourceFile
|
|
2009
|
-
continue;
|
|
2010
|
-
}
|
|
2115
|
+
const sourceFile = getDeclarationFileName(targetSymbol);
|
|
2116
|
+
if (!sourceFile) continue;
|
|
2011
2117
|
unresolvedSymbols.push({
|
|
2012
2118
|
name,
|
|
2013
2119
|
sourceFile,
|
|
@@ -2018,13 +2124,13 @@ var collectFallbackSymbolsFromTypeText = (typeText, scopeNode, checker) => {
|
|
|
2018
2124
|
};
|
|
2019
2125
|
var findInterface = (sourceFile, name) => {
|
|
2020
2126
|
for (const stmt of sourceFile.statements) {
|
|
2021
|
-
if (
|
|
2127
|
+
if (isInterfaceDeclaration2(stmt) && stmt.name.text === name) return stmt;
|
|
2022
2128
|
}
|
|
2023
2129
|
return null;
|
|
2024
2130
|
};
|
|
2025
2131
|
var getInterfacePropertyType = (iface, propertyName, checker) => {
|
|
2026
2132
|
for (const member of iface.members) {
|
|
2027
|
-
if (
|
|
2133
|
+
if (isPropertySignatureDeclaration2(member) && isIdentifier5(member.name) && member.name.text === propertyName && member.type) {
|
|
2028
2134
|
return checker.getTypeFromTypeNode(member.type);
|
|
2029
2135
|
}
|
|
2030
2136
|
}
|
|
@@ -2032,14 +2138,14 @@ var getInterfacePropertyType = (iface, propertyName, checker) => {
|
|
|
2032
2138
|
};
|
|
2033
2139
|
var findMainFunction = (sourceFile) => {
|
|
2034
2140
|
for (const stmt of sourceFile.statements) {
|
|
2035
|
-
if (
|
|
2141
|
+
if (isVariableStatement2(stmt)) {
|
|
2036
2142
|
for (const decl of stmt.declarationList.declarations) {
|
|
2037
|
-
if (
|
|
2143
|
+
if (isIdentifier5(decl.name) && decl.name.text === "main" && decl.initializer && (isArrowFunction(decl.initializer) || isFunctionExpression(decl.initializer))) {
|
|
2038
2144
|
return decl.initializer;
|
|
2039
2145
|
}
|
|
2040
2146
|
}
|
|
2041
2147
|
}
|
|
2042
|
-
if (
|
|
2148
|
+
if (isFunctionDeclaration2(stmt) && stmt.name?.text === "main") {
|
|
2043
2149
|
return stmt;
|
|
2044
2150
|
}
|
|
2045
2151
|
}
|
|
@@ -2049,7 +2155,7 @@ var collectReturnObjectTypeDetails = (funcNode, checker) => {
|
|
|
2049
2155
|
const types = [];
|
|
2050
2156
|
let unresolvedSymbols = [];
|
|
2051
2157
|
const visit = (node) => {
|
|
2052
|
-
if (
|
|
2158
|
+
if (isReturnStatement(node) && node.expression && isObjectLiteralExpression2(node.expression)) {
|
|
2053
2159
|
const type = checker.getTypeAtLocation(node.expression);
|
|
2054
2160
|
const expanded = expandTypeDetailed(type, checker, 0, void 0, { wireProjection: true });
|
|
2055
2161
|
types.push(expanded.text);
|
|
@@ -2059,11 +2165,11 @@ var collectReturnObjectTypeDetails = (funcNode, checker) => {
|
|
|
2059
2165
|
collectFallbackSymbolsFromTypeText(expanded.text, node.expression, checker)
|
|
2060
2166
|
);
|
|
2061
2167
|
}
|
|
2062
|
-
if (!
|
|
2063
|
-
|
|
2168
|
+
if (!isArrowFunction(node) && !isFunctionExpression(node) && !isFunctionDeclaration2(node)) {
|
|
2169
|
+
node.forEachChild(visit);
|
|
2064
2170
|
}
|
|
2065
2171
|
};
|
|
2066
|
-
|
|
2172
|
+
funcNode.forEachChild(visit);
|
|
2067
2173
|
return { text: unionTypes(types), unresolvedSymbols };
|
|
2068
2174
|
};
|
|
2069
2175
|
var STREAM_EMIT_NAMES = /* @__PURE__ */ new Set(["stream", "broadcastStream", "streamTo"]);
|
|
@@ -2071,7 +2177,7 @@ var collectStreamCallPayloadTypeDetails = (funcNode, checker) => {
|
|
|
2071
2177
|
const types = [];
|
|
2072
2178
|
let unresolvedSymbols = [];
|
|
2073
2179
|
const visit = (node) => {
|
|
2074
|
-
if (
|
|
2180
|
+
if (isCallExpression(node) && isIdentifier5(node.expression) && STREAM_EMIT_NAMES.has(node.expression.text)) {
|
|
2075
2181
|
const callName = node.expression.text;
|
|
2076
2182
|
const payloadIndex = callName === "streamTo" ? 1 : 0;
|
|
2077
2183
|
const payloadArg = node.arguments[payloadIndex];
|
|
@@ -2089,11 +2195,11 @@ var collectStreamCallPayloadTypeDetails = (funcNode, checker) => {
|
|
|
2089
2195
|
);
|
|
2090
2196
|
}
|
|
2091
2197
|
}
|
|
2092
|
-
if (!
|
|
2093
|
-
|
|
2198
|
+
if (!isArrowFunction(node) && !isFunctionExpression(node) && !isFunctionDeclaration2(node)) {
|
|
2199
|
+
node.forEachChild(visit);
|
|
2094
2200
|
}
|
|
2095
2201
|
};
|
|
2096
|
-
|
|
2202
|
+
funcNode.forEachChild(visit);
|
|
2097
2203
|
return { text: unionTypes(types), unresolvedSymbols };
|
|
2098
2204
|
};
|
|
2099
2205
|
var unionTypes = (types) => {
|
|
@@ -2107,15 +2213,13 @@ var UnsupportedTransportInputError = class extends Error {
|
|
|
2107
2213
|
}
|
|
2108
2214
|
};
|
|
2109
2215
|
var assertTransportInputIsWireSafe = (typeText, filePath) => {
|
|
2110
|
-
const sourceFile =
|
|
2216
|
+
const sourceFile = parseSourceText(
|
|
2111
2217
|
"__luckystack_input_check.ts",
|
|
2112
2218
|
`type __LuckyStackInput = ${typeText};`,
|
|
2113
|
-
|
|
2114
|
-
true,
|
|
2115
|
-
ts5.ScriptKind.TS
|
|
2219
|
+
ScriptKind2.TS
|
|
2116
2220
|
);
|
|
2117
2221
|
const containsDate = (node) => {
|
|
2118
|
-
if (
|
|
2222
|
+
if (isTypeReferenceNode3(node) && isIdentifier5(node.typeName) && node.typeName.text === "Date") {
|
|
2119
2223
|
return true;
|
|
2120
2224
|
}
|
|
2121
2225
|
return node.getChildren(sourceFile).some((child) => containsDate(child));
|
|
@@ -2129,13 +2233,12 @@ var getInputTypeDetailsFromFile = (filePath) => {
|
|
|
2129
2233
|
const DEFAULT = "{ }";
|
|
2130
2234
|
recordExtractionOutcome({ filePath, kind: "api", field: "input", error: null });
|
|
2131
2235
|
try {
|
|
2132
|
-
const program = getServerProgram();
|
|
2236
|
+
const { program, checker } = getServerProgram();
|
|
2133
2237
|
const sourceFile = program.getSourceFile(filePath);
|
|
2134
2238
|
if (!sourceFile) {
|
|
2135
2239
|
console.warn(`[TypeMapGenerator] getSourceFile miss for ${filePath} \u2014 input types will default to { }`);
|
|
2136
2240
|
return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2137
2241
|
}
|
|
2138
|
-
const checker = program.getTypeChecker();
|
|
2139
2242
|
const iface = findInterface(sourceFile, "ApiParams");
|
|
2140
2243
|
if (!iface) return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2141
2244
|
const dataType = getInterfacePropertyType(iface, "data", checker);
|
|
@@ -2161,9 +2264,9 @@ var extractDeclaredStreamTypeFromApiParams = (sourceFile, checker) => {
|
|
|
2161
2264
|
let result = null;
|
|
2162
2265
|
const visit = (node) => {
|
|
2163
2266
|
if (result) return;
|
|
2164
|
-
if (
|
|
2267
|
+
if (isInterfaceDeclaration2(node) && node.name.text.endsWith("Params")) {
|
|
2165
2268
|
for (const member of node.members) {
|
|
2166
|
-
if (
|
|
2269
|
+
if (isPropertySignatureDeclaration2(member) && isIdentifier5(member.name) && member.name.text === "stream" && member.type && isTypeReferenceNode3(member.type) && isIdentifier5(member.type.typeName) && STREAM_EMITTER_TYPE_NAMES.has(member.type.typeName.text)) {
|
|
2167
2270
|
const typeArg = member.type.typeArguments?.[0];
|
|
2168
2271
|
if (typeArg) {
|
|
2169
2272
|
const argType = checker.getNonNullableType(checker.getTypeFromTypeNode(typeArg));
|
|
@@ -2176,7 +2279,7 @@ var extractDeclaredStreamTypeFromApiParams = (sourceFile, checker) => {
|
|
|
2176
2279
|
}
|
|
2177
2280
|
}
|
|
2178
2281
|
}
|
|
2179
|
-
|
|
2282
|
+
node.forEachChild(visit);
|
|
2180
2283
|
};
|
|
2181
2284
|
visit(sourceFile);
|
|
2182
2285
|
return result;
|
|
@@ -2185,10 +2288,9 @@ var getApiStreamPayloadTypeDetailsFromFile = (filePath) => {
|
|
|
2185
2288
|
const DEFAULT = "never";
|
|
2186
2289
|
recordExtractionOutcome({ filePath, kind: "api", field: "stream", error: null });
|
|
2187
2290
|
try {
|
|
2188
|
-
const program = getServerProgram();
|
|
2291
|
+
const { program, checker } = getServerProgram();
|
|
2189
2292
|
const sourceFile = program.getSourceFile(filePath);
|
|
2190
2293
|
if (!sourceFile) return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2191
|
-
const checker = program.getTypeChecker();
|
|
2192
2294
|
const mainFn = findMainFunction(sourceFile);
|
|
2193
2295
|
if (!mainFn) return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2194
2296
|
const details = collectStreamCallPayloadTypeDetails(mainFn, checker);
|
|
@@ -2207,10 +2309,9 @@ var getOutputTypeDetailsFromFile = (filePath) => {
|
|
|
2207
2309
|
const DEFAULT = "{ status: string }";
|
|
2208
2310
|
recordExtractionOutcome({ filePath, kind: "api", field: "output", error: null });
|
|
2209
2311
|
try {
|
|
2210
|
-
const program = getServerProgram();
|
|
2312
|
+
const { program, checker } = getServerProgram();
|
|
2211
2313
|
const sourceFile = program.getSourceFile(filePath);
|
|
2212
2314
|
if (!sourceFile) return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2213
|
-
const checker = program.getTypeChecker();
|
|
2214
2315
|
const mainFn = findMainFunction(sourceFile);
|
|
2215
2316
|
if (!mainFn) return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2216
2317
|
const details = collectReturnObjectTypeDetails(mainFn, checker);
|
|
@@ -2229,10 +2330,9 @@ var getSyncClientDataTypeDetailsFromFile = (filePath) => {
|
|
|
2229
2330
|
const DEFAULT = "{ }";
|
|
2230
2331
|
recordExtractionOutcome({ filePath, kind: "sync", field: "clientInput", error: null });
|
|
2231
2332
|
try {
|
|
2232
|
-
const program = getServerProgram();
|
|
2333
|
+
const { program, checker } = getServerProgram();
|
|
2233
2334
|
const sourceFile = program.getSourceFile(filePath);
|
|
2234
2335
|
if (!sourceFile) return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2235
|
-
const checker = program.getTypeChecker();
|
|
2236
2336
|
const iface = findInterface(sourceFile, "SyncParams");
|
|
2237
2337
|
if (!iface) return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2238
2338
|
const dataType = getInterfacePropertyType(iface, "clientInput", checker) ?? getInterfacePropertyType(iface, "clientData", checker);
|
|
@@ -2251,10 +2351,9 @@ var getSyncServerStreamPayloadTypeDetailsFromFile = (filePath) => {
|
|
|
2251
2351
|
const DEFAULT = "never";
|
|
2252
2352
|
recordExtractionOutcome({ filePath, kind: "sync", field: "serverStream", error: null });
|
|
2253
2353
|
try {
|
|
2254
|
-
const program = getServerProgram();
|
|
2354
|
+
const { program, checker } = getServerProgram();
|
|
2255
2355
|
const sourceFile = program.getSourceFile(filePath);
|
|
2256
2356
|
if (!sourceFile) return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2257
|
-
const checker = program.getTypeChecker();
|
|
2258
2357
|
const mainFn = findMainFunction(sourceFile);
|
|
2259
2358
|
if (!mainFn) return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2260
2359
|
const details = collectStreamCallPayloadTypeDetails(mainFn, checker);
|
|
@@ -2270,10 +2369,9 @@ var getSyncServerOutputTypeDetailsFromFile = (filePath) => {
|
|
|
2270
2369
|
const DEFAULT = "{ status: string }";
|
|
2271
2370
|
recordExtractionOutcome({ filePath, kind: "sync", field: "serverOutput", error: null });
|
|
2272
2371
|
try {
|
|
2273
|
-
const program = getServerProgram();
|
|
2372
|
+
const { program, checker } = getServerProgram();
|
|
2274
2373
|
const sourceFile = program.getSourceFile(filePath);
|
|
2275
2374
|
if (!sourceFile) return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2276
|
-
const checker = program.getTypeChecker();
|
|
2277
2375
|
const mainFn = findMainFunction(sourceFile);
|
|
2278
2376
|
if (!mainFn) return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2279
2377
|
const details = collectReturnObjectTypeDetails(mainFn, checker);
|
|
@@ -2289,10 +2387,9 @@ var getSyncClientStreamPayloadTypeDetailsFromFile = (filePath) => {
|
|
|
2289
2387
|
const DEFAULT = "never";
|
|
2290
2388
|
recordExtractionOutcome({ filePath, kind: "sync", field: "clientStream", error: null });
|
|
2291
2389
|
try {
|
|
2292
|
-
const program = getServerProgram();
|
|
2390
|
+
const { program, checker } = getServerProgram();
|
|
2293
2391
|
const sourceFile = program.getSourceFile(filePath);
|
|
2294
2392
|
if (!sourceFile) return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2295
|
-
const checker = program.getTypeChecker();
|
|
2296
2393
|
const mainFn = findMainFunction(sourceFile);
|
|
2297
2394
|
if (!mainFn) return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2298
2395
|
const details = collectStreamCallPayloadTypeDetails(mainFn, checker);
|
|
@@ -2308,10 +2405,9 @@ var getSyncClientOutputTypeDetailsFromFile = (filePath) => {
|
|
|
2308
2405
|
const DEFAULT = "{ }";
|
|
2309
2406
|
recordExtractionOutcome({ filePath, kind: "sync", field: "clientOutput", error: null });
|
|
2310
2407
|
try {
|
|
2311
|
-
const program = getServerProgram();
|
|
2408
|
+
const { program, checker } = getServerProgram();
|
|
2312
2409
|
const sourceFile = program.getSourceFile(filePath);
|
|
2313
2410
|
if (!sourceFile) return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2314
|
-
const checker = program.getTypeChecker();
|
|
2315
2411
|
const mainFn = findMainFunction(sourceFile);
|
|
2316
2412
|
if (!mainFn) return { text: DEFAULT, unresolvedSymbols: [] };
|
|
2317
2413
|
const details = collectReturnObjectTypeDetails(mainFn, checker);
|
|
@@ -2325,19 +2421,48 @@ var getSyncClientOutputTypeDetailsFromFile = (filePath) => {
|
|
|
2325
2421
|
};
|
|
2326
2422
|
|
|
2327
2423
|
// src/typeMap/functionsMeta.ts
|
|
2328
|
-
import
|
|
2329
|
-
import
|
|
2330
|
-
import
|
|
2424
|
+
import fs7 from "fs";
|
|
2425
|
+
import path10 from "path";
|
|
2426
|
+
import {
|
|
2427
|
+
createScanner,
|
|
2428
|
+
LanguageVariant,
|
|
2429
|
+
SyntaxKind as SyntaxKind5
|
|
2430
|
+
} from "typescript-7-api/ast";
|
|
2431
|
+
import {
|
|
2432
|
+
isArrowFunction as isArrowFunction2,
|
|
2433
|
+
isClassDeclaration as isClassDeclaration3,
|
|
2434
|
+
isEnumDeclaration as isEnumDeclaration3,
|
|
2435
|
+
isExportAssignment,
|
|
2436
|
+
isExportDeclaration,
|
|
2437
|
+
isFunctionDeclaration as isFunctionDeclaration3,
|
|
2438
|
+
isFunctionExpression as isFunctionExpression2,
|
|
2439
|
+
isIdentifier as isIdentifier6,
|
|
2440
|
+
isInterfaceDeclaration as isInterfaceDeclaration4,
|
|
2441
|
+
isNamedExports,
|
|
2442
|
+
isStringLiteral as isStringLiteral5,
|
|
2443
|
+
isTypeAliasDeclaration as isTypeAliasDeclaration4,
|
|
2444
|
+
isVariableStatement as isVariableStatement3
|
|
2445
|
+
} from "typescript-7-api/ast/is";
|
|
2331
2446
|
|
|
2332
2447
|
// src/typeMap/typeContext.ts
|
|
2333
|
-
import
|
|
2334
|
-
import
|
|
2448
|
+
import path8 from "path";
|
|
2449
|
+
import { SyntaxKind as SyntaxKind4 } from "typescript-7-api/ast";
|
|
2450
|
+
import {
|
|
2451
|
+
isClassDeclaration as isClassDeclaration2,
|
|
2452
|
+
isEnumDeclaration as isEnumDeclaration2,
|
|
2453
|
+
isImportDeclaration as isImportDeclaration2,
|
|
2454
|
+
isInterfaceDeclaration as isInterfaceDeclaration3,
|
|
2455
|
+
isNamedImports as isNamedImports2,
|
|
2456
|
+
isNamespaceImport as isNamespaceImport2,
|
|
2457
|
+
isStringLiteral as isStringLiteral4,
|
|
2458
|
+
isTypeAliasDeclaration as isTypeAliasDeclaration3
|
|
2459
|
+
} from "typescript-7-api/ast/is";
|
|
2335
2460
|
import { getGeneratedSocketTypesPath as getGeneratedSocketTypesPath4 } from "@luckystack/core";
|
|
2336
2461
|
var toGeneratedImportPath = (source, filePath) => {
|
|
2337
2462
|
if (!source.startsWith(".")) return source;
|
|
2338
|
-
const outputDir =
|
|
2339
|
-
const absoluteSource =
|
|
2340
|
-
let relPath =
|
|
2463
|
+
const outputDir = path8.dirname(getGeneratedSocketTypesPath4());
|
|
2464
|
+
const absoluteSource = path8.resolve(path8.dirname(filePath), source);
|
|
2465
|
+
let relPath = path8.relative(outputDir, absoluteSource).replaceAll("\\", "/");
|
|
2341
2466
|
relPath = relPath.replace(/\.tsx?$/, "");
|
|
2342
2467
|
if (!relPath.startsWith(".")) relPath = `./${relPath}`;
|
|
2343
2468
|
return relPath;
|
|
@@ -2345,23 +2470,18 @@ var toGeneratedImportPath = (source, filePath) => {
|
|
|
2345
2470
|
var parseFileTypeContext = (content) => {
|
|
2346
2471
|
const availableExports = /* @__PURE__ */ new Set();
|
|
2347
2472
|
const fileImports = /* @__PURE__ */ new Map();
|
|
2348
|
-
const sourceFile =
|
|
2349
|
-
"__temp__.ts",
|
|
2350
|
-
content,
|
|
2351
|
-
ts6.ScriptTarget.Latest,
|
|
2352
|
-
true
|
|
2353
|
-
);
|
|
2473
|
+
const sourceFile = parseSourceText("__temp__.ts", content);
|
|
2354
2474
|
for (const statement of sourceFile.statements) {
|
|
2355
|
-
if (
|
|
2356
|
-
const hasExport = statement.modifiers?.some((m) => m.kind ===
|
|
2475
|
+
if (isInterfaceDeclaration3(statement) || isTypeAliasDeclaration3(statement) || isClassDeclaration2(statement) || isEnumDeclaration2(statement)) {
|
|
2476
|
+
const hasExport = statement.modifiers?.some((m) => m.kind === SyntaxKind4.ExportKeyword);
|
|
2357
2477
|
if (hasExport && statement.name) {
|
|
2358
2478
|
availableExports.add(statement.name.text);
|
|
2359
2479
|
}
|
|
2360
2480
|
continue;
|
|
2361
2481
|
}
|
|
2362
|
-
if (!
|
|
2482
|
+
if (!isImportDeclaration2(statement)) continue;
|
|
2363
2483
|
const moduleSpecifier = statement.moduleSpecifier;
|
|
2364
|
-
if (!
|
|
2484
|
+
if (!isStringLiteral4(moduleSpecifier)) continue;
|
|
2365
2485
|
const source = moduleSpecifier.text;
|
|
2366
2486
|
const importClause = statement.importClause;
|
|
2367
2487
|
if (!importClause) continue;
|
|
@@ -2370,11 +2490,11 @@ var parseFileTypeContext = (content) => {
|
|
|
2370
2490
|
}
|
|
2371
2491
|
const namedBindings = importClause.namedBindings;
|
|
2372
2492
|
if (!namedBindings) continue;
|
|
2373
|
-
if (
|
|
2493
|
+
if (isNamespaceImport2(namedBindings)) {
|
|
2374
2494
|
fileImports.set(namedBindings.name.text, { source, isDefault: true });
|
|
2375
2495
|
continue;
|
|
2376
2496
|
}
|
|
2377
|
-
if (
|
|
2497
|
+
if (isNamedImports2(namedBindings)) {
|
|
2378
2498
|
for (const specifier of namedBindings.elements) {
|
|
2379
2499
|
const localName = specifier.name.text;
|
|
2380
2500
|
const originalName = specifier.propertyName?.text ?? localName;
|
|
@@ -2424,11 +2544,11 @@ var sanitizeTypeAndCollectImports = ({
|
|
|
2424
2544
|
import { getGeneratedSocketTypesPath as getGeneratedSocketTypesPath5, ROOT_DIR as ROOT_DIR5 } from "@luckystack/core";
|
|
2425
2545
|
|
|
2426
2546
|
// src/functionRegistry.ts
|
|
2427
|
-
import
|
|
2428
|
-
import
|
|
2547
|
+
import fs6 from "fs";
|
|
2548
|
+
import path9 from "path";
|
|
2429
2549
|
import { ROOT_DIR as ROOT_DIR4, getServerFunctionDirs, isTestFile as isTestFile2, isTestDirectory as isTestDirectory2 } from "@luckystack/core";
|
|
2430
2550
|
var normalizePath2 = (value) => value.replaceAll("\\", "/");
|
|
2431
|
-
var toWorkspaceRelative = (absolutePath) => normalizePath2(
|
|
2551
|
+
var toWorkspaceRelative = (absolutePath) => normalizePath2(path9.relative(ROOT_DIR4, absolutePath));
|
|
2432
2552
|
var formatFunctionKeyPath = (keyPath) => keyPath.join(".");
|
|
2433
2553
|
var functionModuleFileName = (keyPath) => {
|
|
2434
2554
|
const fileName = keyPath.at(-1);
|
|
@@ -2440,12 +2560,12 @@ var functionModuleFileName = (keyPath) => {
|
|
|
2440
2560
|
var formatFunctionKeyConflict = (keyPath, firstSourcePath, secondSourcePath) => `[function-injection] Conflict at \`functions.${formatFunctionKeyPath(keyPath)}\`: defined in both \`${firstSourcePath}\` and \`${secondSourcePath}\`. Delete one \u2014 \`shared/\` is the canonical location for framework re-exports.`;
|
|
2441
2561
|
var formatFunctionNamespaceConflict = (moduleKeyPath, moduleSourcePath, nestedKeyPath, nestedSourcePath) => `[function-injection] Conflict at \`functions.${formatFunctionKeyPath(moduleKeyPath)}\`: \`${moduleSourcePath}\` defines it as a module, but \`${nestedSourcePath}\` nests \`functions.${formatFunctionKeyPath(nestedKeyPath)}\` underneath it. Rename one \u2014 a key cannot be both a module and a namespace.`;
|
|
2442
2562
|
var walkFunctionRoot = (dir, rootDir, basePath, collected) => {
|
|
2443
|
-
const entries =
|
|
2563
|
+
const entries = fs6.readdirSync(dir).toSorted();
|
|
2444
2564
|
for (const entry of entries) {
|
|
2445
2565
|
if (entry === "node_modules") continue;
|
|
2446
|
-
const fullPath =
|
|
2566
|
+
const fullPath = path9.join(dir, entry);
|
|
2447
2567
|
if (getRoutingRules().ignore(toWorkspaceRelative(fullPath))) continue;
|
|
2448
|
-
if (
|
|
2568
|
+
if (fs6.statSync(fullPath).isDirectory()) {
|
|
2449
2569
|
if (isTestDirectory2(entry)) continue;
|
|
2450
2570
|
walkFunctionRoot(fullPath, rootDir, [...basePath, entry], collected);
|
|
2451
2571
|
continue;
|
|
@@ -2488,7 +2608,7 @@ var collectFunctionModules = (options = {}) => {
|
|
|
2488
2608
|
onConflict(message);
|
|
2489
2609
|
};
|
|
2490
2610
|
for (const root of functionRoots) {
|
|
2491
|
-
if (!
|
|
2611
|
+
if (!fs6.existsSync(root)) continue;
|
|
2492
2612
|
const fromThisRoot = [];
|
|
2493
2613
|
walkFunctionRoot(root, root, [], fromThisRoot);
|
|
2494
2614
|
for (const module of fromThisRoot) {
|
|
@@ -2562,17 +2682,16 @@ var stripDefaultValues = (params) => {
|
|
|
2562
2682
|
return params.replaceAll(/\s*=(?!>)[^,)]+/g, "");
|
|
2563
2683
|
};
|
|
2564
2684
|
var stripLineComments = (value) => {
|
|
2565
|
-
const scanner =
|
|
2566
|
-
ts7.ScriptTarget.Latest,
|
|
2685
|
+
const scanner = createScanner(
|
|
2567
2686
|
/* skipTrivia */
|
|
2568
2687
|
false,
|
|
2569
|
-
|
|
2688
|
+
LanguageVariant.Standard,
|
|
2570
2689
|
value
|
|
2571
2690
|
);
|
|
2572
2691
|
let result = "";
|
|
2573
2692
|
let token = scanner.scan();
|
|
2574
|
-
while (token !==
|
|
2575
|
-
result += token ===
|
|
2693
|
+
while (token !== SyntaxKind5.EndOfFile) {
|
|
2694
|
+
result += token === SyntaxKind5.SingleLineCommentTrivia ? " " : scanner.getTokenText();
|
|
2576
2695
|
token = scanner.scan();
|
|
2577
2696
|
}
|
|
2578
2697
|
return result;
|
|
@@ -2585,9 +2704,9 @@ var simplifyInferredType = (value) => {
|
|
|
2585
2704
|
if (/\bRedis\b/.test(value)) return "Redis";
|
|
2586
2705
|
return value;
|
|
2587
2706
|
};
|
|
2588
|
-
var getGeneratedFileDir = () =>
|
|
2707
|
+
var getGeneratedFileDir = () => path10.dirname(getGeneratedSocketTypesPath5());
|
|
2589
2708
|
var sourceModuleSpecifier = (sourceFilePath) => {
|
|
2590
|
-
const relative =
|
|
2709
|
+
const relative = path10.relative(getGeneratedFileDir(), sourceFilePath).replaceAll("\\", "/").replace(/\.tsx?$/i, "");
|
|
2591
2710
|
return relative.startsWith(".") ? relative : `./${relative}`;
|
|
2592
2711
|
};
|
|
2593
2712
|
var portableInferredValueType = (inferred, sourceFilePath, exportName) => {
|
|
@@ -2598,16 +2717,16 @@ var relativizeModuleSpecifier = (specifier, sourceFilePath) => {
|
|
|
2598
2717
|
if (!specifier.startsWith("./") && !specifier.startsWith("../")) {
|
|
2599
2718
|
return specifier;
|
|
2600
2719
|
}
|
|
2601
|
-
const absolute =
|
|
2602
|
-
const rel =
|
|
2603
|
-
const normalized = rel.split(
|
|
2720
|
+
const absolute = path10.resolve(path10.dirname(sourceFilePath), specifier);
|
|
2721
|
+
const rel = path10.relative(getGeneratedFileDir(), absolute);
|
|
2722
|
+
const normalized = rel.split(path10.sep).join("/");
|
|
2604
2723
|
return normalized.startsWith(".") ? normalized : `./${normalized}`;
|
|
2605
2724
|
};
|
|
2606
2725
|
var findProgramVariableDeclaration = (sourceFile, exportName) => {
|
|
2607
2726
|
for (const statement of sourceFile.statements) {
|
|
2608
|
-
if (!
|
|
2727
|
+
if (!isVariableStatement3(statement)) continue;
|
|
2609
2728
|
for (const declaration of statement.declarationList.declarations) {
|
|
2610
|
-
if (
|
|
2729
|
+
if (isIdentifier6(declaration.name) && declaration.name.text === exportName) {
|
|
2611
2730
|
return declaration;
|
|
2612
2731
|
}
|
|
2613
2732
|
}
|
|
@@ -2616,10 +2735,10 @@ var findProgramVariableDeclaration = (sourceFile, exportName) => {
|
|
|
2616
2735
|
};
|
|
2617
2736
|
var findProgramTypeDeclaration = (sourceFile, typeName) => {
|
|
2618
2737
|
for (const statement of sourceFile.statements) {
|
|
2619
|
-
if (
|
|
2620
|
-
if (
|
|
2621
|
-
if (
|
|
2622
|
-
if (
|
|
2738
|
+
if (isInterfaceDeclaration4(statement) && statement.name.text === typeName) return statement;
|
|
2739
|
+
if (isTypeAliasDeclaration4(statement) && statement.name.text === typeName) return statement;
|
|
2740
|
+
if (isClassDeclaration3(statement) && statement.name?.text === typeName) return statement;
|
|
2741
|
+
if (isEnumDeclaration3(statement) && statement.name.text === typeName) return statement;
|
|
2623
2742
|
}
|
|
2624
2743
|
return null;
|
|
2625
2744
|
};
|
|
@@ -2636,18 +2755,18 @@ var resolveLocalExportedTypes = ({
|
|
|
2636
2755
|
if (!hasReference) continue;
|
|
2637
2756
|
const declaration = findProgramTypeDeclaration(programSource, exportName);
|
|
2638
2757
|
if (!declaration) continue;
|
|
2639
|
-
const declarationNode =
|
|
2758
|
+
const declarationNode = isClassDeclaration3(declaration) ? declaration.name ?? declaration : isTypeAliasDeclaration4(declaration) ? declaration.type : declaration;
|
|
2640
2759
|
const declarationType = checker.getTypeAtLocation(declarationNode);
|
|
2641
2760
|
const expanded = normalizeInlineType(expandType(declarationType, checker));
|
|
2642
|
-
resolved = resolved.replaceAll(new RegExp(String.raw`\b${exportName}\b`, "g"), expanded);
|
|
2761
|
+
resolved = resolved.replaceAll(new RegExp(String.raw`\b${exportName}\b`, "g"), () => expanded);
|
|
2643
2762
|
}
|
|
2644
2763
|
return resolved;
|
|
2645
2764
|
};
|
|
2646
2765
|
var findSourceVariableDeclaration = (sourceFile, exportName) => {
|
|
2647
2766
|
for (const statement of sourceFile.statements) {
|
|
2648
|
-
if (!
|
|
2767
|
+
if (!isVariableStatement3(statement)) continue;
|
|
2649
2768
|
for (const declaration of statement.declarationList.declarations) {
|
|
2650
|
-
if (
|
|
2769
|
+
if (isIdentifier6(declaration.name) && declaration.name.text === exportName) {
|
|
2651
2770
|
return declaration;
|
|
2652
2771
|
}
|
|
2653
2772
|
}
|
|
@@ -2665,8 +2784,8 @@ var inferValueTypeForExport = ({
|
|
|
2665
2784
|
checker,
|
|
2666
2785
|
programSource
|
|
2667
2786
|
}) => {
|
|
2668
|
-
const resolvedChecker = checker ?? getServerProgram().
|
|
2669
|
-
const resolvedSource = programSource ?? getServerProgram().getSourceFile(filePath);
|
|
2787
|
+
const resolvedChecker = checker ?? getServerProgram().checker;
|
|
2788
|
+
const resolvedSource = programSource ?? getServerProgram().program.getSourceFile(filePath);
|
|
2670
2789
|
if (declaration.type) {
|
|
2671
2790
|
const rawType = normalizeInlineType(rawContent.slice(declaration.type.pos, declaration.type.end).trim());
|
|
2672
2791
|
const localResolvedType = resolvedSource ? resolveLocalExportedTypes({
|
|
@@ -2715,7 +2834,7 @@ var extractSignatureFromNode = (node, rawContent, filePath, availableExports, fi
|
|
|
2715
2834
|
knownGenerics.add(typeParam.name.text);
|
|
2716
2835
|
}
|
|
2717
2836
|
}
|
|
2718
|
-
const isAsync = node.modifiers?.some((m) => m.kind ===
|
|
2837
|
+
const isAsync = node.modifiers?.some((m) => m.kind === SyntaxKind5.AsyncKeyword) ?? false;
|
|
2719
2838
|
const genericsClause = node.typeParameters ? `<${normalizeInlineType(rawContent.slice(node.typeParameters.pos, node.typeParameters.end))}>` : "";
|
|
2720
2839
|
const rawParams = node.parameters.map((p) => normalizeInlineType(rawContent.slice(p.pos, p.end).trim())).join(", ");
|
|
2721
2840
|
const cleanParams = normalizeInlineType(stripDefaultValues(`(${rawParams})`));
|
|
@@ -2758,38 +2877,38 @@ var extractSignatureFromNode = (node, rawContent, filePath, availableExports, fi
|
|
|
2758
2877
|
};
|
|
2759
2878
|
var findSignatureForExport = (name, sourceFile, rawContent, filePath, availableExports, fileImports, collectors, checker, programSource) => {
|
|
2760
2879
|
for (const statement of sourceFile.statements) {
|
|
2761
|
-
if (
|
|
2880
|
+
if (isVariableStatement3(statement)) {
|
|
2762
2881
|
for (const decl of statement.declarationList.declarations) {
|
|
2763
|
-
if (!
|
|
2764
|
-
if (
|
|
2882
|
+
if (!isIdentifier6(decl.name) || decl.name.text !== name || !decl.initializer) continue;
|
|
2883
|
+
if (isArrowFunction2(decl.initializer) || isFunctionExpression2(decl.initializer)) {
|
|
2765
2884
|
return extractSignatureFromNode(decl.initializer, rawContent, filePath, availableExports, fileImports, collectors, checker, programSource);
|
|
2766
2885
|
}
|
|
2767
2886
|
}
|
|
2768
2887
|
}
|
|
2769
|
-
if (
|
|
2888
|
+
if (isFunctionDeclaration3(statement) && statement.name?.text === name) {
|
|
2770
2889
|
return extractSignatureFromNode(statement, rawContent, filePath, availableExports, fileImports, collectors, checker, programSource);
|
|
2771
2890
|
}
|
|
2772
2891
|
}
|
|
2773
2892
|
return "any";
|
|
2774
2893
|
};
|
|
2894
|
+
var hasExportModifier = (statement) => (isVariableStatement3(statement) || isFunctionDeclaration3(statement)) && (statement.modifiers?.some((m) => m.kind === SyntaxKind5.ExportKeyword) ?? false);
|
|
2775
2895
|
var parseFunctionFile = (fullPath, collectors) => {
|
|
2776
2896
|
try {
|
|
2777
|
-
const rawContent =
|
|
2778
|
-
const sourceFile =
|
|
2897
|
+
const rawContent = fs7.readFileSync(fullPath, "utf8");
|
|
2898
|
+
const sourceFile = parseSourceText(fullPath, rawContent);
|
|
2779
2899
|
const { availableExports, fileImports } = parseFileTypeContext(rawContent);
|
|
2780
|
-
const program = getServerProgram();
|
|
2781
|
-
const checker = program.getTypeChecker();
|
|
2900
|
+
const { program, checker } = getServerProgram();
|
|
2782
2901
|
const programSource = program.getSourceFile(fullPath);
|
|
2783
2902
|
const exports = /* @__PURE__ */ new Map();
|
|
2784
2903
|
let defaultExportName = null;
|
|
2785
2904
|
let wildcardReExport = null;
|
|
2786
2905
|
for (const statement of sourceFile.statements) {
|
|
2787
|
-
const hasExport = statement
|
|
2788
|
-
if (
|
|
2906
|
+
const hasExport = hasExportModifier(statement);
|
|
2907
|
+
if (isVariableStatement3(statement) && hasExport) {
|
|
2789
2908
|
for (const decl of statement.declarationList.declarations) {
|
|
2790
|
-
if (
|
|
2909
|
+
if (isIdentifier6(decl.name)) {
|
|
2791
2910
|
const exportName = decl.name.text;
|
|
2792
|
-
if (decl.initializer && (
|
|
2911
|
+
if (decl.initializer && (isArrowFunction2(decl.initializer) || isFunctionExpression2(decl.initializer))) {
|
|
2793
2912
|
exports.set(exportName, findSignatureForExport(exportName, sourceFile, rawContent, fullPath, availableExports, fileImports, collectors, checker, programSource ?? void 0));
|
|
2794
2913
|
continue;
|
|
2795
2914
|
}
|
|
@@ -2807,11 +2926,11 @@ var parseFunctionFile = (fullPath, collectors) => {
|
|
|
2807
2926
|
}
|
|
2808
2927
|
}
|
|
2809
2928
|
}
|
|
2810
|
-
if (
|
|
2929
|
+
if (isFunctionDeclaration3(statement) && hasExport && statement.name) {
|
|
2811
2930
|
exports.set(statement.name.text, findSignatureForExport(statement.name.text, sourceFile, rawContent, fullPath, availableExports, fileImports, collectors, checker, programSource ?? void 0));
|
|
2812
2931
|
}
|
|
2813
|
-
if (
|
|
2814
|
-
const moduleSpecifier = statement.moduleSpecifier &&
|
|
2932
|
+
if (isExportDeclaration(statement) && statement.exportClause && isNamedExports(statement.exportClause)) {
|
|
2933
|
+
const moduleSpecifier = statement.moduleSpecifier && isStringLiteral5(statement.moduleSpecifier) ? statement.moduleSpecifier.text : null;
|
|
2815
2934
|
for (const specifier of statement.exportClause.elements) {
|
|
2816
2935
|
const exportName = specifier.name.text;
|
|
2817
2936
|
const originalName = specifier.propertyName ? specifier.propertyName.text : exportName;
|
|
@@ -2826,7 +2945,7 @@ var parseFunctionFile = (fullPath, collectors) => {
|
|
|
2826
2945
|
continue;
|
|
2827
2946
|
}
|
|
2828
2947
|
const exportDeclaration = findSourceVariableDeclaration(sourceFile, originalName);
|
|
2829
|
-
if (exportDeclaration &&
|
|
2948
|
+
if (exportDeclaration && isIdentifier6(exportDeclaration.name)) {
|
|
2830
2949
|
exports.set(exportName, inferValueTypeForExport({
|
|
2831
2950
|
exportName: originalName,
|
|
2832
2951
|
declaration: exportDeclaration,
|
|
@@ -2843,10 +2962,10 @@ var parseFunctionFile = (fullPath, collectors) => {
|
|
|
2843
2962
|
exports.set(exportName, "any");
|
|
2844
2963
|
}
|
|
2845
2964
|
}
|
|
2846
|
-
if (
|
|
2965
|
+
if (isExportAssignment(statement) && !statement.isExportEquals && isIdentifier6(statement.expression)) {
|
|
2847
2966
|
defaultExportName = statement.expression.text;
|
|
2848
2967
|
}
|
|
2849
|
-
if (
|
|
2968
|
+
if (isExportDeclaration(statement) && !statement.exportClause && statement.moduleSpecifier && isStringLiteral5(statement.moduleSpecifier)) {
|
|
2850
2969
|
wildcardReExport = relativizeModuleSpecifier(statement.moduleSpecifier.text, fullPath);
|
|
2851
2970
|
}
|
|
2852
2971
|
}
|
|
@@ -2920,7 +3039,7 @@ var generateServerFunctions = (collectors) => {
|
|
|
2920
3039
|
if (modules.length === 0) return "";
|
|
2921
3040
|
const merged = { kind: "dir", children: /* @__PURE__ */ new Map(), sourcePath: "<merged>" };
|
|
2922
3041
|
for (const module of modules) {
|
|
2923
|
-
const absolutePath =
|
|
3042
|
+
const absolutePath = path10.resolve(ROOT_DIR5, module.sourcePath);
|
|
2924
3043
|
const parsed = parseFunctionFile(absolutePath, collectors);
|
|
2925
3044
|
if (!parsed) continue;
|
|
2926
3045
|
if (parsed.exports.size === 0 && parsed.defaultExportName === null && parsed.wildcardReExport === null) {
|
|
@@ -3047,7 +3166,7 @@ var collectSyncTypes = (syncServerFiles, syncClientFiles, collectors) => {
|
|
|
3047
3166
|
}
|
|
3048
3167
|
return syncTypesByPage;
|
|
3049
3168
|
};
|
|
3050
|
-
var
|
|
3169
|
+
var runTypeMapGeneration = (options) => {
|
|
3051
3170
|
const { quiet = false } = options;
|
|
3052
3171
|
assertValidRouteNaming({
|
|
3053
3172
|
srcDir: getSrcDir2(),
|
|
@@ -3085,6 +3204,13 @@ var generateTypeMapFile = (options = {}) => {
|
|
|
3085
3204
|
});
|
|
3086
3205
|
writeTypeMapArtifacts({ content, docsData, schemasContent, diagnosticsData });
|
|
3087
3206
|
};
|
|
3207
|
+
var generateTypeMapFile = (options = {}) => {
|
|
3208
|
+
try {
|
|
3209
|
+
runTypeMapGeneration(options);
|
|
3210
|
+
} finally {
|
|
3211
|
+
disposeTsApi();
|
|
3212
|
+
}
|
|
3213
|
+
};
|
|
3088
3214
|
|
|
3089
3215
|
// src/templateRegistry.ts
|
|
3090
3216
|
var BUILT_IN_TEMPLATE_KINDS = [
|
|
@@ -3158,13 +3284,29 @@ var registerDefaultTemplateRules = () => {
|
|
|
3158
3284
|
registerDefaultTemplateRules();
|
|
3159
3285
|
|
|
3160
3286
|
// src/loader.ts
|
|
3161
|
-
import
|
|
3162
|
-
import
|
|
3287
|
+
import fs8 from "fs";
|
|
3288
|
+
import path11 from "path";
|
|
3163
3289
|
import { pathToFileURL } from "url";
|
|
3164
3290
|
import { tryCatch, getSrcDir as getSrcDir3, ROOT_DIR as ROOT_DIR6, isTestFile as isTestFile3 } from "@luckystack/core";
|
|
3165
3291
|
|
|
3166
3292
|
// src/runtimeTypeResolver.ts
|
|
3167
|
-
import
|
|
3293
|
+
import { SymbolFlags as SymbolFlags3 } from "typescript-7-api/sync";
|
|
3294
|
+
import { SyntaxKind as SyntaxKind6 } from "typescript-7-api/ast";
|
|
3295
|
+
import {
|
|
3296
|
+
isEnumDeclaration as isEnumDeclaration4,
|
|
3297
|
+
isIdentifier as isIdentifier7,
|
|
3298
|
+
isImportDeclaration as isImportDeclaration3,
|
|
3299
|
+
isIndexSignatureDeclaration as isIndexSignatureDeclaration2,
|
|
3300
|
+
isInterfaceDeclaration as isInterfaceDeclaration5,
|
|
3301
|
+
isLiteralTypeNode as isLiteralTypeNode2,
|
|
3302
|
+
isNamedImports as isNamedImports3,
|
|
3303
|
+
isPropertySignatureDeclaration as isPropertySignatureDeclaration3,
|
|
3304
|
+
isStringLiteral as isStringLiteral6,
|
|
3305
|
+
isTypeAliasDeclaration as isTypeAliasDeclaration5,
|
|
3306
|
+
isTypeLiteralNode as isTypeLiteralNode2,
|
|
3307
|
+
isTypeReferenceNode as isTypeReferenceNode4,
|
|
3308
|
+
isUnionTypeNode as isUnionTypeNode2
|
|
3309
|
+
} from "typescript-7-api/ast/is";
|
|
3168
3310
|
var MAX_DEPTH = 20;
|
|
3169
3311
|
var unresolvedPrefix = "__RUNTIME_UNRESOLVED__::";
|
|
3170
3312
|
var PRIMITIVE_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -3244,9 +3386,9 @@ var splitTopLevel = (value, splitter) => {
|
|
|
3244
3386
|
};
|
|
3245
3387
|
var parseTypeNode = (typeText) => {
|
|
3246
3388
|
const synthetic = `type __RT = ${typeText};`;
|
|
3247
|
-
const source =
|
|
3389
|
+
const source = parseSourceText("__runtime_type.ts", synthetic);
|
|
3248
3390
|
const statement = source.statements[0];
|
|
3249
|
-
if (!statement || !
|
|
3391
|
+
if (!statement || !isTypeAliasDeclaration5(statement)) return null;
|
|
3250
3392
|
return statement.type;
|
|
3251
3393
|
};
|
|
3252
3394
|
var parseObjectFields = (typeText) => {
|
|
@@ -3255,30 +3397,30 @@ var parseObjectFields = (typeText) => {
|
|
|
3255
3397
|
return { fields: [], indexSignatures: [] };
|
|
3256
3398
|
}
|
|
3257
3399
|
const typeNode = parseTypeNode(clean);
|
|
3258
|
-
if (!typeNode || !
|
|
3400
|
+
if (!typeNode || !isTypeLiteralNode2(typeNode)) {
|
|
3259
3401
|
return { fields: [], indexSignatures: [] };
|
|
3260
3402
|
}
|
|
3261
3403
|
const fields = [];
|
|
3262
3404
|
const indexSignatures = [];
|
|
3263
3405
|
for (const member of typeNode.members) {
|
|
3264
|
-
if (
|
|
3406
|
+
if (isPropertySignatureDeclaration3(member) && member.type) {
|
|
3265
3407
|
let key = null;
|
|
3266
|
-
if (
|
|
3408
|
+
if (isIdentifier7(member.name)) {
|
|
3267
3409
|
key = member.name.text;
|
|
3268
|
-
} else if (
|
|
3410
|
+
} else if (isStringLiteral6(member.name)) {
|
|
3269
3411
|
key = member.name.text;
|
|
3270
3412
|
}
|
|
3271
3413
|
if (key === null) continue;
|
|
3272
3414
|
fields.push({
|
|
3273
3415
|
key,
|
|
3274
|
-
optional:
|
|
3416
|
+
optional: member.postfixToken?.kind === SyntaxKind6.QuestionToken,
|
|
3275
3417
|
type: member.type.getText().trim()
|
|
3276
3418
|
});
|
|
3277
3419
|
continue;
|
|
3278
3420
|
}
|
|
3279
|
-
if (
|
|
3421
|
+
if (isIndexSignatureDeclaration2(member)) {
|
|
3280
3422
|
const param = member.parameters[0];
|
|
3281
|
-
if (!param || !
|
|
3423
|
+
if (!param || !isIdentifier7(param.name) || !param.type) continue;
|
|
3282
3424
|
indexSignatures.push({
|
|
3283
3425
|
keyName: param.name.text,
|
|
3284
3426
|
keyType: param.type.getText().trim(),
|
|
@@ -3303,9 +3445,9 @@ var serializeObjectFields = ({
|
|
|
3303
3445
|
return `{ ${segments.join("; ")} }`;
|
|
3304
3446
|
};
|
|
3305
3447
|
var extractStringLiteralKey = (node) => {
|
|
3306
|
-
if (!
|
|
3448
|
+
if (!isLiteralTypeNode2(node)) return null;
|
|
3307
3449
|
const literal = node.literal;
|
|
3308
|
-
if (!
|
|
3450
|
+
if (!isStringLiteral6(literal)) return null;
|
|
3309
3451
|
return literal.text;
|
|
3310
3452
|
};
|
|
3311
3453
|
var parseLiteralUnionKeys = (value) => {
|
|
@@ -3313,7 +3455,7 @@ var parseLiteralUnionKeys = (value) => {
|
|
|
3313
3455
|
if (!trimmed) return null;
|
|
3314
3456
|
const typeNode = parseTypeNode(trimmed);
|
|
3315
3457
|
if (!typeNode) return null;
|
|
3316
|
-
if (
|
|
3458
|
+
if (isUnionTypeNode2(typeNode)) {
|
|
3317
3459
|
const keys = [];
|
|
3318
3460
|
for (const member of typeNode.types) {
|
|
3319
3461
|
const key = extractStringLiteralKey(member);
|
|
@@ -3329,25 +3471,24 @@ var resolveIdentifier = (identifier, filePath) => {
|
|
|
3329
3471
|
if (PRIMITIVE_TYPES.has(identifier.toLowerCase())) return identifier.toLowerCase();
|
|
3330
3472
|
if (SKIP_EXPANSION2.has(identifier)) return identifier;
|
|
3331
3473
|
try {
|
|
3332
|
-
const program = getServerProgram();
|
|
3474
|
+
const { program, checker } = getServerProgram();
|
|
3333
3475
|
const sourceFile = program.getSourceFile(filePath);
|
|
3334
3476
|
if (!sourceFile) return toUnresolved(`unresolved type ${identifier}`);
|
|
3335
|
-
const checker = program.getTypeChecker();
|
|
3336
3477
|
for (const stmt of sourceFile.statements) {
|
|
3337
|
-
if ((
|
|
3478
|
+
if ((isInterfaceDeclaration5(stmt) || isTypeAliasDeclaration5(stmt) || isEnumDeclaration4(stmt)) && stmt.name.text === identifier) {
|
|
3338
3479
|
const symbol = checker.getSymbolAtLocation(stmt.name);
|
|
3339
3480
|
if (symbol) {
|
|
3340
3481
|
return expandType(checker.getDeclaredTypeOfSymbol(symbol), checker);
|
|
3341
3482
|
}
|
|
3342
3483
|
}
|
|
3343
|
-
if (
|
|
3484
|
+
if (isImportDeclaration3(stmt) && stmt.importClause) {
|
|
3344
3485
|
const { namedBindings, name: defaultName } = stmt.importClause;
|
|
3345
|
-
if (namedBindings &&
|
|
3486
|
+
if (namedBindings && isNamedImports3(namedBindings)) {
|
|
3346
3487
|
for (const specifier of namedBindings.elements) {
|
|
3347
3488
|
if (specifier.name.text === identifier) {
|
|
3348
3489
|
const symbol = checker.getSymbolAtLocation(specifier.name);
|
|
3349
3490
|
if (symbol) {
|
|
3350
|
-
const target = symbol.flags &
|
|
3491
|
+
const target = symbol.flags & SymbolFlags3.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
3351
3492
|
return expandType(checker.getDeclaredTypeOfSymbol(target), checker);
|
|
3352
3493
|
}
|
|
3353
3494
|
}
|
|
@@ -3356,7 +3497,7 @@ var resolveIdentifier = (identifier, filePath) => {
|
|
|
3356
3497
|
if (defaultName?.text === identifier) {
|
|
3357
3498
|
const symbol = checker.getSymbolAtLocation(defaultName);
|
|
3358
3499
|
if (symbol) {
|
|
3359
|
-
const target = symbol.flags &
|
|
3500
|
+
const target = symbol.flags & SymbolFlags3.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
3360
3501
|
return expandType(checker.getDeclaredTypeOfSymbol(target), checker);
|
|
3361
3502
|
}
|
|
3362
3503
|
}
|
|
@@ -3490,7 +3631,7 @@ var resolveExpression = (typeText, filePath, depth, state) => {
|
|
|
3490
3631
|
});
|
|
3491
3632
|
} else {
|
|
3492
3633
|
const typeNode = parseTypeNode(type);
|
|
3493
|
-
const referenceInfo = typeNode &&
|
|
3634
|
+
const referenceInfo = typeNode && isTypeReferenceNode4(typeNode) && isIdentifier7(typeNode.typeName) ? { name: typeNode.typeName.text, args: typeNode.typeArguments } : null;
|
|
3494
3635
|
if (referenceInfo?.args && referenceInfo.args.length > 0) {
|
|
3495
3636
|
const { name: genericName, args: argNodes } = referenceInfo;
|
|
3496
3637
|
const args = argNodes.map((arg) => arg.getText().trim());
|
|
@@ -3541,7 +3682,7 @@ var devSyncs = {};
|
|
|
3541
3682
|
var devFunctions = {};
|
|
3542
3683
|
var normalizePath3 = (value) => value.replaceAll("\\", "/");
|
|
3543
3684
|
var isIgnoredPath = (absolutePath) => {
|
|
3544
|
-
const relativeFromRoot = normalizePath3(
|
|
3685
|
+
const relativeFromRoot = normalizePath3(path11.relative(ROOT_DIR6, absolutePath));
|
|
3545
3686
|
return getRoutingRules().ignore(relativeFromRoot);
|
|
3546
3687
|
};
|
|
3547
3688
|
var mapApiPageLocation = (pageLocation) => {
|
|
@@ -3551,7 +3692,7 @@ var mapSyncPageLocation = (pageLocation) => {
|
|
|
3551
3692
|
return pageLocation || "system";
|
|
3552
3693
|
};
|
|
3553
3694
|
var resolveApiRouteMetaFromPath = (filePath) => {
|
|
3554
|
-
const absolutePath =
|
|
3695
|
+
const absolutePath = path11.resolve(filePath);
|
|
3555
3696
|
const normalizedAbsolutePath = normalizePath3(absolutePath);
|
|
3556
3697
|
const normalizedSrcDir = normalizePath3(getSrcDir3());
|
|
3557
3698
|
if (!normalizedAbsolutePath.startsWith(normalizedSrcDir) || !normalizedAbsolutePath.endsWith(".ts")) {
|
|
@@ -3561,7 +3702,7 @@ var resolveApiRouteMetaFromPath = (filePath) => {
|
|
|
3561
3702
|
return null;
|
|
3562
3703
|
}
|
|
3563
3704
|
const rules2 = getRoutingRules();
|
|
3564
|
-
const relativePath = normalizePath3(
|
|
3705
|
+
const relativePath = normalizePath3(path11.relative(getSrcDir3(), absolutePath));
|
|
3565
3706
|
const segments = relativePath.split("/");
|
|
3566
3707
|
const apiIndex = segments.indexOf(rules2.apiMarker);
|
|
3567
3708
|
if (apiIndex === -1 || apiIndex === segments.length - 1) {
|
|
@@ -3581,7 +3722,7 @@ var resolveApiRouteMetaFromPath = (filePath) => {
|
|
|
3581
3722
|
return { routeKey, absolutePath };
|
|
3582
3723
|
};
|
|
3583
3724
|
var resolveSyncRouteMetaFromPath = (filePath) => {
|
|
3584
|
-
const absolutePath =
|
|
3725
|
+
const absolutePath = path11.resolve(filePath);
|
|
3585
3726
|
const normalizedAbsolutePath = normalizePath3(absolutePath);
|
|
3586
3727
|
const normalizedSrcDir = normalizePath3(getSrcDir3());
|
|
3587
3728
|
if (!normalizedAbsolutePath.startsWith(normalizedSrcDir) || !normalizedAbsolutePath.endsWith(".ts")) {
|
|
@@ -3591,7 +3732,7 @@ var resolveSyncRouteMetaFromPath = (filePath) => {
|
|
|
3591
3732
|
return null;
|
|
3592
3733
|
}
|
|
3593
3734
|
const rules2 = getRoutingRules();
|
|
3594
|
-
const relativePath = normalizePath3(
|
|
3735
|
+
const relativePath = normalizePath3(path11.relative(getSrcDir3(), absolutePath));
|
|
3595
3736
|
const segments = relativePath.split("/");
|
|
3596
3737
|
const syncIndex = segments.indexOf(rules2.syncMarker);
|
|
3597
3738
|
if (syncIndex === -1 || syncIndex === segments.length - 1) {
|
|
@@ -3635,13 +3776,13 @@ var importFile = async (absolutePath) => {
|
|
|
3635
3776
|
};
|
|
3636
3777
|
var collectTsFiles = (dir, relativeTo = "") => {
|
|
3637
3778
|
const results = [];
|
|
3638
|
-
const entries =
|
|
3779
|
+
const entries = fs8.readdirSync(dir);
|
|
3639
3780
|
for (const entry of entries) {
|
|
3640
3781
|
if (entry === "node_modules") continue;
|
|
3641
|
-
const entryPath =
|
|
3782
|
+
const entryPath = path11.join(dir, entry);
|
|
3642
3783
|
if (isIgnoredPath(entryPath)) continue;
|
|
3643
3784
|
const relPath = relativeTo ? `${relativeTo}/${entry}` : entry;
|
|
3644
|
-
if (
|
|
3785
|
+
if (fs8.statSync(entryPath).isDirectory()) {
|
|
3645
3786
|
if (isNonRouteDirectory(entry)) continue;
|
|
3646
3787
|
results.push(...collectTsFiles(entryPath, relPath));
|
|
3647
3788
|
} else if (entry.endsWith(".ts") && !isTestFile3(entry)) {
|
|
@@ -3673,16 +3814,16 @@ var resolveFunctionModule = (loadedModule, fileName) => {
|
|
|
3673
3814
|
var initializeApis = async () => {
|
|
3674
3815
|
for (const key of Object.keys(devApis)) delete devApis[key];
|
|
3675
3816
|
clearRuntimeTypeResolverCache();
|
|
3676
|
-
const srcFolder =
|
|
3817
|
+
const srcFolder = fs8.readdirSync(getSrcDir3());
|
|
3677
3818
|
for (const file of srcFolder) {
|
|
3678
3819
|
await scanApiFolder(file);
|
|
3679
3820
|
}
|
|
3680
3821
|
};
|
|
3681
3822
|
var upsertApiFromFile = async (filePath) => {
|
|
3682
|
-
if (isIgnoredPath(
|
|
3823
|
+
if (isIgnoredPath(path11.resolve(filePath))) return;
|
|
3683
3824
|
const routeMeta = resolveApiRouteMetaFromPath(filePath);
|
|
3684
3825
|
if (!routeMeta) {
|
|
3685
|
-
const normalized = normalizePath3(
|
|
3826
|
+
const normalized = normalizePath3(path11.resolve(filePath));
|
|
3686
3827
|
if (normalized.endsWith(".ts") && normalized.includes(apiMarkerSegment()) && isRouteSurfaceFile(normalized)) {
|
|
3687
3828
|
console.log(
|
|
3688
3829
|
`[loader][api] invalid filename: ${normalized}. Expected <name>_v<number>.ts. File will not be loaded.`,
|
|
@@ -3730,13 +3871,13 @@ var removeApiFromFile = (filePath) => {
|
|
|
3730
3871
|
delete devApis[routeMeta.routeKey];
|
|
3731
3872
|
};
|
|
3732
3873
|
var scanApiFolder = async (file, basePath = "") => {
|
|
3733
|
-
const fullPath =
|
|
3874
|
+
const fullPath = path11.join(getSrcDir3(), basePath, file);
|
|
3734
3875
|
if (isIgnoredPath(fullPath)) return;
|
|
3735
|
-
if (!
|
|
3876
|
+
if (!fs8.statSync(fullPath).isDirectory()) return;
|
|
3736
3877
|
if (file !== getRoutingRules().apiMarker) {
|
|
3737
|
-
const subFolders =
|
|
3878
|
+
const subFolders = fs8.readdirSync(fullPath);
|
|
3738
3879
|
for (const sub of subFolders) {
|
|
3739
|
-
await scanApiFolder(sub,
|
|
3880
|
+
await scanApiFolder(sub, path11.join(basePath, file));
|
|
3740
3881
|
}
|
|
3741
3882
|
return;
|
|
3742
3883
|
}
|
|
@@ -3749,7 +3890,7 @@ var scanApiFolder = async (file, basePath = "") => {
|
|
|
3749
3890
|
const versionMatch = rawApiName.match(apiRules.apiVersionRegex);
|
|
3750
3891
|
if (!versionMatch) {
|
|
3751
3892
|
console.log(
|
|
3752
|
-
`[loader][api] invalid filename: ${
|
|
3893
|
+
`[loader][api] invalid filename: ${path11.join(fullPath, relFile)}. Expected <name>_v<number>.ts. File will not be loaded.`,
|
|
3753
3894
|
"red"
|
|
3754
3895
|
);
|
|
3755
3896
|
continue;
|
|
@@ -3757,7 +3898,7 @@ var scanApiFolder = async (file, basePath = "") => {
|
|
|
3757
3898
|
const version = `v${versionMatch[1]}`;
|
|
3758
3899
|
const apiName = rawApiName.replace(apiRules.apiVersionRegex, "");
|
|
3759
3900
|
const routeKey = `api/${mappedPageLocation}/${apiName}/${version}`;
|
|
3760
|
-
const modulePath =
|
|
3901
|
+
const modulePath = path11.resolve(path11.join(fullPath, relFile));
|
|
3761
3902
|
const [err, module] = await tryCatch(async () => importFile(modulePath));
|
|
3762
3903
|
if (err) {
|
|
3763
3904
|
console.log(`[loader][api] failed to import ${routeKey} from ${modulePath}:`, err, "red");
|
|
@@ -3786,16 +3927,16 @@ var scanApiFolder = async (file, basePath = "") => {
|
|
|
3786
3927
|
var initializeSyncs = async () => {
|
|
3787
3928
|
for (const key of Object.keys(devSyncs)) delete devSyncs[key];
|
|
3788
3929
|
clearRuntimeTypeResolverCache();
|
|
3789
|
-
const srcFolder =
|
|
3930
|
+
const srcFolder = fs8.readdirSync(getSrcDir3());
|
|
3790
3931
|
for (const file of srcFolder) {
|
|
3791
3932
|
await scanSyncFolder(file);
|
|
3792
3933
|
}
|
|
3793
3934
|
};
|
|
3794
3935
|
var upsertSyncFromFile = async (filePath) => {
|
|
3795
|
-
if (isIgnoredPath(
|
|
3936
|
+
if (isIgnoredPath(path11.resolve(filePath))) return;
|
|
3796
3937
|
const routeMeta = resolveSyncRouteMetaFromPath(filePath);
|
|
3797
3938
|
if (!routeMeta) {
|
|
3798
|
-
const normalized = normalizePath3(
|
|
3939
|
+
const normalized = normalizePath3(path11.resolve(filePath));
|
|
3799
3940
|
if (normalized.endsWith(".ts") && normalized.includes(syncMarkerSegment()) && isRouteSurfaceFile(normalized)) {
|
|
3800
3941
|
console.log(
|
|
3801
3942
|
`[loader][sync] invalid filename: ${normalized}. Expected <name>_server_v<number>.ts or <name>_client_v<number>.ts. File will not be loaded.`,
|
|
@@ -3848,13 +3989,13 @@ var removeSyncFromFile = (filePath) => {
|
|
|
3848
3989
|
delete devSyncs[routeMeta.routeKey];
|
|
3849
3990
|
};
|
|
3850
3991
|
var scanSyncFolder = async (file, basePath = "") => {
|
|
3851
|
-
const fullPath =
|
|
3992
|
+
const fullPath = path11.join(getSrcDir3(), basePath, file);
|
|
3852
3993
|
if (isIgnoredPath(fullPath)) return;
|
|
3853
|
-
if (!
|
|
3994
|
+
if (!fs8.statSync(fullPath).isDirectory()) return;
|
|
3854
3995
|
if (file !== getRoutingRules().syncMarker) {
|
|
3855
|
-
const subFolders =
|
|
3996
|
+
const subFolders = fs8.readdirSync(fullPath);
|
|
3856
3997
|
for (const sub of subFolders) {
|
|
3857
|
-
await scanSyncFolder(sub,
|
|
3998
|
+
await scanSyncFolder(sub, path11.join(basePath, file));
|
|
3858
3999
|
}
|
|
3859
4000
|
return;
|
|
3860
4001
|
}
|
|
@@ -3866,7 +4007,7 @@ var scanSyncFolder = async (file, basePath = "") => {
|
|
|
3866
4007
|
const syncMatch = rawSyncFileName.match(syncRules.syncVersionRegex);
|
|
3867
4008
|
if (!syncMatch) {
|
|
3868
4009
|
console.log(
|
|
3869
|
-
`[loader][sync] invalid filename: ${
|
|
4010
|
+
`[loader][sync] invalid filename: ${path11.join(fullPath, relFile)}. Expected <name>_server_v<number>.ts or <name>_client_v<number>.ts. File will not be loaded.`,
|
|
3870
4011
|
"red"
|
|
3871
4012
|
);
|
|
3872
4013
|
continue;
|
|
@@ -3876,7 +4017,7 @@ var scanSyncFolder = async (file, basePath = "") => {
|
|
|
3876
4017
|
const syncName = rawSyncFileName.replace(syncRules.syncVersionRegex, "");
|
|
3877
4018
|
const mappedPageLocation = mapSyncPageLocation(pageLocation);
|
|
3878
4019
|
const routeBaseKey = `sync/${mappedPageLocation}/${syncName}/${version}`;
|
|
3879
|
-
const filePath =
|
|
4020
|
+
const filePath = path11.resolve(path11.join(fullPath, relFile));
|
|
3880
4021
|
const [fileError, fileResult] = await tryCatch(async () => importFile(filePath));
|
|
3881
4022
|
if (fileError) {
|
|
3882
4023
|
console.log(`[loader][sync] failed to import ${filePath}:`, fileError, "red");
|
|
@@ -3908,7 +4049,7 @@ var initializeFunctions = async () => {
|
|
|
3908
4049
|
}
|
|
3909
4050
|
});
|
|
3910
4051
|
for (const functionModule of modules) {
|
|
3911
|
-
const absolutePath =
|
|
4052
|
+
const absolutePath = path11.resolve(ROOT_DIR6, functionModule.sourcePath);
|
|
3912
4053
|
const [err, module] = await tryCatch(async () => importFile(absolutePath));
|
|
3913
4054
|
if (err) {
|
|
3914
4055
|
console.log(`[loader][function] failed to import ${absolutePath}:`, err, "red");
|
|
@@ -3931,19 +4072,25 @@ var initializeFunctions = async () => {
|
|
|
3931
4072
|
|
|
3932
4073
|
// src/hotReload.ts
|
|
3933
4074
|
import { watch } from "chokidar";
|
|
3934
|
-
import
|
|
3935
|
-
import
|
|
4075
|
+
import fs12 from "fs";
|
|
4076
|
+
import path15 from "path";
|
|
3936
4077
|
|
|
3937
4078
|
// src/templateInjector.ts
|
|
3938
|
-
import
|
|
3939
|
-
import
|
|
4079
|
+
import fs9 from "fs";
|
|
4080
|
+
import path12 from "path";
|
|
3940
4081
|
import { fileURLToPath, pathToFileURL as pathToFileURL2 } from "url";
|
|
3941
|
-
import
|
|
4082
|
+
import { ScriptKind as ScriptKind3 } from "typescript-7-api/ast";
|
|
4083
|
+
import {
|
|
4084
|
+
isIdentifier as isIdentifier8,
|
|
4085
|
+
isInterfaceDeclaration as isInterfaceDeclaration6,
|
|
4086
|
+
isPropertySignatureDeclaration as isPropertySignatureDeclaration4,
|
|
4087
|
+
isTypeLiteralNode as isTypeLiteralNode3
|
|
4088
|
+
} from "typescript-7-api/ast/is";
|
|
3942
4089
|
import { ROOT_DIR as ROOT_DIR7, getGeneratedSocketTypesPath as getGeneratedSocketTypesPath6, getSrcDir as getSrcDir4 } from "@luckystack/core";
|
|
3943
4090
|
var __filename = fileURLToPath(import.meta.url);
|
|
3944
|
-
var __dirname =
|
|
3945
|
-
var templatesDir =
|
|
3946
|
-
var getConsumerTemplatesDir = () =>
|
|
4091
|
+
var __dirname = path12.dirname(__filename);
|
|
4092
|
+
var templatesDir = path12.join(__dirname, "templates");
|
|
4093
|
+
var getConsumerTemplatesDir = () => path12.join(ROOT_DIR7, ".luckystack", "templates");
|
|
3947
4094
|
var templateContentFilenames = (kind) => {
|
|
3948
4095
|
const builtIn = BUILT_IN_TEMPLATE_FILENAMES[kind];
|
|
3949
4096
|
if (builtIn) return [builtIn];
|
|
@@ -3952,10 +4099,10 @@ var templateContentFilenames = (kind) => {
|
|
|
3952
4099
|
var resolveTemplateContent = (kind) => {
|
|
3953
4100
|
const consumerDir = getConsumerTemplatesDir();
|
|
3954
4101
|
for (const fileName of templateContentFilenames(kind)) {
|
|
3955
|
-
const consumerFile =
|
|
3956
|
-
if (
|
|
4102
|
+
const consumerFile = path12.join(consumerDir, fileName);
|
|
4103
|
+
if (fs9.existsSync(consumerFile)) {
|
|
3957
4104
|
try {
|
|
3958
|
-
return
|
|
4105
|
+
return fs9.readFileSync(consumerFile, "utf8");
|
|
3959
4106
|
} catch (error) {
|
|
3960
4107
|
console.error(`[TemplateInjector] Could not read consumer template: ${consumerFile}`, error);
|
|
3961
4108
|
}
|
|
@@ -3965,9 +4112,9 @@ var resolveTemplateContent = (kind) => {
|
|
|
3965
4112
|
if (override !== null) return override;
|
|
3966
4113
|
const builtInName = BUILT_IN_TEMPLATE_FILENAMES[kind];
|
|
3967
4114
|
if (builtInName) {
|
|
3968
|
-
const bundled =
|
|
4115
|
+
const bundled = path12.join(templatesDir, builtInName);
|
|
3969
4116
|
try {
|
|
3970
|
-
return
|
|
4117
|
+
return fs9.readFileSync(bundled, "utf8");
|
|
3971
4118
|
} catch (error) {
|
|
3972
4119
|
console.error(`[TemplateInjector] Could not read bundled template: ${bundled}`, error);
|
|
3973
4120
|
return null;
|
|
@@ -3981,11 +4128,11 @@ var ensureConsumerTemplateConfigLoaded = () => {
|
|
|
3981
4128
|
consumerTemplateConfig ??= (async () => {
|
|
3982
4129
|
const dir = getConsumerTemplatesDir();
|
|
3983
4130
|
for (const fileName of ["templateRules.ts", "templateRules.mjs", "templateRules.js"]) {
|
|
3984
|
-
const rulesFile =
|
|
3985
|
-
if (!
|
|
3986
|
-
const resolvedRulesFile =
|
|
3987
|
-
const resolvedRoot =
|
|
3988
|
-
if (!resolvedRulesFile.startsWith(resolvedRoot +
|
|
4131
|
+
const rulesFile = path12.join(dir, fileName);
|
|
4132
|
+
if (!fs9.existsSync(rulesFile)) continue;
|
|
4133
|
+
const resolvedRulesFile = path12.resolve(rulesFile);
|
|
4134
|
+
const resolvedRoot = path12.resolve(ROOT_DIR7);
|
|
4135
|
+
if (!resolvedRulesFile.startsWith(resolvedRoot + path12.sep) && resolvedRulesFile !== resolvedRoot) {
|
|
3989
4136
|
console.warn(
|
|
3990
4137
|
`[TemplateInjector] Template rules file resolves outside project root \u2014 skipping: ${rulesFile}`
|
|
3991
4138
|
);
|
|
@@ -4003,7 +4150,7 @@ var ensureConsumerTemplateConfigLoaded = () => {
|
|
|
4003
4150
|
};
|
|
4004
4151
|
var isEmptyFile = (filePath) => {
|
|
4005
4152
|
try {
|
|
4006
|
-
const content =
|
|
4153
|
+
const content = fs9.readFileSync(filePath, "utf8");
|
|
4007
4154
|
return content.trim().length === 0;
|
|
4008
4155
|
} catch {
|
|
4009
4156
|
return false;
|
|
@@ -4011,7 +4158,7 @@ var isEmptyFile = (filePath) => {
|
|
|
4011
4158
|
};
|
|
4012
4159
|
var isCommentOnlyFile = (filePath) => {
|
|
4013
4160
|
try {
|
|
4014
|
-
const content =
|
|
4161
|
+
const content = fs9.readFileSync(filePath, "utf8");
|
|
4015
4162
|
const withoutBlockComments = content.replaceAll(/\/\*[\s\S]*?\*\//g, "");
|
|
4016
4163
|
const withoutLineComments = withoutBlockComments.replaceAll(/(^|\s)\/\/.*$/gm, "$1");
|
|
4017
4164
|
return withoutLineComments.trim().length === 0;
|
|
@@ -4045,7 +4192,7 @@ var isVersionedSyncFile = (filePath) => {
|
|
|
4045
4192
|
return isVersionedSyncFileName(filePath);
|
|
4046
4193
|
};
|
|
4047
4194
|
var getFileName = (filePath) => {
|
|
4048
|
-
return
|
|
4195
|
+
return path12.basename(filePath.replaceAll("\\", "/"));
|
|
4049
4196
|
};
|
|
4050
4197
|
var stripTsExtension = (fileName) => {
|
|
4051
4198
|
return fileName.replace(/\.ts$/, "");
|
|
@@ -4121,7 +4268,7 @@ var getInvalidVersionMessage = (filePath) => {
|
|
|
4121
4268
|
var computeSrcRelativePath = (filePath) => {
|
|
4122
4269
|
try {
|
|
4123
4270
|
const srcDir = getSrcDir4();
|
|
4124
|
-
const absolute =
|
|
4271
|
+
const absolute = path12.resolve(filePath);
|
|
4125
4272
|
const normalizedSrc = srcDir.replaceAll("\\", "/");
|
|
4126
4273
|
const normalizedAbs = absolute.replaceAll("\\", "/");
|
|
4127
4274
|
if (!normalizedAbs.startsWith(`${normalizedSrc}/`)) return null;
|
|
@@ -4169,7 +4316,7 @@ var getPairedSyncFile = (filePath) => {
|
|
|
4169
4316
|
var hasPairedFile = (filePath) => {
|
|
4170
4317
|
const pairedPath = getPairedSyncFile(filePath);
|
|
4171
4318
|
if (!pairedPath) return false;
|
|
4172
|
-
return
|
|
4319
|
+
return fs9.existsSync(pairedPath);
|
|
4173
4320
|
};
|
|
4174
4321
|
var extractSyncPagePath2 = (filePath) => {
|
|
4175
4322
|
const normalized = filePath.replaceAll("\\", "/");
|
|
@@ -4182,14 +4329,14 @@ var extractSyncName2 = (filePath) => {
|
|
|
4182
4329
|
const normalized = filePath.replaceAll("\\", "/");
|
|
4183
4330
|
const match = /_sync\/(.+)\.ts$/.exec(normalized);
|
|
4184
4331
|
if (!match) {
|
|
4185
|
-
const basename =
|
|
4332
|
+
const basename = path12.basename(filePath, ".ts");
|
|
4186
4333
|
return basename.replace(/_server_v\d+$/, "").replace(/_client_v\d+$/, "");
|
|
4187
4334
|
}
|
|
4188
4335
|
return (match[1] ?? "").replace(/_server_v\d+$/, "").replace(/_client_v\d+$/, "");
|
|
4189
4336
|
};
|
|
4190
4337
|
var extractClientInputFromFile = (filePath) => {
|
|
4191
4338
|
try {
|
|
4192
|
-
const content =
|
|
4339
|
+
const content = fs9.readFileSync(filePath, "utf8");
|
|
4193
4340
|
const syncParamsMatch = /interface\s+SyncParams\s*\{/.exec(content);
|
|
4194
4341
|
if (!syncParamsMatch) return null;
|
|
4195
4342
|
const searchRegion = content.slice(syncParamsMatch.index + syncParamsMatch[0].length);
|
|
@@ -4220,7 +4367,7 @@ var extractClientInputFromFile = (filePath) => {
|
|
|
4220
4367
|
var extractClientInputFromGeneratedTypes = (pagePath, syncName) => {
|
|
4221
4368
|
try {
|
|
4222
4369
|
const generatedTypesPath = getGeneratedSocketTypesPath6();
|
|
4223
|
-
const content =
|
|
4370
|
+
const content = fs9.readFileSync(generatedTypesPath, "utf8");
|
|
4224
4371
|
const escapeRegex = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
|
|
4225
4372
|
const escapedPagePath = escapeRegex(pagePath);
|
|
4226
4373
|
const escapedSyncName = escapeRegex(syncName);
|
|
@@ -4266,7 +4413,7 @@ var calculateRelativePath = (filePath) => {
|
|
|
4266
4413
|
const srcRelative = computeSrcRelativePath(filePath);
|
|
4267
4414
|
if (srcRelative !== null) {
|
|
4268
4415
|
try {
|
|
4269
|
-
const srcDepthFromRoot =
|
|
4416
|
+
const srcDepthFromRoot = path12.relative(ROOT_DIR7, getSrcDir4()).replaceAll("\\", "/").split("/").filter((segment) => segment.length > 0).length;
|
|
4270
4417
|
const dirSegmentsAfterSrc = Math.max(
|
|
4271
4418
|
0,
|
|
4272
4419
|
srcRelative.split("/").filter((segment) => segment.length > 0).length - 1
|
|
@@ -4315,12 +4462,12 @@ var applyTemplatePlaceholders = (content, filePath, fileKind) => {
|
|
|
4315
4462
|
const relPath = calculateRelativePath(filePath);
|
|
4316
4463
|
const pragmaPattern = /\/\/\s*@ts-(?:ignore|expect-error).*\r?\n(.*)\{\{REL_PATH\}\}/g;
|
|
4317
4464
|
let result = content.replaceAll(pragmaPattern, (_, prefix) => `${prefix}${relPath}`);
|
|
4318
|
-
result = result.replaceAll("{{REL_PATH}}", relPath);
|
|
4465
|
+
result = result.replaceAll("{{REL_PATH}}", () => relPath);
|
|
4319
4466
|
if (fileKind === "sync_client" || fileKind === "sync_server") {
|
|
4320
4467
|
const pagePath = extractSyncPagePath2(filePath);
|
|
4321
4468
|
const syncName = extractSyncName2(filePath);
|
|
4322
|
-
result = result.replaceAll("{{PAGE_PATH}}", pagePath);
|
|
4323
|
-
result = result.replaceAll("{{SYNC_NAME}}", syncName);
|
|
4469
|
+
result = result.replaceAll("{{PAGE_PATH}}", () => pagePath);
|
|
4470
|
+
result = result.replaceAll("{{SYNC_NAME}}", () => syncName);
|
|
4324
4471
|
}
|
|
4325
4472
|
return result;
|
|
4326
4473
|
};
|
|
@@ -4345,7 +4492,7 @@ var getTemplate = (filePath) => {
|
|
|
4345
4492
|
var injectTemplate = async (filePath) => {
|
|
4346
4493
|
await ensureConsumerTemplateConfigLoaded();
|
|
4347
4494
|
if (getRouteFilenameValidationMessage(filePath)) {
|
|
4348
|
-
|
|
4495
|
+
fs9.writeFileSync(filePath, getInvalidVersionMessage(filePath), "utf8");
|
|
4349
4496
|
console.log(`[TemplateInjector] Invalid route filename, injected guidance: ${filePath}`);
|
|
4350
4497
|
return true;
|
|
4351
4498
|
}
|
|
@@ -4354,7 +4501,7 @@ var injectTemplate = async (filePath) => {
|
|
|
4354
4501
|
return false;
|
|
4355
4502
|
}
|
|
4356
4503
|
try {
|
|
4357
|
-
|
|
4504
|
+
fs9.writeFileSync(filePath, template, "utf8");
|
|
4358
4505
|
console.log(`[TemplateInjector] Injected template into: ${filePath}`);
|
|
4359
4506
|
return true;
|
|
4360
4507
|
} catch (error) {
|
|
@@ -4410,18 +4557,10 @@ var rewriteClientInputType = (content) => {
|
|
|
4410
4557
|
);
|
|
4411
4558
|
};
|
|
4412
4559
|
var rewriteClientInputTypeAst = (content, sourceFileName) => {
|
|
4413
|
-
const
|
|
4414
|
-
sourceFileName,
|
|
4415
|
-
src,
|
|
4416
|
-
ts9.ScriptTarget.Latest,
|
|
4417
|
-
/* setParentNodes */
|
|
4418
|
-
true,
|
|
4419
|
-
ts9.ScriptKind.TS
|
|
4420
|
-
);
|
|
4421
|
-
const sourceFile = parseSource(content);
|
|
4560
|
+
const sourceFile = parseSourceText(sourceFileName, content, ScriptKind3.TS);
|
|
4422
4561
|
let syncParamsInterface;
|
|
4423
4562
|
for (const stmt of sourceFile.statements) {
|
|
4424
|
-
if (
|
|
4563
|
+
if (isInterfaceDeclaration6(stmt) && stmt.name.text === "SyncParams") {
|
|
4425
4564
|
syncParamsInterface = stmt;
|
|
4426
4565
|
break;
|
|
4427
4566
|
}
|
|
@@ -4429,30 +4568,18 @@ var rewriteClientInputTypeAst = (content, sourceFileName) => {
|
|
|
4429
4568
|
if (!syncParamsInterface) return null;
|
|
4430
4569
|
let clientInputMember;
|
|
4431
4570
|
for (const member of syncParamsInterface.members) {
|
|
4432
|
-
if (
|
|
4571
|
+
if (isPropertySignatureDeclaration4(member) && isIdentifier8(member.name) && member.name.text === "clientInput") {
|
|
4433
4572
|
clientInputMember = member;
|
|
4434
4573
|
break;
|
|
4435
4574
|
}
|
|
4436
4575
|
}
|
|
4437
4576
|
if (!clientInputMember?.type) return null;
|
|
4438
|
-
if (!
|
|
4577
|
+
if (!isTypeLiteralNode3(clientInputMember.type)) return null;
|
|
4439
4578
|
const typeNode = clientInputMember.type;
|
|
4440
4579
|
const start = typeNode.getStart(sourceFile);
|
|
4441
4580
|
const end = typeNode.getEnd();
|
|
4442
4581
|
const rewritten = `${content.slice(0, start)}SyncClientInput<PagePath, SyncName>${content.slice(end)}`;
|
|
4443
|
-
const
|
|
4444
|
-
const verifyProgram = ts9.createProgram({
|
|
4445
|
-
rootNames: [sourceFileName],
|
|
4446
|
-
options: { noResolve: true, skipLibCheck: true },
|
|
4447
|
-
// Supply the in-memory source so `ts.createProgram` never touches the disk.
|
|
4448
|
-
host: {
|
|
4449
|
-
...ts9.createCompilerHost({}),
|
|
4450
|
-
getSourceFile: (name) => name === sourceFileName ? reparsedFile : void 0,
|
|
4451
|
-
fileExists: (name) => name === sourceFileName,
|
|
4452
|
-
readFile: (name) => name === sourceFileName ? rewritten : void 0
|
|
4453
|
-
}
|
|
4454
|
-
});
|
|
4455
|
-
const syntaxErrors = verifyProgram.getSyntacticDiagnostics(reparsedFile);
|
|
4582
|
+
const syntaxErrors = transpileSourceText(sourceFileName, rewritten).diagnostics ?? [];
|
|
4456
4583
|
if (syntaxErrors.length > 0) {
|
|
4457
4584
|
console.log(
|
|
4458
4585
|
`[TemplateInjector] AST rewrite produced invalid TypeScript for ${sourceFileName} \u2014 leaving untouched`,
|
|
@@ -4482,10 +4609,10 @@ var updateClientFileForPairedServer = async (clientFilePath) => {
|
|
|
4482
4609
|
try {
|
|
4483
4610
|
const pagePath = extractSyncPagePath2(clientFilePath);
|
|
4484
4611
|
const syncName = extractSyncName2(clientFilePath);
|
|
4485
|
-
let content =
|
|
4612
|
+
let content = fs9.readFileSync(clientFilePath, "utf8");
|
|
4486
4613
|
content = ensureImportedTypes(content, clientFilePath);
|
|
4487
4614
|
content = insertTypeAliases(content, pagePath, syncName);
|
|
4488
|
-
const astResult = rewriteClientInputTypeAst(content,
|
|
4615
|
+
const astResult = rewriteClientInputTypeAst(content, path12.basename(clientFilePath));
|
|
4489
4616
|
if (astResult === null) {
|
|
4490
4617
|
console.log(
|
|
4491
4618
|
`[TemplateInjector] AST clientInput rewrite unavailable for ${clientFilePath} \u2014 using regex fallback`,
|
|
@@ -4497,7 +4624,7 @@ var updateClientFileForPairedServer = async (clientFilePath) => {
|
|
|
4497
4624
|
}
|
|
4498
4625
|
content = addServerOutputToParams(content);
|
|
4499
4626
|
content = addServerOutputToDestructuring(content);
|
|
4500
|
-
|
|
4627
|
+
fs9.writeFileSync(clientFilePath, content, "utf8");
|
|
4501
4628
|
console.log(`[TemplateInjector] Updated client file to use paired types (preserved code): ${clientFilePath}`);
|
|
4502
4629
|
return true;
|
|
4503
4630
|
} catch (error) {
|
|
@@ -4538,7 +4665,7 @@ var splitAtMainBody = (content) => {
|
|
|
4538
4665
|
};
|
|
4539
4666
|
var updateClientFileForDeletedServer = async (clientFilePath, clientInputTypes) => {
|
|
4540
4667
|
try {
|
|
4541
|
-
let content =
|
|
4668
|
+
let content = fs9.readFileSync(clientFilePath, "utf8");
|
|
4542
4669
|
content = inlineClientInputType(content, clientInputTypes);
|
|
4543
4670
|
const [header, body] = splitAtMainBody(content);
|
|
4544
4671
|
const cleanedHeader = removeServerOutputFromDestructuring(removeServerOutputFromParams(header));
|
|
@@ -4546,7 +4673,7 @@ var updateClientFileForDeletedServer = async (clientFilePath, clientInputTypes)
|
|
|
4546
4673
|
content = removeGeneratedTypeImports(content);
|
|
4547
4674
|
content = removeTypeAliases(content);
|
|
4548
4675
|
content = content.replaceAll(/\n{3,}/g, "\n\n");
|
|
4549
|
-
|
|
4676
|
+
fs9.writeFileSync(clientFilePath, content, "utf8");
|
|
4550
4677
|
console.log(`[TemplateInjector] Updated client file for deleted server (preserved code): ${clientFilePath}`);
|
|
4551
4678
|
return true;
|
|
4552
4679
|
} catch (error) {
|
|
@@ -4567,12 +4694,12 @@ var injectServerTemplateWithClientInput = async (serverFilePath, clientInputType
|
|
|
4567
4694
|
content = content.replaceAll(pragmaPattern, (_, prefix) => {
|
|
4568
4695
|
return `${prefix}${relPath}`;
|
|
4569
4696
|
});
|
|
4570
|
-
content = content.replaceAll("{{REL_PATH}}", relPath);
|
|
4697
|
+
content = content.replaceAll("{{REL_PATH}}", () => relPath);
|
|
4571
4698
|
content = content.replace(
|
|
4572
4699
|
/clientInput:\s*\{[^}]*\}/s,
|
|
4573
4700
|
(_match) => `clientInput: ${clientInputTypes}`
|
|
4574
4701
|
);
|
|
4575
|
-
|
|
4702
|
+
fs9.writeFileSync(serverFilePath, content, "utf8");
|
|
4576
4703
|
console.log(`[TemplateInjector] Injected server template with clientInput: ${serverFilePath}`);
|
|
4577
4704
|
return true;
|
|
4578
4705
|
} catch (error) {
|
|
@@ -4582,24 +4709,24 @@ var injectServerTemplateWithClientInput = async (serverFilePath, clientInputType
|
|
|
4582
4709
|
};
|
|
4583
4710
|
|
|
4584
4711
|
// src/importDependencyGraph.ts
|
|
4585
|
-
import
|
|
4586
|
-
import
|
|
4712
|
+
import fs10 from "fs";
|
|
4713
|
+
import path13 from "path";
|
|
4587
4714
|
import { ROOT_DIR as ROOT_DIR8, getServerFunctionDirs as getServerFunctionDirs2, getSharedDir, getSrcDir as getSrcDir5 } from "@luckystack/core";
|
|
4588
4715
|
var SUPPORTED_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mts", ".cts"];
|
|
4589
|
-
var normalizePath4 = (value) =>
|
|
4716
|
+
var normalizePath4 = (value) => path13.resolve(value).replaceAll("\\", "/");
|
|
4590
4717
|
var isSupportedScriptFile = (value) => {
|
|
4591
4718
|
return SUPPORTED_EXTENSIONS.some((extension) => value.endsWith(extension));
|
|
4592
4719
|
};
|
|
4593
4720
|
var existsFile = (value) => {
|
|
4594
4721
|
try {
|
|
4595
|
-
return
|
|
4722
|
+
return fs10.existsSync(value) && fs10.statSync(value).isFile();
|
|
4596
4723
|
} catch {
|
|
4597
4724
|
return false;
|
|
4598
4725
|
}
|
|
4599
4726
|
};
|
|
4600
4727
|
var existsDirectory = (value) => {
|
|
4601
4728
|
try {
|
|
4602
|
-
return
|
|
4729
|
+
return fs10.existsSync(value) && fs10.statSync(value).isDirectory();
|
|
4603
4730
|
} catch {
|
|
4604
4731
|
return false;
|
|
4605
4732
|
}
|
|
@@ -4610,16 +4737,16 @@ var collectScriptFiles = (dir, output, visited = /* @__PURE__ */ new Set()) => {
|
|
|
4610
4737
|
}
|
|
4611
4738
|
let realDir;
|
|
4612
4739
|
try {
|
|
4613
|
-
realDir =
|
|
4740
|
+
realDir = fs10.realpathSync(dir);
|
|
4614
4741
|
} catch {
|
|
4615
4742
|
return;
|
|
4616
4743
|
}
|
|
4617
4744
|
if (visited.has(realDir)) return;
|
|
4618
4745
|
visited.add(realDir);
|
|
4619
|
-
const entries =
|
|
4746
|
+
const entries = fs10.readdirSync(dir, { withFileTypes: true });
|
|
4620
4747
|
for (const entry of entries) {
|
|
4621
4748
|
if (entry.name === "node_modules") continue;
|
|
4622
|
-
const fullPath =
|
|
4749
|
+
const fullPath = path13.join(dir, entry.name);
|
|
4623
4750
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
4624
4751
|
if (existsDirectory(fullPath)) {
|
|
4625
4752
|
collectScriptFiles(fullPath, output, visited);
|
|
@@ -4636,9 +4763,9 @@ var specifiersCache = /* @__PURE__ */ new Map();
|
|
|
4636
4763
|
var scopedFilesCache = null;
|
|
4637
4764
|
var SCOPED_FILES_TTL_MS = 1e3;
|
|
4638
4765
|
var extractImportSpecifiers = (filePath) => {
|
|
4639
|
-
let mtimeMs
|
|
4766
|
+
let mtimeMs;
|
|
4640
4767
|
try {
|
|
4641
|
-
mtimeMs =
|
|
4768
|
+
mtimeMs = fs10.statSync(filePath).mtimeMs;
|
|
4642
4769
|
} catch {
|
|
4643
4770
|
specifiersCache.delete(filePath);
|
|
4644
4771
|
return [];
|
|
@@ -4648,7 +4775,7 @@ var extractImportSpecifiers = (filePath) => {
|
|
|
4648
4775
|
return cached.specifiers;
|
|
4649
4776
|
}
|
|
4650
4777
|
try {
|
|
4651
|
-
const source =
|
|
4778
|
+
const source = fs10.readFileSync(filePath, "utf8");
|
|
4652
4779
|
const specifiers = /* @__PURE__ */ new Set();
|
|
4653
4780
|
const importExportRegex = /(?:import|export)\s+(?:[\s\S]*?\s+from\s+)?['"]([^'"]+)['"]/g;
|
|
4654
4781
|
const dynamicImportRegex = /import\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
@@ -4683,7 +4810,7 @@ var tryResolveWithExtensions = (basePath) => {
|
|
|
4683
4810
|
}
|
|
4684
4811
|
if (existsDirectory(basePath)) {
|
|
4685
4812
|
for (const extension of SUPPORTED_EXTENSIONS) {
|
|
4686
|
-
const indexFile =
|
|
4813
|
+
const indexFile = path13.join(basePath, `index${extension}`);
|
|
4687
4814
|
if (existsFile(indexFile)) {
|
|
4688
4815
|
return normalizePath4(indexFile);
|
|
4689
4816
|
}
|
|
@@ -4696,18 +4823,18 @@ var resolveImportToFile = (importerPath, specifier) => {
|
|
|
4696
4823
|
return null;
|
|
4697
4824
|
}
|
|
4698
4825
|
if (specifier === "config") {
|
|
4699
|
-
return tryResolveWithExtensions(
|
|
4826
|
+
return tryResolveWithExtensions(path13.join(ROOT_DIR8, "config"));
|
|
4700
4827
|
}
|
|
4701
4828
|
if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
4702
|
-
const relativeBase =
|
|
4829
|
+
const relativeBase = path13.resolve(path13.dirname(importerPath), specifier);
|
|
4703
4830
|
return tryResolveWithExtensions(relativeBase);
|
|
4704
4831
|
}
|
|
4705
4832
|
if (specifier.startsWith("src/") || specifier.startsWith("@/")) {
|
|
4706
4833
|
const sourcePath = specifier.startsWith("@/") ? specifier.slice(2) : specifier.slice(4);
|
|
4707
|
-
return tryResolveWithExtensions(
|
|
4834
|
+
return tryResolveWithExtensions(path13.join(getSrcDir5(), sourcePath));
|
|
4708
4835
|
}
|
|
4709
4836
|
if (specifier.startsWith("shared/")) {
|
|
4710
|
-
return tryResolveWithExtensions(
|
|
4837
|
+
return tryResolveWithExtensions(path13.join(getSharedDir(), specifier.slice(7)));
|
|
4711
4838
|
}
|
|
4712
4839
|
return null;
|
|
4713
4840
|
};
|
|
@@ -4725,7 +4852,7 @@ var collectScopedFiles = () => {
|
|
|
4725
4852
|
for (const dir of getServerFunctionDirs2()) {
|
|
4726
4853
|
collectScriptFiles(dir, files);
|
|
4727
4854
|
}
|
|
4728
|
-
const configFile = tryResolveWithExtensions(
|
|
4855
|
+
const configFile = tryResolveWithExtensions(path13.join(ROOT_DIR8, "config"));
|
|
4729
4856
|
if (configFile) {
|
|
4730
4857
|
files.add(configFile);
|
|
4731
4858
|
}
|
|
@@ -4773,19 +4900,19 @@ var findDependentRouteFiles = (changedFilePath) => {
|
|
|
4773
4900
|
};
|
|
4774
4901
|
|
|
4775
4902
|
// src/prismaClientCheck.ts
|
|
4776
|
-
import
|
|
4777
|
-
import
|
|
4903
|
+
import fs11 from "fs";
|
|
4904
|
+
import path14 from "path";
|
|
4778
4905
|
import { spawn } from "child_process";
|
|
4779
4906
|
import { ROOT_DIR as ROOT_DIR9, tryCatch as tryCatch2 } from "@luckystack/core";
|
|
4780
|
-
var GENERATED_CLIENT_DIR =
|
|
4781
|
-
var GENERATED_CLIENT_MARKER =
|
|
4782
|
-
var DEFAULT_SCHEMA_PATH =
|
|
4783
|
-
var isPrismaClientMissing = () =>
|
|
4907
|
+
var GENERATED_CLIENT_DIR = path14.join(ROOT_DIR9, "node_modules", ".prisma", "client");
|
|
4908
|
+
var GENERATED_CLIENT_MARKER = path14.join(GENERATED_CLIENT_DIR, "schema.prisma");
|
|
4909
|
+
var DEFAULT_SCHEMA_PATH = path14.join(ROOT_DIR9, "prisma", "schema.prisma");
|
|
4910
|
+
var isPrismaClientMissing = () => fs11.existsSync(DEFAULT_SCHEMA_PATH) && !fs11.existsSync(GENERATED_CLIENT_MARKER);
|
|
4784
4911
|
var runPrismaGenerate = async () => tryCatch2(
|
|
4785
4912
|
() => new Promise((resolve, reject) => {
|
|
4786
4913
|
const localBinName = process.platform === "win32" ? "prisma.cmd" : "prisma";
|
|
4787
|
-
const localBin =
|
|
4788
|
-
const useLocal =
|
|
4914
|
+
const localBin = path14.join(ROOT_DIR9, "node_modules", ".bin", localBinName);
|
|
4915
|
+
const useLocal = fs11.existsSync(localBin);
|
|
4789
4916
|
const [cmd, args] = useLocal ? [localBin, ["generate"]] : [process.platform === "win32" ? "npx.cmd" : "npx", ["prisma", "generate"]];
|
|
4790
4917
|
const isWinShim = process.platform === "win32" && /\.(cmd|bat)$/i.test(cmd);
|
|
4791
4918
|
const child = isWinShim ? spawn(
|
|
@@ -4806,7 +4933,7 @@ var runPrismaGenerate = async () => tryCatch2(
|
|
|
4806
4933
|
|
|
4807
4934
|
// src/hotReload.ts
|
|
4808
4935
|
import { tryCatch as tryCatch3, getProjectConfig, getLocaleReloader, isProductionRuntime } from "@luckystack/core";
|
|
4809
|
-
var normalizeFsPath = (value) =>
|
|
4936
|
+
var normalizeFsPath = (value) => path15.resolve(value).replaceAll("\\", "/");
|
|
4810
4937
|
var isGeneratedPath = (normalizedPath) => {
|
|
4811
4938
|
return normalizedPath.includes("apiTypes.generated.ts") || normalizedPath.includes("apiDocs.generated.json");
|
|
4812
4939
|
};
|
|
@@ -5014,7 +5141,7 @@ var setupWatchers = () => {
|
|
|
5014
5141
|
if (shouldInjectTemplate(filePath, { isNewFile: true })) {
|
|
5015
5142
|
if (isSyncServerFile(normalizedPath)) {
|
|
5016
5143
|
const clientPath = getPairedSyncFile(normalizedPath);
|
|
5017
|
-
if (clientPath &&
|
|
5144
|
+
if (clientPath && fs12.existsSync(clientPath) && !isEmptyFile(clientPath)) {
|
|
5018
5145
|
const clientInputTypes = extractClientInputFromFile(clientPath);
|
|
5019
5146
|
if (clientInputTypes) {
|
|
5020
5147
|
await injectServerTemplateWithClientInput(filePath, clientInputTypes);
|
|
@@ -5177,7 +5304,7 @@ var setupWatchers = () => {
|
|
|
5177
5304
|
scheduleReload("sync", async () => {
|
|
5178
5305
|
if (isSyncServerFile(normalizedPath)) {
|
|
5179
5306
|
const clientPath = getPairedSyncFile(normalizedPath);
|
|
5180
|
-
if (clientPath &&
|
|
5307
|
+
if (clientPath && fs12.existsSync(clientPath)) {
|
|
5181
5308
|
const pagePath = extractSyncPagePath2(normalizedPath);
|
|
5182
5309
|
const syncName = extractSyncName2(normalizedPath);
|
|
5183
5310
|
const clientInputTypes = extractClientInputFromGeneratedTypes(pagePath, syncName);
|