{"id":19528936,"url":"https://github.com/adonisjs/assembler","last_synced_at":"2026-01-12T14:32:26.740Z","repository":{"id":36311987,"uuid":"222406930","full_name":"adonisjs/assembler","owner":"adonisjs","description":"A development toolkit used by AdonisJS to perform tasks like starting the dev server in watch mode, running tests in watch mode, and applying codemods to modify source files","archived":false,"fork":false,"pushed_at":"2025-12-31T12:59:16.000Z","size":1388,"stargazers_count":38,"open_issues_count":0,"forks_count":20,"subscribers_count":3,"default_branch":"8.x","last_synced_at":"2026-01-04T18:58:54.651Z","etag":null,"topics":["dev-tools"],"latest_commit_sha":null,"homepage":"https://adonisjs.com","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adonisjs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"thetutlage"}},"created_at":"2019-11-18T09:09:17.000Z","updated_at":"2025-12-31T12:46:21.000Z","dependencies_parsed_at":"2025-12-08T18:07:24.780Z","dependency_job_id":null,"html_url":"https://github.com/adonisjs/assembler","commit_stats":{"total_commits":566,"total_committers":19,"mean_commits":"29.789473684210527","dds":"0.17844522968197885","last_synced_commit":"decb8060f72207c47eeb9c244093700fdd353485"},"previous_names":[],"tags_count":171,"template":false,"template_full_name":null,"purl":"pkg:github/adonisjs/assembler","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adonisjs%2Fassembler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adonisjs%2Fassembler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adonisjs%2Fassembler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adonisjs%2Fassembler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adonisjs","download_url":"https://codeload.github.com/adonisjs/assembler/tar.gz/refs/heads/8.x","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adonisjs%2Fassembler/sbom","scorecard":{"id":167465,"data":{"date":"2025-08-11","repo":{"name":"github.com/adonisjs/assembler","commit":"decb8060f72207c47eeb9c244093700fdd353485"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.1,"checks":[{"name":"Code-Review","score":0,"reason":"Found 2/28 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: third-party GitHubAction not pinned by hash: .github/workflows/checks.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/adonisjs/assembler/checks.yml/7.x?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/checks.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/adonisjs/assembler/checks.yml/7.x?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/checks.yml:9: update your workflow using https://app.stepsecurity.io/secureworkflow/adonisjs/assembler/checks.yml/7.x?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/adonisjs/assembler/release.yml/7.x?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/adonisjs/assembler/release.yml/7.x?enable=pin","Warn: npmCommand not pinned by hash: .github/workflows/release.yml:28","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   3 third-party GitHubAction dependencies pinned","Info:   0 out of   1 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/checks.yml:1","Warn: topLevel 'contents' permission set to 'write': .github/workflows/release.yml:4","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.md:0","Info: FSF or OSI recognized license: MIT License: LICENSE.md:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: github.com/adonisjs/.github/docs/SECURITY.md:1","Info: Found linked content: github.com/adonisjs/.github/docs/SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: github.com/adonisjs/.github/docs/SECURITY.md:1","Info: Found text in security policy: github.com/adonisjs/.github/docs/SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 5 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch '7.x'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-16T15:18:46.774Z","repository_id":36311987,"created_at":"2025-08-16T15:18:46.774Z","updated_at":"2025-08-16T15:18:46.774Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28340400,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T12:22:26.515Z","status":"ssl_error","status_checked_at":"2026-01-12T12:22:10.856Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dev-tools"],"created_at":"2024-11-11T01:20:58.406Z","updated_at":"2026-01-12T14:32:26.726Z","avatar_url":"https://github.com/adonisjs.png","language":"TypeScript","funding_links":["https://github.com/sponsors/thetutlage"],"categories":[],"sub_categories":[],"readme":"# @adonisjs/assembler\n\n\u003cbr /\u003e\n\n[![gh-workflow-image]][gh-workflow-url] [![npm-image]][npm-url] ![][typescript-image] [![license-image]][license-url]\n\n## Introduction\nAdonisJS Assembler is a development toolkit used by AdonisJS to perform tasks like **starting the dev server in watch mode**, **running tests in watch mode**, and **applying codemods** to modify source files.\n\nAssembler should always be installed as a development dependency. If your project needs Assembler APIs in production, you must reconsider your approach.\n\n## Goals\nAssembler is built around the following goals.\n\n- Expose a coding interface and not a user interface. In other words, Assembler will never expose any CLI commands.\n- Encapsulate tasks under a single API. Instead of providing ten different utilities to run a dev server, Assembler will expose one API to run the dev server.\n- House all development APIs needed by AdonisJS. Therefore, the scope of the Assembler might increase over time.\n\n## Dev server\nThe development server can be started using the `DevServer` class. It will run `bin/server.ts` file from the AdonisJS project as a child process and monitor it for changes (in both HMR and watcher modes).\n\nEvery time there is a file change, the `DevServer` will execute the file watcher hooks and if needed will restart the development server.\n\nYou may import and use the `DevServer` as follows.\n\n```ts\nimport ts from 'typescript'\nimport { DevServer } from '@adonisjs/assembler'\n\nconst appRoot = new URL('./', import.meta.url)\n\nconst devServer = new DevServer(appRoot, {\n  /**\n   * Arguments to pass to the \"bin/server.ts\" file\n   */\n  scriptArgs: [],\n\n  /**\n   * Arguments to pass to the Node.js CLI\n   */\n  nodeArgs: [],\n\n  /**\n   * An array of metaFiles to watch and re-start the\n   * HTTP server only if the \"reloadServer\" flag is\n   * true.\n   */\n  metaFiles: [\n    {\n      pattern: 'resources/views/**/*.edge',\n      reloadServer: false,\n    }\n  ]\n})\n\ndevServer.onError((error) =\u003e {\n  process.exitCode = 1\n})\ndevServer.onClose((exitCode) =\u003e {\n  process.exitCode = exitCode\n})\n\nawait devServer.runAndWatch(ts)\n```\n\nYou may start the dev server in HMR mode by setting `hmr: true` and calling the `start` method.\n\n```ts\nconst devServer = new DevServer(appRoot, {\n  hmr: true,\n  // ...rest of the config\n})\n\nawait devServer.start()\n```\n\n## Test runner\nThe `TestRunner` is used to execute the `bin/test.ts` file of your AdonisJS application. Like the `DevServer`, the `TestRunner` allows you to watch for file changes and re-run the tests. The following steps are taken to re-run tests in watch mode.\n\n- If the changed file is a test file, only tests for that file will be re-run.\n- Otherwise, all tests will re-run with respect to the initial filters applied when running the `node ace test` command.\n\n### Usage\n\nYou may import and use the `TestRunner` as follows.\n\n```ts\nimport ts from 'typescript'\nimport { TestRunner } from '@adonisjs/assembler'\n\nconst appRoot = new URL('./', import.meta.url)\n\nconst runner = new TestRunner(appRoot, {\n  /**\n   * Arguments to pass to the \"bin/test.ts\" file\n   */\n  scriptArgs: [],\n\n  /**\n   * Arguments to pass to the Node.js CLI\n   */\n  nodeArgs: [],\n\n  /**\n   * An array of suites and their glob patterns\n   */\n  suites: [\n    {\n      name: 'unit',\n      files: ['tests/unit/**/*.spec.ts']\n    },\n    {\n      name: 'functional',\n      files: ['tests/functional/**/*.spec.ts']\n    }\n  ],\n\n  /**\n   * Initial set of filters to apply. These filters\n   * will be re-applied when re-running tests in\n   * watch mode\n   */\n  filters: {\n    suites: ['unit'],\n    tags: ['@slow']\n  }\n})\n\nawait runner.runAndWatch(ts)\n```\n\nYou can run tests without the watcher using the `run` method.\n\n```ts\nawait runner.run()\n```\n\n## Bundler\nThe `Bundler` is used to create the production build of an AdonisJS application. The following steps are performed to generate the build.\n\n- Clean up the existing build directory.\n- Create JavaScript build using `tsc` (The TypeScript's official compiler).\n- Copy the `ace.js` file to the build folder. Since the ace file ends with the `.js` extension, it is not compiled by the TypeScript compiler.\n- Copy `package.json` and the **lock-file of the package manager** you are using to the `build` folder. This operation only supports `bun | npm | yarn | pnpm`. For other bundlers, you will have to copy the lock file manually.\n- The end.\n\n### Usage\nYou may import and use the `Bundler` as follows.\n\n```ts\nimport ts from 'typescript'\nimport { Bundler } from '@adonisjs/assembler'\n\nconst appRoot = new URL('./', import.meta.url)\n\nconst bundler = new Bundler(appRoot, ts, {\n  /**\n   * Metafiles to copy to the build folder\n   */\n  metaFiles: [\n    {\n      pattern: 'resources/views/**/*.edge',\n      reloadServer: false,\n    }\n  ],\n})\n```\n\n## Codemods\nAssembler also exports certain codemods to modify the source files of an AdonisJS project to configure packages.\n\nThe codemods relies on the defaults of AdonisJS and will not work if a project does not follow the defaults. This is an intentional limit since we only have limited time to craft codemods that work with every possible setup.\n\n### Usage\nYou may import and use the `Codemods` as follows.\n\n```ts\nimport { CodeTransformer } from '@adonisjs/assembler/code_transformer'\n\nconst appRoot = new URL('./', import.meta.url)\n\nconst transformer = new CodeTransformer(appRoot)\n```\n\n### defineEnvValidations\nDefine validation rules for environment variables. The method accepts a key-value pair of variables. The `key` is the env variable name, and the `value` is the validation expression as a string.\n\n\u003e [!IMPORTANT]\n\u003e This codemod expects the `start/env.ts` file to exist and must have the `export default await Env.create` method call.\n\u003e\n\u003e Also, the codemod does not overwrite the existing validation rule for a given environment variable. This is done to respect in-app modifications.\n\n```ts\nconst transformer = new CodeTransformer(appRoot)\n\ntry {\n  await transformer.defineEnvValidations({\n    leadingComment: 'App environment variables',\n    variables: {\n      PORT: 'Env.schema.number()',\n      HOST: 'Env.schema.string()',\n    }\n  })\n} catch (error) {\n  console.error('Unable to define env validations')\n  console.error(error)\n}\n```\n\nOutput\n\n```ts\nimport { Env } from '@adonisjs/core/env'\n\nexport default await Env.create(new URL('../', import.meta.url), {\n  PORT: Env.schema.number(),\n  HOST: Env.schema.string(),\n})\n```\n\n### addMiddlewareToStack\nRegister AdonisJS middleware to one of the known middleware stacks. The method accepts the middleware stack and an array of middleware to register.\n\nThe middleware stack could be one of `server | router | named`.\n\n\u003e [!IMPORTANT]\n\u003e This codemod expects the `start/kernel.ts` file to exist and must have a function call for the middleware stack for which you are trying to register a middleware.\n\n```ts\nconst transformer = new CodeTransformer(appRoot)\n\ntry {\n  await transformer.addMiddlewareToStack('router', [\n    {\n      path: '@adonisjs/core/bodyparser_middleware'\n    }\n  ])\n} catch (error) {\n  console.error('Unable to register middleware')\n  console.error(error)\n}\n```\n\nOutput\n\n```ts\nimport router from '@adonisjs/core/services/router'\n\nrouter.use([\n  () =\u003e import('@adonisjs/core/bodyparser_middleware')\n])\n```\n\nYou may define named middleware as follows.\n\n```ts\nconst transformer = new CodeTransformer(appRoot)\n\ntry {\n  await transformer.addMiddlewareToStack('named', [\n    {\n      name: 'auth',\n      path: '@adonisjs/auth/auth_middleware'\n    }\n  ])\n} catch (error) {\n  console.error('Unable to register middleware')\n  console.error(error)\n}\n```\n\n### updateRcFile\nRegister `providers`, `commands`, define `metaFiles` and `commandAliases` to the `adonisrc.ts` file.\n\n\u003e [!IMPORTANT]\n\u003e This codemod expects the `adonisrc.ts` file to exist and must have an `export default defineConfig` function call.\n\n```ts\nconst transformer = new CodeTransformer(appRoot)\n\ntry {\n  await transformer.updateRcFile((rcFile) =\u003e {\n    rcFile\n      .addProvider('@adonisjs/lucid/db_provider')\n      .addCommand('@adonisjs/lucid/commands'),\n      .setCommandAlias('migrate', 'migration:run')\n  })\n} catch (error) {\n  console.error('Unable to update adonisrc.ts file')\n  console.error(error)  \n}\n```\n\nOutput\n\n```ts\nimport { defineConfig } from '@adonisjs/core/app'\n\nexport default defineConfig({\n  commands: [\n    () =\u003e import('@adonisjs/lucid/commands')\n  ],\n  providers: [\n    () =\u003e import('@adonisjs/lucid/db_provider')\n  ],\n  commandAliases: {\n    migrate: 'migration:run'\n  }\n})\n```\n\n### addJapaPlugin\nRegister a Japa plugin to the `tests/bootstrap.ts` file.\n\n\u003e [!IMPORTANT]\n\u003e This codemod expects the `tests/bootstrap.ts` file to exist and must have the `export const plugins: Config['plugins']` export.\n\n```ts\nconst transformer = new CodeTransformer(appRoot)\n\nconst imports = [\n  {\n    isNamed: false,\n    module: '@adonisjs/core/services/app',\n    identifier: 'app'\n  },\n  {\n    isNamed: true,\n    module: '@adonisjs/session/plugins/api_client',\n    identifier: 'sessionApiClient'\n  }\n]\nconst pluginUsage = 'sessionApiClient(app)'\n\ntry {\n  await transformer.addJapaPlugin(pluginUsage, imports)\n} catch (error) {\n  console.error('Unable to register japa plugin')\n  console.error(error)\n}\n```\n\nOutput\n\n```ts\nimport app from '@adonisjs/core/services/app'\nimport { sessionApiClient } from '@adonisjs/session/plugins/api_client'\n\nexport const plugins: Config['plugins'] = [\n  sessionApiClient(app)\n]\n```\n\n### addVitePlugin\n\nRegister a Vite plugin to the `vite.config.ts` file.\n\n\u003e [!IMPORTANT]\n\u003e This codemod expects the `vite.config.ts` file to exist and must have the `export default defineConfig` function call.\n\n```ts\nconst transformer = new CodeTransformer(appRoot)\nconst imports = [\n  {\n    isNamed: false,\n    module: '@vitejs/plugin-vue',\n    identifier: 'vue'\n  },\n]\nconst pluginUsage = 'vue({ jsx: true })'\n\ntry {\n  await transformer.addVitePlugin(pluginUsage, imports)\n} catch (error) {\n  console.error('Unable to register vite plugin')\n  console.error(error)\n}\n```\n\nOutput\n\n```ts\nimport { defineConfig } from 'vite'\nimport vue from '@vitejs/plugin-vue'\n\nexport default defineConfig({\n  plugins: [\n    vue({ jsx: true })\n  ]\n})\n```\n\n### addPolicies\nRegister AdonisJS bouncer policies to the list of `policies` object exported from the `app/policies/main.ts` file.\n\n\u003e [!IMPORTANT]\n\u003e This codemod expects the `app/policies/main.ts` file to exist and must export a `policies` object from it.\n\n```ts\nconst transformer = new CodeTransformer(appRoot)\n\ntry {\n  await transformer.addPolicies([\n    {\n      name: 'PostPolicy',\n      path: '#policies/post_policy'\n    }\n  ])\n} catch (error) {\n  console.error('Unable to register policy')\n  console.error(error)\n}\n```\n\nOutput\n\n```ts\nexport const policies = {\n  UserPolicy: () =\u003e import('#policies/post_policy')\n}\n```\n\n## Index generator\n\nThe `IndexGenerator` is a core concept in Assembler that is used to watch the filesystem and create barrel files or types from a source directory.\n\nFor example, the core of the framework uses the following config to generate controllers, events, and listeners barrel file.\n\n```ts\nimport hooks from '@adonisjs/assembler/hooks'\n\nexport default hooks.init((type, parent, indexGenerator) =\u003e {\n  indexGenerator.add('controllers', {\n    source: './app/controllers',\n    importAlias: '#controllers',\n    as: 'barrelFile',\n    exportName: 'controllers',\n    removeSuffix: 'controllers',\n    output: './.adonisjs/server/controllers.ts',\n  })\n\n  indexGenerator.add('events', {\n    source: './app/events',\n    importAlias: '#events',\n    as: 'barrelFile',\n    exportName: 'events',\n    output: './.adonisjs/server/events.ts',\n  })\n\n  indexGenerator.add('listeners', {\n    source: './app/listeners',\n    importAlias: '#listeners',\n    as: 'barrelFile',\n    exportName: 'listeners',\n    removeSuffix: 'listener',\n    output: './.adonisjs/server/listeners.ts',\n  })\n})\n```\n\nOnce the configurations have been registered with the `IndexGenerator`, it will scan the needed directories and generate the output files. Additionally, the file watchers will re-trigger the index generation when a file is added or removed from the source directory.\n\n### Barrel file generation\n\nBarrel files provide a single entry point by exporting a collection of lazily imported entities, recursively gathered from a source directory. The `IndexGenerator` automates this process by scanning nested directories and generating import mappings that mirror the file structure.\n\nFor example, given the following `controllers` directory structure:\n\n```sh\napp/controllers/\n├── auth/\n│   ├── login_controller.ts\n│   └── register_controller.ts\n├── blog/\n│   ├── posts_controller.ts\n│   └── post_comments_controller.ts\n└── users_controller.ts\n```\n\nWhen processed with the controllers configuration, the `IndexGenerator` produces a barrel file that reflects the directory hierarchy as nested objects, using capitalized file names as property keys.\n\n```ts\nexport const controllers = {\n  auth: {\n    Login: () =\u003e import('#controllers/auth/login_controller'),\n    Register: () =\u003e import('#controllers/auth/register_controller'),\n  },\n  blog: {\n    Posts: () =\u003e import('#controllers/blog/posts_controller'),\n    PostComments: () =\u003e import('#controllers/blog/post_comments_controller'),\n  },\n  Users: () =\u003e import('#controllers/users_controller'),\n}\n```\n\n### Types generation\n\nTo generate a types file, register a custom callback that takes an instance of the `VirtualFileSystem` and updates the output string via the `buffer` object. \n\nThe collection is represented as key–value pairs:\n\n- **Key** — the relative path (without extension) from the root of the source directory.\n- **Value** — an object containing the file's `importPath`, `relativePath`, and `absolutePath`.\n\n```ts\nimport hooks from '@adonisjs/assembler/hooks'\n\nexport default hooks.init((type, parent, indexGenerator) =\u003e {\n  indexGenerator.add('inertiaPages', {\n    source: './inertia/pages',\n    as: (vfs, buffer) =\u003e {\n      buffer.write(`declare module '@adonisjs/inertia' {`).indent()\n      buffer.write(`export interface Pages {`).indent()\n\n      const files = vfs.asList()\n      Object.keys(files).forEach((filePath) =\u003e {\n        buffer.write(\n          `'${filePath}': InferPageProps\u003ctypeof import('${file.importPath}').default\u003e`\n        )\n      })\n\n      buffer.dedent().write('}')\n      buffer.dedent().write('}')\n    },\n    output: './.adonisjs/server/inertia_pages.d.ts',\n  })\n})\n```\n\n## Contributing\nOne of the primary goals of AdonisJS is to have a vibrant community of users and contributors who believe in the framework's principles.\n\nWe encourage you to read the [contribution guide](https://github.com/adonisjs/.github/blob/main/docs/CONTRIBUTING.md) before contributing to the framework.\n\n## Code of Conduct\nTo ensure that the AdonisJS community is welcoming to all, please review and abide by the [Code of Conduct](https://github.com/adonisjs/.github/blob/main/docs/CODE_OF_CONDUCT.md).\n\n## License\nAdonisJS Assembler is open-sourced software licensed under the [MIT license](LICENSE.md).\n\n[gh-workflow-image]: https://img.shields.io/github/actions/workflow/status/adonisjs/assembler/checks.yml?style=for-the-badge\n[gh-workflow-url]: https://github.com/adonisjs/assembler/actions/workflows/checks.yml \"Github action\"\n\n[npm-image]: https://img.shields.io/npm/v/@adonisjs/assembler/latest.svg?style=for-the-badge\u0026logo=npm\n[npm-url]: https://npmjs.org/package/@adonisjs/assembler/v/latest \"npm\"\n\n[typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge\u0026logo=typescript\n\n[license-url]: LICENSE.md\n[license-image]: https://img.shields.io/github/license/adonisjs/ace?style=for-the-badge\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadonisjs%2Fassembler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadonisjs%2Fassembler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadonisjs%2Fassembler/lists"}