vonosan-cli 0.1.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/__tests__/env-parity.pbt.test.d.ts +15 -0
- package/dist/__tests__/env-parity.pbt.test.d.ts.map +1 -0
- package/dist/__tests__/env-parity.pbt.test.js +125 -0
- package/dist/__tests__/env-parity.pbt.test.js.map +1 -0
- package/dist/__tests__/module-generator.pbt.test.d.ts +15 -0
- package/dist/__tests__/module-generator.pbt.test.d.ts.map +1 -0
- package/dist/__tests__/module-generator.pbt.test.js +130 -0
- package/dist/__tests__/module-generator.pbt.test.js.map +1 -0
- package/dist/commands/add.d.ts +21 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +128 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/audit.d.ts +18 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +73 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/branch-finish.d.ts +19 -0
- package/dist/commands/branch-finish.d.ts.map +1 -0
- package/dist/commands/branch-finish.js +80 -0
- package/dist/commands/branch-finish.js.map +1 -0
- package/dist/commands/branch-new.d.ts +17 -0
- package/dist/commands/branch-new.d.ts.map +1 -0
- package/dist/commands/branch-new.js +70 -0
- package/dist/commands/branch-new.js.map +1 -0
- package/dist/commands/commit.d.ts +21 -0
- package/dist/commands/commit.d.ts.map +1 -0
- package/dist/commands/commit.js +79 -0
- package/dist/commands/commit.js.map +1 -0
- package/dist/commands/db.d.ts +28 -0
- package/dist/commands/db.d.ts.map +1 -0
- package/dist/commands/db.js +83 -0
- package/dist/commands/db.js.map +1 -0
- package/dist/commands/env-add.d.ts +17 -0
- package/dist/commands/env-add.d.ts.map +1 -0
- package/dist/commands/env-add.js +73 -0
- package/dist/commands/env-add.js.map +1 -0
- package/dist/commands/fix-headers.d.ts +15 -0
- package/dist/commands/fix-headers.d.ts.map +1 -0
- package/dist/commands/fix-headers.js +37 -0
- package/dist/commands/fix-headers.js.map +1 -0
- package/dist/commands/fix-logs.d.ts +15 -0
- package/dist/commands/fix-logs.d.ts.map +1 -0
- package/dist/commands/fix-logs.js +87 -0
- package/dist/commands/fix-logs.js.map +1 -0
- package/dist/commands/jobs.d.ts +17 -0
- package/dist/commands/jobs.d.ts.map +1 -0
- package/dist/commands/jobs.js +107 -0
- package/dist/commands/jobs.js.map +1 -0
- package/dist/commands/lint.d.ts +15 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +49 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/make.d.ts +31 -0
- package/dist/commands/make.d.ts.map +1 -0
- package/dist/commands/make.js +176 -0
- package/dist/commands/make.js.map +1 -0
- package/dist/commands/migrate.d.ts +43 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +120 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/schema-sync.d.ts +17 -0
- package/dist/commands/schema-sync.d.ts.map +1 -0
- package/dist/commands/schema-sync.js +48 -0
- package/dist/commands/schema-sync.js.map +1 -0
- package/dist/commands/test.d.ts +19 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +113 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/commands/upgrade.d.ts +24 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +177 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/generators/deployment/docker-compose.d.ts +20 -0
- package/dist/generators/deployment/docker-compose.d.ts.map +1 -0
- package/dist/generators/deployment/docker-compose.js +95 -0
- package/dist/generators/deployment/docker-compose.js.map +1 -0
- package/dist/generators/deployment/dockerfile.d.ts +18 -0
- package/dist/generators/deployment/dockerfile.d.ts.map +1 -0
- package/dist/generators/deployment/dockerfile.js +99 -0
- package/dist/generators/deployment/dockerfile.js.map +1 -0
- package/dist/generators/deployment/pm2.d.ts +17 -0
- package/dist/generators/deployment/pm2.d.ts.map +1 -0
- package/dist/generators/deployment/pm2.js +59 -0
- package/dist/generators/deployment/pm2.js.map +1 -0
- package/dist/generators/deployment/secrets.d.ts +19 -0
- package/dist/generators/deployment/secrets.d.ts.map +1 -0
- package/dist/generators/deployment/secrets.js +41 -0
- package/dist/generators/deployment/secrets.js.map +1 -0
- package/dist/generators/deployment/shutdown.d.ts +17 -0
- package/dist/generators/deployment/shutdown.d.ts.map +1 -0
- package/dist/generators/deployment/shutdown.js +61 -0
- package/dist/generators/deployment/shutdown.js.map +1 -0
- package/dist/generators/deployment/wrangler.d.ts +25 -0
- package/dist/generators/deployment/wrangler.d.ts.map +1 -0
- package/dist/generators/deployment/wrangler.js +93 -0
- package/dist/generators/deployment/wrangler.js.map +1 -0
- package/dist/generators/file-generators.d.ts +38 -0
- package/dist/generators/file-generators.d.ts.map +1 -0
- package/dist/generators/file-generators.js +546 -0
- package/dist/generators/file-generators.js.map +1 -0
- package/dist/generators/module-generator.d.ts +33 -0
- package/dist/generators/module-generator.d.ts.map +1 -0
- package/dist/generators/module-generator.js +61 -0
- package/dist/generators/module-generator.js.map +1 -0
- package/dist/header-generator.d.ts +34 -0
- package/dist/header-generator.d.ts.map +1 -0
- package/dist/header-generator.js +77 -0
- package/dist/header-generator.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +177 -0
- package/dist/index.js.map +1 -0
- package/dist/linter/env-parity.d.ts +28 -0
- package/dist/linter/env-parity.d.ts.map +1 -0
- package/dist/linter/env-parity.js +59 -0
- package/dist/linter/env-parity.js.map +1 -0
- package/dist/linter.d.ts +23 -0
- package/dist/linter.d.ts.map +1 -0
- package/dist/linter.js +207 -0
- package/dist/linter.js.map +1 -0
- package/package.json +32 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ──────────────────────────────────────────────────────────────────
|
|
3
|
+
* 🏢 Company Name: Bonifade Technologies
|
|
4
|
+
* 👨💻 Developer: Bowofade Oyerinde
|
|
5
|
+
* 🐙 GitHub: oyenet1
|
|
6
|
+
* 📅 Created Date: 2026-04-05
|
|
7
|
+
* 🔄 Updated Date: 2026-04-05
|
|
8
|
+
* ──────────────────────────────────────────────────────────────────
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Generates the Bonifade Technologies file header comment string.
|
|
12
|
+
*
|
|
13
|
+
* @param _filePath - reserved for future per-file metadata (unused today)
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateHeader(_filePath: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Returns `true` when the file content already contains the Bonifade header.
|
|
18
|
+
*/
|
|
19
|
+
export declare function hasHeader(content: string): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Injects the Bonifade header at the top of `content` if it is missing.
|
|
22
|
+
* Preserves all existing content unchanged.
|
|
23
|
+
*
|
|
24
|
+
* @param filePath - path used to generate the header (passed to generateHeader)
|
|
25
|
+
* @param content - current file content
|
|
26
|
+
* @returns the (possibly modified) file content
|
|
27
|
+
*/
|
|
28
|
+
export declare function injectHeader(filePath: string, content: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Reads a file from disk, injects the header if missing, and writes it back.
|
|
31
|
+
* Returns `true` when the file was modified, `false` when it already had a header.
|
|
32
|
+
*/
|
|
33
|
+
export declare function fixHeaderInFile(filePath: string): boolean;
|
|
34
|
+
//# sourceMappingURL=header-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header-generator.d.ts","sourceRoot":"","sources":["../src/header-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAcH;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAaxD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAElD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAWtE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAMzD"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ──────────────────────────────────────────────────────────────────
|
|
3
|
+
* 🏢 Company Name: Bonifade Technologies
|
|
4
|
+
* 👨💻 Developer: Bowofade Oyerinde
|
|
5
|
+
* 🐙 GitHub: oyenet1
|
|
6
|
+
* 📅 Created Date: 2026-04-05
|
|
7
|
+
* 🔄 Updated Date: 2026-04-05
|
|
8
|
+
* ──────────────────────────────────────────────────────────────────
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
11
|
+
/** The canonical header marker — used to detect existing headers */
|
|
12
|
+
const HEADER_MARKER = '🏢 Company Name: Bonifade Technologies';
|
|
13
|
+
/**
|
|
14
|
+
* Returns today's date as YYYY-MM-DD.
|
|
15
|
+
*/
|
|
16
|
+
function today() {
|
|
17
|
+
return new Date().toISOString().slice(0, 10);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Generates the Bonifade Technologies file header comment string.
|
|
21
|
+
*
|
|
22
|
+
* @param _filePath - reserved for future per-file metadata (unused today)
|
|
23
|
+
*/
|
|
24
|
+
export function generateHeader(_filePath) {
|
|
25
|
+
const date = today();
|
|
26
|
+
return [
|
|
27
|
+
'/**',
|
|
28
|
+
' * ──────────────────────────────────────────────────────────────────',
|
|
29
|
+
' * 🏢 Company Name: Bonifade Technologies',
|
|
30
|
+
' * 👨💻 Developer: Bowofade Oyerinde',
|
|
31
|
+
' * 🐙 GitHub: oyenet1',
|
|
32
|
+
` * 📅 Created Date: ${date}`,
|
|
33
|
+
` * 🔄 Updated Date: ${date}`,
|
|
34
|
+
' * ──────────────────────────────────────────────────────────────────',
|
|
35
|
+
' */',
|
|
36
|
+
].join('\n');
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Returns `true` when the file content already contains the Bonifade header.
|
|
40
|
+
*/
|
|
41
|
+
export function hasHeader(content) {
|
|
42
|
+
return content.includes(HEADER_MARKER);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Injects the Bonifade header at the top of `content` if it is missing.
|
|
46
|
+
* Preserves all existing content unchanged.
|
|
47
|
+
*
|
|
48
|
+
* @param filePath - path used to generate the header (passed to generateHeader)
|
|
49
|
+
* @param content - current file content
|
|
50
|
+
* @returns the (possibly modified) file content
|
|
51
|
+
*/
|
|
52
|
+
export function injectHeader(filePath, content) {
|
|
53
|
+
if (hasHeader(content))
|
|
54
|
+
return content;
|
|
55
|
+
const header = generateHeader(filePath);
|
|
56
|
+
// Preserve a leading shebang line if present
|
|
57
|
+
if (content.startsWith('#!')) {
|
|
58
|
+
const newlineIdx = content.indexOf('\n');
|
|
59
|
+
const shebang = content.slice(0, newlineIdx + 1);
|
|
60
|
+
const rest = content.slice(newlineIdx + 1);
|
|
61
|
+
return `${shebang}${header}\n\n${rest}`;
|
|
62
|
+
}
|
|
63
|
+
return `${header}\n\n${content}`;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Reads a file from disk, injects the header if missing, and writes it back.
|
|
67
|
+
* Returns `true` when the file was modified, `false` when it already had a header.
|
|
68
|
+
*/
|
|
69
|
+
export function fixHeaderInFile(filePath) {
|
|
70
|
+
const original = readFileSync(filePath, 'utf8');
|
|
71
|
+
const updated = injectHeader(filePath, original);
|
|
72
|
+
if (updated === original)
|
|
73
|
+
return false;
|
|
74
|
+
writeFileSync(filePath, updated, 'utf8');
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=header-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header-generator.js","sourceRoot":"","sources":["../src/header-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAErD,oEAAoE;AACpE,MAAM,aAAa,GAAG,wCAAwC,CAAA;AAE9D;;GAEG;AACH,SAAS,KAAK;IACZ,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AAC9C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,MAAM,IAAI,GAAG,KAAK,EAAE,CAAA;IACpB,OAAO;QACL,KAAK;QACL,uEAAuE;QACvE,2CAA2C;QAC3C,uCAAuC;QACvC,uBAAuB;QACvB,uBAAuB,IAAI,EAAE;QAC7B,uBAAuB,IAAI,EAAE;QAC7B,uEAAuE;QACvE,KAAK;KACN,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,OAAO,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAA;AACxC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,OAAe;IAC5D,IAAI,SAAS,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAA;IACtC,MAAM,MAAM,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAA;IACvC,6CAA6C;IAC7C,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QACxC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,GAAG,CAAC,CAAC,CAAA;QAChD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC,CAAA;QAC1C,OAAO,GAAG,OAAO,GAAG,MAAM,OAAO,IAAI,EAAE,CAAA;IACzC,CAAC;IACD,OAAO,GAAG,MAAM,OAAO,OAAO,EAAE,CAAA;AAClC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IAC/C,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAChD,IAAI,OAAO,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IACtC,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;IACxC,OAAO,IAAI,CAAA;AACb,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ──────────────────────────────────────────────────────────────────
|
|
4
|
+
* 🏢 Company Name: Bonifade Technologies
|
|
5
|
+
* 👨💻 Developer: Bowofade Oyerinde
|
|
6
|
+
* 🐙 GitHub: oyenet1
|
|
7
|
+
* 📅 Created Date: 2026-04-05
|
|
8
|
+
* 🔄 Updated Date: 2026-04-05
|
|
9
|
+
* ──────────────────────────────────────────────────────────────────
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;GAQG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ──────────────────────────────────────────────────────────────────
|
|
4
|
+
* 🏢 Company Name: Bonifade Technologies
|
|
5
|
+
* 👨💻 Developer: Bowofade Oyerinde
|
|
6
|
+
* 🐙 GitHub: oyenet1
|
|
7
|
+
* 📅 Created Date: 2026-04-05
|
|
8
|
+
* 🔄 Updated Date: 2026-04-05
|
|
9
|
+
* ──────────────────────────────────────────────────────────────────
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* @vonosan/cli — Artisan-style CLI for the Vonosan framework.
|
|
13
|
+
*
|
|
14
|
+
* Command router: maps `vonosan <command>` to the appropriate handler.
|
|
15
|
+
*/
|
|
16
|
+
import { runLint } from './commands/lint.js';
|
|
17
|
+
import { runFixHeaders } from './commands/fix-headers.js';
|
|
18
|
+
import { runFixLogs } from './commands/fix-logs.js';
|
|
19
|
+
import { runAudit } from './commands/audit.js';
|
|
20
|
+
import { runEnvAdd } from './commands/env-add.js';
|
|
21
|
+
import { runBranchNew } from './commands/branch-new.js';
|
|
22
|
+
import { runBranchFinish } from './commands/branch-finish.js';
|
|
23
|
+
import { runCommit } from './commands/commit.js';
|
|
24
|
+
import { runMigrateRun, runMigrateRollback, runMigrateStatus, runMigrateReset, runMigrateFresh, runMigrateMake, } from './commands/migrate.js';
|
|
25
|
+
import { runDbPush, runDbStudio, runDbSeed } from './commands/db.js';
|
|
26
|
+
import { runSchemaSync } from './commands/schema-sync.js';
|
|
27
|
+
import { runMakeModule, runMakeVersion, runMakeService, runMakeController, runMakeDto, runMakeRoutes, runMakeSchema, runMakeMiddleware, runMakePage, runMakeComponent, runMakeComposable, runMakeStore, runMakeMigration, runMakeSeed, runMakeTest, runMakeNotification, runMakeResource, runMakePolicy, runMakeJob, runMakeEmail, runMakeHelper, } from './commands/make.js';
|
|
28
|
+
import { runAdd } from './commands/add.js';
|
|
29
|
+
import { runJobsRun } from './commands/jobs.js';
|
|
30
|
+
import { runUpgradeCheck, runUpgradeApply } from './commands/upgrade.js';
|
|
31
|
+
import { runTest, runTestClean } from './commands/test.js';
|
|
32
|
+
const COMMANDS = {
|
|
33
|
+
// Linting & auditing
|
|
34
|
+
lint: runLint,
|
|
35
|
+
'fix:headers': runFixHeaders,
|
|
36
|
+
'fix:logs': runFixLogs,
|
|
37
|
+
audit: runAudit,
|
|
38
|
+
// Environment
|
|
39
|
+
'env:add': runEnvAdd,
|
|
40
|
+
// Git automation
|
|
41
|
+
'branch:new': runBranchNew,
|
|
42
|
+
'branch:finish': runBranchFinish,
|
|
43
|
+
commit: runCommit,
|
|
44
|
+
// Migrations
|
|
45
|
+
'migrate:run': runMigrateRun,
|
|
46
|
+
'migrate:rollback': runMigrateRollback,
|
|
47
|
+
'migrate:status': runMigrateStatus,
|
|
48
|
+
'migrate:reset': runMigrateReset,
|
|
49
|
+
'migrate:fresh': runMigrateFresh,
|
|
50
|
+
'migrate:make': runMigrateMake,
|
|
51
|
+
// Database
|
|
52
|
+
'db:push': runDbPush,
|
|
53
|
+
'db:studio': runDbStudio,
|
|
54
|
+
'db:seed': runDbSeed,
|
|
55
|
+
// Schema
|
|
56
|
+
'schema:sync': runSchemaSync,
|
|
57
|
+
// Code generators
|
|
58
|
+
'make:module': runMakeModule,
|
|
59
|
+
'make:version': runMakeVersion,
|
|
60
|
+
'make:service': runMakeService,
|
|
61
|
+
'make:controller': runMakeController,
|
|
62
|
+
'make:dto': runMakeDto,
|
|
63
|
+
'make:routes': runMakeRoutes,
|
|
64
|
+
'make:schema': runMakeSchema,
|
|
65
|
+
'make:middleware': runMakeMiddleware,
|
|
66
|
+
'make:page': runMakePage,
|
|
67
|
+
'make:component': runMakeComponent,
|
|
68
|
+
'make:composable': runMakeComposable,
|
|
69
|
+
'make:store': runMakeStore,
|
|
70
|
+
'make:migration': runMakeMigration,
|
|
71
|
+
'make:seed': runMakeSeed,
|
|
72
|
+
'make:test': runMakeTest,
|
|
73
|
+
'make:notification': runMakeNotification,
|
|
74
|
+
'make:resource': runMakeResource,
|
|
75
|
+
'make:policy': runMakePolicy,
|
|
76
|
+
'make:job': runMakeJob,
|
|
77
|
+
'make:email': runMakeEmail,
|
|
78
|
+
'make:helper': runMakeHelper,
|
|
79
|
+
// Module installer
|
|
80
|
+
add: runAdd,
|
|
81
|
+
// Jobs
|
|
82
|
+
'jobs:run': runJobsRun,
|
|
83
|
+
// Upgrade
|
|
84
|
+
'upgrade:check': runUpgradeCheck,
|
|
85
|
+
'upgrade:apply-codemods': runUpgradeApply,
|
|
86
|
+
// Test
|
|
87
|
+
test: runTest,
|
|
88
|
+
'test:clean': runTestClean,
|
|
89
|
+
};
|
|
90
|
+
// ─── Help text ────────────────────────────────────────────────────────────────
|
|
91
|
+
function printHelp() {
|
|
92
|
+
process.stdout.write(`
|
|
93
|
+
\x1b[1mVono CLI\x1b[0m — Artisan-style tooling for the Vonosan framework
|
|
94
|
+
|
|
95
|
+
\x1b[33mUsage:\x1b[0m vonosan <command> [args] [options]
|
|
96
|
+
|
|
97
|
+
\x1b[33mLinting & Auditing:\x1b[0m
|
|
98
|
+
vonosan lint [src] Scan for header, log, naming, versioning, DRY violations
|
|
99
|
+
vonosan fix:headers [src] Inject missing Bonifade headers
|
|
100
|
+
vonosan fix:logs [src] Replace console.* with Logger.*
|
|
101
|
+
vonosan audit [--fix] Full audit; exits 0 (clean) or 1 (violations)
|
|
102
|
+
|
|
103
|
+
\x1b[33mEnvironment:\x1b[0m
|
|
104
|
+
vonosan env:add <KEY> [desc] Append key to .env and .env.example
|
|
105
|
+
|
|
106
|
+
\x1b[33mGit Automation:\x1b[0m
|
|
107
|
+
vonosan branch:new <name> Create feature/<name> branch
|
|
108
|
+
vonosan branch:finish Merge feature branch into parent
|
|
109
|
+
vonosan commit "<message>" Validate Conventional Commits and commit
|
|
110
|
+
|
|
111
|
+
\x1b[33mMigrations:\x1b[0m
|
|
112
|
+
vonosan migrate:run Apply pending migrations
|
|
113
|
+
vonosan migrate:rollback Roll back last migration
|
|
114
|
+
vonosan migrate:status Show migration status
|
|
115
|
+
vonosan migrate:reset Rollback all, then re-run
|
|
116
|
+
vonosan migrate:fresh [--seed] Drop all, re-run, optionally seed
|
|
117
|
+
vonosan migrate:make <name> Sync schema barrel + generate migration
|
|
118
|
+
|
|
119
|
+
\x1b[33mDatabase:\x1b[0m
|
|
120
|
+
vonosan db:push Push schema to DB (no migration file)
|
|
121
|
+
vonosan db:studio Open Drizzle Studio
|
|
122
|
+
vonosan db:seed [name] Run seed files
|
|
123
|
+
|
|
124
|
+
\x1b[33mSchema:\x1b[0m
|
|
125
|
+
vonosan schema:sync Regenerate src/db/schema.ts barrel
|
|
126
|
+
|
|
127
|
+
\x1b[33mCode Generators:\x1b[0m
|
|
128
|
+
vonosan make:module <name> Generate full module scaffold
|
|
129
|
+
vonosan make:version <v> Generate new API version namespace
|
|
130
|
+
vonosan make:service <name> Generate service file
|
|
131
|
+
vonosan make:controller <name> Generate controller file
|
|
132
|
+
vonosan make:dto <name> Generate DTO + Zod schema
|
|
133
|
+
vonosan make:routes <name> Generate routes file
|
|
134
|
+
vonosan make:schema <name> Generate Drizzle schema
|
|
135
|
+
vonosan make:middleware <name> Generate middleware
|
|
136
|
+
vonosan make:page <m/Page> Generate .page.vue
|
|
137
|
+
vonosan make:component <m/C> Generate Vue component
|
|
138
|
+
vonosan make:composable <m/use> Generate composable
|
|
139
|
+
vonosan make:store <name> Generate Pinia store
|
|
140
|
+
vonosan make:migration <name> Generate SQL migration file
|
|
141
|
+
vonosan make:seed <name> Generate seed file
|
|
142
|
+
vonosan make:test <name> Generate test file
|
|
143
|
+
vonosan make:notification <n> Generate notification
|
|
144
|
+
vonosan make:resource <name> Generate resource transformer
|
|
145
|
+
vonosan make:policy <name> Generate policy class
|
|
146
|
+
vonosan make:job <name> Generate cron job
|
|
147
|
+
vonosan make:email <name> Generate email template
|
|
148
|
+
vonosan make:helper <name> Generate shared helper
|
|
149
|
+
|
|
150
|
+
\x1b[33mModule Installer:\x1b[0m
|
|
151
|
+
vonosan add <module> Install @vonosan/<module> and update config
|
|
152
|
+
vonosan add <module> --eject Copy module source into src/modules/<module>/
|
|
153
|
+
|
|
154
|
+
\x1b[33mJobs:\x1b[0m
|
|
155
|
+
vonosan jobs:run <name> Execute a named cron job immediately
|
|
156
|
+
`);
|
|
157
|
+
}
|
|
158
|
+
// ─── Entry point ─────────────────────────────────────────────────────────────
|
|
159
|
+
async function main() {
|
|
160
|
+
const [, , command, ...args] = process.argv;
|
|
161
|
+
if (!command || command === '--help' || command === '-h' || command === 'help') {
|
|
162
|
+
printHelp();
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const handler = COMMANDS[command];
|
|
166
|
+
if (!handler) {
|
|
167
|
+
process.stderr.write(`\x1b[31mUnknown command: "${command}"\x1b[0m\n`);
|
|
168
|
+
process.stderr.write(`Run \x1b[1mvono --help\x1b[0m to see available commands.\n`);
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
await handler(args);
|
|
172
|
+
}
|
|
173
|
+
main().catch((err) => {
|
|
174
|
+
process.stderr.write(`\x1b[31mFatal error: ${String(err)}\x1b[0m\n`);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
});
|
|
177
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ──────────────────────────────────────────────────────────────────
|
|
3
|
+
* 🏢 Company Name: Bonifade Technologies
|
|
4
|
+
* 👨💻 Developer: Bowofade Oyerinde
|
|
5
|
+
* 🐙 GitHub: oyenet1
|
|
6
|
+
* 📅 Created Date: 2026-04-05
|
|
7
|
+
* 🔄 Updated Date: 2026-04-05
|
|
8
|
+
* ──────────────────────────────────────────────────────────────────
|
|
9
|
+
*/
|
|
10
|
+
export interface EnvParityResult {
|
|
11
|
+
/** Keys present in .env but missing from .env.example */
|
|
12
|
+
missingInExample: string[];
|
|
13
|
+
/** Keys present in .env.example but missing from .env */
|
|
14
|
+
missingInEnv: string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Parses an env file and returns the set of defined keys.
|
|
18
|
+
* Ignores blank lines and comment lines (starting with #).
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseEnvKeys(content: string): Set<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Compares `.env` and `.env.example` keys in `projectRoot`.
|
|
23
|
+
*
|
|
24
|
+
* Returns lists of keys missing from each file.
|
|
25
|
+
* If `.env` does not exist, returns empty lists (no error — per Requirement 8.4).
|
|
26
|
+
*/
|
|
27
|
+
export declare function checkEnvParity(projectRoot: string): EnvParityResult;
|
|
28
|
+
//# sourceMappingURL=env-parity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-parity.d.ts","sourceRoot":"","sources":["../../src/linter/env-parity.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,MAAM,WAAW,eAAe;IAC9B,yDAAyD;IACzD,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,yDAAyD;IACzD,YAAY,EAAE,MAAM,EAAE,CAAA;CACvB;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAWzD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,CAwBnE"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ──────────────────────────────────────────────────────────────────
|
|
3
|
+
* 🏢 Company Name: Bonifade Technologies
|
|
4
|
+
* 👨💻 Developer: Bowofade Oyerinde
|
|
5
|
+
* 🐙 GitHub: oyenet1
|
|
6
|
+
* 📅 Created Date: 2026-04-05
|
|
7
|
+
* 🔄 Updated Date: 2026-04-05
|
|
8
|
+
* ──────────────────────────────────────────────────────────────────
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
/**
|
|
13
|
+
* Parses an env file and returns the set of defined keys.
|
|
14
|
+
* Ignores blank lines and comment lines (starting with #).
|
|
15
|
+
*/
|
|
16
|
+
export function parseEnvKeys(content) {
|
|
17
|
+
const keys = new Set();
|
|
18
|
+
for (const line of content.split('\n')) {
|
|
19
|
+
const trimmed = line.trim();
|
|
20
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
21
|
+
continue;
|
|
22
|
+
const eqIdx = trimmed.indexOf('=');
|
|
23
|
+
if (eqIdx === -1)
|
|
24
|
+
continue;
|
|
25
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
26
|
+
if (key)
|
|
27
|
+
keys.add(key);
|
|
28
|
+
}
|
|
29
|
+
return keys;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Compares `.env` and `.env.example` keys in `projectRoot`.
|
|
33
|
+
*
|
|
34
|
+
* Returns lists of keys missing from each file.
|
|
35
|
+
* If `.env` does not exist, returns empty lists (no error — per Requirement 8.4).
|
|
36
|
+
*/
|
|
37
|
+
export function checkEnvParity(projectRoot) {
|
|
38
|
+
const envPath = join(projectRoot, '.env');
|
|
39
|
+
const examplePath = join(projectRoot, '.env.example');
|
|
40
|
+
if (!existsSync(envPath)) {
|
|
41
|
+
return { missingInExample: [], missingInEnv: [] };
|
|
42
|
+
}
|
|
43
|
+
const envKeys = parseEnvKeys(readFileSync(envPath, 'utf8'));
|
|
44
|
+
const exampleKeys = existsSync(examplePath)
|
|
45
|
+
? parseEnvKeys(readFileSync(examplePath, 'utf8'))
|
|
46
|
+
: new Set();
|
|
47
|
+
const missingInExample = [];
|
|
48
|
+
const missingInEnv = [];
|
|
49
|
+
for (const key of envKeys) {
|
|
50
|
+
if (!exampleKeys.has(key))
|
|
51
|
+
missingInExample.push(key);
|
|
52
|
+
}
|
|
53
|
+
for (const key of exampleKeys) {
|
|
54
|
+
if (!envKeys.has(key))
|
|
55
|
+
missingInEnv.push(key);
|
|
56
|
+
}
|
|
57
|
+
return { missingInExample, missingInEnv };
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=env-parity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-parity.js","sourceRoot":"","sources":["../../src/linter/env-parity.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAShC;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAC3B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAQ;QACjD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAClC,IAAI,KAAK,KAAK,CAAC,CAAC;YAAE,SAAQ;QAC1B,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAA;QAC1C,IAAI,GAAG;YAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACxB,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,WAAmB;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;IACzC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,EAAE,cAAc,CAAC,CAAA;IAErD,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,gBAAgB,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAA;IACnD,CAAC;IAED,MAAM,OAAO,GAAG,YAAY,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAA;IAC3D,MAAM,WAAW,GAAG,UAAU,CAAC,WAAW,CAAC;QACzC,CAAC,CAAC,YAAY,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACjD,CAAC,CAAC,IAAI,GAAG,EAAU,CAAA;IAErB,MAAM,gBAAgB,GAAa,EAAE,CAAA;IACrC,MAAM,YAAY,GAAa,EAAE,CAAA;IAEjC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACvD,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC/C,CAAC;IAED,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,CAAA;AAC3C,CAAC"}
|
package/dist/linter.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ──────────────────────────────────────────────────────────────────
|
|
3
|
+
* 🏢 Company Name: Bonifade Technologies
|
|
4
|
+
* 👨💻 Developer: Bowofade Oyerinde
|
|
5
|
+
* 🐙 GitHub: oyenet1
|
|
6
|
+
* 📅 Created Date: 2026-04-05
|
|
7
|
+
* 🔄 Updated Date: 2026-04-05
|
|
8
|
+
* ──────────────────────────────────────────────────────────────────
|
|
9
|
+
*/
|
|
10
|
+
export type LintRule = 'header-missing' | 'console-log' | 'naming-snake-case-response' | 'versioning-missing-prefix' | 'dry-violation';
|
|
11
|
+
export interface LintResult {
|
|
12
|
+
file: string;
|
|
13
|
+
line: number;
|
|
14
|
+
rule: LintRule;
|
|
15
|
+
message: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Scans all `.ts` and `.vue` files under `srcDir` and returns all lint violations.
|
|
19
|
+
*
|
|
20
|
+
* @param srcDir - absolute or relative path to the project's `src/` directory
|
|
21
|
+
*/
|
|
22
|
+
export declare function lintProject(srcDir: string): Promise<LintResult[]>;
|
|
23
|
+
//# sourceMappingURL=linter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linter.d.ts","sourceRoot":"","sources":["../src/linter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,MAAM,MAAM,QAAQ,GAChB,gBAAgB,GAChB,aAAa,GACb,4BAA4B,GAC5B,2BAA2B,GAC3B,eAAe,CAAA;AAEnB,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,QAAQ,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;CAChB;AAsLD;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAwBvE"}
|
package/dist/linter.js
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ──────────────────────────────────────────────────────────────────
|
|
3
|
+
* 🏢 Company Name: Bonifade Technologies
|
|
4
|
+
* 👨💻 Developer: Bowofade Oyerinde
|
|
5
|
+
* 🐙 GitHub: oyenet1
|
|
6
|
+
* 📅 Created Date: 2026-04-05
|
|
7
|
+
* 🔄 Updated Date: 2026-04-05
|
|
8
|
+
* ──────────────────────────────────────────────────────────────────
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
import { join, relative } from 'node:path';
|
|
12
|
+
import fg from 'fast-glob';
|
|
13
|
+
import { hasHeader } from './header-generator.js';
|
|
14
|
+
// ─── Individual rule checkers ─────────────────────────────────────────────────
|
|
15
|
+
/**
|
|
16
|
+
* Rule: every .ts / .vue file must start with the Bonifade header.
|
|
17
|
+
*/
|
|
18
|
+
function checkHeader(filePath, content) {
|
|
19
|
+
if (hasHeader(content))
|
|
20
|
+
return [];
|
|
21
|
+
return [
|
|
22
|
+
{
|
|
23
|
+
file: filePath,
|
|
24
|
+
line: 1,
|
|
25
|
+
rule: 'header-missing',
|
|
26
|
+
message: `Missing Bonifade Technologies file header. Run \`vonosan fix:headers\` to auto-fix.`,
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Rule: no raw console.log / console.warn / console.error / console.debug.
|
|
32
|
+
* Files containing `// @vonosan-ignore-logs` are skipped entirely.
|
|
33
|
+
*/
|
|
34
|
+
function checkConsoleLogs(filePath, content) {
|
|
35
|
+
if (content.includes('// @vonosan-ignore-logs'))
|
|
36
|
+
return [];
|
|
37
|
+
const results = [];
|
|
38
|
+
const lines = content.split('\n');
|
|
39
|
+
const consoleRe = /\bconsole\.(log|warn|error|debug|info)\s*\(/;
|
|
40
|
+
for (let i = 0; i < lines.length; i++) {
|
|
41
|
+
const line = lines[i];
|
|
42
|
+
// Skip the logger.ts file itself — it is the ONE allowed place
|
|
43
|
+
if (filePath.includes('logger.ts'))
|
|
44
|
+
continue;
|
|
45
|
+
if (consoleRe.test(line)) {
|
|
46
|
+
const match = line.match(consoleRe);
|
|
47
|
+
results.push({
|
|
48
|
+
file: filePath,
|
|
49
|
+
line: i + 1,
|
|
50
|
+
rule: 'console-log',
|
|
51
|
+
message: `Raw \`console.${match[1]}()\` detected. Use \`Logger.${match[1]}()\` from vonosan/server instead.`,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return results;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Rule: API response objects must not contain snake_case keys.
|
|
59
|
+
* Heuristic: looks for `{ some_key:` patterns inside return statements in
|
|
60
|
+
* controller / service files.
|
|
61
|
+
*/
|
|
62
|
+
function checkNamingConventions(filePath, content) {
|
|
63
|
+
// Only check controller / service files
|
|
64
|
+
if (!filePath.match(/\.(controller|service)\.ts$/))
|
|
65
|
+
return [];
|
|
66
|
+
const results = [];
|
|
67
|
+
const lines = content.split('\n');
|
|
68
|
+
// Matches object literal keys that are snake_case (contain underscore)
|
|
69
|
+
const snakeCaseKeyRe = /\b([a-z][a-z0-9]*(?:_[a-z0-9]+)+)\s*:/;
|
|
70
|
+
for (let i = 0; i < lines.length; i++) {
|
|
71
|
+
const line = lines[i];
|
|
72
|
+
const match = line.match(snakeCaseKeyRe);
|
|
73
|
+
if (match) {
|
|
74
|
+
results.push({
|
|
75
|
+
file: filePath,
|
|
76
|
+
line: i + 1,
|
|
77
|
+
rule: 'naming-snake-case-response',
|
|
78
|
+
message: `API response key \`${match[1]}\` uses snake_case. Convert to camelCase using \`toCamel()\`.`,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return results;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Rule: all routes must be nested under a versioned prefix like /api/v1/.
|
|
86
|
+
* Only checks *.routes.ts files.
|
|
87
|
+
*/
|
|
88
|
+
function checkVersioning(filePath, content) {
|
|
89
|
+
if (!filePath.endsWith('.routes.ts'))
|
|
90
|
+
return [];
|
|
91
|
+
const results = [];
|
|
92
|
+
const lines = content.split('\n');
|
|
93
|
+
// Matches route definitions that start with a path not under /api/v<n>
|
|
94
|
+
// e.g. app.get('/users', ...) — missing /api/v1 prefix
|
|
95
|
+
const routeDefRe = /\.(get|post|put|patch|delete|all)\s*\(\s*['"`](\/[^'"`]*)/;
|
|
96
|
+
for (let i = 0; i < lines.length; i++) {
|
|
97
|
+
const line = lines[i];
|
|
98
|
+
const match = line.match(routeDefRe);
|
|
99
|
+
if (match) {
|
|
100
|
+
const path = match[2];
|
|
101
|
+
if (!path.match(/^\/api\/v\d+/)) {
|
|
102
|
+
results.push({
|
|
103
|
+
file: filePath,
|
|
104
|
+
line: i + 1,
|
|
105
|
+
rule: 'versioning-missing-prefix',
|
|
106
|
+
message: `Route \`${path}\` is not nested under a versioned prefix (e.g. /api/v1/). All routes must be versioned.`,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return results;
|
|
112
|
+
}
|
|
113
|
+
// ─── DRY violation detector ───────────────────────────────────────────────────
|
|
114
|
+
/**
|
|
115
|
+
* Extracts function bodies from a TypeScript file.
|
|
116
|
+
* Returns a map of normalised body → list of { file, line }.
|
|
117
|
+
*/
|
|
118
|
+
function extractFunctionBodies(filePath, content) {
|
|
119
|
+
const bodies = new Map();
|
|
120
|
+
const lines = content.split('\n');
|
|
121
|
+
// Simple heuristic: find `function` or arrow function declarations and
|
|
122
|
+
// capture the block body between matching braces.
|
|
123
|
+
for (let i = 0; i < lines.length; i++) {
|
|
124
|
+
const line = lines[i];
|
|
125
|
+
if (/\bfunction\b|\=\s*\(.*\)\s*=>/.test(line) && line.includes('{')) {
|
|
126
|
+
// Collect body until matching closing brace
|
|
127
|
+
let depth = 0;
|
|
128
|
+
let body = '';
|
|
129
|
+
for (let j = i; j < lines.length; j++) {
|
|
130
|
+
for (const ch of lines[j]) {
|
|
131
|
+
if (ch === '{')
|
|
132
|
+
depth++;
|
|
133
|
+
else if (ch === '}')
|
|
134
|
+
depth--;
|
|
135
|
+
}
|
|
136
|
+
body += lines[j] + '\n';
|
|
137
|
+
if (depth === 0 && j > i)
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
// Normalise whitespace for comparison
|
|
141
|
+
const normalised = body.replace(/\s+/g, ' ').trim();
|
|
142
|
+
if (normalised.length > 40) {
|
|
143
|
+
// Only flag non-trivial bodies
|
|
144
|
+
bodies.set(normalised, i + 1);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return bodies;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Rule: identical function bodies in 2+ module files = DRY violation.
|
|
152
|
+
*/
|
|
153
|
+
function checkDryViolations(files) {
|
|
154
|
+
// Map: normalised body → list of { file, line }
|
|
155
|
+
const bodyMap = new Map();
|
|
156
|
+
for (const { path: filePath, content } of files) {
|
|
157
|
+
// Only check module files
|
|
158
|
+
if (!filePath.includes('/modules/'))
|
|
159
|
+
continue;
|
|
160
|
+
const bodies = extractFunctionBodies(filePath, content);
|
|
161
|
+
for (const [body, line] of bodies) {
|
|
162
|
+
const existing = bodyMap.get(body) ?? [];
|
|
163
|
+
existing.push({ file: filePath, line });
|
|
164
|
+
bodyMap.set(body, existing);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const results = [];
|
|
168
|
+
for (const [, occurrences] of bodyMap) {
|
|
169
|
+
if (occurrences.length >= 2) {
|
|
170
|
+
for (const { file, line } of occurrences) {
|
|
171
|
+
results.push({
|
|
172
|
+
file,
|
|
173
|
+
line,
|
|
174
|
+
rule: 'dry-violation',
|
|
175
|
+
message: `Identical function body found in ${occurrences.length} files. Extract to a shared utility in src/shared/utils/.`,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return results;
|
|
181
|
+
}
|
|
182
|
+
// ─── Main linter entry point ──────────────────────────────────────────────────
|
|
183
|
+
/**
|
|
184
|
+
* Scans all `.ts` and `.vue` files under `srcDir` and returns all lint violations.
|
|
185
|
+
*
|
|
186
|
+
* @param srcDir - absolute or relative path to the project's `src/` directory
|
|
187
|
+
*/
|
|
188
|
+
export async function lintProject(srcDir) {
|
|
189
|
+
const pattern = join(srcDir, '**/*.{ts,vue}').replace(/\\/g, '/');
|
|
190
|
+
const filePaths = await fg(pattern, { absolute: true, ignore: ['**/node_modules/**', '**/dist/**'] });
|
|
191
|
+
const fileContents = [];
|
|
192
|
+
for (const filePath of filePaths) {
|
|
193
|
+
const content = readFileSync(filePath, 'utf8');
|
|
194
|
+
fileContents.push({ path: relative(process.cwd(), filePath), content });
|
|
195
|
+
}
|
|
196
|
+
const results = [];
|
|
197
|
+
for (const { path: filePath, content } of fileContents) {
|
|
198
|
+
results.push(...checkHeader(filePath, content));
|
|
199
|
+
results.push(...checkConsoleLogs(filePath, content));
|
|
200
|
+
results.push(...checkNamingConventions(filePath, content));
|
|
201
|
+
results.push(...checkVersioning(filePath, content));
|
|
202
|
+
}
|
|
203
|
+
// DRY check needs all files at once
|
|
204
|
+
results.push(...checkDryViolations(fileContents));
|
|
205
|
+
return results;
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=linter.js.map
|