schemock 0.0.4-alpha.13 → 0.0.4-alpha.14
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/adapters/index.d.mts +4 -4
- package/dist/adapters/index.d.ts +4 -4
- package/dist/cli/index.d.mts +18 -3
- package/dist/cli/index.d.ts +18 -3
- package/dist/cli/index.js +230 -21
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +230 -21
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli.js +256 -43
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/middleware/index.d.mts +4 -4
- package/dist/middleware/index.d.ts +4 -4
- package/dist/react/index.d.mts +3 -3
- package/dist/react/index.d.ts +3 -3
- package/dist/runtime/index.d.mts +2 -2
- package/dist/runtime/index.d.ts +2 -2
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/index.mjs.map +1 -1
- package/dist/schema/index.d.mts +2 -2
- package/dist/schema/index.d.ts +2 -2
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/index.mjs.map +1 -1
- package/dist/{types-vPJ91BuY.d.mts → types-BBeKlEd1.d.mts} +1 -1
- package/dist/{types-CWZQ6vqt.d.mts → types-BCLdZDSF.d.mts} +3 -3
- package/dist/{types-CWZQ6vqt.d.ts → types-BCLdZDSF.d.ts} +3 -3
- package/dist/{types-4EDTne0h.d.ts → types-CVeLQjhD.d.ts} +1 -1
- package/dist/{types-Ku_ykMzx.d.ts → types-CZdze7Tl.d.ts} +1 -1
- package/dist/{types-D-u5uw1E.d.mts → types-DKrOkBcu.d.mts} +1 -1
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -1228,8 +1228,141 @@ function topologicalSort(schemas) {
|
|
|
1228
1228
|
}
|
|
1229
1229
|
return sorted;
|
|
1230
1230
|
}
|
|
1231
|
-
|
|
1232
|
-
|
|
1231
|
+
var importCache = /* @__PURE__ */ new Map();
|
|
1232
|
+
function parseImportsFromFile(filePath) {
|
|
1233
|
+
if (importCache.has(filePath)) {
|
|
1234
|
+
return importCache.get(filePath);
|
|
1235
|
+
}
|
|
1236
|
+
const imports = /* @__PURE__ */ new Map();
|
|
1237
|
+
try {
|
|
1238
|
+
const content = readFileSync(filePath, "utf-8");
|
|
1239
|
+
const importRegex = /import\s+(?:(?:(\w+)(?:\s*,\s*)?)?(?:\{([^}]+)\})?\s+from\s+)?['"]([^'"]+)['"]/g;
|
|
1240
|
+
let match;
|
|
1241
|
+
while ((match = importRegex.exec(content)) !== null) {
|
|
1242
|
+
const [, defaultImport, namedImports, modulePath] = match;
|
|
1243
|
+
if (defaultImport) {
|
|
1244
|
+
imports.set(defaultImport, modulePath);
|
|
1245
|
+
}
|
|
1246
|
+
if (namedImports) {
|
|
1247
|
+
const names = namedImports.split(",").map((s) => s.trim());
|
|
1248
|
+
for (const name of names) {
|
|
1249
|
+
const asMatch = name.match(/(\w+)\s+as\s+(\w+)/);
|
|
1250
|
+
if (asMatch) {
|
|
1251
|
+
imports.set(asMatch[2], modulePath);
|
|
1252
|
+
} else if (name && /^\w+$/.test(name)) {
|
|
1253
|
+
imports.set(name, modulePath);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
} catch (error) {
|
|
1259
|
+
console.warn(`Warning: Could not parse imports from ${filePath}`);
|
|
1260
|
+
}
|
|
1261
|
+
importCache.set(filePath, imports);
|
|
1262
|
+
return imports;
|
|
1263
|
+
}
|
|
1264
|
+
function detectUsedIdentifiers(functionSource) {
|
|
1265
|
+
const withoutStrings = functionSource.replace(/'[^']*'/g, "").replace(/"[^"]*"/g, "").replace(/`[^`]*`/g, "");
|
|
1266
|
+
const identifiers = /* @__PURE__ */ new Set();
|
|
1267
|
+
const callRegex = /\b([A-Z][a-zA-Z0-9]*|[a-z][a-zA-Z0-9]*)\s*\(/g;
|
|
1268
|
+
let match;
|
|
1269
|
+
while ((match = callRegex.exec(withoutStrings)) !== null) {
|
|
1270
|
+
const name = match[1];
|
|
1271
|
+
if (!isBuiltIn(name) && !isContextProperty(name)) {
|
|
1272
|
+
identifiers.add(name);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
const newRegex = /\bnew\s+([A-Z][a-zA-Z0-9]*)/g;
|
|
1276
|
+
while ((match = newRegex.exec(withoutStrings)) !== null) {
|
|
1277
|
+
const name = match[1];
|
|
1278
|
+
if (!isBuiltIn(name)) {
|
|
1279
|
+
identifiers.add(name);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
const throwRegex = /\bthrow\s+new\s+([A-Z][a-zA-Z0-9]*)/g;
|
|
1283
|
+
while ((match = throwRegex.exec(withoutStrings)) !== null) {
|
|
1284
|
+
identifiers.add(match[1]);
|
|
1285
|
+
}
|
|
1286
|
+
return Array.from(identifiers);
|
|
1287
|
+
}
|
|
1288
|
+
function isBuiltIn(name) {
|
|
1289
|
+
const builtIns = /* @__PURE__ */ new Set([
|
|
1290
|
+
// Functions
|
|
1291
|
+
"console",
|
|
1292
|
+
"JSON",
|
|
1293
|
+
"Object",
|
|
1294
|
+
"Array",
|
|
1295
|
+
"String",
|
|
1296
|
+
"Number",
|
|
1297
|
+
"Boolean",
|
|
1298
|
+
"Date",
|
|
1299
|
+
"Math",
|
|
1300
|
+
"Promise",
|
|
1301
|
+
"Map",
|
|
1302
|
+
"Set",
|
|
1303
|
+
"WeakMap",
|
|
1304
|
+
"WeakSet",
|
|
1305
|
+
"parseInt",
|
|
1306
|
+
"parseFloat",
|
|
1307
|
+
"isNaN",
|
|
1308
|
+
"isFinite",
|
|
1309
|
+
"fetch",
|
|
1310
|
+
"setTimeout",
|
|
1311
|
+
"setInterval",
|
|
1312
|
+
"clearTimeout",
|
|
1313
|
+
"clearInterval",
|
|
1314
|
+
// Errors
|
|
1315
|
+
"Error",
|
|
1316
|
+
"TypeError",
|
|
1317
|
+
"ReferenceError",
|
|
1318
|
+
"SyntaxError",
|
|
1319
|
+
"RangeError",
|
|
1320
|
+
// Common methods that look like function calls
|
|
1321
|
+
"toString",
|
|
1322
|
+
"valueOf",
|
|
1323
|
+
"hasOwnProperty",
|
|
1324
|
+
"length",
|
|
1325
|
+
"push",
|
|
1326
|
+
"pop",
|
|
1327
|
+
"map",
|
|
1328
|
+
"filter",
|
|
1329
|
+
"reduce",
|
|
1330
|
+
"find",
|
|
1331
|
+
"findIndex",
|
|
1332
|
+
"some",
|
|
1333
|
+
"every",
|
|
1334
|
+
"includes",
|
|
1335
|
+
"indexOf",
|
|
1336
|
+
"slice",
|
|
1337
|
+
"splice",
|
|
1338
|
+
"concat",
|
|
1339
|
+
"join",
|
|
1340
|
+
"split"
|
|
1341
|
+
]);
|
|
1342
|
+
return builtIns.has(name);
|
|
1343
|
+
}
|
|
1344
|
+
function isContextProperty(name) {
|
|
1345
|
+
const contextProps = /* @__PURE__ */ new Set([
|
|
1346
|
+
"params",
|
|
1347
|
+
"body",
|
|
1348
|
+
"db",
|
|
1349
|
+
"headers",
|
|
1350
|
+
"ctx",
|
|
1351
|
+
// Common db methods
|
|
1352
|
+
"findMany",
|
|
1353
|
+
"findFirst",
|
|
1354
|
+
"findUnique",
|
|
1355
|
+
"create",
|
|
1356
|
+
"update",
|
|
1357
|
+
"delete",
|
|
1358
|
+
"count",
|
|
1359
|
+
"getAll",
|
|
1360
|
+
"deleteMany",
|
|
1361
|
+
"updateMany",
|
|
1362
|
+
"upsert"
|
|
1363
|
+
]);
|
|
1364
|
+
return contextProps.has(name);
|
|
1365
|
+
}
|
|
1233
1366
|
function analyzeEndpoints(endpoints, endpointFiles) {
|
|
1234
1367
|
return endpoints.map((endpoint) => analyzeEndpoint(endpoint, endpointFiles));
|
|
1235
1368
|
}
|
|
@@ -1241,16 +1374,32 @@ function analyzeEndpoint(endpoint, endpointFiles) {
|
|
|
1241
1374
|
const body = analyzeFields(endpoint.body);
|
|
1242
1375
|
const response = analyzeFields(endpoint.response);
|
|
1243
1376
|
const mockResolverSource = serializeMockResolver(endpoint.mockResolver);
|
|
1377
|
+
const sourceFile = endpointFiles?.get(endpoint.path);
|
|
1244
1378
|
const resolverName = endpoint.mockResolver.name;
|
|
1245
1379
|
const isNamedFunction = resolverName && !resolverName.startsWith("bound ") && resolverName !== "mockResolver";
|
|
1246
1380
|
let mockResolverName;
|
|
1247
1381
|
let mockResolverImportPath;
|
|
1382
|
+
let resolverDependencies;
|
|
1248
1383
|
if (isNamedFunction) {
|
|
1249
1384
|
mockResolverName = resolverName;
|
|
1250
|
-
const sourceFile = endpointFiles?.get(endpoint.path);
|
|
1251
1385
|
if (sourceFile) {
|
|
1252
1386
|
mockResolverImportPath = sourceFile;
|
|
1253
1387
|
}
|
|
1388
|
+
} else if (sourceFile) {
|
|
1389
|
+
const usedIdentifiers = detectUsedIdentifiers(mockResolverSource);
|
|
1390
|
+
if (usedIdentifiers.length > 0) {
|
|
1391
|
+
const fileImports = parseImportsFromFile(sourceFile);
|
|
1392
|
+
const deps = [];
|
|
1393
|
+
for (const identifier of usedIdentifiers) {
|
|
1394
|
+
const importPath = fileImports.get(identifier);
|
|
1395
|
+
if (importPath) {
|
|
1396
|
+
deps.push({ name: identifier, from: importPath });
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
if (deps.length > 0) {
|
|
1400
|
+
resolverDependencies = deps;
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1254
1403
|
}
|
|
1255
1404
|
return {
|
|
1256
1405
|
path: endpoint.path,
|
|
@@ -1264,6 +1413,8 @@ function analyzeEndpoint(endpoint, endpointFiles) {
|
|
|
1264
1413
|
mockResolverSource,
|
|
1265
1414
|
mockResolverName,
|
|
1266
1415
|
mockResolverImportPath,
|
|
1416
|
+
sourceFile,
|
|
1417
|
+
resolverDependencies,
|
|
1267
1418
|
description: endpoint.description
|
|
1268
1419
|
};
|
|
1269
1420
|
}
|
|
@@ -3039,9 +3190,35 @@ function generateEndpointResolvers(endpoints, outputDir) {
|
|
|
3039
3190
|
code.comment("");
|
|
3040
3191
|
code.comment("These resolvers are copied from your defineEndpoint() calls.");
|
|
3041
3192
|
code.comment("They receive { params, body, db, headers } and return the response.");
|
|
3193
|
+
code.comment("");
|
|
3194
|
+
code.comment("NOTE: If your inline resolvers use external functions (e.g., hashPassword, generateToken),");
|
|
3195
|
+
code.comment("consider using named exported functions instead - they will be automatically imported.");
|
|
3196
|
+
code.line();
|
|
3197
|
+
code.line("import type { Database } from './db';");
|
|
3198
|
+
code.line();
|
|
3199
|
+
code.comment("Resolver context with typed database access");
|
|
3200
|
+
code.block("export interface ResolverContext {", () => {
|
|
3201
|
+
code.line("params: Record<string, unknown>;");
|
|
3202
|
+
code.line("body: Record<string, unknown>;");
|
|
3203
|
+
code.line("db: Database;");
|
|
3204
|
+
code.line("headers: Record<string, string>;");
|
|
3205
|
+
});
|
|
3206
|
+
code.line();
|
|
3207
|
+
code.comment("Error class for HTTP errors in resolvers");
|
|
3208
|
+
code.block("export class HttpError extends Error {", () => {
|
|
3209
|
+
code.line("readonly status: number;");
|
|
3210
|
+
code.line("readonly code?: string;");
|
|
3211
|
+
code.line();
|
|
3212
|
+
code.block("constructor(message: string, status: number, code?: string) {", () => {
|
|
3213
|
+
code.line("super(message);");
|
|
3214
|
+
code.line('this.name = "HttpError";');
|
|
3215
|
+
code.line("this.status = status;");
|
|
3216
|
+
code.line("this.code = code;");
|
|
3217
|
+
});
|
|
3218
|
+
});
|
|
3042
3219
|
code.line();
|
|
3043
|
-
code.line("import type { MockResolverContext } from 'schemock/schema';");
|
|
3044
3220
|
const externalResolvers = /* @__PURE__ */ new Map();
|
|
3221
|
+
const inlineDependencies = /* @__PURE__ */ new Map();
|
|
3045
3222
|
for (const endpoint of endpoints) {
|
|
3046
3223
|
if (endpoint.mockResolverName && endpoint.mockResolverImportPath) {
|
|
3047
3224
|
const key = `${endpoint.mockResolverImportPath}:${endpoint.mockResolverName}`;
|
|
@@ -3052,7 +3229,37 @@ function generateEndpointResolvers(endpoints, outputDir) {
|
|
|
3052
3229
|
});
|
|
3053
3230
|
}
|
|
3054
3231
|
}
|
|
3232
|
+
if (endpoint.resolverDependencies) {
|
|
3233
|
+
for (const dep of endpoint.resolverDependencies) {
|
|
3234
|
+
const key = `${dep.from}:${dep.name}`;
|
|
3235
|
+
if (!inlineDependencies.has(key)) {
|
|
3236
|
+
inlineDependencies.set(key, {
|
|
3237
|
+
name: dep.name,
|
|
3238
|
+
importPath: dep.from
|
|
3239
|
+
});
|
|
3240
|
+
}
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3055
3243
|
}
|
|
3244
|
+
const calculateRelativePath = (importPath) => {
|
|
3245
|
+
let relativePath = importPath;
|
|
3246
|
+
if (outputDir) {
|
|
3247
|
+
const toPosix = (p) => p.replace(/\\/g, "/");
|
|
3248
|
+
const from = toPosix(outputDir);
|
|
3249
|
+
const to = toPosix(importPath);
|
|
3250
|
+
const fromParts = from.split("/").filter(Boolean);
|
|
3251
|
+
const toParts = to.split("/").filter(Boolean);
|
|
3252
|
+
while (fromParts.length && toParts.length && fromParts[0] === toParts[0]) {
|
|
3253
|
+
fromParts.shift();
|
|
3254
|
+
toParts.shift();
|
|
3255
|
+
}
|
|
3256
|
+
let rel = "../".repeat(fromParts.length) + toParts.join("/");
|
|
3257
|
+
if (!rel.startsWith(".") && rel !== "") rel = "./" + rel;
|
|
3258
|
+
rel = rel.replace(/\.(ts|js)$/, "");
|
|
3259
|
+
relativePath = rel;
|
|
3260
|
+
}
|
|
3261
|
+
return relativePath;
|
|
3262
|
+
};
|
|
3056
3263
|
if (externalResolvers.size > 0) {
|
|
3057
3264
|
code.line();
|
|
3058
3265
|
code.comment("External resolver imports");
|
|
@@ -3064,27 +3271,29 @@ function generateEndpointResolvers(endpoints, outputDir) {
|
|
|
3064
3271
|
importsByPath.get(importPath).push(name);
|
|
3065
3272
|
}
|
|
3066
3273
|
for (const [importPath, names] of importsByPath) {
|
|
3067
|
-
|
|
3068
|
-
if (outputDir) {
|
|
3069
|
-
const toPosix = (p) => p.replace(/\\/g, "/");
|
|
3070
|
-
const from = toPosix(outputDir);
|
|
3071
|
-
const to = toPosix(importPath);
|
|
3072
|
-
const fromParts = from.split("/").filter(Boolean);
|
|
3073
|
-
const toParts = to.split("/").filter(Boolean);
|
|
3074
|
-
while (fromParts.length && toParts.length && fromParts[0] === toParts[0]) {
|
|
3075
|
-
fromParts.shift();
|
|
3076
|
-
toParts.shift();
|
|
3077
|
-
}
|
|
3078
|
-
let rel = "../".repeat(fromParts.length) + toParts.join("/");
|
|
3079
|
-
if (!rel.startsWith(".") && rel !== "") rel = "./" + rel;
|
|
3080
|
-
rel = rel.replace(/\.(ts|js)$/, "");
|
|
3081
|
-
relativePath = rel;
|
|
3082
|
-
}
|
|
3274
|
+
const relativePath = calculateRelativePath(importPath);
|
|
3083
3275
|
code.line(`import { ${names.join(", ")} } from '${relativePath}';`);
|
|
3084
3276
|
}
|
|
3085
3277
|
}
|
|
3278
|
+
if (inlineDependencies.size > 0) {
|
|
3279
|
+
code.line();
|
|
3280
|
+
code.comment("Dependencies used by inline resolvers");
|
|
3281
|
+
const importsByPath = /* @__PURE__ */ new Map();
|
|
3282
|
+
for (const { name, importPath } of inlineDependencies.values()) {
|
|
3283
|
+
if (!importsByPath.has(importPath)) {
|
|
3284
|
+
importsByPath.set(importPath, []);
|
|
3285
|
+
}
|
|
3286
|
+
const names = importsByPath.get(importPath);
|
|
3287
|
+
if (!names.includes(name)) {
|
|
3288
|
+
names.push(name);
|
|
3289
|
+
}
|
|
3290
|
+
}
|
|
3291
|
+
for (const [importPath, names] of importsByPath) {
|
|
3292
|
+
code.line(`import { ${names.join(", ")} } from '${importPath}';`);
|
|
3293
|
+
}
|
|
3294
|
+
}
|
|
3086
3295
|
code.line();
|
|
3087
|
-
code.line("type ResolverFn = (ctx:
|
|
3296
|
+
code.line("type ResolverFn = (ctx: ResolverContext) => unknown | Promise<unknown>;");
|
|
3088
3297
|
code.line();
|
|
3089
3298
|
code.block("export const endpointResolvers: Record<string, ResolverFn> = {", () => {
|
|
3090
3299
|
for (const endpoint of endpoints) {
|