@emeryld/rrroutes-contract 2.7.5 → 2.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -1
- package/bin/rrroutes-export-finalized-leaves.mjs +14 -0
- package/dist/export/defaultViewerTemplate.d.ts +1 -1
- package/dist/export/exportFinalizedLeaves.cli.d.ts +2 -0
- package/dist/export/exportFinalizedLeaves.d.ts +20 -0
- package/dist/export/extractLeafSourceByAst.d.ts +38 -0
- package/dist/export/index.d.ts +1 -0
- package/dist/index.cjs +705 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +704 -38
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -2
- package/tools/finalized-leaves-viewer.html +175 -7
package/dist/index.cjs
CHANGED
|
@@ -39,6 +39,7 @@ __export(index_exports, {
|
|
|
39
39
|
createSchemaIntrospector: () => createSchemaIntrospector,
|
|
40
40
|
defineSocketEvents: () => defineSocketEvents,
|
|
41
41
|
exportFinalizedLeaves: () => exportFinalizedLeaves,
|
|
42
|
+
extractLeafSourceByAst: () => extractLeafSourceByAst,
|
|
42
43
|
finalize: () => finalize,
|
|
43
44
|
flattenLeafSchemas: () => flattenLeafSchemas,
|
|
44
45
|
flattenSerializableSchema: () => flattenSerializableSchema,
|
|
@@ -107,9 +108,9 @@ function collectNestedFieldSuggestions(shape, prefix = []) {
|
|
|
107
108
|
}
|
|
108
109
|
return suggestions;
|
|
109
110
|
}
|
|
110
|
-
function compilePath(
|
|
111
|
-
if (!params) return
|
|
112
|
-
const withParams =
|
|
111
|
+
function compilePath(path4, params) {
|
|
112
|
+
if (!params) return path4;
|
|
113
|
+
const withParams = path4.replace(/:([A-Za-z0-9_]+)/g, (_, k) => {
|
|
113
114
|
const v = params[k];
|
|
114
115
|
if (v === void 0 || v === null) throw new Error(`Missing param :${k}`);
|
|
115
116
|
return String(v);
|
|
@@ -184,8 +185,8 @@ function buildLowProfileLeaf(leaf) {
|
|
|
184
185
|
}
|
|
185
186
|
};
|
|
186
187
|
}
|
|
187
|
-
var keyOf = (method,
|
|
188
|
-
const key = `${method.toUpperCase()} ${
|
|
188
|
+
var keyOf = (method, path4, encodeSafe) => {
|
|
189
|
+
const key = `${method.toUpperCase()} ${path4}`;
|
|
189
190
|
return encodeSafe ? encodeURIComponent(key) : key;
|
|
190
191
|
};
|
|
191
192
|
|
|
@@ -361,8 +362,8 @@ function joinPaths(parent, child) {
|
|
|
361
362
|
if (!trimmedChild) return trimmedParent;
|
|
362
363
|
return `${trimmedParent}/${trimmedChild}`;
|
|
363
364
|
}
|
|
364
|
-
function assertDynamicLayerUniqueness(
|
|
365
|
-
const segments =
|
|
365
|
+
function assertDynamicLayerUniqueness(path4, dynamicLayerMap) {
|
|
366
|
+
const segments = path4.split("/").filter(Boolean);
|
|
366
367
|
if (segments.length === 0) return;
|
|
367
368
|
for (let i = 0; i < segments.length; i++) {
|
|
368
369
|
const segment = segments[i];
|
|
@@ -682,45 +683,45 @@ function normalizeType(schema) {
|
|
|
682
683
|
return "unknown";
|
|
683
684
|
}
|
|
684
685
|
}
|
|
685
|
-
function isNonEmptyPath(
|
|
686
|
-
return typeof
|
|
686
|
+
function isNonEmptyPath(path4) {
|
|
687
|
+
return typeof path4 === "string" && path4.length > 0;
|
|
687
688
|
}
|
|
688
|
-
function setNode(out,
|
|
689
|
-
if (!isNonEmptyPath(
|
|
690
|
-
out[
|
|
689
|
+
function setNode(out, path4, schema, inherited) {
|
|
690
|
+
if (!isNonEmptyPath(path4)) return;
|
|
691
|
+
out[path4] = {
|
|
691
692
|
type: normalizeType(schema),
|
|
692
693
|
nullable: inherited.nullable || Boolean(schema.nullable),
|
|
693
694
|
optional: inherited.optional || Boolean(schema.optional)
|
|
694
695
|
};
|
|
695
696
|
}
|
|
696
|
-
function flattenInto(out, schema,
|
|
697
|
-
if (!schema || !isNonEmptyPath(
|
|
697
|
+
function flattenInto(out, schema, path4, inherited) {
|
|
698
|
+
if (!schema || !isNonEmptyPath(path4)) return;
|
|
698
699
|
const nextInherited = {
|
|
699
700
|
optional: inherited.optional || Boolean(schema.optional),
|
|
700
701
|
nullable: inherited.nullable || Boolean(schema.nullable)
|
|
701
702
|
};
|
|
702
703
|
if (schema.kind === "union" && Array.isArray(schema.union) && schema.union.length > 0) {
|
|
703
704
|
schema.union.forEach((option, index) => {
|
|
704
|
-
const optionPath = `${
|
|
705
|
+
const optionPath = `${path4}-${index + 1}`;
|
|
705
706
|
flattenInto(out, option, optionPath, inherited);
|
|
706
707
|
});
|
|
707
708
|
return;
|
|
708
709
|
}
|
|
709
|
-
setNode(out,
|
|
710
|
+
setNode(out, path4, schema, inherited);
|
|
710
711
|
if (schema.kind === "object" && schema.properties) {
|
|
711
712
|
for (const [key, child] of Object.entries(schema.properties)) {
|
|
712
|
-
const childPath = `${
|
|
713
|
+
const childPath = `${path4}.${key}`;
|
|
713
714
|
flattenInto(out, child, childPath, nextInherited);
|
|
714
715
|
}
|
|
715
716
|
return;
|
|
716
717
|
}
|
|
717
718
|
if (schema.kind === "array" && schema.element) {
|
|
718
|
-
flattenInto(out, schema.element, `${
|
|
719
|
+
flattenInto(out, schema.element, `${path4}[]`, nextInherited);
|
|
719
720
|
}
|
|
720
721
|
}
|
|
721
|
-
function flattenSerializableSchema(schema,
|
|
722
|
+
function flattenSerializableSchema(schema, path4) {
|
|
722
723
|
const out = {};
|
|
723
|
-
flattenInto(out, schema,
|
|
724
|
+
flattenInto(out, schema, path4, { optional: false, nullable: false });
|
|
724
725
|
return out;
|
|
725
726
|
}
|
|
726
727
|
function isSerializedLeaf(value) {
|
|
@@ -741,7 +742,7 @@ function flattenLeafSchemas(leaf) {
|
|
|
741
742
|
|
|
742
743
|
// src/export/exportFinalizedLeaves.ts
|
|
743
744
|
var import_promises = __toESM(require("fs/promises"), 1);
|
|
744
|
-
var
|
|
745
|
+
var import_node_path2 = __toESM(require("path"), 1);
|
|
745
746
|
var import_node_child_process = require("child_process");
|
|
746
747
|
|
|
747
748
|
// src/export/defaultViewerTemplate.ts
|
|
@@ -796,6 +797,13 @@ var DEFAULT_VIEWER_TEMPLATE = `<!doctype html>
|
|
|
796
797
|
} else {
|
|
797
798
|
statusEl.textContent = 'Loaded baked payload with ' + payload.leaves.length + ' routes.'
|
|
798
799
|
|
|
800
|
+
const toHref = (source) => {
|
|
801
|
+
if (!source || !source.file) return null
|
|
802
|
+
const normalizedPath = String(source.file).replace(/\\\\/g, '/')
|
|
803
|
+
const prefix = normalizedPath.startsWith('/') ? 'file://' : 'file:///'
|
|
804
|
+
return prefix + encodeURI(normalizedPath)
|
|
805
|
+
}
|
|
806
|
+
|
|
799
807
|
payload.leaves.forEach((leaf) => {
|
|
800
808
|
const details = document.createElement('details')
|
|
801
809
|
const summary = document.createElement('summary')
|
|
@@ -804,7 +812,62 @@ var DEFAULT_VIEWER_TEMPLATE = `<!doctype html>
|
|
|
804
812
|
const pre = document.createElement('pre')
|
|
805
813
|
pre.textContent = JSON.stringify(leaf, null, 2)
|
|
806
814
|
|
|
815
|
+
const source = payload.sourceByLeaf && payload.sourceByLeaf[leaf.key]
|
|
816
|
+
let sourceWrap = null
|
|
817
|
+
if (source) {
|
|
818
|
+
sourceWrap = document.createElement('div')
|
|
819
|
+
sourceWrap.className = 'meta'
|
|
820
|
+
|
|
821
|
+
const definitionHref = toHref(source.definition)
|
|
822
|
+
if (definitionHref) {
|
|
823
|
+
const label = document.createElement('div')
|
|
824
|
+
const link = document.createElement('a')
|
|
825
|
+
link.href = definitionHref
|
|
826
|
+
link.target = '_blank'
|
|
827
|
+
link.rel = 'noopener noreferrer'
|
|
828
|
+
link.textContent = 'definition'
|
|
829
|
+
label.appendChild(link)
|
|
830
|
+
const location = document.createElement('span')
|
|
831
|
+
location.textContent =
|
|
832
|
+
' (' +
|
|
833
|
+
source.definition.file +
|
|
834
|
+
':' +
|
|
835
|
+
source.definition.line +
|
|
836
|
+
':' +
|
|
837
|
+
source.definition.column +
|
|
838
|
+
')'
|
|
839
|
+
label.appendChild(location)
|
|
840
|
+
sourceWrap.appendChild(label)
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
if (source.schemas && typeof source.schemas === 'object') {
|
|
844
|
+
Object.entries(source.schemas).forEach(([name, schema]) => {
|
|
845
|
+
if (!schema) return
|
|
846
|
+
const href = toHref(schema)
|
|
847
|
+
const row = document.createElement('div')
|
|
848
|
+
if (href) {
|
|
849
|
+
const link = document.createElement('a')
|
|
850
|
+
link.href = href
|
|
851
|
+
link.target = '_blank'
|
|
852
|
+
link.rel = 'noopener noreferrer'
|
|
853
|
+
link.textContent =
|
|
854
|
+
name + ': ' + (schema.sourceName || schema.tag || '<anonymous>')
|
|
855
|
+
row.appendChild(link)
|
|
856
|
+
const location = document.createElement('span')
|
|
857
|
+
location.textContent =
|
|
858
|
+
' (' + schema.file + ':' + schema.line + ':' + schema.column + ')'
|
|
859
|
+
row.appendChild(location)
|
|
860
|
+
} else {
|
|
861
|
+
row.textContent = name + ': ' + (schema.sourceName || schema.tag || '<anonymous>')
|
|
862
|
+
}
|
|
863
|
+
sourceWrap.appendChild(row)
|
|
864
|
+
})
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
}
|
|
868
|
+
|
|
807
869
|
details.appendChild(summary)
|
|
870
|
+
if (sourceWrap) details.appendChild(sourceWrap)
|
|
808
871
|
details.appendChild(pre)
|
|
809
872
|
resultsEl.appendChild(details)
|
|
810
873
|
})
|
|
@@ -814,6 +877,551 @@ var DEFAULT_VIEWER_TEMPLATE = `<!doctype html>
|
|
|
814
877
|
</html>
|
|
815
878
|
`;
|
|
816
879
|
|
|
880
|
+
// src/export/extractLeafSourceByAst.ts
|
|
881
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
882
|
+
var import_typescript = __toESM(require("typescript"), 1);
|
|
883
|
+
var SCHEMA_KEYS = [
|
|
884
|
+
"bodySchema",
|
|
885
|
+
"querySchema",
|
|
886
|
+
"paramsSchema",
|
|
887
|
+
"outputSchema",
|
|
888
|
+
"outputMetaSchema",
|
|
889
|
+
"queryExtensionSchema"
|
|
890
|
+
];
|
|
891
|
+
var HTTP_METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "patch", "delete"]);
|
|
892
|
+
var MAX_RECURSION_DEPTH = 120;
|
|
893
|
+
function toLocation(node) {
|
|
894
|
+
const sourceFile = node.getSourceFile();
|
|
895
|
+
const { line, character } = sourceFile.getLineAndCharacterOfPosition(
|
|
896
|
+
node.getStart(sourceFile)
|
|
897
|
+
);
|
|
898
|
+
return {
|
|
899
|
+
file: import_node_path.default.resolve(sourceFile.fileName),
|
|
900
|
+
line: line + 1,
|
|
901
|
+
column: character + 1
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
function markFile(ctx, sourceFile) {
|
|
905
|
+
if (!sourceFile) return;
|
|
906
|
+
ctx.visitedFilePaths.add(import_node_path.default.resolve(sourceFile.fileName));
|
|
907
|
+
}
|
|
908
|
+
function trimPreview(text, max = 80) {
|
|
909
|
+
const normalized = text.replace(/\s+/g, " ").trim();
|
|
910
|
+
return normalized.length > max ? `${normalized.slice(0, max)}...` : normalized;
|
|
911
|
+
}
|
|
912
|
+
function unwrapExpression(expression) {
|
|
913
|
+
let current = expression;
|
|
914
|
+
while (true) {
|
|
915
|
+
if (import_typescript.default.isParenthesizedExpression(current) || import_typescript.default.isAsExpression(current) || import_typescript.default.isTypeAssertionExpression(current) || import_typescript.default.isNonNullExpression(current) || import_typescript.default.isSatisfiesExpression(current)) {
|
|
916
|
+
current = current.expression;
|
|
917
|
+
continue;
|
|
918
|
+
}
|
|
919
|
+
break;
|
|
920
|
+
}
|
|
921
|
+
return current;
|
|
922
|
+
}
|
|
923
|
+
function getTextName(name) {
|
|
924
|
+
if (import_typescript.default.isIdentifier(name) || import_typescript.default.isStringLiteral(name) || import_typescript.default.isNumericLiteral(name)) {
|
|
925
|
+
return name.text;
|
|
926
|
+
}
|
|
927
|
+
return void 0;
|
|
928
|
+
}
|
|
929
|
+
function joinPaths2(parent, child) {
|
|
930
|
+
if (!parent) return child;
|
|
931
|
+
if (!child) return parent;
|
|
932
|
+
const trimmedParent = parent.endsWith("/") ? parent.replace(/\/+$/, "") : parent;
|
|
933
|
+
const trimmedChild = child.startsWith("/") ? child.replace(/^\/+/, "") : child;
|
|
934
|
+
if (!trimmedChild) return trimmedParent;
|
|
935
|
+
return `${trimmedParent}/${trimmedChild}`;
|
|
936
|
+
}
|
|
937
|
+
function buildLeafKey(method, leafPath) {
|
|
938
|
+
return `${method.toUpperCase()} ${leafPath}`;
|
|
939
|
+
}
|
|
940
|
+
function normalizeResourceBase(raw) {
|
|
941
|
+
if (raw === "") return "";
|
|
942
|
+
if (raw.startsWith("/") || raw.startsWith(":") || raw.startsWith("*")) {
|
|
943
|
+
return raw;
|
|
944
|
+
}
|
|
945
|
+
return `/${raw}`;
|
|
946
|
+
}
|
|
947
|
+
function getModuleSymbol(checker, sourceFile) {
|
|
948
|
+
return checker.getSymbolAtLocation(sourceFile);
|
|
949
|
+
}
|
|
950
|
+
function getAliasedSymbolIfNeeded(checker, symbol) {
|
|
951
|
+
if ((symbol.flags & import_typescript.default.SymbolFlags.Alias) !== 0) {
|
|
952
|
+
try {
|
|
953
|
+
return checker.getAliasedSymbol(symbol);
|
|
954
|
+
} catch {
|
|
955
|
+
return symbol;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
return symbol;
|
|
959
|
+
}
|
|
960
|
+
function findSourceFile(program, filePath) {
|
|
961
|
+
const wanted = import_node_path.default.resolve(filePath);
|
|
962
|
+
const normalizedWanted = import_node_path.default.normalize(wanted);
|
|
963
|
+
return program.getSourceFiles().find((file) => import_node_path.default.normalize(import_node_path.default.resolve(file.fileName)) === normalizedWanted);
|
|
964
|
+
}
|
|
965
|
+
function declarationToExpression(declaration) {
|
|
966
|
+
if (!declaration) return void 0;
|
|
967
|
+
if (import_typescript.default.isVariableDeclaration(declaration)) {
|
|
968
|
+
return declaration.initializer;
|
|
969
|
+
}
|
|
970
|
+
if (import_typescript.default.isExportAssignment(declaration)) {
|
|
971
|
+
return declaration.expression;
|
|
972
|
+
}
|
|
973
|
+
if (import_typescript.default.isPropertyAssignment(declaration)) {
|
|
974
|
+
return declaration.initializer;
|
|
975
|
+
}
|
|
976
|
+
if (import_typescript.default.isShorthandPropertyAssignment(declaration)) {
|
|
977
|
+
return declaration.name;
|
|
978
|
+
}
|
|
979
|
+
if (import_typescript.default.isBindingElement(declaration)) {
|
|
980
|
+
return declaration.initializer;
|
|
981
|
+
}
|
|
982
|
+
if (import_typescript.default.isEnumMember(declaration)) {
|
|
983
|
+
return declaration.initializer;
|
|
984
|
+
}
|
|
985
|
+
return void 0;
|
|
986
|
+
}
|
|
987
|
+
function symbolKey(symbol) {
|
|
988
|
+
const decl = symbol.declarations?.[0];
|
|
989
|
+
if (!decl) return `${symbol.getName()}#${symbol.flags}`;
|
|
990
|
+
const file = import_node_path.default.resolve(decl.getSourceFile().fileName);
|
|
991
|
+
return `${file}:${decl.getStart()}:${symbol.getName()}`;
|
|
992
|
+
}
|
|
993
|
+
function resolveSymbolFromNode(node, ctx) {
|
|
994
|
+
const symbol = ctx.checker.getSymbolAtLocation(node);
|
|
995
|
+
if (!symbol) {
|
|
996
|
+
ctx.unresolvedReferences += 1;
|
|
997
|
+
return void 0;
|
|
998
|
+
}
|
|
999
|
+
const target = getAliasedSymbolIfNeeded(ctx.checker, symbol);
|
|
1000
|
+
const key = symbolKey(target);
|
|
1001
|
+
ctx.visitedSymbolKeys.add(key);
|
|
1002
|
+
return target;
|
|
1003
|
+
}
|
|
1004
|
+
function getExpressionFromSymbol(symbol, ctx, depth) {
|
|
1005
|
+
const key = symbolKey(symbol);
|
|
1006
|
+
if (ctx.activeSymbols.has(key)) return void 0;
|
|
1007
|
+
if (depth > MAX_RECURSION_DEPTH) return void 0;
|
|
1008
|
+
ctx.activeSymbols.add(key);
|
|
1009
|
+
try {
|
|
1010
|
+
const declaration = symbol.declarations?.[0];
|
|
1011
|
+
markFile(ctx, declaration?.getSourceFile());
|
|
1012
|
+
const direct = declarationToExpression(declaration);
|
|
1013
|
+
if (direct) return direct;
|
|
1014
|
+
if (declaration && import_typescript.default.isImportSpecifier(declaration)) {
|
|
1015
|
+
const target = getAliasedSymbolIfNeeded(ctx.checker, symbol);
|
|
1016
|
+
if (target !== symbol) {
|
|
1017
|
+
return getExpressionFromSymbol(target, ctx, depth + 1);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
return void 0;
|
|
1021
|
+
} finally {
|
|
1022
|
+
ctx.activeSymbols.delete(key);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
function resolveIdentifierExpression(identifier, ctx, depth) {
|
|
1026
|
+
const symbol = resolveSymbolFromNode(identifier, ctx);
|
|
1027
|
+
if (!symbol) return void 0;
|
|
1028
|
+
return getExpressionFromSymbol(symbol, ctx, depth);
|
|
1029
|
+
}
|
|
1030
|
+
function resolvePropertyExpression(expression, ctx, depth) {
|
|
1031
|
+
if (depth > MAX_RECURSION_DEPTH) return void 0;
|
|
1032
|
+
if (import_typescript.default.isPropertyAccessExpression(expression)) {
|
|
1033
|
+
const symbol = resolveSymbolFromNode(expression.name, ctx);
|
|
1034
|
+
if (symbol) {
|
|
1035
|
+
const fromSymbol = getExpressionFromSymbol(symbol, ctx, depth + 1);
|
|
1036
|
+
if (fromSymbol) return fromSymbol;
|
|
1037
|
+
}
|
|
1038
|
+
} else if (expression.argumentExpression) {
|
|
1039
|
+
const symbol = resolveSymbolFromNode(expression.argumentExpression, ctx);
|
|
1040
|
+
if (symbol) {
|
|
1041
|
+
const fromSymbol = getExpressionFromSymbol(symbol, ctx, depth + 1);
|
|
1042
|
+
if (fromSymbol) return fromSymbol;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
const ownerExpr = evaluateExpressionReference(expression.expression, ctx, depth + 1);
|
|
1046
|
+
const owner = ownerExpr ? maybeObjectLiteral(ownerExpr, ctx, depth + 1) : void 0;
|
|
1047
|
+
if (!owner) return void 0;
|
|
1048
|
+
const propName = import_typescript.default.isPropertyAccessExpression(expression) ? expression.name.text : expression.argumentExpression && import_typescript.default.isStringLiteralLike(expression.argumentExpression) ? expression.argumentExpression.text : void 0;
|
|
1049
|
+
if (!propName) return void 0;
|
|
1050
|
+
for (const property of owner.properties) {
|
|
1051
|
+
if (import_typescript.default.isPropertyAssignment(property) && getTextName(property.name) === propName) {
|
|
1052
|
+
return property.initializer;
|
|
1053
|
+
}
|
|
1054
|
+
if (import_typescript.default.isShorthandPropertyAssignment(property) && property.name.text === propName) {
|
|
1055
|
+
return property.name;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
return void 0;
|
|
1059
|
+
}
|
|
1060
|
+
function evaluateExpressionReference(expression, ctx, depth) {
|
|
1061
|
+
const resolved = unwrapExpression(expression);
|
|
1062
|
+
markFile(ctx, resolved.getSourceFile());
|
|
1063
|
+
if (depth > MAX_RECURSION_DEPTH) return void 0;
|
|
1064
|
+
if (import_typescript.default.isIdentifier(resolved)) {
|
|
1065
|
+
return resolveIdentifierExpression(resolved, ctx, depth + 1);
|
|
1066
|
+
}
|
|
1067
|
+
if (import_typescript.default.isPropertyAccessExpression(resolved) || import_typescript.default.isElementAccessExpression(resolved)) {
|
|
1068
|
+
return resolvePropertyExpression(resolved, ctx, depth + 1);
|
|
1069
|
+
}
|
|
1070
|
+
return void 0;
|
|
1071
|
+
}
|
|
1072
|
+
function resolveExportExpression(sourceFile, exportName, checker) {
|
|
1073
|
+
const moduleSymbol = getModuleSymbol(checker, sourceFile);
|
|
1074
|
+
if (!moduleSymbol) return void 0;
|
|
1075
|
+
const exports2 = checker.getExportsOfModule(moduleSymbol);
|
|
1076
|
+
const explicit = exports2.find((entry) => entry.getName() === exportName);
|
|
1077
|
+
if (explicit) {
|
|
1078
|
+
const declaration = getAliasedSymbolIfNeeded(checker, explicit).declarations?.[0];
|
|
1079
|
+
return declarationToExpression(declaration);
|
|
1080
|
+
}
|
|
1081
|
+
const defaultExport = exports2.find((entry) => entry.getName() === "default");
|
|
1082
|
+
if (!defaultExport) return void 0;
|
|
1083
|
+
const defaultDecl = getAliasedSymbolIfNeeded(checker, defaultExport).declarations?.[0];
|
|
1084
|
+
const defaultExpr = declarationToExpression(defaultDecl);
|
|
1085
|
+
if (!defaultExpr) return void 0;
|
|
1086
|
+
const resolved = unwrapExpression(defaultExpr);
|
|
1087
|
+
if (!import_typescript.default.isObjectLiteralExpression(resolved)) return void 0;
|
|
1088
|
+
for (const property of resolved.properties) {
|
|
1089
|
+
if (!import_typescript.default.isPropertyAssignment(property)) continue;
|
|
1090
|
+
const propertyName = getTextName(property.name);
|
|
1091
|
+
if (propertyName !== exportName) continue;
|
|
1092
|
+
return property.initializer;
|
|
1093
|
+
}
|
|
1094
|
+
return void 0;
|
|
1095
|
+
}
|
|
1096
|
+
function maybeObjectLiteral(expression, ctx, depth = 0) {
|
|
1097
|
+
if (!expression || depth > MAX_RECURSION_DEPTH) return void 0;
|
|
1098
|
+
const resolved = unwrapExpression(expression);
|
|
1099
|
+
markFile(ctx, resolved.getSourceFile());
|
|
1100
|
+
if (import_typescript.default.isObjectLiteralExpression(resolved)) return resolved;
|
|
1101
|
+
const referenced = evaluateExpressionReference(resolved, ctx, depth + 1);
|
|
1102
|
+
if (!referenced) return void 0;
|
|
1103
|
+
return maybeObjectLiteral(referenced, ctx, depth + 1);
|
|
1104
|
+
}
|
|
1105
|
+
function collectSchemaExpressionsFromObject(objectLiteral, ctx, depth) {
|
|
1106
|
+
const schemas = {};
|
|
1107
|
+
for (const property of objectLiteral.properties) {
|
|
1108
|
+
if (import_typescript.default.isSpreadAssignment(property)) {
|
|
1109
|
+
const spreadObject = maybeObjectLiteral(property.expression, ctx, depth + 1);
|
|
1110
|
+
if (!spreadObject) continue;
|
|
1111
|
+
Object.assign(
|
|
1112
|
+
schemas,
|
|
1113
|
+
collectSchemaExpressionsFromObject(spreadObject, ctx, depth + 1)
|
|
1114
|
+
);
|
|
1115
|
+
continue;
|
|
1116
|
+
}
|
|
1117
|
+
if (import_typescript.default.isPropertyAssignment(property)) {
|
|
1118
|
+
const key = getTextName(property.name);
|
|
1119
|
+
if (!key || !SCHEMA_KEYS.includes(key)) continue;
|
|
1120
|
+
schemas[key] = property.initializer;
|
|
1121
|
+
continue;
|
|
1122
|
+
}
|
|
1123
|
+
if (import_typescript.default.isShorthandPropertyAssignment(property)) {
|
|
1124
|
+
const key = property.name.text;
|
|
1125
|
+
if (!SCHEMA_KEYS.includes(key)) continue;
|
|
1126
|
+
schemas[key] = property.name;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
return schemas;
|
|
1130
|
+
}
|
|
1131
|
+
function extractSchemaExpressions(cfgExpression, ctx, depth) {
|
|
1132
|
+
const objectLiteral = maybeObjectLiteral(cfgExpression, ctx, depth);
|
|
1133
|
+
if (!objectLiteral) return {};
|
|
1134
|
+
return collectSchemaExpressionsFromObject(objectLiteral, ctx, depth);
|
|
1135
|
+
}
|
|
1136
|
+
function getNearestVariableName(node) {
|
|
1137
|
+
let current = node;
|
|
1138
|
+
while (current) {
|
|
1139
|
+
if (import_typescript.default.isVariableDeclaration(current) && import_typescript.default.isIdentifier(current.name)) {
|
|
1140
|
+
return current.name.text;
|
|
1141
|
+
}
|
|
1142
|
+
current = current.parent;
|
|
1143
|
+
}
|
|
1144
|
+
return void 0;
|
|
1145
|
+
}
|
|
1146
|
+
function isAllAccess(expression) {
|
|
1147
|
+
if (import_typescript.default.isPropertyAccessExpression(expression)) {
|
|
1148
|
+
return expression.name.text === "all";
|
|
1149
|
+
}
|
|
1150
|
+
return Boolean(
|
|
1151
|
+
expression.argumentExpression && import_typescript.default.isStringLiteralLike(expression.argumentExpression) && expression.argumentExpression.text === "all"
|
|
1152
|
+
);
|
|
1153
|
+
}
|
|
1154
|
+
function evaluateBranchExpression(expression, ctx, depth) {
|
|
1155
|
+
const resolved = unwrapExpression(expression);
|
|
1156
|
+
markFile(ctx, resolved.getSourceFile());
|
|
1157
|
+
if (depth > MAX_RECURSION_DEPTH) return void 0;
|
|
1158
|
+
if (import_typescript.default.isIdentifier(resolved)) {
|
|
1159
|
+
const valueExpr = resolveIdentifierExpression(resolved, ctx, depth + 1);
|
|
1160
|
+
if (!valueExpr) return void 0;
|
|
1161
|
+
return evaluateBranchExpression(valueExpr, ctx, depth + 1);
|
|
1162
|
+
}
|
|
1163
|
+
if (!import_typescript.default.isCallExpression(resolved)) return void 0;
|
|
1164
|
+
const call = resolved;
|
|
1165
|
+
if (import_typescript.default.isIdentifier(call.expression) && call.expression.text === "resource") {
|
|
1166
|
+
const firstArg = call.arguments[0];
|
|
1167
|
+
if (!firstArg || !import_typescript.default.isStringLiteralLike(firstArg)) {
|
|
1168
|
+
ctx.unsupportedShapeSeen = true;
|
|
1169
|
+
return void 0;
|
|
1170
|
+
}
|
|
1171
|
+
return { base: normalizeResourceBase(firstArg.text), leaves: [] };
|
|
1172
|
+
}
|
|
1173
|
+
if (!import_typescript.default.isPropertyAccessExpression(call.expression)) {
|
|
1174
|
+
ctx.unsupportedShapeSeen = true;
|
|
1175
|
+
return void 0;
|
|
1176
|
+
}
|
|
1177
|
+
const owner = call.expression.expression;
|
|
1178
|
+
const method = call.expression.name.text;
|
|
1179
|
+
const branch = evaluateBranchExpression(owner, ctx, depth + 1);
|
|
1180
|
+
if (!branch) return void 0;
|
|
1181
|
+
if (method === "with") return branch;
|
|
1182
|
+
if (HTTP_METHODS.has(method)) {
|
|
1183
|
+
const cfgExpression = call.arguments[0];
|
|
1184
|
+
const schemas = extractSchemaExpressions(cfgExpression, ctx, depth + 1);
|
|
1185
|
+
const nextLeaf = {
|
|
1186
|
+
method,
|
|
1187
|
+
path: branch.base,
|
|
1188
|
+
definitionNode: call.expression.name,
|
|
1189
|
+
schemas
|
|
1190
|
+
};
|
|
1191
|
+
return {
|
|
1192
|
+
...branch,
|
|
1193
|
+
leaves: [...branch.leaves, nextLeaf]
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
if (method === "sub") {
|
|
1197
|
+
const mountedLeaves = call.arguments.flatMap(
|
|
1198
|
+
(arg) => evaluateLeavesFromExpression(arg, ctx, depth + 1)
|
|
1199
|
+
);
|
|
1200
|
+
const prefixed = mountedLeaves.map((leaf) => ({
|
|
1201
|
+
...leaf,
|
|
1202
|
+
path: joinPaths2(branch.base, leaf.path)
|
|
1203
|
+
}));
|
|
1204
|
+
return {
|
|
1205
|
+
...branch,
|
|
1206
|
+
leaves: [...branch.leaves, ...prefixed]
|
|
1207
|
+
};
|
|
1208
|
+
}
|
|
1209
|
+
ctx.unsupportedShapeSeen = true;
|
|
1210
|
+
return void 0;
|
|
1211
|
+
}
|
|
1212
|
+
function expressionKey(expression) {
|
|
1213
|
+
const source = expression.getSourceFile();
|
|
1214
|
+
return `${import_node_path.default.resolve(source.fileName)}:${expression.getStart(source)}:${expression.getEnd()}:${expression.kind}`;
|
|
1215
|
+
}
|
|
1216
|
+
function evaluateLeavesFromExpression(expression, ctx, depth = 0) {
|
|
1217
|
+
const resolved = unwrapExpression(expression);
|
|
1218
|
+
markFile(ctx, resolved.getSourceFile());
|
|
1219
|
+
const key = expressionKey(resolved);
|
|
1220
|
+
if (ctx.activeExpressionKeys.has(key)) return [];
|
|
1221
|
+
if (depth > MAX_RECURSION_DEPTH) return [];
|
|
1222
|
+
ctx.activeExpressionKeys.add(key);
|
|
1223
|
+
try {
|
|
1224
|
+
if (import_typescript.default.isIdentifier(resolved)) {
|
|
1225
|
+
const valueExpr = resolveIdentifierExpression(resolved, ctx, depth + 1);
|
|
1226
|
+
if (!valueExpr) return [];
|
|
1227
|
+
return evaluateLeavesFromExpression(valueExpr, ctx, depth + 1);
|
|
1228
|
+
}
|
|
1229
|
+
if (import_typescript.default.isPropertyAccessExpression(resolved) || import_typescript.default.isElementAccessExpression(resolved)) {
|
|
1230
|
+
if (isAllAccess(resolved)) {
|
|
1231
|
+
return evaluateLeavesFromExpression(resolved.expression, ctx, depth + 1);
|
|
1232
|
+
}
|
|
1233
|
+
const refExpr = resolvePropertyExpression(resolved, ctx, depth + 1);
|
|
1234
|
+
if (refExpr) {
|
|
1235
|
+
return evaluateLeavesFromExpression(refExpr, ctx, depth + 1);
|
|
1236
|
+
}
|
|
1237
|
+
return [];
|
|
1238
|
+
}
|
|
1239
|
+
if (import_typescript.default.isArrayLiteralExpression(resolved)) {
|
|
1240
|
+
const leaves = [];
|
|
1241
|
+
for (const element of resolved.elements) {
|
|
1242
|
+
if (import_typescript.default.isSpreadElement(element)) {
|
|
1243
|
+
leaves.push(...evaluateLeavesFromExpression(element.expression, ctx, depth + 1));
|
|
1244
|
+
continue;
|
|
1245
|
+
}
|
|
1246
|
+
leaves.push(...evaluateLeavesFromExpression(element, ctx, depth + 1));
|
|
1247
|
+
}
|
|
1248
|
+
return leaves;
|
|
1249
|
+
}
|
|
1250
|
+
if (import_typescript.default.isCallExpression(resolved)) {
|
|
1251
|
+
if (import_typescript.default.isIdentifier(resolved.expression)) {
|
|
1252
|
+
const callName = resolved.expression.text;
|
|
1253
|
+
if (callName === "finalize") {
|
|
1254
|
+
const arg = resolved.arguments[0];
|
|
1255
|
+
if (!arg) return [];
|
|
1256
|
+
return evaluateLeavesFromExpression(arg, ctx, depth + 1);
|
|
1257
|
+
}
|
|
1258
|
+
if (callName === "mergeArrays") {
|
|
1259
|
+
return resolved.arguments.flatMap(
|
|
1260
|
+
(arg) => evaluateLeavesFromExpression(arg, ctx, depth + 1)
|
|
1261
|
+
);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
if (import_typescript.default.isPropertyAccessExpression(resolved.expression)) {
|
|
1265
|
+
const prop = resolved.expression.name.text;
|
|
1266
|
+
if (prop === "done") {
|
|
1267
|
+
const branch2 = evaluateBranchExpression(
|
|
1268
|
+
resolved.expression.expression,
|
|
1269
|
+
ctx,
|
|
1270
|
+
depth + 1
|
|
1271
|
+
);
|
|
1272
|
+
return branch2?.leaves ?? [];
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
const refExpr = evaluateExpressionReference(resolved, ctx, depth + 1);
|
|
1276
|
+
if (refExpr) return evaluateLeavesFromExpression(refExpr, ctx, depth + 1);
|
|
1277
|
+
ctx.unsupportedShapeSeen = true;
|
|
1278
|
+
return [];
|
|
1279
|
+
}
|
|
1280
|
+
const branch = evaluateBranchExpression(resolved, ctx, depth + 1);
|
|
1281
|
+
if (branch) return branch.leaves;
|
|
1282
|
+
ctx.unsupportedShapeSeen = true;
|
|
1283
|
+
return [];
|
|
1284
|
+
} finally {
|
|
1285
|
+
ctx.activeExpressionKeys.delete(key);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
function resolveSchemaMetadata(expression, ctx) {
|
|
1289
|
+
const resolved = unwrapExpression(expression);
|
|
1290
|
+
if (import_typescript.default.isIdentifier(resolved)) {
|
|
1291
|
+
const symbol = resolveSymbolFromNode(resolved, ctx);
|
|
1292
|
+
const declaration = symbol?.declarations?.[0];
|
|
1293
|
+
const locationNode = declaration ? import_typescript.default.isVariableDeclaration(declaration) ? declaration.name : declaration : resolved;
|
|
1294
|
+
const sourceName = declaration && import_typescript.default.isVariableDeclaration(declaration) && import_typescript.default.isIdentifier(declaration.name) ? declaration.name.text : resolved.text;
|
|
1295
|
+
return {
|
|
1296
|
+
...toLocation(locationNode),
|
|
1297
|
+
sourceName,
|
|
1298
|
+
tag: declaration ? void 0 : "<anonymous>"
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
if (import_typescript.default.isPropertyAccessExpression(resolved) || import_typescript.default.isElementAccessExpression(resolved)) {
|
|
1302
|
+
return {
|
|
1303
|
+
...toLocation(resolved),
|
|
1304
|
+
sourceName: trimPreview(resolved.getText()),
|
|
1305
|
+
tag: "<expression>"
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1308
|
+
return {
|
|
1309
|
+
...toLocation(resolved),
|
|
1310
|
+
sourceName: trimPreview(resolved.getText()),
|
|
1311
|
+
tag: "<inline>"
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
function parseTsConfig(cwd, tsconfigPath) {
|
|
1315
|
+
const resolvedTsconfig = tsconfigPath ? import_node_path.default.resolve(cwd, tsconfigPath) : import_typescript.default.findConfigFile(cwd, import_typescript.default.sys.fileExists, "tsconfig.json");
|
|
1316
|
+
if (!resolvedTsconfig) {
|
|
1317
|
+
return void 0;
|
|
1318
|
+
}
|
|
1319
|
+
const read = import_typescript.default.readConfigFile(resolvedTsconfig, import_typescript.default.sys.readFile);
|
|
1320
|
+
if (read.error) {
|
|
1321
|
+
throw new Error(import_typescript.default.flattenDiagnosticMessageText(read.error.messageText, "\n"));
|
|
1322
|
+
}
|
|
1323
|
+
const parsed = import_typescript.default.parseJsonConfigFileContent(
|
|
1324
|
+
read.config,
|
|
1325
|
+
import_typescript.default.sys,
|
|
1326
|
+
import_node_path.default.dirname(resolvedTsconfig),
|
|
1327
|
+
void 0,
|
|
1328
|
+
resolvedTsconfig
|
|
1329
|
+
);
|
|
1330
|
+
const nonEmptyInputErrors = parsed.errors.filter((entry) => entry.code !== 18003);
|
|
1331
|
+
if (nonEmptyInputErrors.length > 0) {
|
|
1332
|
+
throw new Error(
|
|
1333
|
+
nonEmptyInputErrors.map((entry) => import_typescript.default.flattenDiagnosticMessageText(entry.messageText, "\n")).join("\n")
|
|
1334
|
+
);
|
|
1335
|
+
}
|
|
1336
|
+
return { resolvedTsconfig, parsed };
|
|
1337
|
+
}
|
|
1338
|
+
function createProgramWithFallback(parsed, moduleFileAbs) {
|
|
1339
|
+
const base = import_typescript.default.createProgram({
|
|
1340
|
+
rootNames: parsed.fileNames,
|
|
1341
|
+
options: parsed.options
|
|
1342
|
+
});
|
|
1343
|
+
if (findSourceFile(base, moduleFileAbs)) {
|
|
1344
|
+
return base;
|
|
1345
|
+
}
|
|
1346
|
+
const rootNames = Array.from(/* @__PURE__ */ new Set([...parsed.fileNames, moduleFileAbs]));
|
|
1347
|
+
return import_typescript.default.createProgram({ rootNames, options: parsed.options });
|
|
1348
|
+
}
|
|
1349
|
+
function extractLeafSourceByAst({
|
|
1350
|
+
modulePath,
|
|
1351
|
+
exportName,
|
|
1352
|
+
tsconfigPath,
|
|
1353
|
+
cwd = process.cwd()
|
|
1354
|
+
}) {
|
|
1355
|
+
const parsedConfig = parseTsConfig(cwd, tsconfigPath);
|
|
1356
|
+
if (!parsedConfig) {
|
|
1357
|
+
return {
|
|
1358
|
+
sourceByLeaf: {},
|
|
1359
|
+
reason: "module_not_in_program",
|
|
1360
|
+
stats: { visitedSymbols: 0, visitedFiles: 0, unresolvedReferences: 0 }
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1363
|
+
const moduleAbs = import_node_path.default.resolve(cwd, modulePath);
|
|
1364
|
+
const program = createProgramWithFallback(parsedConfig.parsed, moduleAbs);
|
|
1365
|
+
const checker = program.getTypeChecker();
|
|
1366
|
+
const moduleFile = findSourceFile(program, moduleAbs);
|
|
1367
|
+
if (!moduleFile) {
|
|
1368
|
+
return {
|
|
1369
|
+
sourceByLeaf: {},
|
|
1370
|
+
tsconfigPath: parsedConfig.resolvedTsconfig,
|
|
1371
|
+
reason: "module_not_in_program",
|
|
1372
|
+
stats: { visitedSymbols: 0, visitedFiles: 0, unresolvedReferences: 0 }
|
|
1373
|
+
};
|
|
1374
|
+
}
|
|
1375
|
+
const exportedExpression = resolveExportExpression(moduleFile, exportName, checker);
|
|
1376
|
+
if (!exportedExpression) {
|
|
1377
|
+
return {
|
|
1378
|
+
sourceByLeaf: {},
|
|
1379
|
+
tsconfigPath: parsedConfig.resolvedTsconfig,
|
|
1380
|
+
reason: "export_not_found",
|
|
1381
|
+
stats: { visitedSymbols: 0, visitedFiles: 1, unresolvedReferences: 0 }
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1384
|
+
const ctx = {
|
|
1385
|
+
checker,
|
|
1386
|
+
activeExpressionKeys: /* @__PURE__ */ new Set(),
|
|
1387
|
+
activeSymbols: /* @__PURE__ */ new Set(),
|
|
1388
|
+
visitedSymbolKeys: /* @__PURE__ */ new Set(),
|
|
1389
|
+
visitedFilePaths: /* @__PURE__ */ new Set([import_node_path.default.resolve(moduleFile.fileName)]),
|
|
1390
|
+
unresolvedReferences: 0,
|
|
1391
|
+
unsupportedShapeSeen: false
|
|
1392
|
+
};
|
|
1393
|
+
const evaluatedLeaves = evaluateLeavesFromExpression(exportedExpression, ctx, 0);
|
|
1394
|
+
const sourceByLeaf = {};
|
|
1395
|
+
for (const leaf of evaluatedLeaves) {
|
|
1396
|
+
const key = buildLeafKey(leaf.method, leaf.path);
|
|
1397
|
+
const definition = {
|
|
1398
|
+
...toLocation(leaf.definitionNode),
|
|
1399
|
+
symbolName: getNearestVariableName(leaf.definitionNode)
|
|
1400
|
+
};
|
|
1401
|
+
ctx.visitedFilePaths.add(definition.file);
|
|
1402
|
+
const schemas = {};
|
|
1403
|
+
for (const schemaKey of SCHEMA_KEYS) {
|
|
1404
|
+
const schemaExpression = leaf.schemas[schemaKey];
|
|
1405
|
+
if (!schemaExpression) continue;
|
|
1406
|
+
const schemaMeta = resolveSchemaMetadata(schemaExpression, ctx);
|
|
1407
|
+
ctx.visitedFilePaths.add(schemaMeta.file);
|
|
1408
|
+
schemas[schemaKey] = schemaMeta;
|
|
1409
|
+
}
|
|
1410
|
+
sourceByLeaf[key] = { definition, schemas };
|
|
1411
|
+
}
|
|
1412
|
+
const reason = Object.keys(sourceByLeaf).length > 0 ? void 0 : ctx.unsupportedShapeSeen ? "unsupported_expression_shape" : "resolved_zero_leaves";
|
|
1413
|
+
return {
|
|
1414
|
+
sourceByLeaf,
|
|
1415
|
+
tsconfigPath: parsedConfig.resolvedTsconfig,
|
|
1416
|
+
reason,
|
|
1417
|
+
stats: {
|
|
1418
|
+
visitedSymbols: ctx.visitedSymbolKeys.size,
|
|
1419
|
+
visitedFiles: ctx.visitedFilePaths.size,
|
|
1420
|
+
unresolvedReferences: ctx.unresolvedReferences
|
|
1421
|
+
}
|
|
1422
|
+
};
|
|
1423
|
+
}
|
|
1424
|
+
|
|
817
1425
|
// src/export/exportFinalizedLeaves.ts
|
|
818
1426
|
function isRegistry(value) {
|
|
819
1427
|
return typeof value === "object" && value !== null && "all" in value && "byKey" in value;
|
|
@@ -821,10 +1429,11 @@ function isRegistry(value) {
|
|
|
821
1429
|
function getLeaves(input) {
|
|
822
1430
|
return isRegistry(input) ? input.all : input;
|
|
823
1431
|
}
|
|
824
|
-
function buildMeta() {
|
|
1432
|
+
function buildMeta(sourceExtraction) {
|
|
825
1433
|
return {
|
|
826
1434
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
827
1435
|
description: "Finalized RRRoutes leaves export with serialized schemas and flattened schema paths for downstream processing.",
|
|
1436
|
+
sourceExtraction,
|
|
828
1437
|
fieldCatalog: {
|
|
829
1438
|
leaf: ["key", "method", "path", "cfg"],
|
|
830
1439
|
cfg: [
|
|
@@ -881,20 +1490,20 @@ ${htmlTemplate}`;
|
|
|
881
1490
|
}
|
|
882
1491
|
async function resolveViewerTemplatePath(viewerTemplateFile) {
|
|
883
1492
|
if (viewerTemplateFile) {
|
|
884
|
-
const resolved =
|
|
1493
|
+
const resolved = import_node_path2.default.resolve(viewerTemplateFile);
|
|
885
1494
|
await import_promises.default.access(resolved);
|
|
886
1495
|
return resolved;
|
|
887
1496
|
}
|
|
888
1497
|
const candidates = [
|
|
889
|
-
|
|
1498
|
+
import_node_path2.default.resolve(
|
|
890
1499
|
process.cwd(),
|
|
891
1500
|
"node_modules/@emeryld/rrroutes-contract/tools/finalized-leaves-viewer.html"
|
|
892
1501
|
),
|
|
893
|
-
|
|
1502
|
+
import_node_path2.default.resolve(
|
|
894
1503
|
process.cwd(),
|
|
895
1504
|
"tools/finalized-leaves-viewer.html"
|
|
896
1505
|
),
|
|
897
|
-
|
|
1506
|
+
import_node_path2.default.resolve(
|
|
898
1507
|
process.cwd(),
|
|
899
1508
|
"packages/contract/tools/finalized-leaves-viewer.html"
|
|
900
1509
|
)
|
|
@@ -909,8 +1518,8 @@ async function resolveViewerTemplatePath(viewerTemplateFile) {
|
|
|
909
1518
|
return void 0;
|
|
910
1519
|
}
|
|
911
1520
|
async function writeJsonExport(payload, outFile) {
|
|
912
|
-
const resolved =
|
|
913
|
-
await import_promises.default.mkdir(
|
|
1521
|
+
const resolved = import_node_path2.default.resolve(outFile);
|
|
1522
|
+
await import_promises.default.mkdir(import_node_path2.default.dirname(resolved), { recursive: true });
|
|
914
1523
|
await import_promises.default.writeFile(resolved, `${JSON.stringify(payload, null, 2)}
|
|
915
1524
|
`, "utf8");
|
|
916
1525
|
return resolved;
|
|
@@ -919,13 +1528,13 @@ async function writeBakedHtmlExport(payload, htmlFile, viewerTemplateFile) {
|
|
|
919
1528
|
const templatePath = await resolveViewerTemplatePath(viewerTemplateFile);
|
|
920
1529
|
const template = templatePath ? await import_promises.default.readFile(templatePath, "utf8") : DEFAULT_VIEWER_TEMPLATE;
|
|
921
1530
|
const baked = injectPayloadIntoViewerHtml(template, payload);
|
|
922
|
-
const resolved =
|
|
923
|
-
await import_promises.default.mkdir(
|
|
1531
|
+
const resolved = import_node_path2.default.resolve(htmlFile);
|
|
1532
|
+
await import_promises.default.mkdir(import_node_path2.default.dirname(resolved), { recursive: true });
|
|
924
1533
|
await import_promises.default.writeFile(resolved, baked, "utf8");
|
|
925
1534
|
return resolved;
|
|
926
1535
|
}
|
|
927
1536
|
async function openHtmlInBrowser(filePath) {
|
|
928
|
-
const resolved =
|
|
1537
|
+
const resolved = import_node_path2.default.resolve(filePath);
|
|
929
1538
|
const platform = process.platform;
|
|
930
1539
|
if (platform === "darwin") {
|
|
931
1540
|
(0, import_node_child_process.spawn)("open", [resolved], { detached: true, stdio: "ignore" }).unref();
|
|
@@ -969,10 +1578,54 @@ async function exportFinalizedLeaves(input, options = {}) {
|
|
|
969
1578
|
const schemaFlatByLeaf = Object.fromEntries(
|
|
970
1579
|
serializedLeaves.map((leaf) => [leaf.key, flattenLeafSchemas(leaf)])
|
|
971
1580
|
);
|
|
1581
|
+
const sourceByLeaf = {};
|
|
1582
|
+
let sourceExtraction;
|
|
1583
|
+
if (options.includeSource) {
|
|
1584
|
+
const modulePath = options.sourceModulePath;
|
|
1585
|
+
const exportName = options.sourceExportName ?? "leaves";
|
|
1586
|
+
if (modulePath) {
|
|
1587
|
+
const extracted = extractLeafSourceByAst({
|
|
1588
|
+
modulePath,
|
|
1589
|
+
exportName,
|
|
1590
|
+
tsconfigPath: options.tsconfigPath
|
|
1591
|
+
});
|
|
1592
|
+
const allowedLeafKeys = new Set(serializedLeaves.map((leaf) => leaf.key));
|
|
1593
|
+
for (const [key, source] of Object.entries(extracted.sourceByLeaf)) {
|
|
1594
|
+
if (allowedLeafKeys.has(key)) {
|
|
1595
|
+
sourceByLeaf[key] = source;
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
sourceExtraction = {
|
|
1599
|
+
mode: "ast",
|
|
1600
|
+
enabled: true,
|
|
1601
|
+
modulePath: import_node_path2.default.resolve(modulePath),
|
|
1602
|
+
exportName,
|
|
1603
|
+
tsconfigPath: extracted.tsconfigPath,
|
|
1604
|
+
resolvedLeafCount: Object.keys(sourceByLeaf).length,
|
|
1605
|
+
reason: extracted.reason,
|
|
1606
|
+
stats: extracted.stats
|
|
1607
|
+
};
|
|
1608
|
+
} else {
|
|
1609
|
+
sourceExtraction = {
|
|
1610
|
+
mode: "ast",
|
|
1611
|
+
enabled: false,
|
|
1612
|
+
exportName,
|
|
1613
|
+
tsconfigPath: options.tsconfigPath ? import_node_path2.default.resolve(options.tsconfigPath) : void 0,
|
|
1614
|
+
resolvedLeafCount: 0,
|
|
1615
|
+
reason: "resolved_zero_leaves",
|
|
1616
|
+
stats: {
|
|
1617
|
+
visitedSymbols: 0,
|
|
1618
|
+
visitedFiles: 0,
|
|
1619
|
+
unresolvedReferences: 0
|
|
1620
|
+
}
|
|
1621
|
+
};
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
972
1624
|
const payload = {
|
|
973
|
-
_meta: buildMeta(),
|
|
1625
|
+
_meta: buildMeta(sourceExtraction),
|
|
974
1626
|
leaves: serializedLeaves,
|
|
975
|
-
schemaFlatByLeaf
|
|
1627
|
+
schemaFlatByLeaf,
|
|
1628
|
+
sourceByLeaf: options.includeSource && Object.keys(sourceByLeaf).length > 0 ? sourceByLeaf : void 0
|
|
976
1629
|
};
|
|
977
1630
|
if (options.outFile || options.htmlFile) {
|
|
978
1631
|
await writeFinalizedLeavesExport(payload, {
|
|
@@ -986,14 +1639,19 @@ async function exportFinalizedLeaves(input, options = {}) {
|
|
|
986
1639
|
}
|
|
987
1640
|
|
|
988
1641
|
// src/export/exportFinalizedLeaves.cli.ts
|
|
989
|
-
var
|
|
1642
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
990
1643
|
var import_node_url = require("url");
|
|
991
1644
|
function parseFinalizedLeavesCliArgs(argv) {
|
|
992
1645
|
const args = /* @__PURE__ */ new Map();
|
|
1646
|
+
let withSource = false;
|
|
993
1647
|
for (let i = 0; i < argv.length; i += 1) {
|
|
994
1648
|
const key = argv[i];
|
|
995
1649
|
if (key === "--") continue;
|
|
996
1650
|
if (!key.startsWith("--")) continue;
|
|
1651
|
+
if (key === "--with-source") {
|
|
1652
|
+
withSource = true;
|
|
1653
|
+
continue;
|
|
1654
|
+
}
|
|
997
1655
|
const value = argv[i + 1];
|
|
998
1656
|
if (!value || value.startsWith("--")) {
|
|
999
1657
|
throw new Error(`Missing value for ${key}`);
|
|
@@ -1008,14 +1666,16 @@ function parseFinalizedLeavesCliArgs(argv) {
|
|
|
1008
1666
|
return {
|
|
1009
1667
|
modulePath,
|
|
1010
1668
|
exportName: args.get("--export") ?? "leaves",
|
|
1011
|
-
outFile: args.get("--out") ?? "finalized-leaves.export.json"
|
|
1669
|
+
outFile: args.get("--out") ?? "finalized-leaves.export.json",
|
|
1670
|
+
withSource,
|
|
1671
|
+
tsconfigPath: args.get("--tsconfig") ?? void 0
|
|
1012
1672
|
};
|
|
1013
1673
|
}
|
|
1014
1674
|
async function loadFinalizedLeavesInput({
|
|
1015
1675
|
modulePath,
|
|
1016
1676
|
exportName
|
|
1017
1677
|
}) {
|
|
1018
|
-
const resolvedModule =
|
|
1678
|
+
const resolvedModule = import_node_path3.default.resolve(process.cwd(), modulePath);
|
|
1019
1679
|
const mod = await import((0, import_node_url.pathToFileURL)(resolvedModule).href);
|
|
1020
1680
|
const value = mod[exportName] ?? (mod.default && mod.default[exportName]);
|
|
1021
1681
|
if (!value) {
|
|
@@ -1026,10 +1686,16 @@ async function loadFinalizedLeavesInput({
|
|
|
1026
1686
|
async function runExportFinalizedLeavesCli(argv) {
|
|
1027
1687
|
const args = parseFinalizedLeavesCliArgs(argv);
|
|
1028
1688
|
const input = await loadFinalizedLeavesInput(args);
|
|
1029
|
-
const payload = await exportFinalizedLeaves(input, {
|
|
1689
|
+
const payload = await exportFinalizedLeaves(input, {
|
|
1690
|
+
outFile: args.outFile,
|
|
1691
|
+
includeSource: args.withSource,
|
|
1692
|
+
tsconfigPath: args.tsconfigPath,
|
|
1693
|
+
sourceModulePath: args.modulePath,
|
|
1694
|
+
sourceExportName: args.exportName
|
|
1695
|
+
});
|
|
1030
1696
|
return {
|
|
1031
1697
|
payload,
|
|
1032
|
-
outFile:
|
|
1698
|
+
outFile: import_node_path3.default.resolve(args.outFile)
|
|
1033
1699
|
};
|
|
1034
1700
|
}
|
|
1035
1701
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -1043,6 +1709,7 @@ async function runExportFinalizedLeavesCli(argv) {
|
|
|
1043
1709
|
createSchemaIntrospector,
|
|
1044
1710
|
defineSocketEvents,
|
|
1045
1711
|
exportFinalizedLeaves,
|
|
1712
|
+
extractLeafSourceByAst,
|
|
1046
1713
|
finalize,
|
|
1047
1714
|
flattenLeafSchemas,
|
|
1048
1715
|
flattenSerializableSchema,
|