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