schemock 0.0.4-alpha.13 → 0.0.4-alpha.15
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 +280 -29
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +280 -29
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli.js +306 -51
- 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
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { A as Adapter, a as AdapterContext, b as AdapterResponse, d as MswjsDataFactory, F as FetchAdapterOptions } from '../types-
|
|
2
|
-
export { c as AdapterResponseMeta, D as Database, M as MockAdapterOptions, S as SchemaRegistry } from '../types-
|
|
3
|
-
import { o as EntitySchema, b as FieldDefinition } from '../types-
|
|
4
|
-
import { M as Middleware } from '../types-
|
|
1
|
+
import { A as Adapter, a as AdapterContext, b as AdapterResponse, d as MswjsDataFactory, F as FetchAdapterOptions } from '../types-BBeKlEd1.mjs';
|
|
2
|
+
export { c as AdapterResponseMeta, D as Database, M as MockAdapterOptions, S as SchemaRegistry } from '../types-BBeKlEd1.mjs';
|
|
3
|
+
import { o as EntitySchema, b as FieldDefinition } from '../types-BCLdZDSF.mjs';
|
|
4
|
+
import { M as Middleware } from '../types-DKrOkBcu.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Storage Driver Types - Abstract storage interface for different backends
|
package/dist/adapters/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { A as Adapter, a as AdapterContext, b as AdapterResponse, d as MswjsDataFactory, F as FetchAdapterOptions } from '../types-
|
|
2
|
-
export { c as AdapterResponseMeta, D as Database, M as MockAdapterOptions, S as SchemaRegistry } from '../types-
|
|
3
|
-
import { o as EntitySchema, b as FieldDefinition } from '../types-
|
|
4
|
-
import { M as Middleware } from '../types-
|
|
1
|
+
import { A as Adapter, a as AdapterContext, b as AdapterResponse, d as MswjsDataFactory, F as FetchAdapterOptions } from '../types-CVeLQjhD.js';
|
|
2
|
+
export { c as AdapterResponseMeta, D as Database, M as MockAdapterOptions, S as SchemaRegistry } from '../types-CVeLQjhD.js';
|
|
3
|
+
import { o as EntitySchema, b as FieldDefinition } from '../types-BCLdZDSF.js';
|
|
4
|
+
import { M as Middleware } from '../types-CZdze7Tl.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Storage Driver Types - Abstract storage interface for different backends
|
package/dist/cli/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { l as RLSScopeMapping, m as RLSBypass, n as RLSConfig, o as EntitySchema, v as EndpointSchema, b as FieldDefinition } from '../types-
|
|
2
|
-
export { I as IndexConfig, j as RLSContext, k as RLSFilter, f as RPCArgument, g as RPCConfig } from '../types-
|
|
1
|
+
import { l as RLSScopeMapping, m as RLSBypass, n as RLSConfig, o as EntitySchema, v as EndpointSchema, b as FieldDefinition } from '../types-BCLdZDSF.mjs';
|
|
2
|
+
export { I as IndexConfig, j as RLSContext, k as RLSFilter, f as RPCArgument, g as RPCConfig } from '../types-BCLdZDSF.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* CLI type definitions for Schemock code generation
|
|
@@ -412,6 +412,17 @@ interface AnalyzedEndpointField {
|
|
|
412
412
|
/** Enum values if enum type */
|
|
413
413
|
enumValues?: string[];
|
|
414
414
|
}
|
|
415
|
+
/**
|
|
416
|
+
* Dependency import for inline resolvers
|
|
417
|
+
*/
|
|
418
|
+
interface ResolverDependency {
|
|
419
|
+
/** Identifier name used in the resolver */
|
|
420
|
+
name: string;
|
|
421
|
+
/** Module path to import from */
|
|
422
|
+
from: string;
|
|
423
|
+
/** Whether it's a default import */
|
|
424
|
+
isDefault?: boolean;
|
|
425
|
+
}
|
|
415
426
|
/**
|
|
416
427
|
* Fully analyzed endpoint with all computed properties
|
|
417
428
|
*/
|
|
@@ -440,6 +451,10 @@ interface AnalyzedEndpoint {
|
|
|
440
451
|
mockResolverImportPath?: string;
|
|
441
452
|
/** Export name in the source file */
|
|
442
453
|
mockResolverExportName?: string;
|
|
454
|
+
/** Source file path where this endpoint is defined */
|
|
455
|
+
sourceFile?: string;
|
|
456
|
+
/** Dependencies detected in inline resolver (functions used but not defined locally) */
|
|
457
|
+
resolverDependencies?: ResolverDependency[];
|
|
443
458
|
/** Description */
|
|
444
459
|
description?: string;
|
|
445
460
|
}
|
|
@@ -1053,4 +1068,4 @@ declare function generateFetchClient(schemas: AnalyzedSchema[], config: FetchAda
|
|
|
1053
1068
|
*/
|
|
1054
1069
|
declare function generateFormSchemas(schemas: AnalyzedSchema[]): string;
|
|
1055
1070
|
|
|
1056
|
-
export { type AnalyzedComputed, type AnalyzedEndpoint, type AnalyzedEndpointField, type AnalyzedField, type AnalyzedIndex, type AnalyzedRLS, type AnalyzedRPC, type AnalyzedRelation, type AnalyzedSchema, type AuthProviderConfig, CodeBuilder, type FakerMapping, type FetchAdapterConfig, type FirebaseAdapterConfig, type FrameworkType, type GenerateOptions, type GenerateSQLOptions, type GenerationTarget, type GraphQLAdapterConfig, type MockAdapterConfig, type PGliteAdapterConfig, type PluralizeConfig, RLSBypass, RLSConfig, RLSScopeMapping, type SQLGeneratorResult, type SchemockConfig, type SupabaseAdapterConfig, type TargetMiddlewareConfig, type TargetType, analyzeSchemas, defineConfig, discoverSchemas, fieldToFakerCall, fieldToTsType, generate, generateClaudeMd, generateCursorRules, generateFetchClient, generateFirebaseClient, generateFormSchemas, generateHooks, generateMockClient, generateMockDb, generateMockHandlers, generateSchemockSection, generateSeed, generateSupabaseClient, generateTypes, getDefaultConfig, getRelativePath, loadConfig, mergeClaudeMdContent, pluralize, primitiveToTs, setupAI, toCamelCase, toPascalCase };
|
|
1071
|
+
export { type AnalyzedComputed, type AnalyzedEndpoint, type AnalyzedEndpointField, type AnalyzedField, type AnalyzedIndex, type AnalyzedRLS, type AnalyzedRPC, type AnalyzedRelation, type AnalyzedSchema, type AuthProviderConfig, CodeBuilder, type FakerMapping, type FetchAdapterConfig, type FirebaseAdapterConfig, type FrameworkType, type GenerateOptions, type GenerateSQLOptions, type GenerationTarget, type GraphQLAdapterConfig, type MockAdapterConfig, type PGliteAdapterConfig, type PluralizeConfig, RLSBypass, RLSConfig, RLSScopeMapping, type ResolverDependency, type SQLGeneratorResult, type SchemockConfig, type SupabaseAdapterConfig, type TargetMiddlewareConfig, type TargetType, analyzeSchemas, defineConfig, discoverSchemas, fieldToFakerCall, fieldToTsType, generate, generateClaudeMd, generateCursorRules, generateFetchClient, generateFirebaseClient, generateFormSchemas, generateHooks, generateMockClient, generateMockDb, generateMockHandlers, generateSchemockSection, generateSeed, generateSupabaseClient, generateTypes, getDefaultConfig, getRelativePath, loadConfig, mergeClaudeMdContent, pluralize, primitiveToTs, setupAI, toCamelCase, toPascalCase };
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { l as RLSScopeMapping, m as RLSBypass, n as RLSConfig, o as EntitySchema, v as EndpointSchema, b as FieldDefinition } from '../types-
|
|
2
|
-
export { I as IndexConfig, j as RLSContext, k as RLSFilter, f as RPCArgument, g as RPCConfig } from '../types-
|
|
1
|
+
import { l as RLSScopeMapping, m as RLSBypass, n as RLSConfig, o as EntitySchema, v as EndpointSchema, b as FieldDefinition } from '../types-BCLdZDSF.js';
|
|
2
|
+
export { I as IndexConfig, j as RLSContext, k as RLSFilter, f as RPCArgument, g as RPCConfig } from '../types-BCLdZDSF.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* CLI type definitions for Schemock code generation
|
|
@@ -412,6 +412,17 @@ interface AnalyzedEndpointField {
|
|
|
412
412
|
/** Enum values if enum type */
|
|
413
413
|
enumValues?: string[];
|
|
414
414
|
}
|
|
415
|
+
/**
|
|
416
|
+
* Dependency import for inline resolvers
|
|
417
|
+
*/
|
|
418
|
+
interface ResolverDependency {
|
|
419
|
+
/** Identifier name used in the resolver */
|
|
420
|
+
name: string;
|
|
421
|
+
/** Module path to import from */
|
|
422
|
+
from: string;
|
|
423
|
+
/** Whether it's a default import */
|
|
424
|
+
isDefault?: boolean;
|
|
425
|
+
}
|
|
415
426
|
/**
|
|
416
427
|
* Fully analyzed endpoint with all computed properties
|
|
417
428
|
*/
|
|
@@ -440,6 +451,10 @@ interface AnalyzedEndpoint {
|
|
|
440
451
|
mockResolverImportPath?: string;
|
|
441
452
|
/** Export name in the source file */
|
|
442
453
|
mockResolverExportName?: string;
|
|
454
|
+
/** Source file path where this endpoint is defined */
|
|
455
|
+
sourceFile?: string;
|
|
456
|
+
/** Dependencies detected in inline resolver (functions used but not defined locally) */
|
|
457
|
+
resolverDependencies?: ResolverDependency[];
|
|
443
458
|
/** Description */
|
|
444
459
|
description?: string;
|
|
445
460
|
}
|
|
@@ -1053,4 +1068,4 @@ declare function generateFetchClient(schemas: AnalyzedSchema[], config: FetchAda
|
|
|
1053
1068
|
*/
|
|
1054
1069
|
declare function generateFormSchemas(schemas: AnalyzedSchema[]): string;
|
|
1055
1070
|
|
|
1056
|
-
export { type AnalyzedComputed, type AnalyzedEndpoint, type AnalyzedEndpointField, type AnalyzedField, type AnalyzedIndex, type AnalyzedRLS, type AnalyzedRPC, type AnalyzedRelation, type AnalyzedSchema, type AuthProviderConfig, CodeBuilder, type FakerMapping, type FetchAdapterConfig, type FirebaseAdapterConfig, type FrameworkType, type GenerateOptions, type GenerateSQLOptions, type GenerationTarget, type GraphQLAdapterConfig, type MockAdapterConfig, type PGliteAdapterConfig, type PluralizeConfig, RLSBypass, RLSConfig, RLSScopeMapping, type SQLGeneratorResult, type SchemockConfig, type SupabaseAdapterConfig, type TargetMiddlewareConfig, type TargetType, analyzeSchemas, defineConfig, discoverSchemas, fieldToFakerCall, fieldToTsType, generate, generateClaudeMd, generateCursorRules, generateFetchClient, generateFirebaseClient, generateFormSchemas, generateHooks, generateMockClient, generateMockDb, generateMockHandlers, generateSchemockSection, generateSeed, generateSupabaseClient, generateTypes, getDefaultConfig, getRelativePath, loadConfig, mergeClaudeMdContent, pluralize, primitiveToTs, setupAI, toCamelCase, toPascalCase };
|
|
1071
|
+
export { type AnalyzedComputed, type AnalyzedEndpoint, type AnalyzedEndpointField, type AnalyzedField, type AnalyzedIndex, type AnalyzedRLS, type AnalyzedRPC, type AnalyzedRelation, type AnalyzedSchema, type AuthProviderConfig, CodeBuilder, type FakerMapping, type FetchAdapterConfig, type FirebaseAdapterConfig, type FrameworkType, type GenerateOptions, type GenerateSQLOptions, type GenerationTarget, type GraphQLAdapterConfig, type MockAdapterConfig, type PGliteAdapterConfig, type PluralizeConfig, RLSBypass, RLSConfig, RLSScopeMapping, type ResolverDependency, type SQLGeneratorResult, type SchemockConfig, type SupabaseAdapterConfig, type TargetMiddlewareConfig, type TargetType, analyzeSchemas, defineConfig, discoverSchemas, fieldToFakerCall, fieldToTsType, generate, generateClaudeMd, generateCursorRules, generateFetchClient, generateFirebaseClient, generateFormSchemas, generateHooks, generateMockClient, generateMockDb, generateMockHandlers, generateSchemockSection, generateSeed, generateSupabaseClient, generateTypes, getDefaultConfig, getRelativePath, loadConfig, mergeClaudeMdContent, pluralize, primitiveToTs, setupAI, toCamelCase, toPascalCase };
|
package/dist/cli/index.js
CHANGED
|
@@ -1230,8 +1230,141 @@ function topologicalSort(schemas) {
|
|
|
1230
1230
|
}
|
|
1231
1231
|
return sorted;
|
|
1232
1232
|
}
|
|
1233
|
-
|
|
1234
|
-
|
|
1233
|
+
var importCache = /* @__PURE__ */ new Map();
|
|
1234
|
+
function parseImportsFromFile(filePath) {
|
|
1235
|
+
if (importCache.has(filePath)) {
|
|
1236
|
+
return importCache.get(filePath);
|
|
1237
|
+
}
|
|
1238
|
+
const imports = /* @__PURE__ */ new Map();
|
|
1239
|
+
try {
|
|
1240
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
1241
|
+
const importRegex = /import\s+(?:(?:(\w+)(?:\s*,\s*)?)?(?:\{([^}]+)\})?\s+from\s+)?['"]([^'"]+)['"]/g;
|
|
1242
|
+
let match;
|
|
1243
|
+
while ((match = importRegex.exec(content)) !== null) {
|
|
1244
|
+
const [, defaultImport, namedImports, modulePath] = match;
|
|
1245
|
+
if (defaultImport) {
|
|
1246
|
+
imports.set(defaultImport, modulePath);
|
|
1247
|
+
}
|
|
1248
|
+
if (namedImports) {
|
|
1249
|
+
const names = namedImports.split(",").map((s) => s.trim());
|
|
1250
|
+
for (const name of names) {
|
|
1251
|
+
const asMatch = name.match(/(\w+)\s+as\s+(\w+)/);
|
|
1252
|
+
if (asMatch) {
|
|
1253
|
+
imports.set(asMatch[2], modulePath);
|
|
1254
|
+
} else if (name && /^\w+$/.test(name)) {
|
|
1255
|
+
imports.set(name, modulePath);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
} catch (error) {
|
|
1261
|
+
console.warn(`Warning: Could not parse imports from ${filePath}`);
|
|
1262
|
+
}
|
|
1263
|
+
importCache.set(filePath, imports);
|
|
1264
|
+
return imports;
|
|
1265
|
+
}
|
|
1266
|
+
function detectUsedIdentifiers(functionSource) {
|
|
1267
|
+
const withoutStrings = functionSource.replace(/'[^']*'/g, "").replace(/"[^"]*"/g, "").replace(/`[^`]*`/g, "");
|
|
1268
|
+
const identifiers = /* @__PURE__ */ new Set();
|
|
1269
|
+
const callRegex = /\b([A-Z][a-zA-Z0-9]*|[a-z][a-zA-Z0-9]*)\s*\(/g;
|
|
1270
|
+
let match;
|
|
1271
|
+
while ((match = callRegex.exec(withoutStrings)) !== null) {
|
|
1272
|
+
const name = match[1];
|
|
1273
|
+
if (!isBuiltIn(name) && !isContextProperty(name)) {
|
|
1274
|
+
identifiers.add(name);
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
const newRegex = /\bnew\s+([A-Z][a-zA-Z0-9]*)/g;
|
|
1278
|
+
while ((match = newRegex.exec(withoutStrings)) !== null) {
|
|
1279
|
+
const name = match[1];
|
|
1280
|
+
if (!isBuiltIn(name)) {
|
|
1281
|
+
identifiers.add(name);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
const throwRegex = /\bthrow\s+new\s+([A-Z][a-zA-Z0-9]*)/g;
|
|
1285
|
+
while ((match = throwRegex.exec(withoutStrings)) !== null) {
|
|
1286
|
+
identifiers.add(match[1]);
|
|
1287
|
+
}
|
|
1288
|
+
return Array.from(identifiers);
|
|
1289
|
+
}
|
|
1290
|
+
function isBuiltIn(name) {
|
|
1291
|
+
const builtIns = /* @__PURE__ */ new Set([
|
|
1292
|
+
// Functions
|
|
1293
|
+
"console",
|
|
1294
|
+
"JSON",
|
|
1295
|
+
"Object",
|
|
1296
|
+
"Array",
|
|
1297
|
+
"String",
|
|
1298
|
+
"Number",
|
|
1299
|
+
"Boolean",
|
|
1300
|
+
"Date",
|
|
1301
|
+
"Math",
|
|
1302
|
+
"Promise",
|
|
1303
|
+
"Map",
|
|
1304
|
+
"Set",
|
|
1305
|
+
"WeakMap",
|
|
1306
|
+
"WeakSet",
|
|
1307
|
+
"parseInt",
|
|
1308
|
+
"parseFloat",
|
|
1309
|
+
"isNaN",
|
|
1310
|
+
"isFinite",
|
|
1311
|
+
"fetch",
|
|
1312
|
+
"setTimeout",
|
|
1313
|
+
"setInterval",
|
|
1314
|
+
"clearTimeout",
|
|
1315
|
+
"clearInterval",
|
|
1316
|
+
// Errors
|
|
1317
|
+
"Error",
|
|
1318
|
+
"TypeError",
|
|
1319
|
+
"ReferenceError",
|
|
1320
|
+
"SyntaxError",
|
|
1321
|
+
"RangeError",
|
|
1322
|
+
// Common methods that look like function calls
|
|
1323
|
+
"toString",
|
|
1324
|
+
"valueOf",
|
|
1325
|
+
"hasOwnProperty",
|
|
1326
|
+
"length",
|
|
1327
|
+
"push",
|
|
1328
|
+
"pop",
|
|
1329
|
+
"map",
|
|
1330
|
+
"filter",
|
|
1331
|
+
"reduce",
|
|
1332
|
+
"find",
|
|
1333
|
+
"findIndex",
|
|
1334
|
+
"some",
|
|
1335
|
+
"every",
|
|
1336
|
+
"includes",
|
|
1337
|
+
"indexOf",
|
|
1338
|
+
"slice",
|
|
1339
|
+
"splice",
|
|
1340
|
+
"concat",
|
|
1341
|
+
"join",
|
|
1342
|
+
"split"
|
|
1343
|
+
]);
|
|
1344
|
+
return builtIns.has(name);
|
|
1345
|
+
}
|
|
1346
|
+
function isContextProperty(name) {
|
|
1347
|
+
const contextProps = /* @__PURE__ */ new Set([
|
|
1348
|
+
"params",
|
|
1349
|
+
"body",
|
|
1350
|
+
"db",
|
|
1351
|
+
"headers",
|
|
1352
|
+
"ctx",
|
|
1353
|
+
// Common db methods
|
|
1354
|
+
"findMany",
|
|
1355
|
+
"findFirst",
|
|
1356
|
+
"findUnique",
|
|
1357
|
+
"create",
|
|
1358
|
+
"update",
|
|
1359
|
+
"delete",
|
|
1360
|
+
"count",
|
|
1361
|
+
"getAll",
|
|
1362
|
+
"deleteMany",
|
|
1363
|
+
"updateMany",
|
|
1364
|
+
"upsert"
|
|
1365
|
+
]);
|
|
1366
|
+
return contextProps.has(name);
|
|
1367
|
+
}
|
|
1235
1368
|
function analyzeEndpoints(endpoints, endpointFiles) {
|
|
1236
1369
|
return endpoints.map((endpoint) => analyzeEndpoint(endpoint, endpointFiles));
|
|
1237
1370
|
}
|
|
@@ -1243,16 +1376,32 @@ function analyzeEndpoint(endpoint, endpointFiles) {
|
|
|
1243
1376
|
const body = analyzeFields(endpoint.body);
|
|
1244
1377
|
const response = analyzeFields(endpoint.response);
|
|
1245
1378
|
const mockResolverSource = serializeMockResolver(endpoint.mockResolver);
|
|
1379
|
+
const sourceFile = endpointFiles?.get(endpoint.path);
|
|
1246
1380
|
const resolverName = endpoint.mockResolver.name;
|
|
1247
1381
|
const isNamedFunction = resolverName && !resolverName.startsWith("bound ") && resolverName !== "mockResolver";
|
|
1248
1382
|
let mockResolverName;
|
|
1249
1383
|
let mockResolverImportPath;
|
|
1384
|
+
let resolverDependencies;
|
|
1250
1385
|
if (isNamedFunction) {
|
|
1251
1386
|
mockResolverName = resolverName;
|
|
1252
|
-
const sourceFile = endpointFiles?.get(endpoint.path);
|
|
1253
1387
|
if (sourceFile) {
|
|
1254
1388
|
mockResolverImportPath = sourceFile;
|
|
1255
1389
|
}
|
|
1390
|
+
} else if (sourceFile) {
|
|
1391
|
+
const usedIdentifiers = detectUsedIdentifiers(mockResolverSource);
|
|
1392
|
+
if (usedIdentifiers.length > 0) {
|
|
1393
|
+
const fileImports = parseImportsFromFile(sourceFile);
|
|
1394
|
+
const deps = [];
|
|
1395
|
+
for (const identifier of usedIdentifiers) {
|
|
1396
|
+
const importPath = fileImports.get(identifier);
|
|
1397
|
+
if (importPath) {
|
|
1398
|
+
deps.push({ name: identifier, from: importPath });
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
if (deps.length > 0) {
|
|
1402
|
+
resolverDependencies = deps;
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1256
1405
|
}
|
|
1257
1406
|
return {
|
|
1258
1407
|
path: endpoint.path,
|
|
@@ -1266,6 +1415,8 @@ function analyzeEndpoint(endpoint, endpointFiles) {
|
|
|
1266
1415
|
mockResolverSource,
|
|
1267
1416
|
mockResolverName,
|
|
1268
1417
|
mockResolverImportPath,
|
|
1418
|
+
sourceFile,
|
|
1419
|
+
resolverDependencies,
|
|
1269
1420
|
description: endpoint.description
|
|
1270
1421
|
};
|
|
1271
1422
|
}
|
|
@@ -2967,6 +3118,7 @@ function generateEndpointHandlers(endpoints) {
|
|
|
2967
3118
|
function generateHandler(code, endpoint) {
|
|
2968
3119
|
const { name, method, path, params, body, pathParams } = endpoint;
|
|
2969
3120
|
const httpMethod = method.toLowerCase();
|
|
3121
|
+
const hasBody = body.length > 0;
|
|
2970
3122
|
code.comment(`${method} ${path}`);
|
|
2971
3123
|
code.block(`http.${httpMethod}('${path}', async ({ request, params: pathParams }) => {`, () => {
|
|
2972
3124
|
if (method === "GET" && params.length > 0) {
|
|
@@ -2988,20 +3140,21 @@ function generateHandler(code, endpoint) {
|
|
|
2988
3140
|
}
|
|
2989
3141
|
}, "};");
|
|
2990
3142
|
code.line();
|
|
3143
|
+
} else {
|
|
3144
|
+
code.line("const params = {};");
|
|
3145
|
+
code.line();
|
|
2991
3146
|
}
|
|
2992
|
-
if (
|
|
3147
|
+
if (hasBody) {
|
|
2993
3148
|
code.line("const body = await request.json();");
|
|
2994
|
-
|
|
3149
|
+
} else {
|
|
3150
|
+
code.line("const body = {};");
|
|
2995
3151
|
}
|
|
2996
|
-
|
|
2997
|
-
if (params.length > 0 || pathParams.length > 0) ctxParts.push("params");
|
|
2998
|
-
if (body.length > 0) ctxParts.push("body");
|
|
3152
|
+
code.line();
|
|
2999
3153
|
code.line("const headers: Record<string, string> = {};");
|
|
3000
3154
|
code.line("request.headers.forEach((value, key) => { headers[key] = value; });");
|
|
3001
|
-
ctxParts.push("headers");
|
|
3002
3155
|
code.line();
|
|
3003
3156
|
code.block("try {", () => {
|
|
3004
|
-
code.line(`const result = await endpointResolvers.${name}({
|
|
3157
|
+
code.line(`const result = await endpointResolvers.${name}({ db, params, body, headers });`);
|
|
3005
3158
|
code.line("return HttpResponse.json(result);");
|
|
3006
3159
|
}, "} catch (error) {");
|
|
3007
3160
|
code.indent();
|
|
@@ -3041,9 +3194,44 @@ function generateEndpointResolvers(endpoints, outputDir) {
|
|
|
3041
3194
|
code.comment("");
|
|
3042
3195
|
code.comment("These resolvers are copied from your defineEndpoint() calls.");
|
|
3043
3196
|
code.comment("They receive { params, body, db, headers } and return the response.");
|
|
3197
|
+
code.comment("");
|
|
3198
|
+
code.comment("NOTE: If your inline resolvers use external functions (e.g., hashPassword, generateToken),");
|
|
3199
|
+
code.comment("consider using named exported functions instead - they will be automatically imported.");
|
|
3200
|
+
code.line();
|
|
3201
|
+
code.line("import type { Database } from './db';");
|
|
3202
|
+
code.line("import type * as Types from './types';");
|
|
3203
|
+
code.line();
|
|
3204
|
+
code.comment("Base resolver context with typed database access");
|
|
3205
|
+
code.block("export interface ResolverContext<TParams = Record<string, unknown>, TBody = Record<string, unknown>> {", () => {
|
|
3206
|
+
code.line("params: TParams;");
|
|
3207
|
+
code.line("body: TBody;");
|
|
3208
|
+
code.line("db: Database;");
|
|
3209
|
+
code.line("headers: Record<string, string>;");
|
|
3210
|
+
});
|
|
3211
|
+
code.line();
|
|
3212
|
+
code.comment("Per-endpoint typed resolver contexts");
|
|
3213
|
+
for (const endpoint of endpoints) {
|
|
3214
|
+
const { pascalName, params, body } = endpoint;
|
|
3215
|
+
const paramsType = params.length > 0 ? `Types.${pascalName}Params` : "Record<string, never>";
|
|
3216
|
+
const bodyType = body.length > 0 ? `Types.${pascalName}Body` : "Record<string, never>";
|
|
3217
|
+
code.line(`export type ${pascalName}ResolverContext = ResolverContext<${paramsType}, ${bodyType}>;`);
|
|
3218
|
+
}
|
|
3219
|
+
code.line();
|
|
3220
|
+
code.comment("Error class for HTTP errors in resolvers");
|
|
3221
|
+
code.block("export class HttpError extends Error {", () => {
|
|
3222
|
+
code.line("readonly status: number;");
|
|
3223
|
+
code.line("readonly code?: string;");
|
|
3224
|
+
code.line();
|
|
3225
|
+
code.block("constructor(message: string, status: number, code?: string) {", () => {
|
|
3226
|
+
code.line("super(message);");
|
|
3227
|
+
code.line('this.name = "HttpError";');
|
|
3228
|
+
code.line("this.status = status;");
|
|
3229
|
+
code.line("this.code = code;");
|
|
3230
|
+
});
|
|
3231
|
+
});
|
|
3044
3232
|
code.line();
|
|
3045
|
-
code.line("import type { MockResolverContext } from 'schemock/schema';");
|
|
3046
3233
|
const externalResolvers = /* @__PURE__ */ new Map();
|
|
3234
|
+
const inlineDependencies = /* @__PURE__ */ new Map();
|
|
3047
3235
|
for (const endpoint of endpoints) {
|
|
3048
3236
|
if (endpoint.mockResolverName && endpoint.mockResolverImportPath) {
|
|
3049
3237
|
const key = `${endpoint.mockResolverImportPath}:${endpoint.mockResolverName}`;
|
|
@@ -3054,7 +3242,38 @@ function generateEndpointResolvers(endpoints, outputDir) {
|
|
|
3054
3242
|
});
|
|
3055
3243
|
}
|
|
3056
3244
|
}
|
|
3245
|
+
if (endpoint.resolverDependencies) {
|
|
3246
|
+
for (const dep of endpoint.resolverDependencies) {
|
|
3247
|
+
const key = `${dep.from}:${dep.name}`;
|
|
3248
|
+
if (!inlineDependencies.has(key)) {
|
|
3249
|
+
inlineDependencies.set(key, {
|
|
3250
|
+
name: dep.name,
|
|
3251
|
+
importPath: dep.from,
|
|
3252
|
+
sourceFile: endpoint.sourceFile
|
|
3253
|
+
});
|
|
3254
|
+
}
|
|
3255
|
+
}
|
|
3256
|
+
}
|
|
3057
3257
|
}
|
|
3258
|
+
const calculateRelativePath = (importPath) => {
|
|
3259
|
+
let relativePath = importPath;
|
|
3260
|
+
if (outputDir) {
|
|
3261
|
+
const toPosix = (p) => p.replace(/\\/g, "/");
|
|
3262
|
+
const from = toPosix(outputDir);
|
|
3263
|
+
const to = toPosix(importPath);
|
|
3264
|
+
const fromParts = from.split("/").filter(Boolean);
|
|
3265
|
+
const toParts = to.split("/").filter(Boolean);
|
|
3266
|
+
while (fromParts.length && toParts.length && fromParts[0] === toParts[0]) {
|
|
3267
|
+
fromParts.shift();
|
|
3268
|
+
toParts.shift();
|
|
3269
|
+
}
|
|
3270
|
+
let rel = "../".repeat(fromParts.length) + toParts.join("/");
|
|
3271
|
+
if (!rel.startsWith(".") && rel !== "") rel = "./" + rel;
|
|
3272
|
+
rel = rel.replace(/\.(ts|js)$/, "");
|
|
3273
|
+
relativePath = rel;
|
|
3274
|
+
}
|
|
3275
|
+
return relativePath;
|
|
3276
|
+
};
|
|
3058
3277
|
if (externalResolvers.size > 0) {
|
|
3059
3278
|
code.line();
|
|
3060
3279
|
code.comment("External resolver imports");
|
|
@@ -3066,38 +3285,70 @@ function generateEndpointResolvers(endpoints, outputDir) {
|
|
|
3066
3285
|
importsByPath.get(importPath).push(name);
|
|
3067
3286
|
}
|
|
3068
3287
|
for (const [importPath, names] of importsByPath) {
|
|
3069
|
-
|
|
3070
|
-
|
|
3288
|
+
const relativePath = calculateRelativePath(importPath);
|
|
3289
|
+
code.line(`import { ${names.join(", ")} } from '${relativePath}';`);
|
|
3290
|
+
}
|
|
3291
|
+
}
|
|
3292
|
+
if (inlineDependencies.size > 0) {
|
|
3293
|
+
code.line();
|
|
3294
|
+
code.comment("Dependencies used by inline resolvers");
|
|
3295
|
+
const importsByResolvedPath = /* @__PURE__ */ new Map();
|
|
3296
|
+
for (const { name, importPath, sourceFile } of inlineDependencies.values()) {
|
|
3297
|
+
let resolvedPath = importPath;
|
|
3298
|
+
if (importPath.startsWith(".") && sourceFile && outputDir) {
|
|
3071
3299
|
const toPosix = (p) => p.replace(/\\/g, "/");
|
|
3072
|
-
const
|
|
3073
|
-
const
|
|
3074
|
-
const
|
|
3075
|
-
const
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3300
|
+
const sourceDir = toPosix(sourceFile).replace(/\/[^/]+$/, "");
|
|
3301
|
+
const parts = sourceDir.split("/").filter(Boolean);
|
|
3302
|
+
const importParts = importPath.split("/");
|
|
3303
|
+
for (const part of importParts) {
|
|
3304
|
+
if (part === "..") {
|
|
3305
|
+
parts.pop();
|
|
3306
|
+
} else if (part !== ".") {
|
|
3307
|
+
parts.push(part);
|
|
3308
|
+
}
|
|
3079
3309
|
}
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
rel = rel.replace(/\.(ts|js)$/, "");
|
|
3083
|
-
relativePath = rel;
|
|
3310
|
+
const absolutePath = "/" + parts.join("/");
|
|
3311
|
+
resolvedPath = calculateRelativePath(absolutePath);
|
|
3084
3312
|
}
|
|
3085
|
-
|
|
3313
|
+
if (!importsByResolvedPath.has(resolvedPath)) {
|
|
3314
|
+
importsByResolvedPath.set(resolvedPath, []);
|
|
3315
|
+
}
|
|
3316
|
+
const names = importsByResolvedPath.get(resolvedPath);
|
|
3317
|
+
if (!names.includes(name)) {
|
|
3318
|
+
names.push(name);
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
for (const [resolvedPath, names] of importsByResolvedPath) {
|
|
3322
|
+
code.line(`import { ${names.join(", ")} } from '${resolvedPath}';`);
|
|
3086
3323
|
}
|
|
3087
3324
|
}
|
|
3088
3325
|
code.line();
|
|
3089
|
-
code.
|
|
3326
|
+
code.comment("Typed resolver function types");
|
|
3327
|
+
for (const endpoint of endpoints) {
|
|
3328
|
+
const { pascalName } = endpoint;
|
|
3329
|
+
code.line(
|
|
3330
|
+
`type ${pascalName}ResolverFn = (ctx: ${pascalName}ResolverContext) => Types.${pascalName}Response | Promise<Types.${pascalName}Response>;`
|
|
3331
|
+
);
|
|
3332
|
+
}
|
|
3333
|
+
code.line();
|
|
3334
|
+
code.comment("Typed endpoint resolvers interface");
|
|
3335
|
+
code.block("export interface EndpointResolvers {", () => {
|
|
3336
|
+
for (const endpoint of endpoints) {
|
|
3337
|
+
const { name, pascalName } = endpoint;
|
|
3338
|
+
code.line(`${name}: ${pascalName}ResolverFn;`);
|
|
3339
|
+
}
|
|
3340
|
+
});
|
|
3090
3341
|
code.line();
|
|
3091
|
-
code.block("export const endpointResolvers:
|
|
3342
|
+
code.block("export const endpointResolvers: EndpointResolvers = {", () => {
|
|
3092
3343
|
for (const endpoint of endpoints) {
|
|
3093
3344
|
code.comment(`${endpoint.method} ${endpoint.path}`);
|
|
3094
3345
|
if (endpoint.description) {
|
|
3095
3346
|
code.comment(endpoint.description);
|
|
3096
3347
|
}
|
|
3097
3348
|
if (endpoint.mockResolverName) {
|
|
3098
|
-
code.line(`${endpoint.name}: ${endpoint.mockResolverName},`);
|
|
3349
|
+
code.line(`${endpoint.name}: ${endpoint.mockResolverName} as ${endpoint.pascalName}ResolverFn,`);
|
|
3099
3350
|
} else {
|
|
3100
|
-
code.line(`${endpoint.name}: ${endpoint.mockResolverSource},`);
|
|
3351
|
+
code.line(`${endpoint.name}: ${endpoint.mockResolverSource} as ${endpoint.pascalName}ResolverFn,`);
|
|
3101
3352
|
}
|
|
3102
3353
|
code.line();
|
|
3103
3354
|
}
|