From 1549ebf20de166f29dc53b7d865cc9e698ad6753 Mon Sep 17 00:00:00 2001 From: Julien Ripouteau Date: Wed, 10 Dec 2025 20:03:28 +0100 Subject: [PATCH] feat: add skipSegments option + default values for indexers --- package.json | 2 +- src/assembler_hooks/index_entities.ts | 27 ++++++- src/types.ts | 8 ++ tests/index_generator.spec.ts | 105 ++++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 956348f9..440c570f 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "index:commands": "node --import=@poppinss/ts-exec toolkit/main.js index build/commands" }, "devDependencies": { - "@adonisjs/assembler": "^8.0.0-next.19", + "@adonisjs/assembler": "^8.0.0-next.21", "@adonisjs/eslint-config": "^3.0.0-next.4", "@adonisjs/prettier-config": "^1.4.5", "@adonisjs/tsconfig": "^2.0.0-next.3", diff --git a/src/assembler_hooks/index_entities.ts b/src/assembler_hooks/index_entities.ts index f111c4cb..73e42059 100644 --- a/src/assembler_hooks/index_entities.ts +++ b/src/assembler_hooks/index_entities.ts @@ -47,15 +47,25 @@ import { outputTransformerDataObjects } from '../utils.ts' */ export function indexEntities(entities: IndexEntitiesConfig = {}) { const events = Object.assign( - { enabled: true, source: 'app/events', importAlias: '#events' }, + { enabled: true, source: 'app/events', importAlias: '#events', skipSegments: ['events'] }, entities.events ) const listeners = Object.assign( - { enabled: true, source: 'app/listeners', importAlias: '#listeners' }, + { + enabled: true, + source: 'app/listeners', + importAlias: '#listeners', + skipSegments: ['listeners'], + }, entities.listeners ) const controllers = Object.assign( - { enabled: true, source: 'app/controllers', importAlias: '#controllers' }, + { + enabled: true, + source: 'app/controllers', + importAlias: '#controllers', + skipSegments: ['controllers'], + }, entities.controllers ) const transformers = Object.assign( @@ -64,6 +74,7 @@ export function indexEntities(entities: IndexEntitiesConfig = {}) { source: 'app/transformers', importAlias: '#transformers', withSharedProps: false, + skipSegments: ['transformers'], }, entities.transformers ) @@ -78,6 +89,7 @@ export function indexEntities(entities: IndexEntitiesConfig = {}) { as: 'barrelFile', exportName: 'events', importAlias: events.importAlias, + skipSegments: events.skipSegments, output: '.adonisjs/server/events.ts', }) } @@ -89,6 +101,7 @@ export function indexEntities(entities: IndexEntitiesConfig = {}) { as: 'barrelFile', exportName: 'listeners', importAlias: listeners.importAlias, + skipSegments: listeners.skipSegments, output: '.adonisjs/server/listeners.ts', }) } @@ -100,6 +113,7 @@ export function indexEntities(entities: IndexEntitiesConfig = {}) { as: 'barrelFile', exportName: 'controllers', importAlias: controllers.importAlias, + skipSegments: controllers.skipSegments, removeSuffix: 'controller', output: '.adonisjs/server/controllers.ts', }) @@ -112,8 +126,13 @@ export function indexEntities(entities: IndexEntitiesConfig = {}) { as(vfs, buffer, __, helpers) { const transformersList = vfs.asTree({ transformKey(key) { - const segments = key.split('/') + let segments = key.split('/') const baseName = segments.pop()! + + if (transformers.skipSegments?.length) { + segments = segments.filter((s) => !transformers.skipSegments!.includes(s)) + } + return [ ...segments.map((segment) => stringHelpers.pascalCase(segment)), stringHelpers.create(baseName).removeSuffix('transformer').pascalCase(), diff --git a/src/types.ts b/src/types.ts index ddb3e57f..d31e07ed 100644 --- a/src/types.ts +++ b/src/types.ts @@ -380,6 +380,8 @@ export type IndexEntitiesConfig = { importAlias?: string /** Glob patterns for matching controller files */ glob?: string[] + /** Path segments to skip from generated keys. Defaults to ['controllers'] */ + skipSegments?: string[] } /** Configuration for listeners indexing */ listeners?: { @@ -391,6 +393,8 @@ export type IndexEntitiesConfig = { importAlias?: string /** Glob patterns for matching listener files */ glob?: string[] + /** Path segments to skip from generated keys. Defaults to ['listeners'] */ + skipSegments?: string[] } /** Configuration for events indexing */ events?: { @@ -402,6 +406,8 @@ export type IndexEntitiesConfig = { importAlias?: string /** Glob patterns for matching event files */ glob?: string[] + /** Path segments to skip from generated keys. Defaults to ['events'] */ + skipSegments?: string[] } transformers?: { enabled?: boolean @@ -409,5 +415,7 @@ export type IndexEntitiesConfig = { source?: string importAlias?: string glob?: string[] + /** Path segments to skip from generated keys. Defaults to ['transformers'] */ + skipSegments?: string[] } } diff --git a/tests/index_generator.spec.ts b/tests/index_generator.spec.ts index 3aaef65e..ae4237a2 100644 --- a/tests/index_generator.spec.ts +++ b/tests/index_generator.spec.ts @@ -291,4 +291,109 @@ test.group('Index generator', () => { " `) }) + + test('skip segments from controllers index with module-based folder structure', async ({ + assert, + fs, + }) => { + const cliUi = Kernel.create().ui + cliUi.switchMode('raw') + + await fs.create('app/identity/controllers/auth_controller.ts', '') + await fs.create('app/identity/controllers/users_controller.ts', '') + await fs.create('app/billing/controllers/invoices_controller.ts', '') + + const generator = new IndexGenerator(stringHelpers.toUnixSlash(fs.basePath), cliUi.logger) + const indexer = indexEntities({ + controllers: { + enabled: true, + source: 'app', + glob: ['**/controllers/*_controller.ts'], + importAlias: '#app', + }, + events: { + enabled: false, + }, + listeners: { + enabled: false, + }, + transformers: { + enabled: false, + }, + }) + + indexer.run({} as any, generator) + await generator.generate() + + await assert.fileExists('.adonisjs/server/controllers.ts') + assert.snapshot(await fs.contents('.adonisjs/server/controllers.ts')).matchInline(` + "export const controllers = { + billing: { + Invoices: () => import('#app/billing/controllers/invoices_controller'), + }, + identity: { + Auth: () => import('#app/identity/controllers/auth_controller'), + Users: () => import('#app/identity/controllers/users_controller'), + }, + } + " + `) + await assert.fileNotContains('.adonisjs/server/controllers.ts', [`controllers: {`]) + }) + + test('skip segments from transformers index with module-based folder structure', async ({ + assert, + fs, + }) => { + const cliUi = Kernel.create().ui + cliUi.switchMode('raw') + + await fs.create('app/identity/transformers/user_transformer.ts', '') + await fs.create('app/billing/transformers/invoice_transformer.ts', '') + + const generator = new IndexGenerator(stringHelpers.toUnixSlash(fs.basePath), cliUi.logger) + const indexer = indexEntities({ + controllers: { + enabled: false, + }, + events: { + enabled: false, + }, + listeners: { + enabled: false, + }, + transformers: { + enabled: true, + source: 'app', + glob: ['**/transformers/*_transformer.ts'], + importAlias: '#app', + }, + }) + + indexer.run({} as any, generator) + await generator.generate() + + await assert.fileExists('.adonisjs/client/data.d.ts') + assert.snapshot(await fs.contents('.adonisjs/client/data.d.ts')).matchInline(` + "import type { InferData, InferVariants } from '@adonisjs/core/types/transformers' + import type BillingInvoiceTransformer from '#app/billing/transformers/invoice_transformer' + import type IdentityUserTransformer from '#app/identity/transformers/user_transformer' + + export namespace Data { + export namespace Billing { + export type Invoice = InferData + export namespace Invoice { + export type Variants = InferVariants + } + } + export namespace Identity { + export type User = InferData + export namespace User { + export type Variants = InferVariants + } + } + } + " + `) + }) })