@wild-framework/cli 0.1.1
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/LICENSE +21 -0
- package/README.md +37 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +71 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/make.d.ts +51 -0
- package/dist/commands/make.d.ts.map +1 -0
- package/dist/commands/make.js +174 -0
- package/dist/commands/make.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/templates/controller.d.ts +5 -0
- package/dist/templates/controller.d.ts.map +1 -0
- package/dist/templates/controller.js +33 -0
- package/dist/templates/controller.js.map +1 -0
- package/dist/templates/event.d.ts +5 -0
- package/dist/templates/event.d.ts.map +1 -0
- package/dist/templates/event.js +15 -0
- package/dist/templates/event.js.map +1 -0
- package/dist/templates/index.d.ts +9 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +38 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/templates/job.d.ts +5 -0
- package/dist/templates/job.d.ts.map +1 -0
- package/dist/templates/job.js +21 -0
- package/dist/templates/job.js.map +1 -0
- package/dist/templates/listener.d.ts +5 -0
- package/dist/templates/listener.d.ts.map +1 -0
- package/dist/templates/listener.js +15 -0
- package/dist/templates/listener.js.map +1 -0
- package/dist/templates/policy.d.ts +5 -0
- package/dist/templates/policy.d.ts.map +1 -0
- package/dist/templates/policy.js +18 -0
- package/dist/templates/policy.js.map +1 -0
- package/dist/templates/provider.d.ts +7 -0
- package/dist/templates/provider.d.ts.map +1 -0
- package/dist/templates/provider.js +35 -0
- package/dist/templates/provider.js.map +1 -0
- package/dist/templates/resource.d.ts +5 -0
- package/dist/templates/resource.d.ts.map +1 -0
- package/dist/templates/resource.js +17 -0
- package/dist/templates/resource.js.map +1 -0
- package/dist/templates/service.d.ts +5 -0
- package/dist/templates/service.d.ts.map +1 -0
- package/dist/templates/service.js +28 -0
- package/dist/templates/service.js.map +1 -0
- package/dist/templates/validator.d.ts +5 -0
- package/dist/templates/validator.d.ts.map +1 -0
- package/dist/templates/validator.js +18 -0
- package/dist/templates/validator.js.map +1 -0
- package/dist/wizard.d.ts +20 -0
- package/dist/wizard.d.ts.map +1 -0
- package/dist/wizard.js +173 -0
- package/dist/wizard.js.map +1 -0
- package/package.json +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Wild Framework contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# @wild-framework/cli
|
|
2
|
+
|
|
3
|
+
Scaffolding CLI for [Wild Framework](https://github.com/KhandaSoftware/wild-framework).
|
|
4
|
+
|
|
5
|
+
Generate feature pieces from the documented patterns — no copy-paste.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add -D @wild-framework/cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Interactive wizard
|
|
17
|
+
npx wild make
|
|
18
|
+
|
|
19
|
+
# Direct commands
|
|
20
|
+
npx wild make:module users # features/users/ (provider + service)
|
|
21
|
+
npx wild make:provider OrderProvider features/orders
|
|
22
|
+
npx wild make:service UserService features/users
|
|
23
|
+
npx wild make:controller UserController features/users
|
|
24
|
+
npx wild make:event OrderPlaced features/orders # appends to events.ts
|
|
25
|
+
npx wild make:job SendReceipt features/orders # → send-receipt-job.ts
|
|
26
|
+
npx wild make:validator CreateUserRequest features/users
|
|
27
|
+
npx wild make:resource UserResource features/users
|
|
28
|
+
npx wild make:policy PostPolicy features/posts
|
|
29
|
+
npx wild make:listener SendOrderEmail features/orders
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The wizard also offers optional add-ons: event, queued job, controller,
|
|
33
|
+
validator, and resource — names derived from your base name and written
|
|
34
|
+
into the same feature folder.
|
|
35
|
+
|
|
36
|
+
Files are written under `./src/features/`. PascalCase class names map to
|
|
37
|
+
kebab-case filenames. Existing files are never overwritten.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAuBzD"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { makeCommand } from "./commands/make.js";
|
|
2
|
+
import { runWizard } from "./wizard.js";
|
|
3
|
+
/**
|
|
4
|
+
* Parse and dispatch a CLI command.
|
|
5
|
+
*
|
|
6
|
+
* @returns process exit code (0 = ok, 1 = error)
|
|
7
|
+
*/
|
|
8
|
+
export async function run(argv) {
|
|
9
|
+
const [command, ...rest] = argv;
|
|
10
|
+
if (!command || command === "--help" || command === "-h" || command === "help") {
|
|
11
|
+
printHelp();
|
|
12
|
+
return 0;
|
|
13
|
+
}
|
|
14
|
+
if (command === "--version" || command === "-v" || command === "version") {
|
|
15
|
+
console.log("wild 0.1.1");
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
if (command === "make" || command === "make:interactive" || command === "--interactive" || command === "-i") {
|
|
19
|
+
return runWizard();
|
|
20
|
+
}
|
|
21
|
+
if (command.startsWith("make:")) {
|
|
22
|
+
return runMake(command.slice("make:".length), rest);
|
|
23
|
+
}
|
|
24
|
+
console.error(`wild: unknown command "${command}". Run "wild --help" for usage.`);
|
|
25
|
+
return 1;
|
|
26
|
+
}
|
|
27
|
+
function runMake(piece, args) {
|
|
28
|
+
try {
|
|
29
|
+
const result = makeCommand(piece, args);
|
|
30
|
+
if (result === null) {
|
|
31
|
+
return 1; // error already printed
|
|
32
|
+
}
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
console.error(`wild: ${error instanceof Error ? error.message : String(error)}`);
|
|
37
|
+
return 1;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function printHelp() {
|
|
41
|
+
console.log(`
|
|
42
|
+
Wild Framework CLI — scaffold feature pieces from the documented patterns.
|
|
43
|
+
|
|
44
|
+
Usage:
|
|
45
|
+
wild make → interactive wizard (guided prompts)
|
|
46
|
+
wild make:<piece> <Name> [targetDir]
|
|
47
|
+
|
|
48
|
+
Pieces:
|
|
49
|
+
module wild make:module users → features/users/ (provider + service)
|
|
50
|
+
provider wild make:provider UserProvider → user-provider.ts
|
|
51
|
+
service wild make:service UserService → user-service.ts
|
|
52
|
+
controller wild make:controller UserController → user-controller.ts
|
|
53
|
+
event wild make:event UserRegistered → events.ts (appends)
|
|
54
|
+
job wild make:job SendReceiptJob → send-receipt-job.ts
|
|
55
|
+
validator wild make:validator CreateUserRequest → create-user-request.ts
|
|
56
|
+
resource wild make:resource UserResource → user-resource.ts
|
|
57
|
+
policy wild make:policy PostPolicy → post-policy.ts
|
|
58
|
+
listener wild make:listener SendWelcomeEmail → send-welcome-email.ts
|
|
59
|
+
|
|
60
|
+
Options:
|
|
61
|
+
-i, --interactive run the guided wizard
|
|
62
|
+
|
|
63
|
+
targetDir is optional (default: features/<name>). Files are written under ./src.
|
|
64
|
+
|
|
65
|
+
Examples:
|
|
66
|
+
wild make:provider OrderProvider features/orders
|
|
67
|
+
wild make:event OrderPlaced features/orders
|
|
68
|
+
wild make:module users
|
|
69
|
+
`);
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkB,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAc;IACpC,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAEhC,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QAC7E,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,CAAC;IACb,CAAC;IAED,IAAI,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAC1B,OAAO,CAAC,CAAC;IACb,CAAC;IAED,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,kBAAkB,IAAI,OAAO,KAAK,eAAe,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QAC1G,OAAO,SAAS,EAAE,CAAC;IACvB,CAAC;IAED,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9B,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAc,EAAE,IAAI,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,CAAC,KAAK,CAAC,0BAA0B,OAAO,iCAAiC,CAAC,CAAC;IAClF,OAAO,CAAC,CAAC;AACb,CAAC;AAED,SAAS,OAAO,CAAC,KAAgB,EAAE,IAAc;IAC7C,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACxC,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAClB,OAAO,CAAC,CAAC,CAAC,wBAAwB;QACtC,CAAC;QACD,OAAO,CAAC,CAAC;IACb,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,SAAS,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACjF,OAAO,CAAC,CAAC;IACb,CAAC;AACL,CAAC;AAED,SAAS,SAAS;IACd,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4Bf,CAAC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
import type { PieceName } from "../templates/index.js";
|
|
3
|
+
export type { PieceName };
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the project's source root.
|
|
6
|
+
*
|
|
7
|
+
* Walks up from the cwd looking for a `src/` directory, falling back to `src`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function findProjectSrc(cwd: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Convert a PascalCase class name to kebab-case.
|
|
12
|
+
* "OrderProvider" → "order-provider"
|
|
13
|
+
* "HTTPServer" → "http-server"
|
|
14
|
+
*/
|
|
15
|
+
export declare function toKebabCase(name: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Compute the default feature folder for a piece + name.
|
|
18
|
+
* make:provider OrderProvider → features/order
|
|
19
|
+
* make:module users → features/users
|
|
20
|
+
*/
|
|
21
|
+
export declare function defaultFolderFor(piece: PieceName, name: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* A generated file's target path.
|
|
24
|
+
*/
|
|
25
|
+
export interface TargetFile {
|
|
26
|
+
path: string;
|
|
27
|
+
content: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Compute the target file path(s) for a piece.
|
|
31
|
+
*
|
|
32
|
+
* @param piece piece type (e.g. "provider")
|
|
33
|
+
* @param className PascalCase class name (e.g. "OrderProvider")
|
|
34
|
+
* @param targetDir optional folder (e.g. "features/orders"), default "features/<name>"
|
|
35
|
+
* @param srcRoot the project's src root
|
|
36
|
+
*/
|
|
37
|
+
export declare function targetFor(piece: PieceName, className: string, targetDir: string | undefined, srcRoot: string): TargetFile[];
|
|
38
|
+
/**
|
|
39
|
+
* Write generated files, skipping any that already exist.
|
|
40
|
+
*
|
|
41
|
+
* @returns number of files actually written
|
|
42
|
+
*/
|
|
43
|
+
export declare function writeFiles(files: TargetFile[]): number;
|
|
44
|
+
/**
|
|
45
|
+
* Run a make command.
|
|
46
|
+
*
|
|
47
|
+
* @returns true on success, false on error (error already printed)
|
|
48
|
+
*/
|
|
49
|
+
export declare function makeCommand(piece: PieceName, args: Array<string | undefined>): boolean;
|
|
50
|
+
export { basename };
|
|
51
|
+
//# sourceMappingURL=make.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"make.d.ts","sourceRoot":"","sources":["../../src/commands/make.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,QAAQ,EAAE,MAAM,WAAW,CAAC;AAEpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAYlD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKhD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACrB,KAAK,EAAE,SAAS,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,OAAO,EAAE,MAAM,GAChB,UAAU,EAAE,CAwCd;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,CAatD;AAsBD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,OAAO,CA+BtF;AAmBD,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join, dirname, basename } from "node:path";
|
|
3
|
+
import { render } from "../templates/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the project's source root.
|
|
6
|
+
*
|
|
7
|
+
* Walks up from the cwd looking for a `src/` directory, falling back to `src`.
|
|
8
|
+
*/
|
|
9
|
+
export function findProjectSrc(cwd) {
|
|
10
|
+
let dir = cwd;
|
|
11
|
+
// Walk up a few levels in case we're inside a subfolder (e.g. features/orders)
|
|
12
|
+
for (let i = 0; i < 6; i++) {
|
|
13
|
+
if (existsSync(join(dir, "src"))) {
|
|
14
|
+
return join(dir, "src");
|
|
15
|
+
}
|
|
16
|
+
const parent = dirname(dir);
|
|
17
|
+
if (parent === dir)
|
|
18
|
+
break;
|
|
19
|
+
dir = parent;
|
|
20
|
+
}
|
|
21
|
+
return join(cwd, "src");
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Convert a PascalCase class name to kebab-case.
|
|
25
|
+
* "OrderProvider" → "order-provider"
|
|
26
|
+
* "HTTPServer" → "http-server"
|
|
27
|
+
*/
|
|
28
|
+
export function toKebabCase(name) {
|
|
29
|
+
return name
|
|
30
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
|
31
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2")
|
|
32
|
+
.toLowerCase();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Compute the default feature folder for a piece + name.
|
|
36
|
+
* make:provider OrderProvider → features/order
|
|
37
|
+
* make:module users → features/users
|
|
38
|
+
*/
|
|
39
|
+
export function defaultFolderFor(piece, name) {
|
|
40
|
+
return `features/${toKebabCase(stripSuffix(name, piece))}`;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Compute the target file path(s) for a piece.
|
|
44
|
+
*
|
|
45
|
+
* @param piece piece type (e.g. "provider")
|
|
46
|
+
* @param className PascalCase class name (e.g. "OrderProvider")
|
|
47
|
+
* @param targetDir optional folder (e.g. "features/orders"), default "features/<name>"
|
|
48
|
+
* @param srcRoot the project's src root
|
|
49
|
+
*/
|
|
50
|
+
export function targetFor(piece, className, targetDir, srcRoot) {
|
|
51
|
+
const featureDir = targetDir ?? defaultFolderFor(piece, className);
|
|
52
|
+
const dir = join(srcRoot, featureDir);
|
|
53
|
+
const kebab = toKebabCase(className);
|
|
54
|
+
const file = (name) => join(dir, name);
|
|
55
|
+
switch (piece) {
|
|
56
|
+
case "module": {
|
|
57
|
+
// module name is a folder name (e.g. "users") → derive classes
|
|
58
|
+
const base = className.toLowerCase();
|
|
59
|
+
const cls = toTitleCase(base);
|
|
60
|
+
return [
|
|
61
|
+
{ path: file(`${base}-provider.ts`), content: render("provider", `${cls}Provider`) },
|
|
62
|
+
{ path: file(`${base}-service.ts`), content: render("service", `${cls}Service`) },
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
case "provider":
|
|
66
|
+
return [{ path: file(`${kebab}.ts`), content: render("provider", className) }];
|
|
67
|
+
case "service":
|
|
68
|
+
return [{ path: file(`${kebab}.ts`), content: render("service", className) }];
|
|
69
|
+
case "controller":
|
|
70
|
+
return [{ path: file(`${kebab}.ts`), content: render("controller", className) }];
|
|
71
|
+
case "event":
|
|
72
|
+
return [{ path: file("events.ts"), content: render("event", className) }];
|
|
73
|
+
case "job": {
|
|
74
|
+
const jobName = ensureSuffix(className, "Job");
|
|
75
|
+
return [{ path: file(`${toKebabCase(jobName)}.ts`), content: render("job", jobName) }];
|
|
76
|
+
}
|
|
77
|
+
case "validator":
|
|
78
|
+
return [{ path: file(`${kebab}.ts`), content: render("validator", className) }];
|
|
79
|
+
case "resource":
|
|
80
|
+
return [{ path: file(`${kebab}.ts`), content: render("resource", className) }];
|
|
81
|
+
case "policy":
|
|
82
|
+
return [{ path: file(`${kebab}.ts`), content: render("policy", className) }];
|
|
83
|
+
case "listener": {
|
|
84
|
+
const listenerName = ensureSuffix(className, "Listener");
|
|
85
|
+
return [{ path: file(`${toKebabCase(listenerName)}.ts`), content: render("listener", listenerName) }];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Write generated files, skipping any that already exist.
|
|
91
|
+
*
|
|
92
|
+
* @returns number of files actually written
|
|
93
|
+
*/
|
|
94
|
+
export function writeFiles(files) {
|
|
95
|
+
let written = 0;
|
|
96
|
+
for (const file of files) {
|
|
97
|
+
if (existsSync(file.path)) {
|
|
98
|
+
console.log(` skip ${rel(file.path)} (already exists)`);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
mkdirSync(dirname(file.path), { recursive: true });
|
|
102
|
+
writeFileSync(file.path, file.content, "utf8");
|
|
103
|
+
console.log(` create ${rel(file.path)}`);
|
|
104
|
+
written++;
|
|
105
|
+
}
|
|
106
|
+
return written;
|
|
107
|
+
}
|
|
108
|
+
function rel(path) {
|
|
109
|
+
return path.replace(process.cwd(), ".").replace(/^\.\//, "");
|
|
110
|
+
}
|
|
111
|
+
function stripSuffix(name, piece) {
|
|
112
|
+
const suffix = piece === "provider" ? "Provider"
|
|
113
|
+
: piece === "service" ? "Service"
|
|
114
|
+
: piece === "controller" ? "Controller"
|
|
115
|
+
: piece === "module" ? "Module" : "";
|
|
116
|
+
return suffix && name.endsWith(suffix) ? name.slice(0, -suffix.length) : name;
|
|
117
|
+
}
|
|
118
|
+
function ensureSuffix(name, suffix) {
|
|
119
|
+
return name.endsWith(suffix) ? name : name + suffix;
|
|
120
|
+
}
|
|
121
|
+
function toTitleCase(name) {
|
|
122
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Run a make command.
|
|
126
|
+
*
|
|
127
|
+
* @returns true on success, false on error (error already printed)
|
|
128
|
+
*/
|
|
129
|
+
export function makeCommand(piece, args) {
|
|
130
|
+
const [name, targetDir] = args;
|
|
131
|
+
if (!name) {
|
|
132
|
+
console.error(`wild: make:${piece} requires a name, e.g. "wild make:${piece} ${exampleName(piece)}"`);
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
// Module names are feature folder names (lowercase); classes must be PascalCase
|
|
136
|
+
const namePattern = piece === "module" ? /^[a-z][a-z0-9-]*$/ : /^[A-Z][A-Za-z0-9]*$/;
|
|
137
|
+
if (!namePattern.test(name)) {
|
|
138
|
+
const hint = piece === "module"
|
|
139
|
+
? "Use a lowercase feature name, e.g. \"users\"."
|
|
140
|
+
: "Use PascalCase, e.g. \"OrderProvider\".";
|
|
141
|
+
console.error(`wild: \"${name}\" is not a valid ${piece} name. ${hint}`);
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
const srcRoot = findProjectSrc(process.cwd());
|
|
145
|
+
const files = targetFor(piece, name, targetDir, srcRoot);
|
|
146
|
+
console.log(`\nGenerating ${piece}: ${name}\n`);
|
|
147
|
+
const written = writeFiles(files);
|
|
148
|
+
if (written === 0) {
|
|
149
|
+
console.log("\nNothing to do — all files already exist.");
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
console.log(`\nDone. ${written} file(s) created under ${rel(srcRoot)}.`);
|
|
153
|
+
console.log("Remember to register any new provider in your app: app.register(YourProvider);");
|
|
154
|
+
}
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
function exampleName(piece) {
|
|
158
|
+
const map = {
|
|
159
|
+
module: "users",
|
|
160
|
+
provider: "UserProvider",
|
|
161
|
+
service: "UserService",
|
|
162
|
+
controller: "UserController",
|
|
163
|
+
event: "UserRegistered",
|
|
164
|
+
job: "SendReceiptJob",
|
|
165
|
+
validator: "CreateUserRequest",
|
|
166
|
+
resource: "UserResource",
|
|
167
|
+
policy: "PostPolicy",
|
|
168
|
+
listener: "SendWelcomeEmail",
|
|
169
|
+
};
|
|
170
|
+
return map[piece] ?? "Thing";
|
|
171
|
+
}
|
|
172
|
+
// Re-export for CLI dispatch
|
|
173
|
+
export { basename };
|
|
174
|
+
//# sourceMappingURL=make.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"make.js","sourceRoot":"","sources":["../../src/commands/make.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Wild Framework CLI entry point.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* wild make:provider OrderProvider features/orders
|
|
7
|
+
* wild make:module users
|
|
8
|
+
* wild make:event UserRegistered features/orders
|
|
9
|
+
* ...
|
|
10
|
+
*/
|
|
11
|
+
import { run } from "./cli.js";
|
|
12
|
+
run(process.argv.slice(2)).then((exitCode) => {
|
|
13
|
+
process.exitCode = exitCode;
|
|
14
|
+
}, (error) => {
|
|
15
|
+
console.error(`wild: ${error instanceof Error ? error.message : String(error)}`);
|
|
16
|
+
process.exitCode = 1;
|
|
17
|
+
});
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AACH,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAC3B,CAAC,QAAQ,EAAE,EAAE;IACT,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;AAChC,CAAC,EACD,CAAC,KAAK,EAAE,EAAE;IACN,OAAO,CAAC,KAAK,CAAC,SAAS,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACjF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACzB,CAAC,CACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../src/templates/controller.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CA4B5D"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template for a controller (thin HTTP handlers).
|
|
3
|
+
*/
|
|
4
|
+
export function controllerTemplate(className) {
|
|
5
|
+
return `import type { Request, Response } from "express";
|
|
6
|
+
import { NotFoundException } from "@wild-framework/http";
|
|
7
|
+
// import type { MyService } from "./my-service.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* HTTP controller for this feature.
|
|
11
|
+
*/
|
|
12
|
+
export class ${className} {
|
|
13
|
+
constructor(
|
|
14
|
+
// private service: MyService,
|
|
15
|
+
) {}
|
|
16
|
+
|
|
17
|
+
async index(_req: Request, res: Response) {
|
|
18
|
+
return res.json([]);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async show(req: Request, res: Response) {
|
|
22
|
+
// const item = await this.service.find(String(req.params.id));
|
|
23
|
+
// if (!item) throw new NotFoundException("Not found");
|
|
24
|
+
return res.json({ id: req.params.id });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async store(req: Request, res: Response) {
|
|
28
|
+
return res.status(201).json({ created: req.body });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.js","sourceRoot":"","sources":["../../src/templates/controller.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,SAAiB;IAChD,OAAO;;;;;;;eAOI,SAAS;;;;;;;;;;;;;;;;;;;CAmBvB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event.d.ts","sourceRoot":"","sources":["../../src/templates/event.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAUvD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template for a domain event class (past tense, per NAMING.md).
|
|
3
|
+
*/
|
|
4
|
+
export function eventTemplate(className) {
|
|
5
|
+
return `/**
|
|
6
|
+
* ${className} — fired when this happens.
|
|
7
|
+
*/
|
|
8
|
+
export class ${className} {
|
|
9
|
+
constructor(
|
|
10
|
+
// public readonly id: number,
|
|
11
|
+
) {}
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event.js","sourceRoot":"","sources":["../../src/templates/event.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,SAAiB;IAC3C,OAAO;KACN,SAAS;;eAEC,SAAS;;;;;CAKvB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pieces the CLI can generate.
|
|
3
|
+
*/
|
|
4
|
+
export type PieceName = "module" | "provider" | "service" | "controller" | "event" | "job" | "validator" | "resource" | "policy" | "listener";
|
|
5
|
+
/**
|
|
6
|
+
* Render a template for a piece.
|
|
7
|
+
*/
|
|
8
|
+
export declare function render(piece: PieceName, className: string): string;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAUA;;GAEG;AACH,MAAM,MAAM,SAAS,GACf,QAAQ,GACR,UAAU,GACV,SAAS,GACT,YAAY,GACZ,OAAO,GACP,KAAK,GACL,WAAW,GACX,UAAU,GACV,QAAQ,GACR,UAAU,CAAC;AAEjB;;GAEG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAwBlE"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { providerTemplate } from "./provider.js";
|
|
2
|
+
import { serviceTemplate } from "./service.js";
|
|
3
|
+
import { controllerTemplate } from "./controller.js";
|
|
4
|
+
import { eventTemplate } from "./event.js";
|
|
5
|
+
import { jobTemplate } from "./job.js";
|
|
6
|
+
import { validatorTemplate } from "./validator.js";
|
|
7
|
+
import { resourceTemplate } from "./resource.js";
|
|
8
|
+
import { policyTemplate } from "./policy.js";
|
|
9
|
+
import { listenerTemplate } from "./listener.js";
|
|
10
|
+
/**
|
|
11
|
+
* Render a template for a piece.
|
|
12
|
+
*/
|
|
13
|
+
export function render(piece, className) {
|
|
14
|
+
switch (piece) {
|
|
15
|
+
case "provider":
|
|
16
|
+
return providerTemplate(className);
|
|
17
|
+
case "service":
|
|
18
|
+
return serviceTemplate(className);
|
|
19
|
+
case "controller":
|
|
20
|
+
return controllerTemplate(className);
|
|
21
|
+
case "event":
|
|
22
|
+
return eventTemplate(className);
|
|
23
|
+
case "job":
|
|
24
|
+
return jobTemplate(className);
|
|
25
|
+
case "validator":
|
|
26
|
+
return validatorTemplate(className);
|
|
27
|
+
case "resource":
|
|
28
|
+
return resourceTemplate(className);
|
|
29
|
+
case "policy":
|
|
30
|
+
return policyTemplate(className);
|
|
31
|
+
case "listener":
|
|
32
|
+
return listenerTemplate(className);
|
|
33
|
+
case "module":
|
|
34
|
+
// module composes provider + service (handled in make.ts)
|
|
35
|
+
throw new Error("module is composed in make.ts, not rendered directly");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAiBjD;;GAEG;AACH,MAAM,UAAU,MAAM,CAAC,KAAgB,EAAE,SAAiB;IACtD,QAAQ,KAAK,EAAE,CAAC;QACZ,KAAK,UAAU;YACX,OAAO,gBAAgB,CAAC,SAAS,CAAC,CAAC;QACvC,KAAK,SAAS;YACV,OAAO,eAAe,CAAC,SAAS,CAAC,CAAC;QACtC,KAAK,YAAY;YACb,OAAO,kBAAkB,CAAC,SAAS,CAAC,CAAC;QACzC,KAAK,OAAO;YACR,OAAO,aAAa,CAAC,SAAS,CAAC,CAAC;QACpC,KAAK,KAAK;YACN,OAAO,WAAW,CAAC,SAAS,CAAC,CAAC;QAClC,KAAK,WAAW;YACZ,OAAO,iBAAiB,CAAC,SAAS,CAAC,CAAC;QACxC,KAAK,UAAU;YACX,OAAO,gBAAgB,CAAC,SAAS,CAAC,CAAC;QACvC,KAAK,QAAQ;YACT,OAAO,cAAc,CAAC,SAAS,CAAC,CAAC;QACrC,KAAK,UAAU;YACX,OAAO,gBAAgB,CAAC,SAAS,CAAC,CAAC;QACvC,KAAK,QAAQ;YACT,0DAA0D;YAC1D,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAChF,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job.d.ts","sourceRoot":"","sources":["../../src/templates/job.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAgBrD"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template for a queued job (DI, resolved from the container).
|
|
3
|
+
*/
|
|
4
|
+
export function jobTemplate(className) {
|
|
5
|
+
return `// import { Mail } from "@wild-framework/mail";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A queued job with DI — resolved from the container.
|
|
9
|
+
*/
|
|
10
|
+
export class ${className} {
|
|
11
|
+
constructor(
|
|
12
|
+
// private mail: Mail,
|
|
13
|
+
) {}
|
|
14
|
+
|
|
15
|
+
async handle(_payload: Record<string, unknown>): Promise<void> {
|
|
16
|
+
// Do the work
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=job.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job.js","sourceRoot":"","sources":["../../src/templates/job.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,SAAiB;IACzC,OAAO;;;;;eAKI,SAAS;;;;;;;;;CASvB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../../src/templates/listener.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAU1D"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A listener — reacts to a domain event.
|
|
3
|
+
*/
|
|
4
|
+
export function listenerTemplate(className) {
|
|
5
|
+
return `/**
|
|
6
|
+
* A listener — reacts to a domain event.
|
|
7
|
+
*/
|
|
8
|
+
export class ${className} {
|
|
9
|
+
async handle(event: unknown): Promise<void> {
|
|
10
|
+
// React to event
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=listener.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listener.js","sourceRoot":"","sources":["../../src/templates/listener.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAC9C,OAAO;;;eAGI,SAAS;;;;;CAKvB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/templates/policy.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAaxD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authorization rules for this resource.
|
|
3
|
+
*/
|
|
4
|
+
export function policyTemplate(className) {
|
|
5
|
+
return `import { Policy } from "@wild-framework/auth";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Authorization rules for this resource.
|
|
9
|
+
*/
|
|
10
|
+
export class ${className} extends Policy<unknown> {
|
|
11
|
+
/** Allow an action (user, resource). */
|
|
12
|
+
view(_user: unknown, _resource: unknown): boolean {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
`;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/templates/policy.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC5C,OAAO;;;;;eAKI,SAAS;;;;;;CAMvB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/templates/provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAuB1D"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template for a provider.
|
|
3
|
+
*
|
|
4
|
+
* Matches the canonical provider pattern in the examples.
|
|
5
|
+
*/
|
|
6
|
+
export function providerTemplate(className) {
|
|
7
|
+
return `import type { Provider, Application } from "@wild-framework/core";
|
|
8
|
+
import { Container } from "@wild-framework/container";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Wires the ${featureName(className)} feature: DI bindings and event listeners.
|
|
12
|
+
*/
|
|
13
|
+
export class ${className} implements Provider {
|
|
14
|
+
register(app: Application): void {
|
|
15
|
+
const container = app.resolve<Container>(Container);
|
|
16
|
+
|
|
17
|
+
// Bind services: container.singleton(MyService, (c) => new MyService(...));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
boot(_app: Application): void {
|
|
21
|
+
// Start listeners, seed data
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async shutdown(_app: Application): Promise<void> {
|
|
25
|
+
// Clean up, in reverse order
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
}
|
|
30
|
+
function featureName(className) {
|
|
31
|
+
const base = className.endsWith("Provider") ? className.slice(0, -"Provider".length) : className;
|
|
32
|
+
// "Order" -> "order" for prose
|
|
33
|
+
return base.charAt(0).toLowerCase() + base.slice(1);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/templates/provider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAC9C,OAAO;;;;eAII,WAAW,CAAC,SAAS,CAAC;;eAEtB,SAAS;;;;;;;;;;;;;;;CAevB,CAAC;AACF,CAAC;AAED,SAAS,WAAW,CAAC,SAAiB;IAClC,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACjG,+BAA+B;IAC/B,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../src/templates/resource.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAY1D"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shapes a record for API responses.
|
|
3
|
+
*/
|
|
4
|
+
export function resourceTemplate(className) {
|
|
5
|
+
return `import { Resource } from "@wild-framework/resources";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Shapes a record for API responses.
|
|
9
|
+
*/
|
|
10
|
+
export class ${className} extends Resource<unknown> {
|
|
11
|
+
transform(item: Record<string, unknown>): Record<string, unknown> {
|
|
12
|
+
return item;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
`;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=resource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.js","sourceRoot":"","sources":["../../src/templates/resource.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,SAAiB;IAC9C,OAAO;;;;;eAKI,SAAS;;;;;CAKvB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/templates/service.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAuBzD"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Template for a service (business logic with constructor DI).
|
|
3
|
+
*/
|
|
4
|
+
export function serviceTemplate(className) {
|
|
5
|
+
return `/**
|
|
6
|
+
* ${className} — business logic for this feature.
|
|
7
|
+
*/
|
|
8
|
+
export class ${className} {
|
|
9
|
+
constructor(
|
|
10
|
+
// private repo: SomeRepository,
|
|
11
|
+
) {}
|
|
12
|
+
|
|
13
|
+
all(): unknown[] {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
find(_id: string | number): unknown {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async create(_data: Record<string, unknown>): Promise<unknown> {
|
|
22
|
+
// const item = ...;
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
`;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/templates/service.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC7C,OAAO;KACN,SAAS;;eAEC,SAAS;;;;;;;;;;;;;;;;;;CAkBvB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/templates/validator.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAa3D"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation for creating a record.
|
|
3
|
+
*/
|
|
4
|
+
export function validatorTemplate(className) {
|
|
5
|
+
return `import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Validation for creating a record.
|
|
9
|
+
*/
|
|
10
|
+
export class ${className} {
|
|
11
|
+
static schema = z.object({
|
|
12
|
+
// name: z.string().min(2),
|
|
13
|
+
// email: z.string().email(),
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
`;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/templates/validator.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,SAAiB;IAC/C,OAAO;;;;;eAKI,SAAS;;;;;;CAMvB,CAAC;AACF,CAAC"}
|
package/dist/wizard.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A function that asks the user a question and resolves with their answer.
|
|
3
|
+
*/
|
|
4
|
+
export type AskFn = (question: string) => Promise<string>;
|
|
5
|
+
/**
|
|
6
|
+
* A printer for wizard output (defaults to console.log).
|
|
7
|
+
*/
|
|
8
|
+
export type PrintFn = (line: string) => void;
|
|
9
|
+
/**
|
|
10
|
+
* Run the interactive "wizard" mode using real stdin/stdout.
|
|
11
|
+
*/
|
|
12
|
+
export declare function runWizard(): Promise<number>;
|
|
13
|
+
/**
|
|
14
|
+
* Wizard logic with injectable ask/print — used by the real CLI and tests.
|
|
15
|
+
*/
|
|
16
|
+
export declare function runWizardWith(deps: {
|
|
17
|
+
ask: AskFn;
|
|
18
|
+
print: PrintFn;
|
|
19
|
+
}): Promise<number>;
|
|
20
|
+
//# sourceMappingURL=wizard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE1D;;GAEG;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;AAE7C;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAkBjD;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE;IAAE,GAAG,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAsGzF"}
|
package/dist/wizard.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { createInterface } from "node:readline";
|
|
2
|
+
import { makeCommand, defaultFolderFor } from "./commands/make.js";
|
|
3
|
+
/**
|
|
4
|
+
* Run the interactive "wizard" mode using real stdin/stdout.
|
|
5
|
+
*/
|
|
6
|
+
export async function runWizard() {
|
|
7
|
+
const rl = createInterface({
|
|
8
|
+
input: process.stdin,
|
|
9
|
+
output: process.stdout,
|
|
10
|
+
});
|
|
11
|
+
const ask = (question) => new Promise((resolve) => rl.question(question, resolve));
|
|
12
|
+
try {
|
|
13
|
+
const code = await runWizardWith({ ask, print: console.log });
|
|
14
|
+
rl.close();
|
|
15
|
+
return code;
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
rl.close();
|
|
19
|
+
console.error(`wild: ${error instanceof Error ? error.message : String(error)}`);
|
|
20
|
+
return 1;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Wizard logic with injectable ask/print — used by the real CLI and tests.
|
|
25
|
+
*/
|
|
26
|
+
export async function runWizardWith(deps) {
|
|
27
|
+
const { ask, print } = deps;
|
|
28
|
+
const askChoice = async (question, options) => {
|
|
29
|
+
print(question);
|
|
30
|
+
options.forEach((opt, i) => print(` ${i + 1}) ${opt}`));
|
|
31
|
+
const answer = (await ask(`Choose (1-${options.length}): `)).trim();
|
|
32
|
+
const idx = Number(answer) - 1;
|
|
33
|
+
return options[idx] ?? options[0] ?? "";
|
|
34
|
+
};
|
|
35
|
+
const askYesNo = async (question, defaultValue = false) => {
|
|
36
|
+
const hint = defaultValue ? "(Y/n)" : "(y/N)";
|
|
37
|
+
const answer = (await ask(`${question} ${hint} `)).trim().toLowerCase();
|
|
38
|
+
if (answer === "y" || answer === "yes")
|
|
39
|
+
return true;
|
|
40
|
+
if (answer === "n" || answer === "no")
|
|
41
|
+
return false;
|
|
42
|
+
return defaultValue;
|
|
43
|
+
};
|
|
44
|
+
print("\n🐺 Wild Framework — feature wizard\n");
|
|
45
|
+
// 1. What are we creating?
|
|
46
|
+
const pieceLabel = await askChoice("What do you want to create?", [
|
|
47
|
+
"Module (provider + service)",
|
|
48
|
+
"Provider",
|
|
49
|
+
"Service",
|
|
50
|
+
"Controller",
|
|
51
|
+
"Event",
|
|
52
|
+
"Job",
|
|
53
|
+
"Validator",
|
|
54
|
+
"Resource",
|
|
55
|
+
"Policy",
|
|
56
|
+
"Listener",
|
|
57
|
+
]);
|
|
58
|
+
if (!pieceLabel) {
|
|
59
|
+
print("Nothing selected — aborting.");
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
const pieceMap = {
|
|
63
|
+
"Module (provider + service)": "module",
|
|
64
|
+
Provider: "provider",
|
|
65
|
+
Service: "service",
|
|
66
|
+
Controller: "controller",
|
|
67
|
+
Event: "event",
|
|
68
|
+
Job: "job",
|
|
69
|
+
Validator: "validator",
|
|
70
|
+
Resource: "resource",
|
|
71
|
+
Policy: "policy",
|
|
72
|
+
Listener: "listener",
|
|
73
|
+
};
|
|
74
|
+
const pieceName = pieceMap[pieceLabel] ?? "module";
|
|
75
|
+
// 2. Name
|
|
76
|
+
const example = exampleFor(pieceName);
|
|
77
|
+
let name = (await ask(`Name${example ? ` (e.g. ${example})` : ""}: `)).trim();
|
|
78
|
+
if (!name && example)
|
|
79
|
+
name = example;
|
|
80
|
+
if (!name) {
|
|
81
|
+
print("No name given — aborting.");
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
// 3. Folder — if blank, derive once so the main piece and add-ons share it
|
|
85
|
+
let folder = (await ask("Feature folder (default: auto): ")).trim();
|
|
86
|
+
if (!folder)
|
|
87
|
+
folder = defaultFolderFor(pieceName, name);
|
|
88
|
+
// 4. Optional add-ons
|
|
89
|
+
const addons = [];
|
|
90
|
+
if (await askYesNo("Add an event class?", pieceName === "event")) {
|
|
91
|
+
addons.push("event");
|
|
92
|
+
}
|
|
93
|
+
if (await askYesNo("Add a queued job (queue support)?", false)) {
|
|
94
|
+
addons.push("job");
|
|
95
|
+
}
|
|
96
|
+
if (await askYesNo("Add an HTTP controller?", false)) {
|
|
97
|
+
addons.push("controller");
|
|
98
|
+
}
|
|
99
|
+
if (await askYesNo("Add a validator (Zod request)?", false)) {
|
|
100
|
+
addons.push("validator");
|
|
101
|
+
}
|
|
102
|
+
if (await askYesNo("Add a resource (response shaping)?", false)) {
|
|
103
|
+
addons.push("resource");
|
|
104
|
+
}
|
|
105
|
+
// 5. Generate the main piece
|
|
106
|
+
const baseName = name;
|
|
107
|
+
const mainOk = makeCommand(pieceName, [name, folder]);
|
|
108
|
+
// 6. Generate add-ons with derived names
|
|
109
|
+
for (const addon of addons) {
|
|
110
|
+
const addonName = deriveName(baseName, pieceName, addon);
|
|
111
|
+
const addonOk = makeCommand(addon, [addonName, folder]);
|
|
112
|
+
if (!addonOk) {
|
|
113
|
+
print(` (skipped ${addon})`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return mainOk ? 0 : 1;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Derive a sensible class name for an add-on from the base name.
|
|
120
|
+
*/
|
|
121
|
+
function deriveName(baseName, piece, addon) {
|
|
122
|
+
// Base name as a feature stem: "OrderProvider" → "Order", "users" → "User"
|
|
123
|
+
let stem = baseName;
|
|
124
|
+
for (const suffix of ["Provider", "Service", "Controller", "Job", "Listener"]) {
|
|
125
|
+
if (stem.endsWith(suffix)) {
|
|
126
|
+
stem = stem.slice(0, -suffix.length);
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (!/^[A-Z]/.test(stem))
|
|
131
|
+
stem = stem.charAt(0).toUpperCase() + stem.slice(1);
|
|
132
|
+
switch (addon) {
|
|
133
|
+
case "event":
|
|
134
|
+
return `${stem}Created`;
|
|
135
|
+
case "job":
|
|
136
|
+
return `${stem}Job`;
|
|
137
|
+
case "controller":
|
|
138
|
+
return `${stem}Controller`;
|
|
139
|
+
case "validator":
|
|
140
|
+
return `Create${stem}Request`;
|
|
141
|
+
case "resource":
|
|
142
|
+
return `${stem}Resource`;
|
|
143
|
+
default:
|
|
144
|
+
return `${stem}${addon.charAt(0).toUpperCase()}${addon.slice(1)}`;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function exampleFor(piece) {
|
|
148
|
+
switch (piece) {
|
|
149
|
+
case "module":
|
|
150
|
+
return "users";
|
|
151
|
+
case "provider":
|
|
152
|
+
return "UserProvider";
|
|
153
|
+
case "service":
|
|
154
|
+
return "UserService";
|
|
155
|
+
case "controller":
|
|
156
|
+
return "UserController";
|
|
157
|
+
case "event":
|
|
158
|
+
return "UserRegistered";
|
|
159
|
+
case "job":
|
|
160
|
+
return "SendReceiptJob";
|
|
161
|
+
case "validator":
|
|
162
|
+
return "CreateUserRequest";
|
|
163
|
+
case "resource":
|
|
164
|
+
return "UserResource";
|
|
165
|
+
case "policy":
|
|
166
|
+
return "PostPolicy";
|
|
167
|
+
case "listener":
|
|
168
|
+
return "SendWelcomeEmail";
|
|
169
|
+
default:
|
|
170
|
+
return "";
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=wizard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wizard.js","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wild-framework/cli",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"wild": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"author": "Sphah",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/KhandaSoftware/wild-framework.git"
|
|
27
|
+
},
|
|
28
|
+
"description": "Scaffolding CLI for Wild Framework — generate providers, services, controllers, events and more.",
|
|
29
|
+
"keywords": [
|
|
30
|
+
"wild",
|
|
31
|
+
"framework",
|
|
32
|
+
"cli",
|
|
33
|
+
"scaffold",
|
|
34
|
+
"generator",
|
|
35
|
+
"make"
|
|
36
|
+
],
|
|
37
|
+
"dependencies": {},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsc",
|
|
40
|
+
"clean": "rm -rf dist",
|
|
41
|
+
"test": "vitest run"
|
|
42
|
+
}
|
|
43
|
+
}
|