@contractspec/lib.source-extractors 0.11.0 → 0.13.0
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/browser/codegen/index.js +225 -0
- package/dist/browser/extractors/index.js +835 -0
- package/dist/browser/index.js +1215 -0
- package/dist/browser/types.js +0 -0
- package/dist/codegen/index.d.ts +9 -11
- package/dist/codegen/index.d.ts.map +1 -1
- package/dist/codegen/index.js +223 -14
- package/dist/codegen/operation-gen.d.ts +9 -8
- package/dist/codegen/operation-gen.d.ts.map +1 -1
- package/dist/codegen/registry-gen.d.ts +7 -6
- package/dist/codegen/registry-gen.d.ts.map +1 -1
- package/dist/codegen/schema-gen.d.ts +9 -8
- package/dist/codegen/schema-gen.d.ts.map +1 -1
- package/dist/codegen/types.d.ts +29 -32
- package/dist/codegen/types.d.ts.map +1 -1
- package/dist/detect.d.ts +19 -17
- package/dist/detect.d.ts.map +1 -1
- package/dist/extract.d.ts +10 -8
- package/dist/extract.d.ts.map +1 -1
- package/dist/extractors/base.d.ts +76 -75
- package/dist/extractors/base.d.ts.map +1 -1
- package/dist/extractors/elysia/extractor.d.ts +15 -12
- package/dist/extractors/elysia/extractor.d.ts.map +1 -1
- package/dist/extractors/express/extractor.d.ts +16 -12
- package/dist/extractors/express/extractor.d.ts.map +1 -1
- package/dist/extractors/fastify/extractor.d.ts +16 -12
- package/dist/extractors/fastify/extractor.d.ts.map +1 -1
- package/dist/extractors/hono/extractor.d.ts +15 -12
- package/dist/extractors/hono/extractor.d.ts.map +1 -1
- package/dist/extractors/index.d.ts +16 -17
- package/dist/extractors/index.d.ts.map +1 -1
- package/dist/extractors/index.js +834 -40
- package/dist/extractors/nestjs/extractor.d.ts +28 -23
- package/dist/extractors/nestjs/extractor.d.ts.map +1 -1
- package/dist/extractors/next-api/extractor.d.ts +16 -13
- package/dist/extractors/next-api/extractor.d.ts.map +1 -1
- package/dist/extractors/trpc/extractor.d.ts +16 -12
- package/dist/extractors/trpc/extractor.d.ts.map +1 -1
- package/dist/extractors/zod/extractor.d.ts +15 -13
- package/dist/extractors/zod/extractor.d.ts.map +1 -1
- package/dist/index.d.ts +30 -7
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1215 -6
- package/dist/node/codegen/index.js +225 -0
- package/dist/node/extractors/index.js +835 -0
- package/dist/node/index.js +1215 -0
- package/dist/node/types.js +0 -0
- package/dist/registry.d.ts +69 -68
- package/dist/registry.d.ts.map +1 -1
- package/dist/types.d.ts +182 -185
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/package.json +60 -21
- package/dist/_virtual/_rolldown/runtime.js +0 -18
- package/dist/codegen/index.js.map +0 -1
- package/dist/codegen/operation-gen.js +0 -91
- package/dist/codegen/operation-gen.js.map +0 -1
- package/dist/codegen/registry-gen.js +0 -47
- package/dist/codegen/registry-gen.js.map +0 -1
- package/dist/codegen/schema-gen.js +0 -93
- package/dist/codegen/schema-gen.js.map +0 -1
- package/dist/detect.js +0 -177
- package/dist/detect.js.map +0 -1
- package/dist/extract.js +0 -125
- package/dist/extract.js.map +0 -1
- package/dist/extractors/base.js +0 -152
- package/dist/extractors/base.js.map +0 -1
- package/dist/extractors/elysia/extractor.js +0 -58
- package/dist/extractors/elysia/extractor.js.map +0 -1
- package/dist/extractors/express/extractor.js +0 -61
- package/dist/extractors/express/extractor.js.map +0 -1
- package/dist/extractors/fastify/extractor.js +0 -61
- package/dist/extractors/fastify/extractor.js.map +0 -1
- package/dist/extractors/hono/extractor.js +0 -57
- package/dist/extractors/hono/extractor.js.map +0 -1
- package/dist/extractors/index.js.map +0 -1
- package/dist/extractors/nestjs/extractor.js +0 -118
- package/dist/extractors/nestjs/extractor.js.map +0 -1
- package/dist/extractors/next-api/extractor.js +0 -80
- package/dist/extractors/next-api/extractor.js.map +0 -1
- package/dist/extractors/trpc/extractor.js +0 -71
- package/dist/extractors/trpc/extractor.js.map +0 -1
- package/dist/extractors/zod/extractor.js +0 -69
- package/dist/extractors/zod/extractor.js.map +0 -1
- package/dist/registry.js +0 -87
- package/dist/registry.js.map +0 -1
package/dist/types.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// @bun
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contractspec/lib.source-extractors",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Extract contract candidates from TypeScript source code across multiple frameworks (NestJS, Express, Fastify, Hono, Elysia, tRPC, Next.js)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"contractspec",
|
|
@@ -17,26 +17,27 @@
|
|
|
17
17
|
"scripts": {
|
|
18
18
|
"publish:pkg": "bun publish --tolerate-republish --ignore-scripts --verbose",
|
|
19
19
|
"publish:pkg:canary": "bun publish:pkg --tag canary",
|
|
20
|
-
"build": "bun build:
|
|
21
|
-
"build:bundle": "
|
|
22
|
-
"build:types": "
|
|
23
|
-
"dev": "bun
|
|
20
|
+
"build": "bun run prebuild && bun run build:bundle && bun run build:types",
|
|
21
|
+
"build:bundle": "contractspec-bun-build transpile",
|
|
22
|
+
"build:types": "contractspec-bun-build types",
|
|
23
|
+
"dev": "contractspec-bun-build dev",
|
|
24
24
|
"clean": "rimraf dist .turbo",
|
|
25
25
|
"lint": "bun lint:fix",
|
|
26
26
|
"lint:fix": "eslint src --fix",
|
|
27
27
|
"lint:check": "eslint src",
|
|
28
|
-
"test": "bun test"
|
|
28
|
+
"test": "bun test",
|
|
29
|
+
"prebuild": "contractspec-bun-build prebuild",
|
|
30
|
+
"typecheck": "tsc --noEmit"
|
|
29
31
|
},
|
|
30
32
|
"dependencies": {
|
|
31
|
-
"@contractspec/lib.contracts": "1.
|
|
32
|
-
"@contractspec/lib.schema": "1.
|
|
33
|
+
"@contractspec/lib.contracts": "1.59.0",
|
|
34
|
+
"@contractspec/lib.schema": "1.59.0",
|
|
33
35
|
"typescript": "^5.9.3",
|
|
34
36
|
"zod": "^4.3.5"
|
|
35
37
|
},
|
|
36
38
|
"devDependencies": {
|
|
37
|
-
"@contractspec/tool.
|
|
38
|
-
"@contractspec/tool.
|
|
39
|
-
"tsdown": "^0.20.3"
|
|
39
|
+
"@contractspec/tool.typescript": "1.59.0",
|
|
40
|
+
"@contractspec/tool.bun": "1.58.0"
|
|
40
41
|
},
|
|
41
42
|
"types": "./dist/index.d.ts",
|
|
42
43
|
"files": [
|
|
@@ -44,20 +45,58 @@
|
|
|
44
45
|
"README.md"
|
|
45
46
|
],
|
|
46
47
|
"exports": {
|
|
47
|
-
".": "./
|
|
48
|
-
"./codegen": "./
|
|
49
|
-
"./
|
|
50
|
-
"./
|
|
51
|
-
"
|
|
48
|
+
".": "./src/index.ts",
|
|
49
|
+
"./codegen": "./src/codegen/index.ts",
|
|
50
|
+
"./codegen/index": "./src/codegen/index.ts",
|
|
51
|
+
"./extractors": "./src/extractors/index.ts",
|
|
52
|
+
"./extractors/index": "./src/extractors/index.ts",
|
|
53
|
+
"./types": "./src/types.ts"
|
|
52
54
|
},
|
|
53
55
|
"publishConfig": {
|
|
54
56
|
"access": "public",
|
|
55
57
|
"exports": {
|
|
56
|
-
".":
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
".": {
|
|
59
|
+
"types": "./dist/index.d.ts",
|
|
60
|
+
"bun": "./dist/index.js",
|
|
61
|
+
"node": "./dist/node/index.mjs",
|
|
62
|
+
"browser": "./dist/browser/index.js",
|
|
63
|
+
"default": "./dist/index.js"
|
|
64
|
+
},
|
|
65
|
+
"./codegen": {
|
|
66
|
+
"types": "./dist/codegen/index.d.ts",
|
|
67
|
+
"bun": "./dist/codegen/index.js",
|
|
68
|
+
"node": "./dist/node/codegen/index.mjs",
|
|
69
|
+
"browser": "./dist/browser/codegen/index.js",
|
|
70
|
+
"default": "./dist/codegen/index.js"
|
|
71
|
+
},
|
|
72
|
+
"./codegen/index": {
|
|
73
|
+
"types": "./dist/codegen/index.d.ts",
|
|
74
|
+
"bun": "./dist/codegen/index.js",
|
|
75
|
+
"node": "./dist/node/codegen/index.mjs",
|
|
76
|
+
"browser": "./dist/browser/codegen/index.js",
|
|
77
|
+
"default": "./dist/codegen/index.js"
|
|
78
|
+
},
|
|
79
|
+
"./extractors": {
|
|
80
|
+
"types": "./dist/extractors/index.d.ts",
|
|
81
|
+
"bun": "./dist/extractors/index.js",
|
|
82
|
+
"node": "./dist/node/extractors/index.mjs",
|
|
83
|
+
"browser": "./dist/browser/extractors/index.js",
|
|
84
|
+
"default": "./dist/extractors/index.js"
|
|
85
|
+
},
|
|
86
|
+
"./extractors/index": {
|
|
87
|
+
"types": "./dist/extractors/index.d.ts",
|
|
88
|
+
"bun": "./dist/extractors/index.js",
|
|
89
|
+
"node": "./dist/node/extractors/index.mjs",
|
|
90
|
+
"browser": "./dist/browser/extractors/index.js",
|
|
91
|
+
"default": "./dist/extractors/index.js"
|
|
92
|
+
},
|
|
93
|
+
"./types": {
|
|
94
|
+
"types": "./dist/types.d.ts",
|
|
95
|
+
"bun": "./dist/types.js",
|
|
96
|
+
"node": "./dist/node/types.mjs",
|
|
97
|
+
"browser": "./dist/browser/types.js",
|
|
98
|
+
"default": "./dist/types.js"
|
|
99
|
+
}
|
|
61
100
|
},
|
|
62
101
|
"registry": "https://registry.npmjs.org/"
|
|
63
102
|
},
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
//#region \0rolldown/runtime.js
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __exportAll = (all, no_symbols) => {
|
|
4
|
-
let target = {};
|
|
5
|
-
for (var name in all) {
|
|
6
|
-
__defProp(target, name, {
|
|
7
|
-
get: all[name],
|
|
8
|
-
enumerable: true
|
|
9
|
-
});
|
|
10
|
-
}
|
|
11
|
-
if (!no_symbols) {
|
|
12
|
-
__defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
13
|
-
}
|
|
14
|
-
return target;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
//#endregion
|
|
18
|
-
export { __exportAll };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/codegen/index.ts"],"sourcesContent":["/**\n * Code generation module.\n *\n * Generates ContractSpec definitions from the Intermediate Representation.\n */\n\n// Operation generators\nexport { generateOperation, generateOperations } from './operation-gen';\n\n// Schema generators\nexport { generateSchema, generateSchemas } from './schema-gen';\n\n// Registry generators\nexport { generateRegistry } from './registry-gen';\n\n// Types\nexport type {\n GeneratedFile,\n GenerationOptions,\n GenerationResult,\n} from './types';\n"],"mappings":""}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
//#region src/codegen/operation-gen.ts
|
|
2
|
-
/**
|
|
3
|
-
* Generate a single operation spec file.
|
|
4
|
-
*/
|
|
5
|
-
function generateOperation(endpoint, options) {
|
|
6
|
-
const specName = toSpecName(endpoint);
|
|
7
|
-
return {
|
|
8
|
-
path: `${toFileName(endpoint)}.ts`,
|
|
9
|
-
content: generateOperationCode(endpoint, specName, options),
|
|
10
|
-
type: "operation"
|
|
11
|
-
};
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Generate all operation spec files from IR.
|
|
15
|
-
*/
|
|
16
|
-
function generateOperations(ir, options) {
|
|
17
|
-
return ir.endpoints.map((endpoint) => generateOperation(endpoint, options));
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Convert endpoint to spec name (PascalCase).
|
|
21
|
-
*/
|
|
22
|
-
function toSpecName(endpoint) {
|
|
23
|
-
const parts = endpoint.path.replace(/^\//, "").split("/").filter((p) => p && !p.startsWith(":") && !p.startsWith("{"));
|
|
24
|
-
return `${endpoint.method.toLowerCase()}${parts.map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join("")}Spec`;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Convert endpoint to file name (kebab-case).
|
|
28
|
-
*/
|
|
29
|
-
function toFileName(endpoint) {
|
|
30
|
-
const parts = endpoint.path.replace(/^\//, "").split("/").filter((p) => p && !p.startsWith(":") && !p.startsWith("{"));
|
|
31
|
-
return `${endpoint.method.toLowerCase()}-${parts.join("-")}`.replace(/--+/g, "-");
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Generate the operation spec code.
|
|
35
|
-
*/
|
|
36
|
-
function generateOperationCode(endpoint, specName, options) {
|
|
37
|
-
const defineFunc = endpoint.kind === "command" ? "defineCommand" : "defineQuery";
|
|
38
|
-
const auth = options.defaultAuth ?? "user";
|
|
39
|
-
const owners = options.defaultOwners ?? ["team"];
|
|
40
|
-
return [
|
|
41
|
-
`/**`,
|
|
42
|
-
` * ${endpoint.method} ${endpoint.path}`,
|
|
43
|
-
` *`,
|
|
44
|
-
` * Generated from: ${endpoint.source.file}:${endpoint.source.startLine}`,
|
|
45
|
-
` * Confidence: ${endpoint.confidence.level}`,
|
|
46
|
-
` */`,
|
|
47
|
-
``,
|
|
48
|
-
`import { ${defineFunc} } from '@contractspec/lib.contracts';`,
|
|
49
|
-
`import { fromZod } from '@contractspec/lib.schema';`,
|
|
50
|
-
`import { z } from 'zod';`,
|
|
51
|
-
``,
|
|
52
|
-
`// TODO: Define input schema based on extracted information`,
|
|
53
|
-
`const inputSchema = fromZod(z.object({`,
|
|
54
|
-
` // Add fields here`,
|
|
55
|
-
`}));`,
|
|
56
|
-
``,
|
|
57
|
-
`// TODO: Define output schema`,
|
|
58
|
-
`const outputSchema = fromZod(z.object({`,
|
|
59
|
-
` // Add fields here`,
|
|
60
|
-
`}));`,
|
|
61
|
-
``,
|
|
62
|
-
`export const ${specName} = ${defineFunc}({`,
|
|
63
|
-
` meta: {`,
|
|
64
|
-
` name: '${endpoint.handlerName ?? endpoint.id}',`,
|
|
65
|
-
` version: 1,`,
|
|
66
|
-
` stability: 'experimental',`,
|
|
67
|
-
` owners: ${JSON.stringify(owners)},`,
|
|
68
|
-
` goal: 'TODO: Describe the business goal',`,
|
|
69
|
-
` context: 'Generated from ${endpoint.source.file}',`,
|
|
70
|
-
` },`,
|
|
71
|
-
` io: {`,
|
|
72
|
-
` input: inputSchema,`,
|
|
73
|
-
` output: outputSchema,`,
|
|
74
|
-
` },`,
|
|
75
|
-
` policy: {`,
|
|
76
|
-
` auth: '${auth}',`,
|
|
77
|
-
` },`,
|
|
78
|
-
` transport: {`,
|
|
79
|
-
` rest: {`,
|
|
80
|
-
` method: '${endpoint.method}',`,
|
|
81
|
-
` path: '${endpoint.path}',`,
|
|
82
|
-
` },`,
|
|
83
|
-
` },`,
|
|
84
|
-
`});`,
|
|
85
|
-
``
|
|
86
|
-
].join("\n");
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
//#endregion
|
|
90
|
-
export { generateOperation, generateOperations };
|
|
91
|
-
//# sourceMappingURL=operation-gen.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"operation-gen.js","names":[],"sources":["../../src/codegen/operation-gen.ts"],"sourcesContent":["/**\n * Operation code generator.\n *\n * Generates defineCommand/defineQuery specs from endpoint candidates.\n */\n\nimport type { EndpointCandidate, ImportIR } from '../types';\nimport type { GeneratedFile, GenerationOptions } from './types';\n\n/**\n * Generate a single operation spec file.\n */\nexport function generateOperation(\n endpoint: EndpointCandidate,\n options: GenerationOptions\n): GeneratedFile {\n const specName = toSpecName(endpoint);\n const fileName = `${toFileName(endpoint)}.ts`;\n\n const code = generateOperationCode(endpoint, specName, options);\n\n return {\n path: fileName,\n content: code,\n type: 'operation',\n };\n}\n\n/**\n * Generate all operation spec files from IR.\n */\nexport function generateOperations(\n ir: ImportIR,\n options: GenerationOptions\n): GeneratedFile[] {\n return ir.endpoints.map((endpoint) => generateOperation(endpoint, options));\n}\n\n/**\n * Convert endpoint to spec name (PascalCase).\n */\nfunction toSpecName(endpoint: EndpointCandidate): string {\n const parts = endpoint.path\n .replace(/^\\//, '')\n .split('/')\n .filter((p) => p && !p.startsWith(':') && !p.startsWith('{'));\n\n const methodPart = endpoint.method.toLowerCase();\n const pathPart = parts\n .map((p) => p.charAt(0).toUpperCase() + p.slice(1))\n .join('');\n\n return `${methodPart}${pathPart}Spec`;\n}\n\n/**\n * Convert endpoint to file name (kebab-case).\n */\nfunction toFileName(endpoint: EndpointCandidate): string {\n const parts = endpoint.path\n .replace(/^\\//, '')\n .split('/')\n .filter((p) => p && !p.startsWith(':') && !p.startsWith('{'));\n\n const methodPart = endpoint.method.toLowerCase();\n const pathPart = parts.join('-');\n\n return `${methodPart}-${pathPart}`.replace(/--+/g, '-');\n}\n\n/**\n * Generate the operation spec code.\n */\nfunction generateOperationCode(\n endpoint: EndpointCandidate,\n specName: string,\n options: GenerationOptions\n): string {\n const isCommand = endpoint.kind === 'command';\n const defineFunc = isCommand ? 'defineCommand' : 'defineQuery';\n const auth = options.defaultAuth ?? 'user';\n const owners = options.defaultOwners ?? ['team'];\n\n const lines = [\n `/**`,\n ` * ${endpoint.method} ${endpoint.path}`,\n ` *`,\n ` * Generated from: ${endpoint.source.file}:${endpoint.source.startLine}`,\n ` * Confidence: ${endpoint.confidence.level}`,\n ` */`,\n ``,\n `import { ${defineFunc} } from '@contractspec/lib.contracts';`,\n `import { fromZod } from '@contractspec/lib.schema';`,\n `import { z } from 'zod';`,\n ``,\n `// TODO: Define input schema based on extracted information`,\n `const inputSchema = fromZod(z.object({`,\n ` // Add fields here`,\n `}));`,\n ``,\n `// TODO: Define output schema`,\n `const outputSchema = fromZod(z.object({`,\n ` // Add fields here`,\n `}));`,\n ``,\n `export const ${specName} = ${defineFunc}({`,\n ` meta: {`,\n ` name: '${endpoint.handlerName ?? endpoint.id}',`,\n ` version: 1,`,\n ` stability: 'experimental',`,\n ` owners: ${JSON.stringify(owners)},`,\n ` goal: 'TODO: Describe the business goal',`,\n ` context: 'Generated from ${endpoint.source.file}',`,\n ` },`,\n ` io: {`,\n ` input: inputSchema,`,\n ` output: outputSchema,`,\n ` },`,\n ` policy: {`,\n ` auth: '${auth}',`,\n ` },`,\n ` transport: {`,\n ` rest: {`,\n ` method: '${endpoint.method}',`,\n ` path: '${endpoint.path}',`,\n ` },`,\n ` },`,\n `});`,\n ``,\n ];\n\n return lines.join('\\n');\n}\n"],"mappings":";;;;AAYA,SAAgB,kBACd,UACA,SACe;CACf,MAAM,WAAW,WAAW,SAAS;AAKrC,QAAO;EACL,MALe,GAAG,WAAW,SAAS,CAAC;EAMvC,SAJW,sBAAsB,UAAU,UAAU,QAAQ;EAK7D,MAAM;EACP;;;;;AAMH,SAAgB,mBACd,IACA,SACiB;AACjB,QAAO,GAAG,UAAU,KAAK,aAAa,kBAAkB,UAAU,QAAQ,CAAC;;;;;AAM7E,SAAS,WAAW,UAAqC;CACvD,MAAM,QAAQ,SAAS,KACpB,QAAQ,OAAO,GAAG,CAClB,MAAM,IAAI,CACV,QAAQ,MAAM,KAAK,CAAC,EAAE,WAAW,IAAI,IAAI,CAAC,EAAE,WAAW,IAAI,CAAC;AAO/D,QAAO,GALY,SAAS,OAAO,aAAa,GAC/B,MACd,KAAK,MAAM,EAAE,OAAO,EAAE,CAAC,aAAa,GAAG,EAAE,MAAM,EAAE,CAAC,CAClD,KAAK,GAAG,CAEqB;;;;;AAMlC,SAAS,WAAW,UAAqC;CACvD,MAAM,QAAQ,SAAS,KACpB,QAAQ,OAAO,GAAG,CAClB,MAAM,IAAI,CACV,QAAQ,MAAM,KAAK,CAAC,EAAE,WAAW,IAAI,IAAI,CAAC,EAAE,WAAW,IAAI,CAAC;AAK/D,QAAO,GAHY,SAAS,OAAO,aAAa,CAG3B,GAFJ,MAAM,KAAK,IAAI,GAEG,QAAQ,QAAQ,IAAI;;;;;AAMzD,SAAS,sBACP,UACA,UACA,SACQ;CAER,MAAM,aADY,SAAS,SAAS,YACL,kBAAkB;CACjD,MAAM,OAAO,QAAQ,eAAe;CACpC,MAAM,SAAS,QAAQ,iBAAiB,CAAC,OAAO;AAkDhD,QAhDc;EACZ;EACA,MAAM,SAAS,OAAO,GAAG,SAAS;EAClC;EACA,sBAAsB,SAAS,OAAO,KAAK,GAAG,SAAS,OAAO;EAC9D,kBAAkB,SAAS,WAAW;EACtC;EACA;EACA,YAAY,WAAW;EACvB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,gBAAgB,SAAS,KAAK,WAAW;EACzC;EACA,cAAc,SAAS,eAAe,SAAS,GAAG;EAClD;EACA;EACA,eAAe,KAAK,UAAU,OAAO,CAAC;EACtC;EACA,gCAAgC,SAAS,OAAO,KAAK;EACrD;EACA;EACA;EACA;EACA;EACA;EACA,cAAc,KAAK;EACnB;EACA;EACA;EACA,kBAAkB,SAAS,OAAO;EAClC,gBAAgB,SAAS,KAAK;EAC9B;EACA;EACA;EACA;EACD,CAEY,KAAK,KAAK"}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
//#region src/codegen/registry-gen.ts
|
|
2
|
-
/**
|
|
3
|
-
* Generate a registry file for the generated operations.
|
|
4
|
-
*/
|
|
5
|
-
function generateRegistry(operationFiles) {
|
|
6
|
-
const operationImports = operationFiles.filter((f) => f.type === "operation").map((f) => {
|
|
7
|
-
const name = f.path.replace(".ts", "").replace(/-/g, "_");
|
|
8
|
-
const specName = toPascalCase(name) + "Spec";
|
|
9
|
-
return {
|
|
10
|
-
path: f.path,
|
|
11
|
-
name,
|
|
12
|
-
specName
|
|
13
|
-
};
|
|
14
|
-
});
|
|
15
|
-
const lines = [
|
|
16
|
-
`/**`,
|
|
17
|
-
` * Generated operation registry.`,
|
|
18
|
-
` */`,
|
|
19
|
-
``,
|
|
20
|
-
`import { OperationSpecRegistry } from '@contractspec/lib.contracts';`,
|
|
21
|
-
``
|
|
22
|
-
];
|
|
23
|
-
for (const op of operationImports) {
|
|
24
|
-
const importPath = `./${op.path.replace(".ts", "")}`;
|
|
25
|
-
lines.push(`import { ${op.specName} } from '${importPath}';`);
|
|
26
|
-
}
|
|
27
|
-
lines.push(``);
|
|
28
|
-
lines.push(`export const operationRegistry = new OperationSpecRegistry();`);
|
|
29
|
-
lines.push(``);
|
|
30
|
-
for (const op of operationImports) lines.push(`operationRegistry.register(${op.specName});`);
|
|
31
|
-
lines.push(``);
|
|
32
|
-
return {
|
|
33
|
-
path: "registry.ts",
|
|
34
|
-
content: lines.join("\n"),
|
|
35
|
-
type: "registry"
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Convert kebab-case to PascalCase.
|
|
40
|
-
*/
|
|
41
|
-
function toPascalCase(str) {
|
|
42
|
-
return str.split(/[-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
//#endregion
|
|
46
|
-
export { generateRegistry };
|
|
47
|
-
//# sourceMappingURL=registry-gen.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"registry-gen.js","names":[],"sources":["../../src/codegen/registry-gen.ts"],"sourcesContent":["/**\n * Registry code generator.\n *\n * Generates OperationSpecRegistry from generated operations.\n */\n\nimport type { GeneratedFile } from './types';\n\n/**\n * Generate a registry file for the generated operations.\n */\nexport function generateRegistry(\n operationFiles: GeneratedFile[]\n): GeneratedFile {\n const operationImports = operationFiles\n .filter((f) => f.type === 'operation')\n .map((f) => {\n const name = f.path.replace('.ts', '').replace(/-/g, '_');\n const specName = toPascalCase(name) + 'Spec';\n return { path: f.path, name, specName };\n });\n\n const lines = [\n `/**`,\n ` * Generated operation registry.`,\n ` */`,\n ``,\n `import { OperationSpecRegistry } from '@contractspec/lib.contracts';`,\n ``,\n ];\n\n // Add imports\n for (const op of operationImports) {\n const importPath = `./${op.path.replace('.ts', '')}`;\n lines.push(`import { ${op.specName} } from '${importPath}';`);\n }\n\n lines.push(``);\n lines.push(`export const operationRegistry = new OperationSpecRegistry();`);\n lines.push(``);\n\n // Register operations\n for (const op of operationImports) {\n lines.push(`operationRegistry.register(${op.specName});`);\n }\n\n lines.push(``);\n\n return {\n path: 'registry.ts',\n content: lines.join('\\n'),\n type: 'registry',\n };\n}\n\n/**\n * Convert kebab-case to PascalCase.\n */\nfunction toPascalCase(str: string): string {\n return str\n .split(/[-_]/)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('');\n}\n"],"mappings":";;;;AAWA,SAAgB,iBACd,gBACe;CACf,MAAM,mBAAmB,eACtB,QAAQ,MAAM,EAAE,SAAS,YAAY,CACrC,KAAK,MAAM;EACV,MAAM,OAAO,EAAE,KAAK,QAAQ,OAAO,GAAG,CAAC,QAAQ,MAAM,IAAI;EACzD,MAAM,WAAW,aAAa,KAAK,GAAG;AACtC,SAAO;GAAE,MAAM,EAAE;GAAM;GAAM;GAAU;GACvC;CAEJ,MAAM,QAAQ;EACZ;EACA;EACA;EACA;EACA;EACA;EACD;AAGD,MAAK,MAAM,MAAM,kBAAkB;EACjC,MAAM,aAAa,KAAK,GAAG,KAAK,QAAQ,OAAO,GAAG;AAClD,QAAM,KAAK,YAAY,GAAG,SAAS,WAAW,WAAW,IAAI;;AAG/D,OAAM,KAAK,GAAG;AACd,OAAM,KAAK,gEAAgE;AAC3E,OAAM,KAAK,GAAG;AAGd,MAAK,MAAM,MAAM,iBACf,OAAM,KAAK,8BAA8B,GAAG,SAAS,IAAI;AAG3D,OAAM,KAAK,GAAG;AAEd,QAAO;EACL,MAAM;EACN,SAAS,MAAM,KAAK,KAAK;EACzB,MAAM;EACP;;;;;AAMH,SAAS,aAAa,KAAqB;AACzC,QAAO,IACJ,MAAM,OAAO,CACb,KAAK,SAAS,KAAK,OAAO,EAAE,CAAC,aAAa,GAAG,KAAK,MAAM,EAAE,CAAC,CAC3D,KAAK,GAAG"}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
//#region src/codegen/schema-gen.ts
|
|
2
|
-
/**
|
|
3
|
-
* Generate a single schema file.
|
|
4
|
-
*/
|
|
5
|
-
function generateSchema(schema, _options) {
|
|
6
|
-
const fileName = `${toFileName(schema.name)}.ts`;
|
|
7
|
-
const code = generateSchemaCode(schema);
|
|
8
|
-
return {
|
|
9
|
-
path: `schemas/${fileName}`,
|
|
10
|
-
content: code,
|
|
11
|
-
type: "schema"
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Generate all schema files from IR.
|
|
16
|
-
*/
|
|
17
|
-
function generateSchemas(ir, options) {
|
|
18
|
-
return ir.schemas.map((schema) => generateSchema(schema, options));
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Convert name to file name (kebab-case).
|
|
22
|
-
*/
|
|
23
|
-
function toFileName(name) {
|
|
24
|
-
return name.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/([A-Z])([A-Z][a-z])/g, "$1-$2").toLowerCase();
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Generate schema code.
|
|
28
|
-
*/
|
|
29
|
-
function generateSchemaCode(schema) {
|
|
30
|
-
const lines = [
|
|
31
|
-
`/**`,
|
|
32
|
-
` * ${schema.name}`,
|
|
33
|
-
` *`,
|
|
34
|
-
` * Generated from: ${schema.source.file}:${schema.source.startLine}`,
|
|
35
|
-
` * Schema type: ${schema.schemaType}`,
|
|
36
|
-
` * Confidence: ${schema.confidence.level}`,
|
|
37
|
-
` */`,
|
|
38
|
-
``,
|
|
39
|
-
`import { fromZod } from '@contractspec/lib.schema';`,
|
|
40
|
-
`import { z } from 'zod';`,
|
|
41
|
-
``
|
|
42
|
-
];
|
|
43
|
-
if (schema.rawDefinition && schema.schemaType === "zod") {
|
|
44
|
-
lines.push(`// Original definition from source:`);
|
|
45
|
-
lines.push(`// ${schema.rawDefinition.split("\n")[0]}`);
|
|
46
|
-
lines.push(``);
|
|
47
|
-
}
|
|
48
|
-
lines.push(`export const ${schema.name}Schema = fromZod(z.object({`);
|
|
49
|
-
if (schema.fields && schema.fields.length > 0) for (const field of schema.fields) {
|
|
50
|
-
const zodType = mapToZodType(field.type, field.optional);
|
|
51
|
-
lines.push(` ${field.name}: ${zodType},`);
|
|
52
|
-
}
|
|
53
|
-
else lines.push(` // TODO: Define schema fields`);
|
|
54
|
-
lines.push(`}));`);
|
|
55
|
-
lines.push(``);
|
|
56
|
-
lines.push(`export type ${schema.name} = z.infer<typeof ${schema.name}Schema.zodSchema>;`);
|
|
57
|
-
lines.push(``);
|
|
58
|
-
return lines.join("\n");
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Map TypeScript type to Zod type.
|
|
62
|
-
*/
|
|
63
|
-
function mapToZodType(tsType, optional) {
|
|
64
|
-
let zodType;
|
|
65
|
-
switch (tsType.toLowerCase()) {
|
|
66
|
-
case "string":
|
|
67
|
-
zodType = "z.string()";
|
|
68
|
-
break;
|
|
69
|
-
case "number":
|
|
70
|
-
zodType = "z.number()";
|
|
71
|
-
break;
|
|
72
|
-
case "boolean":
|
|
73
|
-
zodType = "z.boolean()";
|
|
74
|
-
break;
|
|
75
|
-
case "date":
|
|
76
|
-
zodType = "z.date()";
|
|
77
|
-
break;
|
|
78
|
-
case "string[]":
|
|
79
|
-
case "array<string>":
|
|
80
|
-
zodType = "z.array(z.string())";
|
|
81
|
-
break;
|
|
82
|
-
case "number[]":
|
|
83
|
-
case "array<number>":
|
|
84
|
-
zodType = "z.array(z.number())";
|
|
85
|
-
break;
|
|
86
|
-
default: zodType = "z.unknown()";
|
|
87
|
-
}
|
|
88
|
-
return optional ? `${zodType}.optional()` : zodType;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
//#endregion
|
|
92
|
-
export { generateSchema, generateSchemas };
|
|
93
|
-
//# sourceMappingURL=schema-gen.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"schema-gen.js","names":[],"sources":["../../src/codegen/schema-gen.ts"],"sourcesContent":["/**\n * Schema code generator.\n *\n * Generates defineSchemaModel specs from schema candidates.\n */\n\nimport type { SchemaCandidate, ImportIR } from '../types';\nimport type { GeneratedFile, GenerationOptions } from './types';\n\n/**\n * Generate a single schema file.\n */\nexport function generateSchema(\n schema: SchemaCandidate,\n _options: GenerationOptions\n): GeneratedFile {\n const fileName = `${toFileName(schema.name)}.ts`;\n const code = generateSchemaCode(schema);\n\n return {\n path: `schemas/${fileName}`,\n content: code,\n type: 'schema',\n };\n}\n\n/**\n * Generate all schema files from IR.\n */\nexport function generateSchemas(\n ir: ImportIR,\n options: GenerationOptions\n): GeneratedFile[] {\n return ir.schemas.map((schema) => generateSchema(schema, options));\n}\n\n/**\n * Convert name to file name (kebab-case).\n */\nfunction toFileName(name: string): string {\n return name\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')\n .toLowerCase();\n}\n\n/**\n * Generate schema code.\n */\nfunction generateSchemaCode(schema: SchemaCandidate): string {\n const lines = [\n `/**`,\n ` * ${schema.name}`,\n ` *`,\n ` * Generated from: ${schema.source.file}:${schema.source.startLine}`,\n ` * Schema type: ${schema.schemaType}`,\n ` * Confidence: ${schema.confidence.level}`,\n ` */`,\n ``,\n `import { fromZod } from '@contractspec/lib.schema';`,\n `import { z } from 'zod';`,\n ``,\n ];\n\n if (schema.rawDefinition && schema.schemaType === 'zod') {\n // Use the raw Zod definition if available\n lines.push(`// Original definition from source:`);\n lines.push(`// ${schema.rawDefinition.split('\\n')[0]}`);\n lines.push(``);\n }\n\n lines.push(`export const ${schema.name}Schema = fromZod(z.object({`);\n\n if (schema.fields && schema.fields.length > 0) {\n for (const field of schema.fields) {\n const zodType = mapToZodType(field.type, field.optional);\n lines.push(` ${field.name}: ${zodType},`);\n }\n } else {\n lines.push(` // TODO: Define schema fields`);\n }\n\n lines.push(`}));`);\n lines.push(``);\n lines.push(\n `export type ${schema.name} = z.infer<typeof ${schema.name}Schema.zodSchema>;`\n );\n lines.push(``);\n\n return lines.join('\\n');\n}\n\n/**\n * Map TypeScript type to Zod type.\n */\nfunction mapToZodType(tsType: string, optional: boolean): string {\n let zodType: string;\n\n switch (tsType.toLowerCase()) {\n case 'string':\n zodType = 'z.string()';\n break;\n case 'number':\n zodType = 'z.number()';\n break;\n case 'boolean':\n zodType = 'z.boolean()';\n break;\n case 'date':\n zodType = 'z.date()';\n break;\n case 'string[]':\n case 'array<string>':\n zodType = 'z.array(z.string())';\n break;\n case 'number[]':\n case 'array<number>':\n zodType = 'z.array(z.number())';\n break;\n default:\n zodType = 'z.unknown()';\n }\n\n return optional ? `${zodType}.optional()` : zodType;\n}\n"],"mappings":";;;;AAYA,SAAgB,eACd,QACA,UACe;CACf,MAAM,WAAW,GAAG,WAAW,OAAO,KAAK,CAAC;CAC5C,MAAM,OAAO,mBAAmB,OAAO;AAEvC,QAAO;EACL,MAAM,WAAW;EACjB,SAAS;EACT,MAAM;EACP;;;;;AAMH,SAAgB,gBACd,IACA,SACiB;AACjB,QAAO,GAAG,QAAQ,KAAK,WAAW,eAAe,QAAQ,QAAQ,CAAC;;;;;AAMpE,SAAS,WAAW,MAAsB;AACxC,QAAO,KACJ,QAAQ,mBAAmB,QAAQ,CACnC,QAAQ,wBAAwB,QAAQ,CACxC,aAAa;;;;;AAMlB,SAAS,mBAAmB,QAAiC;CAC3D,MAAM,QAAQ;EACZ;EACA,MAAM,OAAO;EACb;EACA,sBAAsB,OAAO,OAAO,KAAK,GAAG,OAAO,OAAO;EAC1D,mBAAmB,OAAO;EAC1B,kBAAkB,OAAO,WAAW;EACpC;EACA;EACA;EACA;EACA;EACD;AAED,KAAI,OAAO,iBAAiB,OAAO,eAAe,OAAO;AAEvD,QAAM,KAAK,sCAAsC;AACjD,QAAM,KAAK,MAAM,OAAO,cAAc,MAAM,KAAK,CAAC,KAAK;AACvD,QAAM,KAAK,GAAG;;AAGhB,OAAM,KAAK,gBAAgB,OAAO,KAAK,6BAA6B;AAEpE,KAAI,OAAO,UAAU,OAAO,OAAO,SAAS,EAC1C,MAAK,MAAM,SAAS,OAAO,QAAQ;EACjC,MAAM,UAAU,aAAa,MAAM,MAAM,MAAM,SAAS;AACxD,QAAM,KAAK,KAAK,MAAM,KAAK,IAAI,QAAQ,GAAG;;KAG5C,OAAM,KAAK,kCAAkC;AAG/C,OAAM,KAAK,OAAO;AAClB,OAAM,KAAK,GAAG;AACd,OAAM,KACJ,eAAe,OAAO,KAAK,oBAAoB,OAAO,KAAK,oBAC5D;AACD,OAAM,KAAK,GAAG;AAEd,QAAO,MAAM,KAAK,KAAK;;;;;AAMzB,SAAS,aAAa,QAAgB,UAA2B;CAC/D,IAAI;AAEJ,SAAQ,OAAO,aAAa,EAA5B;EACE,KAAK;AACH,aAAU;AACV;EACF,KAAK;AACH,aAAU;AACV;EACF,KAAK;AACH,aAAU;AACV;EACF,KAAK;AACH,aAAU;AACV;EACF,KAAK;EACL,KAAK;AACH,aAAU;AACV;EACF,KAAK;EACL,KAAK;AACH,aAAU;AACV;EACF,QACE,WAAU;;AAGd,QAAO,WAAW,GAAG,QAAQ,eAAe"}
|
package/dist/detect.js
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
//#region src/detect.ts
|
|
2
|
-
/**
|
|
3
|
-
* Built-in framework detection rules.
|
|
4
|
-
*/
|
|
5
|
-
const FRAMEWORK_RULES = [
|
|
6
|
-
{
|
|
7
|
-
id: "nestjs",
|
|
8
|
-
name: "NestJS",
|
|
9
|
-
packages: ["@nestjs/core", "@nestjs/common"],
|
|
10
|
-
importPatterns: [/@nestjs\//]
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
id: "express",
|
|
14
|
-
name: "Express",
|
|
15
|
-
packages: ["express"],
|
|
16
|
-
importPatterns: [/from ['"]express['"]/]
|
|
17
|
-
},
|
|
18
|
-
{
|
|
19
|
-
id: "fastify",
|
|
20
|
-
name: "Fastify",
|
|
21
|
-
packages: ["fastify"],
|
|
22
|
-
importPatterns: [/from ['"]fastify['"]/]
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
id: "hono",
|
|
26
|
-
name: "Hono",
|
|
27
|
-
packages: ["hono"],
|
|
28
|
-
importPatterns: [/from ['"]hono['"]/]
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
id: "elysia",
|
|
32
|
-
name: "Elysia",
|
|
33
|
-
packages: ["elysia"],
|
|
34
|
-
importPatterns: [/from ['"]elysia['"]/]
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
id: "trpc",
|
|
38
|
-
name: "tRPC",
|
|
39
|
-
packages: ["@trpc/server"],
|
|
40
|
-
importPatterns: [/@trpc\/server/]
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
id: "next-api",
|
|
44
|
-
name: "Next.js API",
|
|
45
|
-
packages: ["next"],
|
|
46
|
-
filePatterns: [/app\/api\/.*\/route\.ts$/, /pages\/api\/.*\.ts$/]
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
id: "koa",
|
|
50
|
-
name: "Koa",
|
|
51
|
-
packages: ["koa", "@koa/router"],
|
|
52
|
-
importPatterns: [/from ['"]koa['"]/]
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
id: "hapi",
|
|
56
|
-
name: "Hapi",
|
|
57
|
-
packages: ["@hapi/hapi"],
|
|
58
|
-
importPatterns: [/@hapi\/hapi/]
|
|
59
|
-
}
|
|
60
|
-
];
|
|
61
|
-
/**
|
|
62
|
-
* Detect frameworks from package.json dependencies.
|
|
63
|
-
*/
|
|
64
|
-
function detectFrameworksFromPackageJson(packageJson) {
|
|
65
|
-
const allDeps = {
|
|
66
|
-
...packageJson.dependencies,
|
|
67
|
-
...packageJson.devDependencies,
|
|
68
|
-
...packageJson.peerDependencies
|
|
69
|
-
};
|
|
70
|
-
const detected = [];
|
|
71
|
-
for (const rule of FRAMEWORK_RULES) for (const pkg of rule.packages) if (pkg in allDeps) {
|
|
72
|
-
detected.push({
|
|
73
|
-
id: rule.id,
|
|
74
|
-
name: rule.name,
|
|
75
|
-
version: allDeps[pkg],
|
|
76
|
-
confidence: "high"
|
|
77
|
-
});
|
|
78
|
-
break;
|
|
79
|
-
}
|
|
80
|
-
return detected;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Detect frameworks from source code imports.
|
|
84
|
-
*/
|
|
85
|
-
function detectFrameworksFromCode(sourceCode) {
|
|
86
|
-
const detected = [];
|
|
87
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
88
|
-
for (const rule of FRAMEWORK_RULES) {
|
|
89
|
-
if (!rule.importPatterns) continue;
|
|
90
|
-
for (const pattern of rule.importPatterns) if (pattern.test(sourceCode) && !seenIds.has(rule.id)) {
|
|
91
|
-
detected.push({
|
|
92
|
-
id: rule.id,
|
|
93
|
-
name: rule.name,
|
|
94
|
-
confidence: "medium"
|
|
95
|
-
});
|
|
96
|
-
seenIds.add(rule.id);
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
return detected;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Detect frameworks from file paths.
|
|
104
|
-
*/
|
|
105
|
-
function detectFrameworksFromPaths(filePaths) {
|
|
106
|
-
const detected = [];
|
|
107
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
108
|
-
for (const rule of FRAMEWORK_RULES) {
|
|
109
|
-
if (!rule.filePatterns) continue;
|
|
110
|
-
for (const pattern of rule.filePatterns) for (const filePath of filePaths) if (pattern.test(filePath) && !seenIds.has(rule.id)) {
|
|
111
|
-
detected.push({
|
|
112
|
-
id: rule.id,
|
|
113
|
-
name: rule.name,
|
|
114
|
-
confidence: "medium"
|
|
115
|
-
});
|
|
116
|
-
seenIds.add(rule.id);
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return detected;
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Merge framework detections, preferring higher confidence.
|
|
124
|
-
*/
|
|
125
|
-
function mergeFrameworkDetections(...detections) {
|
|
126
|
-
const byId = /* @__PURE__ */ new Map();
|
|
127
|
-
const confidenceOrder = {
|
|
128
|
-
high: 3,
|
|
129
|
-
medium: 2,
|
|
130
|
-
low: 1,
|
|
131
|
-
ambiguous: 0
|
|
132
|
-
};
|
|
133
|
-
for (const group of detections) for (const fw of group) {
|
|
134
|
-
const existing = byId.get(fw.id);
|
|
135
|
-
if (!existing || confidenceOrder[fw.confidence] > confidenceOrder[existing.confidence]) byId.set(fw.id, fw);
|
|
136
|
-
}
|
|
137
|
-
return Array.from(byId.values());
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Detect frameworks for a project.
|
|
141
|
-
* This is a convenience function that combines all detection methods.
|
|
142
|
-
*/
|
|
143
|
-
async function detectFramework(rootPath, options) {
|
|
144
|
-
const project = {
|
|
145
|
-
rootPath,
|
|
146
|
-
frameworks: []
|
|
147
|
-
};
|
|
148
|
-
if (options?.readFile) try {
|
|
149
|
-
const packageJsonPath = `${rootPath}/package.json`;
|
|
150
|
-
const content = await options.readFile(packageJsonPath);
|
|
151
|
-
const packageJson = JSON.parse(content);
|
|
152
|
-
project.packageJsonPath = packageJsonPath;
|
|
153
|
-
project.frameworks = detectFrameworksFromPackageJson(packageJson);
|
|
154
|
-
} catch {}
|
|
155
|
-
if (options?.readFile) try {
|
|
156
|
-
const tsConfigPath = `${rootPath}/tsconfig.json`;
|
|
157
|
-
await options.readFile(tsConfigPath);
|
|
158
|
-
project.tsConfigPath = tsConfigPath;
|
|
159
|
-
} catch {}
|
|
160
|
-
return project;
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Get all supported framework IDs.
|
|
164
|
-
*/
|
|
165
|
-
function getSupportedFrameworks() {
|
|
166
|
-
return FRAMEWORK_RULES.map((r) => r.id);
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Check if a framework ID is supported.
|
|
170
|
-
*/
|
|
171
|
-
function isFrameworkSupported(id) {
|
|
172
|
-
return FRAMEWORK_RULES.some((r) => r.id === id);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
//#endregion
|
|
176
|
-
export { detectFramework, detectFrameworksFromCode, detectFrameworksFromPackageJson, detectFrameworksFromPaths, getSupportedFrameworks, isFrameworkSupported, mergeFrameworkDetections };
|
|
177
|
-
//# sourceMappingURL=detect.js.map
|
package/dist/detect.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"detect.js","names":[],"sources":["../src/detect.ts"],"sourcesContent":["/**\n * Framework detection utilities.\n *\n * Analyzes a project to detect which frameworks are in use.\n */\n\nimport type { ConfidenceLevel, FrameworkInfo, ProjectInfo } from './types';\n\n/**\n * Framework detection rule.\n */\ninterface FrameworkDetectionRule {\n id: string;\n name: string;\n /** Package names that indicate this framework */\n packages: string[];\n /** File patterns that indicate this framework */\n filePatterns?: RegExp[];\n /** Import patterns in code that indicate this framework */\n importPatterns?: RegExp[];\n}\n\n/**\n * Built-in framework detection rules.\n */\nconst FRAMEWORK_RULES: FrameworkDetectionRule[] = [\n {\n id: 'nestjs',\n name: 'NestJS',\n packages: ['@nestjs/core', '@nestjs/common'],\n importPatterns: [/@nestjs\\//],\n },\n {\n id: 'express',\n name: 'Express',\n packages: ['express'],\n importPatterns: [/from ['\"]express['\"]/],\n },\n {\n id: 'fastify',\n name: 'Fastify',\n packages: ['fastify'],\n importPatterns: [/from ['\"]fastify['\"]/],\n },\n {\n id: 'hono',\n name: 'Hono',\n packages: ['hono'],\n importPatterns: [/from ['\"]hono['\"]/],\n },\n {\n id: 'elysia',\n name: 'Elysia',\n packages: ['elysia'],\n importPatterns: [/from ['\"]elysia['\"]/],\n },\n {\n id: 'trpc',\n name: 'tRPC',\n packages: ['@trpc/server'],\n importPatterns: [/@trpc\\/server/],\n },\n {\n id: 'next-api',\n name: 'Next.js API',\n packages: ['next'],\n filePatterns: [/app\\/api\\/.*\\/route\\.ts$/, /pages\\/api\\/.*\\.ts$/],\n },\n {\n id: 'koa',\n name: 'Koa',\n packages: ['koa', '@koa/router'],\n importPatterns: [/from ['\"]koa['\"]/],\n },\n {\n id: 'hapi',\n name: 'Hapi',\n packages: ['@hapi/hapi'],\n importPatterns: [/@hapi\\/hapi/],\n },\n];\n\n/**\n * Dependencies from package.json.\n */\ninterface PackageDependencies {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n}\n\n/**\n * Detect frameworks from package.json dependencies.\n */\nexport function detectFrameworksFromPackageJson(\n packageJson: PackageDependencies\n): FrameworkInfo[] {\n const allDeps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n ...packageJson.peerDependencies,\n };\n\n const detected: FrameworkInfo[] = [];\n\n for (const rule of FRAMEWORK_RULES) {\n for (const pkg of rule.packages) {\n if (pkg in allDeps) {\n detected.push({\n id: rule.id,\n name: rule.name,\n version: allDeps[pkg],\n confidence: 'high',\n });\n break; // Only add once per framework\n }\n }\n }\n\n return detected;\n}\n\n/**\n * Detect frameworks from source code imports.\n */\nexport function detectFrameworksFromCode(sourceCode: string): FrameworkInfo[] {\n const detected: FrameworkInfo[] = [];\n const seenIds = new Set<string>();\n\n for (const rule of FRAMEWORK_RULES) {\n if (!rule.importPatterns) continue;\n\n for (const pattern of rule.importPatterns) {\n if (pattern.test(sourceCode) && !seenIds.has(rule.id)) {\n detected.push({\n id: rule.id,\n name: rule.name,\n confidence: 'medium',\n });\n seenIds.add(rule.id);\n break;\n }\n }\n }\n\n return detected;\n}\n\n/**\n * Detect frameworks from file paths.\n */\nexport function detectFrameworksFromPaths(\n filePaths: string[]\n): FrameworkInfo[] {\n const detected: FrameworkInfo[] = [];\n const seenIds = new Set<string>();\n\n for (const rule of FRAMEWORK_RULES) {\n if (!rule.filePatterns) continue;\n\n for (const pattern of rule.filePatterns) {\n for (const filePath of filePaths) {\n if (pattern.test(filePath) && !seenIds.has(rule.id)) {\n detected.push({\n id: rule.id,\n name: rule.name,\n confidence: 'medium',\n });\n seenIds.add(rule.id);\n break;\n }\n }\n }\n }\n\n return detected;\n}\n\n/**\n * Merge framework detections, preferring higher confidence.\n */\nexport function mergeFrameworkDetections(\n ...detections: FrameworkInfo[][]\n): FrameworkInfo[] {\n const byId = new Map<string, FrameworkInfo>();\n\n const confidenceOrder: Record<ConfidenceLevel, number> = {\n high: 3,\n medium: 2,\n low: 1,\n ambiguous: 0,\n };\n\n for (const group of detections) {\n for (const fw of group) {\n const existing = byId.get(fw.id);\n if (\n !existing ||\n confidenceOrder[fw.confidence] > confidenceOrder[existing.confidence]\n ) {\n byId.set(fw.id, fw);\n }\n }\n }\n\n return Array.from(byId.values());\n}\n\n/**\n * Detect frameworks for a project.\n * This is a convenience function that combines all detection methods.\n */\nexport async function detectFramework(\n rootPath: string,\n options?: {\n readFile?: (path: string) => Promise<string>;\n glob?: (pattern: string) => Promise<string[]>;\n }\n): Promise<ProjectInfo> {\n const project: ProjectInfo = {\n rootPath,\n frameworks: [],\n };\n\n // Try to read package.json\n if (options?.readFile) {\n try {\n const packageJsonPath = `${rootPath}/package.json`;\n const content = await options.readFile(packageJsonPath);\n const packageJson = JSON.parse(content) as PackageDependencies;\n project.packageJsonPath = packageJsonPath;\n project.frameworks = detectFrameworksFromPackageJson(packageJson);\n } catch {\n // No package.json or parse error\n }\n }\n\n // Check for tsconfig.json\n if (options?.readFile) {\n try {\n const tsConfigPath = `${rootPath}/tsconfig.json`;\n await options.readFile(tsConfigPath);\n project.tsConfigPath = tsConfigPath;\n } catch {\n // No tsconfig.json\n }\n }\n\n return project;\n}\n\n/**\n * Get all supported framework IDs.\n */\nexport function getSupportedFrameworks(): string[] {\n return FRAMEWORK_RULES.map((r) => r.id);\n}\n\n/**\n * Check if a framework ID is supported.\n */\nexport function isFrameworkSupported(id: string): boolean {\n return FRAMEWORK_RULES.some((r) => r.id === id);\n}\n"],"mappings":"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"}
|