@contractspec/lib.source-extractors 2.7.6 → 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 +58 -76
- package/dist/browser/codegen/index.js +36 -36
- package/dist/browser/extractors/index.js +167 -167
- package/dist/browser/index.js +203 -203
- package/dist/codegen/index.d.ts +1 -1
- package/dist/codegen/index.js +36 -36
- package/dist/codegen/schema-gen.d.ts +1 -1
- package/dist/extractors/index.d.ts +4 -4
- package/dist/extractors/index.js +167 -167
- package/dist/index.d.ts +3 -3
- package/dist/index.js +203 -203
- package/dist/node/codegen/index.js +36 -36
- package/dist/node/extractors/index.js +167 -167
- package/dist/node/index.js +203 -203
- package/package.json +4 -4
|
@@ -317,101 +317,54 @@ class BaseExtractor {
|
|
|
317
317
|
ctx.ir.schemas.push(schema);
|
|
318
318
|
}
|
|
319
319
|
}
|
|
320
|
-
// src/extractors/
|
|
320
|
+
// src/extractors/elysia/extractor.ts
|
|
321
321
|
var PATTERNS = {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
body: /@Body\s*\(\s*\)/g,
|
|
325
|
-
param: /@Param\s*\(\s*(?:['"`]([^'"`]*)['"`])?\s*\)/g,
|
|
326
|
-
query: /@Query\s*\(\s*(?:['"`]([^'"`]*)['"`])?\s*\)/g,
|
|
327
|
-
dto: /class\s+(\w+(?:Dto|DTO|Request|Response|Input|Output))\s*\{/g,
|
|
328
|
-
classValidator: /@(IsString|IsNumber|IsBoolean|IsArray|IsOptional|IsNotEmpty|Min|Max|Length|Matches)/g
|
|
322
|
+
route: /\.(get|post|put|patch|delete)\s*\(\s*['"`]([^'"`]+)['"`]/gi,
|
|
323
|
+
tSchema: /body:\s*t\.\w+/g
|
|
329
324
|
};
|
|
330
325
|
|
|
331
|
-
class
|
|
332
|
-
id = "
|
|
333
|
-
name = "
|
|
334
|
-
frameworks = ["
|
|
335
|
-
priority =
|
|
326
|
+
class ElysiaExtractor extends BaseExtractor {
|
|
327
|
+
id = "elysia";
|
|
328
|
+
name = "Elysia Extractor";
|
|
329
|
+
frameworks = ["elysia"];
|
|
330
|
+
priority = 15;
|
|
336
331
|
async doExtract(ctx) {
|
|
337
332
|
const { project, options, fs } = ctx;
|
|
338
333
|
const pattern = options.scope?.length ? options.scope.map((s) => `${s}/**/*.ts`).join(",") : "**/*.ts";
|
|
339
334
|
const files = await fs.glob(pattern, { cwd: project.rootPath });
|
|
340
335
|
ctx.ir.stats.filesScanned = files.length;
|
|
341
336
|
for (const file of files) {
|
|
342
|
-
if (file.includes("node_modules") || file.includes(".
|
|
337
|
+
if (file.includes("node_modules") || file.includes(".test."))
|
|
343
338
|
continue;
|
|
344
|
-
}
|
|
345
339
|
const fullPath = `${project.rootPath}/${file}`;
|
|
346
340
|
const content = await fs.readFile(fullPath);
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
}
|
|
351
|
-
async extractControllers(ctx, file, content) {
|
|
352
|
-
const controllerMatches = [...content.matchAll(PATTERNS.controller)];
|
|
353
|
-
for (const controllerMatch of controllerMatches) {
|
|
354
|
-
const basePath = controllerMatch[1] || "";
|
|
355
|
-
const controllerIndex = controllerMatch.index ?? 0;
|
|
356
|
-
const afterDecorator = content.slice(controllerIndex);
|
|
357
|
-
const classMatch = afterDecorator.match(/class\s+(\w+)/);
|
|
358
|
-
const controllerName = classMatch?.[1] ?? "UnknownController";
|
|
359
|
-
const nextController = content.indexOf("@Controller", controllerIndex + 1);
|
|
360
|
-
const controllerBlock = nextController > 0 ? content.slice(controllerIndex, nextController) : content.slice(controllerIndex);
|
|
361
|
-
const routeMatches = [...controllerBlock.matchAll(PATTERNS.route)];
|
|
362
|
-
for (const routeMatch of routeMatches) {
|
|
363
|
-
const method = routeMatch[1]?.toUpperCase();
|
|
364
|
-
const routePath = routeMatch[2] || "";
|
|
365
|
-
const fullPath = this.normalizePath(`/${basePath}/${routePath}`);
|
|
366
|
-
const afterRoute = controllerBlock.slice(routeMatch.index ?? 0);
|
|
367
|
-
const methodMatch = afterRoute.match(/(?:async\s+)?(\w+)\s*\([^)]*\)\s*(?::\s*\w+(?:<[^>]+>)?)?\s*\{/);
|
|
368
|
-
const handlerName = methodMatch?.[1] ?? "unknownHandler";
|
|
369
|
-
const absoluteIndex = controllerIndex + (routeMatch.index ?? 0);
|
|
370
|
-
const lineNumber = content.slice(0, absoluteIndex).split(`
|
|
371
|
-
`).length;
|
|
372
|
-
const hasBody = PATTERNS.body.test(afterRoute.slice(0, 200));
|
|
373
|
-
const hasParams = PATTERNS.param.test(afterRoute.slice(0, 200));
|
|
374
|
-
const hasQuery = PATTERNS.query.test(afterRoute.slice(0, 200));
|
|
375
|
-
const endpoint = {
|
|
376
|
-
id: this.generateEndpointId(method, fullPath, handlerName),
|
|
377
|
-
method,
|
|
378
|
-
path: fullPath,
|
|
379
|
-
kind: this.methodToOpKind(method),
|
|
380
|
-
handlerName,
|
|
381
|
-
controllerName,
|
|
382
|
-
source: this.createLocation(file, lineNumber, lineNumber + 10),
|
|
383
|
-
confidence: this.createConfidence("medium", "decorator-hints"),
|
|
384
|
-
frameworkMeta: {
|
|
385
|
-
hasBody,
|
|
386
|
-
hasParams,
|
|
387
|
-
hasQuery
|
|
388
|
-
}
|
|
389
|
-
};
|
|
390
|
-
this.addEndpoint(ctx, endpoint);
|
|
391
|
-
}
|
|
341
|
+
if (!content.includes("elysia"))
|
|
342
|
+
continue;
|
|
343
|
+
await this.extractRoutes(ctx, file, content);
|
|
392
344
|
}
|
|
393
345
|
}
|
|
394
|
-
async
|
|
395
|
-
const
|
|
396
|
-
for (const match of
|
|
397
|
-
const
|
|
346
|
+
async extractRoutes(ctx, file, content) {
|
|
347
|
+
const matches = [...content.matchAll(PATTERNS.route)];
|
|
348
|
+
for (const match of matches) {
|
|
349
|
+
const method = match[1]?.toUpperCase() ?? "GET";
|
|
350
|
+
const path = match[2] ?? "/";
|
|
398
351
|
const index = match.index ?? 0;
|
|
399
352
|
const lineNumber = content.slice(0, index).split(`
|
|
400
353
|
`).length;
|
|
401
|
-
const
|
|
402
|
-
const
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
354
|
+
const afterMatch = content.slice(index, index + 500);
|
|
355
|
+
const hasTSchema = PATTERNS.tSchema.test(afterMatch);
|
|
356
|
+
const endpoint = {
|
|
357
|
+
id: this.generateEndpointId(method, path),
|
|
358
|
+
method,
|
|
359
|
+
path,
|
|
360
|
+
kind: this.methodToOpKind(method),
|
|
361
|
+
handlerName: "handler",
|
|
362
|
+
source: this.createLocation(file, lineNumber, lineNumber + 5),
|
|
363
|
+
confidence: this.createConfidence(hasTSchema ? "high" : "medium", hasTSchema ? "explicit-schema" : "decorator-hints")
|
|
408
364
|
};
|
|
409
|
-
this.
|
|
365
|
+
this.addEndpoint(ctx, endpoint);
|
|
410
366
|
}
|
|
411
367
|
}
|
|
412
|
-
normalizePath(path) {
|
|
413
|
-
return "/" + path.replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "");
|
|
414
|
-
}
|
|
415
368
|
}
|
|
416
369
|
// src/extractors/express/extractor.ts
|
|
417
370
|
var PATTERNS2 = {
|
|
@@ -560,119 +513,104 @@ class HonoExtractor extends BaseExtractor {
|
|
|
560
513
|
}
|
|
561
514
|
}
|
|
562
515
|
}
|
|
563
|
-
// src/extractors/
|
|
516
|
+
// src/extractors/nestjs/extractor.ts
|
|
564
517
|
var PATTERNS5 = {
|
|
565
|
-
|
|
566
|
-
|
|
518
|
+
controller: /@Controller\s*\(\s*['"`]([^'"`]*)['"`]\s*\)/g,
|
|
519
|
+
route: /@(Get|Post|Put|Patch|Delete|Head|Options)\s*\(\s*(?:['"`]([^'"`]*)['"`])?\s*\)/g,
|
|
520
|
+
body: /@Body\s*\(\s*\)/g,
|
|
521
|
+
param: /@Param\s*\(\s*(?:['"`]([^'"`]*)['"`])?\s*\)/g,
|
|
522
|
+
query: /@Query\s*\(\s*(?:['"`]([^'"`]*)['"`])?\s*\)/g,
|
|
523
|
+
dto: /class\s+(\w+(?:Dto|DTO|Request|Response|Input|Output))\s*\{/g,
|
|
524
|
+
classValidator: /@(IsString|IsNumber|IsBoolean|IsArray|IsOptional|IsNotEmpty|Min|Max|Length|Matches)/g
|
|
567
525
|
};
|
|
568
526
|
|
|
569
|
-
class
|
|
570
|
-
id = "
|
|
571
|
-
name = "
|
|
572
|
-
frameworks = ["
|
|
573
|
-
priority =
|
|
527
|
+
class NestJsExtractor extends BaseExtractor {
|
|
528
|
+
id = "nestjs";
|
|
529
|
+
name = "NestJS Extractor";
|
|
530
|
+
frameworks = ["nestjs"];
|
|
531
|
+
priority = 20;
|
|
574
532
|
async doExtract(ctx) {
|
|
575
533
|
const { project, options, fs } = ctx;
|
|
576
534
|
const pattern = options.scope?.length ? options.scope.map((s) => `${s}/**/*.ts`).join(",") : "**/*.ts";
|
|
577
535
|
const files = await fs.glob(pattern, { cwd: project.rootPath });
|
|
578
536
|
ctx.ir.stats.filesScanned = files.length;
|
|
579
537
|
for (const file of files) {
|
|
580
|
-
if (file.includes("node_modules") || file.includes(".test."))
|
|
538
|
+
if (file.includes("node_modules") || file.includes(".spec.") || file.includes(".test.")) {
|
|
581
539
|
continue;
|
|
540
|
+
}
|
|
582
541
|
const fullPath = `${project.rootPath}/${file}`;
|
|
583
542
|
const content = await fs.readFile(fullPath);
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
await this.extractRoutes(ctx, file, content);
|
|
543
|
+
await this.extractControllers(ctx, file, content);
|
|
544
|
+
await this.extractDtos(ctx, file, content);
|
|
587
545
|
}
|
|
588
546
|
}
|
|
589
|
-
async
|
|
590
|
-
const
|
|
591
|
-
for (const
|
|
592
|
-
const
|
|
593
|
-
const
|
|
594
|
-
const
|
|
595
|
-
const
|
|
547
|
+
async extractControllers(ctx, file, content) {
|
|
548
|
+
const controllerMatches = [...content.matchAll(PATTERNS5.controller)];
|
|
549
|
+
for (const controllerMatch of controllerMatches) {
|
|
550
|
+
const basePath = controllerMatch[1] || "";
|
|
551
|
+
const controllerIndex = controllerMatch.index ?? 0;
|
|
552
|
+
const afterDecorator = content.slice(controllerIndex);
|
|
553
|
+
const classMatch = afterDecorator.match(/class\s+(\w+)/);
|
|
554
|
+
const controllerName = classMatch?.[1] ?? "UnknownController";
|
|
555
|
+
const nextController = content.indexOf("@Controller", controllerIndex + 1);
|
|
556
|
+
const controllerBlock = nextController > 0 ? content.slice(controllerIndex, nextController) : content.slice(controllerIndex);
|
|
557
|
+
const routeMatches = [...controllerBlock.matchAll(PATTERNS5.route)];
|
|
558
|
+
for (const routeMatch of routeMatches) {
|
|
559
|
+
const method = routeMatch[1]?.toUpperCase();
|
|
560
|
+
const routePath = routeMatch[2] || "";
|
|
561
|
+
const fullPath = this.normalizePath(`/${basePath}/${routePath}`);
|
|
562
|
+
const afterRoute = controllerBlock.slice(routeMatch.index ?? 0);
|
|
563
|
+
const methodMatch = afterRoute.match(/(?:async\s+)?(\w+)\s*\([^)]*\)\s*(?::\s*\w+(?:<[^>]+>)?)?\s*\{/);
|
|
564
|
+
const handlerName = methodMatch?.[1] ?? "unknownHandler";
|
|
565
|
+
const absoluteIndex = controllerIndex + (routeMatch.index ?? 0);
|
|
566
|
+
const lineNumber = content.slice(0, absoluteIndex).split(`
|
|
596
567
|
`).length;
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
zodOutput: /\.output\s*\(\s*(\w+)/g
|
|
618
|
-
};
|
|
619
|
-
|
|
620
|
-
class TrpcExtractor extends BaseExtractor {
|
|
621
|
-
id = "trpc";
|
|
622
|
-
name = "tRPC Extractor";
|
|
623
|
-
frameworks = ["trpc"];
|
|
624
|
-
priority = 15;
|
|
625
|
-
async doExtract(ctx) {
|
|
626
|
-
const { project, options, fs } = ctx;
|
|
627
|
-
const pattern = options.scope?.length ? options.scope.map((s) => `${s}/**/*.ts`).join(",") : "**/*.ts";
|
|
628
|
-
const files = await fs.glob(pattern, { cwd: project.rootPath });
|
|
629
|
-
ctx.ir.stats.filesScanned = files.length;
|
|
630
|
-
for (const file of files) {
|
|
631
|
-
if (file.includes("node_modules") || file.includes(".test."))
|
|
632
|
-
continue;
|
|
633
|
-
const fullPath = `${project.rootPath}/${file}`;
|
|
634
|
-
const content = await fs.readFile(fullPath);
|
|
635
|
-
if (!content.includes("trpc") && !content.includes("Procedure"))
|
|
636
|
-
continue;
|
|
637
|
-
await this.extractProcedures(ctx, file, content);
|
|
568
|
+
const hasBody = PATTERNS5.body.test(afterRoute.slice(0, 200));
|
|
569
|
+
const hasParams = PATTERNS5.param.test(afterRoute.slice(0, 200));
|
|
570
|
+
const hasQuery = PATTERNS5.query.test(afterRoute.slice(0, 200));
|
|
571
|
+
const endpoint = {
|
|
572
|
+
id: this.generateEndpointId(method, fullPath, handlerName),
|
|
573
|
+
method,
|
|
574
|
+
path: fullPath,
|
|
575
|
+
kind: this.methodToOpKind(method),
|
|
576
|
+
handlerName,
|
|
577
|
+
controllerName,
|
|
578
|
+
source: this.createLocation(file, lineNumber, lineNumber + 10),
|
|
579
|
+
confidence: this.createConfidence("medium", "decorator-hints"),
|
|
580
|
+
frameworkMeta: {
|
|
581
|
+
hasBody,
|
|
582
|
+
hasParams,
|
|
583
|
+
hasQuery
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
this.addEndpoint(ctx, endpoint);
|
|
587
|
+
}
|
|
638
588
|
}
|
|
639
589
|
}
|
|
640
|
-
async
|
|
641
|
-
const
|
|
642
|
-
for (const match of
|
|
643
|
-
const
|
|
590
|
+
async extractDtos(ctx, file, content) {
|
|
591
|
+
const dtoMatches = [...content.matchAll(PATTERNS5.dto)];
|
|
592
|
+
for (const match of dtoMatches) {
|
|
593
|
+
const name = match[1] ?? "UnknownDto";
|
|
644
594
|
const index = match.index ?? 0;
|
|
645
595
|
const lineNumber = content.slice(0, index).split(`
|
|
646
596
|
`).length;
|
|
647
|
-
const
|
|
648
|
-
const
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
const hasSchema = hasZodInput || hasZodOutput;
|
|
655
|
-
const method = isMutation ? "POST" : "GET";
|
|
656
|
-
const endpoint = {
|
|
657
|
-
id: `trpc.${procedureName}`,
|
|
658
|
-
method,
|
|
659
|
-
path: `/trpc/${procedureName}`,
|
|
660
|
-
kind: isMutation ? "command" : "query",
|
|
661
|
-
handlerName: procedureName,
|
|
662
|
-
source: this.createLocation(file, lineNumber, lineNumber + 10),
|
|
663
|
-
confidence: this.createConfidence(hasSchema ? "high" : "medium", hasSchema ? "explicit-schema" : "inferred-types"),
|
|
664
|
-
frameworkMeta: {
|
|
665
|
-
procedureType: isMutation ? "mutation" : "query",
|
|
666
|
-
hasInput: hasZodInput,
|
|
667
|
-
hasOutput: hasZodOutput
|
|
668
|
-
}
|
|
597
|
+
const hasClassValidator = content.includes("class-validator") || content.includes("@IsString") || content.includes("@IsNumber");
|
|
598
|
+
const schema = {
|
|
599
|
+
id: this.generateSchemaId(name, file),
|
|
600
|
+
name,
|
|
601
|
+
schemaType: hasClassValidator ? "class-validator" : "typescript",
|
|
602
|
+
source: this.createLocation(file, lineNumber, lineNumber + 20),
|
|
603
|
+
confidence: this.createConfidence(hasClassValidator ? "high" : "medium", hasClassValidator ? "explicit-schema" : "inferred-types")
|
|
669
604
|
};
|
|
670
|
-
this.
|
|
605
|
+
this.addSchema(ctx, schema);
|
|
671
606
|
}
|
|
672
607
|
}
|
|
608
|
+
normalizePath(path) {
|
|
609
|
+
return "/" + path.replace(/\/+/g, "/").replace(/^\/+|\/+$/g, "");
|
|
610
|
+
}
|
|
673
611
|
}
|
|
674
612
|
// src/extractors/next-api/extractor.ts
|
|
675
|
-
var
|
|
613
|
+
var PATTERNS6 = {
|
|
676
614
|
appRouterExport: /export\s+(?:async\s+)?function\s+(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)/gi,
|
|
677
615
|
pagesHandler: /export\s+default\s+(?:async\s+)?function/g,
|
|
678
616
|
zodSchema: /z\.\w+\(/g
|
|
@@ -706,13 +644,13 @@ class NextApiExtractor extends BaseExtractor {
|
|
|
706
644
|
async extractAppRoutes(ctx, file, content) {
|
|
707
645
|
const pathMatch = file.match(/app\/api\/(.+)\/route\.ts$/);
|
|
708
646
|
const routePath = pathMatch ? `/api/${pathMatch[1]}` : "/api";
|
|
709
|
-
const matches = [...content.matchAll(
|
|
647
|
+
const matches = [...content.matchAll(PATTERNS6.appRouterExport)];
|
|
710
648
|
for (const match of matches) {
|
|
711
649
|
const method = match[1]?.toUpperCase() ?? "GET";
|
|
712
650
|
const index = match.index ?? 0;
|
|
713
651
|
const lineNumber = content.slice(0, index).split(`
|
|
714
652
|
`).length;
|
|
715
|
-
const hasZod =
|
|
653
|
+
const hasZod = PATTERNS6.zodSchema.test(content);
|
|
716
654
|
const endpoint = {
|
|
717
655
|
id: this.generateEndpointId(method, routePath),
|
|
718
656
|
method,
|
|
@@ -729,10 +667,10 @@ class NextApiExtractor extends BaseExtractor {
|
|
|
729
667
|
async extractPagesRoutes(ctx, file, content) {
|
|
730
668
|
const pathMatch = file.match(/pages\/api\/(.+)\.ts$/);
|
|
731
669
|
const routePath = pathMatch ? `/api/${pathMatch[1]}` : "/api";
|
|
732
|
-
if (!
|
|
670
|
+
if (!PATTERNS6.pagesHandler.test(content))
|
|
733
671
|
return;
|
|
734
672
|
const lineNumber = 1;
|
|
735
|
-
const _hasZod =
|
|
673
|
+
const _hasZod = PATTERNS6.zodSchema.test(content);
|
|
736
674
|
const methods = ["GET", "POST"];
|
|
737
675
|
for (const method of methods) {
|
|
738
676
|
const endpoint = {
|
|
@@ -749,6 +687,68 @@ class NextApiExtractor extends BaseExtractor {
|
|
|
749
687
|
}
|
|
750
688
|
}
|
|
751
689
|
}
|
|
690
|
+
// src/extractors/trpc/extractor.ts
|
|
691
|
+
var PATTERNS7 = {
|
|
692
|
+
procedure: /\.(query|mutation)\s*\(\s*(?:\{[^}]*\}|[^)]+)\)/gi,
|
|
693
|
+
procedureName: /(\w+)\s*:\s*(?:publicProcedure|protectedProcedure|procedure)/g,
|
|
694
|
+
zodInput: /\.input\s*\(\s*(\w+)/g,
|
|
695
|
+
zodOutput: /\.output\s*\(\s*(\w+)/g
|
|
696
|
+
};
|
|
697
|
+
|
|
698
|
+
class TrpcExtractor extends BaseExtractor {
|
|
699
|
+
id = "trpc";
|
|
700
|
+
name = "tRPC Extractor";
|
|
701
|
+
frameworks = ["trpc"];
|
|
702
|
+
priority = 15;
|
|
703
|
+
async doExtract(ctx) {
|
|
704
|
+
const { project, options, fs } = ctx;
|
|
705
|
+
const pattern = options.scope?.length ? options.scope.map((s) => `${s}/**/*.ts`).join(",") : "**/*.ts";
|
|
706
|
+
const files = await fs.glob(pattern, { cwd: project.rootPath });
|
|
707
|
+
ctx.ir.stats.filesScanned = files.length;
|
|
708
|
+
for (const file of files) {
|
|
709
|
+
if (file.includes("node_modules") || file.includes(".test."))
|
|
710
|
+
continue;
|
|
711
|
+
const fullPath = `${project.rootPath}/${file}`;
|
|
712
|
+
const content = await fs.readFile(fullPath);
|
|
713
|
+
if (!content.includes("trpc") && !content.includes("Procedure"))
|
|
714
|
+
continue;
|
|
715
|
+
await this.extractProcedures(ctx, file, content);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
async extractProcedures(ctx, file, content) {
|
|
719
|
+
const nameMatches = [...content.matchAll(PATTERNS7.procedureName)];
|
|
720
|
+
for (const match of nameMatches) {
|
|
721
|
+
const procedureName = match[1] ?? "unknownProcedure";
|
|
722
|
+
const index = match.index ?? 0;
|
|
723
|
+
const lineNumber = content.slice(0, index).split(`
|
|
724
|
+
`).length;
|
|
725
|
+
const afterMatch = content.slice(index, index + 500);
|
|
726
|
+
const isQuery = afterMatch.includes(".query(");
|
|
727
|
+
const isMutation = afterMatch.includes(".mutation(");
|
|
728
|
+
if (!isQuery && !isMutation)
|
|
729
|
+
continue;
|
|
730
|
+
const hasZodInput = PATTERNS7.zodInput.test(afterMatch);
|
|
731
|
+
const hasZodOutput = PATTERNS7.zodOutput.test(afterMatch);
|
|
732
|
+
const hasSchema = hasZodInput || hasZodOutput;
|
|
733
|
+
const method = isMutation ? "POST" : "GET";
|
|
734
|
+
const endpoint = {
|
|
735
|
+
id: `trpc.${procedureName}`,
|
|
736
|
+
method,
|
|
737
|
+
path: `/trpc/${procedureName}`,
|
|
738
|
+
kind: isMutation ? "command" : "query",
|
|
739
|
+
handlerName: procedureName,
|
|
740
|
+
source: this.createLocation(file, lineNumber, lineNumber + 10),
|
|
741
|
+
confidence: this.createConfidence(hasSchema ? "high" : "medium", hasSchema ? "explicit-schema" : "inferred-types"),
|
|
742
|
+
frameworkMeta: {
|
|
743
|
+
procedureType: isMutation ? "mutation" : "query",
|
|
744
|
+
hasInput: hasZodInput,
|
|
745
|
+
hasOutput: hasZodOutput
|
|
746
|
+
}
|
|
747
|
+
};
|
|
748
|
+
this.addEndpoint(ctx, endpoint);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
752
|
// src/extractors/zod/extractor.ts
|
|
753
753
|
var PATTERNS8 = {
|
|
754
754
|
zodSchema: /(?:export\s+)?const\s+(\w+)\s*=\s*z\.(?:object|string|number|boolean|array|enum|union|intersection|literal|tuple|record)/g,
|