opencroc 0.3.1 → 0.5.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/README.en.md +3 -3
- package/README.ja.md +3 -3
- package/README.md +3 -3
- package/README.zh-CN.md +3 -3
- package/dist/cli/index.js +103 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +356 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -260,7 +260,7 @@ export default defineConfig({
|
|
|
260
260
|
|
|
261
261
|
| Layer | Supported | Planned |
|
|
262
262
|
|---|---|---|
|
|
263
|
-
| **ORM** | Sequelize, TypeORM, Prisma |
|
|
263
|
+
| **ORM** | Sequelize, TypeORM, Prisma, Drizzle | — |
|
|
264
264
|
| **Framework** | Express | NestJS, Fastify, Koa |
|
|
265
265
|
| **Test Runner** | Playwright | — |
|
|
266
266
|
| **LLM** | OpenAI, ZhiPu (GLM), Ollama (local) | Anthropic |
|
|
@@ -293,9 +293,9 @@ export default defineConfig({
|
|
|
293
293
|
- [x] VS Code extension scaffold
|
|
294
294
|
- [x] Plugin system
|
|
295
295
|
- [x] HTML / JSON / Markdown report generation
|
|
296
|
-
- [
|
|
296
|
+
- [x] NestJS controller parser
|
|
297
297
|
- [ ] Visual dashboard (opencroc.com)
|
|
298
|
-
- [
|
|
298
|
+
- [x] Drizzle ORM adapter
|
|
299
299
|
|
|
300
300
|
## Documentation
|
|
301
301
|
|
package/README.ja.md
CHANGED
|
@@ -260,7 +260,7 @@ export default defineConfig({
|
|
|
260
260
|
|
|
261
261
|
| レイヤー | 対応済み | 予定 |
|
|
262
262
|
|---|---|---|
|
|
263
|
-
| **ORM** | Sequelize, TypeORM, Prisma |
|
|
263
|
+
| **ORM** | Sequelize, TypeORM, Prisma, Drizzle | — |
|
|
264
264
|
| **Framework** | Express | NestJS, Fastify, Koa |
|
|
265
265
|
| **Test Runner** | Playwright | — |
|
|
266
266
|
| **LLM** | OpenAI, ZhiPu (GLM), Ollama (local) | Anthropic |
|
|
@@ -293,9 +293,9 @@ export default defineConfig({
|
|
|
293
293
|
- [x] VS Code extension scaffold
|
|
294
294
|
- [x] Plugin system
|
|
295
295
|
- [x] HTML / JSON / Markdown report generation
|
|
296
|
-
- [
|
|
296
|
+
- [x] NestJS controller parser
|
|
297
297
|
- [ ] Visual dashboard (opencroc.com)
|
|
298
|
-
- [
|
|
298
|
+
- [x] Drizzle ORM adapter
|
|
299
299
|
|
|
300
300
|
## ドキュメント
|
|
301
301
|
|
package/README.md
CHANGED
|
@@ -260,7 +260,7 @@ export default defineConfig({
|
|
|
260
260
|
|
|
261
261
|
| Layer | Supported | Planned |
|
|
262
262
|
|---|---|---|
|
|
263
|
-
| **ORM** | Sequelize, TypeORM, Prisma |
|
|
263
|
+
| **ORM** | Sequelize, TypeORM, Prisma, Drizzle | — |
|
|
264
264
|
| **Framework** | Express | NestJS, Fastify, Koa |
|
|
265
265
|
| **Test Runner** | Playwright | — |
|
|
266
266
|
| **LLM** | OpenAI, ZhiPu (GLM), Ollama (local) | Anthropic |
|
|
@@ -293,9 +293,9 @@ export default defineConfig({
|
|
|
293
293
|
- [x] VS Code extension scaffold
|
|
294
294
|
- [x] Plugin system
|
|
295
295
|
- [x] HTML / JSON / Markdown report generation
|
|
296
|
-
- [
|
|
296
|
+
- [x] NestJS controller parser
|
|
297
297
|
- [ ] Visual dashboard (opencroc.com)
|
|
298
|
-
- [
|
|
298
|
+
- [x] Drizzle ORM adapter
|
|
299
299
|
|
|
300
300
|
## Documentation
|
|
301
301
|
|
package/README.zh-CN.md
CHANGED
|
@@ -260,7 +260,7 @@ export default defineConfig({
|
|
|
260
260
|
|
|
261
261
|
| 层级 | 已支持 | 规划中 |
|
|
262
262
|
|---|---|---|
|
|
263
|
-
| **ORM** | Sequelize, TypeORM, Prisma |
|
|
263
|
+
| **ORM** | Sequelize, TypeORM, Prisma, Drizzle | — |
|
|
264
264
|
| **Framework** | Express | NestJS, Fastify, Koa |
|
|
265
265
|
| **Test Runner** | Playwright | — |
|
|
266
266
|
| **LLM** | OpenAI, ZhiPu (GLM), Ollama (local) | Anthropic |
|
|
@@ -293,9 +293,9 @@ export default defineConfig({
|
|
|
293
293
|
- [x] VS Code extension scaffold
|
|
294
294
|
- [x] Plugin system
|
|
295
295
|
- [x] HTML / JSON / Markdown report generation
|
|
296
|
-
- [
|
|
296
|
+
- [x] NestJS controller parser
|
|
297
297
|
- [ ] Visual dashboard (opencroc.com)
|
|
298
|
-
- [
|
|
298
|
+
- [x] Drizzle ORM adapter
|
|
299
299
|
|
|
300
300
|
## 文档
|
|
301
301
|
|
package/dist/cli/index.js
CHANGED
|
@@ -339,7 +339,8 @@ import * as fs2 from "fs";
|
|
|
339
339
|
import * as path3 from "path";
|
|
340
340
|
import {
|
|
341
341
|
Project as Project2,
|
|
342
|
-
SyntaxKind as SyntaxKind2
|
|
342
|
+
SyntaxKind as SyntaxKind2,
|
|
343
|
+
Node
|
|
343
344
|
} from "ts-morph";
|
|
344
345
|
function parseControllerFile(filePath) {
|
|
345
346
|
const absolutePath = path3.resolve(filePath);
|
|
@@ -350,6 +351,7 @@ function parseControllerFile(filePath) {
|
|
|
350
351
|
const endpoints = [];
|
|
351
352
|
endpoints.push(...extractRouterCalls(sourceFile));
|
|
352
353
|
endpoints.push(...extractBaseCrudRoutes(sourceFile));
|
|
354
|
+
endpoints.push(...extractNestControllerRoutes(sourceFile));
|
|
353
355
|
return deduplicateEndpoints(endpoints);
|
|
354
356
|
} catch {
|
|
355
357
|
return [];
|
|
@@ -442,6 +444,49 @@ function extractBaseCrudRoutes(sourceFile) {
|
|
|
442
444
|
}
|
|
443
445
|
return endpoints;
|
|
444
446
|
}
|
|
447
|
+
function extractNestControllerRoutes(sourceFile) {
|
|
448
|
+
const endpoints = [];
|
|
449
|
+
for (const cls of sourceFile.getClasses()) {
|
|
450
|
+
const controllerDecorator = cls.getDecorators().find((d) => d.getName().toLowerCase() === "controller");
|
|
451
|
+
if (!controllerDecorator) continue;
|
|
452
|
+
const controllerBasePath = normalizeRoutePath(extractDecoratorPath(controllerDecorator, sourceFile) ?? "");
|
|
453
|
+
for (const methodDecl of cls.getMethods()) {
|
|
454
|
+
const requestMapping = extractRequestMapping(methodDecl, sourceFile);
|
|
455
|
+
if (requestMapping) {
|
|
456
|
+
const fullPath2 = joinRoutePath(controllerBasePath, normalizeRoutePath(requestMapping.path));
|
|
457
|
+
endpoints.push({
|
|
458
|
+
method: requestMapping.method,
|
|
459
|
+
path: fullPath2,
|
|
460
|
+
pathParams: extractPathParams(fullPath2),
|
|
461
|
+
queryParams: [],
|
|
462
|
+
bodyFields: [],
|
|
463
|
+
responseFields: [],
|
|
464
|
+
relatedTables: [],
|
|
465
|
+
description: extractMethodDescription(methodDecl)
|
|
466
|
+
});
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
const httpDecorator = methodDecl.getDecorators().find((d) => NEST_HTTP_DECORATORS.has(d.getName().toLowerCase()));
|
|
470
|
+
if (!httpDecorator) continue;
|
|
471
|
+
const methodName = httpDecorator.getName().toLowerCase();
|
|
472
|
+
const method = METHOD_MAP[methodName];
|
|
473
|
+
if (!method) continue;
|
|
474
|
+
const methodPath = normalizeRoutePath(extractDecoratorPath(httpDecorator, sourceFile) ?? "");
|
|
475
|
+
const fullPath = joinRoutePath(controllerBasePath, methodPath);
|
|
476
|
+
endpoints.push({
|
|
477
|
+
method,
|
|
478
|
+
path: fullPath,
|
|
479
|
+
pathParams: extractPathParams(fullPath),
|
|
480
|
+
queryParams: [],
|
|
481
|
+
bodyFields: [],
|
|
482
|
+
responseFields: [],
|
|
483
|
+
relatedTables: [],
|
|
484
|
+
description: extractMethodDescription(methodDecl)
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return endpoints;
|
|
489
|
+
}
|
|
445
490
|
function resolveRoutePath(node, sourceFile) {
|
|
446
491
|
const kind = node.getKind();
|
|
447
492
|
if (kind === SyntaxKind2.StringLiteral) return node.getText().slice(1, -1);
|
|
@@ -453,6 +498,60 @@ function resolveRoutePath(node, sourceFile) {
|
|
|
453
498
|
}
|
|
454
499
|
return null;
|
|
455
500
|
}
|
|
501
|
+
function extractDecoratorPath(decorator, sourceFile) {
|
|
502
|
+
const args = decorator.getArguments();
|
|
503
|
+
if (args.length === 0) return "";
|
|
504
|
+
const firstArg = args[0];
|
|
505
|
+
if (firstArg.getKind() === SyntaxKind2.ObjectLiteralExpression) {
|
|
506
|
+
return extractPathFromObjectLiteral(firstArg, sourceFile);
|
|
507
|
+
}
|
|
508
|
+
return resolveRoutePath(firstArg, sourceFile);
|
|
509
|
+
}
|
|
510
|
+
function extractPathFromObjectLiteral(node, sourceFile) {
|
|
511
|
+
const pathProp = node.getProperty("path");
|
|
512
|
+
if (!pathProp || !Node.isPropertyAssignment(pathProp)) return null;
|
|
513
|
+
const initializer = pathProp.getInitializer();
|
|
514
|
+
if (!initializer) return null;
|
|
515
|
+
return resolveRoutePath(initializer, sourceFile);
|
|
516
|
+
}
|
|
517
|
+
function extractRequestMapping(methodDecl, sourceFile) {
|
|
518
|
+
const decorator = methodDecl.getDecorators().find((d) => d.getName().toLowerCase() === "requestmapping");
|
|
519
|
+
if (!decorator) return null;
|
|
520
|
+
const args = decorator.getArguments();
|
|
521
|
+
if (args.length === 0) return null;
|
|
522
|
+
const firstArg = args[0];
|
|
523
|
+
if (firstArg.getKind() !== SyntaxKind2.ObjectLiteralExpression) return null;
|
|
524
|
+
const obj = firstArg;
|
|
525
|
+
const methodProp = obj.getProperty("method");
|
|
526
|
+
let method = "GET";
|
|
527
|
+
if (methodProp && Node.isPropertyAssignment(methodProp)) {
|
|
528
|
+
const init = methodProp.getInitializer();
|
|
529
|
+
const methodText = init?.getText() || "";
|
|
530
|
+
const normalized = methodText.replace(/['"`]/g, "").split(".").pop()?.toUpperCase();
|
|
531
|
+
if (normalized && ["GET", "POST", "PUT", "DELETE", "PATCH"].includes(normalized)) {
|
|
532
|
+
method = normalized;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
const pathValue = extractPathFromObjectLiteral(obj, sourceFile) ?? "";
|
|
536
|
+
return { method, path: pathValue };
|
|
537
|
+
}
|
|
538
|
+
function normalizeRoutePath(routePath) {
|
|
539
|
+
const cleaned = routePath.trim();
|
|
540
|
+
if (!cleaned || cleaned === "/") return "";
|
|
541
|
+
return `/${cleaned.replace(/^\/+|\/+$/g, "")}`;
|
|
542
|
+
}
|
|
543
|
+
function joinRoutePath(basePath, childPath) {
|
|
544
|
+
const joined = `${basePath}${childPath}`.replace(/\/+/g, "/");
|
|
545
|
+
return joined || "/";
|
|
546
|
+
}
|
|
547
|
+
function extractMethodDescription(methodDecl) {
|
|
548
|
+
const docs = methodDecl.getJsDocs();
|
|
549
|
+
if (docs.length > 0) {
|
|
550
|
+
const desc = docs[0].getDescription().trim();
|
|
551
|
+
if (desc) return desc;
|
|
552
|
+
}
|
|
553
|
+
return "";
|
|
554
|
+
}
|
|
456
555
|
function resolveTemplateLiteral(node, sourceFile) {
|
|
457
556
|
let result = node.getText().slice(1, -1);
|
|
458
557
|
result = result.replace(/\$\{([^}]+)\}/g, (_match, expr) => {
|
|
@@ -516,7 +615,7 @@ function deduplicateEndpoints(endpoints) {
|
|
|
516
615
|
}
|
|
517
616
|
return Array.from(seen.values());
|
|
518
617
|
}
|
|
519
|
-
var HTTP_METHODS, METHOD_MAP;
|
|
618
|
+
var HTTP_METHODS, METHOD_MAP, NEST_HTTP_DECORATORS;
|
|
520
619
|
var init_controller_parser = __esm({
|
|
521
620
|
"src/parsers/controller-parser.ts"() {
|
|
522
621
|
"use strict";
|
|
@@ -529,6 +628,7 @@ var init_controller_parser = __esm({
|
|
|
529
628
|
delete: "DELETE",
|
|
530
629
|
patch: "PATCH"
|
|
531
630
|
};
|
|
631
|
+
NEST_HTTP_DECORATORS = /* @__PURE__ */ new Set(["get", "post", "put", "delete", "patch"]);
|
|
532
632
|
}
|
|
533
633
|
});
|
|
534
634
|
|
|
@@ -2031,7 +2131,7 @@ var init_report = __esm({
|
|
|
2031
2131
|
init_esm_shims();
|
|
2032
2132
|
import { Command } from "commander";
|
|
2033
2133
|
var program = new Command();
|
|
2034
|
-
program.name("opencroc").description("AI-native E2E testing framework").version("0.
|
|
2134
|
+
program.name("opencroc").description("AI-native E2E testing framework").version("0.5.0");
|
|
2035
2135
|
program.command("init").description("Initialize OpenCroc in the current project").option("-y, --yes", "Skip prompts and use defaults").action(async (opts) => {
|
|
2036
2136
|
const { initProject: initProject2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
2037
2137
|
await initProject2(opts);
|