@faapi/faapi 3.2.0 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +480 -339
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +375 -234
- package/dist/index.js.map +1 -1
- package/dist/testing.js +303 -163
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
package/dist/testing.js
CHANGED
|
@@ -129,14 +129,14 @@ var ValidationError = class extends FaapiError {
|
|
|
129
129
|
issues;
|
|
130
130
|
};
|
|
131
131
|
var RouteNotFoundError = class extends FaapiError {
|
|
132
|
-
constructor(
|
|
133
|
-
super("ROUTE_NOT_FOUND", `Route not found: ${
|
|
132
|
+
constructor(path12) {
|
|
133
|
+
super("ROUTE_NOT_FOUND", `Route not found: ${path12}`, 404);
|
|
134
134
|
this.name = "RouteNotFoundError";
|
|
135
135
|
}
|
|
136
136
|
};
|
|
137
137
|
var MethodNotAllowedError = class extends FaapiError {
|
|
138
|
-
constructor(method,
|
|
139
|
-
super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${
|
|
138
|
+
constructor(method, path12, allowedMethods) {
|
|
139
|
+
super("METHOD_NOT_ALLOWED", `Method ${method} not allowed for ${path12}`, 405);
|
|
140
140
|
this.allowedMethods = allowedMethods;
|
|
141
141
|
this.name = "MethodNotAllowedError";
|
|
142
142
|
}
|
|
@@ -370,8 +370,8 @@ function createContext(request, params, config = {}, ip = "") {
|
|
|
370
370
|
return ctx;
|
|
371
371
|
}
|
|
372
372
|
function createTestContext(options) {
|
|
373
|
-
const { method = "GET", path:
|
|
374
|
-
const url = new URL(`http://localhost${
|
|
373
|
+
const { method = "GET", path: path12, query, headers, params = {}, config = {}, ip = "" } = options;
|
|
374
|
+
const url = new URL(`http://localhost${path12}`);
|
|
375
375
|
if (query) {
|
|
376
376
|
for (const [key, value] of Object.entries(query)) {
|
|
377
377
|
if (Array.isArray(value)) {
|
|
@@ -756,9 +756,9 @@ async function invokeHandler(handler, ctx, body, middlewares, injectors) {
|
|
|
756
756
|
}
|
|
757
757
|
|
|
758
758
|
// src/testServer.ts
|
|
759
|
-
import
|
|
759
|
+
import path11 from "path";
|
|
760
760
|
import os from "os";
|
|
761
|
-
import
|
|
761
|
+
import fs10 from "fs/promises";
|
|
762
762
|
|
|
763
763
|
// src/router/scanRoutes.ts
|
|
764
764
|
import fg from "fast-glob";
|
|
@@ -770,9 +770,9 @@ var HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
|
|
|
770
770
|
var HTTP_METHOD_SET = new Set(HTTP_METHODS);
|
|
771
771
|
|
|
772
772
|
// src/utils/normalizePath.ts
|
|
773
|
-
function normalizePath(
|
|
774
|
-
if (!
|
|
775
|
-
let result =
|
|
773
|
+
function normalizePath(path12) {
|
|
774
|
+
if (!path12) return "";
|
|
775
|
+
let result = path12.replace(/\\/g, "/");
|
|
776
776
|
result = result.replace(/\/+/g, "/");
|
|
777
777
|
result = result.replace(/\/+$/, "");
|
|
778
778
|
if (result && !result.startsWith("/")) {
|
|
@@ -1045,25 +1045,93 @@ function sortRoutes(routes) {
|
|
|
1045
1045
|
}
|
|
1046
1046
|
|
|
1047
1047
|
// src/cli/generateSchemaFiles.ts
|
|
1048
|
-
import
|
|
1049
|
-
import
|
|
1048
|
+
import path4 from "path";
|
|
1049
|
+
import fs3 from "fs/promises";
|
|
1050
1050
|
|
|
1051
1051
|
// src/ast/createProgram.ts
|
|
1052
1052
|
import ts2 from "typescript";
|
|
1053
|
+
import fs2 from "fs";
|
|
1054
|
+
import path2 from "path";
|
|
1053
1055
|
var programCache = /* @__PURE__ */ new Map();
|
|
1056
|
+
var tsConfigCache = /* @__PURE__ */ new Map();
|
|
1057
|
+
function findTsConfig(filePath) {
|
|
1058
|
+
let dir = path2.dirname(filePath);
|
|
1059
|
+
const root = path2.parse(dir).root;
|
|
1060
|
+
while (true) {
|
|
1061
|
+
const candidate = path2.join(dir, "tsconfig.json");
|
|
1062
|
+
if (fs2.existsSync(candidate)) {
|
|
1063
|
+
return candidate;
|
|
1064
|
+
}
|
|
1065
|
+
if (dir === root) return null;
|
|
1066
|
+
const parent = path2.dirname(dir);
|
|
1067
|
+
if (parent === dir) return null;
|
|
1068
|
+
dir = parent;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
function parseTsConfig(tsconfigPath) {
|
|
1072
|
+
const cached = tsConfigCache.get(tsconfigPath);
|
|
1073
|
+
if (cached) return cached;
|
|
1074
|
+
const result = { fileNames: [] };
|
|
1075
|
+
try {
|
|
1076
|
+
const configFile = ts2.readConfigFile(tsconfigPath, (p) => fs2.readFileSync(p, "utf-8"));
|
|
1077
|
+
if (configFile.error) {
|
|
1078
|
+
tsConfigCache.set(tsconfigPath, result);
|
|
1079
|
+
return result;
|
|
1080
|
+
}
|
|
1081
|
+
const config = configFile.config ?? {};
|
|
1082
|
+
const basePath = path2.dirname(tsconfigPath);
|
|
1083
|
+
const parsed = ts2.parseJsonConfigFileContent(
|
|
1084
|
+
config,
|
|
1085
|
+
ts2.sys,
|
|
1086
|
+
basePath,
|
|
1087
|
+
/* existingOptions */
|
|
1088
|
+
void 0,
|
|
1089
|
+
tsconfigPath
|
|
1090
|
+
);
|
|
1091
|
+
result.fileNames = parsed.fileNames;
|
|
1092
|
+
if (parsed.options.module !== void 0) {
|
|
1093
|
+
result.module = parsed.options.module;
|
|
1094
|
+
}
|
|
1095
|
+
if (parsed.options.moduleResolution !== void 0) {
|
|
1096
|
+
result.moduleResolution = parsed.options.moduleResolution;
|
|
1097
|
+
}
|
|
1098
|
+
} catch {
|
|
1099
|
+
}
|
|
1100
|
+
tsConfigCache.set(tsconfigPath, result);
|
|
1101
|
+
return result;
|
|
1102
|
+
}
|
|
1054
1103
|
function createProgram(filePath) {
|
|
1055
1104
|
const cached = programCache.get(filePath);
|
|
1056
1105
|
if (cached) {
|
|
1057
1106
|
return cached;
|
|
1058
1107
|
}
|
|
1059
|
-
const
|
|
1108
|
+
const options = {
|
|
1060
1109
|
strict: true,
|
|
1061
1110
|
target: ts2.ScriptTarget.ES2022,
|
|
1062
1111
|
module: ts2.ModuleKind.NodeNext,
|
|
1063
1112
|
moduleResolution: ts2.ModuleResolutionKind.NodeNext,
|
|
1064
1113
|
skipLibCheck: true,
|
|
1065
1114
|
noEmit: true
|
|
1066
|
-
}
|
|
1115
|
+
};
|
|
1116
|
+
let rootNames = [filePath];
|
|
1117
|
+
const tsconfigPath = findTsConfig(filePath);
|
|
1118
|
+
if (tsconfigPath) {
|
|
1119
|
+
const tsOptions = parseTsConfig(tsconfigPath);
|
|
1120
|
+
if (tsOptions.module !== void 0) {
|
|
1121
|
+
options.module = tsOptions.module;
|
|
1122
|
+
}
|
|
1123
|
+
if (tsOptions.moduleResolution !== void 0) {
|
|
1124
|
+
options.moduleResolution = tsOptions.moduleResolution;
|
|
1125
|
+
}
|
|
1126
|
+
if (tsOptions.fileNames.length > 0) {
|
|
1127
|
+
if (!tsOptions.fileNames.includes(filePath)) {
|
|
1128
|
+
rootNames = [filePath, ...tsOptions.fileNames];
|
|
1129
|
+
} else {
|
|
1130
|
+
rootNames = tsOptions.fileNames;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
const program = ts2.createProgram(rootNames, options);
|
|
1067
1135
|
programCache.set(filePath, program);
|
|
1068
1136
|
return program;
|
|
1069
1137
|
}
|
|
@@ -1073,6 +1141,10 @@ import ts4 from "typescript";
|
|
|
1073
1141
|
|
|
1074
1142
|
// src/ast/resolveTypeNode.ts
|
|
1075
1143
|
import ts3 from "typescript";
|
|
1144
|
+
var currentProgram = null;
|
|
1145
|
+
function setProgramContext(program) {
|
|
1146
|
+
currentProgram = program;
|
|
1147
|
+
}
|
|
1076
1148
|
var SchemaExtractionError = class extends Error {
|
|
1077
1149
|
constructor(typeText, reason, options) {
|
|
1078
1150
|
super(`\u65E0\u6CD5\u89E3\u6790\u7C7B\u578B "${typeText}": ${reason}`, options);
|
|
@@ -1395,11 +1467,69 @@ function resolveTypeReference(typeNode, checker, visited = /* @__PURE__ */ new S
|
|
|
1395
1467
|
if (ts3.isEnumDeclaration(declaration)) {
|
|
1396
1468
|
return resolveEnumDeclaration(declaration);
|
|
1397
1469
|
}
|
|
1470
|
+
if (ts3.isImportSpecifier(declaration) || ts3.isImportClause(declaration)) {
|
|
1471
|
+
const resolved = resolveImportAlias(typeNode, symbol, checker, visited);
|
|
1472
|
+
if (resolved) return resolved;
|
|
1473
|
+
}
|
|
1398
1474
|
}
|
|
1399
1475
|
}
|
|
1400
1476
|
}
|
|
1401
1477
|
throw new SchemaExtractionError(typeNode.getText(), `\u65E0\u6CD5\u89E3\u6790\u7684\u5F15\u7528\u7C7B\u578B "${typeName}"`);
|
|
1402
1478
|
}
|
|
1479
|
+
function resolveImportAlias(typeNode, symbol, checker, visited) {
|
|
1480
|
+
const typeName = typeNode.typeName.getText();
|
|
1481
|
+
try {
|
|
1482
|
+
const aliased = checker.getAliasedSymbol(symbol);
|
|
1483
|
+
if (aliased && aliased.declarations && aliased.declarations.length > 0) {
|
|
1484
|
+
const decl = aliased.declarations[0];
|
|
1485
|
+
if (ts3.isInterfaceDeclaration(decl)) {
|
|
1486
|
+
return resolveInterfaceDeclaration(decl, checker, visited);
|
|
1487
|
+
}
|
|
1488
|
+
if (ts3.isTypeAliasDeclaration(decl)) {
|
|
1489
|
+
return resolveTypeNode(decl.type, checker, visited);
|
|
1490
|
+
}
|
|
1491
|
+
if (ts3.isEnumDeclaration(decl)) {
|
|
1492
|
+
return resolveEnumDeclaration(decl);
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
} catch {
|
|
1496
|
+
}
|
|
1497
|
+
const program = currentProgram;
|
|
1498
|
+
if (!program) return null;
|
|
1499
|
+
const allSFs = program.getSourceFiles();
|
|
1500
|
+
for (const sourceFile of allSFs) {
|
|
1501
|
+
if (sourceFile.fileName.includes("/node_modules/") || sourceFile.fileName.includes("typescript/lib/")) {
|
|
1502
|
+
continue;
|
|
1503
|
+
}
|
|
1504
|
+
const found = findTopLevelDecl(sourceFile, typeName);
|
|
1505
|
+
if (found) {
|
|
1506
|
+
if (found.kind === "interface") {
|
|
1507
|
+
return resolveInterfaceDeclaration(found.node, checker, visited);
|
|
1508
|
+
}
|
|
1509
|
+
if (found.kind === "typeAlias") {
|
|
1510
|
+
return resolveTypeNode(found.node.type, checker, visited);
|
|
1511
|
+
}
|
|
1512
|
+
if (found.kind === "enum") {
|
|
1513
|
+
return resolveEnumDeclaration(found.node);
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
return null;
|
|
1518
|
+
}
|
|
1519
|
+
function findTopLevelDecl(sourceFile, typeName) {
|
|
1520
|
+
let found = null;
|
|
1521
|
+
ts3.forEachChild(sourceFile, (node) => {
|
|
1522
|
+
if (found) return;
|
|
1523
|
+
if (ts3.isInterfaceDeclaration(node) && node.name.text === typeName) {
|
|
1524
|
+
found = { kind: "interface", node };
|
|
1525
|
+
} else if (ts3.isTypeAliasDeclaration(node) && node.name.text === typeName) {
|
|
1526
|
+
found = { kind: "typeAlias", node };
|
|
1527
|
+
} else if (ts3.isEnumDeclaration(node) && node.name.text === typeName) {
|
|
1528
|
+
found = { kind: "enum", node };
|
|
1529
|
+
}
|
|
1530
|
+
});
|
|
1531
|
+
return found;
|
|
1532
|
+
}
|
|
1403
1533
|
function resolveEnumDeclaration(node) {
|
|
1404
1534
|
const members = [];
|
|
1405
1535
|
let nextNumericValue = 0;
|
|
@@ -1604,80 +1734,90 @@ function extractTypeInfo(program, filePath, typeName) {
|
|
|
1604
1734
|
const sourceFile = program.getSourceFile(filePath);
|
|
1605
1735
|
if (!sourceFile) return null;
|
|
1606
1736
|
const checker = program.getTypeChecker();
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1737
|
+
setProgramContext(program);
|
|
1738
|
+
try {
|
|
1739
|
+
let result = null;
|
|
1740
|
+
ts4.forEachChild(sourceFile, (node) => {
|
|
1741
|
+
if (result) return;
|
|
1742
|
+
if (ts4.isInterfaceDeclaration(node) && node.name.text === typeName) {
|
|
1743
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1744
|
+
visited.add(typeName);
|
|
1745
|
+
const runtimeType = withFileContext(
|
|
1746
|
+
filePath,
|
|
1747
|
+
typeName,
|
|
1748
|
+
() => resolveInterfaceDeclaration(node, checker, visited)
|
|
1749
|
+
);
|
|
1750
|
+
result = {
|
|
1751
|
+
name: typeName,
|
|
1752
|
+
properties: runtimeType.kind === "object" ? runtimeType.properties : [],
|
|
1753
|
+
runtimeType
|
|
1754
|
+
};
|
|
1755
|
+
return;
|
|
1756
|
+
}
|
|
1757
|
+
if (ts4.isTypeAliasDeclaration(node) && node.name.text === typeName) {
|
|
1758
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1759
|
+
visited.add(typeName);
|
|
1760
|
+
const runtimeType = withFileContext(
|
|
1761
|
+
filePath,
|
|
1762
|
+
typeName,
|
|
1763
|
+
() => resolveTypeNode(node.type, checker, visited)
|
|
1764
|
+
);
|
|
1765
|
+
result = {
|
|
1766
|
+
name: typeName,
|
|
1767
|
+
properties: runtimeType.kind === "object" ? runtimeType.properties : [],
|
|
1768
|
+
runtimeType
|
|
1769
|
+
};
|
|
1770
|
+
return;
|
|
1771
|
+
}
|
|
1772
|
+
});
|
|
1773
|
+
return result;
|
|
1774
|
+
} finally {
|
|
1775
|
+
setProgramContext(null);
|
|
1776
|
+
}
|
|
1642
1777
|
}
|
|
1643
1778
|
function extractAllTypes(program, filePath) {
|
|
1644
1779
|
const sourceFile = program.getSourceFile(filePath);
|
|
1645
1780
|
if (!sourceFile) return /* @__PURE__ */ new Map();
|
|
1646
1781
|
const checker = program.getTypeChecker();
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1782
|
+
setProgramContext(program);
|
|
1783
|
+
try {
|
|
1784
|
+
const result = /* @__PURE__ */ new Map();
|
|
1785
|
+
ts4.forEachChild(sourceFile, (node) => {
|
|
1786
|
+
if (ts4.isInterfaceDeclaration(node)) {
|
|
1787
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1788
|
+
visited.add(node.name.text);
|
|
1789
|
+
const runtimeType = withFileContext(
|
|
1790
|
+
filePath,
|
|
1791
|
+
node.name.text,
|
|
1792
|
+
() => resolveInterfaceDeclaration(node, checker, visited)
|
|
1793
|
+
);
|
|
1794
|
+
result.set(node.name.text, {
|
|
1795
|
+
name: node.name.text,
|
|
1796
|
+
properties: runtimeType.kind === "object" ? runtimeType.properties : [],
|
|
1797
|
+
runtimeType
|
|
1798
|
+
});
|
|
1799
|
+
return;
|
|
1800
|
+
}
|
|
1801
|
+
if (ts4.isTypeAliasDeclaration(node)) {
|
|
1802
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1803
|
+
visited.add(node.name.text);
|
|
1804
|
+
const runtimeType = withFileContext(
|
|
1805
|
+
filePath,
|
|
1806
|
+
node.name.text,
|
|
1807
|
+
() => resolveTypeNode(node.type, checker, visited)
|
|
1808
|
+
);
|
|
1809
|
+
result.set(node.name.text, {
|
|
1810
|
+
name: node.name.text,
|
|
1811
|
+
properties: runtimeType.kind === "object" ? runtimeType.properties : [],
|
|
1812
|
+
runtimeType
|
|
1813
|
+
});
|
|
1814
|
+
return;
|
|
1815
|
+
}
|
|
1816
|
+
});
|
|
1817
|
+
return result;
|
|
1818
|
+
} finally {
|
|
1819
|
+
setProgramContext(null);
|
|
1820
|
+
}
|
|
1681
1821
|
}
|
|
1682
1822
|
function withFileContext(filePath, typeName, fn) {
|
|
1683
1823
|
try {
|
|
@@ -1760,11 +1900,11 @@ function extractSchema(typeNode, sourceFile) {
|
|
|
1760
1900
|
}
|
|
1761
1901
|
|
|
1762
1902
|
// src/cli/collectRouteSchemaSources.ts
|
|
1763
|
-
import
|
|
1903
|
+
import path3 from "path";
|
|
1764
1904
|
function collectRouteSchemaSources(routes, rootDir) {
|
|
1765
1905
|
const methodsByFile = /* @__PURE__ */ new Map();
|
|
1766
1906
|
for (const route of routes) {
|
|
1767
|
-
const filePath = rootDir ?
|
|
1907
|
+
const filePath = rootDir ? path3.resolve(rootDir, route.filePath) : route.filePath;
|
|
1768
1908
|
let entry = methodsByFile.get(filePath);
|
|
1769
1909
|
if (!entry) {
|
|
1770
1910
|
entry = { urlPath: route.urlPath, methods: /* @__PURE__ */ new Set() };
|
|
@@ -2115,7 +2255,7 @@ function getSchemaOutputPath(sourceFile, dist, rootDir) {
|
|
|
2115
2255
|
}
|
|
2116
2256
|
const idx = rel.lastIndexOf("/");
|
|
2117
2257
|
const relDir = idx >= 0 ? rel.slice(0, idx) : "";
|
|
2118
|
-
return
|
|
2258
|
+
return path4.resolve(rootDir, dist, relDir, "zod.js");
|
|
2119
2259
|
}
|
|
2120
2260
|
function getRuntimeSchemaPath(filePath, dist, rootDir) {
|
|
2121
2261
|
let rel = filePath.replace(/\\/g, "/");
|
|
@@ -2126,7 +2266,7 @@ function getRuntimeSchemaPath(filePath, dist, rootDir) {
|
|
|
2126
2266
|
}
|
|
2127
2267
|
const idx = rel.lastIndexOf("/");
|
|
2128
2268
|
const relDir = idx >= 0 ? rel.slice(0, idx) : "";
|
|
2129
|
-
return
|
|
2269
|
+
return path4.resolve(rootDir, dist, relDir, "zod.js");
|
|
2130
2270
|
}
|
|
2131
2271
|
function getHelpersImportPath(relDir) {
|
|
2132
2272
|
if (!relDir) return `./${HELPERS_FILENAME}`;
|
|
@@ -2176,7 +2316,7 @@ async function generateSchemaFiles(routes, rootDir, dist) {
|
|
|
2176
2316
|
}
|
|
2177
2317
|
const fileEntries = [];
|
|
2178
2318
|
for (const [filePath, fileSources] of sourcesByFile) {
|
|
2179
|
-
const relFile =
|
|
2319
|
+
const relFile = path4.relative(rootDir, filePath).replace(/\\/g, "/");
|
|
2180
2320
|
const outputPath = getSchemaOutputPath(relFile, dist, rootDir);
|
|
2181
2321
|
const allTypes = allTypesByFile.get(filePath) ?? /* @__PURE__ */ new Map();
|
|
2182
2322
|
let relForDir = relFile;
|
|
@@ -2191,7 +2331,7 @@ async function generateSchemaFiles(routes, rootDir, dist) {
|
|
|
2191
2331
|
}
|
|
2192
2332
|
const allSourceCode = fileEntries.map((e) => e.source).join("\n");
|
|
2193
2333
|
if (usesCoerceHelpers(allSourceCode)) {
|
|
2194
|
-
const helpersPath =
|
|
2334
|
+
const helpersPath = path4.resolve(rootDir, dist, HELPERS_FILENAME);
|
|
2195
2335
|
await writeSchemaFile(helpersPath, generateHelpersFileSource());
|
|
2196
2336
|
}
|
|
2197
2337
|
await Promise.all(
|
|
@@ -2199,22 +2339,22 @@ async function generateSchemaFiles(routes, rootDir, dist) {
|
|
|
2199
2339
|
);
|
|
2200
2340
|
}
|
|
2201
2341
|
async function writeSchemaFile(outputPath, source) {
|
|
2202
|
-
await
|
|
2203
|
-
await
|
|
2342
|
+
await fs3.mkdir(path4.dirname(outputPath), { recursive: true });
|
|
2343
|
+
await fs3.writeFile(outputPath, source, "utf-8");
|
|
2204
2344
|
}
|
|
2205
2345
|
|
|
2206
2346
|
// src/cli/compileOnDemand.ts
|
|
2207
|
-
import
|
|
2208
|
-
import
|
|
2347
|
+
import path8 from "path";
|
|
2348
|
+
import fs7 from "fs";
|
|
2209
2349
|
|
|
2210
2350
|
// src/cli/compileDevRoutes.ts
|
|
2211
|
-
import
|
|
2212
|
-
import
|
|
2351
|
+
import path7 from "path";
|
|
2352
|
+
import fs6 from "fs";
|
|
2213
2353
|
import fg2 from "fast-glob";
|
|
2214
2354
|
|
|
2215
2355
|
// src/cli/aliasPlugin.ts
|
|
2216
|
-
import
|
|
2217
|
-
import
|
|
2356
|
+
import path6 from "path";
|
|
2357
|
+
import fs5 from "fs";
|
|
2218
2358
|
|
|
2219
2359
|
// src/utils/resolveAlias.ts
|
|
2220
2360
|
function resolveAlias(specifier, config) {
|
|
@@ -2241,11 +2381,11 @@ function resolveAlias(specifier, config) {
|
|
|
2241
2381
|
|
|
2242
2382
|
// src/utils/readTsconfig.ts
|
|
2243
2383
|
import ts6 from "typescript";
|
|
2244
|
-
import
|
|
2245
|
-
import
|
|
2384
|
+
import path5 from "path";
|
|
2385
|
+
import fs4 from "fs";
|
|
2246
2386
|
function readTsconfig(rootDir) {
|
|
2247
|
-
const tsconfigPath =
|
|
2248
|
-
if (!
|
|
2387
|
+
const tsconfigPath = path5.resolve(rootDir, "tsconfig.json");
|
|
2388
|
+
if (!fs4.existsSync(tsconfigPath)) return null;
|
|
2249
2389
|
const configFile = ts6.readConfigFile(tsconfigPath, ts6.sys.readFile);
|
|
2250
2390
|
if (configFile.error || !configFile.config) return null;
|
|
2251
2391
|
const parsed = ts6.parseJsonConfigFileContent(configFile.config, ts6.sys, rootDir);
|
|
@@ -2254,7 +2394,7 @@ function readTsconfig(rootDir) {
|
|
|
2254
2394
|
if (!rawPaths) return null;
|
|
2255
2395
|
const paths = {};
|
|
2256
2396
|
for (const [pattern, targets] of Object.entries(rawPaths)) {
|
|
2257
|
-
paths[pattern] = targets.map((t) =>
|
|
2397
|
+
paths[pattern] = targets.map((t) => path5.resolve(baseUrl, t));
|
|
2258
2398
|
}
|
|
2259
2399
|
return { baseUrl, paths };
|
|
2260
2400
|
}
|
|
@@ -2267,29 +2407,29 @@ function toProdExtension(filePath) {
|
|
|
2267
2407
|
return filePath;
|
|
2268
2408
|
}
|
|
2269
2409
|
function toProdImportPath(sourceFile, importer) {
|
|
2270
|
-
const importerDir =
|
|
2271
|
-
let rel =
|
|
2272
|
-
rel = rel.split(
|
|
2410
|
+
const importerDir = path6.dirname(importer);
|
|
2411
|
+
let rel = path6.relative(importerDir, sourceFile);
|
|
2412
|
+
rel = rel.split(path6.sep).join("/");
|
|
2273
2413
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
2274
2414
|
return toProdExtension(rel);
|
|
2275
2415
|
}
|
|
2276
2416
|
function toRealPath(p) {
|
|
2277
2417
|
try {
|
|
2278
|
-
return
|
|
2418
|
+
return fs5.realpathSync(p);
|
|
2279
2419
|
} catch {
|
|
2280
2420
|
return p;
|
|
2281
2421
|
}
|
|
2282
2422
|
}
|
|
2283
2423
|
function isInsideDir(filePath, dir) {
|
|
2284
|
-
const rel =
|
|
2285
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
2424
|
+
const rel = path6.relative(dir, filePath);
|
|
2425
|
+
return rel !== "" && !rel.startsWith("..") && !path6.isAbsolute(rel);
|
|
2286
2426
|
}
|
|
2287
2427
|
var APP_DIR = "src";
|
|
2288
2428
|
function toStrippedProdImportPath(sourceFile, rootDir) {
|
|
2289
|
-
const appDirAbs = toRealPath(
|
|
2429
|
+
const appDirAbs = toRealPath(path6.resolve(rootDir, APP_DIR));
|
|
2290
2430
|
const sourceReal = toRealPath(sourceFile);
|
|
2291
|
-
let rel =
|
|
2292
|
-
rel = rel.split(
|
|
2431
|
+
let rel = path6.relative(appDirAbs, sourceReal);
|
|
2432
|
+
rel = rel.split(path6.sep).join("/");
|
|
2293
2433
|
if (!rel.startsWith(".")) rel = "./" + rel;
|
|
2294
2434
|
return toProdExtension(rel);
|
|
2295
2435
|
}
|
|
@@ -2304,34 +2444,34 @@ var INDEX_EXTS = [
|
|
|
2304
2444
|
"/index.cjs"
|
|
2305
2445
|
];
|
|
2306
2446
|
function resolveRelativeSpecifier(importer, specifier) {
|
|
2307
|
-
const importerDir =
|
|
2308
|
-
const base =
|
|
2447
|
+
const importerDir = path6.dirname(importer);
|
|
2448
|
+
const base = path6.resolve(importerDir, specifier);
|
|
2309
2449
|
if (PROD_EXTS.some((ext) => specifier.endsWith(ext))) {
|
|
2310
|
-
return
|
|
2450
|
+
return fs5.existsSync(base) ? base : null;
|
|
2311
2451
|
}
|
|
2312
2452
|
if (/\.(ts|tsx|jsx)$/.test(specifier)) {
|
|
2313
|
-
return
|
|
2453
|
+
return fs5.existsSync(base) ? base : null;
|
|
2314
2454
|
}
|
|
2315
2455
|
for (const ext of SOURCE_EXTS) {
|
|
2316
2456
|
const file = base + ext;
|
|
2317
|
-
if (
|
|
2457
|
+
if (fs5.existsSync(file)) return file;
|
|
2318
2458
|
}
|
|
2319
2459
|
for (const indexExt of INDEX_EXTS) {
|
|
2320
2460
|
const file = base + indexExt;
|
|
2321
|
-
if (
|
|
2461
|
+
if (fs5.existsSync(file)) return file;
|
|
2322
2462
|
}
|
|
2323
2463
|
return null;
|
|
2324
2464
|
}
|
|
2325
2465
|
function createAliasPlugin(config, options) {
|
|
2326
2466
|
const SPEC_RE = /(\bfrom\s*|import\s*\(\s*)(['"])([^'"]+)\2/g;
|
|
2327
|
-
const appDirAbs = options?.rootDir ? toRealPath(
|
|
2467
|
+
const appDirAbs = options?.rootDir ? toRealPath(path6.resolve(options.rootDir, APP_DIR)) : null;
|
|
2328
2468
|
return {
|
|
2329
2469
|
name: "faapi-alias",
|
|
2330
2470
|
setup(build) {
|
|
2331
2471
|
build.onLoad({ filter: /\.(ts|tsx|js|jsx|mjs|cjs)$/ }, (args) => {
|
|
2332
2472
|
let source;
|
|
2333
2473
|
try {
|
|
2334
|
-
source =
|
|
2474
|
+
source = fs5.readFileSync(args.path, "utf8");
|
|
2335
2475
|
} catch {
|
|
2336
2476
|
return void 0;
|
|
2337
2477
|
}
|
|
@@ -2364,7 +2504,7 @@ function createAliasPlugin(config, options) {
|
|
|
2364
2504
|
for (const candidate of candidates) {
|
|
2365
2505
|
for (const ext of SOURCE_EXTS) {
|
|
2366
2506
|
const file = candidate + ext;
|
|
2367
|
-
if (
|
|
2507
|
+
if (fs5.existsSync(file)) {
|
|
2368
2508
|
modified = true;
|
|
2369
2509
|
if (appDirAbs && importerOutsideAppDir && isInsideDir(file, appDirAbs)) {
|
|
2370
2510
|
return `${prefix}${quote}${toStrippedProdImportPath(
|
|
@@ -2377,7 +2517,7 @@ function createAliasPlugin(config, options) {
|
|
|
2377
2517
|
}
|
|
2378
2518
|
for (const indexExt of INDEX_EXTS) {
|
|
2379
2519
|
const file = candidate + indexExt;
|
|
2380
|
-
if (
|
|
2520
|
+
if (fs5.existsSync(file)) {
|
|
2381
2521
|
modified = true;
|
|
2382
2522
|
if (appDirAbs && importerOutsideAppDir && isInsideDir(file, appDirAbs)) {
|
|
2383
2523
|
return `${prefix}${quote}${toStrippedProdImportPath(
|
|
@@ -2415,11 +2555,11 @@ async function compileDevRoutes(options) {
|
|
|
2415
2555
|
if (entryPoints.length === 0) {
|
|
2416
2556
|
return { compiledFiles: [] };
|
|
2417
2557
|
}
|
|
2418
|
-
const absDist =
|
|
2419
|
-
await
|
|
2558
|
+
const absDist = path7.resolve(rootDir, dist);
|
|
2559
|
+
await fs6.promises.mkdir(absDist, { recursive: true });
|
|
2420
2560
|
const plugins = buildAliasPlugins(rootDir);
|
|
2421
2561
|
const esbuild = await import("esbuild");
|
|
2422
|
-
const outbase =
|
|
2562
|
+
const outbase = path7.resolve(rootDir, APP_DIR2);
|
|
2423
2563
|
const result = await esbuild.build({
|
|
2424
2564
|
entryPoints,
|
|
2425
2565
|
outdir: absDist,
|
|
@@ -2436,10 +2576,10 @@ async function compileDevRoutes(options) {
|
|
|
2436
2576
|
if (result.outputFiles) {
|
|
2437
2577
|
await Promise.all(
|
|
2438
2578
|
result.outputFiles.map(async (file) => {
|
|
2439
|
-
await
|
|
2579
|
+
await fs6.promises.mkdir(path7.dirname(file.path), { recursive: true });
|
|
2440
2580
|
const tmp = `${file.path}.tmp-${process.pid}-${Math.random().toString(36).slice(2)}`;
|
|
2441
|
-
await
|
|
2442
|
-
await
|
|
2581
|
+
await fs6.promises.writeFile(tmp, file.contents);
|
|
2582
|
+
await fs6.promises.rename(tmp, file.path);
|
|
2443
2583
|
})
|
|
2444
2584
|
);
|
|
2445
2585
|
}
|
|
@@ -2449,8 +2589,8 @@ async function compileDevRoutes(options) {
|
|
|
2449
2589
|
// src/cli/compileOnDemand.ts
|
|
2450
2590
|
function isProductFresh(sourceAbsPath, productAbsPath) {
|
|
2451
2591
|
try {
|
|
2452
|
-
const srcStat =
|
|
2453
|
-
const prodStat =
|
|
2592
|
+
const srcStat = fs7.statSync(sourceAbsPath);
|
|
2593
|
+
const prodStat = fs7.statSync(productAbsPath);
|
|
2454
2594
|
return prodStat.mtimeMs >= srcStat.mtimeMs;
|
|
2455
2595
|
} catch {
|
|
2456
2596
|
return false;
|
|
@@ -2477,7 +2617,7 @@ async function ensureCompiled(sourceAbsPath, rootDir, dist) {
|
|
|
2477
2617
|
if (state.compiledFiles.has(sourceAbsPath)) {
|
|
2478
2618
|
return false;
|
|
2479
2619
|
}
|
|
2480
|
-
if (!
|
|
2620
|
+
if (!fs7.existsSync(sourceAbsPath)) {
|
|
2481
2621
|
return false;
|
|
2482
2622
|
}
|
|
2483
2623
|
const productPath = prodSourcePathToProductPath(sourceAbsPath, rootDir, dist);
|
|
@@ -2503,11 +2643,11 @@ async function ensureCompiled(sourceAbsPath, rootDir, dist) {
|
|
|
2503
2643
|
}
|
|
2504
2644
|
}
|
|
2505
2645
|
function prodSourcePathToProductPath(sourceAbsPath, rootDir, dist) {
|
|
2506
|
-
const rel =
|
|
2646
|
+
const rel = path8.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
|
|
2507
2647
|
if (!rel.startsWith("src/")) return null;
|
|
2508
2648
|
const relWithoutSrc = rel.slice(4);
|
|
2509
2649
|
const jsRel = relWithoutSrc.replace(/\.ts$/, ".js");
|
|
2510
|
-
return
|
|
2650
|
+
return path8.resolve(rootDir, dist, jsRel);
|
|
2511
2651
|
}
|
|
2512
2652
|
async function ensureSchemaGenerated(schemaPath, routeFilePath, routes, rootDir, dist) {
|
|
2513
2653
|
const inFlight = state.inFlightSchemaGenerations.get(schemaPath);
|
|
@@ -2519,9 +2659,9 @@ async function ensureSchemaGenerated(schemaPath, routeFilePath, routes, rootDir,
|
|
|
2519
2659
|
if (state.generatedSchemas.has(schemaPath)) {
|
|
2520
2660
|
return false;
|
|
2521
2661
|
}
|
|
2522
|
-
const prodAbsPath =
|
|
2662
|
+
const prodAbsPath = path8.resolve(rootDir, routeFilePath);
|
|
2523
2663
|
const sourceAbsPath = prodPathToSourcePath(prodAbsPath, rootDir, dist);
|
|
2524
|
-
if (!
|
|
2664
|
+
if (!fs7.existsSync(sourceAbsPath)) {
|
|
2525
2665
|
return false;
|
|
2526
2666
|
}
|
|
2527
2667
|
if (isProductFresh(sourceAbsPath, schemaPath)) {
|
|
@@ -2532,7 +2672,7 @@ async function ensureSchemaGenerated(schemaPath, routeFilePath, routes, rootDir,
|
|
|
2532
2672
|
if (fileRoutes.length === 0) {
|
|
2533
2673
|
return false;
|
|
2534
2674
|
}
|
|
2535
|
-
const sourceRelPath =
|
|
2675
|
+
const sourceRelPath = path8.relative(rootDir, sourceAbsPath).replace(/\\/g, "/");
|
|
2536
2676
|
const sourceRoutes = fileRoutes.map((r) => ({ ...r, filePath: sourceRelPath }));
|
|
2537
2677
|
const generatePromise = (async () => {
|
|
2538
2678
|
await generateSchemaFiles(sourceRoutes, rootDir, dist);
|
|
@@ -2547,16 +2687,16 @@ async function ensureSchemaGenerated(schemaPath, routeFilePath, routes, rootDir,
|
|
|
2547
2687
|
}
|
|
2548
2688
|
}
|
|
2549
2689
|
function prodPathToSourcePath(prodAbsPath, rootDir, dist) {
|
|
2550
|
-
const rel =
|
|
2690
|
+
const rel = path8.relative(rootDir, prodAbsPath).replace(/\\/g, "/");
|
|
2551
2691
|
let relWithoutDist = rel;
|
|
2552
2692
|
if (relWithoutDist.startsWith(`${dist}/`)) {
|
|
2553
2693
|
relWithoutDist = relWithoutDist.slice(dist.length + 1);
|
|
2554
2694
|
}
|
|
2555
2695
|
const srcRel = `src/${relWithoutDist}`;
|
|
2556
2696
|
const tsRel = srcRel.replace(/\.js$/, ".ts");
|
|
2557
|
-
const tsAbs =
|
|
2558
|
-
if (
|
|
2559
|
-
return
|
|
2697
|
+
const tsAbs = path8.resolve(rootDir, tsRel);
|
|
2698
|
+
if (fs7.existsSync(tsAbs)) return tsAbs;
|
|
2699
|
+
return path8.resolve(rootDir, srcRel);
|
|
2560
2700
|
}
|
|
2561
2701
|
function isDevOnDemandEnabled() {
|
|
2562
2702
|
return state.enabled;
|
|
@@ -2609,9 +2749,9 @@ async function validateInput(schemaPath, method, inputType, input) {
|
|
|
2609
2749
|
function mapZodIssues(error) {
|
|
2610
2750
|
return error.issues.map((issue) => {
|
|
2611
2751
|
const code = mapZodCode(issue.code, issue.message);
|
|
2612
|
-
const
|
|
2752
|
+
const path12 = issue.path.map(String).join(".") || "";
|
|
2613
2753
|
return {
|
|
2614
|
-
path:
|
|
2754
|
+
path: path12,
|
|
2615
2755
|
code,
|
|
2616
2756
|
expected: issue.expected ?? mapExpectedFromMessage(issue.message),
|
|
2617
2757
|
received: issue.received ?? mapReceivedFromMessage(issue.message),
|
|
@@ -2659,45 +2799,45 @@ import {
|
|
|
2659
2799
|
import { createSecureServer as createHttp2SecureServer } from "http2";
|
|
2660
2800
|
import { readFileSync } from "fs";
|
|
2661
2801
|
import { Readable as Readable2 } from "stream";
|
|
2662
|
-
import
|
|
2802
|
+
import path10 from "path";
|
|
2663
2803
|
|
|
2664
2804
|
// src/router/matchRoute.ts
|
|
2665
|
-
function matchRoute(routes, method,
|
|
2805
|
+
function matchRoute(routes, method, path12) {
|
|
2666
2806
|
for (const route of routes) {
|
|
2667
2807
|
if (route.method !== method) {
|
|
2668
2808
|
continue;
|
|
2669
2809
|
}
|
|
2670
2810
|
if (!route.isDynamic) {
|
|
2671
|
-
if (route.urlPath ===
|
|
2811
|
+
if (route.urlPath === path12) {
|
|
2672
2812
|
return { route, params: {} };
|
|
2673
2813
|
}
|
|
2674
2814
|
continue;
|
|
2675
2815
|
}
|
|
2676
|
-
const params = matchDynamicPath(route.urlPath,
|
|
2816
|
+
const params = matchDynamicPath(route.urlPath, path12, route.paramNames, route.isCatchAll);
|
|
2677
2817
|
if (params !== null) {
|
|
2678
2818
|
return { route, params };
|
|
2679
2819
|
}
|
|
2680
2820
|
}
|
|
2681
2821
|
return null;
|
|
2682
2822
|
}
|
|
2683
|
-
function matchWsRoute(wsRoutes,
|
|
2823
|
+
function matchWsRoute(wsRoutes, path12) {
|
|
2684
2824
|
for (const route of wsRoutes) {
|
|
2685
2825
|
if (!route.isDynamic) {
|
|
2686
|
-
if (route.urlPath ===
|
|
2826
|
+
if (route.urlPath === path12) {
|
|
2687
2827
|
return { route, params: {} };
|
|
2688
2828
|
}
|
|
2689
2829
|
continue;
|
|
2690
2830
|
}
|
|
2691
|
-
const params = matchDynamicPath(route.urlPath,
|
|
2831
|
+
const params = matchDynamicPath(route.urlPath, path12, route.paramNames, route.isCatchAll);
|
|
2692
2832
|
if (params !== null) {
|
|
2693
2833
|
return { route, params };
|
|
2694
2834
|
}
|
|
2695
2835
|
}
|
|
2696
2836
|
return null;
|
|
2697
2837
|
}
|
|
2698
|
-
function matchDynamicPath(pattern,
|
|
2838
|
+
function matchDynamicPath(pattern, path12, paramNames, isCatchAll) {
|
|
2699
2839
|
const patternSegments = pattern.split("/").filter(Boolean);
|
|
2700
|
-
const pathSegments =
|
|
2840
|
+
const pathSegments = path12.split("/").filter(Boolean);
|
|
2701
2841
|
if (isCatchAll) {
|
|
2702
2842
|
const nonCatchAllCount = patternSegments.length - 1;
|
|
2703
2843
|
if (pathSegments.length <= nonCatchAllCount) {
|
|
@@ -2743,7 +2883,7 @@ function matchDynamicPath(pattern, path11, paramNames, isCatchAll) {
|
|
|
2743
2883
|
}
|
|
2744
2884
|
|
|
2745
2885
|
// src/loader/loadRouteModule.ts
|
|
2746
|
-
import
|
|
2886
|
+
import fs8 from "fs";
|
|
2747
2887
|
|
|
2748
2888
|
// src/loader/resolveExports.ts
|
|
2749
2889
|
function resolveExport(module, exportName) {
|
|
@@ -2775,7 +2915,7 @@ async function loadRouteModule(filePath, method, rootDir) {
|
|
|
2775
2915
|
const dist = getDevDist();
|
|
2776
2916
|
if (dist) {
|
|
2777
2917
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
2778
|
-
if (sourcePath &&
|
|
2918
|
+
if (sourcePath && fs8.existsSync(sourcePath)) {
|
|
2779
2919
|
try {
|
|
2780
2920
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
2781
2921
|
} catch (compileErr) {
|
|
@@ -3081,9 +3221,9 @@ function logger(options = {}) {
|
|
|
3081
3221
|
}
|
|
3082
3222
|
|
|
3083
3223
|
// src/server/handleWsUpgrade.ts
|
|
3084
|
-
import
|
|
3224
|
+
import fs9 from "fs";
|
|
3085
3225
|
import { WebSocketServer, WebSocket } from "ws";
|
|
3086
|
-
import
|
|
3226
|
+
import path9 from "path";
|
|
3087
3227
|
|
|
3088
3228
|
// src/server/serverUtils.ts
|
|
3089
3229
|
function nodeHttpToWebHeaders(req) {
|
|
@@ -3139,7 +3279,7 @@ async function loadWsHandler(filePath, ctx, rootDir) {
|
|
|
3139
3279
|
const dist = getDevDist();
|
|
3140
3280
|
if (dist) {
|
|
3141
3281
|
const sourcePath = prodPathToSourcePath(filePath, rootDir, dist);
|
|
3142
|
-
if (sourcePath &&
|
|
3282
|
+
if (sourcePath && fs9.existsSync(sourcePath)) {
|
|
3143
3283
|
await ensureCompiled(sourcePath, rootDir, dist);
|
|
3144
3284
|
}
|
|
3145
3285
|
}
|
|
@@ -3219,7 +3359,7 @@ function attachWebSocket(options) {
|
|
|
3219
3359
|
const finalHandler = async () => {
|
|
3220
3360
|
let handlers;
|
|
3221
3361
|
try {
|
|
3222
|
-
const absoluteFilePath =
|
|
3362
|
+
const absoluteFilePath = path9.resolve(rootDir, route.filePath);
|
|
3223
3363
|
handlers = await loadWsHandler(absoluteFilePath, ctx, rootDir);
|
|
3224
3364
|
} catch (err) {
|
|
3225
3365
|
const reason = err instanceof Error ? err.message : String(err);
|
|
@@ -3343,15 +3483,15 @@ function limitStreamSize(stream, maxSize) {
|
|
|
3343
3483
|
}
|
|
3344
3484
|
});
|
|
3345
3485
|
}
|
|
3346
|
-
function findAllowedMethods(routes,
|
|
3486
|
+
function findAllowedMethods(routes, path12) {
|
|
3347
3487
|
const methods = /* @__PURE__ */ new Set();
|
|
3348
3488
|
for (const route of routes) {
|
|
3349
|
-
if (route.urlPath ===
|
|
3489
|
+
if (route.urlPath === path12) {
|
|
3350
3490
|
methods.add(route.method);
|
|
3351
3491
|
continue;
|
|
3352
3492
|
}
|
|
3353
3493
|
if (route.isDynamic) {
|
|
3354
|
-
const params = matchDynamicPath(route.urlPath,
|
|
3494
|
+
const params = matchDynamicPath(route.urlPath, path12, route.paramNames, route.isCatchAll);
|
|
3355
3495
|
if (params !== null) {
|
|
3356
3496
|
methods.add(route.method);
|
|
3357
3497
|
}
|
|
@@ -3443,7 +3583,7 @@ function createRoutePipeline(opts) {
|
|
|
3443
3583
|
const match = resolveRouteOrThrow(routes, method, urlPath);
|
|
3444
3584
|
ctx.params = match.params;
|
|
3445
3585
|
const { route } = match;
|
|
3446
|
-
const absoluteFilePath =
|
|
3586
|
+
const absoluteFilePath = path10.resolve(rootDir, route.filePath);
|
|
3447
3587
|
const routeModule = await loadRouteModule(absoluteFilePath, route.method, rootDir);
|
|
3448
3588
|
const input = await resolveInput(route.method, request);
|
|
3449
3589
|
const inputType = getInputTypeForMethod(route.method);
|
|
@@ -3530,7 +3670,7 @@ async function createTestServer(options) {
|
|
|
3530
3670
|
} = options;
|
|
3531
3671
|
const { routes, wsRoutes } = await scanRoutes(rootDir, patterns);
|
|
3532
3672
|
const sorted = sortRoutes(routes);
|
|
3533
|
-
const schemaDist = dist ?
|
|
3673
|
+
const schemaDist = dist ? path11.isAbsolute(dist) ? dist : path11.resolve(rootDir, dist) : await fs10.mkdtemp(path11.join(os.tmpdir(), "faapi-test-schema-"));
|
|
3534
3674
|
await generateSchemaFiles(sorted, rootDir, schemaDist);
|
|
3535
3675
|
const { server } = createServer({
|
|
3536
3676
|
routes: sorted,
|
|
@@ -3563,7 +3703,7 @@ async function createTestServer(options) {
|
|
|
3563
3703
|
await new Promise((resolve) => {
|
|
3564
3704
|
server.close(() => resolve());
|
|
3565
3705
|
});
|
|
3566
|
-
await
|
|
3706
|
+
await fs10.rm(schemaDist, { recursive: true, force: true }).catch(() => {
|
|
3567
3707
|
});
|
|
3568
3708
|
invalidateSchemaCache();
|
|
3569
3709
|
}
|