@ooneex/cli 1.28.4 → 1.29.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/dist/index.js +563 -451
- package/dist/index.js.map +5 -4
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -5209,6 +5209,7 @@ _oo() {
|
|
|
5209
5209
|
'make\\:migration:Generate a new migration file'
|
|
5210
5210
|
'migration\\:up:Run migrations for all modules'
|
|
5211
5211
|
'make\\:module:Generate a new module'
|
|
5212
|
+
'module\\:lock:Lock module migrations by hashing their content into a yml file'
|
|
5212
5213
|
'remove\\:module:Remove an existing module'
|
|
5213
5214
|
'make\\:permission:Generate a new permission class'
|
|
5214
5215
|
'make\\:pubsub:Generate a new PubSub event class'
|
|
@@ -5281,6 +5282,11 @@ _oo() {
|
|
|
5281
5282
|
_arguments -s \\
|
|
5282
5283
|
'--module=[Module name]:module:_oo_modules'
|
|
5283
5284
|
;;
|
|
5285
|
+
module:lock)
|
|
5286
|
+
_arguments -s \\
|
|
5287
|
+
'--module=[Module name]:module:_oo_modules' \\
|
|
5288
|
+
'--override[Override already registered migrations]'
|
|
5289
|
+
;;
|
|
5284
5290
|
make:seed)
|
|
5285
5291
|
_arguments -s \\
|
|
5286
5292
|
'--name=[Name of the resource]:name' \\
|
|
@@ -5368,6 +5374,7 @@ _ooneex() {
|
|
|
5368
5374
|
'make\\:migration:Generate a new migration file'
|
|
5369
5375
|
'migration\\:up:Run migrations for all modules'
|
|
5370
5376
|
'make\\:module:Generate a new module'
|
|
5377
|
+
'module\\:lock:Lock module migrations by hashing their content into a yml file'
|
|
5371
5378
|
'remove\\:module:Remove an existing module'
|
|
5372
5379
|
'make\\:permission:Generate a new permission class'
|
|
5373
5380
|
'make\\:pubsub:Generate a new PubSub event class'
|
|
@@ -5440,6 +5447,11 @@ _ooneex() {
|
|
|
5440
5447
|
_arguments -s \\
|
|
5441
5448
|
'--module=[Module name]:module:_ooneex_modules'
|
|
5442
5449
|
;;
|
|
5450
|
+
module:lock)
|
|
5451
|
+
_arguments -s \\
|
|
5452
|
+
'--module=[Module name]:module:_ooneex_modules' \\
|
|
5453
|
+
'--override[Override already registered migrations]'
|
|
5454
|
+
;;
|
|
5443
5455
|
make:seed)
|
|
5444
5456
|
_arguments -s \\
|
|
5445
5457
|
'--name=[Name of the resource]:name' \\
|
|
@@ -5822,6 +5834,7 @@ ${closingIndent}`;
|
|
|
5822
5834
|
await Bun.write(join6(srcDir, `${pascalName}Module.ts`), moduleContent);
|
|
5823
5835
|
await Bun.write(join6(moduleDir, "package.json"), packageContent);
|
|
5824
5836
|
await Bun.write(join6(moduleDir, "tsconfig.json"), tsconfig_default);
|
|
5837
|
+
await Bun.write(join6(moduleDir, `${kebabName}.yml`), "");
|
|
5825
5838
|
await Bun.write(join6(testsDir, `${pascalName}Module.spec.ts`), testContent);
|
|
5826
5839
|
if (kebabName !== "app") {
|
|
5827
5840
|
const appModulePath = join6(cwd, "modules", "app", "src", "AppModule.ts");
|
|
@@ -7603,58 +7616,58 @@ git commit -m "refactor(product): Reorganize service file structure"
|
|
|
7603
7616
|
`;
|
|
7604
7617
|
|
|
7605
7618
|
// src/templates/claude/skills/make.ai.md.txt
|
|
7606
|
-
var make_ai_md_default = '---\nname: make:ai\ndescription: Generate a new AI class with its test file, then complete the generated code. Use when creating a new AI chat class that uses OpenAI via the @ooneex/ai package.\n---\n\n# Make AI Class\n\nGenerate a new AI class and its test file using the `make:ai` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the AI class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:ai --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/ai/<Name>Ai.ts` - The AI class file (or `modules/<module>/src/ai/<Name>Ai.ts` with `--module`)\n- `tests/ai/<Name>Ai.spec.ts` - The test file (or `modules/<module>/tests/ai/<Name>Ai.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the AI class\n\nEdit `src/ai/<Name>Ai.ts` to complete the implementation:\n\n- Update the prompt in the `run` method from `"My prompt"` to a meaningful prompt based on the class purpose\n- Update the prompt in the `runStream` method from `"My prompt"` to a meaningful prompt based on the class purpose\n- Add any additional configuration or methods relevant to the AI class purpose\n- Ensure proper typing for the `run<T>()` generic return type\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator, type IAiChat, OpenAi, type OpenAiConfigType } from "@ooneex/ai";\nimport { inject } from "@ooneex/container";\n\n@decorator.ai()\nexport class <Name>Ai implements IAiChat<OpenAiConfigType> {\n constructor(@inject(OpenAi) private readonly ai: OpenAi) {}\n\n public async run<T>(prompt?: string, config?: Omit<OpenAiConfigType, "prompt">): Promise<T> {\n return this.ai.run<T>(prompt || "My prompt", config);\n }\n\n public async *runStream(\n prompt?: string,\n config?: Omit<OpenAiConfigType, "prompt" | "output">,\n ): AsyncGenerator<string, void, unknown> {\n yield* this.ai.runStream(prompt || "My prompt", config);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/ai/<Name>Ai.spec.ts` to
|
|
7619
|
+
var make_ai_md_default = '---\nname: make:ai\ndescription: Generate a new AI class with its test file, then complete the generated code. Use when creating a new AI chat class that uses OpenAI via the @ooneex/ai package.\n---\n\n# Make AI Class\n\nGenerate a new AI class and its test file using the `make:ai` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the AI class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:ai --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/ai/<Name>Ai.ts` - The AI class file (or `modules/<module>/src/ai/<Name>Ai.ts` with `--module`)\n- `tests/ai/<Name>Ai.spec.ts` - The test file (or `modules/<module>/tests/ai/<Name>Ai.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the AI class\n\nEdit `src/ai/<Name>Ai.ts` to complete the implementation:\n\n- Update the prompt in the `run` method from `"My prompt"` to a meaningful prompt based on the class purpose\n- Update the prompt in the `runStream` method from `"My prompt"` to a meaningful prompt based on the class purpose\n- Add any additional configuration or methods relevant to the AI class purpose\n- Ensure proper typing for the `run<T>()` generic return type\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { decorator, type IAiChat, OpenAi, type OpenAiConfigType } from "@ooneex/ai";\nimport { inject } from "@ooneex/container";\n\n@decorator.ai()\nexport class <Name>Ai implements IAiChat<OpenAiConfigType> {\n constructor(@inject(OpenAi) private readonly ai: OpenAi) {}\n\n public async run<T>(prompt?: string, config?: Omit<OpenAiConfigType, "prompt">): Promise<T> {\n return this.ai.run<T>(prompt || "My prompt", config);\n }\n\n public async *runStream(\n prompt?: string,\n config?: Omit<OpenAiConfigType, "prompt" | "output">,\n ): AsyncGenerator<string, void, unknown> {\n yield* this.ai.runStream(prompt || "My prompt", config);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/ai/<Name>Ai.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name ends with `Ai`, is a constructor function\n- **`run` contract**: method exists, returns a `Promise` when called with and without a prompt string\n- **`runStream` contract**: method exists, returns an `AsyncGenerator` (has `Symbol.asyncIterator`)\n- **Prompt forwarding**: use a mock `OpenAi` instance to verify the prompt is forwarded correctly\n- **Instance isolation**: two instances are independent\n\nThe complete test file must follow this structure:\n\n```typescript\nimport { describe, expect, mock, test } from "bun:test";\nimport { <Name>Ai } from "@/ai/<Name>Ai";\n\ndescribe("<Name>Ai", () => {\n // --- Class identity ---\n\n test("should have class name ending with \'Ai\'", () => {\n expect(<Name>Ai.name.endsWith("Ai")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof <Name>Ai).toBe("function");\n });\n\n // --- run ---\n\n test("should have \'run\' method", () => {\n expect(typeof <Name>Ai.prototype.run).toBe("function");\n });\n\n test("\'run\' should return a Promise", () => {\n const mockAi = { run: mock(() => Promise.resolve("result")), runStream: mock(async function* () {}) };\n const ai = new <Name>Ai(mockAi as any);\n const result = ai.run();\n expect(result).toBeInstanceOf(Promise);\n return result.catch(() => {});\n });\n\n test("\'run\' should forward the prompt to the underlying AI client", async () => {\n const runMock = mock(() => Promise.resolve("result"));\n const mockAi = { run: runMock, runStream: mock(async function* () {}) };\n const ai = new <Name>Ai(mockAi as any);\n await ai.run("Custom prompt");\n expect(runMock).toHaveBeenCalledWith("Custom prompt", undefined);\n });\n\n test("\'run\' should use the default prompt when none is provided", async () => {\n const runMock = mock((_prompt: string) => Promise.resolve("result"));\n const mockAi = { run: runMock, runStream: mock(async function* () {}) };\n const ai = new <Name>Ai(mockAi as any);\n await ai.run();\n const calledWith = runMock.mock.calls[0]?.[0];\n expect(typeof calledWith).toBe("string");\n expect((calledWith as string).length).toBeGreaterThan(0);\n });\n\n // --- runStream ---\n\n test("should have \'runStream\' method", () => {\n expect(typeof <Name>Ai.prototype.runStream).toBe("function");\n });\n\n test("\'runStream\' should return an AsyncGenerator", () => {\n const mockAi = {\n run: mock(() => Promise.resolve("")),\n runStream: mock(async function* () { yield "token"; }),\n };\n const ai = new <Name>Ai(mockAi as any);\n const gen = ai.runStream();\n expect(typeof gen[Symbol.asyncIterator]).toBe("function");\n gen.return(undefined);\n });\n\n test("\'runStream\' should yield tokens from the underlying AI client", async () => {\n const mockAi = {\n run: mock(() => Promise.resolve("")),\n runStream: mock(async function* () { yield "hello"; yield " world"; }),\n };\n const ai = new <Name>Ai(mockAi as any);\n const tokens: string[] = [];\n for await (const token of ai.runStream()) {\n tokens.push(token);\n }\n expect(tokens).toEqual(["hello", " world"]);\n });\n\n // --- Instance isolation ---\n\n test("should produce independent instances", () => {\n const mockAi = { run: mock(() => Promise.resolve("")), runStream: mock(async function* () {}) };\n const a = new <Name>Ai(mockAi as any);\n const b = new <Name>Ai(mockAi as any);\n expect(a).not.toBe(b);\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/ai/<Name>Ai.ts tests/ai/<Name>Ai.spec.ts\n```\n';
|
|
7607
7620
|
|
|
7608
7621
|
// src/templates/claude/skills/make.analytics.md.txt
|
|
7609
|
-
var make_analytics_md_default = '---\nname: make:analytics\ndescription: Generate a new analytics class with its test file, then complete the generated code. Use when creating a new analytics tracking class that uses the @ooneex/analytics package.\n---\n\n# Make Analytics Class\n\nGenerate a new analytics class and its test file using the `make:analytics` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the analytics class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:analytics --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/analytics/<Name>Analytics.ts` - The analytics class file (or `modules/<module>/src/analytics/<Name>Analytics.ts` with `--module`)\n- `tests/analytics/<Name>Analytics.spec.ts` - The test file (or `modules/<module>/tests/analytics/<Name>Analytics.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the analytics class\n\nEdit `src/analytics/<Name>Analytics.ts` to complete the implementation:\n\n- Implement the `capture` method with actual analytics tracking logic\n- Define a proper type for `CaptureOptionsType` instead of `Record<string, unknown>` based on the analytics purpose\n- Add any additional methods or properties relevant to the analytics class purpose\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { type IAnalytics, decorator } from "@ooneex/analytics";\n\ntype CaptureOptionsType = Record<string, unknown>;\n\n@decorator.analytics()\nexport class <Name>Analytics<T extends CaptureOptionsType = CaptureOptionsType> implements IAnalytics<T> {\n public capture(options: T): void {\n // console.log("Analytics captured:", options);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/analytics/<Name>Analytics.spec.ts` to
|
|
7622
|
+
var make_analytics_md_default = '---\nname: make:analytics\ndescription: Generate a new analytics class with its test file, then complete the generated code. Use when creating a new analytics tracking class that uses the @ooneex/analytics package.\n---\n\n# Make Analytics Class\n\nGenerate a new analytics class and its test file using the `make:analytics` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the analytics class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:analytics --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/analytics/<Name>Analytics.ts` - The analytics class file (or `modules/<module>/src/analytics/<Name>Analytics.ts` with `--module`)\n- `tests/analytics/<Name>Analytics.spec.ts` - The test file (or `modules/<module>/tests/analytics/<Name>Analytics.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the analytics class\n\nEdit `src/analytics/<Name>Analytics.ts` to complete the implementation:\n\n- Implement the `capture` method with actual analytics tracking logic\n- Define a proper type for `CaptureOptionsType` instead of `Record<string, unknown>` based on the analytics purpose\n- Add any additional methods or properties relevant to the analytics class purpose\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { type IAnalytics, decorator } from "@ooneex/analytics";\n\ntype CaptureOptionsType = Record<string, unknown>;\n\n@decorator.analytics()\nexport class <Name>Analytics<T extends CaptureOptionsType = CaptureOptionsType> implements IAnalytics<T> {\n public capture(options: T): void {\n // console.log("Analytics captured:", options);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/analytics/<Name>Analytics.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name ends with `Analytics`, is a constructor function\n- **`capture` contract**: method exists, is synchronous (returns `void`), does not throw with valid options\n- **Options shape**: calling `capture` with the expected `CaptureOptionsType` fields produces the expected side effect (spy on the underlying tracker if applicable)\n- **Edge cases**: calling `capture` with an empty object does not throw\n- **Instance isolation**: two instances are independent\n\nThe complete test file must follow this structure:\n\n```typescript\nimport { describe, expect, mock, test } from "bun:test";\nimport { <Name>Analytics } from "@/analytics/<Name>Analytics";\n\ndescribe("<Name>Analytics", () => {\n // --- Class identity ---\n\n test("should have class name ending with \'Analytics\'", () => {\n expect(<Name>Analytics.name.endsWith("Analytics")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof <Name>Analytics).toBe("function");\n });\n\n // --- capture method ---\n\n test("should have \'capture\' method", () => {\n expect(typeof <Name>Analytics.prototype.capture).toBe("function");\n });\n\n test("\'capture\' should not throw when called with an empty object", () => {\n const analytics = new <Name>Analytics();\n expect(() => analytics.capture({} as any)).not.toThrow();\n });\n\n test("\'capture\' should not throw when called with valid options", () => {\n const analytics = new <Name>Analytics();\n expect(() => analytics.capture({ event: "page_view", userId: "u1" } as any)).not.toThrow();\n });\n\n test("\'capture\' should return void", () => {\n const analytics = new <Name>Analytics();\n const result = analytics.capture({ event: "click" } as any);\n expect(result).toBeUndefined();\n });\n\n // --- Behavioral tests (add after implementing capture) ---\n // Example: spy on the underlying tracker to verify the event is forwarded.\n //\n // test("should forward the event to the underlying tracker", () => {\n // const tracker = { track: mock(() => {}) };\n // const analytics = new <Name>Analytics(tracker as any);\n // analytics.capture({ event: "signup", userId: "u2" });\n // expect(tracker.track).toHaveBeenCalledWith(\n // expect.objectContaining({ event: "signup", userId: "u2" }),\n // );\n // });\n\n // --- Instance isolation ---\n\n test("should produce independent instances", () => {\n const a = new <Name>Analytics();\n const b = new <Name>Analytics();\n expect(a).not.toBe(b);\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/analytics/<Name>Analytics.ts tests/analytics/<Name>Analytics.spec.ts\n```\n';
|
|
7610
7623
|
|
|
7611
7624
|
// src/templates/claude/skills/make.cache.md.txt
|
|
7612
|
-
var make_cache_md_default = '---\nname: make:cache\ndescription: Generate a new cache adapter class with its test file, then complete the generated code. Use when creating a new cache adapter that implements the ICache interface from @ooneex/cache.\n---\n\n# Make Cache Class\n\nGenerate a new cache class and its test file using the `make:cache` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the cache class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:cache --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/cache/<Name>Cache.ts` - The cache class file (or `modules/<module>/src/cache/<Name>Cache.ts` with `--module`)\n- `tests/cache/<Name>Cache.spec.ts` - The test file (or `modules/<module>/tests/cache/<Name>Cache.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the cache class\n\nEdit `src/cache/<Name>Cache.ts` to complete the implementation:\n\n- Implement the `get` method to retrieve cached values by key\n- Implement the `set` method to store values with optional TTL\n- Implement the `delete` method to remove cached entries\n- Implement the `has` method to check key existence\n- Replace the `CacheException` throws with actual cache logic\n- Inject any required dependencies (e.g., Redis client) via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { CacheException, type ICache, decorator } from "@ooneex/cache";\n\n@decorator.cache()\nexport class <Name>Cache implements ICache {\n public async get<T = unknown>(key: string): Promise<T | undefined> {\n throw new CacheException(`Failed to get key "${key}": Not implemented`);\n }\n\n public async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\n throw new CacheException(`Failed to set key "${key}": Not implemented`);\n }\n\n public async delete(key: string): Promise<boolean> {\n throw new CacheException(`Failed to delete key "${key}": Not implemented`);\n }\n\n public async has(key: string): Promise<boolean> {\n throw new CacheException(`Failed to check if key "${key}" exists: Not implemented`);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/cache/<Name>Cache.spec.ts` to
|
|
7625
|
+
var make_cache_md_default = '---\nname: make:cache\ndescription: Generate a new cache adapter class with its test file, then complete the generated code. Use when creating a new cache adapter that implements the ICache interface from @ooneex/cache.\n---\n\n# Make Cache Class\n\nGenerate a new cache class and its test file using the `make:cache` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the cache class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:cache --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/cache/<Name>Cache.ts` - The cache class file (or `modules/<module>/src/cache/<Name>Cache.ts` with `--module`)\n- `tests/cache/<Name>Cache.spec.ts` - The test file (or `modules/<module>/tests/cache/<Name>Cache.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the cache class\n\nEdit `src/cache/<Name>Cache.ts` to complete the implementation:\n\n- Implement the `get` method to retrieve cached values by key\n- Implement the `set` method to store values with optional TTL\n- Implement the `delete` method to remove cached entries\n- Implement the `has` method to check key existence\n- Replace the `CacheException` throws with actual cache logic\n- Inject any required dependencies (e.g., Redis client) via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { CacheException, type ICache, decorator } from "@ooneex/cache";\n\n@decorator.cache()\nexport class <Name>Cache implements ICache {\n public async get<T = unknown>(key: string): Promise<T | undefined> {\n throw new CacheException(`Failed to get key "${key}": Not implemented`);\n }\n\n public async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\n throw new CacheException(`Failed to set key "${key}": Not implemented`);\n }\n\n public async delete(key: string): Promise<boolean> {\n throw new CacheException(`Failed to delete key "${key}": Not implemented`);\n }\n\n public async has(key: string): Promise<boolean> {\n throw new CacheException(`Failed to check if key "${key}" exists: Not implemented`);\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/cache/<Name>Cache.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name ends with `Cache`, is a constructor function\n- **Each method**: `get`, `set`, `delete`, `has` exist, are functions, return Promises\n- **Default implementation**: before replacing the throws, verify each method rejects with `CacheException`\n- **After implementation**: add set\u2192get round-trip, set\u2192has, set\u2192delete\u2192has, TTL semantics if supported\n- **Instance isolation**: two instances maintain separate state\n\nThe complete test file must follow this structure:\n\n```typescript\nimport { CacheException } from "@ooneex/cache";\nimport { describe, expect, test } from "bun:test";\nimport { <Name>Cache } from "@/cache/<Name>Cache";\n\ndescribe("<Name>Cache", () => {\n // --- Class identity ---\n\n test("should have class name ending with \'Cache\'", () => {\n expect(<Name>Cache.name.endsWith("Cache")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof <Name>Cache).toBe("function");\n });\n\n // --- Method existence and return type ---\n\n test("should have \'get\' method that returns a Promise", () => {\n const cache = new <Name>Cache();\n expect(typeof <Name>Cache.prototype.get).toBe("function");\n const result = cache.get("k");\n expect(result).toBeInstanceOf(Promise);\n return result.catch(() => {});\n });\n\n test("should have \'set\' method that returns a Promise", () => {\n const cache = new <Name>Cache();\n expect(typeof <Name>Cache.prototype.set).toBe("function");\n const result = cache.set("k", "v");\n expect(result).toBeInstanceOf(Promise);\n return result.catch(() => {});\n });\n\n test("should have \'delete\' method that returns a Promise", () => {\n const cache = new <Name>Cache();\n expect(typeof <Name>Cache.prototype.delete).toBe("function");\n const result = cache.delete("k");\n expect(result).toBeInstanceOf(Promise);\n return result.catch(() => {});\n });\n\n test("should have \'has\' method that returns a Promise", () => {\n const cache = new <Name>Cache();\n expect(typeof <Name>Cache.prototype.has).toBe("function");\n const result = cache.has("k");\n expect(result).toBeInstanceOf(Promise);\n return result.catch(() => {});\n });\n\n // --- Behavioral tests (add after implementing the methods) ---\n // Replace the CacheException tests below with real round-trip tests once implemented.\n\n test("\'get\' should reject with CacheException before implementation", async () => {\n const cache = new <Name>Cache();\n await expect(cache.get("key")).rejects.toBeInstanceOf(CacheException);\n });\n\n test("\'set\' should reject with CacheException before implementation", async () => {\n const cache = new <Name>Cache();\n await expect(cache.set("key", "value")).rejects.toBeInstanceOf(CacheException);\n });\n\n test("\'delete\' should reject with CacheException before implementation", async () => {\n const cache = new <Name>Cache();\n await expect(cache.delete("key")).rejects.toBeInstanceOf(CacheException);\n });\n\n test("\'has\' should reject with CacheException before implementation", async () => {\n const cache = new <Name>Cache();\n await expect(cache.has("key")).rejects.toBeInstanceOf(CacheException);\n });\n\n // Once the cache is implemented, replace the four tests above with:\n //\n // test("set then get should return the stored value", async () => {\n // const cache = new <Name>Cache();\n // await cache.set("user:1", { name: "Alice" });\n // const value = await cache.get("user:1");\n // expect(value).toEqual({ name: "Alice" });\n // });\n //\n // test("has should return true after set", async () => {\n // const cache = new <Name>Cache();\n // await cache.set("flag", true);\n // expect(await cache.has("flag")).toBe(true);\n // });\n //\n // test("has should return false for unknown key", async () => {\n // const cache = new <Name>Cache();\n // expect(await cache.has("unknown-key")).toBe(false);\n // });\n //\n // test("delete should remove a key", async () => {\n // const cache = new <Name>Cache();\n // await cache.set("tmp", 42);\n // await cache.delete("tmp");\n // expect(await cache.has("tmp")).toBe(false);\n // });\n //\n // test("get should return undefined for a deleted key", async () => {\n // const cache = new <Name>Cache();\n // await cache.set("tmp", 42);\n // await cache.delete("tmp");\n // expect(await cache.get("tmp")).toBeUndefined();\n // });\n\n // --- Instance isolation ---\n\n test("should produce independent instances", () => {\n const a = new <Name>Cache();\n const b = new <Name>Cache();\n expect(a).not.toBe(b);\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/cache/<Name>Cache.ts tests/cache/<Name>Cache.spec.ts\n```\n';
|
|
7613
7626
|
|
|
7614
7627
|
// src/templates/claude/skills/make.controller.md.txt
|
|
7615
|
-
var make_controller_md_default = "---\nname: make:controller\ndescription: Generate a new controller class with route type and test file, then complete the generated code. Use when creating a new HTTP or WebSocket controller with routing, validation, and role-based access.\n---\n\n# Make Controller Class\n\nGenerate a new controller class, its route type, and test file using the `make:controller` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport { decorator, type ISeed } from \"@ooneex/seeds\";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the controller class and related files:\n\n```bash\nbunx @ooneex/cli@latest make:controller --name=<name> --module=<module> --is-socket=<true|false> --route-name=<route.name> --route-path=<route.path> --route-method=<route.method>\n```\n\nWhere:\n- `<name>` is the controller name provided by the user\n- `--module` is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root\n- `--is-socket` determines HTTP vs WebSocket controller (defaults to `false`)\n- `--route-name` is the route name using dot notation: `<resource>.<action>` (e.g., `user.create`, `book.list`, `flashcard.delete`)\n- `--route-path` is the route path (e.g., `/users`)\n- `--route-method` is the HTTP method (e.g., `get`, `post`, `put`, `patch`, `delete`) \u2014 only for HTTP controllers\n\nThe command will generate (paths prefixed with `modules/<module>/` when `--module` is provided):\n- `src/controllers/<Name>Controller.ts` - The controller class file\n- `src/types/routes/<route.name>.ts` - The route type file (will be moved into the controller file \u2014 see step 3)\n- `tests/controllers/<Name>Controller.spec.ts` - The test file\n\n### 2. Read the generated files\n\nRead all three generated files to understand the scaffolded code.\n\n### 3. Complete the route type\n\n**IMPORTANT: Keep the route type inside the controller file**, not in a separate type file. Define the type directly in `src/controllers/<Name>Controller.ts` above the class definition. Delete the generated `src/types/routes/<route.name>.ts` file if it was created.\n\n**Remove unnecessary `params`, `payload`, and `queries` \u2014 only include what the route actually needs:**\n\n- **`params`** \u2014 Include only when the route path contains dynamic segments (e.g., `/users/:id`). Remove entirely for routes with no URL parameters (e.g., `/users`).\n- **`payload`** \u2014 Include only for methods that accept a request body (`post`, `put`, `patch`). Remove entirely for `get` and `delete` routes.\n- **`queries`** \u2014 Include only when the route supports query string filtering, pagination, or sorting (e.g., list/search endpoints). Remove entirely when not needed.\n- **`response`** \u2014 Always include.\n\nThe route type structure follows this pattern (remove unused sections):\n\n```typescript\n// Example: GET /users (list) \u2014 no params, no payload, has queries\ntype <TypeName>RouteType = {\n queries: {\n\n },\n response: {\n\n },\n};\n\n// Example: POST /users (create) \u2014 no params, has payload, no queries\ntype <TypeName>RouteType = {\n payload: {\n\n },\n response: {\n\n },\n};\n\n// Example: GET /users/:id (detail) \u2014 has params, no payload, no queries\ntype <TypeName>RouteType = {\n params: {\n\n },\n response: {\n\n },\n};\n\n// Example: PUT /users/:id (update) \u2014 has params, has payload, no queries\ntype <TypeName>RouteType = {\n params: {\n\n },\n payload: {\n\n },\n response: {\n\n },\n};\n```\n\n### 4. Complete the controller class\n\nEdit `src/controllers/<Name>Controller.ts` to complete the implementation:\n\n- Set appropriate `roles` for access control\n- Add a meaningful `description` for the route that explains what the endpoint does (e.g., `\"Create a new user account\"`, `\"List all books with pagination\"`)\n- **Keep the controller thin** \u2014 do NOT put business logic in the controller. Put all logic in the corresponding service and inject the service into the controller via the constructor. The controller's `index` method should only delegate to the service.\n- **Remove unnecessary `params`, `payload`, and `queries`** from both the route type and the `@Route` decorator \u2014 only include what the route actually needs (see step 3 rules).\n\n**Add or remove `params`, `payload`, and `queries` in the `@Route` decorator to match the route type (step 3):**\n\n- **`params`** \u2014 Include with `Assert()` validators only when the route has URL parameters. Remove the `params` key entirely otherwise.\n- **`payload`** \u2014 Include with `Assert({...})` only for `post`, `put`, `patch` methods. Remove the `payload` key entirely for `get` and `delete`.\n- **`queries`** \u2014 Include with `Assert({...})` only when query parameters are expected. Remove the `queries` key entirely otherwise.\n- **`response`** \u2014 Always include with `Assert({...})`.\n\n**HTTP controller** generated structure (remove `params`, `payload`, `queries` as needed \u2014 see rules above):\n\n```typescript\nimport type { ContextType } from \"@ooneex/controller\";\nimport { ERole } from \"@ooneex/role\";\nimport { Route } from \"@ooneex/routing\";\nimport { Assert } from \"@ooneex/validation\";\n\ntype <TypeName>RouteType = {\n // Only include params, payload, queries as needed (see step 3)\n response: {\n\n },\n};\n\n@Route.<method>(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n // Only include params, payload, queries as needed (see step 3)\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n return context.response.json({\n\n });\n }\n}\n```\n\n**Socket controller** generated structure (remove `params`, `payload`, `queries` as needed \u2014 see rules above):\n\n```typescript\nimport type { ContextType } from \"@ooneex/socket\";\nimport { ERole } from \"@ooneex/role\";\nimport { Route } from \"@ooneex/routing\";\nimport { Assert } from \"@ooneex/validation\";\n\ntype <TypeName>RouteType = {\n // Only include params, payload, queries as needed (see step 3)\n response: {\n\n },\n};\n\n@Route.socket(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n // Only include params, payload, queries as needed (see step 3)\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n return context.response.json({\n\n });\n }\n}\n```\n\n### 5. Complete the test file\n\nEdit `tests/controllers/<Name>Controller.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, index method)\n- Add tests relevant to the specific controller behavior\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Controller } from \"@/controllers/<Name>Controller\";\n\ndescribe(\"<Name>Controller\", () => {\n test(\"should have class name ending with 'Controller'\", () => {\n expect(<Name>Controller.name.endsWith(\"Controller\")).toBe(true);\n });\n\n test(\"should have 'index' method\", () => {\n expect(<Name>Controller.prototype.index).toBeDefined();\n expect(typeof <Name>Controller.prototype.index).toBe(\"function\");\n });\n});\n```\n\n### 6. Register the controller in the module\n\nAdd the new controller to the module's `controllers` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Controller } from \"./controllers/<Name>Controller\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [<Name>Controller],\n entities: [],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other controllers registered, append the new controller to the existing `controllers` array and add the import alongside existing imports.\n\n### 7. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/controllers/<Name>Controller.ts tests/controllers/<Name>Controller.spec.ts\n```\n\n### 8. Create the service\n\nAfter the controller is created, generate a service class for the controller's business logic using the `make:service` skill:\n\n```\n/make:service --name=<Name>\n```\n\nWhere `<Name>` matches the controller name (e.g., if the controller is `CreateUserController`, the service is `CreateUserService`).\n\n### 9. Create the pubsub event (mutation only)\n\n**Only create a pubsub event for mutation routes** (`post`, `put`, `patch`, `delete`). Do NOT create a pubsub event for `get` routes or read-only endpoints.\n\nAfter the service is created, generate a pubsub event class for the controller's domain events using the `make:pubsub` skill:\n\n```\n/make:pubsub --name=<Name> --channel=<resource>.<action>\n```\n\nWhere:\n- `<Name>` matches the controller name (e.g., if the controller is `CreateUserController`, the event is `CreateUserEvent`)\n- `<resource>.<action>` follows the same dot notation as the route name (e.g., `user.create`, `book.delete`)\n\nOnce the event is created:\n- Inject the **service** into the **event** via the constructor, and call the service's `execute` method from the event's `handler` method.\n- Inject the **event** into the **controller** via the constructor, and publish the event from the controller's `index` method.\n";
|
|
7628
|
+
var make_controller_md_default = "---\nname: make:controller\ndescription: Generate a new controller class with route type and test file, then complete the generated code. Use when creating a new HTTP or WebSocket controller with routing, validation, and role-based access.\n---\n\n# Make Controller Class\n\nGenerate a new controller class, its route type, and test file using the `make:controller` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport { decorator, type ISeed } from \"@ooneex/seeds\";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the controller class and related files:\n\n```bash\nbunx @ooneex/cli@latest make:controller --name=<name> --module=<module> --is-socket=<true|false> --route-name=<route.name> --route-path=<route.path> --route-method=<route.method>\n```\n\nWhere:\n- `<name>` is the controller name provided by the user\n- `--module` is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root\n- `--is-socket` determines HTTP vs WebSocket controller (defaults to `false`)\n- `--route-name` is the route name using dot notation: `<resource>.<action>` (e.g., `user.create`, `book.list`, `flashcard.delete`)\n- `--route-path` is the route path (e.g., `/users`)\n- `--route-method` is the HTTP method (e.g., `get`, `post`, `put`, `patch`, `delete`) \u2014 only for HTTP controllers\n\nThe command will generate (paths prefixed with `modules/<module>/` when `--module` is provided):\n- `src/controllers/<Name>Controller.ts` - The controller class file\n- `src/types/routes/<route.name>.ts` - The route type file (will be moved into the controller file \u2014 see step 3)\n- `tests/controllers/<Name>Controller.spec.ts` - The test file\n\n### 2. Read the generated files\n\nRead all three generated files to understand the scaffolded code.\n\n### 3. Complete the route type\n\n**IMPORTANT: Keep the route type inside the controller file**, not in a separate type file. Define the type directly in `src/controllers/<Name>Controller.ts` above the class definition. Delete the generated `src/types/routes/<route.name>.ts` file if it was created.\n\n**Remove unnecessary `params`, `payload`, and `queries` \u2014 only include what the route actually needs:**\n\n- **`params`** \u2014 Include only when the route path contains dynamic segments (e.g., `/users/:id`). Remove entirely for routes with no URL parameters (e.g., `/users`).\n- **`payload`** \u2014 Include only for methods that accept a request body (`post`, `put`, `patch`). Remove entirely for `get` and `delete` routes.\n- **`queries`** \u2014 Include only when the route supports query string filtering, pagination, or sorting (e.g., list/search endpoints). Remove entirely when not needed.\n- **`response`** \u2014 Always include.\n\nThe route type structure follows this pattern (remove unused sections):\n\n```typescript\n// Example: GET /users (list) \u2014 no params, no payload, has queries\ntype <TypeName>RouteType = {\n queries: {\n\n },\n response: {\n\n },\n};\n\n// Example: POST /users (create) \u2014 no params, has payload, no queries\ntype <TypeName>RouteType = {\n payload: {\n\n },\n response: {\n\n },\n};\n\n// Example: GET /users/:id (detail) \u2014 has params, no payload, no queries\ntype <TypeName>RouteType = {\n params: {\n\n },\n response: {\n\n },\n};\n\n// Example: PUT /users/:id (update) \u2014 has params, has payload, no queries\ntype <TypeName>RouteType = {\n params: {\n\n },\n payload: {\n\n },\n response: {\n\n },\n};\n```\n\n### 4. Complete the controller class\n\nEdit `src/controllers/<Name>Controller.ts` to complete the implementation:\n\n- Set appropriate `roles` for access control\n- Add a meaningful `description` for the route that explains what the endpoint does (e.g., `\"Create a new user account\"`, `\"List all books with pagination\"`)\n- **Keep the controller thin** \u2014 do NOT put business logic in the controller. Put all logic in the corresponding service and inject the service into the controller via the constructor. The controller's `index` method should only delegate to the service.\n- **Remove unnecessary `params`, `payload`, and `queries`** from both the route type and the `@Route` decorator \u2014 only include what the route actually needs (see step 3 rules).\n\n**Add or remove `params`, `payload`, and `queries` in the `@Route` decorator to match the route type (step 3):**\n\n- **`params`** \u2014 Include with `Assert()` validators only when the route has URL parameters. Remove the `params` key entirely otherwise.\n- **`payload`** \u2014 Include with `Assert({...})` only for `post`, `put`, `patch` methods. Remove the `payload` key entirely for `get` and `delete`.\n- **`queries`** \u2014 Include with `Assert({...})` only when query parameters are expected. Remove the `queries` key entirely otherwise.\n- **`response`** \u2014 Always include with `Assert({...})`.\n\n**HTTP controller** generated structure (remove `params`, `payload`, `queries` as needed \u2014 see rules above):\n\n```typescript\nimport type { ContextType } from \"@ooneex/controller\";\nimport { ERole } from \"@ooneex/role\";\nimport { Route } from \"@ooneex/routing\";\nimport { Assert } from \"@ooneex/validation\";\n\ntype <TypeName>RouteType = {\n // Only include params, payload, queries as needed (see step 3)\n response: {\n\n },\n};\n\n@Route.<method>(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n // Only include params, payload, queries as needed (see step 3)\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n return context.response.json({\n\n });\n }\n}\n```\n\n**Socket controller** generated structure (remove `params`, `payload`, `queries` as needed \u2014 see rules above):\n\n```typescript\nimport type { ContextType } from \"@ooneex/socket\";\nimport { ERole } from \"@ooneex/role\";\nimport { Route } from \"@ooneex/routing\";\nimport { Assert } from \"@ooneex/validation\";\n\ntype <TypeName>RouteType = {\n // Only include params, payload, queries as needed (see step 3)\n response: {\n\n },\n};\n\n@Route.socket(\"<route.path>\", {\n name: \"<route.name>\",\n version: 1,\n description: \"\",\n // Only include params, payload, queries as needed (see step 3)\n response: Assert({\n\n }),\n roles: [ERole.USER],\n})\nexport class <Name>Controller {\n public async index(context: ContextType<<TypeName>RouteType>) {\n return context.response.json({\n\n });\n }\n}\n```\n\n### 5. Complete the test file\n\nEdit `tests/controllers/<Name>Controller.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name ends with `Controller`, is a constructor function\n- **`index` contract**: method exists, returns a `Promise`\n- **Minimal context**: use a stub context with a `response.json` spy to verify the response shape\n- **Instance isolation**: two instances are independent\n\nThe complete test file must follow this structure:\n\n```typescript\nimport { describe, expect, mock, test } from \"bun:test\";\nimport { <Name>Controller } from \"@/controllers/<Name>Controller\";\n\ndescribe(\"<Name>Controller\", () => {\n // --- Class identity ---\n\n test(\"should have class name ending with 'Controller'\", () => {\n expect(<Name>Controller.name.endsWith(\"Controller\")).toBe(true);\n });\n\n test(\"should be a constructor function\", () => {\n expect(typeof <Name>Controller).toBe(\"function\");\n });\n\n // --- index method ---\n\n test(\"should have 'index' method\", () => {\n expect(typeof <Name>Controller.prototype.index).toBe(\"function\");\n });\n\n test(\"'index' should return a Promise\", () => {\n const controller = new <Name>Controller();\n const context = { response: { json: () => {} } } as any;\n const result = controller.index(context);\n expect(result).toBeInstanceOf(Promise);\n return result.catch(() => {});\n });\n\n test(\"'index' should call context.response.json\", async () => {\n const controller = new <Name>Controller();\n const json = mock(() => {});\n const context = { response: { json } } as any;\n try {\n await controller.index(context);\n expect(json).toHaveBeenCalledTimes(1);\n } catch {\n // Expected when injected dependencies are absent \u2014 still validates delegation\n }\n });\n\n // --- Response shape tests ---\n // After injecting a mock service, add tests that verify the JSON payload shape.\n //\n // Example:\n // test(\"'index' should return the expected payload structure\", async () => {\n // let captured: unknown;\n // const context = { response: { json: (data: unknown) => { captured = data; } } } as any;\n // await new <Name>Controller().index(context);\n // expect(captured).toMatchObject({ success: true });\n // });\n\n // --- Instance isolation ---\n\n test(\"should produce independent instances\", () => {\n const a = new <Name>Controller();\n const b = new <Name>Controller();\n expect(a).not.toBe(b);\n });\n});\n```\n\n### 6. Register the controller in the module\n\nAdd the new controller to the module's `controllers` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Controller } from \"./controllers/<Name>Controller\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [<Name>Controller],\n entities: [],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other controllers registered, append the new controller to the existing `controllers` array and add the import alongside existing imports.\n\n### 7. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/controllers/<Name>Controller.ts tests/controllers/<Name>Controller.spec.ts\n```\n\n### 8. Create the service\n\nAfter the controller is created, generate a service class for the controller's business logic using the `make:service` skill:\n\n```\n/make:service --name=<Name>\n```\n\nWhere `<Name>` matches the controller name (e.g., if the controller is `CreateUserController`, the service is `CreateUserService`).\n\n### 9. Create the pubsub event (mutation only)\n\n**Only create a pubsub event for mutation routes** (`post`, `put`, `patch`, `delete`). Do NOT create a pubsub event for `get` routes or read-only endpoints.\n\nAfter the service is created, generate a pubsub event class for the controller's domain events using the `make:pubsub` skill:\n\n```\n/make:pubsub --name=<Name> --channel=<resource>.<action>\n```\n\nWhere:\n- `<Name>` matches the controller name (e.g., if the controller is `CreateUserController`, the event is `CreateUserEvent`)\n- `<resource>.<action>` follows the same dot notation as the route name (e.g., `user.create`, `book.delete`)\n\nOnce the event is created:\n- Inject the **service** into the **event** via the constructor, and call the service's `execute` method from the event's `handler` method.\n- Inject the **event** into the **controller** via the constructor, and publish the event from the controller's `index` method.\n";
|
|
7616
7629
|
|
|
7617
7630
|
// src/templates/claude/skills/make.cron.md.txt
|
|
7618
|
-
var make_cron_md_default = '---\nname: make:cron\ndescription: Generate a new cron job class with its test file, then complete the generated code. Use when creating a new scheduled task that extends the Cron base class from @ooneex/cron.\n---\n\n# Make Cron Class\n\nGenerate a new cron class and its test file using the `make:cron` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the cron class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:cron --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/cron/<Name>Cron.ts` - The cron class file (or `modules/<module>/src/cron/<Name>Cron.ts` with `--module`)\n- `tests/cron/<Name>Cron.spec.ts` - The test file (or `modules/<module>/tests/cron/<Name>Cron.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the cron class\n\nEdit `src/cron/<Name>Cron.ts` to complete the implementation:\n\n- Set the appropriate cron schedule in `getTime()` (e.g., `"every 5 minutes"`, `"every 1 hours"`, `"every 30 seconds"`)\n- Set the timezone in `getTimeZone()` if needed, or keep `null` for server timezone\n- Implement the `handler()` method with the actual cron job logic\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { TimeZoneType } from "@ooneex/country";\nimport { Cron, type CronTimeType, decorator } from "@ooneex/cron";\n\n@decorator.cron()\nexport class <Name>Cron extends Cron {\n public getTime(): CronTimeType {\n // Examples: "every 5 minutes", "every 1 hours", "every 30 seconds"\n return "every 1 hours";\n }\n\n public getTimeZone(): TimeZoneType | null {\n // Return null to use server timezone, or specify a timezone like "Europe/Paris"\n return null;\n }\n\n public async handler(): Promise<void> {\n // Implement your cron handler logic here\n // console.log("<Name>Cron handler executed");\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/cron/<Name>Cron.spec.ts` to
|
|
7631
|
+
var make_cron_md_default = '---\nname: make:cron\ndescription: Generate a new cron job class with its test file, then complete the generated code. Use when creating a new scheduled task that extends the Cron base class from @ooneex/cron.\n---\n\n# Make Cron Class\n\nGenerate a new cron class and its test file using the `make:cron` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the cron class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:cron --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/cron/<Name>Cron.ts` - The cron class file (or `modules/<module>/src/cron/<Name>Cron.ts` with `--module`)\n- `tests/cron/<Name>Cron.spec.ts` - The test file (or `modules/<module>/tests/cron/<Name>Cron.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the cron class\n\nEdit `src/cron/<Name>Cron.ts` to complete the implementation:\n\n- Set the appropriate cron schedule in `getTime()` (e.g., `"every 5 minutes"`, `"every 1 hours"`, `"every 30 seconds"`)\n- Set the timezone in `getTimeZone()` if needed, or keep `null` for server timezone\n- Implement the `handler()` method with the actual cron job logic\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { TimeZoneType } from "@ooneex/country";\nimport { Cron, type CronTimeType, decorator } from "@ooneex/cron";\n\n@decorator.cron()\nexport class <Name>Cron extends Cron {\n public getTime(): CronTimeType {\n // Examples: "every 5 minutes", "every 1 hours", "every 30 seconds"\n return "every 1 hours";\n }\n\n public getTimeZone(): TimeZoneType | null {\n // Return null to use server timezone, or specify a timezone like "Europe/Paris"\n return null;\n }\n\n public async handler(): Promise<void> {\n // Implement your cron handler logic here\n // console.log("<Name>Cron handler executed");\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/cron/<Name>Cron.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name ends with `Cron`, is a constructor function\n- **`getTime`**: exists, returns a non-empty string, matches the `every N unit` format\n- **`getTimeZone`**: exists, returns `null` or a non-empty IANA timezone string\n- **`handler` contract**: exists, returns a `Promise`\n- **Instance isolation**: two instances are independent\n\nThe complete test file must follow this structure:\n\n```typescript\nimport { describe, expect, test } from "bun:test";\nimport { <Name>Cron } from "@/cron/<Name>Cron";\n\ndescribe("<Name>Cron", () => {\n // --- Class identity ---\n\n test("should have class name ending with \'Cron\'", () => {\n expect(<Name>Cron.name.endsWith("Cron")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof <Name>Cron).toBe("function");\n });\n\n // --- getTime ---\n\n test("should have \'getTime\' method", () => {\n expect(typeof <Name>Cron.prototype.getTime).toBe("function");\n });\n\n test("\'getTime\' should return a non-empty string", () => {\n const cron = new <Name>Cron();\n const time = cron.getTime();\n expect(typeof time).toBe("string");\n expect(time.length).toBeGreaterThan(0);\n });\n\n test("\'getTime\' should use the \'every N unit\' format", () => {\n const cron = new <Name>Cron();\n expect(cron.getTime()).toMatch(/^every \\d+ (second|minute|hour|day)s?$/);\n });\n\n // --- getTimeZone ---\n\n test("should have \'getTimeZone\' method", () => {\n expect(typeof <Name>Cron.prototype.getTimeZone).toBe("function");\n });\n\n test("\'getTimeZone\' should return null or a non-empty string", () => {\n const cron = new <Name>Cron();\n const tz = cron.getTimeZone();\n expect(tz === null || (typeof tz === "string" && tz.length > 0)).toBe(true);\n });\n\n // --- handler ---\n\n test("should have \'handler\' method", () => {\n expect(typeof <Name>Cron.prototype.handler).toBe("function");\n });\n\n test("\'handler\' should return a Promise", () => {\n const cron = new <Name>Cron();\n const result = cron.handler();\n expect(result).toBeInstanceOf(Promise);\n return result.catch(() => {});\n });\n\n test("\'handler\' should resolve without throwing", async () => {\n const cron = new <Name>Cron();\n try {\n await cron.handler();\n } catch {\n // Expected when injected dependencies are absent\n }\n });\n\n // --- Instance isolation ---\n\n test("should produce independent instances", () => {\n const a = new <Name>Cron();\n const b = new <Name>Cron();\n expect(a).not.toBe(b);\n });\n});\n```\n\n### 5. Register the cron job in the module\n\nAdd the new cron job to the module\'s `cronJobs` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from "@ooneex/module";\nimport { <Name>Cron } from "./cron/<Name>Cron";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n middlewares: [],\n cronJobs: [<Name>Cron],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other cron jobs registered, append the new cron job to the existing `cronJobs` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/cron/<Name>Cron.ts tests/cron/<Name>Cron.spec.ts\n```\n';
|
|
7619
7632
|
|
|
7620
7633
|
// src/templates/claude/skills/make.database.md.txt
|
|
7621
|
-
var make_database_md_default = '---\nname: make:database\ndescription: Generate a new database class with its test file, then complete the generated code. Use when creating a new database adapter that extends TypeormDatabase from @ooneex/database.\n---\n\n# Make Database Class\n\nGenerate a new database class and its test file using the `make:database` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the database class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:database --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/databases/<Name>Database.ts` - The database class file (or `modules/<module>/src/databases/<Name>Database.ts` with `--module`)\n- `tests/databases/<Name>Database.spec.ts` - The test file (or `modules/<module>/tests/databases/<Name>Database.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the database class\n\nEdit `src/databases/<Name>Database.ts` to complete the implementation:\n\n- Add entity imports and register them in the `entities` array\n- Adjust the database path if needed (default is `"var/db"`)\n- Configure DataSource options as appropriate (type, synchronize, etc.)\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { DataSource } from "typeorm";\nimport { TypeormDatabase, DatabaseException, decorator } from "@ooneex/database";\n\n@decorator.database()\nexport class <Name>Database extends TypeormDatabase {\n public getSource(database?: string): DataSource {\n database = database || "var/db";\n\n this.source = new DataSource({\n synchronize: false,\n entities: [\n // TODO: Load your entities here\n ],\n enableWAL: true,\n busyErrorRetry: 2000,\n busyTimeout: 30_000,\n database,\n type: "sqlite",\n });\n\n return this.source;\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/databases/<Name>Database.spec.ts` to
|
|
7634
|
+
var make_database_md_default = '---\nname: make:database\ndescription: Generate a new database class with its test file, then complete the generated code. Use when creating a new database adapter that extends TypeormDatabase from @ooneex/database.\n---\n\n# Make Database Class\n\nGenerate a new database class and its test file using the `make:database` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the database class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:database --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/databases/<Name>Database.ts` - The database class file (or `modules/<module>/src/databases/<Name>Database.ts` with `--module`)\n- `tests/databases/<Name>Database.spec.ts` - The test file (or `modules/<module>/tests/databases/<Name>Database.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the database class\n\nEdit `src/databases/<Name>Database.ts` to complete the implementation:\n\n- Add entity imports and register them in the `entities` array\n- Adjust the database path if needed (default is `"var/db"`)\n- Configure DataSource options as appropriate (type, synchronize, etc.)\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { DataSource } from "typeorm";\nimport { TypeormDatabase, DatabaseException, decorator } from "@ooneex/database";\n\n@decorator.database()\nexport class <Name>Database extends TypeormDatabase {\n public getSource(database?: string): DataSource {\n database = database || "var/db";\n\n this.source = new DataSource({\n synchronize: false,\n entities: [\n // TODO: Load your entities here\n ],\n enableWAL: true,\n busyErrorRetry: 2000,\n busyTimeout: 30_000,\n database,\n type: "sqlite",\n });\n\n return this.source;\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/databases/<Name>Database.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name ends with `Database`, is a constructor function\n- **`getSource` contract**: method exists, returns a `DataSource` instance (has `initialize` and `destroy` methods)\n- **Default path**: calling `getSource()` without arguments uses `"var/db"` as the database path\n- **Custom path**: calling `getSource("custom/path")` uses the provided path\n- **Entities registered**: the returned `DataSource` options include the expected entities\n- **Instance isolation**: two instances are independent\n\nThe complete test file must follow this structure:\n\n```typescript\nimport { describe, expect, test } from "bun:test";\nimport { <Name>Database } from "@/databases/<Name>Database";\n\ndescribe("<Name>Database", () => {\n // --- Class identity ---\n\n test("should have class name ending with \'Database\'", () => {\n expect(<Name>Database.name.endsWith("Database")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof <Name>Database).toBe("function");\n });\n\n // --- getSource ---\n\n test("should have \'getSource\' method", () => {\n expect(typeof <Name>Database.prototype.getSource).toBe("function");\n });\n\n test("\'getSource\' should return a DataSource-like object", () => {\n const db = new <Name>Database();\n const source = db.getSource();\n expect(source).toBeDefined();\n expect(typeof source.initialize).toBe("function");\n expect(typeof source.destroy).toBe("function");\n });\n\n test("\'getSource\' should use the default database path when no argument is given", () => {\n const db = new <Name>Database();\n const source = db.getSource();\n expect((source.options as any).database).toBe("var/db");\n });\n\n test("\'getSource\' should use the provided path when given", () => {\n const db = new <Name>Database();\n const source = db.getSource("custom/path/db");\n expect((source.options as any).database).toBe("custom/path/db");\n });\n\n test("\'getSource\' options should have synchronize disabled", () => {\n const db = new <Name>Database();\n const source = db.getSource();\n expect((source.options as any).synchronize).toBe(false);\n });\n\n test("\'getSource\' options should include the registered entities", () => {\n const db = new <Name>Database();\n const source = db.getSource();\n expect(Array.isArray((source.options as any).entities)).toBe(true);\n });\n\n // --- Instance isolation ---\n\n test("should produce independent instances", () => {\n const a = new <Name>Database();\n const b = new <Name>Database();\n expect(a).not.toBe(b);\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/databases/<Name>Database.ts tests/databases/<Name>Database.spec.ts\n```\n';
|
|
7622
7635
|
|
|
7623
7636
|
// src/templates/claude/skills/make.entity.md.txt
|
|
7624
|
-
var make_entity_md_default = "---\nname: make:entity\ndescription: Generate a new TypeORM entity class with its test file, then complete the generated code. Use when creating a new database entity with columns, relations, and table mapping.\n---\n\n# Make Entity Class\n\nGenerate a new entity class and its test file using the `make:entity` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, always add `null` to the type of optional properties (i.e., any property marked with `?`). For example, `createdAt?: Date;` must be written as `createdAt?: Date | null;`\n- For optional properties, do NOT use `= undefined` initializer. Use `name?: string | null;` not `name?: string | null = undefined;`\n- Avoid non-null assertions (`!`). For example, `public name!: string;` should be `public name: string;`\n- Always specify `nullable` explicitly in every `@Column` decorator. Never omit it. Use `nullable: true` or `nullable: false`. For example, never write `@Column({ name: \"name\", type: \"varchar\", length: 150 })` \u2014 always write `@Column({ name: \"name\", type: \"varchar\", length: 150, nullable: true })` or `@Column({ name: \"name\", type: \"varchar\", length: 150, nullable: false })`\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport { decorator, type ISeed } from \"@ooneex/seeds\";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the entity class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:entity --name=<name> --module=<module> --table-name=<table_name>\n```\n\nWhere `<name>` is the name provided by the user. The `--table-name` option is optional \u2014 if omitted, it defaults to the snake_case pluralized form of the name (e.g., `UserProfile` becomes `user_profiles`). The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/entities/<Name>Entity.ts` - The entity class file (or `modules/<module>/src/entities/<Name>Entity.ts` with `--module`)\n- `tests/entities/<Name>Entity.spec.ts` - The test file (or `modules/<module>/tests/entities/<Name>Entity.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the entity class\n\nEdit `src/entities/<Name>Entity.ts` to complete the implementation:\n\n- Add entity-specific columns with appropriate TypeORM decorators (`@Column`)\n- Add relations if needed (`@ManyToOne`, `@OneToMany`, `@ManyToMany`, etc.)\n- Remove any scaffolded columns that are not relevant to the entity\n- Adjust column types, lengths, and constraints as needed\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { LocaleType } from \"@ooneex/translation\";\nimport { random } from \"@ooneex/utils\";\nimport { Column, CreateDateColumn, DeleteDateColumn, PrimaryColumn, UpdateDateColumn } from \"typeorm\";\n\n@Entity({\n name: \"<table_name>\",\n})\nexport class <Name>Entity extends BaseEntity {\n @PrimaryColumn({ name: \"id\", type: \"varchar\", length: 25 })\n id: string = random.nanoid(25);\n\n @Column({\n name: \"is_locked\",\n type: \"boolean\",\n default: false,\n nullable: true,\n })\n isLocked?: boolean | null;\n\n @Column({ name: \"locked_at\", type: \"timestamptz\", nullable: true })\n lockedAt?: Date | null;\n\n @Column({\n name: \"is_blocked\",\n type: \"boolean\",\n default: false,\n nullable: true,\n })\n isBlocked?: boolean | null;\n\n @Column({ name: \"blocked_at\", type: \"timestamptz\", nullable: true })\n blockedAt?: Date | null;\n\n @Column({ name: \"block_reason\", type: \"text\", nullable: true })\n blockReason?: string | null;\n\n @Column({ name: \"is_public\", type: \"boolean\", default: true, nullable: true })\n isPublic?: boolean | null;\n\n @Column({ name: \"lang\", type: \"varchar\", length: 10, nullable: true })\n lang?: LocaleType | null;\n\n @CreateDateColumn({ name: \"created_at\" })\n createdAt?: Date | null;\n\n @UpdateDateColumn({ name: \"updated_at\" })\n updatedAt?: Date | null;\n\n @DeleteDateColumn({ name: \"deleted_at\" })\n deletedAt?: Date | null;\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/entities/<Name>Entity.spec.ts` to add meaningful tests beyond the scaffolded ones:\n\n- Keep the existing scaffolded tests (class name, id, default columns)\n- Add tests for any new entity-specific columns and relations\n- Update tests if scaffolded columns were removed\n\nThe generated test structure follows this pattern:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Entity } from \"@/entities/<Name>Entity\";\n\ndescribe(\"<Name>Entity\", () => {\n test(\"should have class name ending with 'Entity'\", () => {\n expect(<Name>Entity.name.endsWith(\"Entity\")).toBe(true);\n });\n\n test(\"should have 'id' property with default nanoid\", () => {\n const entity = new <Name>Entity();\n expect(entity.id).toBeDefined();\n expect(typeof entity.id).toBe(\"string\");\n expect(entity.id.length).toBe(25);\n });\n\n test(\"should have 'isLocked' property\", () => {\n const entity = new <Name>Entity();\n expect(\"isLocked\" in entity).toBe(true);\n });\n\n // ... additional property tests\n});\n```\n\n### 5. Register the entity in the module\n\nAdd the new entity to the module's `entities` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Entity } from \"./entities/<Name>Entity\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [<Name>Entity],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other entities registered, append the new entity to the existing `entities` array and add the import alongside existing imports.\n\n### 6. Create a migration for the entity\n\nAfter creating or updating an entity, generate a migration to apply the corresponding schema changes to the database.\n\nRun the generator:\n\n```bash\nbunx @ooneex/cli@latest make:migration\n```\n\nThen read the generated migration file in `src/migrations/` and complete it:\n\n- In the `up` method, write the SQL to create the table (or alter it if updating an existing entity). Include all columns, types, constraints, defaults, and indexes matching the entity definition.\n- In the `down` method, write the reverse SQL to undo the changes (e.g., `DROP TABLE` or `ALTER TABLE DROP COLUMN`).\n- If the migration depends on another migration (e.g., a foreign key referencing another table), add that migration class to the `getDependencies()` return array.\n\nExample `up` method for a new entity:\n\n```typescript\npublic async up(tx: TransactionSQL): Promise<void> {\n await tx`\n CREATE TABLE IF NOT EXISTS <table_name> (\n id VARCHAR(25) PRIMARY KEY,\n is_locked BOOLEAN DEFAULT false,\n locked_at TIMESTAMPTZ,\n is_blocked BOOLEAN DEFAULT false,\n blocked_at TIMESTAMPTZ,\n block_reason TEXT,\n is_public BOOLEAN DEFAULT true,\n lang VARCHAR(10),\n created_at TIMESTAMPTZ DEFAULT NOW(),\n updated_at TIMESTAMPTZ DEFAULT NOW(),\n deleted_at TIMESTAMPTZ\n )\n `;\n}\n```\n\n### 7. Create a repository for the entity\n\nAfter creating the entity, generate a repository to handle database operations for it.\n\nRun the generator:\n\n```bash\nbunx @ooneex/cli@latest make:repository --name=<name>\n```\n\nWhere `<name>` is the same name used for the entity. The command will generate:\n- `src/repositories/<Name>Repository.ts` - The repository class\n- `tests/repositories/<Name>Repository.spec.ts` - The test file\n\nThen read the generated files and complete the repository implementation:\n\n- Adjust search fields in the `find()` method to match the entity's searchable columns\n- Customize relations loading in `findOne`/`findOneBy` if the entity has relations\n- Add any domain-specific methods relevant to the entity\n- Remove methods that don't apply to the entity\n- Update tests to match the final repository methods\n\n### 8. Lint and format\n\nRun linting and formatting on all generated files:\n\n```bash\nbunx biome check --fix src/entities/<Name>Entity.ts tests/entities/<Name>Entity.spec.ts src/repositories/<Name>Repository.ts tests/repositories/<Name>Repository.spec.ts src/migrations/\n```\n";
|
|
7637
|
+
var make_entity_md_default = "---\nname: make:entity\ndescription: Generate a new TypeORM entity class with its test file, then complete the generated code. Use when creating a new database entity with columns, relations, and table mapping.\n---\n\n# Make Entity Class\n\nGenerate a new entity class and its test file using the `make:entity` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, always add `null` to the type of optional properties (i.e., any property marked with `?`). For example, `createdAt?: Date;` must be written as `createdAt?: Date | null;`\n- For optional properties, do NOT use `= undefined` initializer. Use `name?: string | null;` not `name?: string | null = undefined;`\n- Avoid non-null assertions (`!`). For example, `public name!: string;` should be `public name: string;`\n- Always specify `nullable` explicitly in every `@Column` decorator. Never omit it. Use `nullable: true` or `nullable: false`. For example, never write `@Column({ name: \"name\", type: \"varchar\", length: 150 })` \u2014 always write `@Column({ name: \"name\", type: \"varchar\", length: 150, nullable: true })` or `@Column({ name: \"name\", type: \"varchar\", length: 150, nullable: false })`\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport { decorator, type ISeed } from \"@ooneex/seeds\";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the entity class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:entity --name=<name> --module=<module> --table-name=<table_name>\n```\n\nWhere `<name>` is the name provided by the user. The `--table-name` option is optional \u2014 if omitted, it defaults to the snake_case pluralized form of the name (e.g., `UserProfile` becomes `user_profiles`). The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/entities/<Name>Entity.ts` - The entity class file (or `modules/<module>/src/entities/<Name>Entity.ts` with `--module`)\n- `tests/entities/<Name>Entity.spec.ts` - The test file (or `modules/<module>/tests/entities/<Name>Entity.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the entity class\n\nEdit `src/entities/<Name>Entity.ts` to complete the implementation:\n\n- Add entity-specific columns with appropriate TypeORM decorators (`@Column`)\n- Add relations if needed (`@ManyToOne`, `@OneToMany`, `@ManyToMany`, etc.)\n- Remove any scaffolded columns that are not relevant to the entity\n- Adjust column types, lengths, and constraints as needed\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { LocaleType } from \"@ooneex/translation\";\nimport { random } from \"@ooneex/utils\";\nimport { Column, CreateDateColumn, DeleteDateColumn, PrimaryColumn, UpdateDateColumn } from \"typeorm\";\n\n@Entity({\n name: \"<table_name>\",\n})\nexport class <Name>Entity extends BaseEntity {\n @PrimaryColumn({ name: \"id\", type: \"varchar\", length: 25 })\n id: string = random.nanoid(25);\n\n @Column({\n name: \"is_locked\",\n type: \"boolean\",\n default: false,\n nullable: true,\n })\n isLocked?: boolean | null;\n\n @Column({ name: \"locked_at\", type: \"timestamptz\", nullable: true })\n lockedAt?: Date | null;\n\n @Column({\n name: \"is_blocked\",\n type: \"boolean\",\n default: false,\n nullable: true,\n })\n isBlocked?: boolean | null;\n\n @Column({ name: \"blocked_at\", type: \"timestamptz\", nullable: true })\n blockedAt?: Date | null;\n\n @Column({ name: \"block_reason\", type: \"text\", nullable: true })\n blockReason?: string | null;\n\n @Column({ name: \"is_public\", type: \"boolean\", default: true, nullable: true })\n isPublic?: boolean | null;\n\n @Column({ name: \"lang\", type: \"varchar\", length: 10, nullable: true })\n lang?: LocaleType | null;\n\n @CreateDateColumn({ name: \"created_at\" })\n createdAt?: Date | null;\n\n @UpdateDateColumn({ name: \"updated_at\" })\n updatedAt?: Date | null;\n\n @DeleteDateColumn({ name: \"deleted_at\" })\n deletedAt?: Date | null;\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/entities/<Name>Entity.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: class name ends with `Entity`, is a constructor function\n- **ID generation**: auto-generated, string, 25 chars, unique per instance\n- **Each column property**: property exists (`\"prop\" in entity`), default value is correct, accepts valid values, accepts `null` for nullable columns, accepts `undefined` for optional columns\n- **Boolean columns with defaults**: verify the default is `false` or `true` as declared, verify toggling to the opposite value works\n- **Date/timestamp columns**: start as `undefined`/`null`, accept a `Date` object, accept `null`\n- **String columns**: default is `undefined`/`null`, accepts a string value, accepts `null`\n- **Property assignment**: setting a property on one instance does not affect another instance (no shared state)\n- **Multiple instances**: two instances created in the same test have different `id` values\n\nThe complete test file must follow this structure \u2014 replace `<Name>` with the actual entity name and add/remove property blocks to match the final entity columns:\n\n```typescript\nimport { describe, expect, test } from \"bun:test\";\nimport { <Name>Entity } from \"@/entities/<Name>Entity\";\n\ndescribe(\"<Name>Entity\", () => {\n // --- Class identity ---\n\n test(\"should have class name ending with 'Entity'\", () => {\n expect(<Name>Entity.name.endsWith(\"Entity\")).toBe(true);\n });\n\n test(\"should be a constructor function\", () => {\n expect(typeof <Name>Entity).toBe(\"function\");\n });\n\n // --- ID ---\n\n test(\"should auto-generate a nanoid for 'id'\", () => {\n const entity = new <Name>Entity();\n expect(entity.id).toBeDefined();\n expect(typeof entity.id).toBe(\"string\");\n expect(entity.id.length).toBe(25);\n });\n\n test(\"should generate a unique 'id' for each instance\", () => {\n const a = new <Name>Entity();\n const b = new <Name>Entity();\n expect(a.id).not.toBe(b.id);\n });\n\n // --- isLocked ---\n\n test(\"should have 'isLocked' defaulting to undefined\", () => {\n const entity = new <Name>Entity();\n expect(\"isLocked\" in entity).toBe(true);\n expect(entity.isLocked).toBeUndefined();\n });\n\n test(\"should accept true for 'isLocked'\", () => {\n const entity = new <Name>Entity();\n entity.isLocked = true;\n expect(entity.isLocked).toBe(true);\n });\n\n test(\"should accept false for 'isLocked'\", () => {\n const entity = new <Name>Entity();\n entity.isLocked = false;\n expect(entity.isLocked).toBe(false);\n });\n\n test(\"should accept null for 'isLocked'\", () => {\n const entity = new <Name>Entity();\n entity.isLocked = null;\n expect(entity.isLocked).toBeNull();\n });\n\n // --- lockedAt ---\n\n test(\"should have 'lockedAt' defaulting to undefined\", () => {\n const entity = new <Name>Entity();\n expect(\"lockedAt\" in entity).toBe(true);\n expect(entity.lockedAt).toBeUndefined();\n });\n\n test(\"should accept a Date for 'lockedAt'\", () => {\n const entity = new <Name>Entity();\n const date = new Date(\"2025-01-01T00:00:00Z\");\n entity.lockedAt = date;\n expect(entity.lockedAt).toEqual(date);\n });\n\n test(\"should accept null for 'lockedAt'\", () => {\n const entity = new <Name>Entity();\n entity.lockedAt = null;\n expect(entity.lockedAt).toBeNull();\n });\n\n // --- isBlocked ---\n\n test(\"should have 'isBlocked' defaulting to undefined\", () => {\n const entity = new <Name>Entity();\n expect(\"isBlocked\" in entity).toBe(true);\n expect(entity.isBlocked).toBeUndefined();\n });\n\n test(\"should accept true for 'isBlocked'\", () => {\n const entity = new <Name>Entity();\n entity.isBlocked = true;\n expect(entity.isBlocked).toBe(true);\n });\n\n test(\"should accept null for 'isBlocked'\", () => {\n const entity = new <Name>Entity();\n entity.isBlocked = null;\n expect(entity.isBlocked).toBeNull();\n });\n\n // --- blockedAt ---\n\n test(\"should have 'blockedAt' defaulting to undefined\", () => {\n const entity = new <Name>Entity();\n expect(\"blockedAt\" in entity).toBe(true);\n expect(entity.blockedAt).toBeUndefined();\n });\n\n test(\"should accept a Date for 'blockedAt'\", () => {\n const entity = new <Name>Entity();\n const date = new Date(\"2025-06-15T12:00:00Z\");\n entity.blockedAt = date;\n expect(entity.blockedAt).toEqual(date);\n });\n\n test(\"should accept null for 'blockedAt'\", () => {\n const entity = new <Name>Entity();\n entity.blockedAt = null;\n expect(entity.blockedAt).toBeNull();\n });\n\n // --- blockReason ---\n\n test(\"should have 'blockReason' defaulting to undefined\", () => {\n const entity = new <Name>Entity();\n expect(\"blockReason\" in entity).toBe(true);\n expect(entity.blockReason).toBeUndefined();\n });\n\n test(\"should accept a string for 'blockReason'\", () => {\n const entity = new <Name>Entity();\n entity.blockReason = \"Violated terms of service\";\n expect(entity.blockReason).toBe(\"Violated terms of service\");\n });\n\n test(\"should accept null for 'blockReason'\", () => {\n const entity = new <Name>Entity();\n entity.blockReason = null;\n expect(entity.blockReason).toBeNull();\n });\n\n // --- isPublic ---\n\n test(\"should have 'isPublic' defaulting to undefined\", () => {\n const entity = new <Name>Entity();\n expect(\"isPublic\" in entity).toBe(true);\n expect(entity.isPublic).toBeUndefined();\n });\n\n test(\"should accept true for 'isPublic'\", () => {\n const entity = new <Name>Entity();\n entity.isPublic = true;\n expect(entity.isPublic).toBe(true);\n });\n\n test(\"should accept false for 'isPublic'\", () => {\n const entity = new <Name>Entity();\n entity.isPublic = false;\n expect(entity.isPublic).toBe(false);\n });\n\n test(\"should accept null for 'isPublic'\", () => {\n const entity = new <Name>Entity();\n entity.isPublic = null;\n expect(entity.isPublic).toBeNull();\n });\n\n // --- lang ---\n\n test(\"should have 'lang' defaulting to undefined\", () => {\n const entity = new <Name>Entity();\n expect(\"lang\" in entity).toBe(true);\n expect(entity.lang).toBeUndefined();\n });\n\n test(\"should accept a locale string for 'lang'\", () => {\n const entity = new <Name>Entity();\n entity.lang = \"en\";\n expect(entity.lang).toBe(\"en\");\n });\n\n test(\"should accept null for 'lang'\", () => {\n const entity = new <Name>Entity();\n entity.lang = null;\n expect(entity.lang).toBeNull();\n });\n\n // --- createdAt / updatedAt / deletedAt ---\n\n test(\"should have 'createdAt' defaulting to undefined\", () => {\n const entity = new <Name>Entity();\n expect(\"createdAt\" in entity).toBe(true);\n expect(entity.createdAt).toBeUndefined();\n });\n\n test(\"should accept a Date for 'createdAt'\", () => {\n const entity = new <Name>Entity();\n const date = new Date();\n entity.createdAt = date;\n expect(entity.createdAt).toEqual(date);\n });\n\n test(\"should have 'updatedAt' defaulting to undefined\", () => {\n const entity = new <Name>Entity();\n expect(\"updatedAt\" in entity).toBe(true);\n expect(entity.updatedAt).toBeUndefined();\n });\n\n test(\"should accept a Date for 'updatedAt'\", () => {\n const entity = new <Name>Entity();\n const date = new Date();\n entity.updatedAt = date;\n expect(entity.updatedAt).toEqual(date);\n });\n\n test(\"should have 'deletedAt' defaulting to undefined\", () => {\n const entity = new <Name>Entity();\n expect(\"deletedAt\" in entity).toBe(true);\n expect(entity.deletedAt).toBeUndefined();\n });\n\n test(\"should accept a Date for 'deletedAt'\", () => {\n const entity = new <Name>Entity();\n const date = new Date();\n entity.deletedAt = date;\n expect(entity.deletedAt).toEqual(date);\n });\n\n test(\"should accept null for 'deletedAt' (soft-delete reset)\", () => {\n const entity = new <Name>Entity();\n entity.deletedAt = null;\n expect(entity.deletedAt).toBeNull();\n });\n\n // --- Instance isolation ---\n\n test(\"should not share property state between instances\", () => {\n const a = new <Name>Entity();\n const b = new <Name>Entity();\n a.isLocked = true;\n expect(b.isLocked).toBeUndefined();\n });\n});\n```\n\n**When entity-specific columns were added or scaffolded columns removed**, update the test file accordingly:\n- Remove test blocks for columns that were removed from the entity.\n- Add new test blocks for every custom column following the same patterns above (presence check, default value, valid assignment, null acceptance for nullable columns).\n- For relation properties (e.g., `@ManyToOne`), add a test that the property exists and defaults to `undefined`.\n\n### 5. Register the entity in the module\n\nAdd the new entity to the module's `entities` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from \"@ooneex/module\";\nimport { <Name>Entity } from \"./entities/<Name>Entity\";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [<Name>Entity],\n middlewares: [],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other entities registered, append the new entity to the existing `entities` array and add the import alongside existing imports.\n\n### 6. Create a migration for the entity\n\nAfter creating or updating an entity, use the `make:migration` skill to generate and complete the migration file for this entity.\n\n### 7. Create a repository for the entity\n\nAfter creating the entity, use the `make:repository` skill to generate and complete the repository for this entity.\n\n### 8. Lint and format\n\nRun linting and formatting on the entity files:\n\n```bash\nbunx biome check --fix src/entities/<Name>Entity.ts tests/entities/<Name>Entity.spec.ts\n```\n";
|
|
7625
7638
|
|
|
7626
7639
|
// src/templates/claude/skills/make.logger.md.txt
|
|
7627
|
-
var make_logger_md_default = '---\nname: make:logger\ndescription: Generate a new logger class with its test file, then complete the generated code. Use when creating a new logger that implements the ILogger interface from @ooneex/logger.\n---\n\n# Make Logger Class\n\nGenerate a new logger class and its test file using the `make:logger` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the logger class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:logger --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/loggers/<Name>Logger.ts` - The logger class file (or `modules/<module>/src/loggers/<Name>Logger.ts` with `--module`)\n- `tests/loggers/<Name>Logger.spec.ts` - The test file (or `modules/<module>/tests/loggers/<Name>Logger.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the logger class\n\nEdit `src/loggers/<Name>Logger.ts` to complete the implementation:\n\n- Implement the `init()` method to set up the logger (e.g., open file handles, configure transports)\n- Implement `log`, `debug`, `info`, `success`, `warn`, and `error` methods with actual logging logic\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { IException } from "@ooneex/exception";\nimport { type ILogger, decorator } from "@ooneex/logger";\nimport type { ScalarType } from "@ooneex/types";\n\n@decorator.logger()\nexport class <Name>Logger implements ILogger {\n public async init(): Promise<void> {\n // Initialize your logger here\n }\n\n public log(message: string, data?: Record<string, ScalarType>): void {\n // Handle general logging\n }\n\n public debug(message: string, data?: Record<string, ScalarType>): void {\n // Handle debug logging\n }\n\n public info(message: string, data?: Record<string, ScalarType>): void {\n // Handle info logging\n }\n\n public success(message: string, data?: Record<string, ScalarType>): void {\n // Handle success logging\n }\n\n public warn(message: string, data?: Record<string, ScalarType>): void {\n // Handle warning logging\n }\n\n public error(message: string | IException, data?: Record<string, ScalarType>): void {\n // Handle error logging\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/loggers/<Name>Logger.spec.ts` to
|
|
7640
|
+
var make_logger_md_default = '---\nname: make:logger\ndescription: Generate a new logger class with its test file, then complete the generated code. Use when creating a new logger that implements the ILogger interface from @ooneex/logger.\n---\n\n# Make Logger Class\n\nGenerate a new logger class and its test file using the `make:logger` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the logger class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:logger --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/loggers/<Name>Logger.ts` - The logger class file (or `modules/<module>/src/loggers/<Name>Logger.ts` with `--module`)\n- `tests/loggers/<Name>Logger.spec.ts` - The test file (or `modules/<module>/tests/loggers/<Name>Logger.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the logger class\n\nEdit `src/loggers/<Name>Logger.ts` to complete the implementation:\n\n- Implement the `init()` method to set up the logger (e.g., open file handles, configure transports)\n- Implement `log`, `debug`, `info`, `success`, `warn`, and `error` methods with actual logging logic\n- Inject any required dependencies via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { IException } from "@ooneex/exception";\nimport { type ILogger, decorator } from "@ooneex/logger";\nimport type { ScalarType } from "@ooneex/types";\n\n@decorator.logger()\nexport class <Name>Logger implements ILogger {\n public async init(): Promise<void> {\n // Initialize your logger here\n }\n\n public log(message: string, data?: Record<string, ScalarType>): void {\n // Handle general logging\n }\n\n public debug(message: string, data?: Record<string, ScalarType>): void {\n // Handle debug logging\n }\n\n public info(message: string, data?: Record<string, ScalarType>): void {\n // Handle info logging\n }\n\n public success(message: string, data?: Record<string, ScalarType>): void {\n // Handle success logging\n }\n\n public warn(message: string, data?: Record<string, ScalarType>): void {\n // Handle warning logging\n }\n\n public error(message: string | IException, data?: Record<string, ScalarType>): void {\n // Handle error logging\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/loggers/<Name>Logger.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name ends with `Logger`, is a constructor function\n- **`init` contract**: method exists, returns a `Promise`\n- **Each log method** (`log`, `debug`, `info`, `success`, `warn`, `error`): method exists, does not throw when called with a message string, does not throw when called with a message and a data object\n- **`error` with exception**: calling `error` with an `IException` instance does not throw\n- **Instance isolation**: two instances are independent\n\nThe complete test file must follow this structure:\n\n```typescript\nimport { describe, expect, test } from "bun:test";\nimport { <Name>Logger } from "@/loggers/<Name>Logger";\n\ndescribe("<Name>Logger", () => {\n // --- Class identity ---\n\n test("should have class name ending with \'Logger\'", () => {\n expect(<Name>Logger.name.endsWith("Logger")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof <Name>Logger).toBe("function");\n });\n\n // --- init ---\n\n test("should have \'init\' method", () => {\n expect(typeof <Name>Logger.prototype.init).toBe("function");\n });\n\n test("\'init\' should return a Promise", () => {\n const logger = new <Name>Logger();\n const result = logger.init();\n expect(result).toBeInstanceOf(Promise);\n return result.catch(() => {});\n });\n\n // --- log ---\n\n test("should have \'log\' method", () => {\n expect(typeof <Name>Logger.prototype.log).toBe("function");\n });\n\n test("\'log\' should not throw when called with a message", () => {\n const logger = new <Name>Logger();\n expect(() => logger.log("test message")).not.toThrow();\n });\n\n test("\'log\' should not throw when called with a message and data", () => {\n const logger = new <Name>Logger();\n expect(() => logger.log("test message", { key: "value" })).not.toThrow();\n });\n\n // --- debug ---\n\n test("should have \'debug\' method", () => {\n expect(typeof <Name>Logger.prototype.debug).toBe("function");\n });\n\n test("\'debug\' should not throw when called with a message", () => {\n const logger = new <Name>Logger();\n expect(() => logger.debug("debug message")).not.toThrow();\n });\n\n // --- info ---\n\n test("should have \'info\' method", () => {\n expect(typeof <Name>Logger.prototype.info).toBe("function");\n });\n\n test("\'info\' should not throw when called with a message", () => {\n const logger = new <Name>Logger();\n expect(() => logger.info("info message")).not.toThrow();\n });\n\n // --- success ---\n\n test("should have \'success\' method", () => {\n expect(typeof <Name>Logger.prototype.success).toBe("function");\n });\n\n test("\'success\' should not throw when called with a message", () => {\n const logger = new <Name>Logger();\n expect(() => logger.success("success message")).not.toThrow();\n });\n\n // --- warn ---\n\n test("should have \'warn\' method", () => {\n expect(typeof <Name>Logger.prototype.warn).toBe("function");\n });\n\n test("\'warn\' should not throw when called with a message", () => {\n const logger = new <Name>Logger();\n expect(() => logger.warn("warn message")).not.toThrow();\n });\n\n // --- error ---\n\n test("should have \'error\' method", () => {\n expect(typeof <Name>Logger.prototype.error).toBe("function");\n });\n\n test("\'error\' should not throw when called with a string message", () => {\n const logger = new <Name>Logger();\n expect(() => logger.error("error message")).not.toThrow();\n });\n\n test("\'error\' should not throw when called with an Error-like object", () => {\n const logger = new <Name>Logger();\n const err = { message: "Something went wrong", stack: "" } as any;\n expect(() => logger.error(err)).not.toThrow();\n });\n\n test("\'error\' should not throw when called with a message and data", () => {\n const logger = new <Name>Logger();\n expect(() => logger.error("error message", { code: 500 })).not.toThrow();\n });\n\n // --- Instance isolation ---\n\n test("should produce independent instances", () => {\n const a = new <Name>Logger();\n const b = new <Name>Logger();\n expect(a).not.toBe(b);\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/loggers/<Name>Logger.ts tests/loggers/<Name>Logger.spec.ts\n```\n';
|
|
7628
7641
|
|
|
7629
7642
|
// src/templates/claude/skills/make.mailer.md.txt
|
|
7630
|
-
var make_mailer_md_default = '---\nname: make:mailer\ndescription: Generate a new mailer class with its template and test files, then complete the generated code. Use when creating a new email sender with JSX template using @ooneex/mailer.\n---\n\n# Make Mailer Class\n\nGenerate a new mailer class, its JSX template, and test files using the `make:mailer` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the mailer class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:mailer --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate (paths prefixed with `modules/<module>/` when `--module` is provided):\n- `src/mailers/<Name>Mailer.ts` - The mailer class file\n- `src/mailers/<Name>MailerTemplate.tsx` - The JSX email template\n- `tests/mailers/<Name>Mailer.spec.ts` - The mailer test file\n- `tests/mailers/<Name>MailerTemplate.spec.ts` - The template test file\n\n### 2. Read the generated files\n\nRead all four generated files to understand the scaffolded code.\n\n### 3. Complete the mailer class\n\nEdit `src/mailers/<Name>Mailer.ts` to complete the implementation:\n\n- Adjust the `send` method config type if additional parameters are needed\n- Add any pre-send logic (validation, data transformation, etc.)\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport type { IMailer } from "@ooneex/mailer";\nimport { type <Name>MailerPropsType, <Name>MailerTemplate } from "./<Name>MailerTemplate";\n\nexport class <Name>Mailer implements IMailer {\n constructor(\n @inject("mailer")\n private readonly mailer: IMailer,\n ) {}\n\n public send = async (config: {\n to: string[];\n subject: string;\n from?: { name: string; address: string };\n data?: <Name>MailerPropsType;\n }): Promise<void> => {\n const { data, ...rest } = config;\n\n await this.mailer.send({\n ...rest,\n content: <Name>MailerTemplate(data),\n });\n };\n}\n```\n\n### 4. Complete the mailer template\n\nEdit `src/mailers/<Name>MailerTemplate.tsx` to complete the implementation:\n\n- Update `<Name>MailerPropsType` with the actual props needed for the email\n- Build the email body using `MailerLayout` components (Header, Body, Footer)\n- Add email content, styling, and dynamic data rendering\n\nThe generated template structure follows this pattern:\n\n```tsx\nimport { MailerLayout } from "@ooneex/mailer";\n\nexport type <Name>MailerPropsType = {\n link: string;\n};\n\nexport const <Name>MailerTemplate = (props?: <Name>MailerPropsType) => (\n <MailerLayout>\n <MailerLayout.Header />\n <MailerLayout.Body>\n <a href={props?.link}>Login</a>\n </MailerLayout.Body>\n <MailerLayout.Footer />\n </MailerLayout>\n);\n```\n\n### 5. Complete the test files\n\nEdit `tests/mailers/<Name>Mailer.spec.ts` and `tests/mailers/<Name>MailerTemplate.spec.ts` to
|
|
7643
|
+
var make_mailer_md_default = '---\nname: make:mailer\ndescription: Generate a new mailer class with its template and test files, then complete the generated code. Use when creating a new email sender with JSX template using @ooneex/mailer.\n---\n\n# Make Mailer Class\n\nGenerate a new mailer class, its JSX template, and test files using the `make:mailer` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the mailer class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:mailer --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate (paths prefixed with `modules/<module>/` when `--module` is provided):\n- `src/mailers/<Name>Mailer.ts` - The mailer class file\n- `src/mailers/<Name>MailerTemplate.tsx` - The JSX email template\n- `tests/mailers/<Name>Mailer.spec.ts` - The mailer test file\n- `tests/mailers/<Name>MailerTemplate.spec.ts` - The template test file\n\n### 2. Read the generated files\n\nRead all four generated files to understand the scaffolded code.\n\n### 3. Complete the mailer class\n\nEdit `src/mailers/<Name>Mailer.ts` to complete the implementation:\n\n- Adjust the `send` method config type if additional parameters are needed\n- Add any pre-send logic (validation, data transformation, etc.)\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport type { IMailer } from "@ooneex/mailer";\nimport { type <Name>MailerPropsType, <Name>MailerTemplate } from "./<Name>MailerTemplate";\n\nexport class <Name>Mailer implements IMailer {\n constructor(\n @inject("mailer")\n private readonly mailer: IMailer,\n ) {}\n\n public send = async (config: {\n to: string[];\n subject: string;\n from?: { name: string; address: string };\n data?: <Name>MailerPropsType;\n }): Promise<void> => {\n const { data, ...rest } = config;\n\n await this.mailer.send({\n ...rest,\n content: <Name>MailerTemplate(data),\n });\n };\n}\n```\n\n### 4. Complete the mailer template\n\nEdit `src/mailers/<Name>MailerTemplate.tsx` to complete the implementation:\n\n- Update `<Name>MailerPropsType` with the actual props needed for the email\n- Build the email body using `MailerLayout` components (Header, Body, Footer)\n- Add email content, styling, and dynamic data rendering\n\nThe generated template structure follows this pattern:\n\n```tsx\nimport { MailerLayout } from "@ooneex/mailer";\n\nexport type <Name>MailerPropsType = {\n link: string;\n};\n\nexport const <Name>MailerTemplate = (props?: <Name>MailerPropsType) => (\n <MailerLayout>\n <MailerLayout.Header />\n <MailerLayout.Body>\n <a href={props?.link}>Login</a>\n </MailerLayout.Body>\n <MailerLayout.Footer />\n </MailerLayout>\n);\n```\n\n### 5. Complete the test files\n\nEdit `tests/mailers/<Name>Mailer.spec.ts` and `tests/mailers/<Name>MailerTemplate.spec.ts` to replace the scaffolded tests with comprehensive suites that cover all use cases.\n\n**`<Name>Mailer.spec.ts` coverage requirements:**\n\n- **Class identity**: name ends with `Mailer`, is a constructor function\n- **`send` contract**: method exists, returns a `Promise`\n- **Delegation**: `send` forwards the call to the underlying `IMailer` instance (use a mock)\n- **Content rendering**: the template is rendered and passed as `content` to the underlying mailer\n\n```typescript\nimport { describe, expect, mock, test } from "bun:test";\nimport { <Name>Mailer } from "@/mailers/<Name>Mailer";\n\ndescribe("<Name>Mailer", () => {\n // --- Class identity ---\n\n test("should have class name ending with \'Mailer\'", () => {\n expect(<Name>Mailer.name.endsWith("Mailer")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof <Name>Mailer).toBe("function");\n });\n\n // --- send method ---\n\n test("should have \'send\' method", () => {\n expect(typeof <Name>Mailer.prototype.send).toBe("function");\n });\n\n test("\'send\' should return a Promise", () => {\n const mockMailer = { send: mock(() => Promise.resolve()) };\n const mailer = new <Name>Mailer(mockMailer as any);\n const result = mailer.send({ to: ["user@example.com"], subject: "Test" });\n expect(result).toBeInstanceOf(Promise);\n return result.catch(() => {});\n });\n\n test("\'send\' should delegate to the underlying mailer", async () => {\n const sendMock = mock(() => Promise.resolve());\n const mockMailer = { send: sendMock };\n const mailer = new <Name>Mailer(mockMailer as any);\n await mailer.send({ to: ["user@example.com"], subject: "Hello" });\n expect(sendMock).toHaveBeenCalledTimes(1);\n });\n\n test("\'send\' should forward \'to\' and \'subject\' to the underlying mailer", async () => {\n const sendMock = mock((_config: unknown) => Promise.resolve());\n const mockMailer = { send: sendMock };\n const mailer = new <Name>Mailer(mockMailer as any);\n await mailer.send({ to: ["a@b.com"], subject: "Subj" });\n const calledWith = sendMock.mock.calls[0]?.[0] as any;\n expect(calledWith.to).toEqual(["a@b.com"]);\n expect(calledWith.subject).toBe("Subj");\n });\n\n test("\'send\' should include rendered \'content\' in the delegated call", async () => {\n const sendMock = mock((_config: unknown) => Promise.resolve());\n const mockMailer = { send: sendMock };\n const mailer = new <Name>Mailer(mockMailer as any);\n await mailer.send({ to: ["a@b.com"], subject: "Subj", data: { link: "https://example.com" } });\n const calledWith = sendMock.mock.calls[0]?.[0] as any;\n expect(calledWith.content).toBeDefined();\n });\n\n // --- Instance isolation ---\n\n test("should produce independent instances", () => {\n const mockMailer = { send: mock(() => Promise.resolve()) };\n const a = new <Name>Mailer(mockMailer as any);\n const b = new <Name>Mailer(mockMailer as any);\n expect(a).not.toBe(b);\n });\n});\n```\n\n**`<Name>MailerTemplate.spec.ts` coverage requirements:**\n\n- **Function existence**: `<Name>MailerTemplate` is a function\n- **Renders with props**: calling with props returns JSX (non-null, object-like)\n- **Renders without props**: calling with no arguments does not throw\n- **Props reflected in output**: rendered output contains expected content from props\n\n```typescript\nimport { describe, expect, test } from "bun:test";\nimport { <Name>MailerTemplate } from "@/mailers/<Name>MailerTemplate";\n\ndescribe("<Name>MailerTemplate", () => {\n test("should be a function", () => {\n expect(typeof <Name>MailerTemplate).toBe("function");\n });\n\n test("should render without props without throwing", () => {\n expect(() => <Name>MailerTemplate()).not.toThrow();\n });\n\n test("should render with props without throwing", () => {\n expect(() => <Name>MailerTemplate({ link: "https://example.com" })).not.toThrow();\n });\n\n test("should return a non-null value", () => {\n const result = <Name>MailerTemplate({ link: "https://example.com" });\n expect(result).not.toBeNull();\n expect(result).toBeDefined();\n });\n\n // Add props-specific assertions after updating <Name>MailerPropsType:\n //\n // test("should include the link in the rendered output", () => {\n // const result = <Name>MailerTemplate({ link: "https://example.com" });\n // // Inspect JSX element props or rendered HTML string as appropriate\n // expect(JSON.stringify(result)).toContain("https://example.com");\n // });\n});\n```\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/mailers/<Name>Mailer.ts src/mailers/<Name>MailerTemplate.tsx tests/mailers/<Name>Mailer.spec.ts tests/mailers/<Name>MailerTemplate.spec.ts\n```\n';
|
|
7631
7644
|
|
|
7632
7645
|
// src/templates/claude/skills/make.middleware.md.txt
|
|
7633
|
-
var make_middleware_md_default = '---\nname: make:middleware\ndescription: Generate a new middleware class with its test file, then complete the generated code. Use when creating a new HTTP or WebSocket middleware that implements IMiddleware from @ooneex/middleware.\n---\n\n# Make Middleware Class\n\nGenerate a new middleware class and its test file using the `make:middleware` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the middleware class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:middleware --name=<name> --module=<module> --is-socket=<true|false>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The `--is-socket` option determines whether to generate an HTTP middleware or a WebSocket middleware (defaults to `false` if omitted). The command will generate:\n- `src/middlewares/<Name>Middleware.ts` - The middleware class file (or `modules/<module>/src/middlewares/<Name>Middleware.ts` with `--module`)\n- `tests/middlewares/<Name>Middleware.spec.ts` - The test file (or `modules/<module>/tests/middlewares/<Name>Middleware.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the middleware class\n\nEdit `src/middlewares/<Name>Middleware.ts` to complete the implementation:\n\n- Implement the `handler` method with actual middleware logic\n- Add request/response transformations, authentication checks, logging, etc.\n- Inject any required dependencies via the constructor\n\n**HTTP middleware** generated structure:\n\n```typescript\nimport type { ContextType } from "@ooneex/controller";\nimport { decorator, type IMiddleware } from "@ooneex/middleware";\n\n@decorator.middleware()\nexport class <Name>Middleware implements IMiddleware {\n public async handler(context: ContextType): Promise<ContextType> {\n // Example: Add custom header\n // context.response.header("X-Custom-Header", "value");\n\n return context\n }\n}\n```\n\n**Socket middleware** generated structure:\n\n```typescript\nimport type { ContextType } from "@ooneex/socket";\nimport { decorator, type IMiddleware } from "@ooneex/middleware";\n\n@decorator.middleware()\nexport class <Name>Middleware implements IMiddleware {\n public async handler(context: ContextType): Promise<ContextType> {\n // Example: Add custom header\n // context.response.header("X-Custom-Header", "value");\n\n return context\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/middlewares/<Name>Middleware.spec.ts` to
|
|
7646
|
+
var make_middleware_md_default = '---\nname: make:middleware\ndescription: Generate a new middleware class with its test file, then complete the generated code. Use when creating a new HTTP or WebSocket middleware that implements IMiddleware from @ooneex/middleware.\n---\n\n# Make Middleware Class\n\nGenerate a new middleware class and its test file using the `make:middleware` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the middleware class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:middleware --name=<name> --module=<module> --is-socket=<true|false>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The `--is-socket` option determines whether to generate an HTTP middleware or a WebSocket middleware (defaults to `false` if omitted). The command will generate:\n- `src/middlewares/<Name>Middleware.ts` - The middleware class file (or `modules/<module>/src/middlewares/<Name>Middleware.ts` with `--module`)\n- `tests/middlewares/<Name>Middleware.spec.ts` - The test file (or `modules/<module>/tests/middlewares/<Name>Middleware.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the middleware class\n\nEdit `src/middlewares/<Name>Middleware.ts` to complete the implementation:\n\n- Implement the `handler` method with actual middleware logic\n- Add request/response transformations, authentication checks, logging, etc.\n- Inject any required dependencies via the constructor\n\n**HTTP middleware** generated structure:\n\n```typescript\nimport type { ContextType } from "@ooneex/controller";\nimport { decorator, type IMiddleware } from "@ooneex/middleware";\n\n@decorator.middleware()\nexport class <Name>Middleware implements IMiddleware {\n public async handler(context: ContextType): Promise<ContextType> {\n // Example: Add custom header\n // context.response.header("X-Custom-Header", "value");\n\n return context\n }\n}\n```\n\n**Socket middleware** generated structure:\n\n```typescript\nimport type { ContextType } from "@ooneex/socket";\nimport { decorator, type IMiddleware } from "@ooneex/middleware";\n\n@decorator.middleware()\nexport class <Name>Middleware implements IMiddleware {\n public async handler(context: ContextType): Promise<ContextType> {\n // Example: Add custom header\n // context.response.header("X-Custom-Header", "value");\n\n return context\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/middlewares/<Name>Middleware.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name ends with `Middleware`, is a constructor function\n- **`handler` contract**: method exists, returns a `Promise`, resolves to the same context object (pass-through contract)\n- **Context immutability**: `handler` must return the original context reference (not a copy)\n- **Instance isolation**: two instances are independent\n\nThe complete test file must follow this structure:\n\n```typescript\nimport { describe, expect, test } from "bun:test";\nimport { <Name>Middleware } from "@/middlewares/<Name>Middleware";\n\ndescribe("<Name>Middleware", () => {\n // --- Class identity ---\n\n test("should have class name ending with \'Middleware\'", () => {\n expect(<Name>Middleware.name.endsWith("Middleware")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof <Name>Middleware).toBe("function");\n });\n\n // --- handler method ---\n\n test("should have \'handler\' method", () => {\n expect(typeof <Name>Middleware.prototype.handler).toBe("function");\n });\n\n test("\'handler\' should return a Promise", () => {\n const middleware = new <Name>Middleware();\n const context = {} as any;\n const result = middleware.handler(context);\n expect(result).toBeInstanceOf(Promise);\n return result.catch(() => {});\n });\n\n test("\'handler\' should resolve to the context object", async () => {\n const middleware = new <Name>Middleware();\n const context = { request: {}, response: { header: () => {} } } as any;\n const result = await middleware.handler(context);\n expect(result).toBe(context);\n });\n\n test("\'handler\' should not replace the context with a different object", async () => {\n const middleware = new <Name>Middleware();\n const context = { request: {}, response: { header: () => {} } } as any;\n const returned = await middleware.handler(context);\n expect(returned).toBe(context);\n });\n\n // --- Behavior tests ---\n // Add tests for any transformations, header injections, auth checks, or\n // redirects the middleware performs. Use a minimal mock context.\n //\n // Example for a middleware that injects a header:\n // test("should add \'X-Custom-Header\' to the response", async () => {\n // const headers: Record<string, string> = {};\n // const context = {\n // request: {},\n // response: { header: (k: string, v: string) => { headers[k] = v; } },\n // } as any;\n // await new <Name>Middleware().handler(context);\n // expect(headers["X-Custom-Header"]).toBeDefined();\n // });\n\n // --- Instance isolation ---\n\n test("should produce independent instances", () => {\n const a = new <Name>Middleware();\n const b = new <Name>Middleware();\n expect(a).not.toBe(b);\n });\n});\n```\n\n### 5. Register the middleware in the module\n\nAdd the new middleware to the module\'s `middlewares` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from "@ooneex/module";\nimport { <Name>Middleware } from "./middlewares/<Name>Middleware";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n middlewares: [<Name>Middleware],\n cronJobs: [],\n events: [],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other middlewares registered, append the new middleware to the existing `middlewares` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/middlewares/<Name>Middleware.ts tests/middlewares/<Name>Middleware.spec.ts\n```\n';
|
|
7634
7647
|
|
|
7635
7648
|
// src/templates/claude/skills/make.migration.md.txt
|
|
7636
|
-
var make_migration_md_default = '---\nname: make:migration\ndescription: Generate a new database migration file with its test file, then complete the generated code. Use when creating a new database migration for schema changes using @ooneex/migrations.\n---\n\n# Make Migration\n\nGenerate a new migration file and its test file using the `make:migration` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the migration file and test files:\n\n```bash\nbunx @ooneex/cli@latest make:migration --module=<module>\n```\n\nThe `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/migrations/Migration<version>.ts` - The migration class file (or `modules/<module>/src/migrations/Migration<version>.ts` with `--module`)\n- `tests/migrations/Migration<version>.spec.ts` - The test file (or `modules/<module>/tests/migrations/Migration<version>.spec.ts` with `--module`)\n\nIt will also:\n- Generate a `migrations.ts` root export file in the migrations directory\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the migration\n\nEdit `src/migrations/Migration<version>.ts` to implement:\n\n- The `up` method with the schema changes (create tables, add columns, create indexes, etc.)\n- The `down` method with the reverse operations to undo the migration\n\n#### Indexes\n\nAlways add indexes on fields that are frequently queried, filtered, sorted, or used in joins. Apply the following rules:\n\n- **Foreign keys**: always indexed (e.g. `user_id`, `order_id`)\n- **Lookup fields**: fields used in `WHERE` clauses (e.g. `email`, `slug`, `token`, `status`, `type`)\n- **Sort fields**: fields used in `ORDER BY` (e.g. `created_at`, `updated_at`, `position`)\n- **Unique constraints**: add a unique index for fields that must be unique (e.g. `email`, `slug`, `uuid`)\n- **Composite indexes**: when two fields are always queried together, prefer a single composite index over two separate ones\n\nDrop each index explicitly in the `down` method before dropping the table or column it covers.\n\n### 4. Complete the test file\n\nEdit `tests/migrations/Migration<version>.spec.ts` to
|
|
7649
|
+
var make_migration_md_default = '---\nname: make:migration\ndescription: Generate a new database migration file with its test file, then complete the generated code. Use when creating a new database migration for schema changes using @ooneex/migrations.\n---\n\n# Make Migration\n\nGenerate a new migration file and its test file using the `make:migration` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the migration file and test files:\n\n```bash\nbunx @ooneex/cli@latest make:migration --module=<module>\n```\n\nThe `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/migrations/Migration<version>.ts` - The migration class file (or `modules/<module>/src/migrations/Migration<version>.ts` with `--module`)\n- `tests/migrations/Migration<version>.spec.ts` - The test file (or `modules/<module>/tests/migrations/Migration<version>.spec.ts` with `--module`)\n\nIt will also:\n- Generate a `migrations.ts` root export file in the migrations directory\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the migration\n\nEdit `src/migrations/Migration<version>.ts` to implement:\n\n- The `up` method with the schema changes (create tables, add columns, create indexes, etc.)\n- The `down` method with the reverse operations to undo the migration\n\n#### Indexes\n\nAlways add indexes on fields that are frequently queried, filtered, sorted, or used in joins. Apply the following rules:\n\n- **Foreign keys**: always indexed (e.g. `user_id`, `order_id`)\n- **Lookup fields**: fields used in `WHERE` clauses (e.g. `email`, `slug`, `token`, `status`, `type`)\n- **Sort fields**: fields used in `ORDER BY` (e.g. `created_at`, `updated_at`, `position`)\n- **Unique constraints**: add a unique index for fields that must be unique (e.g. `email`, `slug`, `uuid`)\n- **Composite indexes**: when two fields are always queried together, prefer a single composite index over two separate ones\n\nDrop each index explicitly in the `down` method before dropping the table or column it covers.\n\n### 4. Complete the test file\n\nEdit `tests/migrations/Migration<version>.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name starts with `Migration`, is a constructor function\n- **`up` / `down` contract**: both exist, return Promises (runtime execution requires a DB connection \u2014 structural test only)\n- **`getVersion`**: exists, returns a string or number that is non-empty/positive and matches the version in the class name\n- **`getDependencies`**: exists, returns an array (empty if no dependency, or containing migration class references)\n- **Symmetry hint**: comment reminder that every `up` operation must have a corresponding `down`\n\nThe complete test file must follow this structure:\n\n```typescript\nimport { describe, expect, test } from "bun:test";\nimport { Migration<version> } from "@/migrations/Migration<version>";\n\ndescribe("Migration<version>", () => {\n // --- Class identity ---\n\n test("should have class name starting with \'Migration\'", () => {\n expect(Migration<version>.name.startsWith("Migration")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof Migration<version>).toBe("function");\n });\n\n // --- up ---\n\n test("should have \'up\' method", () => {\n expect(typeof Migration<version>.prototype.up).toBe("function");\n });\n\n test("\'up\' should return a Promise when called with a mock runner", () => {\n const migration = new Migration<version>();\n const mockRunner = {\n query: async (_sql: string) => {},\n startTransaction: async () => {},\n commitTransaction: async () => {},\n rollbackTransaction: async () => {},\n } as any;\n const result = migration.up(mockRunner);\n expect(result).toBeInstanceOf(Promise);\n return result.catch(() => {});\n });\n\n // --- down ---\n\n test("should have \'down\' method", () => {\n expect(typeof Migration<version>.prototype.down).toBe("function");\n });\n\n test("\'down\' should return a Promise when called with a mock runner", () => {\n const migration = new Migration<version>();\n const mockRunner = {\n query: async (_sql: string) => {},\n startTransaction: async () => {},\n commitTransaction: async () => {},\n rollbackTransaction: async () => {},\n } as any;\n const result = migration.down(mockRunner);\n expect(result).toBeInstanceOf(Promise);\n return result.catch(() => {});\n });\n\n // --- getVersion ---\n\n test("should have \'getVersion\' method", () => {\n expect(typeof Migration<version>.prototype.getVersion).toBe("function");\n });\n\n test("\'getVersion\' should return a non-empty value", () => {\n const migration = new Migration<version>();\n const version = migration.getVersion();\n expect(version !== null && version !== undefined && String(version).length > 0).toBe(true);\n });\n\n test("\'getVersion\' result should match the version suffix in the class name", () => {\n const migration = new Migration<version>();\n const version = String(migration.getVersion());\n expect(Migration<version>.name).toContain(version);\n });\n\n // --- getDependencies ---\n\n test("should have \'getDependencies\' method", () => {\n expect(typeof Migration<version>.prototype.getDependencies).toBe("function");\n });\n\n test("\'getDependencies\' should return an array", () => {\n const migration = new Migration<version>();\n expect(Array.isArray(migration.getDependencies())).toBe(true);\n });\n\n // --- Instance isolation ---\n\n test("should produce independent instances", () => {\n const a = new Migration<version>();\n const b = new Migration<version>();\n expect(a).not.toBe(b);\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/migrations/Migration<version>.ts tests/migrations/Migration<version>.spec.ts\n```\n';
|
|
7637
7650
|
|
|
7638
7651
|
// src/templates/claude/skills/make.permission.md.txt
|
|
7639
|
-
var make_permission_md_default = '---\nname: make:permission\ndescription: Generate a new permission class with its test file, then complete the generated code. Use when creating a new permission that extends Permission from @ooneex/permission.\n---\n\n# Make Permission Class\n\nGenerate a new permission class and its test file using the `make:permission` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the permission class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:permission --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/permissions/<Name>Permission.ts` - The permission class file (or `modules/<module>/src/permissions/<Name>Permission.ts` with `--module`)\n- `tests/permissions/<Name>Permission.spec.ts` - The test file (or `modules/<module>/tests/permissions/<Name>Permission.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the permission class\n\nEdit `src/permissions/<Name>Permission.ts` to complete the implementation:\n\n- Implement the `allow()` method with permission rules using `this.ability.can()`\n- Implement the `setUserPermissions()` method with role-based permission logic\n- Define which actions (read, create, update, delete, manage) are allowed on which entities\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { ContextType } from "@ooneex/controller";\nimport { decorator, Permission } from "@ooneex/permission";\n\n@decorator.permission()\nexport class <Name>Permission extends Permission {\n public allow(): this {\n // Example: Add permissions using this.ability.can()\n // this.ability.can("read", "YourEntity");\n // this.ability.can(["read", "update"], "YourEntity", { userId: user.id });\n\n return this;\n }\n\n public setUserPermissions(context: ContextType): this {\n // Example: Grant full access to admins\n // const { user } = context;\n //\n // if (!user) {\n // return this;\n // }\n //\n // const { roles } = user;\n // if (roles.includes(ERole.ADMIN)) {\n // this.ability.can("manage", "all");\n // return this;\n // }\n\n // Example: Grant specific permissions based on roles\n // const { user } = context;\n //\n // if (user) {\n // for (const role of user.roles) {\n // if (role === ERole.USER) {\n // this.ability.can(["read", "update"], "YourEntity", { userId: user.id });\n // }\n //\n // if (role === ERole.GUEST) {\n // this.ability.can("read", "YourEntity", { public: true });\n // }\n // }\n // }\n\n return this;\n }\n\n public check(context: ContextType): boolean {\n return true;\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/permissions/<Name>Permission.spec.ts` to
|
|
7652
|
+
var make_permission_md_default = '---\nname: make:permission\ndescription: Generate a new permission class with its test file, then complete the generated code. Use when creating a new permission that extends Permission from @ooneex/permission.\n---\n\n# Make Permission Class\n\nGenerate a new permission class and its test file using the `make:permission` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the permission class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:permission --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/permissions/<Name>Permission.ts` - The permission class file (or `modules/<module>/src/permissions/<Name>Permission.ts` with `--module`)\n- `tests/permissions/<Name>Permission.spec.ts` - The test file (or `modules/<module>/tests/permissions/<Name>Permission.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the permission class\n\nEdit `src/permissions/<Name>Permission.ts` to complete the implementation:\n\n- Implement the `allow()` method with permission rules using `this.ability.can()`\n- Implement the `setUserPermissions()` method with role-based permission logic\n- Define which actions (read, create, update, delete, manage) are allowed on which entities\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport type { ContextType } from "@ooneex/controller";\nimport { decorator, Permission } from "@ooneex/permission";\n\n@decorator.permission()\nexport class <Name>Permission extends Permission {\n public allow(): this {\n // Example: Add permissions using this.ability.can()\n // this.ability.can("read", "YourEntity");\n // this.ability.can(["read", "update"], "YourEntity", { userId: user.id });\n\n return this;\n }\n\n public setUserPermissions(context: ContextType): this {\n // Example: Grant full access to admins\n // const { user } = context;\n //\n // if (!user) {\n // return this;\n // }\n //\n // const { roles } = user;\n // if (roles.includes(ERole.ADMIN)) {\n // this.ability.can("manage", "all");\n // return this;\n // }\n\n // Example: Grant specific permissions based on roles\n // const { user } = context;\n //\n // if (user) {\n // for (const role of user.roles) {\n // if (role === ERole.USER) {\n // this.ability.can(["read", "update"], "YourEntity", { userId: user.id });\n // }\n //\n // if (role === ERole.GUEST) {\n // this.ability.can("read", "YourEntity", { public: true });\n // }\n // }\n // }\n\n return this;\n }\n\n public check(context: ContextType): boolean {\n return true;\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/permissions/<Name>Permission.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name ends with `Permission`, is a constructor function\n- **Inheritance**: instance is a `Permission` instance\n- **`allow` contract**: exists, returns `this` (fluent interface)\n- **`setUserPermissions` contract**: exists, accepts a context, returns `this`\n- **`check` contract**: exists, returns a `boolean`\n- **Rule tests**: after implementing, add one test per role/action combination in `allow()` and `setUserPermissions()`\n- **Instance isolation**: two instances are independent\n\nThe complete test file must follow this structure:\n\n```typescript\nimport { Permission } from "@ooneex/permission";\nimport { describe, expect, test } from "bun:test";\nimport { <Name>Permission } from "@/permissions/<Name>Permission";\n\ndescribe("<Name>Permission", () => {\n // --- Class identity ---\n\n test("should have class name ending with \'Permission\'", () => {\n expect(<Name>Permission.name.endsWith("Permission")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof <Name>Permission).toBe("function");\n });\n\n test("should extend Permission", () => {\n const permission = new <Name>Permission();\n expect(permission).toBeInstanceOf(Permission);\n });\n\n // --- allow ---\n\n test("should have \'allow\' method", () => {\n expect(typeof <Name>Permission.prototype.allow).toBe("function");\n });\n\n test("\'allow\' should return \'this\' for fluent chaining", () => {\n const permission = new <Name>Permission();\n expect(permission.allow()).toBe(permission);\n });\n\n test("\'allow\' should not throw", () => {\n const permission = new <Name>Permission();\n expect(() => permission.allow()).not.toThrow();\n });\n\n // --- setUserPermissions ---\n\n test("should have \'setUserPermissions\' method", () => {\n expect(typeof <Name>Permission.prototype.setUserPermissions).toBe("function");\n });\n\n test("\'setUserPermissions\' should return \'this\' for fluent chaining", () => {\n const permission = new <Name>Permission();\n const context = {} as any;\n expect(permission.setUserPermissions(context)).toBe(permission);\n });\n\n test("\'setUserPermissions\' should not throw when user is absent from context", () => {\n const permission = new <Name>Permission();\n expect(() => permission.setUserPermissions({ user: undefined } as any)).not.toThrow();\n });\n\n // --- check ---\n\n test("should have \'check\' method", () => {\n expect(typeof <Name>Permission.prototype.check).toBe("function");\n });\n\n test("\'check\' should return a boolean", () => {\n const permission = new <Name>Permission();\n const result = permission.check({} as any);\n expect(typeof result).toBe("boolean");\n });\n\n // --- Rule tests (add after implementing allow/setUserPermissions) ---\n // Add one test per role/action combination.\n //\n // Example for ADMIN having full access:\n // test("admin should be allowed to manage all resources", () => {\n // const permission = new <Name>Permission();\n // permission.setUserPermissions({ user: { roles: ["admin"] } } as any);\n // expect(permission.ability.can("manage", "all")).toBe(true);\n // });\n //\n // Example for GUEST having read-only access:\n // test("guest should only be allowed to read public resources", () => {\n // const permission = new <Name>Permission();\n // permission.setUserPermissions({ user: { roles: ["guest"] } } as any);\n // expect(permission.ability.can("read", "YourEntity")).toBe(true);\n // expect(permission.ability.can("create", "YourEntity")).toBe(false);\n // });\n\n // --- Instance isolation ---\n\n test("should produce independent instances", () => {\n const a = new <Name>Permission();\n const b = new <Name>Permission();\n expect(a).not.toBe(b);\n });\n});\n```\n\n### 5. Register the permission in the module\n\nThe permission class is standalone and does not need to be registered in a module.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/permissions/<Name>Permission.ts tests/permissions/<Name>Permission.spec.ts\n```\n';
|
|
7640
7653
|
|
|
7641
7654
|
// src/templates/claude/skills/make.pubsub.md.txt
|
|
7642
|
-
var make_pubsub_md_default = '---\nname: make:pubsub\ndescription: Generate a new PubSub event class with its test file, then complete the generated code. Use when creating a new publish/subscribe event that extends PubSub from @ooneex/pub-sub.\n---\n\n# Make PubSub Event Class\n\nGenerate a new PubSub event class and its test file using the `make:pubsub` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the PubSub event class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:pubsub --name=<name> --module=<module> --channel=<channel>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The `--channel` option is optional \u2014 if omitted, it defaults to the kebab-case form of the name (e.g., `UserCreated` becomes `user-created`). The command will generate:\n- `src/events/<Name>Event.ts` - The event class file (or `modules/<module>/src/events/<Name>Event.ts` with `--module`)\n- `tests/events/<Name>Event.spec.ts` - The test file (or `modules/<module>/tests/events/<Name>Event.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the PubSub event class\n\nEdit `src/events/<Name>Event.ts` to complete the implementation:\n\n- Define a proper data type instead of `Record<string, ScalarType>` for the event payload\n- Implement the `handler()` method with actual event handling logic\n- Set the appropriate channel name in `getChannel()`\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport type { ScalarType } from "@ooneex/types";\nimport { decorator, PubSub, RedisPubSub } from "@ooneex/pub-sub";\n\n@decorator.pubSub()\nexport class <Name>Event<Data extends Record<string, ScalarType> = Record<string, ScalarType>> extends PubSub<Data> {\n constructor(\n @inject(RedisPubSub)\n client: RedisPubSub<Data>,\n ) {\n super(client);\n }\n\n public getChannel(): string {\n return "<channel>";\n }\n\n public async handler(context: { data: Data; channel: string }): Promise<void> {\n console.log(context);\n // TODO: Implement handler logic here\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/events/<Name>Event.spec.ts` to
|
|
7655
|
+
var make_pubsub_md_default = '---\nname: make:pubsub\ndescription: Generate a new PubSub event class with its test file, then complete the generated code. Use when creating a new publish/subscribe event that extends PubSub from @ooneex/pub-sub.\n---\n\n# Make PubSub Event Class\n\nGenerate a new PubSub event class and its test file using the `make:pubsub` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the PubSub event class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:pubsub --name=<name> --module=<module> --channel=<channel>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The `--channel` option is optional \u2014 if omitted, it defaults to the kebab-case form of the name (e.g., `UserCreated` becomes `user-created`). The command will generate:\n- `src/events/<Name>Event.ts` - The event class file (or `modules/<module>/src/events/<Name>Event.ts` with `--module`)\n- `tests/events/<Name>Event.spec.ts` - The test file (or `modules/<module>/tests/events/<Name>Event.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the PubSub event class\n\nEdit `src/events/<Name>Event.ts` to complete the implementation:\n\n- Define a proper data type instead of `Record<string, ScalarType>` for the event payload\n- Implement the `handler()` method with actual event handling logic\n- Set the appropriate channel name in `getChannel()`\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport type { ScalarType } from "@ooneex/types";\nimport { decorator, PubSub, RedisPubSub } from "@ooneex/pub-sub";\n\n@decorator.pubSub()\nexport class <Name>Event<Data extends Record<string, ScalarType> = Record<string, ScalarType>> extends PubSub<Data> {\n constructor(\n @inject(RedisPubSub)\n client: RedisPubSub<Data>,\n ) {\n super(client);\n }\n\n public getChannel(): string {\n return "<channel>";\n }\n\n public async handler(context: { data: Data; channel: string }): Promise<void> {\n console.log(context);\n // TODO: Implement handler logic here\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/events/<Name>Event.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name ends with `Event`, is a constructor function\n- **`getChannel`**: exists, returns a non-empty string, and consistently returns the same value on repeated calls\n- **`handler` contract**: exists, returns a `Promise`\n- **Inherited methods** (`publish`, `subscribe`, `unsubscribe`, `unsubscribeAll`): all exist on prototype\n- **Handler behavior**: use a mock to verify the handler calls the injected service\'s `execute` method with the event data\n\nThe complete test file must follow this structure:\n\n```typescript\nimport { describe, expect, mock, test } from "bun:test";\nimport { <Name>Event } from "@/events/<Name>Event";\n\ndescribe("<Name>Event", () => {\n // --- Class identity ---\n\n test("should have class name ending with \'Event\'", () => {\n expect(<Name>Event.name.endsWith("Event")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof <Name>Event).toBe("function");\n });\n\n // --- getChannel ---\n\n test("should have \'getChannel\' method", () => {\n expect(typeof <Name>Event.prototype.getChannel).toBe("function");\n });\n\n test("\'getChannel\' should return a non-empty string", () => {\n const event = Object.create(<Name>Event.prototype) as <Name>Event;\n const channel = event.getChannel();\n expect(typeof channel).toBe("string");\n expect(channel.length).toBeGreaterThan(0);\n });\n\n test("\'getChannel\' should return the same value on repeated calls", () => {\n const event = Object.create(<Name>Event.prototype) as <Name>Event;\n expect(event.getChannel()).toBe(event.getChannel());\n });\n\n // --- handler ---\n\n test("should have \'handler\' method", () => {\n expect(typeof <Name>Event.prototype.handler).toBe("function");\n });\n\n test("\'handler\' should return a Promise", () => {\n const mockClient = {\n subscribe: mock(() => Promise.resolve()),\n publish: mock(() => Promise.resolve()),\n unsubscribe: mock(() => Promise.resolve()),\n unsubscribeAll: mock(() => Promise.resolve()),\n };\n const event = new <Name>Event(mockClient as any);\n const result = event.handler({ data: {} as any, channel: event.getChannel() });\n expect(result).toBeInstanceOf(Promise);\n return result.catch(() => {});\n });\n\n // --- publish / subscribe / unsubscribe / unsubscribeAll ---\n\n test("should have \'publish\' method", () => {\n expect(typeof <Name>Event.prototype.publish).toBe("function");\n });\n\n test("should have \'subscribe\' method", () => {\n expect(typeof <Name>Event.prototype.subscribe).toBe("function");\n });\n\n test("should have \'unsubscribe\' method", () => {\n expect(typeof <Name>Event.prototype.unsubscribe).toBe("function");\n });\n\n test("should have \'unsubscribeAll\' method", () => {\n expect(typeof <Name>Event.prototype.unsubscribeAll).toBe("function");\n });\n\n // --- handler behavior (add after implementing handler) ---\n //\n // test("\'handler\' should call the service\'s execute method with event data", async () => {\n // const executeMock = mock(() => Promise.resolve());\n // const mockService = { execute: executeMock };\n // const mockClient = { subscribe: mock(() => Promise.resolve()), publish: mock(() => Promise.resolve()) };\n // const event = new <Name>Event(mockClient as any, mockService as any);\n // const data = { userId: "u1" };\n // await event.handler({ data, channel: event.getChannel() });\n // expect(executeMock).toHaveBeenCalledWith(data);\n // });\n});\n```\n\n### 5. Register the event in the module\n\nAdd the new event to the module\'s `events` array in `src/<PascalModuleName>Module.ts` (e.g., `src/BookModule.ts` for the `book` module):\n\n```typescript\nimport type { ModuleType } from "@ooneex/module";\nimport { <Name>Event } from "./events/<Name>Event";\n\nexport const <PascalModuleName>Module: ModuleType = {\n controllers: [],\n entities: [],\n middlewares: [],\n cronJobs: [],\n events: [<Name>Event],\n};\n```\n\nThe module file uses PascalCase naming: `<PascalModuleName>Module.ts` with export `<PascalModuleName>Module`.\n\nIf the module already has other events registered, append the new event to the existing `events` array and add the import alongside existing imports.\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/events/<Name>Event.ts tests/events/<Name>Event.spec.ts\n```\n';
|
|
7643
7656
|
|
|
7644
7657
|
// src/templates/claude/skills/make.repository.md.txt
|
|
7645
|
-
var make_repository_md_default = '---\nname: make:repository\ndescription: Generate a new repository class with its test file, then complete the generated code. Use when creating a new TypeORM repository for database operations on an entity.\n---\n\n# Make Repository Class\n\nGenerate a new repository class and its test file using the `make:repository` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the repository class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:repository --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/repositories/<Name>Repository.ts` - The repository class file (or `modules/<module>/src/repositories/<Name>Repository.ts` with `--module`)\n- `tests/repositories/<Name>Repository.spec.ts` - The test file (or `modules/<module>/tests/repositories/<Name>Repository.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the repository class\n\nEdit `src/repositories/<Name>Repository.ts` to complete the implementation:\n\n- Verify the entity import path matches the actual entity location\n- Adjust the `find` method\'s search fields (default searches `name` with `ILike`)\n- Customize relations loading in `findOne`/`findOneBy` if needed\n\n#### Adding methods\n\nLook at the entity\'s fields, relations, and business context to determine if custom domain-specific methods are needed. For example:\n- A `SessionRepository` might need `revokeSession(sessionId: string)` and `revokeAllUserSessions(userId: string)`\n- A `NotificationRepository` might need `markAsRead(id: string)` and `markAllAsRead(userId: string)`\n- Entities with status fields may need methods like `archive(id: string)` or `activate(id: string)`\n\nRead related entities, services, or actions in the module to understand what operations the repository should support, then add the appropriate methods.\n\n#### Removing methods\n\nRemove scaffolded methods that don\'t make sense for the entity\'s context:\n- Remove `createMany`/`updateMany` if the entity is always managed individually (e.g., user profiles, settings)\n- Remove `delete` if the entity uses soft deletes only (use a custom `softDelete` or `archive` method instead)\n- Remove `find` if the entity is only ever accessed by ID or specific criteria (e.g., singleton config entities)\n- Remove `count` if there\'s no use case for counting records of this entity\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport type { ITypeormDatabase } from "@ooneex/database";\nimport { decorator } from "@ooneex/repository";\nimport type { FilterResultType } from "@ooneex/types";\nimport type { FindManyOptions, FindOptionsWhere, Repository, SaveOptions, UpdateResult } from "typeorm";\nimport { ILike } from "typeorm";\nimport { <Name>Entity } from "../entities/<Name>Entity";\n\n@decorator.repository()\nexport class <Name>Repository {\n constructor(\n @inject("database")\n private readonly database: ITypeormDatabase,\n ) {}\n\n public async open(): Promise<Repository<<Name>Entity>> {\n return await this.database.open(<Name>Entity);\n }\n\n public async close(): Promise<void> {\n await this.database.close();\n }\n\n public async find(\n criteria: FindManyOptions<<Name>Entity> & { page?: number; limit?: number; q?: string },\n ): Promise<FilterResultType<<Name>Entity>> {\n // ... pagination and search logic\n }\n\n public async findOne(id: string): Promise<<Name>Entity | null> { ... }\n public async findOneBy(criteria: FindOptionsWhere<<Name>Entity>): Promise<<Name>Entity | null> { ... }\n public async create(entity: <Name>Entity, options?: SaveOptions): Promise<<Name>Entity> { ... }\n public async createMany(entities: <Name>Entity[], options?: SaveOptions): Promise<<Name>Entity[]> { ... }\n public async update(entity: <Name>Entity, options?: SaveOptions): Promise<<Name>Entity> { ... }\n public async updateMany(entities: <Name>Entity[], options?: SaveOptions): Promise<<Name>Entity[]> { ... }\n public async delete(criteria: FindOptionsWhere<<Name>Entity> | FindOptionsWhere<<Name>Entity>[]): Promise<UpdateResult> { ... }\n public async count(criteria?: FindOptionsWhere<<Name>Entity> | FindOptionsWhere<<Name>Entity>[]): Promise<number> { ... }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/repositories/<Name>Repository.spec.ts` to
|
|
7658
|
+
var make_repository_md_default = '---\nname: make:repository\ndescription: Generate a new repository class with its test file, then complete the generated code. Use when creating a new TypeORM repository for database operations on an entity.\n---\n\n# Make Repository Class\n\nGenerate a new repository class and its test file using the `make:repository` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the repository class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:repository --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/repositories/<Name>Repository.ts` - The repository class file (or `modules/<module>/src/repositories/<Name>Repository.ts` with `--module`)\n- `tests/repositories/<Name>Repository.spec.ts` - The test file (or `modules/<module>/tests/repositories/<Name>Repository.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the repository class\n\nEdit `src/repositories/<Name>Repository.ts` to complete the implementation:\n\n- Verify the entity import path matches the actual entity location\n- Adjust the `find` method\'s search fields (default searches `name` with `ILike`)\n- Customize relations loading in `findOne`/`findOneBy` if needed\n\n#### Adding methods\n\nLook at the entity\'s fields, relations, and business context to determine if custom domain-specific methods are needed. For example:\n- A `SessionRepository` might need `revokeSession(sessionId: string)` and `revokeAllUserSessions(userId: string)`\n- A `NotificationRepository` might need `markAsRead(id: string)` and `markAllAsRead(userId: string)`\n- Entities with status fields may need methods like `archive(id: string)` or `activate(id: string)`\n\nRead related entities, services, or actions in the module to understand what operations the repository should support, then add the appropriate methods.\n\n#### Removing methods\n\nRemove scaffolded methods that don\'t make sense for the entity\'s context:\n- Remove `createMany`/`updateMany` if the entity is always managed individually (e.g., user profiles, settings)\n- Remove `delete` if the entity uses soft deletes only (use a custom `softDelete` or `archive` method instead)\n- Remove `find` if the entity is only ever accessed by ID or specific criteria (e.g., singleton config entities)\n- Remove `count` if there\'s no use case for counting records of this entity\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport type { ITypeormDatabase } from "@ooneex/database";\nimport { decorator } from "@ooneex/repository";\nimport type { FilterResultType } from "@ooneex/types";\nimport type { FindManyOptions, FindOptionsWhere, Repository, SaveOptions, UpdateResult } from "typeorm";\nimport { ILike } from "typeorm";\nimport { <Name>Entity } from "../entities/<Name>Entity";\n\n@decorator.repository()\nexport class <Name>Repository {\n constructor(\n @inject("database")\n private readonly database: ITypeormDatabase,\n ) {}\n\n public async open(): Promise<Repository<<Name>Entity>> {\n return await this.database.open(<Name>Entity);\n }\n\n public async close(): Promise<void> {\n await this.database.close();\n }\n\n public async find(\n criteria: FindManyOptions<<Name>Entity> & { page?: number; limit?: number; q?: string },\n ): Promise<FilterResultType<<Name>Entity>> {\n // ... pagination and search logic\n }\n\n public async findOne(id: string): Promise<<Name>Entity | null> { ... }\n public async findOneBy(criteria: FindOptionsWhere<<Name>Entity>): Promise<<Name>Entity | null> { ... }\n public async create(entity: <Name>Entity, options?: SaveOptions): Promise<<Name>Entity> { ... }\n public async createMany(entities: <Name>Entity[], options?: SaveOptions): Promise<<Name>Entity[]> { ... }\n public async update(entity: <Name>Entity, options?: SaveOptions): Promise<<Name>Entity> { ... }\n public async updateMany(entities: <Name>Entity[], options?: SaveOptions): Promise<<Name>Entity[]> { ... }\n public async delete(criteria: FindOptionsWhere<<Name>Entity> | FindOptionsWhere<<Name>Entity>[]): Promise<UpdateResult> { ... }\n public async count(criteria?: FindOptionsWhere<<Name>Entity> | FindOptionsWhere<<Name>Entity>[]): Promise<number> { ... }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/repositories/<Name>Repository.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name ends with `Repository`, is a constructor function\n- **Each retained CRUD method**: method exists on prototype (remove tests for methods that were removed in step 3)\n- **Each custom domain method**: existence test for every method added\n- **No live-database tests**: repository methods require a real connection \u2014 structural tests only; integration tests belong in a separate suite\n\nThe complete test file must follow this structure \u2014 remove test blocks for any methods removed from the repository, and add new blocks for each custom method:\n\n```typescript\nimport { describe, expect, test } from "bun:test";\nimport { <Name>Repository } from "@/repositories/<Name>Repository";\n\ndescribe("<Name>Repository", () => {\n // --- Class identity ---\n\n test("should have class name ending with \'Repository\'", () => {\n expect(<Name>Repository.name.endsWith("Repository")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof <Name>Repository).toBe("function");\n });\n\n // --- Standard CRUD methods ---\n // Keep only the blocks for methods that were NOT removed in step 3.\n\n test("should have \'open\' method", () => {\n expect(typeof <Name>Repository.prototype.open).toBe("function");\n });\n\n test("should have \'close\' method", () => {\n expect(typeof <Name>Repository.prototype.close).toBe("function");\n });\n\n test("should have \'find\' method", () => {\n expect(typeof <Name>Repository.prototype.find).toBe("function");\n });\n\n test("should have \'findOne\' method", () => {\n expect(typeof <Name>Repository.prototype.findOne).toBe("function");\n });\n\n test("should have \'findOneBy\' method", () => {\n expect(typeof <Name>Repository.prototype.findOneBy).toBe("function");\n });\n\n test("should have \'create\' method", () => {\n expect(typeof <Name>Repository.prototype.create).toBe("function");\n });\n\n test("should have \'createMany\' method", () => {\n expect(typeof <Name>Repository.prototype.createMany).toBe("function");\n });\n\n test("should have \'update\' method", () => {\n expect(typeof <Name>Repository.prototype.update).toBe("function");\n });\n\n test("should have \'updateMany\' method", () => {\n expect(typeof <Name>Repository.prototype.updateMany).toBe("function");\n });\n\n test("should have \'delete\' method", () => {\n expect(typeof <Name>Repository.prototype.delete).toBe("function");\n });\n\n test("should have \'count\' method", () => {\n expect(typeof <Name>Repository.prototype.count).toBe("function");\n });\n\n // --- Custom domain methods ---\n // Add one block per custom method added in step 3.\n // Example:\n // test("should have \'revokeSession\' method", () => {\n // expect(typeof <Name>Repository.prototype.revokeSession).toBe("function");\n // });\n //\n // test("should have \'markAllAsRead\' method", () => {\n // expect(typeof <Name>Repository.prototype.markAllAsRead).toBe("function");\n // });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/repositories/<Name>Repository.ts tests/repositories/<Name>Repository.spec.ts\n```\n';
|
|
7646
7659
|
|
|
7647
7660
|
// src/templates/claude/skills/make.seed.md.txt
|
|
7648
|
-
var make_seed_md_default = '---\nname: make:seed\ndescription: Generate a new database seed file with its test file, then complete the generated code. Use when creating seed data for populating the database using @ooneex/seeds.\n---\n\n# Make Seed\n\nGenerate a new seed file and its test file using the `make:seed` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the seed file and test files:\n\n```bash\nbunx @ooneex/cli@latest make:seed --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/seeds/<Name>Seed.ts` - The seed class file (or `modules/<module>/src/seeds/<Name>Seed.ts` with `--module`)\n- `src/seeds/<name-seed>.yml` - The seed data file in kebab-case (or `modules/<module>/src/seeds/<name-seed>.yml` with `--module`)\n- `tests/seeds/<Name>Seed.spec.ts` - The test file (or `modules/<module>/tests/seeds/<Name>Seed.spec.ts` with `--module`)\n\nIt will also:\n- Generate a `seeds.ts` root export file in the seeds directory\n\n### 2. Read the generated files\n\nRead all generated files to understand the scaffolded code.\n\n### 3. Complete the seed data\n\nEdit `src/seeds/<name-seed>.yml` to add the seed data entries. Each entry should have hardcoded nanoid values for `id` fields (generate via `bun -e "import { random } from \'@ooneex/utils\'; console.log(random.nanoid())"`)\n\n- Do NOT use sequential IDs like `"item-1"`, `"item-2"`\n- Ensure the same entity uses the same ID everywhere it appears\n\n### 4. Complete the seed class\n\nEdit `src/seeds/<Name>Seed.ts` to implement:\n\n- Import the relevant entity classes and repository\n- Use `resolve()` from `@ooneex/container` to get the repository instance\n- Map the imported YAML data to entity instances\n- Use the repository to persist the entities\n\n### 5. Complete the test file\n\nEdit `tests/seeds/<Name>Seed.spec.ts` to
|
|
7661
|
+
var make_seed_md_default = '---\nname: make:seed\ndescription: Generate a new database seed file with its test file, then complete the generated code. Use when creating seed data for populating the database using @ooneex/seeds.\n---\n\n# Make Seed\n\nGenerate a new seed file and its test file using the `make:seed` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the seed file and test files:\n\n```bash\nbunx @ooneex/cli@latest make:seed --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/seeds/<Name>Seed.ts` - The seed class file (or `modules/<module>/src/seeds/<Name>Seed.ts` with `--module`)\n- `src/seeds/<name-seed>.yml` - The seed data file in kebab-case (or `modules/<module>/src/seeds/<name-seed>.yml` with `--module`)\n- `tests/seeds/<Name>Seed.spec.ts` - The test file (or `modules/<module>/tests/seeds/<Name>Seed.spec.ts` with `--module`)\n\nIt will also:\n- Generate a `seeds.ts` root export file in the seeds directory\n\n### 2. Read the generated files\n\nRead all generated files to understand the scaffolded code.\n\n### 3. Complete the seed data\n\nEdit `src/seeds/<name-seed>.yml` to add the seed data entries. Each entry should have hardcoded nanoid values for `id` fields (generate via `bun -e "import { random } from \'@ooneex/utils\'; console.log(random.nanoid())"`)\n\n- Do NOT use sequential IDs like `"item-1"`, `"item-2"`\n- Ensure the same entity uses the same ID everywhere it appears\n\n### 4. Complete the seed class\n\nEdit `src/seeds/<Name>Seed.ts` to implement:\n\n- Import the relevant entity classes and repository\n- Use `resolve()` from `@ooneex/container` to get the repository instance\n- Map the imported YAML data to entity instances\n- Use the repository to persist the entities\n\n### 5. Complete the test file\n\nEdit `tests/seeds/<Name>Seed.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name ends with `Seed`, is a constructor function\n- **`run` contract**: method exists on prototype (requires DB \u2014 no runtime call)\n- **`isActive`**: exists, returns `true` by default (seed is active unless explicitly disabled)\n- **`getDependencies`**: exists, returns an array (empty or with seed class references)\n- **Data YAML file**: file exists, is not empty, parses as valid YAML with at least one entry\n- **Instance isolation**: two instances are independent\n\nThe complete test file must follow this structure:\n\n```typescript\nimport { existsSync, readFileSync } from "node:fs";\nimport { join } from "node:path";\nimport { describe, expect, test } from "bun:test";\nimport { <Name>Seed } from "@/seeds/<Name>Seed";\n\ndescribe("<Name>Seed", () => {\n // --- Class identity ---\n\n test("should have class name ending with \'Seed\'", () => {\n expect(<Name>Seed.name.endsWith("Seed")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof <Name>Seed).toBe("function");\n });\n\n // --- run ---\n\n test("should have \'run\' method", () => {\n expect(typeof <Name>Seed.prototype.run).toBe("function");\n });\n\n // --- isActive ---\n\n test("should have \'isActive\' method", () => {\n expect(typeof <Name>Seed.prototype.isActive).toBe("function");\n });\n\n test("\'isActive\' should return a boolean", () => {\n const seed = Object.create(<Name>Seed.prototype) as <Name>Seed;\n expect(typeof seed.isActive()).toBe("boolean");\n });\n\n test("\'isActive\' should return true by default", () => {\n const seed = Object.create(<Name>Seed.prototype) as <Name>Seed;\n expect(seed.isActive()).toBe(true);\n });\n\n // --- getDependencies ---\n\n test("should have \'getDependencies\' method", () => {\n expect(typeof <Name>Seed.prototype.getDependencies).toBe("function");\n });\n\n test("\'getDependencies\' should return an array", () => {\n const seed = Object.create(<Name>Seed.prototype) as <Name>Seed;\n expect(Array.isArray(seed.getDependencies())).toBe(true);\n });\n\n // --- Data YAML file ---\n\n test("should have a data yml file", () => {\n const dataFile = join(__dirname, "..", "src", "seeds", "<name-seed>.yml");\n expect(existsSync(dataFile)).toBe(true);\n });\n\n test("data yml file should not be empty", () => {\n const dataFile = join(__dirname, "..", "src", "seeds", "<name-seed>.yml");\n const content = readFileSync(dataFile, "utf-8");\n expect(content.trim().length).toBeGreaterThan(0);\n });\n\n test("data yml file should contain at least one entry", () => {\n const dataFile = join(__dirname, "..", "src", "seeds", "<name-seed>.yml");\n const content = readFileSync(dataFile, "utf-8");\n // Each entry starts with \'- \' in YAML list format\n expect(content).toMatch(/^-\\s/m);\n });\n\n // --- Instance isolation ---\n\n test("should produce independent instances", () => {\n const a = Object.create(<Name>Seed.prototype) as <Name>Seed;\n const b = Object.create(<Name>Seed.prototype) as <Name>Seed;\n expect(a).not.toBe(b);\n });\n});\n```\n\n### 6. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/seeds/<Name>Seed.ts src/seeds/<name-seed>.yml tests/seeds/<Name>Seed.spec.ts\n```\n';
|
|
7649
7662
|
|
|
7650
7663
|
// src/templates/claude/skills/make.service.md.txt
|
|
7651
|
-
var make_service_md_default = '---\nname: make:service\ndescription: Generate a new service class with its test file, then complete the generated code. Use when creating a new business logic service that implements IService from @ooneex/service.\n---\n\n# Make Service Class\n\nGenerate a new service class and its test file using the `make:service` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the service class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:service --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/services/<Name>Service.ts` - The service class file (or `modules/<module>/src/services/<Name>Service.ts` with `--module`)\n- `tests/services/<Name>Service.spec.ts` - The test file (or `modules/<module>/tests/services/<Name>Service.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the service class\n\nEdit `src/services/<Name>Service.ts` to complete the implementation:\n\n- Define a proper type for `ServiceDataType` instead of `Record<string, unknown>`\n- Implement the `execute()` method with actual business logic\n- Inject any required dependencies (repositories, other services, etc.) via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { type IService, decorator } from "@ooneex/service";\n\ntype ServiceDataType = Record<string, unknown>;\n\n@decorator.service()\nexport class <Name>Service implements IService {\n public async execute(data?: ServiceDataType): Promise<void> {\n // TODO: Implement service logic\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/services/<Name>Service.spec.ts` to
|
|
7664
|
+
var make_service_md_default = '---\nname: make:service\ndescription: Generate a new service class with its test file, then complete the generated code. Use when creating a new business logic service that implements IService from @ooneex/service.\n---\n\n# Make Service Class\n\nGenerate a new service class and its test file using the `make:service` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the service class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:service --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/services/<Name>Service.ts` - The service class file (or `modules/<module>/src/services/<Name>Service.ts` with `--module`)\n- `tests/services/<Name>Service.spec.ts` - The test file (or `modules/<module>/tests/services/<Name>Service.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the service class\n\nEdit `src/services/<Name>Service.ts` to complete the implementation:\n\n- Define a proper type for `ServiceDataType` instead of `Record<string, unknown>`\n- Implement the `execute()` method with actual business logic\n- Inject any required dependencies (repositories, other services, etc.) via the constructor\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { type IService, decorator } from "@ooneex/service";\n\ntype ServiceDataType = Record<string, unknown>;\n\n@decorator.service()\nexport class <Name>Service implements IService {\n public async execute(data?: ServiceDataType): Promise<void> {\n // TODO: Implement service logic\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/services/<Name>Service.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name ends with `Service`, is a constructor function\n- **`execute` contract**: method exists, returns a `Promise` when called with no args and with data\n- **Awaitable**: calling `await execute()` does not hang or reject unexpectedly\n- **Instance isolation**: two instances are independent objects\n\nThe complete test file must follow this structure:\n\n```typescript\nimport { describe, expect, test } from "bun:test";\nimport { <Name>Service } from "@/services/<Name>Service";\n\ndescribe("<Name>Service", () => {\n // --- Class identity ---\n\n test("should have class name ending with \'Service\'", () => {\n expect(<Name>Service.name.endsWith("Service")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof <Name>Service).toBe("function");\n });\n\n // --- execute method ---\n\n test("should have \'execute\' method", () => {\n expect(typeof <Name>Service.prototype.execute).toBe("function");\n });\n\n test("\'execute\' should return a Promise when called with no arguments", () => {\n const service = new <Name>Service();\n const result = service.execute();\n expect(result).toBeInstanceOf(Promise);\n return result.catch(() => {});\n });\n\n test("\'execute\' should return a Promise when called with data", () => {\n const service = new <Name>Service();\n const result = service.execute({ key: "value" });\n expect(result).toBeInstanceOf(Promise);\n return result.catch(() => {});\n });\n\n test("\'execute\' result should be awaitable", async () => {\n const service = new <Name>Service();\n try {\n await service.execute();\n } catch {\n // Expected when dependencies are not injected \u2014 still validates the Promise contract\n }\n });\n\n // --- Business logic tests ---\n // Add one test per meaningful behavior of the service after implementing execute().\n // Focus on: happy path output, invalid input handling, edge cases.\n //\n // Example:\n // test("should return formatted result for valid input", async () => {\n // const service = new <Name>Service();\n // const result = await service.execute({ name: "Alice" });\n // expect(result).toMatchObject({ greeting: "Hello, Alice" });\n // });\n\n // --- Instance isolation ---\n\n test("should produce independent instances", () => {\n const a = new <Name>Service();\n const b = new <Name>Service();\n expect(a).not.toBe(b);\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/services/<Name>Service.ts tests/services/<Name>Service.spec.ts\n```\n';
|
|
7652
7665
|
|
|
7653
7666
|
// src/templates/claude/skills/make.storage.md.txt
|
|
7654
|
-
var make_storage_md_default = '---\nname: make:storage\ndescription: Generate a new storage class with its test file, then complete the generated code. Use when creating a new S3-compatible storage adapter that extends Storage from @ooneex/storage.\n---\n\n# Make Storage Class\n\nGenerate a new storage class and its test file using the `make:storage` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the storage class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:storage --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/storage/<Name>Storage.ts` - The storage class file (or `modules/<module>/src/storage/<Name>Storage.ts` with `--module`)\n- `tests/storage/<Name>Storage.spec.ts` - The test file (or `modules/<module>/tests/storage/<Name>Storage.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the storage class\n\nEdit `src/storage/<Name>Storage.ts` to complete the implementation:\n\n- Set the `bucket` property to the appropriate bucket name\n- Verify the environment variable names match the project configuration (`STORAGE_<NAME_UPPER>_ACCESS_KEY`, `STORAGE_<NAME_UPPER>_SECRET_KEY`, `STORAGE_<NAME_UPPER>_ENDPOINT`, `STORAGE_<NAME_UPPER>_REGION`)\n- Add any additional storage-specific methods if needed\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { Storage, decorator, StorageException } from "@ooneex/storage";\nimport type { S3Options } from "bun";\n\n@decorator.storage()\nexport class <Name>Storage extends Storage {\n protected bucket: string;\n private readonly accessKey: string;\n private readonly secretKey: string;\n private readonly endpoint: string;\n private readonly region: string;\n\n constructor(options?: {\n accessKey?: string;\n secretKey?: string;\n endpoint?: string;\n region?: string;\n }) {\n super();\n\n const accessKey = options?.accessKey || Bun.env.STORAGE_<NAME_UPPER>_ACCESS_KEY;\n const secretKey = options?.secretKey || Bun.env.STORAGE_<NAME_UPPER>_SECRET_KEY;\n const endpoint = options?.endpoint || Bun.env.STORAGE_<NAME_UPPER>_ENDPOINT;\n\n // ... validation throws StorageException if missing ...\n\n this.accessKey = accessKey;\n this.secretKey = secretKey;\n this.endpoint = endpoint;\n this.region = options?.region || Bun.env.STORAGE_<NAME_UPPER>_REGION || "auto";\n }\n\n public getOptions(): S3Options {\n return {\n accessKeyId: this.accessKey,\n secretAccessKey: this.secretKey,\n endpoint: this.endpoint,\n bucket: this.bucket,\n region: this.region,\n };\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/storage/<Name>Storage.spec.ts` to
|
|
7667
|
+
var make_storage_md_default = '---\nname: make:storage\ndescription: Generate a new storage class with its test file, then complete the generated code. Use when creating a new S3-compatible storage adapter that extends Storage from @ooneex/storage.\n---\n\n# Make Storage Class\n\nGenerate a new storage class and its test file using the `make:storage` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the storage class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:storage --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/storage/<Name>Storage.ts` - The storage class file (or `modules/<module>/src/storage/<Name>Storage.ts` with `--module`)\n- `tests/storage/<Name>Storage.spec.ts` - The test file (or `modules/<module>/tests/storage/<Name>Storage.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the storage class\n\nEdit `src/storage/<Name>Storage.ts` to complete the implementation:\n\n- Set the `bucket` property to the appropriate bucket name\n- Verify the environment variable names match the project configuration (`STORAGE_<NAME_UPPER>_ACCESS_KEY`, `STORAGE_<NAME_UPPER>_SECRET_KEY`, `STORAGE_<NAME_UPPER>_ENDPOINT`, `STORAGE_<NAME_UPPER>_REGION`)\n- Add any additional storage-specific methods if needed\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { Storage, decorator, StorageException } from "@ooneex/storage";\nimport type { S3Options } from "bun";\n\n@decorator.storage()\nexport class <Name>Storage extends Storage {\n protected bucket: string;\n private readonly accessKey: string;\n private readonly secretKey: string;\n private readonly endpoint: string;\n private readonly region: string;\n\n constructor(options?: {\n accessKey?: string;\n secretKey?: string;\n endpoint?: string;\n region?: string;\n }) {\n super();\n\n const accessKey = options?.accessKey || Bun.env.STORAGE_<NAME_UPPER>_ACCESS_KEY;\n const secretKey = options?.secretKey || Bun.env.STORAGE_<NAME_UPPER>_SECRET_KEY;\n const endpoint = options?.endpoint || Bun.env.STORAGE_<NAME_UPPER>_ENDPOINT;\n\n // ... validation throws StorageException if missing ...\n\n this.accessKey = accessKey;\n this.secretKey = secretKey;\n this.endpoint = endpoint;\n this.region = options?.region || Bun.env.STORAGE_<NAME_UPPER>_REGION || "auto";\n }\n\n public getOptions(): S3Options {\n return {\n accessKeyId: this.accessKey,\n secretAccessKey: this.secretKey,\n endpoint: this.endpoint,\n bucket: this.bucket,\n region: this.region,\n };\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/storage/<Name>Storage.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name ends with `Storage`, is a constructor function\n- **Constructor \u2014 missing credentials**: throws `StorageException` when required env vars are absent\n- **Constructor \u2014 explicit credentials**: succeeds when all credentials are passed via options\n- **`getOptions` shape**: returns an object with `accessKeyId`, `secretAccessKey`, `endpoint`, `bucket`, and `region` keys\n- **`bucket`**: the returned options include the expected bucket name\n- **Default region**: when no region is provided, defaults to `"auto"`\n- **Instance isolation**: two instances are independent\n\nThe complete test file must follow this structure:\n\n```typescript\nimport { StorageException } from "@ooneex/storage";\nimport { describe, expect, test } from "bun:test";\nimport { <Name>Storage } from "@/storage/<Name>Storage";\n\nconst VALID_OPTIONS = {\n accessKey: "test-access-key",\n secretKey: "test-secret-key",\n endpoint: "https://s3.example.com",\n region: "eu-west-1",\n};\n\ndescribe("<Name>Storage", () => {\n // --- Class identity ---\n\n test("should have class name ending with \'Storage\'", () => {\n expect(<Name>Storage.name.endsWith("Storage")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof <Name>Storage).toBe("function");\n });\n\n // --- Constructor validation ---\n\n test("should throw StorageException when accessKey is missing", () => {\n expect(() => new <Name>Storage({ secretKey: "s", endpoint: "https://s3.example.com" })).toThrow(StorageException);\n });\n\n test("should throw StorageException when secretKey is missing", () => {\n expect(() => new <Name>Storage({ accessKey: "a", endpoint: "https://s3.example.com" })).toThrow(StorageException);\n });\n\n test("should throw StorageException when endpoint is missing", () => {\n expect(() => new <Name>Storage({ accessKey: "a", secretKey: "s" })).toThrow(StorageException);\n });\n\n test("should construct successfully when all required credentials are provided", () => {\n expect(() => new <Name>Storage(VALID_OPTIONS)).not.toThrow();\n });\n\n // --- getOptions ---\n\n test("should have \'getOptions\' method", () => {\n expect(typeof <Name>Storage.prototype.getOptions).toBe("function");\n });\n\n test("\'getOptions\' should return an object with all required S3 keys", () => {\n const storage = new <Name>Storage(VALID_OPTIONS);\n const opts = storage.getOptions();\n expect(opts).toHaveProperty("accessKeyId");\n expect(opts).toHaveProperty("secretAccessKey");\n expect(opts).toHaveProperty("endpoint");\n expect(opts).toHaveProperty("bucket");\n expect(opts).toHaveProperty("region");\n });\n\n test("\'getOptions\' should reflect the provided credentials", () => {\n const storage = new <Name>Storage(VALID_OPTIONS);\n const opts = storage.getOptions();\n expect(opts.accessKeyId).toBe(VALID_OPTIONS.accessKey);\n expect(opts.secretAccessKey).toBe(VALID_OPTIONS.secretKey);\n expect(opts.endpoint).toBe(VALID_OPTIONS.endpoint);\n expect(opts.region).toBe(VALID_OPTIONS.region);\n });\n\n test("\'getOptions\' should default region to \'auto\' when not provided", () => {\n const storage = new <Name>Storage({ accessKey: "a", secretKey: "s", endpoint: "https://s3.example.com" });\n expect(storage.getOptions().region).toBe("auto");\n });\n\n test("\'getOptions\' should include the bucket name", () => {\n const storage = new <Name>Storage(VALID_OPTIONS);\n const opts = storage.getOptions();\n expect(typeof opts.bucket).toBe("string");\n expect((opts.bucket as string).length).toBeGreaterThan(0);\n });\n\n // --- Instance isolation ---\n\n test("should produce independent instances", () => {\n const a = new <Name>Storage(VALID_OPTIONS);\n const b = new <Name>Storage(VALID_OPTIONS);\n expect(a).not.toBe(b);\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/storage/<Name>Storage.ts tests/storage/<Name>Storage.spec.ts\n```\n';
|
|
7655
7668
|
|
|
7656
7669
|
// src/templates/claude/skills/make.vector-database.md.txt
|
|
7657
|
-
var make_vector_database_md_default = '---\nname: make:vector-database\ndescription: Generate a new vector database class with its test file, then complete the generated code. Use when creating a new vector database that extends VectorDatabase from @ooneex/rag.\n---\n\n# Make Vector Database Class\n\nGenerate a new vector database class and its test file using the `make:vector-database` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the vector database class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:vector-database --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/databases/<Name>VectorDatabase.ts` - The vector database class file (or `modules/<module>/src/databases/<Name>VectorDatabase.ts` with `--module`)\n- `tests/databases/<Name>VectorDatabase.spec.ts` - The test file (or `modules/<module>/tests/databases/<Name>VectorDatabase.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the vector database class\n\nEdit `src/databases/<Name>VectorDatabase.ts` to complete the implementation:\n\n- Set the `getDatabaseUri()` return value to the actual LanceDB database path\n- Configure the embedding provider and model in `getEmbeddingModel()`\n- Define the custom data fields in `DataType` and map them in `getSchema()`\n- Import the appropriate Apache Arrow types for your schema fields\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { type EmbeddingModelType, type EmbeddingProviderType, type FieldValueType, VectorDatabase, decorator } from "@ooneex/rag";\nimport { Utf8 } from "apache-arrow";\n\ntype DataType = {\n name: string;\n};\n\n@decorator.vectorDatabase()\nexport class <Name>VectorDatabase extends VectorDatabase<DataType> {\n public getDatabaseUri(): string {\n return "";\n }\n\n public getEmbeddingModel(): { provider: EmbeddingProviderType; model: EmbeddingModelType["model"] } {\n return { provider: "openai", model: "text-embedding-ada-002" };\n }\n\n public getSchema(): { [K in keyof DataType]: FieldValueType } {\n return {\n name: new Utf8(),\n };\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/databases/<Name>VectorDatabase.spec.ts` to
|
|
7670
|
+
var make_vector_database_md_default = '---\nname: make:vector-database\ndescription: Generate a new vector database class with its test file, then complete the generated code. Use when creating a new vector database that extends VectorDatabase from @ooneex/rag.\n---\n\n# Make Vector Database Class\n\nGenerate a new vector database class and its test file using the `make:vector-database` CLI command, then complete the generated code with proper implementation.\n\n## Coding Conventions\n\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`)\n- Always use arrow functions when possible, but NOT for class methods (class methods use regular method syntax)\n- End type names with the `Type` suffix (e.g., `ExceptionStackFrameType`, `ServiceDataType`)\n- Start interface names with the `I` prefix (e.g., `IException`, `IService`, `IAiChat`)\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from "@ooneex/container";\nimport { decorator, type ISeed } from "@ooneex/seeds";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Run the generator\n\nRun the following command to scaffold the vector database class and test files:\n\n```bash\nbunx @ooneex/cli@latest make:vector-database --name=<name> --module=<module>\n```\n\nWhere `<name>` is the name provided by the user. The `--module` option is optional \u2014 if provided, files are generated under `modules/<module>/` instead of the project root. The command will generate:\n- `src/databases/<Name>VectorDatabase.ts` - The vector database class file (or `modules/<module>/src/databases/<Name>VectorDatabase.ts` with `--module`)\n- `tests/databases/<Name>VectorDatabase.spec.ts` - The test file (or `modules/<module>/tests/databases/<Name>VectorDatabase.spec.ts` with `--module`)\n\n### 2. Read the generated files\n\nRead both generated files to understand the scaffolded code.\n\n### 3. Complete the vector database class\n\nEdit `src/databases/<Name>VectorDatabase.ts` to complete the implementation:\n\n- Set the `getDatabaseUri()` return value to the actual LanceDB database path\n- Configure the embedding provider and model in `getEmbeddingModel()`\n- Define the custom data fields in `DataType` and map them in `getSchema()`\n- Import the appropriate Apache Arrow types for your schema fields\n\nThe generated class structure follows this pattern:\n\n```typescript\nimport { type EmbeddingModelType, type EmbeddingProviderType, type FieldValueType, VectorDatabase, decorator } from "@ooneex/rag";\nimport { Utf8 } from "apache-arrow";\n\ntype DataType = {\n name: string;\n};\n\n@decorator.vectorDatabase()\nexport class <Name>VectorDatabase extends VectorDatabase<DataType> {\n public getDatabaseUri(): string {\n return "";\n }\n\n public getEmbeddingModel(): { provider: EmbeddingProviderType; model: EmbeddingModelType["model"] } {\n return { provider: "openai", model: "text-embedding-ada-002" };\n }\n\n public getSchema(): { [K in keyof DataType]: FieldValueType } {\n return {\n name: new Utf8(),\n };\n }\n}\n```\n\n### 4. Complete the test file\n\nEdit `tests/databases/<Name>VectorDatabase.spec.ts` to replace the scaffolded tests with a comprehensive suite that covers all use cases.\n\n**Coverage requirements:**\n\n- **Class identity**: name ends with `VectorDatabase`, is a constructor function\n- **`getDatabaseUri`**: exists, returns a non-empty string (the LanceDB path)\n- **`getEmbeddingModel`**: exists, returns an object with `provider` (string) and `model` (string) keys that are non-empty\n- **`getSchema`**: exists, returns a non-empty object whose keys match the `DataType` fields\n- **Instance isolation**: two instances are independent\n\nThe complete test file must follow this structure:\n\n```typescript\nimport { describe, expect, test } from "bun:test";\nimport { <Name>VectorDatabase } from "@/databases/<Name>VectorDatabase";\n\ndescribe("<Name>VectorDatabase", () => {\n // --- Class identity ---\n\n test("should have class name ending with \'VectorDatabase\'", () => {\n expect(<Name>VectorDatabase.name.endsWith("VectorDatabase")).toBe(true);\n });\n\n test("should be a constructor function", () => {\n expect(typeof <Name>VectorDatabase).toBe("function");\n });\n\n // --- getDatabaseUri ---\n\n test("should have \'getDatabaseUri\' method", () => {\n expect(typeof <Name>VectorDatabase.prototype.getDatabaseUri).toBe("function");\n });\n\n test("\'getDatabaseUri\' should return a string", () => {\n const db = new <Name>VectorDatabase();\n expect(typeof db.getDatabaseUri()).toBe("string");\n });\n\n test("\'getDatabaseUri\' should return a non-empty path after configuration", () => {\n const db = new <Name>VectorDatabase();\n const uri = db.getDatabaseUri();\n // A valid URI is non-empty once configured \u2014 check it\'s a string at minimum\n expect(typeof uri).toBe("string");\n });\n\n // --- getEmbeddingModel ---\n\n test("should have \'getEmbeddingModel\' method", () => {\n expect(typeof <Name>VectorDatabase.prototype.getEmbeddingModel).toBe("function");\n });\n\n test("\'getEmbeddingModel\' should return an object with \'provider\' and \'model\' keys", () => {\n const db = new <Name>VectorDatabase();\n const embedding = db.getEmbeddingModel();\n expect(embedding).toBeDefined();\n expect(typeof embedding.provider).toBe("string");\n expect(embedding.provider.length).toBeGreaterThan(0);\n expect(typeof embedding.model).toBe("string");\n expect(embedding.model.length).toBeGreaterThan(0);\n });\n\n test("\'getEmbeddingModel\' provider should be a recognized value", () => {\n const db = new <Name>VectorDatabase();\n const { provider } = db.getEmbeddingModel();\n expect(["openai", "cohere", "huggingface", "ollama"]).toContain(provider);\n });\n\n // --- getSchema ---\n\n test("should have \'getSchema\' method", () => {\n expect(typeof <Name>VectorDatabase.prototype.getSchema).toBe("function");\n });\n\n test("\'getSchema\' should return a non-empty object", () => {\n const db = new <Name>VectorDatabase();\n const schema = db.getSchema();\n expect(schema).toBeDefined();\n expect(typeof schema).toBe("object");\n expect(Object.keys(schema).length).toBeGreaterThan(0);\n });\n\n test("\'getSchema\' keys should match the DataType fields", () => {\n const db = new <Name>VectorDatabase();\n const schema = db.getSchema();\n // Update this list to match the actual DataType fields defined in the class\n const expectedFields = ["name"]; // e.g. ["title", "content", "source"]\n for (const field of expectedFields) {\n expect(Object.keys(schema)).toContain(field);\n }\n });\n\n // --- Instance isolation ---\n\n test("should produce independent instances", () => {\n const a = new <Name>VectorDatabase();\n const b = new <Name>VectorDatabase();\n expect(a).not.toBe(b);\n });\n});\n```\n\n### 5. Lint and format\n\nRun linting and formatting on the generated files:\n\n```bash\nbunx biome check --fix src/databases/<Name>VectorDatabase.ts tests/databases/<Name>VectorDatabase.spec.ts\n```\n';
|
|
7658
7671
|
|
|
7659
7672
|
// src/templates/claude/skills/optimize.md.txt
|
|
7660
7673
|
var optimize_md_default = "---\nname: optimize\ndescription: Optimize a module's codebase for quality, performance, and clean conventions. Enforces arrow functions (except class methods), type/interface naming, removes duplication, and ensures only important tests remain.\n---\n\n# Optimize Codebase\n\nOptimize a module's codebase for quality, performance, and clean conventions.\n\n## Coding Conventions\n\nApply these conventions across all files in the target module:\n\n- **Arrow functions everywhere** \u2014 use arrow functions for all function expressions, callbacks, standalone functions, and variable declarations. The ONLY exception is class methods, which must use regular method syntax.\n- **Type naming** \u2014 all type aliases must end with the `Type` suffix (e.g., `UserDataType`, `ConfigOptionsType`). Rename any that don't comply.\n- **Interface naming** \u2014 all interface names must start with the `I` prefix (e.g., `IUser`, `IService`, `IRepository`). Rename any that don't comply.\n- **No definite assignment assertions** \u2014 never use `!` on class properties (e.g., `email!: string`). Use a default value or make the property optional (`?`) instead.\n- Always explicitly show visibility on class methods and properties (`private`, `public`, `protected`).\n- For Entity class, if property is optional, add `null` to its type.\n- For dependencies, use `inject` from `@ooneex/container`. For example:\n\n```typescript\nimport { inject } from \"@ooneex/container\";\nimport { decorator, type ISeed } from \"@ooneex/seeds\";\n\n@decorator.seed()\nexport class BookSeed implements ISeed {\n constructor(\n @inject(BookRepository)\n private readonly repository: BookRepository,\n ) {}\n}\n```\n\n## Important\n\nAll commands must be run from the root of the project (not from within a package or module directory).\n\n## Steps\n\n### 1. Identify the target\n\nDetermine the module to optimize. If the user specifies a module name, work in `modules/<module>/`. If no module is specified, ask the user which module to optimize.\n\n### 2. Read and analyze the module\n\nRead all source files (`src/**/*.ts`) and test files (`tests/**/*.ts`) in the target module. Build a full picture of:\n\n- All types, interfaces, classes, and functions\n- Dependencies between files\n- Existing test coverage\n\n### 3. Enforce naming conventions\n\nScan every file and fix:\n\n- **Types not ending with `Type`** \u2014 rename the type and update all references across the module\n- **Interfaces not starting with `I`** \u2014 rename the interface and update all references across the module\n- **Non-arrow functions** \u2014 convert all function expressions, callbacks, and standalone functions to arrow functions. Do NOT convert class methods.\n- **Missing visibility modifiers** \u2014 add explicit `public`, `private`, or `protected` to all class methods and properties\n\n### 4. Remove code duplication\n\nIdentify duplicated or near-duplicated code within the module:\n\n- Extract shared logic into well-named helper arrow functions or base classes\n- Consolidate repeated type definitions\n- Merge similar utility functions\n- Remove dead code (unused imports, unreachable branches, unused variables)\n\n### 5. Optimize for performance\n\nReview and improve:\n\n- Replace inefficient loops or repeated iterations with single-pass approaches where possible\n- Use `Map`/`Set` instead of arrays for lookups when appropriate\n- Avoid unnecessary object spreads or deep clones\n- Prefer early returns to reduce nesting\n- Remove unnecessary `async`/`await` where a direct return suffices\n- Eliminate redundant null/undefined checks when the type system already guarantees the value\n\n### 6. Optimize tests\n\nReview all test files and restructure:\n\n- **Remove trivial tests** \u2014 delete tests that only check obvious things (e.g., \"class name ends with X\", \"method exists\") unless they serve as smoke tests for generated code\n- **Keep and improve important tests** \u2014 focus on tests that verify actual business logic, edge cases, error handling, and integration behavior\n- **Write fewer but more meaningful tests** \u2014 each test should validate a real scenario or invariant, not just existence checks\n- **Consolidate redundant test cases** \u2014 merge tests that cover the same code path with slightly different inputs into parameterized patterns\n- **Ensure critical paths are covered** \u2014 every public method with logic should have at least one test covering its happy path and one covering its error/edge case\n\n### 7. Final cleanup\n\n- Remove all unused imports\n- Remove empty files or files with no exports\n- Ensure consistent formatting\n\n### 8. Lint and format\n\nRun linting and formatting on all modified files:\n\n```bash\nbunx biome check --fix <list of modified files>\n```\n\n### 9. Run tests\n\nRun the module's tests to verify nothing is broken:\n\n```bash\nbun test <module test directory>\n```\n\nIf any test fails, fix the issue and re-run until all tests pass.\n";
|
|
@@ -9740,10 +9753,109 @@ class MakeMigrationCommand {
|
|
|
9740
9753
|
MakeMigrationCommand = __legacyDecorateClassTS([
|
|
9741
9754
|
decorator22.command()
|
|
9742
9755
|
], MakeMigrationCommand);
|
|
9743
|
-
// src/commands/
|
|
9756
|
+
// src/commands/ModuleLockCommand.ts
|
|
9744
9757
|
import { join as join23 } from "path";
|
|
9745
9758
|
import { decorator as decorator23 } from "@ooneex/command";
|
|
9746
9759
|
import { TerminalLogger as TerminalLogger22 } from "@ooneex/logger";
|
|
9760
|
+
import { migrationTestCreate } from "@ooneex/migrations";
|
|
9761
|
+
class ModuleLockCommand {
|
|
9762
|
+
getName() {
|
|
9763
|
+
return "module:lock";
|
|
9764
|
+
}
|
|
9765
|
+
getDescription() {
|
|
9766
|
+
return "Lock module migrations by hashing their content into a yml file";
|
|
9767
|
+
}
|
|
9768
|
+
async run(options) {
|
|
9769
|
+
const { module, override } = options;
|
|
9770
|
+
const logger = new TerminalLogger22;
|
|
9771
|
+
if (module) {
|
|
9772
|
+
await ensureModule(module);
|
|
9773
|
+
}
|
|
9774
|
+
const base = module ? join23("modules", module) : ".";
|
|
9775
|
+
const migrationsDir = join23(process.cwd(), base, "src", "migrations");
|
|
9776
|
+
const glob = new Bun.Glob("Migration*.ts");
|
|
9777
|
+
const migrationFiles = [];
|
|
9778
|
+
for await (const file of glob.scan({ cwd: migrationsDir, onlyFiles: true })) {
|
|
9779
|
+
migrationFiles.push(file);
|
|
9780
|
+
}
|
|
9781
|
+
if (migrationFiles.length === 0) {
|
|
9782
|
+
logger.info("No migration files found", undefined, {
|
|
9783
|
+
showTimestamp: false,
|
|
9784
|
+
showArrow: false
|
|
9785
|
+
});
|
|
9786
|
+
return;
|
|
9787
|
+
}
|
|
9788
|
+
const moduleName = module ?? await this.resolveModuleName(base);
|
|
9789
|
+
const ymlPath = join23(process.cwd(), base, `${moduleName}.yml`);
|
|
9790
|
+
const testsDir = join23(base, "tests", "migrations");
|
|
9791
|
+
const registered = await this.parseYml(ymlPath);
|
|
9792
|
+
let added = 0;
|
|
9793
|
+
let skipped = 0;
|
|
9794
|
+
for (const file of migrationFiles.sort()) {
|
|
9795
|
+
const name = file.replace(/\.ts$/, "");
|
|
9796
|
+
await migrationTestCreate({ name, testsDir, ...module && { module } });
|
|
9797
|
+
if (registered[name] && !override) {
|
|
9798
|
+
skipped++;
|
|
9799
|
+
continue;
|
|
9800
|
+
}
|
|
9801
|
+
const content = await Bun.file(join23(migrationsDir, file)).text();
|
|
9802
|
+
registered[name] = new Bun.CryptoHasher("sha256").update(content).digest("hex");
|
|
9803
|
+
added++;
|
|
9804
|
+
}
|
|
9805
|
+
await this.writeYml(ymlPath, registered);
|
|
9806
|
+
if (added > 0) {
|
|
9807
|
+
logger.success(`${ymlPath} updated (${added} migration(s) locked)`, undefined, {
|
|
9808
|
+
showTimestamp: false,
|
|
9809
|
+
showArrow: false,
|
|
9810
|
+
useSymbol: true
|
|
9811
|
+
});
|
|
9812
|
+
}
|
|
9813
|
+
if (skipped > 0) {
|
|
9814
|
+
logger.info(`${skipped} migration(s) already registered \u2014 use --override to update`, undefined, {
|
|
9815
|
+
showTimestamp: false,
|
|
9816
|
+
showArrow: false
|
|
9817
|
+
});
|
|
9818
|
+
}
|
|
9819
|
+
}
|
|
9820
|
+
async resolveModuleName(base) {
|
|
9821
|
+
const pkgFile = Bun.file(join23(process.cwd(), base, "package.json"));
|
|
9822
|
+
if (await pkgFile.exists()) {
|
|
9823
|
+
const pkg = await pkgFile.json();
|
|
9824
|
+
const name = pkg.name ?? "module";
|
|
9825
|
+
return name.split("/").pop() ?? name;
|
|
9826
|
+
}
|
|
9827
|
+
return "module";
|
|
9828
|
+
}
|
|
9829
|
+
async parseYml(ymlPath) {
|
|
9830
|
+
const file = Bun.file(ymlPath);
|
|
9831
|
+
if (!await file.exists())
|
|
9832
|
+
return {};
|
|
9833
|
+
const data = Bun.YAML.parse(await file.text());
|
|
9834
|
+
const result = {};
|
|
9835
|
+
for (const [name, entry] of Object.entries(data.migrations ?? {})) {
|
|
9836
|
+
if (entry?.hash)
|
|
9837
|
+
result[name] = entry.hash;
|
|
9838
|
+
}
|
|
9839
|
+
return result;
|
|
9840
|
+
}
|
|
9841
|
+
async writeYml(ymlPath, migrations) {
|
|
9842
|
+
const lines = ["migrations:"];
|
|
9843
|
+
for (const [name, hash] of Object.entries(migrations).sort(([a], [b]) => a.localeCompare(b))) {
|
|
9844
|
+
lines.push(` ${name}:`);
|
|
9845
|
+
lines.push(` hash: ${hash}`);
|
|
9846
|
+
}
|
|
9847
|
+
await Bun.write(ymlPath, `${lines.join(`
|
|
9848
|
+
`)}
|
|
9849
|
+
`);
|
|
9850
|
+
}
|
|
9851
|
+
}
|
|
9852
|
+
ModuleLockCommand = __legacyDecorateClassTS([
|
|
9853
|
+
decorator23.command()
|
|
9854
|
+
], ModuleLockCommand);
|
|
9855
|
+
// src/commands/MakePermissionCommand.ts
|
|
9856
|
+
import { join as join24 } from "path";
|
|
9857
|
+
import { decorator as decorator24 } from "@ooneex/command";
|
|
9858
|
+
import { TerminalLogger as TerminalLogger23 } from "@ooneex/logger";
|
|
9747
9859
|
import { toPascalCase as toPascalCase12 } from "@ooneex/utils";
|
|
9748
9860
|
|
|
9749
9861
|
// src/templates/permission.test.txt
|
|
@@ -9881,28 +9993,28 @@ class MakePermissionCommand {
|
|
|
9881
9993
|
if (module) {
|
|
9882
9994
|
await ensureModule(module);
|
|
9883
9995
|
}
|
|
9884
|
-
const base = module ?
|
|
9885
|
-
const permissionLocalDir =
|
|
9886
|
-
const permissionDir =
|
|
9887
|
-
const filePath =
|
|
9996
|
+
const base = module ? join24("modules", module) : ".";
|
|
9997
|
+
const permissionLocalDir = join24(base, "src", "permissions");
|
|
9998
|
+
const permissionDir = join24(process.cwd(), permissionLocalDir);
|
|
9999
|
+
const filePath = join24(permissionDir, `${name}Permission.ts`);
|
|
9888
10000
|
await Bun.write(filePath, content);
|
|
9889
10001
|
const testContent = permission_test_default.replace(/{{NAME}}/g, name).replace(/{{MODULE}}/g, module ?? "");
|
|
9890
|
-
const testsLocalDir =
|
|
9891
|
-
const testsDir =
|
|
9892
|
-
const testFilePath =
|
|
10002
|
+
const testsLocalDir = join24(base, "tests", "permissions");
|
|
10003
|
+
const testsDir = join24(process.cwd(), testsLocalDir);
|
|
10004
|
+
const testFilePath = join24(testsDir, `${name}Permission.spec.ts`);
|
|
9893
10005
|
await Bun.write(testFilePath, testContent);
|
|
9894
|
-
const logger = new
|
|
9895
|
-
logger.success(`${
|
|
10006
|
+
const logger = new TerminalLogger23;
|
|
10007
|
+
logger.success(`${join24(permissionLocalDir, name)}Permission.ts created successfully`, undefined, {
|
|
9896
10008
|
showTimestamp: false,
|
|
9897
10009
|
showArrow: false,
|
|
9898
10010
|
useSymbol: true
|
|
9899
10011
|
});
|
|
9900
|
-
logger.success(`${
|
|
10012
|
+
logger.success(`${join24(testsLocalDir, name)}Permission.spec.ts created successfully`, undefined, {
|
|
9901
10013
|
showTimestamp: false,
|
|
9902
10014
|
showArrow: false,
|
|
9903
10015
|
useSymbol: true
|
|
9904
10016
|
});
|
|
9905
|
-
const packageJsonPath =
|
|
10017
|
+
const packageJsonPath = join24(process.cwd(), "package.json");
|
|
9906
10018
|
const packageJson = await Bun.file(packageJsonPath).json();
|
|
9907
10019
|
const deps = packageJson.dependencies ?? {};
|
|
9908
10020
|
const devDeps = packageJson.devDependencies ?? {};
|
|
@@ -9917,12 +10029,12 @@ class MakePermissionCommand {
|
|
|
9917
10029
|
}
|
|
9918
10030
|
}
|
|
9919
10031
|
MakePermissionCommand = __legacyDecorateClassTS([
|
|
9920
|
-
|
|
10032
|
+
decorator24.command()
|
|
9921
10033
|
], MakePermissionCommand);
|
|
9922
10034
|
// src/commands/MakePubSubCommand.ts
|
|
9923
|
-
import { basename as basename5, join as
|
|
9924
|
-
import { decorator as
|
|
9925
|
-
import { TerminalLogger as
|
|
10035
|
+
import { basename as basename5, join as join25 } from "path";
|
|
10036
|
+
import { decorator as decorator25 } from "@ooneex/command";
|
|
10037
|
+
import { TerminalLogger as TerminalLogger24 } from "@ooneex/logger";
|
|
9926
10038
|
import { toKebabCase as toKebabCase4, toPascalCase as toPascalCase13 } from "@ooneex/utils";
|
|
9927
10039
|
|
|
9928
10040
|
// src/templates/pubsub.test.txt
|
|
@@ -10030,33 +10142,33 @@ class MakePubSubCommand {
|
|
|
10030
10142
|
if (module) {
|
|
10031
10143
|
await ensureModule(module);
|
|
10032
10144
|
}
|
|
10033
|
-
const base = module ?
|
|
10034
|
-
const pubSubLocalDir =
|
|
10035
|
-
const pubSubDir =
|
|
10036
|
-
const filePath =
|
|
10145
|
+
const base = module ? join25("modules", module) : ".";
|
|
10146
|
+
const pubSubLocalDir = join25(base, "src", "events");
|
|
10147
|
+
const pubSubDir = join25(process.cwd(), pubSubLocalDir);
|
|
10148
|
+
const filePath = join25(pubSubDir, `${name}Event.ts`);
|
|
10037
10149
|
await Bun.write(filePath, content);
|
|
10038
10150
|
const testContent = pubsub_test_default.replace(/{{NAME}}/g, name).replace(/{{MODULE}}/g, module ?? "");
|
|
10039
|
-
const testsLocalDir =
|
|
10040
|
-
const testsDir =
|
|
10041
|
-
const testFilePath =
|
|
10151
|
+
const testsLocalDir = join25(base, "tests", "events");
|
|
10152
|
+
const testsDir = join25(process.cwd(), testsLocalDir);
|
|
10153
|
+
const testFilePath = join25(testsDir, `${name}Event.spec.ts`);
|
|
10042
10154
|
await Bun.write(testFilePath, testContent);
|
|
10043
10155
|
const modulePascalName = module ? toPascalCase13(module) : toPascalCase13(basename5(process.cwd()));
|
|
10044
|
-
const modulePath =
|
|
10156
|
+
const modulePath = join25(process.cwd(), base, "src", `${modulePascalName}Module.ts`);
|
|
10045
10157
|
if (await Bun.file(modulePath).exists()) {
|
|
10046
10158
|
await this.addToModule(modulePath, name);
|
|
10047
10159
|
}
|
|
10048
|
-
const logger = new
|
|
10049
|
-
logger.success(`${
|
|
10160
|
+
const logger = new TerminalLogger24;
|
|
10161
|
+
logger.success(`${join25(pubSubLocalDir, name)}Event.ts created successfully`, undefined, {
|
|
10050
10162
|
showTimestamp: false,
|
|
10051
10163
|
showArrow: false,
|
|
10052
10164
|
useSymbol: true
|
|
10053
10165
|
});
|
|
10054
|
-
logger.success(`${
|
|
10166
|
+
logger.success(`${join25(testsLocalDir, name)}Event.spec.ts created successfully`, undefined, {
|
|
10055
10167
|
showTimestamp: false,
|
|
10056
10168
|
showArrow: false,
|
|
10057
10169
|
useSymbol: true
|
|
10058
10170
|
});
|
|
10059
|
-
const packageJsonPath =
|
|
10171
|
+
const packageJsonPath = join25(process.cwd(), "package.json");
|
|
10060
10172
|
const packageJson = await Bun.file(packageJsonPath).json();
|
|
10061
10173
|
const deps = packageJson.dependencies ?? {};
|
|
10062
10174
|
const devDeps = packageJson.devDependencies ?? {};
|
|
@@ -10071,13 +10183,13 @@ class MakePubSubCommand {
|
|
|
10071
10183
|
}
|
|
10072
10184
|
}
|
|
10073
10185
|
MakePubSubCommand = __legacyDecorateClassTS([
|
|
10074
|
-
|
|
10186
|
+
decorator25.command()
|
|
10075
10187
|
], MakePubSubCommand);
|
|
10076
10188
|
// src/commands/MakeReleaseCommand.ts
|
|
10077
10189
|
import { readdir } from "fs/promises";
|
|
10078
|
-
import { join as
|
|
10079
|
-
import { decorator as
|
|
10080
|
-
import { TerminalLogger as
|
|
10190
|
+
import { join as join26 } from "path";
|
|
10191
|
+
import { decorator as decorator26 } from "@ooneex/command";
|
|
10192
|
+
import { TerminalLogger as TerminalLogger25 } from "@ooneex/logger";
|
|
10081
10193
|
var {$ } = globalThis.Bun;
|
|
10082
10194
|
var COMMIT_TYPE_TO_CATEGORY = {
|
|
10083
10195
|
feat: "Added",
|
|
@@ -10100,7 +10212,7 @@ class MakeReleaseCommand {
|
|
|
10100
10212
|
return "Release packages with version bump, changelog, and git tag";
|
|
10101
10213
|
}
|
|
10102
10214
|
async run() {
|
|
10103
|
-
const logger = new
|
|
10215
|
+
const logger = new TerminalLogger25;
|
|
10104
10216
|
const cwd = process.cwd();
|
|
10105
10217
|
const dirs = [];
|
|
10106
10218
|
for (const { name, type } of [
|
|
@@ -10108,8 +10220,8 @@ class MakeReleaseCommand {
|
|
|
10108
10220
|
{ name: "modules", type: "module" }
|
|
10109
10221
|
]) {
|
|
10110
10222
|
try {
|
|
10111
|
-
const entries = await readdir(
|
|
10112
|
-
dirs.push(...entries.filter((d) => d.isDirectory()).map((d) => ({ base:
|
|
10223
|
+
const entries = await readdir(join26(cwd, name), { withFileTypes: true });
|
|
10224
|
+
dirs.push(...entries.filter((d) => d.isDirectory()).map((d) => ({ base: join26(name, d.name), type })));
|
|
10113
10225
|
} catch {}
|
|
10114
10226
|
}
|
|
10115
10227
|
const logOptions = { showTimestamp: false, showArrow: false, useSymbol: true };
|
|
@@ -10119,8 +10231,8 @@ class MakeReleaseCommand {
|
|
|
10119
10231
|
}
|
|
10120
10232
|
let releasedCount = 0;
|
|
10121
10233
|
for (const dir of dirs) {
|
|
10122
|
-
const fullDir =
|
|
10123
|
-
const pkgJsonPath =
|
|
10234
|
+
const fullDir = join26(cwd, dir.base);
|
|
10235
|
+
const pkgJsonPath = join26(fullDir, "package.json");
|
|
10124
10236
|
const pkgJsonFile = Bun.file(pkgJsonPath);
|
|
10125
10237
|
if (!await pkgJsonFile.exists()) {
|
|
10126
10238
|
continue;
|
|
@@ -10138,7 +10250,7 @@ class MakeReleaseCommand {
|
|
|
10138
10250
|
await Bun.write(pkgJsonPath, `${JSON.stringify(pkgJson, null, 2)}
|
|
10139
10251
|
`);
|
|
10140
10252
|
await this.updateChangelog(fullDir, newVersion, tag, commits);
|
|
10141
|
-
await this.gitAdd(
|
|
10253
|
+
await this.gitAdd(join26(dir.base, "package.json"), join26(dir.base, "CHANGELOG.md"));
|
|
10142
10254
|
await this.gitCommit(`chore(release): ${pkgJson.name}@${newVersion}`);
|
|
10143
10255
|
await this.gitTag(tag, `chore(release): ${pkgJson.name}@${newVersion}`);
|
|
10144
10256
|
logger.success(`${pkgJson.name}@${newVersion} released (${bumpType} bump, ${commits.length} commit(s))`, undefined, logOptions);
|
|
@@ -10239,7 +10351,7 @@ class MakeReleaseCommand {
|
|
|
10239
10351
|
}
|
|
10240
10352
|
}
|
|
10241
10353
|
async updateChangelog(dir, version, tag, commits) {
|
|
10242
|
-
const changelogPath =
|
|
10354
|
+
const changelogPath = join26(dir, "CHANGELOG.md");
|
|
10243
10355
|
const today = new Date().toISOString().split("T")[0];
|
|
10244
10356
|
const repoUrl = await this.getRepoUrl();
|
|
10245
10357
|
const grouped = new Map;
|
|
@@ -10316,12 +10428,12 @@ ${section}
|
|
|
10316
10428
|
}
|
|
10317
10429
|
}
|
|
10318
10430
|
MakeReleaseCommand = __legacyDecorateClassTS([
|
|
10319
|
-
|
|
10431
|
+
decorator26.command()
|
|
10320
10432
|
], MakeReleaseCommand);
|
|
10321
10433
|
// src/commands/MakeRepositoryCommand.ts
|
|
10322
|
-
import { join as
|
|
10323
|
-
import { decorator as
|
|
10324
|
-
import { TerminalLogger as
|
|
10434
|
+
import { join as join27 } from "path";
|
|
10435
|
+
import { decorator as decorator27 } from "@ooneex/command";
|
|
10436
|
+
import { TerminalLogger as TerminalLogger26 } from "@ooneex/logger";
|
|
10325
10437
|
import { toPascalCase as toPascalCase14 } from "@ooneex/utils";
|
|
10326
10438
|
|
|
10327
10439
|
// src/templates/repository.test.txt
|
|
@@ -10535,28 +10647,28 @@ class MakeRepositoryCommand {
|
|
|
10535
10647
|
if (module) {
|
|
10536
10648
|
await ensureModule(module);
|
|
10537
10649
|
}
|
|
10538
|
-
const base = module ?
|
|
10539
|
-
const repositoriesLocalDir =
|
|
10540
|
-
const repositoriesDir =
|
|
10541
|
-
const filePath =
|
|
10650
|
+
const base = module ? join27("modules", module) : ".";
|
|
10651
|
+
const repositoriesLocalDir = join27(base, "src", "repositories");
|
|
10652
|
+
const repositoriesDir = join27(process.cwd(), repositoriesLocalDir);
|
|
10653
|
+
const filePath = join27(repositoriesDir, `${name}Repository.ts`);
|
|
10542
10654
|
await Bun.write(filePath, content);
|
|
10543
10655
|
const testContent = repository_test_default.replace(/{{NAME}}/g, name).replace(/{{MODULE}}/g, module ?? "");
|
|
10544
|
-
const testsLocalDir =
|
|
10545
|
-
const testsDir =
|
|
10546
|
-
const testFilePath =
|
|
10656
|
+
const testsLocalDir = join27(base, "tests", "repositories");
|
|
10657
|
+
const testsDir = join27(process.cwd(), testsLocalDir);
|
|
10658
|
+
const testFilePath = join27(testsDir, `${name}Repository.spec.ts`);
|
|
10547
10659
|
await Bun.write(testFilePath, testContent);
|
|
10548
|
-
const logger = new
|
|
10549
|
-
logger.success(`${
|
|
10660
|
+
const logger = new TerminalLogger26;
|
|
10661
|
+
logger.success(`${join27(repositoriesLocalDir, name)}Repository.ts created successfully`, undefined, {
|
|
10550
10662
|
showTimestamp: false,
|
|
10551
10663
|
showArrow: false,
|
|
10552
10664
|
useSymbol: true
|
|
10553
10665
|
});
|
|
10554
|
-
logger.success(`${
|
|
10666
|
+
logger.success(`${join27(testsLocalDir, name)}Repository.spec.ts created successfully`, undefined, {
|
|
10555
10667
|
showTimestamp: false,
|
|
10556
10668
|
showArrow: false,
|
|
10557
10669
|
useSymbol: true
|
|
10558
10670
|
});
|
|
10559
|
-
const packageJsonPath =
|
|
10671
|
+
const packageJsonPath = join27(process.cwd(), "package.json");
|
|
10560
10672
|
const packageJson = await Bun.file(packageJsonPath).json();
|
|
10561
10673
|
const deps = packageJson.dependencies ?? {};
|
|
10562
10674
|
const devDeps = packageJson.devDependencies ?? {};
|
|
@@ -10571,11 +10683,11 @@ class MakeRepositoryCommand {
|
|
|
10571
10683
|
}
|
|
10572
10684
|
}
|
|
10573
10685
|
MakeRepositoryCommand = __legacyDecorateClassTS([
|
|
10574
|
-
|
|
10686
|
+
decorator27.command()
|
|
10575
10687
|
], MakeRepositoryCommand);
|
|
10576
10688
|
// src/commands/MakeResourceBookCommand.ts
|
|
10577
|
-
import { join as
|
|
10578
|
-
import { decorator as
|
|
10689
|
+
import { join as join29 } from "path";
|
|
10690
|
+
import { decorator as decorator29 } from "@ooneex/command";
|
|
10579
10691
|
var {Glob } = globalThis.Bun;
|
|
10580
10692
|
|
|
10581
10693
|
// src/templates/resources/book/BookEntity.txt
|
|
@@ -11271,9 +11383,9 @@ export class UpdateBookService implements IService {
|
|
|
11271
11383
|
`;
|
|
11272
11384
|
|
|
11273
11385
|
// src/commands/MakeServiceCommand.ts
|
|
11274
|
-
import { join as
|
|
11275
|
-
import { decorator as
|
|
11276
|
-
import { TerminalLogger as
|
|
11386
|
+
import { join as join28 } from "path";
|
|
11387
|
+
import { decorator as decorator28 } from "@ooneex/command";
|
|
11388
|
+
import { TerminalLogger as TerminalLogger27 } from "@ooneex/logger";
|
|
11277
11389
|
import { toPascalCase as toPascalCase15 } from "@ooneex/utils";
|
|
11278
11390
|
|
|
11279
11391
|
// src/templates/service.test.txt
|
|
@@ -11325,28 +11437,28 @@ class MakeServiceCommand {
|
|
|
11325
11437
|
if (module) {
|
|
11326
11438
|
await ensureModule(module);
|
|
11327
11439
|
}
|
|
11328
|
-
const base = module ?
|
|
11329
|
-
const serviceLocalDir =
|
|
11330
|
-
const serviceDir =
|
|
11331
|
-
const filePath =
|
|
11440
|
+
const base = module ? join28("modules", module) : ".";
|
|
11441
|
+
const serviceLocalDir = join28(base, "src", "services");
|
|
11442
|
+
const serviceDir = join28(process.cwd(), serviceLocalDir);
|
|
11443
|
+
const filePath = join28(serviceDir, `${name}Service.ts`);
|
|
11332
11444
|
await Bun.write(filePath, content);
|
|
11333
11445
|
const testContent = service_test_default.replace(/{{NAME}}/g, name).replace(/{{MODULE}}/g, module ?? "");
|
|
11334
|
-
const testsLocalDir =
|
|
11335
|
-
const testsDir =
|
|
11336
|
-
const testFilePath =
|
|
11446
|
+
const testsLocalDir = join28(base, "tests", "services");
|
|
11447
|
+
const testsDir = join28(process.cwd(), testsLocalDir);
|
|
11448
|
+
const testFilePath = join28(testsDir, `${name}Service.spec.ts`);
|
|
11337
11449
|
await Bun.write(testFilePath, testContent);
|
|
11338
|
-
const logger = new
|
|
11339
|
-
logger.success(`${
|
|
11450
|
+
const logger = new TerminalLogger27;
|
|
11451
|
+
logger.success(`${join28(serviceLocalDir, name)}Service.ts created successfully`, undefined, {
|
|
11340
11452
|
showTimestamp: false,
|
|
11341
11453
|
showArrow: false,
|
|
11342
11454
|
useSymbol: true
|
|
11343
11455
|
});
|
|
11344
|
-
logger.success(`${
|
|
11456
|
+
logger.success(`${join28(testsLocalDir, name)}Service.spec.ts created successfully`, undefined, {
|
|
11345
11457
|
showTimestamp: false,
|
|
11346
11458
|
showArrow: false,
|
|
11347
11459
|
useSymbol: true
|
|
11348
11460
|
});
|
|
11349
|
-
const packageJsonPath =
|
|
11461
|
+
const packageJsonPath = join28(process.cwd(), "package.json");
|
|
11350
11462
|
const packageJson = await Bun.file(packageJsonPath).json();
|
|
11351
11463
|
const deps = packageJson.dependencies ?? {};
|
|
11352
11464
|
const devDeps = packageJson.devDependencies ?? {};
|
|
@@ -11361,7 +11473,7 @@ class MakeServiceCommand {
|
|
|
11361
11473
|
}
|
|
11362
11474
|
}
|
|
11363
11475
|
MakeServiceCommand = __legacyDecorateClassTS([
|
|
11364
|
-
|
|
11476
|
+
decorator28.command()
|
|
11365
11477
|
], MakeServiceCommand);
|
|
11366
11478
|
|
|
11367
11479
|
// src/commands/MakeResourceBookCommand.ts
|
|
@@ -11374,7 +11486,7 @@ class MakeResourceBookCommand {
|
|
|
11374
11486
|
}
|
|
11375
11487
|
async run() {
|
|
11376
11488
|
const module = "book";
|
|
11377
|
-
const base =
|
|
11489
|
+
const base = join29("modules", module);
|
|
11378
11490
|
const makeModuleCommand = new MakeModuleCommand;
|
|
11379
11491
|
await makeModuleCommand.run({ name: module, silent: true });
|
|
11380
11492
|
const makeEntityCommand = new MakeEntityCommand;
|
|
@@ -11394,26 +11506,26 @@ class MakeResourceBookCommand {
|
|
|
11394
11506
|
for (const controller of controllers) {
|
|
11395
11507
|
await makeControllerCommand.run({ ...controller, module, isSocket: false });
|
|
11396
11508
|
}
|
|
11397
|
-
const controllersDir =
|
|
11398
|
-
await Bun.write(
|
|
11399
|
-
await Bun.write(
|
|
11400
|
-
await Bun.write(
|
|
11401
|
-
await Bun.write(
|
|
11402
|
-
await Bun.write(
|
|
11509
|
+
const controllersDir = join29(process.cwd(), base, "src", "controllers");
|
|
11510
|
+
await Bun.write(join29(controllersDir, "CreateBookController.ts"), CreateBookController_default);
|
|
11511
|
+
await Bun.write(join29(controllersDir, "GetBookController.ts"), GetBookController_default);
|
|
11512
|
+
await Bun.write(join29(controllersDir, "ListBooksController.ts"), ListBooksController_default);
|
|
11513
|
+
await Bun.write(join29(controllersDir, "UpdateBookController.ts"), UpdateBookController_default);
|
|
11514
|
+
await Bun.write(join29(controllersDir, "DeleteBookController.ts"), DeleteBookController_default);
|
|
11403
11515
|
const makeServiceCommand = new MakeServiceCommand;
|
|
11404
11516
|
const services = ["CreateBook", "GetBook", "ListBooks", "UpdateBook", "DeleteBook"];
|
|
11405
11517
|
for (const name of services) {
|
|
11406
11518
|
await makeServiceCommand.run({ name, module });
|
|
11407
11519
|
}
|
|
11408
|
-
const servicesDir =
|
|
11409
|
-
await Bun.write(
|
|
11410
|
-
await Bun.write(
|
|
11411
|
-
await Bun.write(
|
|
11412
|
-
await Bun.write(
|
|
11413
|
-
await Bun.write(
|
|
11414
|
-
const entityPath =
|
|
11520
|
+
const servicesDir = join29(process.cwd(), base, "src", "services");
|
|
11521
|
+
await Bun.write(join29(servicesDir, "CreateBookService.ts"), CreateBookService_default);
|
|
11522
|
+
await Bun.write(join29(servicesDir, "GetBookService.ts"), GetBookService_default);
|
|
11523
|
+
await Bun.write(join29(servicesDir, "ListBooksService.ts"), ListBooksService_default);
|
|
11524
|
+
await Bun.write(join29(servicesDir, "UpdateBookService.ts"), UpdateBookService_default);
|
|
11525
|
+
await Bun.write(join29(servicesDir, "DeleteBookService.ts"), DeleteBookService_default);
|
|
11526
|
+
const entityPath = join29(process.cwd(), base, "src", "entities", "BookEntity.ts");
|
|
11415
11527
|
await Bun.write(entityPath, BookEntity_default);
|
|
11416
|
-
const migrationsDir =
|
|
11528
|
+
const migrationsDir = join29(process.cwd(), base, "src", "migrations");
|
|
11417
11529
|
const glob = new Glob("Migration*.ts");
|
|
11418
11530
|
for await (const file of glob.scan(migrationsDir)) {
|
|
11419
11531
|
if (file === "migrations.ts")
|
|
@@ -11421,18 +11533,18 @@ class MakeResourceBookCommand {
|
|
|
11421
11533
|
const name = file.replace(/\.ts$/, "");
|
|
11422
11534
|
const version = name.replace("Migration", "");
|
|
11423
11535
|
const content = BookMigration_default.replaceAll("{{ name }}", name).replaceAll("{{ version }}", version);
|
|
11424
|
-
await Bun.write(
|
|
11536
|
+
await Bun.write(join29(migrationsDir, file), content);
|
|
11425
11537
|
}
|
|
11426
|
-
const repositoryPath =
|
|
11538
|
+
const repositoryPath = join29(process.cwd(), base, "src", "repositories", "BookRepository.ts");
|
|
11427
11539
|
await Bun.write(repositoryPath, BookRepository_default);
|
|
11428
11540
|
}
|
|
11429
11541
|
}
|
|
11430
11542
|
MakeResourceBookCommand = __legacyDecorateClassTS([
|
|
11431
|
-
|
|
11543
|
+
decorator29.command()
|
|
11432
11544
|
], MakeResourceBookCommand);
|
|
11433
11545
|
// src/commands/MakeResourceCalendarEventCommand.ts
|
|
11434
|
-
import { join as
|
|
11435
|
-
import { decorator as
|
|
11546
|
+
import { join as join30 } from "path";
|
|
11547
|
+
import { decorator as decorator30 } from "@ooneex/command";
|
|
11436
11548
|
var {Glob: Glob2 } = globalThis.Bun;
|
|
11437
11549
|
|
|
11438
11550
|
// src/templates/resources/calendar-event/CalendarEventEntity.txt
|
|
@@ -12124,7 +12236,7 @@ class MakeResourceCalendarEventCommand {
|
|
|
12124
12236
|
}
|
|
12125
12237
|
async run() {
|
|
12126
12238
|
const module = "calendar-event";
|
|
12127
|
-
const base =
|
|
12239
|
+
const base = join30("modules", module);
|
|
12128
12240
|
const makeModuleCommand = new MakeModuleCommand;
|
|
12129
12241
|
await makeModuleCommand.run({ name: module, silent: true });
|
|
12130
12242
|
const makeEntityCommand = new MakeEntityCommand;
|
|
@@ -12159,12 +12271,12 @@ class MakeResourceCalendarEventCommand {
|
|
|
12159
12271
|
for (const controller of controllers) {
|
|
12160
12272
|
await makeControllerCommand.run({ ...controller, module, isSocket: false });
|
|
12161
12273
|
}
|
|
12162
|
-
const controllersDir =
|
|
12163
|
-
await Bun.write(
|
|
12164
|
-
await Bun.write(
|
|
12165
|
-
await Bun.write(
|
|
12166
|
-
await Bun.write(
|
|
12167
|
-
await Bun.write(
|
|
12274
|
+
const controllersDir = join30(process.cwd(), base, "src", "controllers");
|
|
12275
|
+
await Bun.write(join30(controllersDir, "CreateCalendarEventController.ts"), CreateCalendarEventController_default);
|
|
12276
|
+
await Bun.write(join30(controllersDir, "GetCalendarEventController.ts"), GetCalendarEventController_default);
|
|
12277
|
+
await Bun.write(join30(controllersDir, "ListCalendarEventsController.ts"), ListCalendarEventsController_default);
|
|
12278
|
+
await Bun.write(join30(controllersDir, "UpdateCalendarEventController.ts"), UpdateCalendarEventController_default);
|
|
12279
|
+
await Bun.write(join30(controllersDir, "DeleteCalendarEventController.ts"), DeleteCalendarEventController_default);
|
|
12168
12280
|
const makeServiceCommand = new MakeServiceCommand;
|
|
12169
12281
|
const services = [
|
|
12170
12282
|
"CreateCalendarEvent",
|
|
@@ -12176,15 +12288,15 @@ class MakeResourceCalendarEventCommand {
|
|
|
12176
12288
|
for (const name of services) {
|
|
12177
12289
|
await makeServiceCommand.run({ name, module });
|
|
12178
12290
|
}
|
|
12179
|
-
const servicesDir =
|
|
12180
|
-
await Bun.write(
|
|
12181
|
-
await Bun.write(
|
|
12182
|
-
await Bun.write(
|
|
12183
|
-
await Bun.write(
|
|
12184
|
-
await Bun.write(
|
|
12185
|
-
const entityPath =
|
|
12291
|
+
const servicesDir = join30(process.cwd(), base, "src", "services");
|
|
12292
|
+
await Bun.write(join30(servicesDir, "CreateCalendarEventService.ts"), CreateCalendarEventService_default);
|
|
12293
|
+
await Bun.write(join30(servicesDir, "GetCalendarEventService.ts"), GetCalendarEventService_default);
|
|
12294
|
+
await Bun.write(join30(servicesDir, "ListCalendarEventsService.ts"), ListCalendarEventsService_default);
|
|
12295
|
+
await Bun.write(join30(servicesDir, "UpdateCalendarEventService.ts"), UpdateCalendarEventService_default);
|
|
12296
|
+
await Bun.write(join30(servicesDir, "DeleteCalendarEventService.ts"), DeleteCalendarEventService_default);
|
|
12297
|
+
const entityPath = join30(process.cwd(), base, "src", "entities", "CalendarEventEntity.ts");
|
|
12186
12298
|
await Bun.write(entityPath, CalendarEventEntity_default);
|
|
12187
|
-
const migrationsDir =
|
|
12299
|
+
const migrationsDir = join30(process.cwd(), base, "src", "migrations");
|
|
12188
12300
|
const glob = new Glob2("Migration*.ts");
|
|
12189
12301
|
for await (const file of glob.scan(migrationsDir)) {
|
|
12190
12302
|
if (file === "migrations.ts")
|
|
@@ -12192,18 +12304,18 @@ class MakeResourceCalendarEventCommand {
|
|
|
12192
12304
|
const name = file.replace(/\.ts$/, "");
|
|
12193
12305
|
const version = name.replace("Migration", "");
|
|
12194
12306
|
const content = CalendarEventMigration_default.replaceAll("{{ name }}", name).replaceAll("{{ version }}", version);
|
|
12195
|
-
await Bun.write(
|
|
12307
|
+
await Bun.write(join30(migrationsDir, file), content);
|
|
12196
12308
|
}
|
|
12197
|
-
const repositoryPath =
|
|
12309
|
+
const repositoryPath = join30(process.cwd(), base, "src", "repositories", "CalendarEventRepository.ts");
|
|
12198
12310
|
await Bun.write(repositoryPath, CalendarEventRepository_default);
|
|
12199
12311
|
}
|
|
12200
12312
|
}
|
|
12201
12313
|
MakeResourceCalendarEventCommand = __legacyDecorateClassTS([
|
|
12202
|
-
|
|
12314
|
+
decorator30.command()
|
|
12203
12315
|
], MakeResourceCalendarEventCommand);
|
|
12204
12316
|
// src/commands/MakeResourceCategoryCommand.ts
|
|
12205
|
-
import { join as
|
|
12206
|
-
import { decorator as
|
|
12317
|
+
import { join as join31 } from "path";
|
|
12318
|
+
import { decorator as decorator31 } from "@ooneex/command";
|
|
12207
12319
|
var {Glob: Glob3 } = globalThis.Bun;
|
|
12208
12320
|
|
|
12209
12321
|
// src/templates/resources/category/CategoryEntity.txt
|
|
@@ -12794,7 +12906,7 @@ class MakeResourceCategoryCommand {
|
|
|
12794
12906
|
}
|
|
12795
12907
|
async run() {
|
|
12796
12908
|
const module = "category";
|
|
12797
|
-
const base =
|
|
12909
|
+
const base = join31("modules", module);
|
|
12798
12910
|
const makeModuleCommand = new MakeModuleCommand;
|
|
12799
12911
|
await makeModuleCommand.run({ name: module, silent: true });
|
|
12800
12912
|
const makeEntityCommand = new MakeEntityCommand;
|
|
@@ -12829,26 +12941,26 @@ class MakeResourceCategoryCommand {
|
|
|
12829
12941
|
for (const controller of controllers) {
|
|
12830
12942
|
await makeControllerCommand.run({ ...controller, module, isSocket: false });
|
|
12831
12943
|
}
|
|
12832
|
-
const controllersDir =
|
|
12833
|
-
await Bun.write(
|
|
12834
|
-
await Bun.write(
|
|
12835
|
-
await Bun.write(
|
|
12836
|
-
await Bun.write(
|
|
12837
|
-
await Bun.write(
|
|
12944
|
+
const controllersDir = join31(process.cwd(), base, "src", "controllers");
|
|
12945
|
+
await Bun.write(join31(controllersDir, "CreateCategoryController.ts"), CreateCategoryController_default);
|
|
12946
|
+
await Bun.write(join31(controllersDir, "GetCategoryController.ts"), GetCategoryController_default);
|
|
12947
|
+
await Bun.write(join31(controllersDir, "ListCategoriesController.ts"), ListCategoriesController_default);
|
|
12948
|
+
await Bun.write(join31(controllersDir, "UpdateCategoryController.ts"), UpdateCategoryController_default);
|
|
12949
|
+
await Bun.write(join31(controllersDir, "DeleteCategoryController.ts"), DeleteCategoryController_default);
|
|
12838
12950
|
const makeServiceCommand = new MakeServiceCommand;
|
|
12839
12951
|
const services = ["CreateCategory", "GetCategory", "ListCategories", "UpdateCategory", "DeleteCategory"];
|
|
12840
12952
|
for (const name of services) {
|
|
12841
12953
|
await makeServiceCommand.run({ name, module });
|
|
12842
12954
|
}
|
|
12843
|
-
const servicesDir =
|
|
12844
|
-
await Bun.write(
|
|
12845
|
-
await Bun.write(
|
|
12846
|
-
await Bun.write(
|
|
12847
|
-
await Bun.write(
|
|
12848
|
-
await Bun.write(
|
|
12849
|
-
const entityPath =
|
|
12955
|
+
const servicesDir = join31(process.cwd(), base, "src", "services");
|
|
12956
|
+
await Bun.write(join31(servicesDir, "CreateCategoryService.ts"), CreateCategoryService_default);
|
|
12957
|
+
await Bun.write(join31(servicesDir, "GetCategoryService.ts"), GetCategoryService_default);
|
|
12958
|
+
await Bun.write(join31(servicesDir, "ListCategoriesService.ts"), ListCategoriesService_default);
|
|
12959
|
+
await Bun.write(join31(servicesDir, "UpdateCategoryService.ts"), UpdateCategoryService_default);
|
|
12960
|
+
await Bun.write(join31(servicesDir, "DeleteCategoryService.ts"), DeleteCategoryService_default);
|
|
12961
|
+
const entityPath = join31(process.cwd(), base, "src", "entities", "CategoryEntity.ts");
|
|
12850
12962
|
await Bun.write(entityPath, CategoryEntity_default);
|
|
12851
|
-
const migrationsDir =
|
|
12963
|
+
const migrationsDir = join31(process.cwd(), base, "src", "migrations");
|
|
12852
12964
|
const glob = new Glob3("Migration*.ts");
|
|
12853
12965
|
for await (const file of glob.scan(migrationsDir)) {
|
|
12854
12966
|
if (file === "migrations.ts")
|
|
@@ -12856,18 +12968,18 @@ class MakeResourceCategoryCommand {
|
|
|
12856
12968
|
const name = file.replace(/\.ts$/, "");
|
|
12857
12969
|
const version = name.replace("Migration", "");
|
|
12858
12970
|
const content = CategoryMigration_default.replaceAll("{{ name }}", name).replaceAll("{{ version }}", version);
|
|
12859
|
-
await Bun.write(
|
|
12971
|
+
await Bun.write(join31(migrationsDir, file), content);
|
|
12860
12972
|
}
|
|
12861
|
-
const repositoryPath =
|
|
12973
|
+
const repositoryPath = join31(process.cwd(), base, "src", "repositories", "CategoryRepository.ts");
|
|
12862
12974
|
await Bun.write(repositoryPath, CategoryRepository_default);
|
|
12863
12975
|
}
|
|
12864
12976
|
}
|
|
12865
12977
|
MakeResourceCategoryCommand = __legacyDecorateClassTS([
|
|
12866
|
-
|
|
12978
|
+
decorator31.command()
|
|
12867
12979
|
], MakeResourceCategoryCommand);
|
|
12868
12980
|
// src/commands/MakeResourceColorCommand.ts
|
|
12869
|
-
import { join as
|
|
12870
|
-
import { decorator as
|
|
12981
|
+
import { join as join33 } from "path";
|
|
12982
|
+
import { decorator as decorator33 } from "@ooneex/command";
|
|
12871
12983
|
var {Glob: Glob4 } = globalThis.Bun;
|
|
12872
12984
|
|
|
12873
12985
|
// src/templates/resources/color/ColorEntity.txt
|
|
@@ -13659,9 +13771,9 @@ export class UpdateColorService implements IService {
|
|
|
13659
13771
|
`;
|
|
13660
13772
|
|
|
13661
13773
|
// src/commands/MakeSeedCommand.ts
|
|
13662
|
-
import { join as
|
|
13663
|
-
import { decorator as
|
|
13664
|
-
import { TerminalLogger as
|
|
13774
|
+
import { join as join32 } from "path";
|
|
13775
|
+
import { decorator as decorator32 } from "@ooneex/command";
|
|
13776
|
+
import { TerminalLogger as TerminalLogger28 } from "@ooneex/logger";
|
|
13665
13777
|
import { seedCreate } from "@ooneex/seeds";
|
|
13666
13778
|
|
|
13667
13779
|
// src/templates/module/seed.run.txt
|
|
@@ -13700,19 +13812,19 @@ class MakeSeedCommand {
|
|
|
13700
13812
|
if (module) {
|
|
13701
13813
|
await ensureModule(module);
|
|
13702
13814
|
}
|
|
13703
|
-
const base = module ?
|
|
13815
|
+
const base = module ? join32("modules", module) : ".";
|
|
13704
13816
|
const { seedPath: filePath, dataPath } = await seedCreate({
|
|
13705
13817
|
name,
|
|
13706
|
-
seedsDir:
|
|
13707
|
-
testsDir:
|
|
13818
|
+
seedsDir: join32(base, "src", "seeds"),
|
|
13819
|
+
testsDir: join32(base, "tests", "seeds"),
|
|
13708
13820
|
module: module ?? ""
|
|
13709
13821
|
});
|
|
13710
|
-
const binSeedRunPath =
|
|
13822
|
+
const binSeedRunPath = join32(process.cwd(), base, "bin", "seed", "run.ts");
|
|
13711
13823
|
const binSeedRunFile = Bun.file(binSeedRunPath);
|
|
13712
13824
|
if (!await binSeedRunFile.exists()) {
|
|
13713
13825
|
await Bun.write(binSeedRunPath, seed_run_default.replace(/{{name}}/g, module ?? ""));
|
|
13714
13826
|
}
|
|
13715
|
-
const logger = new
|
|
13827
|
+
const logger = new TerminalLogger28;
|
|
13716
13828
|
logger.success(`${filePath} created successfully`, undefined, {
|
|
13717
13829
|
showTimestamp: false,
|
|
13718
13830
|
showArrow: false,
|
|
@@ -13726,7 +13838,7 @@ class MakeSeedCommand {
|
|
|
13726
13838
|
}
|
|
13727
13839
|
}
|
|
13728
13840
|
MakeSeedCommand = __legacyDecorateClassTS([
|
|
13729
|
-
|
|
13841
|
+
decorator32.command()
|
|
13730
13842
|
], MakeSeedCommand);
|
|
13731
13843
|
|
|
13732
13844
|
// src/commands/MakeResourceColorCommand.ts
|
|
@@ -13739,7 +13851,7 @@ class MakeResourceColorCommand {
|
|
|
13739
13851
|
}
|
|
13740
13852
|
async run() {
|
|
13741
13853
|
const module = "color";
|
|
13742
|
-
const base =
|
|
13854
|
+
const base = join33("modules", module);
|
|
13743
13855
|
const makeModuleCommand = new MakeModuleCommand;
|
|
13744
13856
|
await makeModuleCommand.run({ name: module, silent: true });
|
|
13745
13857
|
const makeEntityCommand = new MakeEntityCommand;
|
|
@@ -13762,26 +13874,26 @@ class MakeResourceColorCommand {
|
|
|
13762
13874
|
for (const controller of controllers) {
|
|
13763
13875
|
await makeControllerCommand.run({ ...controller, module, isSocket: false });
|
|
13764
13876
|
}
|
|
13765
|
-
const controllersDir =
|
|
13766
|
-
await Bun.write(
|
|
13767
|
-
await Bun.write(
|
|
13768
|
-
await Bun.write(
|
|
13769
|
-
await Bun.write(
|
|
13770
|
-
await Bun.write(
|
|
13877
|
+
const controllersDir = join33(process.cwd(), base, "src", "controllers");
|
|
13878
|
+
await Bun.write(join33(controllersDir, "CreateColorController.ts"), CreateColorController_default);
|
|
13879
|
+
await Bun.write(join33(controllersDir, "GetColorController.ts"), GetColorController_default);
|
|
13880
|
+
await Bun.write(join33(controllersDir, "ListColorsController.ts"), ListColorsController_default);
|
|
13881
|
+
await Bun.write(join33(controllersDir, "UpdateColorController.ts"), UpdateColorController_default);
|
|
13882
|
+
await Bun.write(join33(controllersDir, "DeleteColorController.ts"), DeleteColorController_default);
|
|
13771
13883
|
const makeServiceCommand = new MakeServiceCommand;
|
|
13772
13884
|
const services = ["CreateColor", "GetColor", "ListColors", "UpdateColor", "DeleteColor"];
|
|
13773
13885
|
for (const name of services) {
|
|
13774
13886
|
await makeServiceCommand.run({ name, module });
|
|
13775
13887
|
}
|
|
13776
|
-
const servicesDir =
|
|
13777
|
-
await Bun.write(
|
|
13778
|
-
await Bun.write(
|
|
13779
|
-
await Bun.write(
|
|
13780
|
-
await Bun.write(
|
|
13781
|
-
await Bun.write(
|
|
13782
|
-
const entityPath =
|
|
13888
|
+
const servicesDir = join33(process.cwd(), base, "src", "services");
|
|
13889
|
+
await Bun.write(join33(servicesDir, "CreateColorService.ts"), CreateColorService_default);
|
|
13890
|
+
await Bun.write(join33(servicesDir, "GetColorService.ts"), GetColorService_default);
|
|
13891
|
+
await Bun.write(join33(servicesDir, "ListColorsService.ts"), ListColorsService_default);
|
|
13892
|
+
await Bun.write(join33(servicesDir, "UpdateColorService.ts"), UpdateColorService_default);
|
|
13893
|
+
await Bun.write(join33(servicesDir, "DeleteColorService.ts"), DeleteColorService_default);
|
|
13894
|
+
const entityPath = join33(process.cwd(), base, "src", "entities", "ColorEntity.ts");
|
|
13783
13895
|
await Bun.write(entityPath, ColorEntity_default);
|
|
13784
|
-
const migrationsDir =
|
|
13896
|
+
const migrationsDir = join33(process.cwd(), base, "src", "migrations");
|
|
13785
13897
|
const glob = new Glob4("Migration*.ts");
|
|
13786
13898
|
for await (const file of glob.scan(migrationsDir)) {
|
|
13787
13899
|
if (file === "migrations.ts")
|
|
@@ -13789,23 +13901,23 @@ class MakeResourceColorCommand {
|
|
|
13789
13901
|
const name = file.replace(/\.ts$/, "");
|
|
13790
13902
|
const version = name.replace("Migration", "");
|
|
13791
13903
|
const content = ColorMigration_default.replaceAll("{{ name }}", name).replaceAll("{{ version }}", version);
|
|
13792
|
-
await Bun.write(
|
|
13904
|
+
await Bun.write(join33(migrationsDir, file), content);
|
|
13793
13905
|
}
|
|
13794
|
-
const repositoryPath =
|
|
13906
|
+
const repositoryPath = join33(process.cwd(), base, "src", "repositories", "ColorRepository.ts");
|
|
13795
13907
|
await Bun.write(repositoryPath, ColorRepository_default);
|
|
13796
13908
|
const makeSeedCommand = new MakeSeedCommand;
|
|
13797
13909
|
await makeSeedCommand.run({ name: "Color", module });
|
|
13798
|
-
const seedsDir =
|
|
13799
|
-
await Bun.write(
|
|
13800
|
-
await Bun.write(
|
|
13910
|
+
const seedsDir = join33(process.cwd(), base, "src", "seeds");
|
|
13911
|
+
await Bun.write(join33(seedsDir, "ColorSeed.ts"), ColorSeed_default);
|
|
13912
|
+
await Bun.write(join33(seedsDir, "color-seed.yml"), color_seed_default);
|
|
13801
13913
|
}
|
|
13802
13914
|
}
|
|
13803
13915
|
MakeResourceColorCommand = __legacyDecorateClassTS([
|
|
13804
|
-
|
|
13916
|
+
decorator33.command()
|
|
13805
13917
|
], MakeResourceColorCommand);
|
|
13806
13918
|
// src/commands/MakeResourceDiscountCommand.ts
|
|
13807
|
-
import { join as
|
|
13808
|
-
import { decorator as
|
|
13919
|
+
import { join as join34 } from "path";
|
|
13920
|
+
import { decorator as decorator34 } from "@ooneex/command";
|
|
13809
13921
|
var {Glob: Glob5 } = globalThis.Bun;
|
|
13810
13922
|
|
|
13811
13923
|
// src/templates/resources/discount/controllers/CreateDiscountController.txt
|
|
@@ -14448,7 +14560,7 @@ class MakeResourceDiscountCommand {
|
|
|
14448
14560
|
}
|
|
14449
14561
|
async run() {
|
|
14450
14562
|
const module = "discount";
|
|
14451
|
-
const base =
|
|
14563
|
+
const base = join34("modules", module);
|
|
14452
14564
|
const makeModuleCommand = new MakeModuleCommand;
|
|
14453
14565
|
await makeModuleCommand.run({ name: module, silent: true });
|
|
14454
14566
|
const makeEntityCommand = new MakeEntityCommand;
|
|
@@ -14483,26 +14595,26 @@ class MakeResourceDiscountCommand {
|
|
|
14483
14595
|
for (const controller of controllers) {
|
|
14484
14596
|
await makeControllerCommand.run({ ...controller, module, isSocket: false });
|
|
14485
14597
|
}
|
|
14486
|
-
const controllersDir =
|
|
14487
|
-
await Bun.write(
|
|
14488
|
-
await Bun.write(
|
|
14489
|
-
await Bun.write(
|
|
14490
|
-
await Bun.write(
|
|
14491
|
-
await Bun.write(
|
|
14598
|
+
const controllersDir = join34(process.cwd(), base, "src", "controllers");
|
|
14599
|
+
await Bun.write(join34(controllersDir, "CreateDiscountController.ts"), CreateDiscountController_default);
|
|
14600
|
+
await Bun.write(join34(controllersDir, "GetDiscountController.ts"), GetDiscountController_default);
|
|
14601
|
+
await Bun.write(join34(controllersDir, "ListDiscountsController.ts"), ListDiscountsController_default);
|
|
14602
|
+
await Bun.write(join34(controllersDir, "UpdateDiscountController.ts"), UpdateDiscountController_default);
|
|
14603
|
+
await Bun.write(join34(controllersDir, "DeleteDiscountController.ts"), DeleteDiscountController_default);
|
|
14492
14604
|
const makeServiceCommand = new MakeServiceCommand;
|
|
14493
14605
|
const services = ["CreateDiscount", "GetDiscount", "ListDiscounts", "UpdateDiscount", "DeleteDiscount"];
|
|
14494
14606
|
for (const name of services) {
|
|
14495
14607
|
await makeServiceCommand.run({ name, module });
|
|
14496
14608
|
}
|
|
14497
|
-
const servicesDir =
|
|
14498
|
-
await Bun.write(
|
|
14499
|
-
await Bun.write(
|
|
14500
|
-
await Bun.write(
|
|
14501
|
-
await Bun.write(
|
|
14502
|
-
await Bun.write(
|
|
14503
|
-
const entityPath =
|
|
14609
|
+
const servicesDir = join34(process.cwd(), base, "src", "services");
|
|
14610
|
+
await Bun.write(join34(servicesDir, "CreateDiscountService.ts"), CreateDiscountService_default);
|
|
14611
|
+
await Bun.write(join34(servicesDir, "GetDiscountService.ts"), GetDiscountService_default);
|
|
14612
|
+
await Bun.write(join34(servicesDir, "ListDiscountsService.ts"), ListDiscountsService_default);
|
|
14613
|
+
await Bun.write(join34(servicesDir, "UpdateDiscountService.ts"), UpdateDiscountService_default);
|
|
14614
|
+
await Bun.write(join34(servicesDir, "DeleteDiscountService.ts"), DeleteDiscountService_default);
|
|
14615
|
+
const entityPath = join34(process.cwd(), base, "src", "entities", "DiscountEntity.ts");
|
|
14504
14616
|
await Bun.write(entityPath, DiscountEntity_default);
|
|
14505
|
-
const migrationsDir =
|
|
14617
|
+
const migrationsDir = join34(process.cwd(), base, "src", "migrations");
|
|
14506
14618
|
const glob = new Glob5("Migration*.ts");
|
|
14507
14619
|
for await (const file of glob.scan(migrationsDir)) {
|
|
14508
14620
|
if (file === "migrations.ts")
|
|
@@ -14510,18 +14622,18 @@ class MakeResourceDiscountCommand {
|
|
|
14510
14622
|
const name = file.replace(/\.ts$/, "");
|
|
14511
14623
|
const version = name.replace("Migration", "");
|
|
14512
14624
|
const content = DiscountMigration_default.replaceAll("{{ name }}", name).replaceAll("{{ version }}", version);
|
|
14513
|
-
await Bun.write(
|
|
14625
|
+
await Bun.write(join34(migrationsDir, file), content);
|
|
14514
14626
|
}
|
|
14515
|
-
const repositoryPath =
|
|
14627
|
+
const repositoryPath = join34(process.cwd(), base, "src", "repositories", "DiscountRepository.ts");
|
|
14516
14628
|
await Bun.write(repositoryPath, DiscountRepository_default);
|
|
14517
14629
|
}
|
|
14518
14630
|
}
|
|
14519
14631
|
MakeResourceDiscountCommand = __legacyDecorateClassTS([
|
|
14520
|
-
|
|
14632
|
+
decorator34.command()
|
|
14521
14633
|
], MakeResourceDiscountCommand);
|
|
14522
14634
|
// src/commands/MakeResourceFolderCommand.ts
|
|
14523
|
-
import { join as
|
|
14524
|
-
import { decorator as
|
|
14635
|
+
import { join as join35 } from "path";
|
|
14636
|
+
import { decorator as decorator35 } from "@ooneex/command";
|
|
14525
14637
|
var {Glob: Glob6 } = globalThis.Bun;
|
|
14526
14638
|
|
|
14527
14639
|
// src/templates/resources/folder/controllers/CreateFolderController.txt
|
|
@@ -15148,7 +15260,7 @@ class MakeResourceFolderCommand {
|
|
|
15148
15260
|
}
|
|
15149
15261
|
async run() {
|
|
15150
15262
|
const module = "folder";
|
|
15151
|
-
const base =
|
|
15263
|
+
const base = join35("modules", module);
|
|
15152
15264
|
const makeModuleCommand = new MakeModuleCommand;
|
|
15153
15265
|
await makeModuleCommand.run({ name: module, silent: true });
|
|
15154
15266
|
const makeEntityCommand = new MakeEntityCommand;
|
|
@@ -15183,26 +15295,26 @@ class MakeResourceFolderCommand {
|
|
|
15183
15295
|
for (const controller of controllers) {
|
|
15184
15296
|
await makeControllerCommand.run({ ...controller, module, isSocket: false });
|
|
15185
15297
|
}
|
|
15186
|
-
const controllersDir =
|
|
15187
|
-
await Bun.write(
|
|
15188
|
-
await Bun.write(
|
|
15189
|
-
await Bun.write(
|
|
15190
|
-
await Bun.write(
|
|
15191
|
-
await Bun.write(
|
|
15298
|
+
const controllersDir = join35(process.cwd(), base, "src", "controllers");
|
|
15299
|
+
await Bun.write(join35(controllersDir, "CreateFolderController.ts"), CreateFolderController_default);
|
|
15300
|
+
await Bun.write(join35(controllersDir, "GetFolderController.ts"), GetFolderController_default);
|
|
15301
|
+
await Bun.write(join35(controllersDir, "ListFoldersController.ts"), ListFoldersController_default);
|
|
15302
|
+
await Bun.write(join35(controllersDir, "UpdateFolderController.ts"), UpdateFolderController_default);
|
|
15303
|
+
await Bun.write(join35(controllersDir, "DeleteFolderController.ts"), DeleteFolderController_default);
|
|
15192
15304
|
const makeServiceCommand = new MakeServiceCommand;
|
|
15193
15305
|
const services = ["CreateFolder", "GetFolder", "ListFolders", "UpdateFolder", "DeleteFolder"];
|
|
15194
15306
|
for (const name of services) {
|
|
15195
15307
|
await makeServiceCommand.run({ name, module });
|
|
15196
15308
|
}
|
|
15197
|
-
const servicesDir =
|
|
15198
|
-
await Bun.write(
|
|
15199
|
-
await Bun.write(
|
|
15200
|
-
await Bun.write(
|
|
15201
|
-
await Bun.write(
|
|
15202
|
-
await Bun.write(
|
|
15203
|
-
const entityPath =
|
|
15309
|
+
const servicesDir = join35(process.cwd(), base, "src", "services");
|
|
15310
|
+
await Bun.write(join35(servicesDir, "CreateFolderService.ts"), CreateFolderService_default);
|
|
15311
|
+
await Bun.write(join35(servicesDir, "GetFolderService.ts"), GetFolderService_default);
|
|
15312
|
+
await Bun.write(join35(servicesDir, "ListFoldersService.ts"), ListFoldersService_default);
|
|
15313
|
+
await Bun.write(join35(servicesDir, "UpdateFolderService.ts"), UpdateFolderService_default);
|
|
15314
|
+
await Bun.write(join35(servicesDir, "DeleteFolderService.ts"), DeleteFolderService_default);
|
|
15315
|
+
const entityPath = join35(process.cwd(), base, "src", "entities", "FolderEntity.ts");
|
|
15204
15316
|
await Bun.write(entityPath, FolderEntity_default);
|
|
15205
|
-
const migrationsDir =
|
|
15317
|
+
const migrationsDir = join35(process.cwd(), base, "src", "migrations");
|
|
15206
15318
|
const glob = new Glob6("Migration*.ts");
|
|
15207
15319
|
for await (const file of glob.scan(migrationsDir)) {
|
|
15208
15320
|
if (file === "migrations.ts")
|
|
@@ -15210,18 +15322,18 @@ class MakeResourceFolderCommand {
|
|
|
15210
15322
|
const name = file.replace(/\.ts$/, "");
|
|
15211
15323
|
const version = name.replace("Migration", "");
|
|
15212
15324
|
const content = FolderMigration_default.replaceAll("{{ name }}", name).replaceAll("{{ version }}", version);
|
|
15213
|
-
await Bun.write(
|
|
15325
|
+
await Bun.write(join35(migrationsDir, file), content);
|
|
15214
15326
|
}
|
|
15215
|
-
const repositoryPath =
|
|
15327
|
+
const repositoryPath = join35(process.cwd(), base, "src", "repositories", "FolderRepository.ts");
|
|
15216
15328
|
await Bun.write(repositoryPath, FolderRepository_default);
|
|
15217
15329
|
}
|
|
15218
15330
|
}
|
|
15219
15331
|
MakeResourceFolderCommand = __legacyDecorateClassTS([
|
|
15220
|
-
|
|
15332
|
+
decorator35.command()
|
|
15221
15333
|
], MakeResourceFolderCommand);
|
|
15222
15334
|
// src/commands/MakeResourceImageCommand.ts
|
|
15223
|
-
import { join as
|
|
15224
|
-
import { decorator as
|
|
15335
|
+
import { join as join36 } from "path";
|
|
15336
|
+
import { decorator as decorator36 } from "@ooneex/command";
|
|
15225
15337
|
var {Glob: Glob7 } = globalThis.Bun;
|
|
15226
15338
|
|
|
15227
15339
|
// src/templates/resources/image/controllers/CreateImageController.txt
|
|
@@ -15887,7 +15999,7 @@ class MakeResourceImageCommand {
|
|
|
15887
15999
|
}
|
|
15888
16000
|
async run() {
|
|
15889
16001
|
const module = "image";
|
|
15890
|
-
const base =
|
|
16002
|
+
const base = join36("modules", module);
|
|
15891
16003
|
const makeModuleCommand = new MakeModuleCommand;
|
|
15892
16004
|
await makeModuleCommand.run({ name: module, silent: true });
|
|
15893
16005
|
const makeEntityCommand = new MakeEntityCommand;
|
|
@@ -15922,26 +16034,26 @@ class MakeResourceImageCommand {
|
|
|
15922
16034
|
for (const controller of controllers) {
|
|
15923
16035
|
await makeControllerCommand.run({ ...controller, module, isSocket: false });
|
|
15924
16036
|
}
|
|
15925
|
-
const controllersDir =
|
|
15926
|
-
await Bun.write(
|
|
15927
|
-
await Bun.write(
|
|
15928
|
-
await Bun.write(
|
|
15929
|
-
await Bun.write(
|
|
15930
|
-
await Bun.write(
|
|
16037
|
+
const controllersDir = join36(process.cwd(), base, "src", "controllers");
|
|
16038
|
+
await Bun.write(join36(controllersDir, "CreateImageController.ts"), CreateImageController_default);
|
|
16039
|
+
await Bun.write(join36(controllersDir, "GetImageController.ts"), GetImageController_default);
|
|
16040
|
+
await Bun.write(join36(controllersDir, "ListImagesController.ts"), ListImagesController_default);
|
|
16041
|
+
await Bun.write(join36(controllersDir, "UpdateImageController.ts"), UpdateImageController_default);
|
|
16042
|
+
await Bun.write(join36(controllersDir, "DeleteImageController.ts"), DeleteImageController_default);
|
|
15931
16043
|
const makeServiceCommand = new MakeServiceCommand;
|
|
15932
16044
|
const services = ["CreateImage", "GetImage", "ListImages", "UpdateImage", "DeleteImage"];
|
|
15933
16045
|
for (const name of services) {
|
|
15934
16046
|
await makeServiceCommand.run({ name, module });
|
|
15935
16047
|
}
|
|
15936
|
-
const servicesDir =
|
|
15937
|
-
await Bun.write(
|
|
15938
|
-
await Bun.write(
|
|
15939
|
-
await Bun.write(
|
|
15940
|
-
await Bun.write(
|
|
15941
|
-
await Bun.write(
|
|
15942
|
-
const entityPath =
|
|
16048
|
+
const servicesDir = join36(process.cwd(), base, "src", "services");
|
|
16049
|
+
await Bun.write(join36(servicesDir, "CreateImageService.ts"), CreateImageService_default);
|
|
16050
|
+
await Bun.write(join36(servicesDir, "GetImageService.ts"), GetImageService_default);
|
|
16051
|
+
await Bun.write(join36(servicesDir, "ListImagesService.ts"), ListImagesService_default);
|
|
16052
|
+
await Bun.write(join36(servicesDir, "UpdateImageService.ts"), UpdateImageService_default);
|
|
16053
|
+
await Bun.write(join36(servicesDir, "DeleteImageService.ts"), DeleteImageService_default);
|
|
16054
|
+
const entityPath = join36(process.cwd(), base, "src", "entities", "ImageEntity.ts");
|
|
15943
16055
|
await Bun.write(entityPath, ImageEntity_default);
|
|
15944
|
-
const migrationsDir =
|
|
16056
|
+
const migrationsDir = join36(process.cwd(), base, "src", "migrations");
|
|
15945
16057
|
const glob = new Glob7("Migration*.ts");
|
|
15946
16058
|
for await (const file of glob.scan(migrationsDir)) {
|
|
15947
16059
|
if (file === "migrations.ts")
|
|
@@ -15949,18 +16061,18 @@ class MakeResourceImageCommand {
|
|
|
15949
16061
|
const name = file.replace(/\.ts$/, "");
|
|
15950
16062
|
const version = name.replace("Migration", "");
|
|
15951
16063
|
const content = ImageMigration_default.replaceAll("{{ name }}", name).replaceAll("{{ version }}", version);
|
|
15952
|
-
await Bun.write(
|
|
16064
|
+
await Bun.write(join36(migrationsDir, file), content);
|
|
15953
16065
|
}
|
|
15954
|
-
const repositoryPath =
|
|
16066
|
+
const repositoryPath = join36(process.cwd(), base, "src", "repositories", "ImageRepository.ts");
|
|
15955
16067
|
await Bun.write(repositoryPath, ImageRepository_default);
|
|
15956
16068
|
}
|
|
15957
16069
|
}
|
|
15958
16070
|
MakeResourceImageCommand = __legacyDecorateClassTS([
|
|
15959
|
-
|
|
16071
|
+
decorator36.command()
|
|
15960
16072
|
], MakeResourceImageCommand);
|
|
15961
16073
|
// src/commands/MakeResourceNoteCommand.ts
|
|
15962
|
-
import { join as
|
|
15963
|
-
import { decorator as
|
|
16074
|
+
import { join as join37 } from "path";
|
|
16075
|
+
import { decorator as decorator37 } from "@ooneex/command";
|
|
15964
16076
|
var {Glob: Glob8 } = globalThis.Bun;
|
|
15965
16077
|
|
|
15966
16078
|
// src/templates/resources/note/controllers/CreateNoteController.txt
|
|
@@ -16665,7 +16777,7 @@ class MakeResourceNoteCommand {
|
|
|
16665
16777
|
}
|
|
16666
16778
|
async run() {
|
|
16667
16779
|
const module = "note";
|
|
16668
|
-
const base =
|
|
16780
|
+
const base = join37("modules", module);
|
|
16669
16781
|
const makeModuleCommand = new MakeModuleCommand;
|
|
16670
16782
|
await makeModuleCommand.run({ name: module, silent: true });
|
|
16671
16783
|
const makeEntityCommand = new MakeEntityCommand;
|
|
@@ -16700,26 +16812,26 @@ class MakeResourceNoteCommand {
|
|
|
16700
16812
|
for (const controller of controllers) {
|
|
16701
16813
|
await makeControllerCommand.run({ ...controller, module, isSocket: false });
|
|
16702
16814
|
}
|
|
16703
|
-
const controllersDir =
|
|
16704
|
-
await Bun.write(
|
|
16705
|
-
await Bun.write(
|
|
16706
|
-
await Bun.write(
|
|
16707
|
-
await Bun.write(
|
|
16708
|
-
await Bun.write(
|
|
16815
|
+
const controllersDir = join37(process.cwd(), base, "src", "controllers");
|
|
16816
|
+
await Bun.write(join37(controllersDir, "CreateNoteController.ts"), CreateNoteController_default);
|
|
16817
|
+
await Bun.write(join37(controllersDir, "GetNoteController.ts"), GetNoteController_default);
|
|
16818
|
+
await Bun.write(join37(controllersDir, "ListNotesController.ts"), ListNotesController_default);
|
|
16819
|
+
await Bun.write(join37(controllersDir, "UpdateNoteController.ts"), UpdateNoteController_default);
|
|
16820
|
+
await Bun.write(join37(controllersDir, "DeleteNoteController.ts"), DeleteNoteController_default);
|
|
16709
16821
|
const makeServiceCommand = new MakeServiceCommand;
|
|
16710
16822
|
const services = ["CreateNote", "GetNote", "ListNotes", "UpdateNote", "DeleteNote"];
|
|
16711
16823
|
for (const name of services) {
|
|
16712
16824
|
await makeServiceCommand.run({ name, module });
|
|
16713
16825
|
}
|
|
16714
|
-
const servicesDir =
|
|
16715
|
-
await Bun.write(
|
|
16716
|
-
await Bun.write(
|
|
16717
|
-
await Bun.write(
|
|
16718
|
-
await Bun.write(
|
|
16719
|
-
await Bun.write(
|
|
16720
|
-
const entityPath =
|
|
16826
|
+
const servicesDir = join37(process.cwd(), base, "src", "services");
|
|
16827
|
+
await Bun.write(join37(servicesDir, "CreateNoteService.ts"), CreateNoteService_default);
|
|
16828
|
+
await Bun.write(join37(servicesDir, "GetNoteService.ts"), GetNoteService_default);
|
|
16829
|
+
await Bun.write(join37(servicesDir, "ListNotesService.ts"), ListNotesService_default);
|
|
16830
|
+
await Bun.write(join37(servicesDir, "UpdateNoteService.ts"), UpdateNoteService_default);
|
|
16831
|
+
await Bun.write(join37(servicesDir, "DeleteNoteService.ts"), DeleteNoteService_default);
|
|
16832
|
+
const entityPath = join37(process.cwd(), base, "src", "entities", "NoteEntity.ts");
|
|
16721
16833
|
await Bun.write(entityPath, NoteEntity_default);
|
|
16722
|
-
const migrationsDir =
|
|
16834
|
+
const migrationsDir = join37(process.cwd(), base, "src", "migrations");
|
|
16723
16835
|
const glob = new Glob8("Migration*.ts");
|
|
16724
16836
|
for await (const file of glob.scan(migrationsDir)) {
|
|
16725
16837
|
if (file === "migrations.ts")
|
|
@@ -16727,18 +16839,18 @@ class MakeResourceNoteCommand {
|
|
|
16727
16839
|
const name = file.replace(/\.ts$/, "");
|
|
16728
16840
|
const version = name.replace("Migration", "");
|
|
16729
16841
|
const content = NoteMigration_default.replaceAll("{{ name }}", name).replaceAll("{{ version }}", version);
|
|
16730
|
-
await Bun.write(
|
|
16842
|
+
await Bun.write(join37(migrationsDir, file), content);
|
|
16731
16843
|
}
|
|
16732
|
-
const repositoryPath =
|
|
16844
|
+
const repositoryPath = join37(process.cwd(), base, "src", "repositories", "NoteRepository.ts");
|
|
16733
16845
|
await Bun.write(repositoryPath, NoteRepository_default);
|
|
16734
16846
|
}
|
|
16735
16847
|
}
|
|
16736
16848
|
MakeResourceNoteCommand = __legacyDecorateClassTS([
|
|
16737
|
-
|
|
16849
|
+
decorator37.command()
|
|
16738
16850
|
], MakeResourceNoteCommand);
|
|
16739
16851
|
// src/commands/MakeResourceStatusCommand.ts
|
|
16740
|
-
import { join as
|
|
16741
|
-
import { decorator as
|
|
16852
|
+
import { join as join38 } from "path";
|
|
16853
|
+
import { decorator as decorator38 } from "@ooneex/command";
|
|
16742
16854
|
var {Glob: Glob9 } = globalThis.Bun;
|
|
16743
16855
|
|
|
16744
16856
|
// src/templates/resources/status/controllers/CreateStatusController.txt
|
|
@@ -17599,7 +17711,7 @@ class MakeResourceStatusCommand {
|
|
|
17599
17711
|
}
|
|
17600
17712
|
async run() {
|
|
17601
17713
|
const module = "status";
|
|
17602
|
-
const base =
|
|
17714
|
+
const base = join38("modules", module);
|
|
17603
17715
|
const makeModuleCommand = new MakeModuleCommand;
|
|
17604
17716
|
await makeModuleCommand.run({ name: module, silent: true });
|
|
17605
17717
|
const makeEntityCommand = new MakeEntityCommand;
|
|
@@ -17634,26 +17746,26 @@ class MakeResourceStatusCommand {
|
|
|
17634
17746
|
for (const controller of controllers) {
|
|
17635
17747
|
await makeControllerCommand.run({ ...controller, module, isSocket: false });
|
|
17636
17748
|
}
|
|
17637
|
-
const controllersDir =
|
|
17638
|
-
await Bun.write(
|
|
17639
|
-
await Bun.write(
|
|
17640
|
-
await Bun.write(
|
|
17641
|
-
await Bun.write(
|
|
17642
|
-
await Bun.write(
|
|
17749
|
+
const controllersDir = join38(process.cwd(), base, "src", "controllers");
|
|
17750
|
+
await Bun.write(join38(controllersDir, "CreateStatusController.ts"), CreateStatusController_default);
|
|
17751
|
+
await Bun.write(join38(controllersDir, "GetStatusController.ts"), GetStatusController_default);
|
|
17752
|
+
await Bun.write(join38(controllersDir, "ListStatusesController.ts"), ListStatusesController_default);
|
|
17753
|
+
await Bun.write(join38(controllersDir, "UpdateStatusController.ts"), UpdateStatusController_default);
|
|
17754
|
+
await Bun.write(join38(controllersDir, "DeleteStatusController.ts"), DeleteStatusController_default);
|
|
17643
17755
|
const makeServiceCommand = new MakeServiceCommand;
|
|
17644
17756
|
const services = ["CreateStatus", "GetStatus", "ListStatuses", "UpdateStatus", "DeleteStatus"];
|
|
17645
17757
|
for (const name of services) {
|
|
17646
17758
|
await makeServiceCommand.run({ name, module });
|
|
17647
17759
|
}
|
|
17648
|
-
const servicesDir =
|
|
17649
|
-
await Bun.write(
|
|
17650
|
-
await Bun.write(
|
|
17651
|
-
await Bun.write(
|
|
17652
|
-
await Bun.write(
|
|
17653
|
-
await Bun.write(
|
|
17654
|
-
const entityPath =
|
|
17760
|
+
const servicesDir = join38(process.cwd(), base, "src", "services");
|
|
17761
|
+
await Bun.write(join38(servicesDir, "CreateStatusService.ts"), CreateStatusService_default);
|
|
17762
|
+
await Bun.write(join38(servicesDir, "GetStatusService.ts"), GetStatusService_default);
|
|
17763
|
+
await Bun.write(join38(servicesDir, "ListStatusesService.ts"), ListStatusesService_default);
|
|
17764
|
+
await Bun.write(join38(servicesDir, "UpdateStatusService.ts"), UpdateStatusService_default);
|
|
17765
|
+
await Bun.write(join38(servicesDir, "DeleteStatusService.ts"), DeleteStatusService_default);
|
|
17766
|
+
const entityPath = join38(process.cwd(), base, "src", "entities", "StatusEntity.ts");
|
|
17655
17767
|
await Bun.write(entityPath, StatusEntity_default);
|
|
17656
|
-
const migrationsDir =
|
|
17768
|
+
const migrationsDir = join38(process.cwd(), base, "src", "migrations");
|
|
17657
17769
|
const glob = new Glob9("Migration*.ts");
|
|
17658
17770
|
for await (const file of glob.scan(migrationsDir)) {
|
|
17659
17771
|
if (file === "migrations.ts")
|
|
@@ -17661,23 +17773,23 @@ class MakeResourceStatusCommand {
|
|
|
17661
17773
|
const name = file.replace(/\.ts$/, "");
|
|
17662
17774
|
const version = name.replace("Migration", "");
|
|
17663
17775
|
const content = StatusMigration_default.replaceAll("{{ name }}", name).replaceAll("{{ version }}", version);
|
|
17664
|
-
await Bun.write(
|
|
17776
|
+
await Bun.write(join38(migrationsDir, file), content);
|
|
17665
17777
|
}
|
|
17666
|
-
const repositoryPath =
|
|
17778
|
+
const repositoryPath = join38(process.cwd(), base, "src", "repositories", "StatusRepository.ts");
|
|
17667
17779
|
await Bun.write(repositoryPath, StatusRepository_default);
|
|
17668
17780
|
const makeSeedCommand = new MakeSeedCommand;
|
|
17669
17781
|
await makeSeedCommand.run({ name: "Status", module });
|
|
17670
|
-
const seedsDir =
|
|
17671
|
-
await Bun.write(
|
|
17672
|
-
await Bun.write(
|
|
17782
|
+
const seedsDir = join38(process.cwd(), base, "src", "seeds");
|
|
17783
|
+
await Bun.write(join38(seedsDir, "StatusSeed.ts"), StatusSeed_default);
|
|
17784
|
+
await Bun.write(join38(seedsDir, "status-seed.yml"), status_seed_default);
|
|
17673
17785
|
}
|
|
17674
17786
|
}
|
|
17675
17787
|
MakeResourceStatusCommand = __legacyDecorateClassTS([
|
|
17676
|
-
|
|
17788
|
+
decorator38.command()
|
|
17677
17789
|
], MakeResourceStatusCommand);
|
|
17678
17790
|
// src/commands/MakeResourceTagCommand.ts
|
|
17679
|
-
import { join as
|
|
17680
|
-
import { decorator as
|
|
17791
|
+
import { join as join39 } from "path";
|
|
17792
|
+
import { decorator as decorator39 } from "@ooneex/command";
|
|
17681
17793
|
var {Glob: Glob10 } = globalThis.Bun;
|
|
17682
17794
|
|
|
17683
17795
|
// src/templates/resources/tag/controllers/CreateTagController.txt
|
|
@@ -18268,7 +18380,7 @@ class MakeResourceTagCommand {
|
|
|
18268
18380
|
}
|
|
18269
18381
|
async run() {
|
|
18270
18382
|
const module = "tag";
|
|
18271
|
-
const base =
|
|
18383
|
+
const base = join39("modules", module);
|
|
18272
18384
|
const makeModuleCommand = new MakeModuleCommand;
|
|
18273
18385
|
await makeModuleCommand.run({ name: module, silent: true });
|
|
18274
18386
|
const makeEntityCommand = new MakeEntityCommand;
|
|
@@ -18303,26 +18415,26 @@ class MakeResourceTagCommand {
|
|
|
18303
18415
|
for (const controller of controllers) {
|
|
18304
18416
|
await makeControllerCommand.run({ ...controller, module, isSocket: false });
|
|
18305
18417
|
}
|
|
18306
|
-
const controllersDir =
|
|
18307
|
-
await Bun.write(
|
|
18308
|
-
await Bun.write(
|
|
18309
|
-
await Bun.write(
|
|
18310
|
-
await Bun.write(
|
|
18311
|
-
await Bun.write(
|
|
18418
|
+
const controllersDir = join39(process.cwd(), base, "src", "controllers");
|
|
18419
|
+
await Bun.write(join39(controllersDir, "CreateTagController.ts"), CreateTagController_default);
|
|
18420
|
+
await Bun.write(join39(controllersDir, "GetTagController.ts"), GetTagController_default);
|
|
18421
|
+
await Bun.write(join39(controllersDir, "ListTagsController.ts"), ListTagsController_default);
|
|
18422
|
+
await Bun.write(join39(controllersDir, "UpdateTagController.ts"), UpdateTagController_default);
|
|
18423
|
+
await Bun.write(join39(controllersDir, "DeleteTagController.ts"), DeleteTagController_default);
|
|
18312
18424
|
const makeServiceCommand = new MakeServiceCommand;
|
|
18313
18425
|
const services = ["CreateTag", "GetTag", "ListTags", "UpdateTag", "DeleteTag"];
|
|
18314
18426
|
for (const name of services) {
|
|
18315
18427
|
await makeServiceCommand.run({ name, module });
|
|
18316
18428
|
}
|
|
18317
|
-
const servicesDir =
|
|
18318
|
-
await Bun.write(
|
|
18319
|
-
await Bun.write(
|
|
18320
|
-
await Bun.write(
|
|
18321
|
-
await Bun.write(
|
|
18322
|
-
await Bun.write(
|
|
18323
|
-
const entityPath =
|
|
18429
|
+
const servicesDir = join39(process.cwd(), base, "src", "services");
|
|
18430
|
+
await Bun.write(join39(servicesDir, "CreateTagService.ts"), CreateTagService_default);
|
|
18431
|
+
await Bun.write(join39(servicesDir, "GetTagService.ts"), GetTagService_default);
|
|
18432
|
+
await Bun.write(join39(servicesDir, "ListTagsService.ts"), ListTagsService_default);
|
|
18433
|
+
await Bun.write(join39(servicesDir, "UpdateTagService.ts"), UpdateTagService_default);
|
|
18434
|
+
await Bun.write(join39(servicesDir, "DeleteTagService.ts"), DeleteTagService_default);
|
|
18435
|
+
const entityPath = join39(process.cwd(), base, "src", "entities", "TagEntity.ts");
|
|
18324
18436
|
await Bun.write(entityPath, TagEntity_default);
|
|
18325
|
-
const migrationsDir =
|
|
18437
|
+
const migrationsDir = join39(process.cwd(), base, "src", "migrations");
|
|
18326
18438
|
const glob = new Glob10("Migration*.ts");
|
|
18327
18439
|
for await (const file of glob.scan(migrationsDir)) {
|
|
18328
18440
|
if (file === "migrations.ts")
|
|
@@ -18330,18 +18442,18 @@ class MakeResourceTagCommand {
|
|
|
18330
18442
|
const name = file.replace(/\.ts$/, "");
|
|
18331
18443
|
const version = name.replace("Migration", "");
|
|
18332
18444
|
const content = TagMigration_default.replaceAll("{{ name }}", name).replaceAll("{{ version }}", version);
|
|
18333
|
-
await Bun.write(
|
|
18445
|
+
await Bun.write(join39(migrationsDir, file), content);
|
|
18334
18446
|
}
|
|
18335
|
-
const repositoryPath =
|
|
18447
|
+
const repositoryPath = join39(process.cwd(), base, "src", "repositories", "TagRepository.ts");
|
|
18336
18448
|
await Bun.write(repositoryPath, TagRepository_default);
|
|
18337
18449
|
}
|
|
18338
18450
|
}
|
|
18339
18451
|
MakeResourceTagCommand = __legacyDecorateClassTS([
|
|
18340
|
-
|
|
18452
|
+
decorator39.command()
|
|
18341
18453
|
], MakeResourceTagCommand);
|
|
18342
18454
|
// src/commands/MakeResourceTaskCommand.ts
|
|
18343
|
-
import { join as
|
|
18344
|
-
import { decorator as
|
|
18455
|
+
import { join as join40 } from "path";
|
|
18456
|
+
import { decorator as decorator40 } from "@ooneex/command";
|
|
18345
18457
|
var {Glob: Glob11 } = globalThis.Bun;
|
|
18346
18458
|
|
|
18347
18459
|
// src/templates/resources/task/controllers/CreateTaskController.txt
|
|
@@ -19014,7 +19126,7 @@ class MakeResourceTaskCommand {
|
|
|
19014
19126
|
}
|
|
19015
19127
|
async run() {
|
|
19016
19128
|
const module = "task";
|
|
19017
|
-
const base =
|
|
19129
|
+
const base = join40("modules", module);
|
|
19018
19130
|
const makeModuleCommand = new MakeModuleCommand;
|
|
19019
19131
|
await makeModuleCommand.run({ name: module, silent: true });
|
|
19020
19132
|
const makeEntityCommand = new MakeEntityCommand;
|
|
@@ -19049,26 +19161,26 @@ class MakeResourceTaskCommand {
|
|
|
19049
19161
|
for (const controller of controllers) {
|
|
19050
19162
|
await makeControllerCommand.run({ ...controller, module, isSocket: false });
|
|
19051
19163
|
}
|
|
19052
|
-
const controllersDir =
|
|
19053
|
-
await Bun.write(
|
|
19054
|
-
await Bun.write(
|
|
19055
|
-
await Bun.write(
|
|
19056
|
-
await Bun.write(
|
|
19057
|
-
await Bun.write(
|
|
19164
|
+
const controllersDir = join40(process.cwd(), base, "src", "controllers");
|
|
19165
|
+
await Bun.write(join40(controllersDir, "CreateTaskController.ts"), CreateTaskController_default);
|
|
19166
|
+
await Bun.write(join40(controllersDir, "GetTaskController.ts"), GetTaskController_default);
|
|
19167
|
+
await Bun.write(join40(controllersDir, "ListTasksController.ts"), ListTasksController_default);
|
|
19168
|
+
await Bun.write(join40(controllersDir, "UpdateTaskController.ts"), UpdateTaskController_default);
|
|
19169
|
+
await Bun.write(join40(controllersDir, "DeleteTaskController.ts"), DeleteTaskController_default);
|
|
19058
19170
|
const makeServiceCommand = new MakeServiceCommand;
|
|
19059
19171
|
const services = ["CreateTask", "GetTask", "ListTasks", "UpdateTask", "DeleteTask"];
|
|
19060
19172
|
for (const name of services) {
|
|
19061
19173
|
await makeServiceCommand.run({ name, module });
|
|
19062
19174
|
}
|
|
19063
|
-
const servicesDir =
|
|
19064
|
-
await Bun.write(
|
|
19065
|
-
await Bun.write(
|
|
19066
|
-
await Bun.write(
|
|
19067
|
-
await Bun.write(
|
|
19068
|
-
await Bun.write(
|
|
19069
|
-
const entityPath =
|
|
19175
|
+
const servicesDir = join40(process.cwd(), base, "src", "services");
|
|
19176
|
+
await Bun.write(join40(servicesDir, "CreateTaskService.ts"), CreateTaskService_default);
|
|
19177
|
+
await Bun.write(join40(servicesDir, "GetTaskService.ts"), GetTaskService_default);
|
|
19178
|
+
await Bun.write(join40(servicesDir, "ListTasksService.ts"), ListTasksService_default);
|
|
19179
|
+
await Bun.write(join40(servicesDir, "UpdateTaskService.ts"), UpdateTaskService_default);
|
|
19180
|
+
await Bun.write(join40(servicesDir, "DeleteTaskService.ts"), DeleteTaskService_default);
|
|
19181
|
+
const entityPath = join40(process.cwd(), base, "src", "entities", "TaskEntity.ts");
|
|
19070
19182
|
await Bun.write(entityPath, TaskEntity_default);
|
|
19071
|
-
const migrationsDir =
|
|
19183
|
+
const migrationsDir = join40(process.cwd(), base, "src", "migrations");
|
|
19072
19184
|
const glob = new Glob11("Migration*.ts");
|
|
19073
19185
|
for await (const file of glob.scan(migrationsDir)) {
|
|
19074
19186
|
if (file === "migrations.ts")
|
|
@@ -19076,18 +19188,18 @@ class MakeResourceTaskCommand {
|
|
|
19076
19188
|
const name = file.replace(/\.ts$/, "");
|
|
19077
19189
|
const version = name.replace("Migration", "");
|
|
19078
19190
|
const content = TaskMigration_default.replaceAll("{{ name }}", name).replaceAll("{{ version }}", version);
|
|
19079
|
-
await Bun.write(
|
|
19191
|
+
await Bun.write(join40(migrationsDir, file), content);
|
|
19080
19192
|
}
|
|
19081
|
-
const repositoryPath =
|
|
19193
|
+
const repositoryPath = join40(process.cwd(), base, "src", "repositories", "TaskRepository.ts");
|
|
19082
19194
|
await Bun.write(repositoryPath, TaskRepository_default);
|
|
19083
19195
|
}
|
|
19084
19196
|
}
|
|
19085
19197
|
MakeResourceTaskCommand = __legacyDecorateClassTS([
|
|
19086
|
-
|
|
19198
|
+
decorator40.command()
|
|
19087
19199
|
], MakeResourceTaskCommand);
|
|
19088
19200
|
// src/commands/MakeResourceTopicCommand.ts
|
|
19089
|
-
import { join as
|
|
19090
|
-
import { decorator as
|
|
19201
|
+
import { join as join41 } from "path";
|
|
19202
|
+
import { decorator as decorator41 } from "@ooneex/command";
|
|
19091
19203
|
var {Glob: Glob12 } = globalThis.Bun;
|
|
19092
19204
|
|
|
19093
19205
|
// src/templates/resources/topic/controllers/CreateTopicController.txt
|
|
@@ -19678,7 +19790,7 @@ class MakeResourceTopicCommand {
|
|
|
19678
19790
|
}
|
|
19679
19791
|
async run() {
|
|
19680
19792
|
const module = "topic";
|
|
19681
|
-
const base =
|
|
19793
|
+
const base = join41("modules", module);
|
|
19682
19794
|
const makeModuleCommand = new MakeModuleCommand;
|
|
19683
19795
|
await makeModuleCommand.run({ name: module, silent: true });
|
|
19684
19796
|
const makeEntityCommand = new MakeEntityCommand;
|
|
@@ -19713,26 +19825,26 @@ class MakeResourceTopicCommand {
|
|
|
19713
19825
|
for (const controller of controllers) {
|
|
19714
19826
|
await makeControllerCommand.run({ ...controller, module, isSocket: false });
|
|
19715
19827
|
}
|
|
19716
|
-
const controllersDir =
|
|
19717
|
-
await Bun.write(
|
|
19718
|
-
await Bun.write(
|
|
19719
|
-
await Bun.write(
|
|
19720
|
-
await Bun.write(
|
|
19721
|
-
await Bun.write(
|
|
19828
|
+
const controllersDir = join41(process.cwd(), base, "src", "controllers");
|
|
19829
|
+
await Bun.write(join41(controllersDir, "CreateTopicController.ts"), CreateTopicController_default);
|
|
19830
|
+
await Bun.write(join41(controllersDir, "GetTopicController.ts"), GetTopicController_default);
|
|
19831
|
+
await Bun.write(join41(controllersDir, "ListTopicsController.ts"), ListTopicsController_default);
|
|
19832
|
+
await Bun.write(join41(controllersDir, "UpdateTopicController.ts"), UpdateTopicController_default);
|
|
19833
|
+
await Bun.write(join41(controllersDir, "DeleteTopicController.ts"), DeleteTopicController_default);
|
|
19722
19834
|
const makeServiceCommand = new MakeServiceCommand;
|
|
19723
19835
|
const services = ["CreateTopic", "GetTopic", "ListTopics", "UpdateTopic", "DeleteTopic"];
|
|
19724
19836
|
for (const name of services) {
|
|
19725
19837
|
await makeServiceCommand.run({ name, module });
|
|
19726
19838
|
}
|
|
19727
|
-
const servicesDir =
|
|
19728
|
-
await Bun.write(
|
|
19729
|
-
await Bun.write(
|
|
19730
|
-
await Bun.write(
|
|
19731
|
-
await Bun.write(
|
|
19732
|
-
await Bun.write(
|
|
19733
|
-
const entityPath =
|
|
19839
|
+
const servicesDir = join41(process.cwd(), base, "src", "services");
|
|
19840
|
+
await Bun.write(join41(servicesDir, "CreateTopicService.ts"), CreateTopicService_default);
|
|
19841
|
+
await Bun.write(join41(servicesDir, "GetTopicService.ts"), GetTopicService_default);
|
|
19842
|
+
await Bun.write(join41(servicesDir, "ListTopicsService.ts"), ListTopicsService_default);
|
|
19843
|
+
await Bun.write(join41(servicesDir, "UpdateTopicService.ts"), UpdateTopicService_default);
|
|
19844
|
+
await Bun.write(join41(servicesDir, "DeleteTopicService.ts"), DeleteTopicService_default);
|
|
19845
|
+
const entityPath = join41(process.cwd(), base, "src", "entities", "TopicEntity.ts");
|
|
19734
19846
|
await Bun.write(entityPath, TopicEntity_default);
|
|
19735
|
-
const migrationsDir =
|
|
19847
|
+
const migrationsDir = join41(process.cwd(), base, "src", "migrations");
|
|
19736
19848
|
const glob = new Glob12("Migration*.ts");
|
|
19737
19849
|
for await (const file of glob.scan(migrationsDir)) {
|
|
19738
19850
|
if (file === "migrations.ts")
|
|
@@ -19740,18 +19852,18 @@ class MakeResourceTopicCommand {
|
|
|
19740
19852
|
const name = file.replace(/\.ts$/, "");
|
|
19741
19853
|
const version = name.replace("Migration", "");
|
|
19742
19854
|
const content = TopicMigration_default.replaceAll("{{ name }}", name).replaceAll("{{ version }}", version);
|
|
19743
|
-
await Bun.write(
|
|
19855
|
+
await Bun.write(join41(migrationsDir, file), content);
|
|
19744
19856
|
}
|
|
19745
|
-
const repositoryPath =
|
|
19857
|
+
const repositoryPath = join41(process.cwd(), base, "src", "repositories", "TopicRepository.ts");
|
|
19746
19858
|
await Bun.write(repositoryPath, TopicRepository_default);
|
|
19747
19859
|
}
|
|
19748
19860
|
}
|
|
19749
19861
|
MakeResourceTopicCommand = __legacyDecorateClassTS([
|
|
19750
|
-
|
|
19862
|
+
decorator41.command()
|
|
19751
19863
|
], MakeResourceTopicCommand);
|
|
19752
19864
|
// src/commands/MakeResourceUserCommand.ts
|
|
19753
|
-
import { join as
|
|
19754
|
-
import { decorator as
|
|
19865
|
+
import { join as join42 } from "path";
|
|
19866
|
+
import { decorator as decorator42 } from "@ooneex/command";
|
|
19755
19867
|
var {Glob: Glob13 } = globalThis.Bun;
|
|
19756
19868
|
|
|
19757
19869
|
// src/templates/resources/user/controllers/BanUserController.txt
|
|
@@ -20572,7 +20684,7 @@ class MakeResourceUserCommand {
|
|
|
20572
20684
|
}
|
|
20573
20685
|
async run() {
|
|
20574
20686
|
const module = "user";
|
|
20575
|
-
const base =
|
|
20687
|
+
const base = join42("modules", module);
|
|
20576
20688
|
const makeModuleCommand = new MakeModuleCommand;
|
|
20577
20689
|
await makeModuleCommand.run({ name: module, silent: true });
|
|
20578
20690
|
const makeEntityCommand = new MakeEntityCommand;
|
|
@@ -20623,14 +20735,14 @@ class MakeResourceUserCommand {
|
|
|
20623
20735
|
for (const controller of controllers) {
|
|
20624
20736
|
await makeControllerCommand.run({ ...controller, module, isSocket: false });
|
|
20625
20737
|
}
|
|
20626
|
-
const controllersDir =
|
|
20627
|
-
await Bun.write(
|
|
20628
|
-
await Bun.write(
|
|
20629
|
-
await Bun.write(
|
|
20630
|
-
await Bun.write(
|
|
20631
|
-
await Bun.write(
|
|
20632
|
-
await Bun.write(
|
|
20633
|
-
await Bun.write(
|
|
20738
|
+
const controllersDir = join42(process.cwd(), base, "src", "controllers");
|
|
20739
|
+
await Bun.write(join42(controllersDir, "BanUserController.ts"), BanUserController_default);
|
|
20740
|
+
await Bun.write(join42(controllersDir, "LockUserController.ts"), LockUserController_default);
|
|
20741
|
+
await Bun.write(join42(controllersDir, "SignOutController.ts"), SignOutController_default);
|
|
20742
|
+
await Bun.write(join42(controllersDir, "UpdateUserProfileController.ts"), UpdateUserProfileController_default);
|
|
20743
|
+
await Bun.write(join42(controllersDir, "UpdateUserProfileImageController.ts"), UpdateUserProfileImageController_default);
|
|
20744
|
+
await Bun.write(join42(controllersDir, "DeleteUserProfileImageController.ts"), DeleteUserProfileImageController_default);
|
|
20745
|
+
await Bun.write(join42(controllersDir, "UpdateUserRolesController.ts"), UpdateUserRolesController_default);
|
|
20634
20746
|
const makeServiceCommand = new MakeServiceCommand;
|
|
20635
20747
|
const services = [
|
|
20636
20748
|
"BanUser",
|
|
@@ -20644,17 +20756,17 @@ class MakeResourceUserCommand {
|
|
|
20644
20756
|
for (const name of services) {
|
|
20645
20757
|
await makeServiceCommand.run({ name, module });
|
|
20646
20758
|
}
|
|
20647
|
-
const servicesDir =
|
|
20648
|
-
await Bun.write(
|
|
20649
|
-
await Bun.write(
|
|
20650
|
-
await Bun.write(
|
|
20651
|
-
await Bun.write(
|
|
20652
|
-
await Bun.write(
|
|
20653
|
-
await Bun.write(
|
|
20654
|
-
await Bun.write(
|
|
20655
|
-
const entityPath =
|
|
20759
|
+
const servicesDir = join42(process.cwd(), base, "src", "services");
|
|
20760
|
+
await Bun.write(join42(servicesDir, "BanUserService.ts"), BanUserService_default);
|
|
20761
|
+
await Bun.write(join42(servicesDir, "LockUserService.ts"), LockUserService_default);
|
|
20762
|
+
await Bun.write(join42(servicesDir, "SignOutService.ts"), SignOutService_default);
|
|
20763
|
+
await Bun.write(join42(servicesDir, "UpdateUserProfileService.ts"), UpdateUserProfileService_default);
|
|
20764
|
+
await Bun.write(join42(servicesDir, "UpdateUserProfileImageService.ts"), UpdateUserProfileImageService_default);
|
|
20765
|
+
await Bun.write(join42(servicesDir, "DeleteUserProfileImageService.ts"), DeleteUserProfileImageService_default);
|
|
20766
|
+
await Bun.write(join42(servicesDir, "UpdateUserRolesService.ts"), UpdateUserRolesService_default);
|
|
20767
|
+
const entityPath = join42(process.cwd(), base, "src", "entities", "UserEntity.ts");
|
|
20656
20768
|
await Bun.write(entityPath, UserEntity_default);
|
|
20657
|
-
const migrationsDir =
|
|
20769
|
+
const migrationsDir = join42(process.cwd(), base, "src", "migrations");
|
|
20658
20770
|
const glob = new Glob13("Migration*.ts");
|
|
20659
20771
|
for await (const file of glob.scan(migrationsDir)) {
|
|
20660
20772
|
if (file === "migrations.ts")
|
|
@@ -20662,18 +20774,18 @@ class MakeResourceUserCommand {
|
|
|
20662
20774
|
const name = file.replace(/\.ts$/, "");
|
|
20663
20775
|
const version = name.replace("Migration", "");
|
|
20664
20776
|
const content = UserMigration_default.replaceAll("{{ name }}", name).replaceAll("{{ version }}", version);
|
|
20665
|
-
await Bun.write(
|
|
20777
|
+
await Bun.write(join42(migrationsDir, file), content);
|
|
20666
20778
|
}
|
|
20667
|
-
const repositoryPath =
|
|
20779
|
+
const repositoryPath = join42(process.cwd(), base, "src", "repositories", "UserRepository.ts");
|
|
20668
20780
|
await Bun.write(repositoryPath, UserRepository_default);
|
|
20669
20781
|
}
|
|
20670
20782
|
}
|
|
20671
20783
|
MakeResourceUserCommand = __legacyDecorateClassTS([
|
|
20672
|
-
|
|
20784
|
+
decorator42.command()
|
|
20673
20785
|
], MakeResourceUserCommand);
|
|
20674
20786
|
// src/commands/MakeResourceVideoCommand.ts
|
|
20675
|
-
import { join as
|
|
20676
|
-
import { decorator as
|
|
20787
|
+
import { join as join43 } from "path";
|
|
20788
|
+
import { decorator as decorator43 } from "@ooneex/command";
|
|
20677
20789
|
var {Glob: Glob14 } = globalThis.Bun;
|
|
20678
20790
|
|
|
20679
20791
|
// src/templates/resources/video/controllers/CreateVideoController.txt
|
|
@@ -21352,7 +21464,7 @@ class MakeResourceVideoCommand {
|
|
|
21352
21464
|
}
|
|
21353
21465
|
async run() {
|
|
21354
21466
|
const module = "video";
|
|
21355
|
-
const base =
|
|
21467
|
+
const base = join43("modules", module);
|
|
21356
21468
|
const makeModuleCommand = new MakeModuleCommand;
|
|
21357
21469
|
await makeModuleCommand.run({ name: module, silent: true });
|
|
21358
21470
|
const makeEntityCommand = new MakeEntityCommand;
|
|
@@ -21387,26 +21499,26 @@ class MakeResourceVideoCommand {
|
|
|
21387
21499
|
for (const controller of controllers) {
|
|
21388
21500
|
await makeControllerCommand.run({ ...controller, module, isSocket: false });
|
|
21389
21501
|
}
|
|
21390
|
-
const controllersDir =
|
|
21391
|
-
await Bun.write(
|
|
21392
|
-
await Bun.write(
|
|
21393
|
-
await Bun.write(
|
|
21394
|
-
await Bun.write(
|
|
21395
|
-
await Bun.write(
|
|
21502
|
+
const controllersDir = join43(process.cwd(), base, "src", "controllers");
|
|
21503
|
+
await Bun.write(join43(controllersDir, "CreateVideoController.ts"), CreateVideoController_default);
|
|
21504
|
+
await Bun.write(join43(controllersDir, "GetVideoController.ts"), GetVideoController_default);
|
|
21505
|
+
await Bun.write(join43(controllersDir, "ListVideosController.ts"), ListVideosController_default);
|
|
21506
|
+
await Bun.write(join43(controllersDir, "UpdateVideoController.ts"), UpdateVideoController_default);
|
|
21507
|
+
await Bun.write(join43(controllersDir, "DeleteVideoController.ts"), DeleteVideoController_default);
|
|
21396
21508
|
const makeServiceCommand = new MakeServiceCommand;
|
|
21397
21509
|
const services = ["CreateVideo", "GetVideo", "ListVideos", "UpdateVideo", "DeleteVideo"];
|
|
21398
21510
|
for (const name of services) {
|
|
21399
21511
|
await makeServiceCommand.run({ name, module });
|
|
21400
21512
|
}
|
|
21401
|
-
const servicesDir =
|
|
21402
|
-
await Bun.write(
|
|
21403
|
-
await Bun.write(
|
|
21404
|
-
await Bun.write(
|
|
21405
|
-
await Bun.write(
|
|
21406
|
-
await Bun.write(
|
|
21407
|
-
const entityPath =
|
|
21513
|
+
const servicesDir = join43(process.cwd(), base, "src", "services");
|
|
21514
|
+
await Bun.write(join43(servicesDir, "CreateVideoService.ts"), CreateVideoService_default);
|
|
21515
|
+
await Bun.write(join43(servicesDir, "GetVideoService.ts"), GetVideoService_default);
|
|
21516
|
+
await Bun.write(join43(servicesDir, "ListVideosService.ts"), ListVideosService_default);
|
|
21517
|
+
await Bun.write(join43(servicesDir, "UpdateVideoService.ts"), UpdateVideoService_default);
|
|
21518
|
+
await Bun.write(join43(servicesDir, "DeleteVideoService.ts"), DeleteVideoService_default);
|
|
21519
|
+
const entityPath = join43(process.cwd(), base, "src", "entities", "VideoEntity.ts");
|
|
21408
21520
|
await Bun.write(entityPath, VideoEntity_default);
|
|
21409
|
-
const migrationsDir =
|
|
21521
|
+
const migrationsDir = join43(process.cwd(), base, "src", "migrations");
|
|
21410
21522
|
const glob = new Glob14("Migration*.ts");
|
|
21411
21523
|
for await (const file of glob.scan(migrationsDir)) {
|
|
21412
21524
|
if (file === "migrations.ts")
|
|
@@ -21414,19 +21526,19 @@ class MakeResourceVideoCommand {
|
|
|
21414
21526
|
const name = file.replace(/\.ts$/, "");
|
|
21415
21527
|
const version = name.replace("Migration", "");
|
|
21416
21528
|
const content = VideoMigration_default.replaceAll("{{ name }}", name).replaceAll("{{ version }}", version);
|
|
21417
|
-
await Bun.write(
|
|
21529
|
+
await Bun.write(join43(migrationsDir, file), content);
|
|
21418
21530
|
}
|
|
21419
|
-
const repositoryPath =
|
|
21531
|
+
const repositoryPath = join43(process.cwd(), base, "src", "repositories", "VideoRepository.ts");
|
|
21420
21532
|
await Bun.write(repositoryPath, VideoRepository_default);
|
|
21421
21533
|
}
|
|
21422
21534
|
}
|
|
21423
21535
|
MakeResourceVideoCommand = __legacyDecorateClassTS([
|
|
21424
|
-
|
|
21536
|
+
decorator43.command()
|
|
21425
21537
|
], MakeResourceVideoCommand);
|
|
21426
21538
|
// src/commands/MakeStorageCommand.ts
|
|
21427
|
-
import { join as
|
|
21428
|
-
import { decorator as
|
|
21429
|
-
import { TerminalLogger as
|
|
21539
|
+
import { join as join44 } from "path";
|
|
21540
|
+
import { decorator as decorator44 } from "@ooneex/command";
|
|
21541
|
+
import { TerminalLogger as TerminalLogger29 } from "@ooneex/logger";
|
|
21430
21542
|
import { toPascalCase as toPascalCase16, toSnakeCase as toSnakeCase3 } from "@ooneex/utils";
|
|
21431
21543
|
|
|
21432
21544
|
// src/templates/storage.test.txt
|
|
@@ -21526,28 +21638,28 @@ class MakeStorageCommand {
|
|
|
21526
21638
|
if (module) {
|
|
21527
21639
|
await ensureModule(module);
|
|
21528
21640
|
}
|
|
21529
|
-
const base = module ?
|
|
21530
|
-
const storageLocalDir =
|
|
21531
|
-
const storageDir =
|
|
21532
|
-
const filePath =
|
|
21641
|
+
const base = module ? join44("modules", module) : ".";
|
|
21642
|
+
const storageLocalDir = join44(base, "src", "storage");
|
|
21643
|
+
const storageDir = join44(process.cwd(), storageLocalDir);
|
|
21644
|
+
const filePath = join44(storageDir, `${name}Storage.ts`);
|
|
21533
21645
|
await Bun.write(filePath, content);
|
|
21534
21646
|
const testContent = storage_test_default.replace(/{{NAME}}/g, name).replace(/{{MODULE}}/g, module ?? "");
|
|
21535
|
-
const testsLocalDir =
|
|
21536
|
-
const testsDir =
|
|
21537
|
-
const testFilePath =
|
|
21647
|
+
const testsLocalDir = join44(base, "tests", "storage");
|
|
21648
|
+
const testsDir = join44(process.cwd(), testsLocalDir);
|
|
21649
|
+
const testFilePath = join44(testsDir, `${name}Storage.spec.ts`);
|
|
21538
21650
|
await Bun.write(testFilePath, testContent);
|
|
21539
|
-
const logger = new
|
|
21540
|
-
logger.success(`${
|
|
21651
|
+
const logger = new TerminalLogger29;
|
|
21652
|
+
logger.success(`${join44(storageLocalDir, name)}Storage.ts created successfully`, undefined, {
|
|
21541
21653
|
showTimestamp: false,
|
|
21542
21654
|
showArrow: false,
|
|
21543
21655
|
useSymbol: true
|
|
21544
21656
|
});
|
|
21545
|
-
logger.success(`${
|
|
21657
|
+
logger.success(`${join44(testsLocalDir, name)}Storage.spec.ts created successfully`, undefined, {
|
|
21546
21658
|
showTimestamp: false,
|
|
21547
21659
|
showArrow: false,
|
|
21548
21660
|
useSymbol: true
|
|
21549
21661
|
});
|
|
21550
|
-
const packageJsonPath =
|
|
21662
|
+
const packageJsonPath = join44(process.cwd(), "package.json");
|
|
21551
21663
|
const packageJson = await Bun.file(packageJsonPath).json();
|
|
21552
21664
|
const deps = packageJson.dependencies ?? {};
|
|
21553
21665
|
const devDeps = packageJson.devDependencies ?? {};
|
|
@@ -21562,12 +21674,12 @@ class MakeStorageCommand {
|
|
|
21562
21674
|
}
|
|
21563
21675
|
}
|
|
21564
21676
|
MakeStorageCommand = __legacyDecorateClassTS([
|
|
21565
|
-
|
|
21677
|
+
decorator44.command()
|
|
21566
21678
|
], MakeStorageCommand);
|
|
21567
21679
|
// src/commands/MakeVectorDatabaseCommand.ts
|
|
21568
|
-
import { join as
|
|
21569
|
-
import { decorator as
|
|
21570
|
-
import { TerminalLogger as
|
|
21680
|
+
import { join as join45 } from "path";
|
|
21681
|
+
import { decorator as decorator45 } from "@ooneex/command";
|
|
21682
|
+
import { TerminalLogger as TerminalLogger30 } from "@ooneex/logger";
|
|
21571
21683
|
import { toPascalCase as toPascalCase17 } from "@ooneex/utils";
|
|
21572
21684
|
|
|
21573
21685
|
// src/templates/vector-database.test.txt
|
|
@@ -21641,28 +21753,28 @@ class MakeVectorDatabaseCommand {
|
|
|
21641
21753
|
if (module) {
|
|
21642
21754
|
await ensureModule(module);
|
|
21643
21755
|
}
|
|
21644
|
-
const base = module ?
|
|
21645
|
-
const vectorDatabaseLocalDir =
|
|
21646
|
-
const vectorDatabaseDir =
|
|
21647
|
-
const filePath =
|
|
21756
|
+
const base = module ? join45("modules", module) : ".";
|
|
21757
|
+
const vectorDatabaseLocalDir = join45(base, "src", "databases");
|
|
21758
|
+
const vectorDatabaseDir = join45(process.cwd(), vectorDatabaseLocalDir);
|
|
21759
|
+
const filePath = join45(vectorDatabaseDir, `${name}VectorDatabase.ts`);
|
|
21648
21760
|
await Bun.write(filePath, content);
|
|
21649
21761
|
const testContent = vector_database_test_default.replace(/{{NAME}}/g, name).replace(/{{MODULE}}/g, module ?? "");
|
|
21650
|
-
const testsLocalDir =
|
|
21651
|
-
const testsDir =
|
|
21652
|
-
const testFilePath =
|
|
21762
|
+
const testsLocalDir = join45(base, "tests", "databases");
|
|
21763
|
+
const testsDir = join45(process.cwd(), testsLocalDir);
|
|
21764
|
+
const testFilePath = join45(testsDir, `${name}VectorDatabase.spec.ts`);
|
|
21653
21765
|
await Bun.write(testFilePath, testContent);
|
|
21654
|
-
const logger = new
|
|
21655
|
-
logger.success(`${
|
|
21766
|
+
const logger = new TerminalLogger30;
|
|
21767
|
+
logger.success(`${join45(vectorDatabaseLocalDir, name)}VectorDatabase.ts created successfully`, undefined, {
|
|
21656
21768
|
showTimestamp: false,
|
|
21657
21769
|
showArrow: false,
|
|
21658
21770
|
useSymbol: true
|
|
21659
21771
|
});
|
|
21660
|
-
logger.success(`${
|
|
21772
|
+
logger.success(`${join45(testsLocalDir, name)}VectorDatabase.spec.ts created successfully`, undefined, {
|
|
21661
21773
|
showTimestamp: false,
|
|
21662
21774
|
showArrow: false,
|
|
21663
21775
|
useSymbol: true
|
|
21664
21776
|
});
|
|
21665
|
-
const packageJsonPath =
|
|
21777
|
+
const packageJsonPath = join45(process.cwd(), "package.json");
|
|
21666
21778
|
const packageJson = await Bun.file(packageJsonPath).json();
|
|
21667
21779
|
const deps = packageJson.dependencies ?? {};
|
|
21668
21780
|
const devDeps = packageJson.devDependencies ?? {};
|
|
@@ -21677,13 +21789,13 @@ class MakeVectorDatabaseCommand {
|
|
|
21677
21789
|
}
|
|
21678
21790
|
}
|
|
21679
21791
|
MakeVectorDatabaseCommand = __legacyDecorateClassTS([
|
|
21680
|
-
|
|
21792
|
+
decorator45.command()
|
|
21681
21793
|
], MakeVectorDatabaseCommand);
|
|
21682
21794
|
// src/commands/MigrationUpCommand.ts
|
|
21683
21795
|
import { existsSync as existsSync2 } from "fs";
|
|
21684
|
-
import { join as
|
|
21685
|
-
import { decorator as
|
|
21686
|
-
import { TerminalLogger as
|
|
21796
|
+
import { join as join46 } from "path";
|
|
21797
|
+
import { decorator as decorator46 } from "@ooneex/command";
|
|
21798
|
+
import { TerminalLogger as TerminalLogger31 } from "@ooneex/logger";
|
|
21687
21799
|
class MigrationUpCommand {
|
|
21688
21800
|
getName() {
|
|
21689
21801
|
return "migration:up";
|
|
@@ -21692,8 +21804,8 @@ class MigrationUpCommand {
|
|
|
21692
21804
|
return "Run migrations for all modules";
|
|
21693
21805
|
}
|
|
21694
21806
|
async run(options) {
|
|
21695
|
-
const logger = new
|
|
21696
|
-
const modulesDir =
|
|
21807
|
+
const logger = new TerminalLogger31;
|
|
21808
|
+
const modulesDir = join46(process.cwd(), "modules");
|
|
21697
21809
|
if (!existsSync2(modulesDir)) {
|
|
21698
21810
|
logger.warn("No modules with migrations found", undefined, {
|
|
21699
21811
|
showTimestamp: false,
|
|
@@ -21706,10 +21818,10 @@ class MigrationUpCommand {
|
|
|
21706
21818
|
const modules = [];
|
|
21707
21819
|
for await (const match of glob.scan({ cwd: modulesDir, onlyFiles: true })) {
|
|
21708
21820
|
const entry = match.replace("/package.json", "");
|
|
21709
|
-
const moduleDir =
|
|
21710
|
-
const migrationUpFile = Bun.file(
|
|
21821
|
+
const moduleDir = join46(modulesDir, entry);
|
|
21822
|
+
const migrationUpFile = Bun.file(join46(moduleDir, "bin", "migration", "up.ts"));
|
|
21711
21823
|
if (await migrationUpFile.exists()) {
|
|
21712
|
-
const packageJson = await Bun.file(
|
|
21824
|
+
const packageJson = await Bun.file(join46(modulesDir, match)).json();
|
|
21713
21825
|
modules.push({ name: packageJson.name ?? entry, dir: moduleDir });
|
|
21714
21826
|
}
|
|
21715
21827
|
}
|
|
@@ -21722,7 +21834,7 @@ class MigrationUpCommand {
|
|
|
21722
21834
|
return;
|
|
21723
21835
|
}
|
|
21724
21836
|
for (const { name, dir } of modules) {
|
|
21725
|
-
const migrationUpPath =
|
|
21837
|
+
const migrationUpPath = join46(dir, "bin", "migration", "up.ts");
|
|
21726
21838
|
logger.info(`Running migrations for ${name}...`, undefined, {
|
|
21727
21839
|
showTimestamp: false,
|
|
21728
21840
|
showArrow: false,
|
|
@@ -21755,13 +21867,13 @@ class MigrationUpCommand {
|
|
|
21755
21867
|
}
|
|
21756
21868
|
}
|
|
21757
21869
|
MigrationUpCommand = __legacyDecorateClassTS([
|
|
21758
|
-
|
|
21870
|
+
decorator46.command()
|
|
21759
21871
|
], MigrationUpCommand);
|
|
21760
21872
|
// src/commands/RemoveModuleCommand.ts
|
|
21761
21873
|
import { rmdir } from "fs/promises";
|
|
21762
|
-
import { join as
|
|
21763
|
-
import { decorator as
|
|
21764
|
-
import { TerminalLogger as
|
|
21874
|
+
import { join as join47 } from "path";
|
|
21875
|
+
import { decorator as decorator47 } from "@ooneex/command";
|
|
21876
|
+
import { TerminalLogger as TerminalLogger32 } from "@ooneex/logger";
|
|
21765
21877
|
import { toKebabCase as toKebabCase5, toPascalCase as toPascalCase18 } from "@ooneex/utils";
|
|
21766
21878
|
class RemoveModuleCommand {
|
|
21767
21879
|
getName() {
|
|
@@ -21832,7 +21944,7 @@ class RemoveModuleCommand {
|
|
|
21832
21944
|
const kebabName = toKebabCase5(pascalName);
|
|
21833
21945
|
if (kebabName === "app" || kebabName === "shared") {
|
|
21834
21946
|
if (!silent) {
|
|
21835
|
-
const logger = new
|
|
21947
|
+
const logger = new TerminalLogger32;
|
|
21836
21948
|
logger.error(`Cannot remove the "${kebabName}" module`, undefined, {
|
|
21837
21949
|
showTimestamp: false,
|
|
21838
21950
|
showArrow: false,
|
|
@@ -21841,11 +21953,11 @@ class RemoveModuleCommand {
|
|
|
21841
21953
|
}
|
|
21842
21954
|
return;
|
|
21843
21955
|
}
|
|
21844
|
-
const moduleDir =
|
|
21845
|
-
const moduleDirExists = await Bun.file(
|
|
21956
|
+
const moduleDir = join47(cwd, "modules", kebabName);
|
|
21957
|
+
const moduleDirExists = await Bun.file(join47(moduleDir, "package.json")).exists();
|
|
21846
21958
|
if (!moduleDirExists) {
|
|
21847
21959
|
if (!silent) {
|
|
21848
|
-
const logger = new
|
|
21960
|
+
const logger = new TerminalLogger32;
|
|
21849
21961
|
logger.error(`Module "${kebabName}" does not exist`, undefined, {
|
|
21850
21962
|
showTimestamp: false,
|
|
21851
21963
|
showArrow: false,
|
|
@@ -21862,17 +21974,17 @@ class RemoveModuleCommand {
|
|
|
21862
21974
|
if (!confirmed)
|
|
21863
21975
|
return;
|
|
21864
21976
|
}
|
|
21865
|
-
const appModulePath =
|
|
21977
|
+
const appModulePath = join47(cwd, "modules", "app", "src", "AppModule.ts");
|
|
21866
21978
|
await this.removeFromAppModule(appModulePath, pascalName, kebabName);
|
|
21867
|
-
const sharedModulePath =
|
|
21979
|
+
const sharedModulePath = join47(cwd, "modules", "shared", "src", "SharedModule.ts");
|
|
21868
21980
|
await this.removeFromSharedModule(sharedModulePath, pascalName, kebabName);
|
|
21869
|
-
const appTsconfigPath =
|
|
21981
|
+
const appTsconfigPath = join47(cwd, "tsconfig.json");
|
|
21870
21982
|
await this.removePathAlias(appTsconfigPath, kebabName);
|
|
21871
|
-
const commitlintPath =
|
|
21983
|
+
const commitlintPath = join47(cwd, ".commitlintrc.ts");
|
|
21872
21984
|
await this.removeModuleScope(commitlintPath, kebabName);
|
|
21873
21985
|
await rmdir(moduleDir, { recursive: true });
|
|
21874
21986
|
if (!silent) {
|
|
21875
|
-
const logger = new
|
|
21987
|
+
const logger = new TerminalLogger32;
|
|
21876
21988
|
logger.success(`modules/${kebabName} removed successfully`, undefined, {
|
|
21877
21989
|
showTimestamp: false,
|
|
21878
21990
|
showArrow: false,
|
|
@@ -21882,13 +21994,13 @@ class RemoveModuleCommand {
|
|
|
21882
21994
|
}
|
|
21883
21995
|
}
|
|
21884
21996
|
RemoveModuleCommand = __legacyDecorateClassTS([
|
|
21885
|
-
|
|
21997
|
+
decorator47.command()
|
|
21886
21998
|
], RemoveModuleCommand);
|
|
21887
21999
|
// src/commands/SeedRunCommand.ts
|
|
21888
22000
|
import { existsSync as existsSync3 } from "fs";
|
|
21889
|
-
import { join as
|
|
21890
|
-
import { decorator as
|
|
21891
|
-
import { TerminalLogger as
|
|
22001
|
+
import { join as join48 } from "path";
|
|
22002
|
+
import { decorator as decorator48 } from "@ooneex/command";
|
|
22003
|
+
import { TerminalLogger as TerminalLogger33 } from "@ooneex/logger";
|
|
21892
22004
|
class SeedRunCommand {
|
|
21893
22005
|
getName() {
|
|
21894
22006
|
return "seed:run";
|
|
@@ -21897,8 +22009,8 @@ class SeedRunCommand {
|
|
|
21897
22009
|
return "Run seeds for all modules";
|
|
21898
22010
|
}
|
|
21899
22011
|
async run(options) {
|
|
21900
|
-
const logger = new
|
|
21901
|
-
const modulesDir =
|
|
22012
|
+
const logger = new TerminalLogger33;
|
|
22013
|
+
const modulesDir = join48(process.cwd(), "modules");
|
|
21902
22014
|
if (!existsSync3(modulesDir)) {
|
|
21903
22015
|
logger.warn("No modules with seeds found", undefined, {
|
|
21904
22016
|
showTimestamp: false,
|
|
@@ -21911,10 +22023,10 @@ class SeedRunCommand {
|
|
|
21911
22023
|
const modules = [];
|
|
21912
22024
|
for await (const match of glob.scan({ cwd: modulesDir, onlyFiles: true })) {
|
|
21913
22025
|
const entry = match.replace("/package.json", "");
|
|
21914
|
-
const moduleDir =
|
|
21915
|
-
const seedRunFile = Bun.file(
|
|
22026
|
+
const moduleDir = join48(modulesDir, entry);
|
|
22027
|
+
const seedRunFile = Bun.file(join48(moduleDir, "bin", "seed", "run.ts"));
|
|
21916
22028
|
if (await seedRunFile.exists()) {
|
|
21917
|
-
const packageJson = await Bun.file(
|
|
22029
|
+
const packageJson = await Bun.file(join48(modulesDir, match)).json();
|
|
21918
22030
|
modules.push({ name: packageJson.name ?? entry, dir: moduleDir });
|
|
21919
22031
|
}
|
|
21920
22032
|
}
|
|
@@ -21927,7 +22039,7 @@ class SeedRunCommand {
|
|
|
21927
22039
|
return;
|
|
21928
22040
|
}
|
|
21929
22041
|
for (const { name, dir } of modules) {
|
|
21930
|
-
const seedRunPath =
|
|
22042
|
+
const seedRunPath = join48(dir, "bin", "seed", "run.ts");
|
|
21931
22043
|
logger.info(`Running seeds for ${name}...`, undefined, {
|
|
21932
22044
|
showTimestamp: false,
|
|
21933
22045
|
showArrow: false,
|
|
@@ -21960,9 +22072,9 @@ class SeedRunCommand {
|
|
|
21960
22072
|
}
|
|
21961
22073
|
}
|
|
21962
22074
|
SeedRunCommand = __legacyDecorateClassTS([
|
|
21963
|
-
|
|
22075
|
+
decorator48.command()
|
|
21964
22076
|
], SeedRunCommand);
|
|
21965
22077
|
// src/index.ts
|
|
21966
22078
|
await run();
|
|
21967
22079
|
|
|
21968
|
-
//# debugId=
|
|
22080
|
+
//# debugId=FFFA0F9ADF05768464756E2164756E21
|