gherkin-ai 1.3.0 → 1.4.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.md +13 -20
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +21 -5
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/create.d.ts +6 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +130 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/lang.d.ts +4 -0
- package/dist/commands/lang.d.ts.map +1 -0
- package/dist/commands/lang.js +38 -0
- package/dist/commands/lang.js.map +1 -0
- package/dist/core/stack-detector.d.ts.map +1 -1
- package/dist/core/stack-detector.js +174 -57
- package/dist/core/stack-detector.js.map +1 -1
- package/dist/index.js +28 -2
- package/dist/index.js.map +1 -1
- package/dist/utils/file-system.d.ts +2 -0
- package/dist/utils/file-system.d.ts.map +1 -1
- package/dist/utils/file-system.js +12 -0
- package/dist/utils/file-system.js.map +1 -1
- package/dist/utils/i18n-cli.d.ts +53 -0
- package/dist/utils/i18n-cli.d.ts.map +1 -0
- package/dist/utils/i18n-cli.js +124 -0
- package/dist/utils/i18n-cli.js.map +1 -0
- package/docs/ARCHITECTURE.md +35 -16
- package/docs/USAGE_GUIDE.md +96 -69
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -16,29 +16,33 @@ While simple AI prompt generators produce generic text instructions, AI agents o
|
|
|
16
16
|
- **`contracts.ts`**: Strict domain interfaces, event schemas, Zod DTOs, CQRS Event Store ports, and Architecture Decision Records (ADRs).
|
|
17
17
|
- **`openapi.json`**: Auto-generated OpenAPI 3.0 specification derived directly from Gherkin AST schemas.
|
|
18
18
|
- **`fixtures.ts` & `seed.sql`**: Concrete database seeds (hashed passwords, bcrypt cost factor 12, pre-conditions) raising AI acceptance test success rates from ~30% to ~85%.
|
|
19
|
-
- **
|
|
19
|
+
- **Interactive Spec Wizard (`ghk create`)**: Create Gherkin specifications step-by-step directly from your terminal.
|
|
20
|
+
- **Brownfield Integration (`ghk detect` & `ghk add`)**: Inject contracts directly into existing project module folders (Laravel, Rails, .NET, Angular, NestJS, etc.).
|
|
20
21
|
- **Bilingual Gherkin Parsing**: Native support for English (`Given/When/Then`) and Spanish (`Dado/Cuando/Entonces`).
|
|
21
|
-
- **Strict Stack Versions**: Enforces explicit package versions (e.g., NestJS v10 + Prisma + Zod + Redis) so agents never diverge.
|
|
22
|
-
- **Runnable Infrastructure**: Includes pre-configured `docker-compose.yml` (PostgreSQL, Redis, RabbitMQ) and native AWS Lambda `serverless.yml` for FaaS architectures.
|
|
23
|
-
- **`ghk validate`**: Deep Architectural Linter checking layer boundary import isolation, step coverage, and circular dependency rules.
|
|
24
22
|
|
|
25
23
|
---
|
|
26
24
|
|
|
27
|
-
## 🚀
|
|
25
|
+
## 🚀 Quick Start Commands
|
|
28
26
|
|
|
29
|
-
### 1.
|
|
27
|
+
### 1. Create a Gherkin Spec Interactively (`ghk create`)
|
|
30
28
|
|
|
31
|
-
|
|
29
|
+
Don't have a `.feature` file ready? Build one interactively step-by-step in terminal:
|
|
32
30
|
|
|
33
31
|
```bash
|
|
34
|
-
#
|
|
32
|
+
ghk create # (or: ghk new)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Existing Projects (Brownfield Mode)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# 1. Auto-detect stack (Laravel, Rails, .NET, NestJS, Angular, Flutter, etc.)
|
|
35
39
|
ghk detect
|
|
36
40
|
|
|
37
41
|
# 2. Inject contract directly into an existing module folder
|
|
38
42
|
ghk add --feature ./specs/payments.feature --target ./src/modules/payments
|
|
39
43
|
```
|
|
40
44
|
|
|
41
|
-
###
|
|
45
|
+
### 3. New Projects (Greenfield Mode)
|
|
42
46
|
|
|
43
47
|
```bash
|
|
44
48
|
# 1. Initialize project configuration interactively
|
|
@@ -53,17 +57,6 @@ ghk validate --feature ./specs/auth.feature
|
|
|
53
57
|
|
|
54
58
|
---
|
|
55
59
|
|
|
56
|
-
## 🏗️ Supported Architecture Styles
|
|
57
|
-
|
|
58
|
-
- **Hexagonal Architecture (Ports & Adapters)**
|
|
59
|
-
- **Domain-Driven Design (DDD)**
|
|
60
|
-
- **Clean Architecture**
|
|
61
|
-
- **CQRS + Event Sourcing (Real Event Store & Aggregate Versions)**
|
|
62
|
-
- **Serverless / FaaS (Native AWS Lambda & `serverless.yml`)**
|
|
63
|
-
- **Microservices Architecture**
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
60
|
## 📖 Complete Documentation
|
|
68
61
|
|
|
69
62
|
- [Comprehensive Usage Guide](docs/USAGE_GUIDE.md)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAeA,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAwErH"}
|
package/dist/commands/add.js
CHANGED
|
@@ -8,24 +8,40 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
9
|
exports.handleAddCommand = handleAddCommand;
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
11
12
|
const config_1 = require("../core/config");
|
|
12
13
|
const stack_detector_1 = require("../core/stack-detector");
|
|
13
14
|
const gherkin_parser_1 = require("../core/gherkin-parser");
|
|
14
15
|
const contracts_1 = require("../generators/contracts");
|
|
15
16
|
const prompts_1 = require("../generators/prompts");
|
|
17
|
+
const create_1 = require("./create");
|
|
16
18
|
const file_system_1 = require("../utils/file-system");
|
|
17
19
|
const logger_1 = require("../utils/logger");
|
|
18
20
|
async function handleAddCommand(options) {
|
|
19
21
|
logger_1.logger.banner();
|
|
20
22
|
if (!options.feature) {
|
|
21
|
-
logger_1.logger.
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
logger_1.logger.info('No --feature file specified. Launching interactive spec wizard...');
|
|
24
|
+
await (0, create_1.handleCreateCommand)({ target: options.target });
|
|
25
|
+
return;
|
|
24
26
|
}
|
|
25
27
|
const featurePath = path_1.default.resolve(process.cwd(), options.feature);
|
|
26
28
|
if (!(0, file_system_1.fileExistsSync)(featurePath)) {
|
|
27
|
-
logger_1.logger.
|
|
28
|
-
|
|
29
|
+
logger_1.logger.warn(`Feature file not found at: ${featurePath}`);
|
|
30
|
+
const answer = await inquirer_1.default.prompt([
|
|
31
|
+
{
|
|
32
|
+
type: 'confirm',
|
|
33
|
+
name: 'createNow',
|
|
34
|
+
message: '¿Deseas crear la especificación Gherkin paso a paso ahora (wizard interactivo)?',
|
|
35
|
+
default: true
|
|
36
|
+
}
|
|
37
|
+
]);
|
|
38
|
+
if (answer.createNow) {
|
|
39
|
+
await (0, create_1.handleCreateCommand)({ output: options.feature, target: options.target });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
29
45
|
}
|
|
30
46
|
// Load config or auto-detect if config doesn't exist
|
|
31
47
|
let config = (0, config_1.loadConfig)(options.config);
|
package/dist/commands/add.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":";AAAA;;gFAEgF;;;;;
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":";AAAA;;gFAEgF;;;;;AAahF,4CAwEC;AAnFD,gDAAwB;AACxB,wDAAgC;AAChC,2CAA4C;AAC5C,2DAA6D;AAC7D,2DAA0D;AAC1D,uDAA4D;AAC5D,mDAAwD;AACxD,qCAA+C;AAC/C,sDAAkG;AAClG,4CAAyC;AAElC,KAAK,UAAU,gBAAgB,CAAC,OAA+D;IACpG,eAAM,CAAC,MAAM,EAAE,CAAC;IAEhB,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,eAAM,CAAC,IAAI,CAAC,mEAAmE,CAAC,CAAC;QACjF,MAAM,IAAA,4BAAmB,EAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,OAAO;IACT,CAAC;IAED,MAAM,WAAW,GAAG,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAEjE,IAAI,CAAC,IAAA,4BAAc,EAAC,WAAW,CAAC,EAAE,CAAC;QACjC,eAAM,CAAC,IAAI,CAAC,8BAA8B,WAAW,EAAE,CAAC,CAAC;QAEzD,MAAM,MAAM,GAAG,MAAM,kBAAQ,CAAC,MAAM,CAAC;YACnC;gBACE,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,iFAAiF;gBAC1F,OAAO,EAAE,IAAI;aACd;SACF,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,MAAM,IAAA,4BAAmB,EAAC,EAAE,MAAM,EAAE,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAC/E,OAAO;QACT,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,qDAAqD;IACrD,IAAI,MAAM,GAAG,IAAA,mBAAU,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,IAAA,4BAAc,EAAC,cAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,wBAAwB,CAAC,CAAC,EAAE,CAAC;QAC3F,eAAM,CAAC,IAAI,CAAC,gEAAgE,CAAC,CAAC;QAC9E,MAAM,GAAG,IAAA,oCAAmB,EAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,eAAM,CAAC,IAAI,CAAC,8BAA8B,WAAW,EAAE,CAAC,CAAC;IACzD,MAAM,WAAW,GAAG,IAAA,0BAAY,EAAC,WAAW,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,IAAA,iCAAgB,EAAC,WAAW,CAAC,CAAC;IAE7C,MAAM,aAAa,GAAG,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,IAAI,SAAS,CAAC;IACnF,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM;QAC9B,CAAC,CAAC,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC;QAC7C,CAAC,CAAC,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa,CAAC,WAAW,EAAE,CAAC,CAAC;IAE/E,IAAA,2BAAa,EAAC,SAAS,CAAC,CAAC;IACzB,eAAM,CAAC,IAAI,CAAC,0CAA0C,SAAS,EAAE,CAAC,CAAC;IAEnE,kCAAkC;IAClC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,IAAA,6BAAiB,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9E,MAAM,gBAAgB,GAAG,GAAG,aAAa,CAAC,WAAW,EAAE,cAAc,CAAC;IAEtE,IAAA,2BAAa,EAAC,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,EAAE,WAAW,CAAC,CAAC;IACnE,IAAA,2BAAa,EAAC,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,aAAa,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,WAAW,CAAC,CAAC;IAChG,IAAA,2BAAa,EAAC,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,aAAa,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IACtE,eAAM,CAAC,OAAO,CAAC,0BAA0B,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,EAAE,CAAC,CAAC;IAEnF,iDAAiD;IACjD,MAAM,UAAU,GAAG,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACnD,IAAA,2BAAa,EAAC,UAAU,CAAC,CAAC;IAE1B,MAAM,OAAO,GAAG,IAAA,yBAAe,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;QACtC,IAAA,2BAAa,EAAC,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IACH,eAAM,CAAC,OAAO,CAAC,0CAA0C,UAAU,EAAE,CAAC,CAAC;IAEvE,eAAM,CAAC,MAAM,EAAE,CAAC;IAChB,eAAM,CAAC,OAAO,CAAC,4DAA4D,SAAS,GAAG,CAAC,CAAC;IACzF,eAAM,CAAC,IAAI,CAAC,wCAAwC,gBAAgB,+BAA+B,CAAC,CAAC;AACvG,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAWA,wBAAsB,mBAAmB,CAAC,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiIrH"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* ==========================================================================
|
|
3
|
+
gherkin-ai-cli - 'create' Command Handler (Localized Interactive Spec Wizard)
|
|
4
|
+
========================================================================== */
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.handleCreateCommand = handleCreateCommand;
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
12
|
+
const add_1 = require("./add");
|
|
13
|
+
const i18n_cli_1 = require("../utils/i18n-cli");
|
|
14
|
+
const file_system_1 = require("../utils/file-system");
|
|
15
|
+
const logger_1 = require("../utils/logger");
|
|
16
|
+
async function handleCreateCommand(options) {
|
|
17
|
+
logger_1.logger.banner();
|
|
18
|
+
const locale = await (0, i18n_cli_1.ensureCliLanguage)(options.lang);
|
|
19
|
+
const isEs = locale === 'es';
|
|
20
|
+
logger_1.logger.info(isEs ? 'Asistente Interactivo Gherkin - Creación paso a paso' : 'Interactive Gherkin Spec Wizard - Step-by-step feature creator');
|
|
21
|
+
const answers = await inquirer_1.default.prompt([
|
|
22
|
+
{
|
|
23
|
+
type: 'input',
|
|
24
|
+
name: 'featureName',
|
|
25
|
+
message: (0, i18n_cli_1.t)('featureNamePrompt', locale),
|
|
26
|
+
default: isEs ? 'Autenticación de Doble Factor 2FA' : 'Two Factor Authentication 2FA',
|
|
27
|
+
validate: (input) => input.trim().length > 0 || 'Name cannot be empty.'
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
type: 'input',
|
|
31
|
+
name: 'actor',
|
|
32
|
+
message: (0, i18n_cli_1.t)('actorPrompt', locale),
|
|
33
|
+
default: isEs ? 'usuario autenticado del sistema' : 'authenticated system user'
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
type: 'input',
|
|
37
|
+
name: 'action',
|
|
38
|
+
message: (0, i18n_cli_1.t)('actionPrompt', locale),
|
|
39
|
+
default: isEs ? 'habilitar y verificar un código OTP de dos factores' : 'enable and verify a two-factor OTP code'
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
type: 'input',
|
|
43
|
+
name: 'outcome',
|
|
44
|
+
message: (0, i18n_cli_1.t)('outcomePrompt', locale),
|
|
45
|
+
default: isEs ? 'proteger mi cuenta contra accesos no autorizados' : 'protect my account against unauthorized access'
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
type: 'input',
|
|
49
|
+
name: 'scenarioName',
|
|
50
|
+
message: (0, i18n_cli_1.t)('scenarioNamePrompt', locale),
|
|
51
|
+
default: isEs ? 'Habilitar y verificar código 2FA exitosamente' : 'Enable and verify 2FA code successfully'
|
|
52
|
+
}
|
|
53
|
+
]);
|
|
54
|
+
const steps = [];
|
|
55
|
+
console.log(isEs ? '\n--- Asistente de Pasos Gherkin (Dado / Cuando / Entonces) ---' : '\n--- Step-by-step Gherkin Scenario Builder (Given / When / Then) ---');
|
|
56
|
+
let addMore = true;
|
|
57
|
+
let defaultKw = isEs ? 'Dado' : 'Given';
|
|
58
|
+
const choicesEn = ['Given', 'When', 'Then', 'And', 'But'];
|
|
59
|
+
const choicesEs = ['Dado', 'Cuando', 'Entonces', 'Y', 'Pero'];
|
|
60
|
+
while (addMore) {
|
|
61
|
+
const stepAnswers = await inquirer_1.default.prompt([
|
|
62
|
+
{
|
|
63
|
+
type: 'list',
|
|
64
|
+
name: 'keyword',
|
|
65
|
+
message: (0, i18n_cli_1.t)('stepKeywordPrompt', locale),
|
|
66
|
+
choices: isEs ? choicesEs : choicesEn,
|
|
67
|
+
default: defaultKw
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
type: 'input',
|
|
71
|
+
name: 'text',
|
|
72
|
+
message: (0, i18n_cli_1.t)('stepDescPrompt', locale),
|
|
73
|
+
validate: (input) => input.trim().length > 0 || 'Description cannot be empty.'
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
type: 'confirm',
|
|
77
|
+
name: 'next',
|
|
78
|
+
message: (0, i18n_cli_1.t)('addAnotherStepPrompt', locale),
|
|
79
|
+
default: true
|
|
80
|
+
}
|
|
81
|
+
]);
|
|
82
|
+
steps.push({ keyword: stepAnswers.keyword, text: stepAnswers.text });
|
|
83
|
+
if (['Dado', 'Given'].includes(stepAnswers.keyword))
|
|
84
|
+
defaultKw = isEs ? 'Cuando' : 'When';
|
|
85
|
+
else if (['Cuando', 'When'].includes(stepAnswers.keyword))
|
|
86
|
+
defaultKw = isEs ? 'Entonces' : 'Then';
|
|
87
|
+
else
|
|
88
|
+
defaultKw = isEs ? 'Y' : 'And';
|
|
89
|
+
addMore = stepAnswers.next;
|
|
90
|
+
}
|
|
91
|
+
// Construct Gherkin File Content
|
|
92
|
+
const featureKw = isEs ? 'Característica:' : 'Feature:';
|
|
93
|
+
const asKw = isEs ? 'Como' : 'As a';
|
|
94
|
+
const wantKw = isEs ? 'Quiero' : 'I want to';
|
|
95
|
+
const soKw = isEs ? 'Para' : 'So that';
|
|
96
|
+
const scKw = isEs ? 'Escenario:' : 'Scenario:';
|
|
97
|
+
let gherkinContent = `${featureKw} ${answers.featureName}\n`;
|
|
98
|
+
gherkinContent += ` ${asKw} ${answers.actor}\n`;
|
|
99
|
+
gherkinContent += ` ${wantKw} ${answers.action}\n`;
|
|
100
|
+
gherkinContent += ` ${soKw} ${answers.outcome}\n\n`;
|
|
101
|
+
gherkinContent += ` ${scKw} ${answers.scenarioName}\n`;
|
|
102
|
+
steps.forEach(st => {
|
|
103
|
+
gherkinContent += ` ${st.keyword} ${st.text}\n`;
|
|
104
|
+
});
|
|
105
|
+
const defaultFileName = answers.featureName.toLowerCase().replace(/[^a-z0-9]/g, '_') + '.feature';
|
|
106
|
+
const targetSpecPath = options.output
|
|
107
|
+
? path_1.default.resolve(process.cwd(), options.output)
|
|
108
|
+
: path_1.default.resolve(process.cwd(), 'specs', defaultFileName);
|
|
109
|
+
(0, file_system_1.writeFileSync)(targetSpecPath, gherkinContent);
|
|
110
|
+
logger_1.logger.success(`${(0, i18n_cli_1.t)('specCreated', locale)} ${targetSpecPath}`);
|
|
111
|
+
console.log('\n------------------------------------------------------------');
|
|
112
|
+
console.log(gherkinContent);
|
|
113
|
+
console.log('------------------------------------------------------------\n');
|
|
114
|
+
// Prompt to immediately inject contracts into project
|
|
115
|
+
const injectAnswer = await inquirer_1.default.prompt([
|
|
116
|
+
{
|
|
117
|
+
type: 'confirm',
|
|
118
|
+
name: 'inject',
|
|
119
|
+
message: (0, i18n_cli_1.t)('injectPrompt', locale),
|
|
120
|
+
default: true
|
|
121
|
+
}
|
|
122
|
+
]);
|
|
123
|
+
if (injectAnswer.inject) {
|
|
124
|
+
await (0, add_1.handleAddCommand)({
|
|
125
|
+
feature: targetSpecPath,
|
|
126
|
+
target: options.target
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lang.d.ts","sourceRoot":"","sources":["../../src/commands/lang.ts"],"names":[],"mappings":"AAQA,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BhF"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* ==========================================================================
|
|
3
|
+
gherkin-ai-cli - 'lang' Command Handler (Language Switcher)
|
|
4
|
+
========================================================================== */
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.handleLangCommand = handleLangCommand;
|
|
10
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
11
|
+
const i18n_cli_1 = require("../utils/i18n-cli");
|
|
12
|
+
const logger_1 = require("../utils/logger");
|
|
13
|
+
async function handleLangCommand(options) {
|
|
14
|
+
logger_1.logger.banner();
|
|
15
|
+
if (options.set === 'en' || options.set === 'es') {
|
|
16
|
+
(0, i18n_cli_1.saveGlobalUserLocale)(options.set);
|
|
17
|
+
logger_1.logger.success((0, i18n_cli_1.t)('langUpdated', options.set));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const current = (0, i18n_cli_1.getGlobalUserLocale)() || 'en';
|
|
21
|
+
logger_1.logger.info(`${(0, i18n_cli_1.t)('langCurrent', current)} ${current === 'es' ? '🇪🇸 Español' : '🇺🇸 English'}`);
|
|
22
|
+
const answer = await inquirer_1.default.prompt([
|
|
23
|
+
{
|
|
24
|
+
type: 'list',
|
|
25
|
+
name: 'locale',
|
|
26
|
+
message: (0, i18n_cli_1.t)('selectLanguagePrompt', current),
|
|
27
|
+
choices: [
|
|
28
|
+
{ name: '🇺🇸 English', value: 'en' },
|
|
29
|
+
{ name: '🇪🇸 Español', value: 'es' }
|
|
30
|
+
],
|
|
31
|
+
default: current
|
|
32
|
+
}
|
|
33
|
+
]);
|
|
34
|
+
const selected = answer.locale;
|
|
35
|
+
(0, i18n_cli_1.saveGlobalUserLocale)(selected);
|
|
36
|
+
logger_1.logger.success((0, i18n_cli_1.t)('langUpdated', selected));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lang.js","sourceRoot":"","sources":["../../src/commands/lang.ts"],"names":[],"mappings":";AAAA;;gFAEgF;;;;;AAMhF,8CA4BC;AAhCD,wDAAgC;AAChC,gDAAqH;AACrH,4CAAyC;AAElC,KAAK,UAAU,iBAAiB,CAAC,OAAyB;IAC/D,eAAM,CAAC,MAAM,EAAE,CAAC;IAEhB,IAAI,OAAO,CAAC,GAAG,KAAK,IAAI,IAAI,OAAO,CAAC,GAAG,KAAK,IAAI,EAAE,CAAC;QACjD,IAAA,+BAAoB,EAAC,OAAO,CAAC,GAAsB,CAAC,CAAC;QACrD,eAAM,CAAC,OAAO,CAAC,IAAA,YAAC,EAAC,aAAa,EAAE,OAAO,CAAC,GAAsB,CAAC,CAAC,CAAC;QACjE,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,IAAA,8BAAmB,GAAE,IAAI,IAAI,CAAC;IAC9C,eAAM,CAAC,IAAI,CAAC,GAAG,IAAA,YAAC,EAAC,aAAa,EAAE,OAAO,CAAC,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC;IAElG,MAAM,MAAM,GAAG,MAAM,kBAAQ,CAAC,MAAM,CAAC;QACnC;YACE,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,IAAA,YAAC,EAAC,sBAAsB,EAAE,OAAO,CAAC;YAC3C,OAAO,EAAE;gBACP,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,IAAI,EAAE;gBACrC,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,IAAI,EAAE;aACtC;YACD,OAAO,EAAE,OAAO;SACjB;KACF,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAyB,CAAC;IAClD,IAAA,+BAAoB,EAAC,QAAQ,CAAC,CAAC;IAC/B,eAAM,CAAC,OAAO,CAAC,IAAA,YAAC,EAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stack-detector.d.ts","sourceRoot":"","sources":["../../src/core/stack-detector.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"stack-detector.d.ts","sourceRoot":"","sources":["../../src/core/stack-detector.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,eAAe,EAAiB,MAAM,UAAU,CAAC;AAE1D,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,MAAsB,GAAG,eAAe,CAmNpF"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/* ==========================================================================
|
|
3
|
-
gherkin-ai-cli - Stack & Architecture Auto-Detector
|
|
3
|
+
gherkin-ai-cli - Multi-Language Stack & Architecture Auto-Detector
|
|
4
|
+
Supports: PHP/Laravel, Ruby/Rails, C#/.NET, Java/Spring, Python/Django/FastAPI,
|
|
5
|
+
Go, Node/Nest/Express, Angular, Ionic, React, Vue, Svelte, Flutter.
|
|
4
6
|
========================================================================== */
|
|
5
7
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
8
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
@@ -19,84 +21,196 @@ function detectExistingStack(rootDir = process.cwd()) {
|
|
|
19
21
|
rules: { ...config_1.defaultConfig.rules },
|
|
20
22
|
outputDir: './src'
|
|
21
23
|
};
|
|
22
|
-
const
|
|
24
|
+
const gemfilePath = path_1.default.join(rootDir, 'Gemfile');
|
|
25
|
+
const composerJsonPath = path_1.default.join(rootDir, 'composer.json');
|
|
26
|
+
const artisanPath = path_1.default.join(rootDir, 'artisan');
|
|
27
|
+
const goModPath = path_1.default.join(rootDir, 'go.mod');
|
|
23
28
|
const pyProjectPath = path_1.default.join(rootDir, 'pyproject.toml');
|
|
24
29
|
const reqTxtPath = path_1.default.join(rootDir, 'requirements.txt');
|
|
30
|
+
const managePyPath = path_1.default.join(rootDir, 'manage.py');
|
|
25
31
|
const pomXmlPath = path_1.default.join(rootDir, 'pom.xml');
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
const buildGradlePath = path_1.default.join(rootDir, 'build.gradle');
|
|
33
|
+
const angularJsonPath = path_1.default.join(rootDir, 'angular.json');
|
|
34
|
+
const pubspecPath = path_1.default.join(rootDir, 'pubspec.yaml');
|
|
35
|
+
const packageJsonPath = path_1.default.join(rootDir, 'package.json');
|
|
36
|
+
// 1. Ruby on Rails Stack Detection
|
|
37
|
+
if ((0, file_system_1.fileExistsSync)(gemfilePath)) {
|
|
38
|
+
detected.stack.language = 'ruby';
|
|
39
|
+
detected.stack.framework = 'rails';
|
|
40
|
+
detected.stack.orm = 'active-record';
|
|
41
|
+
detected.stack.database = 'postgresql';
|
|
42
|
+
detected.stack.validation = 'active-model-validations';
|
|
43
|
+
detected.stack.testing = 'rspec';
|
|
44
|
+
detected.architecture = 'monolith';
|
|
45
|
+
detected.outputDir = './app';
|
|
46
|
+
try {
|
|
47
|
+
const gemContent = (0, file_system_1.readFileSync)(gemfilePath);
|
|
48
|
+
if (gemContent.includes('rspec-rails'))
|
|
49
|
+
detected.stack.testing = 'rspec';
|
|
50
|
+
else
|
|
51
|
+
detected.stack.testing = 'minitest';
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Ignore
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// 2. C# / .NET / ASP.NET Core Stack Detection
|
|
58
|
+
else if ((0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'Program.cs')) || (0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'appsettings.json'))) {
|
|
59
|
+
detected.stack.language = 'csharp';
|
|
60
|
+
detected.stack.framework = 'dotnet-aspnetcore';
|
|
61
|
+
detected.stack.orm = 'entity-framework-core';
|
|
62
|
+
detected.stack.database = 'sql-server';
|
|
63
|
+
detected.stack.validation = 'fluent-validation';
|
|
64
|
+
detected.stack.testing = 'xunit';
|
|
65
|
+
}
|
|
66
|
+
// 3. PHP / Laravel Stack Detection
|
|
67
|
+
else if ((0, file_system_1.fileExistsSync)(artisanPath) || (0, file_system_1.fileExistsSync)(composerJsonPath)) {
|
|
68
|
+
detected.stack.language = 'php';
|
|
69
|
+
detected.stack.framework = 'laravel';
|
|
70
|
+
detected.stack.orm = 'eloquent';
|
|
71
|
+
detected.stack.database = 'postgresql';
|
|
72
|
+
detected.stack.validation = 'laravel-validation';
|
|
73
|
+
detected.stack.auth = 'laravel-sanctum';
|
|
74
|
+
detected.stack.testing = 'phpunit';
|
|
75
|
+
detected.architecture = 'monolith';
|
|
76
|
+
detected.outputDir = './app';
|
|
77
|
+
if ((0, file_system_1.fileExistsSync)(composerJsonPath)) {
|
|
78
|
+
try {
|
|
79
|
+
const raw = (0, file_system_1.readFileSync)(composerJsonPath);
|
|
80
|
+
const composer = JSON.parse(raw);
|
|
81
|
+
if (composer.name)
|
|
82
|
+
detected.projectName = composer.name.split('/')[1] || composer.name;
|
|
83
|
+
const reqs = { ...(composer.require || {}), ...(composer['require-dev'] || {}) };
|
|
84
|
+
if (reqs['pestphp/pest'])
|
|
85
|
+
detected.stack.testing = 'pest';
|
|
86
|
+
if (reqs['symfony/symfony']) {
|
|
87
|
+
detected.stack.framework = 'symfony';
|
|
88
|
+
detected.stack.orm = 'doctrine';
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
// Ignore
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// 4. Flutter / Dart Mobile Detection
|
|
97
|
+
else if ((0, file_system_1.fileExistsSync)(pubspecPath)) {
|
|
98
|
+
detected.stack.language = 'dart';
|
|
99
|
+
detected.stack.framework = 'flutter';
|
|
100
|
+
detected.stack.orm = 'sqflite';
|
|
101
|
+
detected.stack.database = 'sqlite';
|
|
102
|
+
detected.stack.validation = 'form-validation';
|
|
103
|
+
detected.stack.testing = 'flutter_test';
|
|
104
|
+
detected.outputDir = './lib';
|
|
105
|
+
}
|
|
106
|
+
// 5. Python Stack Detection (Django / FastAPI / Flask)
|
|
107
|
+
else if ((0, file_system_1.fileExistsSync)(managePyPath) || (0, file_system_1.fileExistsSync)(pyProjectPath) || (0, file_system_1.fileExistsSync)(reqTxtPath)) {
|
|
108
|
+
detected.stack.language = 'python';
|
|
109
|
+
detected.stack.testing = 'pytest';
|
|
110
|
+
detected.stack.database = 'postgresql';
|
|
111
|
+
if ((0, file_system_1.fileExistsSync)(managePyPath)) {
|
|
112
|
+
detected.stack.framework = 'django';
|
|
113
|
+
detected.stack.orm = 'django-orm';
|
|
114
|
+
detected.stack.validation = 'django-forms';
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
detected.stack.framework = 'fastapi';
|
|
118
|
+
detected.stack.orm = 'sqlalchemy';
|
|
119
|
+
detected.stack.validation = 'pydantic';
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// 6. Go Stack Detection
|
|
123
|
+
else if ((0, file_system_1.fileExistsSync)(goModPath)) {
|
|
124
|
+
detected.stack.language = 'go';
|
|
125
|
+
detected.stack.framework = 'gin';
|
|
126
|
+
detected.stack.orm = 'gorm';
|
|
127
|
+
detected.stack.database = 'postgresql';
|
|
128
|
+
detected.stack.validation = 'validator-v10';
|
|
129
|
+
detected.stack.testing = 'testing';
|
|
130
|
+
}
|
|
131
|
+
// 7. Java / Kotlin Stack Detection
|
|
132
|
+
else if ((0, file_system_1.fileExistsSync)(pomXmlPath) || (0, file_system_1.fileExistsSync)(buildGradlePath)) {
|
|
133
|
+
detected.stack.language = 'java';
|
|
134
|
+
detected.stack.framework = 'spring-boot';
|
|
135
|
+
detected.stack.orm = 'hibernate';
|
|
136
|
+
detected.stack.database = 'postgresql';
|
|
137
|
+
detected.stack.validation = 'jakarta-validation';
|
|
138
|
+
detected.stack.testing = 'junit';
|
|
139
|
+
}
|
|
140
|
+
// 8. Node.js / Frontend / Ionic / Angular / React / Vue Stack Detection
|
|
141
|
+
else if ((0, file_system_1.fileExistsSync)(packageJsonPath)) {
|
|
28
142
|
try {
|
|
29
143
|
const raw = (0, file_system_1.readFileSync)(packageJsonPath);
|
|
30
144
|
const pkg = JSON.parse(raw);
|
|
31
145
|
const allDeps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
32
146
|
if (pkg.name)
|
|
33
147
|
detected.projectName = pkg.name;
|
|
34
|
-
// Language
|
|
35
|
-
if (allDeps['typescript'] || (0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'tsconfig.json'))) {
|
|
148
|
+
// Language Detection (TypeScript if angular, tsconfig or typescript dep exists)
|
|
149
|
+
if (allDeps['typescript'] || (0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'tsconfig.json')) || (0, file_system_1.fileExistsSync)(angularJsonPath) || allDeps['@angular/core']) {
|
|
36
150
|
detected.stack.language = 'typescript';
|
|
37
151
|
}
|
|
38
152
|
else {
|
|
39
153
|
detected.stack.language = 'javascript';
|
|
40
154
|
}
|
|
41
|
-
//
|
|
42
|
-
if (allDeps['@
|
|
155
|
+
// Angular / Ionic Frontend Detection
|
|
156
|
+
if ((0, file_system_1.fileExistsSync)(angularJsonPath) || allDeps['@angular/core']) {
|
|
157
|
+
if (allDeps['@ionic/angular']) {
|
|
158
|
+
detected.stack.framework = 'ionic-angular';
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
detected.stack.framework = 'angular';
|
|
162
|
+
}
|
|
163
|
+
detected.stack.orm = 'http-client-rxjs';
|
|
164
|
+
detected.stack.database = 'localstorage-indexeddb';
|
|
165
|
+
detected.stack.validation = 'angular-reactive-forms';
|
|
166
|
+
detected.stack.testing = 'jasmine-karma';
|
|
167
|
+
detected.architecture = 'modular';
|
|
168
|
+
detected.outputDir = './src/app';
|
|
169
|
+
}
|
|
170
|
+
// React Native Detection
|
|
171
|
+
else if (allDeps['react-native']) {
|
|
172
|
+
detected.stack.framework = 'react-native';
|
|
173
|
+
detected.stack.orm = 'async-storage';
|
|
174
|
+
detected.stack.database = 'sqlite-capacitor';
|
|
175
|
+
detected.stack.validation = 'zod';
|
|
176
|
+
detected.stack.testing = 'jest';
|
|
177
|
+
detected.architecture = 'modular';
|
|
178
|
+
}
|
|
179
|
+
// React / Next.js Frontend
|
|
180
|
+
else if (allDeps['react'] || allDeps['next']) {
|
|
181
|
+
detected.stack.framework = allDeps['next'] ? 'nextjs' : 'react';
|
|
182
|
+
detected.stack.orm = allDeps['prisma'] ? 'prisma' : 'tanstack-query';
|
|
183
|
+
detected.stack.database = 'postgresql';
|
|
184
|
+
detected.stack.validation = 'zod';
|
|
185
|
+
detected.stack.testing = 'vitest';
|
|
186
|
+
}
|
|
187
|
+
// Vue / Nuxt Frontend
|
|
188
|
+
else if (allDeps['vue'] || allDeps['nuxt']) {
|
|
189
|
+
detected.stack.framework = allDeps['nuxt'] ? 'nuxtjs' : 'vue';
|
|
190
|
+
detected.stack.orm = 'pinia-axios';
|
|
191
|
+
detected.stack.database = 'localstorage';
|
|
192
|
+
detected.stack.validation = 'vee-validate';
|
|
193
|
+
detected.stack.testing = 'vitest';
|
|
194
|
+
}
|
|
195
|
+
// Node.js Backend Frameworks (NestJS, Express, Fastify)
|
|
196
|
+
else if (allDeps['@nestjs/core']) {
|
|
43
197
|
detected.stack.framework = 'nestjs';
|
|
44
|
-
|
|
198
|
+
detected.stack.orm = allDeps['prisma'] ? 'prisma' : 'typeorm';
|
|
199
|
+
detected.stack.validation = 'zod';
|
|
200
|
+
detected.stack.testing = 'jest';
|
|
201
|
+
}
|
|
202
|
+
else if (allDeps['express']) {
|
|
45
203
|
detected.stack.framework = 'express';
|
|
46
|
-
|
|
47
|
-
detected.stack.framework = 'fastify';
|
|
48
|
-
else if (allDeps['next'])
|
|
49
|
-
detected.stack.framework = 'nextjs';
|
|
50
|
-
// ORM / Persistence
|
|
51
|
-
if (allDeps['prisma'] || (0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'prisma', 'schema.prisma')))
|
|
52
|
-
detected.stack.orm = 'prisma';
|
|
53
|
-
else if (allDeps['typeorm'])
|
|
54
|
-
detected.stack.orm = 'typeorm';
|
|
55
|
-
else if (allDeps['sequelize'])
|
|
56
|
-
detected.stack.orm = 'sequelize';
|
|
57
|
-
else if (allDeps['mongoose'])
|
|
58
|
-
detected.stack.orm = 'mongoose';
|
|
59
|
-
// Database
|
|
60
|
-
if (allDeps['pg'] || allDeps['postgres'] || allDeps['@prisma/client'])
|
|
61
|
-
detected.stack.database = 'postgresql';
|
|
62
|
-
else if (allDeps['mongodb'] || allDeps['mongoose'])
|
|
63
|
-
detected.stack.database = 'mongodb';
|
|
64
|
-
else if (allDeps['redis'] || allDeps['ioredis'])
|
|
65
|
-
detected.stack.database = 'redis';
|
|
66
|
-
// Validation
|
|
67
|
-
if (allDeps['zod'])
|
|
204
|
+
detected.stack.orm = allDeps['prisma'] ? 'prisma' : 'sequelize';
|
|
68
205
|
detected.stack.validation = 'zod';
|
|
69
|
-
else if (allDeps['class-validator'])
|
|
70
|
-
detected.stack.validation = 'class-validator';
|
|
71
|
-
else if (allDeps['joi'])
|
|
72
|
-
detected.stack.validation = 'joi';
|
|
73
|
-
// Testing
|
|
74
|
-
if (allDeps['jest'])
|
|
75
206
|
detected.stack.testing = 'jest';
|
|
76
|
-
|
|
77
|
-
detected.stack.testing = 'vitest';
|
|
207
|
+
}
|
|
78
208
|
}
|
|
79
209
|
catch {
|
|
80
210
|
// Ignore JSON parse errors
|
|
81
211
|
}
|
|
82
212
|
}
|
|
83
|
-
//
|
|
84
|
-
else if ((0, file_system_1.fileExistsSync)(pyProjectPath) || (0, file_system_1.fileExistsSync)(reqTxtPath)) {
|
|
85
|
-
detected.stack.language = 'python';
|
|
86
|
-
detected.stack.framework = 'fastapi';
|
|
87
|
-
detected.stack.orm = 'sqlalchemy';
|
|
88
|
-
detected.stack.validation = 'pydantic';
|
|
89
|
-
detected.stack.testing = 'pytest';
|
|
90
|
-
}
|
|
91
|
-
// 3. Java Stack Detection
|
|
92
|
-
else if ((0, file_system_1.fileExistsSync)(pomXmlPath)) {
|
|
93
|
-
detected.stack.language = 'java';
|
|
94
|
-
detected.stack.framework = 'spring-boot';
|
|
95
|
-
detected.stack.orm = 'hibernate';
|
|
96
|
-
detected.stack.validation = 'jakarta-validation';
|
|
97
|
-
detected.stack.testing = 'junit';
|
|
98
|
-
}
|
|
99
|
-
// 4. Architecture Style Heuristic Detection
|
|
213
|
+
// 9. Architecture Style Heuristic Detection
|
|
100
214
|
if ((0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'src', 'domain')) && (0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'src', 'ports'))) {
|
|
101
215
|
detected.architecture = 'hexagonal';
|
|
102
216
|
}
|
|
@@ -106,7 +220,10 @@ function detectExistingStack(rootDir = process.cwd()) {
|
|
|
106
220
|
else if ((0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'serverless.yml'))) {
|
|
107
221
|
detected.architecture = 'serverless';
|
|
108
222
|
}
|
|
109
|
-
else if ((0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, '
|
|
223
|
+
else if ((0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'app', 'Http', 'Controllers')) || (0, file_system_1.fileExistsSync)(artisanPath)) {
|
|
224
|
+
detected.architecture = 'monolith';
|
|
225
|
+
}
|
|
226
|
+
else if ((0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'src', 'modules')) || (0, file_system_1.fileExistsSync)(path_1.default.join(rootDir, 'src', 'app'))) {
|
|
110
227
|
detected.architecture = 'modular';
|
|
111
228
|
}
|
|
112
229
|
return detected;
|