{"owner":"jhipster","repo":"generator-jhipster","hasSkills":true,"totalSkillsCount":4,"totalTokensCount":6152,"categories":["claude-rule","copilot-instructions","root-instruction","project-spec"],"hasMcp":false,"mcpConfig":null,"found":["CLAUDE.md",".github/copilot-instructions.md","AGENTS.md","ARCHITECTURE.md"],"skills":{"CLAUDE.md":"See [`AGENTS.md`](./AGENTS.md) at the repository root for the canonical AI agent instructions for this codebase.\n",".github/copilot-instructions.md":"See [`AGENTS.md`](../AGENTS.md) at the repository root for the canonical AI agent instructions for this codebase.\n","AGENTS.md":"# AI agent instructions for generator-jhipster\n\nJHipster is a Yeoman-based code generator (TypeScript, ESM, Node — see `engines` in `package.json` for the required version) that scaffolds Spring Boot + Angular/React/Vue applications. See `ARCHITECTURE.md`, `BLUEPRINTS.md`, `DEVELOPMENT.md`, and `JDL.md` (the reference of the JDL language) for background context.\n\n**Trust order when docs disagree:** `package.json` scripts and the current source tree are the source of truth. Prose docs (including `DEVELOPMENT.md`) may be stale — verify commands against `package.json` before running them.\n\n## Build, lint, test\n\n- Install: `npm ci` (also compiles via `prepare` → `build`).\n- Build: `npm run build` (runs `clean` → `tsc` of TypeScript 7, the `typescript7` alias → copy non-TS template files + `.d.ts` to `dist/`, then `bin/fix-bin.cjs`). Use `npm run compile` alone for a faster TS-only recompile.\n- Type-check tests: `npm run check-types` (`tsc -p tsconfig.spec.json` of TypeScript 7; the `typescript` package stays TypeScript 6, for typescript-eslint).\n- Lint: `npm run lint` (eslint, `--max-warnings 5`). Auto-fix: `npm run lint-fix` (runs eslint `--fix` then `prettier --write`).\n- Prettier check/format: `npm run prettier:check` / `npm run prettier:format`.\n- Full test (lint + type-check + tests): `npm test`. Runs expect-node (`exnode`) over the spec files of `expect-node.config.ts` (`test generators cli .blueprint lib`) with `--forbid-only`.\n- Fast test (skip lint/type-check): `npx exnode`.\n- Single test files / directories: `npx exnode <path>...` (add `--workers 0` to run each file in a process of its own).\n- Update snapshots: `npm run update-snapshot -- <path>...` or `npm run update-snapshots` (all). Equivalent: `npx exnode --update-snapshot <path>...`.\n- JDL-only tests: `npm run jdl:test` (watch: `npm run jdl:test-watch`).\n\nSnapshots live next to specs as `*.snap` and are committed. Never hand-edit them — regenerate.\n\n**Always run `npm run prettier:format` (or `npm run lint-fix`) before committing** so changes match the project's Prettier configuration. CI will fail otherwise.\n\n## Running the generator locally\n\nTwo options (see `DEVELOPMENT.md`):\n\n- JIT: `alias jhipster=\"$PWD/bin/jhipster.cjs\"` — no build step needed.\n- Linked build: `npm run build && npm link`; rebuild after changes.\n  On generated apps use `jhipster --skip-jhipster-dependencies` plus `npm link generator-jhipster` so the dev version is picked up. `jhipster --install-path` shows which copy is active.\n\n`jhipster describe` prints the generators; `jhipster describe <generator> [--no-imports] [--prompts] [--json]` the arguments, options, `.yo-rc.json` keys, choices, defaults, derived properties and prompts of a command (model in `lib/command/describe-command.ts`, generator resolution in `lib/resolver/`); `jhipster describe --config <name>` finds the command declaring a config. The generators are named as the cli names them, without the `jhipster:` prefix (`spring-boot`, `spring-boot:cache`; the generators of a blueprint keep their namespace), and `<generator>` takes that name or the namespace. Use it instead of reading `command.ts` files when you need the option catalog or the prompt order.\n\n## Big-picture architecture\n\n- CLI entry: `cli/jhipster.cjs` → `cli/cli.ts` (env checks) → `cli/program.ts` (commander parsing, generator/blueprint lookup) → spawns a Yeoman Environment which runs the selected generator.\n- Generator hierarchy (extend the lowest level that has what you need):\n  `GeneratorBaseCore` → `GeneratorBase` (blueprint composition) → `GeneratorApplication` (entity APIs).\n- Each generator lives in `generators/<name>/` with a fixed layout:\n  - `index.ts` — re-exports the generator as **default** plus the `command`. Required for the exports map in `package.json`.\n  - `generator.ts` — priority task groups (see below).\n  - `command.ts` — CLI args/options/configs (consumed by `parseJHipsterArguments` / `parseJHipsterConfigs` and by `program.ts` to build the CLI).\n  - `templates/` — EJS templates rendered during `writing`/`writingEntities`.\n  - `support/` — exported helpers (part of the public API via `./generators/*/support`).\n  - `internal/` — non-exported helpers.\n  - `resources/`, `jdl/` — supporting data / JDL specs.\n    Sub-generators nest under `generators/<parent>/generators/<child>/` and are exported via the same pattern.\n- Priority lifecycle (order matters, see `ARCHITECTURE.md` for full list): `initializing` → `prompting` → `configuring` → `composing` → `loading` → `preparing` → `configuringEachEntity` → `loadingEntities` → `preparingEachEntity` → `preparingEachEntityField` → `preparingEachEntityRelationship` → `default` → `writing` → `writingEntities` → `postWriting` → `install` → `end`. Use the matching `as<Priority>TaskGroup()` helper on the generator to get typed task signatures.\n- Blueprints (`BLUEPRINTS.md`): three flavors — replacement, side-by-side, standalone. `GeneratorBase` handles composition; blueprinted sub-generators are discovered and composed in `beforeQueue`.\n- `lib/` holds shared, **exported** code: `lib/jdl` (Chevrotain-based JDL parser), `lib/testing` (test harness, also importable as `#testing`), `lib/utils`, `lib/eslint`, `lib/ci`. Keep cross-generator logic here, not inside an individual generator.\n- `.blueprint/` is the in-repo \"dev blueprint\" enabled when running via JIT. It provides sub-generators like `generate-sample`, `describe-samples` (what each CI sample generates and the environment it runs on, `--json` for scripts), `github-build-matrix` (the matrix of a CI workflow, including the `daily-*` workflows of jhipster-daily-builds), `generate-generator`, `from-issue`, `update-spring-boot`, etc. — use these instead of ad-hoc scripts when generating samples for manual testing.\n- Build output in `dist/` is what gets published. The `exports` map in `package.json` defines the public API surface — don't import across generator `internal/` boundaries.\n- **Never edit `dist/` directly.** Modify source in `cli/`, `generators/`, `lib/`, etc., then rebuild with `npm run build` (or `npm run compile` for TS-only).\n\n## Key conventions\n\n- **ESM + TypeScript everywhere**; `\"type\": \"module\"` in `package.json`. Use `.ts`/`.mts`. Tests are `*.spec.ts` run by `expect-node` on node:test, importing `describe`, `it`, `expect` and `exnode` (mocks) from `expect-node`.\n- **Task groups**: define priorities as getters returning the result of `this.as<Priority>TaskGroup({...})`. Never call tasks directly — the Yeoman environment orchestrates them.\n- **Config access**: prefer `this.jhipsterConfig` (persists to `.yo-rc.json`), `this.jhipsterConfigWithDefaults` (read-only with defaults applied), and the `application`/`entity`/`field`/`relationship` context objects injected into tasks. Derived booleans (e.g. `entity.dtoMapstruct`, `field.fieldTypeInteger`) belong in `preparing*` priorities, not in templates.\n- **Writing files**: use `this.writeFiles({ blocks, context })` with `condition` functions on blocks rather than branching inside templates. Use `editFile(path, transform)` or the needle APIs on `source` in `postWriting` to inject into already-written files.\n- **Templates**: EJS (`.ejs`). Two-space indent for template logic; generated file's own rules apply to content. Factor shared fragments into `.ejs` sub-templates included via `<%- include('../path', { ... }) -%>`.\n- **Commit messages** (enforced at review): imperative present tense, lowercase first letter, no trailing dot, header ≤100 chars. Do not reference issues in commit messages: GitHub adds every commit that mentions an issue (on each push, rebase and amend) to the issue timeline, and agents create many commits. Reference the issue in the pull request description instead (`Fix #1234`). Do not use `[ci skip]` or `[skip ci]`, even for docs-only commits: it blocks the required CI workflows.\n- **Tests required** for every feature or bug fix. When behavior touches generated output, update/extend snapshots rather than asserting strings by hand.\n- **Path aliases** for tests: `#testing` → `lib/testing/index.ts`, `#test-support` → `test/support/index.ts`.\n- **Node version**: CI and local must match `engines` in `package.json`; avoid APIs only in newer releases.\n\n## Opening pull requests\n\n- Open pull requests as draft (`gh pr create --draft`).\n- Use `.github/PULL_REQUEST_TEMPLATE.md` as the body: the description in place of its first comment, and its checklist kept.\n- Leave the \"I have personally reviewed, understood, and tested the changes\" item unchecked. The user checks it after reviewing the changes, and marks the pull request ready for review.\n\n## Reviewing pull requests\n\n- Post reviews as comments (`gh pr review --comment` or `gh pr comment`). Never submit a \"request changes\" review: it blocks the merge, and that decision belongs to a human reviewer alone.\n","ARCHITECTURE.md":"# JHipster architecture\n\n## Yeoman basis\n\nInternally, JHipster uses [Yeoman](https://yeoman.io) as the core. JHipster is the [most popular generator of all time](https://yeoman.io/generators/).\n\n## File structure\n\n- `.blueprint` - development blueprint, used to generate and manage samples\n- `.devcontainer` - vscode's devcontainer definitions\n- `.github` - github configuration\n- `.vscode` - vscode's configuration\n- `bin` - jit executable and helper\n- `cli` - (exported) cli implementation\n- `generators/*` - (exported) generators\n  - `command.ts` - cli options, cli arguments definitions\n  - `generator.ts` - generator implementation\n  - `index.ts` - generator exports. Must re-export generator as default export and the command\n  - `internal` - non-exported supporting libs\n  - `resources` - supporting resources\n  - `jdl` - generator's jdl specifications\n  - `support` - (exported) exported supporting libs\n  - `templates` - templates folder\n- `lib` - (exported) shared libraries, utilities, types and jdl parser\n- `rfcs` - [RFCs](CONTRIBUTING.md#rfcs)\n- `test` - package tests\n\n## Lifecycle\n\n- [CLI entry point](https://github.com/jhipster/generator-jhipster/blob/main/cli/jhipster.cjs)\n- [Basic environment validation](https://github.com/jhipster/generator-jhipster/blob/main/cli/cli.ts)\n- [Cli arguments parsing and Environment bootstrap](https://github.com/jhipster/generator-jhipster/blob/main/cli/program.ts)\n  - Lookup for generators and blueprints\n  - Build CLI options and arguments definition\n  - Parse options and arguments\n- Run Generator (start the Environment) passing options and arguments\n- Run every task from the highest precedence priority until there is no more pending task\n\n### Priorities\n\n#### Initializing (yeoman)\n\nInitial generator information.\n\n- say generator specific hello\n- initial environment checks\n- argument and options loading\n\n```ts\nget [Generator.INITIALIZING]() {\n  return this.asInitializingTaskGroup() {\n    sayHelloTask() {\n      this.log.info('Welcome to your generator');\n    },\n    envChecks() {\n      checkNode();\n      checkDocker();\n    },\n    async loadOptions() {\n      this.parseJHipsterArguments(command.arguments);\n      this.parseJHipsterConfigs(command.configs);\n    },\n  }\n}\n```\n\n#### Prompting (yeoman)\n\nPrompt for configuration.\n\n```ts\nget [Generator.PROMPTING]() {\n  return this.asPromptingTaskGroup() {\n    async prompting() {\n      await this.prompt(this.prepareQuestions(command.configs));\n    },\n  }\n}\n```\n\n#### Configuring (yeoman)\n\nCheck and fix configurations:\n\n```ts\nget [Generator.CONFIGURING]() {\n  return this.asConfiguringTaskGroup() {\n    checkConfig() {\n      if (this.jhipsterConfigWithDefaults.reactive && this.jhipsterConfigWithDefaults.cacheProvider !== 'no') {\n        this.log.warn(\"Reactive applications doesn't support cache. Disabling\");\n        this.jhipsterConfig.cacheProvider = 'no';\n      }\n    },\n  }\n}\n```\n\n#### Composing (base)\n\nCompose with other generators:\n\n```ts\nget [Generator.COMPOSING]() {\n  return this.asComposingTaskGroup() {\n    async composing() {\n      if (this.jhipsterConfigWithDefaults.clientFramework === 'angular') {\n        await this.composeWithJHipster('angular');\n      }\n    },\n  }\n}\n```\n\n#### Loading (base)\n\nLoad configuration:\n\n```ts\nget [Generator.LOADING]() {\n  return this.asLoadingTaskGroup() {\n    loading({ application }) {\n      application.myCustomConfig = this.jhipsterConfig.myCustomConfig;\n      application.myBlueprintCustomConfig = this.blueprintConfig.myBlueprintCustomConfig;\n    },\n  }\n}\n```\n\n#### Preparing (base)\n\nGenerate properties to improve understanding:\n\n```ts\nget [Generator.PREPARING]() {\n  return this.asPreparingTaskGroup() {\n    preparing({ application }) {\n      application.myCustomConfigFoo = this.jhipsterConfig.myCustomConfig === 'foo';\n      application.myCustomConfigBar = this.jhipsterConfig.myCustomConfig === 'bar';\n      application.myCustomConfigNo = !this.jhipsterConfig.myCustomConfig || this.jhipsterConfig.myCustomConfig === 'no';\n    },\n  }\n}\n```\n\n#### Custom objects (base-core)\n\nA generator declares its own objects with the `customObjects` feature, a list of objects (`{ name, before }`), and\nimplements a getter of each name giving an array of the objects. Each object gets three priorities before its `before`\npriority (the post preparing one by default, so after the preparing priority), in the order the objects are declared,\neach with the array of the objects (`service`):\n\n- `loading<Name>`: its tasks load the objects;\n- `preparing<Name>`: its tasks prepare them;\n- `postPreparing<Name>`: its tasks use the prepared objects.\n\nThe objects are written in two priorities of their own, with every custom object of the generator by name:\n`writingObjects` (`Generator.WRITING_OBJECTS`), after the writing priority and before the post writing one, and\n`postWritingObjects` (`Generator.POST_WRITING_OBJECTS`), after the post writing priority, with the `source` too. A\ngenerator declaring the names of its custom objects as the `customObjectNames` type gets them typed, with the type of\ntheir getters, through `asWritingObjectsTaskGroup` and `asPostWritingObjectsTaskGroup`.\n\nTo share the objects with the other generators declaring them, the getter reads them from the context\n(`getContextData`), and each phase runs for every generator before the next one. While the objects are prepared, a\ndefault (`mutateData`) reading a property not yet set waits for it, and is applied before the post preparing, like the\napplication ones. An application generator gives the phases the `application`, and they run before its entity priorities. A workspaces generator runs\nthem after its workspaces priorities, before the default priority, and gives them the `deployment` and its\n`applications`. `Generator.objectPriority(name, phase)` gives the priority of a phase:\n\n```ts\nexport default class extends Generator {\n  constructor(args, options, features) {\n    super(args, options, { ...features, customObjects: [{ name: 'service' }] });\n  }\n\n  get service() {\n    return this.getContextData('my-blueprint:service', { factory: () => [{}] });\n  }\n\n  get [Generator.objectPriority('service', 'loading')]() {\n    return {\n      loading({ service: [service] }) {\n        service.name = 'Book';\n      },\n    };\n  }\n\n  get [Generator.objectPriority('service', 'preparing')]() {\n    return {\n      preparing({ service }) {\n        for (const each of service) {\n          each.className = `${each.name}Service`;\n        }\n      },\n    };\n  }\n\n  // The names of the custom objects, for the writing objects tasks to get them typed.\n  declare readonly customObjectNames: readonly ['service'];\n\n  get [Generator.WRITING_OBJECTS]() {\n    return this.asWritingObjectsTaskGroup({\n      async writeServices({ application, service }) {\n        for (const each of service) {\n          await this.writeFiles({ sections: serviceFiles, context: { ...application, service: each } });\n        }\n      },\n    });\n  }\n}\n```\n\n#### Objects of the application (base-application)\n\nThe `objects` of the `.yo-rc.json` file declare the objects of an application by name, out of the `generator-jhipster`\nkey: each with its `type`, `documentation`, `annotations` and `fields`, a field with its `type`, `documentation`,\n`validations` and `annotations`. A type is a type of the JDL or an enum, a reference to an entity\n(`{ \"$ref\": \".jhipster/Order.json\" }`) or to an object (`{ \"$ref\": \"#/objects/Quote\" }`), or an array of the type of its\nitems:\n\n- `getObjectConfig(name)` gives the configuration of an object as declared;\n- `getObject(name)` gives the object, with its `name`, and the objects and the entities it references embedded in place of\n  their reference, each the same instance wherever it is referenced, an entity the one the application prepares; a\n  reference with other fields (`{ \"$ref\": \"#/objects/Quote\", \"documentation\": \"...\" }`) gives a copy of the referenced\n  one with the fields merged over it, the objects and the entities it references kept;\n- `findObjects(type)` gives the objects of a type, sorted by name.\n\nThe type of an object is the name of the custom object handling it: its getter gives `findObjects(<name>)`, and its\n`before` priority is the default one, the entities being prepared by then:\n\n```ts\nexport default class extends BaseApplicationGenerator {\n  constructor(args, options, features) {\n    super(args, options, { ...features, customObjects: [{ name: 'service', before: 'default' }] });\n  }\n\n  get service() {\n    return this.findObjects('service');\n  }\n}\n```\n\n#### Configuring each entity (base-application)\n\nConfigure and check entity's configuration:\n\n```ts\nget [Generator.CONFIGURING_EACH_ENTITY]() {\n  return this.asConfiguringEachEntityTaskGroup() {\n    configuring({ application, entityConfig }) {\n      if (application.searchEngineNo && entityConfig.searchEngine && entityConfig.searchEngine !== 'no') {\n        this.log.warn(\"Search engine cannot be enabled at entity because it's disabled at application\");\n        entityConfig.searchEngine = 'no';\n      }\n    },\n  }\n}\n```\n\n#### Loading entities (base-application)\n\nUsually empty the entire entity configuration is loaded by default.\n\n#### Preparing each entity (base-application)\n\nGenerate properties to improve understanding at the entity level:\n\n```ts\nget [Generator.PREPARING_EACH_ENTITY]() {\n  return this.asPreparingEachEntityTaskGroup() {\n    preparing({ application, entity }) {\n      entity.dtoMapstruct = entity.dto === 'mapstruct';\n    },\n  }\n}\n```\n\n#### Preparing each entity field (base-application)\n\nGenerate properties to improve understanding at the field level:\n\n```ts\nget [Generator.PREPARING_EACH_ENTITY_FIELD]() {\n  return this.asPreparingEachEntityFieldTaskGroup() {\n    preparing({ application, entity, field }) {\n      field.technologyFieldTypeIntegerMap = field.fieldType === 'Integer';\n    },\n  }\n}\n```\n\n#### Preparing each entity relationship (base-application)\n\nGenerate properties to improve understanding at the relationship level:\n\n```ts\nget [Generator.PREPARING_EACH_ENTITY_RELATIONSHIP]() {\n  return this.asPreparingEachEntityRelationshipTaskGroup() {\n    preparing({ application, entity, relationship }) {\n      relationship.technologyRelationshipDbName = relationship.relationshipTypeOneToOne ? 'foo' : 'bar';\n    },\n  };\n}\n```\n\n#### Default (yeoman)\n\nGenerate properties to improve understanding that depends on others' properties:\n\n```ts\nget [Generator.DEFAULT]() {\n  return this.asDefaultTaskGroup() {\n    preparing({ application, entities }) {\n      application.hasEntityFieldInteger = entities.some(entity => entity.fields.some(field => field.fieldTypeInteger));\n    },\n  };\n}\n```\n\n#### Writing (yeoman)\n\nWrite files to the in-memory file system.\n\nThere are a lot of APIs to write files, copy files, and delete files.\nThe `writeFiles()` method is the most used in official generators.\n\n```ts\nget [Generator.WRITING]() {\n  return this.asWritingTaskGroup({\n    async writingTask({ application }) {\n      await this.writeFiles({\n        blocks: [\n          {\n            condition: ctx => ctx.shouldWrite,\n            templates: ['template.file'],\n          }\n        ],\n        context: application,\n      });\n    },\n  });\n}\n```\n\n#### Writing entities (base-application)\n\nWrite entity files to the in-memory file system.\n\nWriting entities is a separate priority to keep the workflow sane when using options like `--skip-application` and `--single-entity`.\n\n```ts\nget [Generator.WRITING_ENTITIES]() {\n  return this.asWritingTaskGroup({\n    async writingTask({ application, entities }) {\n      for (const entity of entities) {\n        await this.writeFiles({\n          blocks: [\n            {\n              condition: ctx => ctx.shouldWrite,\n              templates: ['entity.template.file'],\n            }\n          ],\n          context: { ...application, ...entity },\n        });\n      }\n    },\n  });\n}\n```\n\n#### Post writing (base)\n\nInjects code in the generated source.\n\n##### Injecting code with provided apis (needles)\n\nJHipster adds APIs for code injection:\n\n```ts\nget [Generator.POST_WRITING]() {\n  return this.asPostWritingTaskGroup({\n    postWritingTask({ source }) {\n      source.someProvidedInjectionApi({ code: 'some code' });\n    }\n  });\n}\n```\n\n##### Custom code injection\n\nEvery file can be edited manually.\n\n```ts\nget [Generator.POST_WRITING]() {\n  return this.asPostWritingTaskGroup({\n    postWritingTask({ source }) {\n      this.editFile('path/to/some/file', content => content.replaceAll('some content', 'another content'));\n    }\n  });\n}\n```\n\n#### Install (yeoman)\n\nUsually empty.\nInstall task is queued by detecting `package.json` changes.\n\n#### End (yeoman)\n\nPrint generator result and info:\n\n```ts\nget [Generator.END]() {\n  return this.asEndTaskGroup() {\n    preparing({ application }) {\n      this.log.success('Tech application generated successfully');\n      this.log.log(`Start the application running 'npm run start:app'`);\n    },\n  };\n}\n```\n\n## Blueprints\n\nBlueprint support allows customizing the generation process.\n\nA Blueprint package can include any number of sub-generators, each can be a replacement blueprint, a side-by-side blueprint, or a stand alone blueprint.\n\n- Normal blueprints will completely replace the blueprinted sub-generator with a replacement.\n- Side by side blueprint doesn't change the generation process, it customizes it.\n- Stand alone blueprint doesn't hook into a sub-generator.\n\nExamples:\n\n- [Micronaut](https://github.com/jhipster/generator-jhipster-micronaut) has a [server](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/server) replacement blueprint, an [angular](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/angular), [client](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/client), [cypress](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/cypress), [docker](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/docker) and [react](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/react) side by side blueprints, and a [micronaut-cache](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/micronaut-cache) stand alone blueprint\n\nMore information can be found at:\n\n[Extending and customizing](https://www.jhipster.tech/modules/extending-and-customizing/)\n[Creating a stand alone Blueprint](https://www.jhipster.tech/modules/creating-a-module/)\n[Creating a blueprint](https://www.jhipster.tech/modules/creating-a-blueprint/)\n\n### Blueprint scope\n\nA blueprint belongs to the project whose `.yo-rc.json` stores it ([RFC-7](rfcs/7-jhipster-rfc-blueprint-scope.md)):\n\n- `--blueprints` applies to the project the command runs in, `--global-blueprints` to every project the run generates, the ones in other folders included.\n- A generator composed in another folder (`composeWithJHipster` with a `destinationRoot`) uses the blueprints of the `.yo-rc.json` of that folder, unless they are passed to it.\n- The `jdl` generator is not blueprinted: the applications of a jdl use the blueprints their jdl declares.\n\n### Blueprint lifecycle\n\n#### Replacement blueprint\n\n| Priority     | Blueprinted sub-gen                   | Blueprint sub-gen              |\n| ------------ | ------------------------------------- | ------------------------------ |\n| beforeQueue  | composes with blueprints/dependencies | composes with dependencies     |\n| initializing | X                                     | replacement initializing tasks |\n| prompting    | X                                     | replacement prompting tasks    |\n| ...          | X                                     | ...                            |\n\n#### Side by side blueprint\n\n| Priority     | Blueprinted sub-gen                   | Blueprint sub-gen             | Another blueprint sub-gen     |\n| ------------ | ------------------------------------- | ----------------------------- | ----------------------------- |\n| beforeQueue  | composes with blueprints/dependencies | composes with dependencies    | composes with dependencies    |\n| initializing | initializing tasks                    | additional initializing tasks | additional initializing tasks |\n| prompting    | prompting tasks                       | additional prompting tasks    | additional prompting tasks    |\n| ...          | ...                                   | ...                           | ...                           |\n\n#### Stand alone blueprint\n\n| Priority     | Blueprint sub-gen          |\n| ------------ | -------------------------- |\n| beforeQueue  | composes with dependencies |\n| initializing | initializing tasks         |\n| prompting    | prompting tasks            |\n| ...          | ...                        |\n\n## Generator Hierarchy\n\n### GeneratorBaseCore\n\nAdds custom APIs to `yeoman-generator` and customizes the behavior.\n\n### GeneratorBase\n\nAdds Blueprint composing APIs.\n\n### GeneratorApplication\n\nAdds Entities related apis.\n"},"files":{"CLAUDE.md":"See [`AGENTS.md`](./AGENTS.md) at the repository root for the canonical AI agent instructions for this codebase.\n",".github/copilot-instructions.md":"See [`AGENTS.md`](../AGENTS.md) at the repository root for the canonical AI agent instructions for this codebase.\n","AGENTS.md":"# AI agent instructions for generator-jhipster\n\nJHipster is a Yeoman-based code generator (TypeScript, ESM, Node — see `engines` in `package.json` for the required version) that scaffolds Spring Boot + Angular/React/Vue applications. See `ARCHITECTURE.md`, `BLUEPRINTS.md`, `DEVELOPMENT.md`, and `JDL.md` (the reference of the JDL language) for background context.\n\n**Trust order when docs disagree:** `package.json` scripts and the current source tree are the source of truth. Prose docs (including `DEVELOPMENT.md`) may be stale — verify commands against `package.json` before running them.\n\n## Build, lint, test\n\n- Install: `npm ci` (also compiles via `prepare` → `build`).\n- Build: `npm run build` (runs `clean` → `tsc` of TypeScript 7, the `typescript7` alias → copy non-TS template files + `.d.ts` to `dist/`, then `bin/fix-bin.cjs`). Use `npm run compile` alone for a faster TS-only recompile.\n- Type-check tests: `npm run check-types` (`tsc -p tsconfig.spec.json` of TypeScript 7; the `typescript` package stays TypeScript 6, for typescript-eslint).\n- Lint: `npm run lint` (eslint, `--max-warnings 5`). Auto-fix: `npm run lint-fix` (runs eslint `--fix` then `prettier --write`).\n- Prettier check/format: `npm run prettier:check` / `npm run prettier:format`.\n- Full test (lint + type-check + tests): `npm test`. Runs expect-node (`exnode`) over the spec files of `expect-node.config.ts` (`test generators cli .blueprint lib`) with `--forbid-only`.\n- Fast test (skip lint/type-check): `npx exnode`.\n- Single test files / directories: `npx exnode <path>...` (add `--workers 0` to run each file in a process of its own).\n- Update snapshots: `npm run update-snapshot -- <path>...` or `npm run update-snapshots` (all). Equivalent: `npx exnode --update-snapshot <path>...`.\n- JDL-only tests: `npm run jdl:test` (watch: `npm run jdl:test-watch`).\n\nSnapshots live next to specs as `*.snap` and are committed. Never hand-edit them — regenerate.\n\n**Always run `npm run prettier:format` (or `npm run lint-fix`) before committing** so changes match the project's Prettier configuration. CI will fail otherwise.\n\n## Running the generator locally\n\nTwo options (see `DEVELOPMENT.md`):\n\n- JIT: `alias jhipster=\"$PWD/bin/jhipster.cjs\"` — no build step needed.\n- Linked build: `npm run build && npm link`; rebuild after changes.\n  On generated apps use `jhipster --skip-jhipster-dependencies` plus `npm link generator-jhipster` so the dev version is picked up. `jhipster --install-path` shows which copy is active.\n\n`jhipster describe` prints the generators; `jhipster describe <generator> [--no-imports] [--prompts] [--json]` the arguments, options, `.yo-rc.json` keys, choices, defaults, derived properties and prompts of a command (model in `lib/command/describe-command.ts`, generator resolution in `lib/resolver/`); `jhipster describe --config <name>` finds the command declaring a config. The generators are named as the cli names them, without the `jhipster:` prefix (`spring-boot`, `spring-boot:cache`; the generators of a blueprint keep their namespace), and `<generator>` takes that name or the namespace. Use it instead of reading `command.ts` files when you need the option catalog or the prompt order.\n\n## Big-picture architecture\n\n- CLI entry: `cli/jhipster.cjs` → `cli/cli.ts` (env checks) → `cli/program.ts` (commander parsing, generator/blueprint lookup) → spawns a Yeoman Environment which runs the selected generator.\n- Generator hierarchy (extend the lowest level that has what you need):\n  `GeneratorBaseCore` → `GeneratorBase` (blueprint composition) → `GeneratorApplication` (entity APIs).\n- Each generator lives in `generators/<name>/` with a fixed layout:\n  - `index.ts` — re-exports the generator as **default** plus the `command`. Required for the exports map in `package.json`.\n  - `generator.ts` — priority task groups (see below).\n  - `command.ts` — CLI args/options/configs (consumed by `parseJHipsterArguments` / `parseJHipsterConfigs` and by `program.ts` to build the CLI).\n  - `templates/` — EJS templates rendered during `writing`/`writingEntities`.\n  - `support/` — exported helpers (part of the public API via `./generators/*/support`).\n  - `internal/` — non-exported helpers.\n  - `resources/`, `jdl/` — supporting data / JDL specs.\n    Sub-generators nest under `generators/<parent>/generators/<child>/` and are exported via the same pattern.\n- Priority lifecycle (order matters, see `ARCHITECTURE.md` for full list): `initializing` → `prompting` → `configuring` → `composing` → `loading` → `preparing` → `configuringEachEntity` → `loadingEntities` → `preparingEachEntity` → `preparingEachEntityField` → `preparingEachEntityRelationship` → `default` → `writing` → `writingEntities` → `postWriting` → `install` → `end`. Use the matching `as<Priority>TaskGroup()` helper on the generator to get typed task signatures.\n- Blueprints (`BLUEPRINTS.md`): three flavors — replacement, side-by-side, standalone. `GeneratorBase` handles composition; blueprinted sub-generators are discovered and composed in `beforeQueue`.\n- `lib/` holds shared, **exported** code: `lib/jdl` (Chevrotain-based JDL parser), `lib/testing` (test harness, also importable as `#testing`), `lib/utils`, `lib/eslint`, `lib/ci`. Keep cross-generator logic here, not inside an individual generator.\n- `.blueprint/` is the in-repo \"dev blueprint\" enabled when running via JIT. It provides sub-generators like `generate-sample`, `describe-samples` (what each CI sample generates and the environment it runs on, `--json` for scripts), `github-build-matrix` (the matrix of a CI workflow, including the `daily-*` workflows of jhipster-daily-builds), `generate-generator`, `from-issue`, `update-spring-boot`, etc. — use these instead of ad-hoc scripts when generating samples for manual testing.\n- Build output in `dist/` is what gets published. The `exports` map in `package.json` defines the public API surface — don't import across generator `internal/` boundaries.\n- **Never edit `dist/` directly.** Modify source in `cli/`, `generators/`, `lib/`, etc., then rebuild with `npm run build` (or `npm run compile` for TS-only).\n\n## Key conventions\n\n- **ESM + TypeScript everywhere**; `\"type\": \"module\"` in `package.json`. Use `.ts`/`.mts`. Tests are `*.spec.ts` run by `expect-node` on node:test, importing `describe`, `it`, `expect` and `exnode` (mocks) from `expect-node`.\n- **Task groups**: define priorities as getters returning the result of `this.as<Priority>TaskGroup({...})`. Never call tasks directly — the Yeoman environment orchestrates them.\n- **Config access**: prefer `this.jhipsterConfig` (persists to `.yo-rc.json`), `this.jhipsterConfigWithDefaults` (read-only with defaults applied), and the `application`/`entity`/`field`/`relationship` context objects injected into tasks. Derived booleans (e.g. `entity.dtoMapstruct`, `field.fieldTypeInteger`) belong in `preparing*` priorities, not in templates.\n- **Writing files**: use `this.writeFiles({ blocks, context })` with `condition` functions on blocks rather than branching inside templates. Use `editFile(path, transform)` or the needle APIs on `source` in `postWriting` to inject into already-written files.\n- **Templates**: EJS (`.ejs`). Two-space indent for template logic; generated file's own rules apply to content. Factor shared fragments into `.ejs` sub-templates included via `<%- include('../path', { ... }) -%>`.\n- **Commit messages** (enforced at review): imperative present tense, lowercase first letter, no trailing dot, header ≤100 chars. Do not reference issues in commit messages: GitHub adds every commit that mentions an issue (on each push, rebase and amend) to the issue timeline, and agents create many commits. Reference the issue in the pull request description instead (`Fix #1234`). Do not use `[ci skip]` or `[skip ci]`, even for docs-only commits: it blocks the required CI workflows.\n- **Tests required** for every feature or bug fix. When behavior touches generated output, update/extend snapshots rather than asserting strings by hand.\n- **Path aliases** for tests: `#testing` → `lib/testing/index.ts`, `#test-support` → `test/support/index.ts`.\n- **Node version**: CI and local must match `engines` in `package.json`; avoid APIs only in newer releases.\n\n## Opening pull requests\n\n- Open pull requests as draft (`gh pr create --draft`).\n- Use `.github/PULL_REQUEST_TEMPLATE.md` as the body: the description in place of its first comment, and its checklist kept.\n- Leave the \"I have personally reviewed, understood, and tested the changes\" item unchecked. The user checks it after reviewing the changes, and marks the pull request ready for review.\n\n## Reviewing pull requests\n\n- Post reviews as comments (`gh pr review --comment` or `gh pr comment`). Never submit a \"request changes\" review: it blocks the merge, and that decision belongs to a human reviewer alone.\n","ARCHITECTURE.md":"# JHipster architecture\n\n## Yeoman basis\n\nInternally, JHipster uses [Yeoman](https://yeoman.io) as the core. JHipster is the [most popular generator of all time](https://yeoman.io/generators/).\n\n## File structure\n\n- `.blueprint` - development blueprint, used to generate and manage samples\n- `.devcontainer` - vscode's devcontainer definitions\n- `.github` - github configuration\n- `.vscode` - vscode's configuration\n- `bin` - jit executable and helper\n- `cli` - (exported) cli implementation\n- `generators/*` - (exported) generators\n  - `command.ts` - cli options, cli arguments definitions\n  - `generator.ts` - generator implementation\n  - `index.ts` - generator exports. Must re-export generator as default export and the command\n  - `internal` - non-exported supporting libs\n  - `resources` - supporting resources\n  - `jdl` - generator's jdl specifications\n  - `support` - (exported) exported supporting libs\n  - `templates` - templates folder\n- `lib` - (exported) shared libraries, utilities, types and jdl parser\n- `rfcs` - [RFCs](CONTRIBUTING.md#rfcs)\n- `test` - package tests\n\n## Lifecycle\n\n- [CLI entry point](https://github.com/jhipster/generator-jhipster/blob/main/cli/jhipster.cjs)\n- [Basic environment validation](https://github.com/jhipster/generator-jhipster/blob/main/cli/cli.ts)\n- [Cli arguments parsing and Environment bootstrap](https://github.com/jhipster/generator-jhipster/blob/main/cli/program.ts)\n  - Lookup for generators and blueprints\n  - Build CLI options and arguments definition\n  - Parse options and arguments\n- Run Generator (start the Environment) passing options and arguments\n- Run every task from the highest precedence priority until there is no more pending task\n\n### Priorities\n\n#### Initializing (yeoman)\n\nInitial generator information.\n\n- say generator specific hello\n- initial environment checks\n- argument and options loading\n\n```ts\nget [Generator.INITIALIZING]() {\n  return this.asInitializingTaskGroup() {\n    sayHelloTask() {\n      this.log.info('Welcome to your generator');\n    },\n    envChecks() {\n      checkNode();\n      checkDocker();\n    },\n    async loadOptions() {\n      this.parseJHipsterArguments(command.arguments);\n      this.parseJHipsterConfigs(command.configs);\n    },\n  }\n}\n```\n\n#### Prompting (yeoman)\n\nPrompt for configuration.\n\n```ts\nget [Generator.PROMPTING]() {\n  return this.asPromptingTaskGroup() {\n    async prompting() {\n      await this.prompt(this.prepareQuestions(command.configs));\n    },\n  }\n}\n```\n\n#### Configuring (yeoman)\n\nCheck and fix configurations:\n\n```ts\nget [Generator.CONFIGURING]() {\n  return this.asConfiguringTaskGroup() {\n    checkConfig() {\n      if (this.jhipsterConfigWithDefaults.reactive && this.jhipsterConfigWithDefaults.cacheProvider !== 'no') {\n        this.log.warn(\"Reactive applications doesn't support cache. Disabling\");\n        this.jhipsterConfig.cacheProvider = 'no';\n      }\n    },\n  }\n}\n```\n\n#### Composing (base)\n\nCompose with other generators:\n\n```ts\nget [Generator.COMPOSING]() {\n  return this.asComposingTaskGroup() {\n    async composing() {\n      if (this.jhipsterConfigWithDefaults.clientFramework === 'angular') {\n        await this.composeWithJHipster('angular');\n      }\n    },\n  }\n}\n```\n\n#### Loading (base)\n\nLoad configuration:\n\n```ts\nget [Generator.LOADING]() {\n  return this.asLoadingTaskGroup() {\n    loading({ application }) {\n      application.myCustomConfig = this.jhipsterConfig.myCustomConfig;\n      application.myBlueprintCustomConfig = this.blueprintConfig.myBlueprintCustomConfig;\n    },\n  }\n}\n```\n\n#### Preparing (base)\n\nGenerate properties to improve understanding:\n\n```ts\nget [Generator.PREPARING]() {\n  return this.asPreparingTaskGroup() {\n    preparing({ application }) {\n      application.myCustomConfigFoo = this.jhipsterConfig.myCustomConfig === 'foo';\n      application.myCustomConfigBar = this.jhipsterConfig.myCustomConfig === 'bar';\n      application.myCustomConfigNo = !this.jhipsterConfig.myCustomConfig || this.jhipsterConfig.myCustomConfig === 'no';\n    },\n  }\n}\n```\n\n#### Custom objects (base-core)\n\nA generator declares its own objects with the `customObjects` feature, a list of objects (`{ name, before }`), and\nimplements a getter of each name giving an array of the objects. Each object gets three priorities before its `before`\npriority (the post preparing one by default, so after the preparing priority), in the order the objects are declared,\neach with the array of the objects (`service`):\n\n- `loading<Name>`: its tasks load the objects;\n- `preparing<Name>`: its tasks prepare them;\n- `postPreparing<Name>`: its tasks use the prepared objects.\n\nThe objects are written in two priorities of their own, with every custom object of the generator by name:\n`writingObjects` (`Generator.WRITING_OBJECTS`), after the writing priority and before the post writing one, and\n`postWritingObjects` (`Generator.POST_WRITING_OBJECTS`), after the post writing priority, with the `source` too. A\ngenerator declaring the names of its custom objects as the `customObjectNames` type gets them typed, with the type of\ntheir getters, through `asWritingObjectsTaskGroup` and `asPostWritingObjectsTaskGroup`.\n\nTo share the objects with the other generators declaring them, the getter reads them from the context\n(`getContextData`), and each phase runs for every generator before the next one. While the objects are prepared, a\ndefault (`mutateData`) reading a property not yet set waits for it, and is applied before the post preparing, like the\napplication ones. An application generator gives the phases the `application`, and they run before its entity priorities. A workspaces generator runs\nthem after its workspaces priorities, before the default priority, and gives them the `deployment` and its\n`applications`. `Generator.objectPriority(name, phase)` gives the priority of a phase:\n\n```ts\nexport default class extends Generator {\n  constructor(args, options, features) {\n    super(args, options, { ...features, customObjects: [{ name: 'service' }] });\n  }\n\n  get service() {\n    return this.getContextData('my-blueprint:service', { factory: () => [{}] });\n  }\n\n  get [Generator.objectPriority('service', 'loading')]() {\n    return {\n      loading({ service: [service] }) {\n        service.name = 'Book';\n      },\n    };\n  }\n\n  get [Generator.objectPriority('service', 'preparing')]() {\n    return {\n      preparing({ service }) {\n        for (const each of service) {\n          each.className = `${each.name}Service`;\n        }\n      },\n    };\n  }\n\n  // The names of the custom objects, for the writing objects tasks to get them typed.\n  declare readonly customObjectNames: readonly ['service'];\n\n  get [Generator.WRITING_OBJECTS]() {\n    return this.asWritingObjectsTaskGroup({\n      async writeServices({ application, service }) {\n        for (const each of service) {\n          await this.writeFiles({ sections: serviceFiles, context: { ...application, service: each } });\n        }\n      },\n    });\n  }\n}\n```\n\n#### Objects of the application (base-application)\n\nThe `objects` of the `.yo-rc.json` file declare the objects of an application by name, out of the `generator-jhipster`\nkey: each with its `type`, `documentation`, `annotations` and `fields`, a field with its `type`, `documentation`,\n`validations` and `annotations`. A type is a type of the JDL or an enum, a reference to an entity\n(`{ \"$ref\": \".jhipster/Order.json\" }`) or to an object (`{ \"$ref\": \"#/objects/Quote\" }`), or an array of the type of its\nitems:\n\n- `getObjectConfig(name)` gives the configuration of an object as declared;\n- `getObject(name)` gives the object, with its `name`, and the objects and the entities it references embedded in place of\n  their reference, each the same instance wherever it is referenced, an entity the one the application prepares; a\n  reference with other fields (`{ \"$ref\": \"#/objects/Quote\", \"documentation\": \"...\" }`) gives a copy of the referenced\n  one with the fields merged over it, the objects and the entities it references kept;\n- `findObjects(type)` gives the objects of a type, sorted by name.\n\nThe type of an object is the name of the custom object handling it: its getter gives `findObjects(<name>)`, and its\n`before` priority is the default one, the entities being prepared by then:\n\n```ts\nexport default class extends BaseApplicationGenerator {\n  constructor(args, options, features) {\n    super(args, options, { ...features, customObjects: [{ name: 'service', before: 'default' }] });\n  }\n\n  get service() {\n    return this.findObjects('service');\n  }\n}\n```\n\n#### Configuring each entity (base-application)\n\nConfigure and check entity's configuration:\n\n```ts\nget [Generator.CONFIGURING_EACH_ENTITY]() {\n  return this.asConfiguringEachEntityTaskGroup() {\n    configuring({ application, entityConfig }) {\n      if (application.searchEngineNo && entityConfig.searchEngine && entityConfig.searchEngine !== 'no') {\n        this.log.warn(\"Search engine cannot be enabled at entity because it's disabled at application\");\n        entityConfig.searchEngine = 'no';\n      }\n    },\n  }\n}\n```\n\n#### Loading entities (base-application)\n\nUsually empty the entire entity configuration is loaded by default.\n\n#### Preparing each entity (base-application)\n\nGenerate properties to improve understanding at the entity level:\n\n```ts\nget [Generator.PREPARING_EACH_ENTITY]() {\n  return this.asPreparingEachEntityTaskGroup() {\n    preparing({ application, entity }) {\n      entity.dtoMapstruct = entity.dto === 'mapstruct';\n    },\n  }\n}\n```\n\n#### Preparing each entity field (base-application)\n\nGenerate properties to improve understanding at the field level:\n\n```ts\nget [Generator.PREPARING_EACH_ENTITY_FIELD]() {\n  return this.asPreparingEachEntityFieldTaskGroup() {\n    preparing({ application, entity, field }) {\n      field.technologyFieldTypeIntegerMap = field.fieldType === 'Integer';\n    },\n  }\n}\n```\n\n#### Preparing each entity relationship (base-application)\n\nGenerate properties to improve understanding at the relationship level:\n\n```ts\nget [Generator.PREPARING_EACH_ENTITY_RELATIONSHIP]() {\n  return this.asPreparingEachEntityRelationshipTaskGroup() {\n    preparing({ application, entity, relationship }) {\n      relationship.technologyRelationshipDbName = relationship.relationshipTypeOneToOne ? 'foo' : 'bar';\n    },\n  };\n}\n```\n\n#### Default (yeoman)\n\nGenerate properties to improve understanding that depends on others' properties:\n\n```ts\nget [Generator.DEFAULT]() {\n  return this.asDefaultTaskGroup() {\n    preparing({ application, entities }) {\n      application.hasEntityFieldInteger = entities.some(entity => entity.fields.some(field => field.fieldTypeInteger));\n    },\n  };\n}\n```\n\n#### Writing (yeoman)\n\nWrite files to the in-memory file system.\n\nThere are a lot of APIs to write files, copy files, and delete files.\nThe `writeFiles()` method is the most used in official generators.\n\n```ts\nget [Generator.WRITING]() {\n  return this.asWritingTaskGroup({\n    async writingTask({ application }) {\n      await this.writeFiles({\n        blocks: [\n          {\n            condition: ctx => ctx.shouldWrite,\n            templates: ['template.file'],\n          }\n        ],\n        context: application,\n      });\n    },\n  });\n}\n```\n\n#### Writing entities (base-application)\n\nWrite entity files to the in-memory file system.\n\nWriting entities is a separate priority to keep the workflow sane when using options like `--skip-application` and `--single-entity`.\n\n```ts\nget [Generator.WRITING_ENTITIES]() {\n  return this.asWritingTaskGroup({\n    async writingTask({ application, entities }) {\n      for (const entity of entities) {\n        await this.writeFiles({\n          blocks: [\n            {\n              condition: ctx => ctx.shouldWrite,\n              templates: ['entity.template.file'],\n            }\n          ],\n          context: { ...application, ...entity },\n        });\n      }\n    },\n  });\n}\n```\n\n#### Post writing (base)\n\nInjects code in the generated source.\n\n##### Injecting code with provided apis (needles)\n\nJHipster adds APIs for code injection:\n\n```ts\nget [Generator.POST_WRITING]() {\n  return this.asPostWritingTaskGroup({\n    postWritingTask({ source }) {\n      source.someProvidedInjectionApi({ code: 'some code' });\n    }\n  });\n}\n```\n\n##### Custom code injection\n\nEvery file can be edited manually.\n\n```ts\nget [Generator.POST_WRITING]() {\n  return this.asPostWritingTaskGroup({\n    postWritingTask({ source }) {\n      this.editFile('path/to/some/file', content => content.replaceAll('some content', 'another content'));\n    }\n  });\n}\n```\n\n#### Install (yeoman)\n\nUsually empty.\nInstall task is queued by detecting `package.json` changes.\n\n#### End (yeoman)\n\nPrint generator result and info:\n\n```ts\nget [Generator.END]() {\n  return this.asEndTaskGroup() {\n    preparing({ application }) {\n      this.log.success('Tech application generated successfully');\n      this.log.log(`Start the application running 'npm run start:app'`);\n    },\n  };\n}\n```\n\n## Blueprints\n\nBlueprint support allows customizing the generation process.\n\nA Blueprint package can include any number of sub-generators, each can be a replacement blueprint, a side-by-side blueprint, or a stand alone blueprint.\n\n- Normal blueprints will completely replace the blueprinted sub-generator with a replacement.\n- Side by side blueprint doesn't change the generation process, it customizes it.\n- Stand alone blueprint doesn't hook into a sub-generator.\n\nExamples:\n\n- [Micronaut](https://github.com/jhipster/generator-jhipster-micronaut) has a [server](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/server) replacement blueprint, an [angular](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/angular), [client](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/client), [cypress](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/cypress), [docker](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/docker) and [react](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/react) side by side blueprints, and a [micronaut-cache](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/micronaut-cache) stand alone blueprint\n\nMore information can be found at:\n\n[Extending and customizing](https://www.jhipster.tech/modules/extending-and-customizing/)\n[Creating a stand alone Blueprint](https://www.jhipster.tech/modules/creating-a-module/)\n[Creating a blueprint](https://www.jhipster.tech/modules/creating-a-blueprint/)\n\n### Blueprint scope\n\nA blueprint belongs to the project whose `.yo-rc.json` stores it ([RFC-7](rfcs/7-jhipster-rfc-blueprint-scope.md)):\n\n- `--blueprints` applies to the project the command runs in, `--global-blueprints` to every project the run generates, the ones in other folders included.\n- A generator composed in another folder (`composeWithJHipster` with a `destinationRoot`) uses the blueprints of the `.yo-rc.json` of that folder, unless they are passed to it.\n- The `jdl` generator is not blueprinted: the applications of a jdl use the blueprints their jdl declares.\n\n### Blueprint lifecycle\n\n#### Replacement blueprint\n\n| Priority     | Blueprinted sub-gen                   | Blueprint sub-gen              |\n| ------------ | ------------------------------------- | ------------------------------ |\n| beforeQueue  | composes with blueprints/dependencies | composes with dependencies     |\n| initializing | X                                     | replacement initializing tasks |\n| prompting    | X                                     | replacement prompting tasks    |\n| ...          | X                                     | ...                            |\n\n#### Side by side blueprint\n\n| Priority     | Blueprinted sub-gen                   | Blueprint sub-gen             | Another blueprint sub-gen     |\n| ------------ | ------------------------------------- | ----------------------------- | ----------------------------- |\n| beforeQueue  | composes with blueprints/dependencies | composes with dependencies    | composes with dependencies    |\n| initializing | initializing tasks                    | additional initializing tasks | additional initializing tasks |\n| prompting    | prompting tasks                       | additional prompting tasks    | additional prompting tasks    |\n| ...          | ...                                   | ...                           | ...                           |\n\n#### Stand alone blueprint\n\n| Priority     | Blueprint sub-gen          |\n| ------------ | -------------------------- |\n| beforeQueue  | composes with dependencies |\n| initializing | initializing tasks         |\n| prompting    | prompting tasks            |\n| ...          | ...                        |\n\n## Generator Hierarchy\n\n### GeneratorBaseCore\n\nAdds custom APIs to `yeoman-generator` and customizes the behavior.\n\n### GeneratorBase\n\nAdds Blueprint composing APIs.\n\n### GeneratorApplication\n\nAdds Entities related apis.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/jhipster/generator-jhipster/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# AI agent instructions for generator-jhipster\n\nJHipster is a Yeoman-based code generator (TypeScript, ESM, Node — see `engines` in `package.json` for the required version) that scaffolds Spring Boot + Angular/React/Vue applications. See `ARCHITECTURE.md`, `BLUEPRINTS.md`, `DEVELOPMENT.md`, and `JDL.md` (the reference of the JDL language) for background context.\n\n**Trust order when docs disagree:** `package.json` scripts and the current source tree are the source of truth. Prose docs (including `DEVELOPMENT.md`) may be stale — verify commands against `package.json` before running them.\n\n## Build, lint, test\n\n- Install: `npm ci` (also compiles via `prepare` → `build`).\n- Build: `npm run build` (runs `clean` → `tsc` of TypeScript 7, the `typescript7` alias → copy non-TS template files + `.d.ts` to `dist/`, then `bin/fix-bin.cjs`). Use `npm run compile` alone for a faster TS-only recompile.\n- Type-check tests: `npm run check-types` (`tsc -p tsconfig.spec.json` of TypeScript 7; the `typescript` package stays TypeScript 6, for typescript-eslint).\n- Lint: `npm run lint` (eslint, `--max-warnings 5`). Auto-fix: `npm run lint-fix` (runs eslint `--fix` then `prettier --write`).\n- Prettier check/format: `npm run prettier:check` / `npm run prettier:format`.\n- Full test (lint + type-check + tests): `npm test`. Runs expect-node (`exnode`) over the spec files of `expect-node.config.ts` (`test generators cli .blueprint lib`) with `--forbid-only`.\n- Fast test (skip lint/type-check): `npx exnode`.\n- Single test files / directories: `npx exnode <path>...` (add `--workers 0` to run each file in a process of its own).\n- Update snapshots: `npm run update-snapshot -- <path>...` or `npm run update-snapshots` (all). Equivalent: `npx exnode --update-snapshot <path>...`.\n- JDL-only tests: `npm run jdl:test` (watch: `npm run jdl:test-watch`).\n\nSnapshots live next to specs as `*.snap` and are committed. Never hand-edit them — regenerate.\n\n**Always run `npm run prettier:format` (or `npm run lint-fix`) before committing** so changes match the project's Prettier configuration. CI will fail otherwise.\n\n## Running the generator locally\n\nTwo options (see `DEVELOPMENT.md`):\n\n- JIT: `alias jhipster=\"$PWD/bin/jhipster.cjs\"` — no build step needed.\n- Linked build: `npm run build && npm link`; rebuild after changes.\n  On generated apps use `jhipster --skip-jhipster-dependencies` plus `npm link generator-jhipster` so the dev version is picked up. `jhipster --install-path` shows which copy is active.\n\n`jhipster describe` prints the generators; `jhipster describe <generator> [--no-imports] [--prompts] [--json]` the arguments, options, `.yo-rc.json` keys, choices, defaults, derived properties and prompts of a command (model in `lib/command/describe-command.ts`, generator resolution in `lib/resolver/`); `jhipster describe --config <name>` finds the command declaring a config. The generators are named as the cli names them, without the `jhipster:` prefix (`spring-boot`, `spring-boot:cache`; the generators of a blueprint keep their namespace), and `<generator>` takes that name or the namespace. Use it instead of reading `command.ts` files when you need the option catalog or the prompt order.\n\n## Big-picture architecture\n\n- CLI entry: `cli/jhipster.cjs` → `cli/cli.ts` (env checks) → `cli/program.ts` (commander parsing, generator/blueprint lookup) → spawns a Yeoman Environment which runs the selected generator.\n- Generator hierarchy (extend the lowest level that has what you need):\n  `GeneratorBaseCore` → `GeneratorBase` (blueprint composition) → `GeneratorApplication` (entity APIs).\n- Each generator lives in `generators/<name>/` with a fixed layout:\n  - `index.ts` — re-exports the generator as **default** plus the `command`. Required for the exports map in `package.json`.\n  - `generator.ts` — priority task groups (see below).\n  - `command.ts` — CLI args/options/configs (consumed by `parseJHipsterArguments` / `parseJHipsterConfigs` and by `program.ts` to build the CLI).\n  - `templates/` — EJS templates rendered during `writing`/`writingEntities`.\n  - `support/` — exported helpers (part of the public API via `./generators/*/support`).\n  - `internal/` — non-exported helpers.\n  - `resources/`, `jdl/` — supporting data / JDL specs.\n    Sub-generators nest under `generators/<parent>/generators/<child>/` and are exported via the same pattern.\n- Priority lifecycle (order matters, see `ARCHITECTURE.md` for full list): `initializing` → `prompting` → `configuring` → `composing` → `loading` → `preparing` → `configuringEachEntity` → `loadingEntities` → `preparingEachEntity` → `preparingEachEntityField` → `preparingEachEntityRelationship` → `default` → `writing` → `writingEntities` → `postWriting` → `install` → `end`. Use the matching `as<Priority>TaskGroup()` helper on the generator to get typed task signatures.\n- Blueprints (`BLUEPRINTS.md`): three flavors — replacement, side-by-side, standalone. `GeneratorBase` handles composition; blueprinted sub-generators are discovered and composed in `beforeQueue`.\n- `lib/` holds shared, **exported** code: `lib/jdl` (Chevrotain-based JDL parser), `lib/testing` (test harness, also importable as `#testing`), `lib/utils`, `lib/eslint`, `lib/ci`. Keep cross-generator logic here, not inside an individual generator.\n- `.blueprint/` is the in-repo \"dev blueprint\" enabled when running via JIT. It provides sub-generators like `generate-sample`, `describe-samples` (what each CI sample generates and the environment it runs on, `--json` for scripts), `github-build-matrix` (the matrix of a CI workflow, including the `daily-*` workflows of jhipster-daily-builds), `generate-generator`, `from-issue`, `update-spring-boot`, etc. — use these instead of ad-hoc scripts when generating samples for manual testing.\n- Build output in `dist/` is what gets published. The `exports` map in `package.json` defines the public API surface — don't import across generator `internal/` boundaries.\n- **Never edit `dist/` directly.** Modify source in `cli/`, `generators/`, `lib/`, etc., then rebuild with `npm run build` (or `npm run compile` for TS-only).\n\n## Key conventions\n\n- **ESM + TypeScript everywhere**; `\"type\": \"module\"` in `package.json`. Use `.ts`/`.mts`. Tests are `*.spec.ts` run by `expect-node` on node:test, importing `describe`, `it`, `expect` and `exnode` (mocks) from `expect-node`.\n- **Task groups**: define priorities as getters returning the result of `this.as<Priority>TaskGroup({...})`. Never call tasks directly — the Yeoman environment orchestrates them.\n- **Config access**: prefer `this.jhipsterConfig` (persists to `.yo-rc.json`), `this.jhipsterConfigWithDefaults` (read-only with defaults applied), and the `application`/`entity`/`field`/`relationship` context objects injected into tasks. Derived booleans (e.g. `entity.dtoMapstruct`, `field.fieldTypeInteger`) belong in `preparing*` priorities, not in templates.\n- **Writing files**: use `this.writeFiles({ blocks, context })` with `condition` functions on blocks rather than branching inside templates. Use `editFile(path, transform)` or the needle APIs on `source` in `postWriting` to inject into already-written files.\n- **Templates**: EJS (`.ejs`). Two-space indent for template logic; generated file's own rules apply to content. Factor shared fragments into `.ejs` sub-templates included via `<%- include('../path', { ... }) -%>`.\n- **Commit messages** (enforced at review): imperative present tense, lowercase first letter, no trailing dot, header ≤100 chars. Do not reference issues in commit messages: GitHub adds every commit that mentions an issue (on each push, rebase and amend) to the issue timeline, and agents create many commits. Reference the issue in the pull request description instead (`Fix #1234`). Do not use `[ci skip]` or `[skip ci]`, even for docs-only commits: it blocks the required CI workflows.\n- **Tests required** for every feature or bug fix. When behavior touches generated output, update/extend snapshots rather than asserting strings by hand.\n- **Path aliases** for tests: `#testing` → `lib/testing/index.ts`, `#test-support` → `test/support/index.ts`.\n- **Node version**: CI and local must match `engines` in `package.json`; avoid APIs only in newer releases.\n\n## Opening pull requests\n\n- Open pull requests as draft (`gh pr create --draft`).\n- Use `.github/PULL_REQUEST_TEMPLATE.md` as the body: the description in place of its first comment, and its checklist kept.\n- Leave the \"I have personally reviewed, understood, and tested the changes\" item unchecked. The user checks it after reviewing the changes, and marks the pull request ready for review.\n\n## Reviewing pull requests\n\n- Post reviews as comments (`gh pr review --comment` or `gh pr comment`). Never submit a \"request changes\" review: it blocks the merge, and that decision belongs to a human reviewer alone.\n","isInternal":false,"tokens":2223,"sizeBytes":8934},{"name":"ARCHITECTURE.md","path":"ARCHITECTURE.md","rawUrl":"https://raw.githubusercontent.com/jhipster/generator-jhipster/HEAD/ARCHITECTURE.md","title":"System Architecture & Module Boundaries","category":"project-spec","format":"markdown","content":"# JHipster architecture\n\n## Yeoman basis\n\nInternally, JHipster uses [Yeoman](https://yeoman.io) as the core. JHipster is the [most popular generator of all time](https://yeoman.io/generators/).\n\n## File structure\n\n- `.blueprint` - development blueprint, used to generate and manage samples\n- `.devcontainer` - vscode's devcontainer definitions\n- `.github` - github configuration\n- `.vscode` - vscode's configuration\n- `bin` - jit executable and helper\n- `cli` - (exported) cli implementation\n- `generators/*` - (exported) generators\n  - `command.ts` - cli options, cli arguments definitions\n  - `generator.ts` - generator implementation\n  - `index.ts` - generator exports. Must re-export generator as default export and the command\n  - `internal` - non-exported supporting libs\n  - `resources` - supporting resources\n  - `jdl` - generator's jdl specifications\n  - `support` - (exported) exported supporting libs\n  - `templates` - templates folder\n- `lib` - (exported) shared libraries, utilities, types and jdl parser\n- `rfcs` - [RFCs](CONTRIBUTING.md#rfcs)\n- `test` - package tests\n\n## Lifecycle\n\n- [CLI entry point](https://github.com/jhipster/generator-jhipster/blob/main/cli/jhipster.cjs)\n- [Basic environment validation](https://github.com/jhipster/generator-jhipster/blob/main/cli/cli.ts)\n- [Cli arguments parsing and Environment bootstrap](https://github.com/jhipster/generator-jhipster/blob/main/cli/program.ts)\n  - Lookup for generators and blueprints\n  - Build CLI options and arguments definition\n  - Parse options and arguments\n- Run Generator (start the Environment) passing options and arguments\n- Run every task from the highest precedence priority until there is no more pending task\n\n### Priorities\n\n#### Initializing (yeoman)\n\nInitial generator information.\n\n- say generator specific hello\n- initial environment checks\n- argument and options loading\n\n```ts\nget [Generator.INITIALIZING]() {\n  return this.asInitializingTaskGroup() {\n    sayHelloTask() {\n      this.log.info('Welcome to your generator');\n    },\n    envChecks() {\n      checkNode();\n      checkDocker();\n    },\n    async loadOptions() {\n      this.parseJHipsterArguments(command.arguments);\n      this.parseJHipsterConfigs(command.configs);\n    },\n  }\n}\n```\n\n#### Prompting (yeoman)\n\nPrompt for configuration.\n\n```ts\nget [Generator.PROMPTING]() {\n  return this.asPromptingTaskGroup() {\n    async prompting() {\n      await this.prompt(this.prepareQuestions(command.configs));\n    },\n  }\n}\n```\n\n#### Configuring (yeoman)\n\nCheck and fix configurations:\n\n```ts\nget [Generator.CONFIGURING]() {\n  return this.asConfiguringTaskGroup() {\n    checkConfig() {\n      if (this.jhipsterConfigWithDefaults.reactive && this.jhipsterConfigWithDefaults.cacheProvider !== 'no') {\n        this.log.warn(\"Reactive applications doesn't support cache. Disabling\");\n        this.jhipsterConfig.cacheProvider = 'no';\n      }\n    },\n  }\n}\n```\n\n#### Composing (base)\n\nCompose with other generators:\n\n```ts\nget [Generator.COMPOSING]() {\n  return this.asComposingTaskGroup() {\n    async composing() {\n      if (this.jhipsterConfigWithDefaults.clientFramework === 'angular') {\n        await this.composeWithJHipster('angular');\n      }\n    },\n  }\n}\n```\n\n#### Loading (base)\n\nLoad configuration:\n\n```ts\nget [Generator.LOADING]() {\n  return this.asLoadingTaskGroup() {\n    loading({ application }) {\n      application.myCustomConfig = this.jhipsterConfig.myCustomConfig;\n      application.myBlueprintCustomConfig = this.blueprintConfig.myBlueprintCustomConfig;\n    },\n  }\n}\n```\n\n#### Preparing (base)\n\nGenerate properties to improve understanding:\n\n```ts\nget [Generator.PREPARING]() {\n  return this.asPreparingTaskGroup() {\n    preparing({ application }) {\n      application.myCustomConfigFoo = this.jhipsterConfig.myCustomConfig === 'foo';\n      application.myCustomConfigBar = this.jhipsterConfig.myCustomConfig === 'bar';\n      application.myCustomConfigNo = !this.jhipsterConfig.myCustomConfig || this.jhipsterConfig.myCustomConfig === 'no';\n    },\n  }\n}\n```\n\n#### Custom objects (base-core)\n\nA generator declares its own objects with the `customObjects` feature, a list of objects (`{ name, before }`), and\nimplements a getter of each name giving an array of the objects. Each object gets three priorities before its `before`\npriority (the post preparing one by default, so after the preparing priority), in the order the objects are declared,\neach with the array of the objects (`service`):\n\n- `loading<Name>`: its tasks load the objects;\n- `preparing<Name>`: its tasks prepare them;\n- `postPreparing<Name>`: its tasks use the prepared objects.\n\nThe objects are written in two priorities of their own, with every custom object of the generator by name:\n`writingObjects` (`Generator.WRITING_OBJECTS`), after the writing priority and before the post writing one, and\n`postWritingObjects` (`Generator.POST_WRITING_OBJECTS`), after the post writing priority, with the `source` too. A\ngenerator declaring the names of its custom objects as the `customObjectNames` type gets them typed, with the type of\ntheir getters, through `asWritingObjectsTaskGroup` and `asPostWritingObjectsTaskGroup`.\n\nTo share the objects with the other generators declaring them, the getter reads them from the context\n(`getContextData`), and each phase runs for every generator before the next one. While the objects are prepared, a\ndefault (`mutateData`) reading a property not yet set waits for it, and is applied before the post preparing, like the\napplication ones. An application generator gives the phases the `application`, and they run before its entity priorities. A workspaces generator runs\nthem after its workspaces priorities, before the default priority, and gives them the `deployment` and its\n`applications`. `Generator.objectPriority(name, phase)` gives the priority of a phase:\n\n```ts\nexport default class extends Generator {\n  constructor(args, options, features) {\n    super(args, options, { ...features, customObjects: [{ name: 'service' }] });\n  }\n\n  get service() {\n    return this.getContextData('my-blueprint:service', { factory: () => [{}] });\n  }\n\n  get [Generator.objectPriority('service', 'loading')]() {\n    return {\n      loading({ service: [service] }) {\n        service.name = 'Book';\n      },\n    };\n  }\n\n  get [Generator.objectPriority('service', 'preparing')]() {\n    return {\n      preparing({ service }) {\n        for (const each of service) {\n          each.className = `${each.name}Service`;\n        }\n      },\n    };\n  }\n\n  // The names of the custom objects, for the writing objects tasks to get them typed.\n  declare readonly customObjectNames: readonly ['service'];\n\n  get [Generator.WRITING_OBJECTS]() {\n    return this.asWritingObjectsTaskGroup({\n      async writeServices({ application, service }) {\n        for (const each of service) {\n          await this.writeFiles({ sections: serviceFiles, context: { ...application, service: each } });\n        }\n      },\n    });\n  }\n}\n```\n\n#### Objects of the application (base-application)\n\nThe `objects` of the `.yo-rc.json` file declare the objects of an application by name, out of the `generator-jhipster`\nkey: each with its `type`, `documentation`, `annotations` and `fields`, a field with its `type`, `documentation`,\n`validations` and `annotations`. A type is a type of the JDL or an enum, a reference to an entity\n(`{ \"$ref\": \".jhipster/Order.json\" }`) or to an object (`{ \"$ref\": \"#/objects/Quote\" }`), or an array of the type of its\nitems:\n\n- `getObjectConfig(name)` gives the configuration of an object as declared;\n- `getObject(name)` gives the object, with its `name`, and the objects and the entities it references embedded in place of\n  their reference, each the same instance wherever it is referenced, an entity the one the application prepares; a\n  reference with other fields (`{ \"$ref\": \"#/objects/Quote\", \"documentation\": \"...\" }`) gives a copy of the referenced\n  one with the fields merged over it, the objects and the entities it references kept;\n- `findObjects(type)` gives the objects of a type, sorted by name.\n\nThe type of an object is the name of the custom object handling it: its getter gives `findObjects(<name>)`, and its\n`before` priority is the default one, the entities being prepared by then:\n\n```ts\nexport default class extends BaseApplicationGenerator {\n  constructor(args, options, features) {\n    super(args, options, { ...features, customObjects: [{ name: 'service', before: 'default' }] });\n  }\n\n  get service() {\n    return this.findObjects('service');\n  }\n}\n```\n\n#### Configuring each entity (base-application)\n\nConfigure and check entity's configuration:\n\n```ts\nget [Generator.CONFIGURING_EACH_ENTITY]() {\n  return this.asConfiguringEachEntityTaskGroup() {\n    configuring({ application, entityConfig }) {\n      if (application.searchEngineNo && entityConfig.searchEngine && entityConfig.searchEngine !== 'no') {\n        this.log.warn(\"Search engine cannot be enabled at entity because it's disabled at application\");\n        entityConfig.searchEngine = 'no';\n      }\n    },\n  }\n}\n```\n\n#### Loading entities (base-application)\n\nUsually empty the entire entity configuration is loaded by default.\n\n#### Preparing each entity (base-application)\n\nGenerate properties to improve understanding at the entity level:\n\n```ts\nget [Generator.PREPARING_EACH_ENTITY]() {\n  return this.asPreparingEachEntityTaskGroup() {\n    preparing({ application, entity }) {\n      entity.dtoMapstruct = entity.dto === 'mapstruct';\n    },\n  }\n}\n```\n\n#### Preparing each entity field (base-application)\n\nGenerate properties to improve understanding at the field level:\n\n```ts\nget [Generator.PREPARING_EACH_ENTITY_FIELD]() {\n  return this.asPreparingEachEntityFieldTaskGroup() {\n    preparing({ application, entity, field }) {\n      field.technologyFieldTypeIntegerMap = field.fieldType === 'Integer';\n    },\n  }\n}\n```\n\n#### Preparing each entity relationship (base-application)\n\nGenerate properties to improve understanding at the relationship level:\n\n```ts\nget [Generator.PREPARING_EACH_ENTITY_RELATIONSHIP]() {\n  return this.asPreparingEachEntityRelationshipTaskGroup() {\n    preparing({ application, entity, relationship }) {\n      relationship.technologyRelationshipDbName = relationship.relationshipTypeOneToOne ? 'foo' : 'bar';\n    },\n  };\n}\n```\n\n#### Default (yeoman)\n\nGenerate properties to improve understanding that depends on others' properties:\n\n```ts\nget [Generator.DEFAULT]() {\n  return this.asDefaultTaskGroup() {\n    preparing({ application, entities }) {\n      application.hasEntityFieldInteger = entities.some(entity => entity.fields.some(field => field.fieldTypeInteger));\n    },\n  };\n}\n```\n\n#### Writing (yeoman)\n\nWrite files to the in-memory file system.\n\nThere are a lot of APIs to write files, copy files, and delete files.\nThe `writeFiles()` method is the most used in official generators.\n\n```ts\nget [Generator.WRITING]() {\n  return this.asWritingTaskGroup({\n    async writingTask({ application }) {\n      await this.writeFiles({\n        blocks: [\n          {\n            condition: ctx => ctx.shouldWrite,\n            templates: ['template.file'],\n          }\n        ],\n        context: application,\n      });\n    },\n  });\n}\n```\n\n#### Writing entities (base-application)\n\nWrite entity files to the in-memory file system.\n\nWriting entities is a separate priority to keep the workflow sane when using options like `--skip-application` and `--single-entity`.\n\n```ts\nget [Generator.WRITING_ENTITIES]() {\n  return this.asWritingTaskGroup({\n    async writingTask({ application, entities }) {\n      for (const entity of entities) {\n        await this.writeFiles({\n          blocks: [\n            {\n              condition: ctx => ctx.shouldWrite,\n              templates: ['entity.template.file'],\n            }\n          ],\n          context: { ...application, ...entity },\n        });\n      }\n    },\n  });\n}\n```\n\n#### Post writing (base)\n\nInjects code in the generated source.\n\n##### Injecting code with provided apis (needles)\n\nJHipster adds APIs for code injection:\n\n```ts\nget [Generator.POST_WRITING]() {\n  return this.asPostWritingTaskGroup({\n    postWritingTask({ source }) {\n      source.someProvidedInjectionApi({ code: 'some code' });\n    }\n  });\n}\n```\n\n##### Custom code injection\n\nEvery file can be edited manually.\n\n```ts\nget [Generator.POST_WRITING]() {\n  return this.asPostWritingTaskGroup({\n    postWritingTask({ source }) {\n      this.editFile('path/to/some/file', content => content.replaceAll('some content', 'another content'));\n    }\n  });\n}\n```\n\n#### Install (yeoman)\n\nUsually empty.\nInstall task is queued by detecting `package.json` changes.\n\n#### End (yeoman)\n\nPrint generator result and info:\n\n```ts\nget [Generator.END]() {\n  return this.asEndTaskGroup() {\n    preparing({ application }) {\n      this.log.success('Tech application generated successfully');\n      this.log.log(`Start the application running 'npm run start:app'`);\n    },\n  };\n}\n```\n\n## Blueprints\n\nBlueprint support allows customizing the generation process.\n\nA Blueprint package can include any number of sub-generators, each can be a replacement blueprint, a side-by-side blueprint, or a stand alone blueprint.\n\n- Normal blueprints will completely replace the blueprinted sub-generator with a replacement.\n- Side by side blueprint doesn't change the generation process, it customizes it.\n- Stand alone blueprint doesn't hook into a sub-generator.\n\nExamples:\n\n- [Micronaut](https://github.com/jhipster/generator-jhipster-micronaut) has a [server](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/server) replacement blueprint, an [angular](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/angular), [client](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/client), [cypress](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/cypress), [docker](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/docker) and [react](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/react) side by side blueprints, and a [micronaut-cache](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/micronaut-cache) stand alone blueprint\n\nMore information can be found at:\n\n[Extending and customizing](https://www.jhipster.tech/modules/extending-and-customizing/)\n[Creating a stand alone Blueprint](https://www.jhipster.tech/modules/creating-a-module/)\n[Creating a blueprint](https://www.jhipster.tech/modules/creating-a-blueprint/)\n\n### Blueprint scope\n\nA blueprint belongs to the project whose `.yo-rc.json` stores it ([RFC-7](rfcs/7-jhipster-rfc-blueprint-scope.md)):\n\n- `--blueprints` applies to the project the command runs in, `--global-blueprints` to every project the run generates, the ones in other folders included.\n- A generator composed in another folder (`composeWithJHipster` with a `destinationRoot`) uses the blueprints of the `.yo-rc.json` of that folder, unless they are passed to it.\n- The `jdl` generator is not blueprinted: the applications of a jdl use the blueprints their jdl declares.\n\n### Blueprint lifecycle\n\n#### Replacement blueprint\n\n| Priority     | Blueprinted sub-gen                   | Blueprint sub-gen              |\n| ------------ | ------------------------------------- | ------------------------------ |\n| beforeQueue  | composes with blueprints/dependencies | composes with dependencies     |\n| initializing | X                                     | replacement initializing tasks |\n| prompting    | X                                     | replacement prompting tasks    |\n| ...          | X                                     | ...                            |\n\n#### Side by side blueprint\n\n| Priority     | Blueprinted sub-gen                   | Blueprint sub-gen             | Another blueprint sub-gen     |\n| ------------ | ------------------------------------- | ----------------------------- | ----------------------------- |\n| beforeQueue  | composes with blueprints/dependencies | composes with dependencies    | composes with dependencies    |\n| initializing | initializing tasks                    | additional initializing tasks | additional initializing tasks |\n| prompting    | prompting tasks                       | additional prompting tasks    | additional prompting tasks    |\n| ...          | ...                                   | ...                           | ...                           |\n\n#### Stand alone blueprint\n\n| Priority     | Blueprint sub-gen          |\n| ------------ | -------------------------- |\n| beforeQueue  | composes with dependencies |\n| initializing | initializing tasks         |\n| prompting    | prompting tasks            |\n| ...          | ...                        |\n\n## Generator Hierarchy\n\n### GeneratorBaseCore\n\nAdds custom APIs to `yeoman-generator` and customizes the behavior.\n\n### GeneratorBase\n\nAdds Blueprint composing APIs.\n\n### GeneratorApplication\n\nAdds Entities related apis.\n","isInternal":false,"tokens":3877,"sizeBytes":17259},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/jhipster/generator-jhipster/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"See [`AGENTS.md`](./AGENTS.md) at the repository root for the canonical AI agent instructions for this codebase.\n","isInternal":false,"tokens":26,"sizeBytes":113},{"name":"copilot-instructions.md","path":".github/copilot-instructions.md","rawUrl":"https://raw.githubusercontent.com/jhipster/generator-jhipster/HEAD/.github/copilot-instructions.md","title":"GitHub Copilot Instructions","category":"copilot-instructions","format":"markdown","content":"See [`AGENTS.md`](../AGENTS.md) at the repository root for the canonical AI agent instructions for this codebase.\n","isInternal":false,"tokens":26,"sizeBytes":114}],"systemPromptSnippet":"<yakaai_skills repo=\"jhipster/generator-jhipster\">\n<!-- File: AGENTS.md (Tokens: ~2223 | Category: root-instruction) -->\n# AI agent instructions for generator-jhipster\n\nJHipster is a Yeoman-based code generator (TypeScript, ESM, Node — see `engines` in `package.json` for the required version) that scaffolds Spring Boot + Angular/React/Vue applications. See `ARCHITECTURE.md`, `BLUEPRINTS.md`, `DEVELOPMENT.md`, and `JDL.md` (the reference of the JDL language) for background context.\n\n**Trust order when docs disagree:** `package.json` scripts and the current source tree are the source of truth. Prose docs (including `DEVELOPMENT.md`) may be stale — verify commands against `package.json` before running them.\n\n## Build, lint, test\n\n- Install: `npm ci` (also compiles via `prepare` → `build`).\n- Build: `npm run build` (runs `clean` → `tsc` of TypeScript 7, the `typescript7` alias → copy non-TS template files + `.d.ts` to `dist/`, then `bin/fix-bin.cjs`). Use `npm run compile` alone for a faster TS-only recompile.\n- Type-check tests: `npm run check-types` (`tsc -p tsconfig.spec.json` of TypeScript 7; the `typescript` package stays TypeScript 6, for typescript-eslint).\n- Lint: `npm run lint` (eslint, `--max-warnings 5`). Auto-fix: `npm run lint-fix` (runs eslint `--fix` then `prettier --write`).\n- Prettier check/format: `npm run prettier:check` / `npm run prettier:format`.\n- Full test (lint + type-check + tests): `npm test`. Runs expect-node (`exnode`) over the spec files of `expect-node.config.ts` (`test generators cli .blueprint lib`) with `--forbid-only`.\n- Fast test (skip lint/type-check): `npx exnode`.\n- Single test files / directories: `npx exnode <path>...` (add `--workers 0` to run each file in a process of its own).\n- Update snapshots: `npm run update-snapshot -- <path>...` or `npm run update-snapshots` (all). Equivalent: `npx exnode --update-snapshot <path>...`.\n- JDL-only tests: `npm run jdl:test` (watch: `npm run jdl:test-watch`).\n\nSnapshots live next to specs as `*.snap` and are committed. Never hand-edit them — regenerate.\n\n**Always run `npm run prettier:format` (or `npm run lint-fix`) before committing** so changes match the project's Prettier configuration. CI will fail otherwise.\n\n## Running the generator locally\n\nTwo options (see `DEVELOPMENT.md`):\n\n- JIT: `alias jhipster=\"$PWD/bin/jhipster.cjs\"` — no build step needed.\n- Linked build: `npm run build && npm link`; rebuild after changes.\n  On generated apps use `jhipster --skip-jhipster-dependencies` plus `npm link generator-jhipster` so the dev version is picked up. `jhipster --install-path` shows which copy is active.\n\n`jhipster describe` prints the generators; `jhipster describe <generator> [--no-imports] [--prompts] [--json]` the arguments, options, `.yo-rc.json` keys, choices, defaults, derived properties and prompts of a command (model in `lib/command/describe-command.ts`, generator resolution in `lib/resolver/`); `jhipster describe --config <name>` finds the command declaring a config. The generators are named as the cli names them, without the `jhipster:` prefix (`spring-boot`, `spring-boot:cache`; the generators of a blueprint keep their namespace), and `<generator>` takes that name or the namespace. Use it instead of reading `command.ts` files when you need the option catalog or the prompt order.\n\n## Big-picture architecture\n\n- CLI entry: `cli/jhipster.cjs` → `cli/cli.ts` (env checks) → `cli/program.ts` (commander parsing, generator/blueprint lookup) → spawns a Yeoman Environment which runs the selected generator.\n- Generator hierarchy (extend the lowest level that has what you need):\n  `GeneratorBaseCore` → `GeneratorBase` (blueprint composition) → `GeneratorApplication` (entity APIs).\n- Each generator lives in `generators/<name>/` with a fixed layout:\n  - `index.ts` — re-exports the generator as **default** plus the `command`. Required for the exports map in `package.json`.\n  - `generator.ts` — priority task groups (see below).\n  - `command.ts` — CLI args/options/configs (consumed by `parseJHipsterArguments` / `parseJHipsterConfigs` and by `program.ts` to build the CLI).\n  - `templates/` — EJS templates rendered during `writing`/`writingEntities`.\n  - `support/` — exported helpers (part of the public API via `./generators/*/support`).\n  - `internal/` — non-exported helpers.\n  - `resources/`, `jdl/` — supporting data / JDL specs.\n    Sub-generators nest under `generators/<parent>/generators/<child>/` and are exported via the same pattern.\n- Priority lifecycle (order matters, see `ARCHITECTURE.md` for full list): `initializing` → `prompting` → `configuring` → `composing` → `loading` → `preparing` → `configuringEachEntity` → `loadingEntities` → `preparingEachEntity` → `preparingEachEntityField` → `preparingEachEntityRelationship` → `default` → `writing` → `writingEntities` → `postWriting` → `install` → `end`. Use the matching `as<Priority>TaskGroup()` helper on the generator to get typed task signatures.\n- Blueprints (`BLUEPRINTS.md`): three flavors — replacement, side-by-side, standalone. `GeneratorBase` handles composition; blueprinted sub-generators are discovered and composed in `beforeQueue`.\n- `lib/` holds shared, **exported** code: `lib/jdl` (Chevrotain-based JDL parser), `lib/testing` (test harness, also importable as `#testing`), `lib/utils`, `lib/eslint`, `lib/ci`. Keep cross-generator logic here, not inside an individual generator.\n- `.blueprint/` is the in-repo \"dev blueprint\" enabled when running via JIT. It provides sub-generators like `generate-sample`, `describe-samples` (what each CI sample generates and the environment it runs on, `--json` for scripts), `github-build-matrix` (the matrix of a CI workflow, including the `daily-*` workflows of jhipster-daily-builds), `generate-generator`, `from-issue`, `update-spring-boot`, etc. — use these instead of ad-hoc scripts when generating samples for manual testing.\n- Build output in `dist/` is what gets published. The `exports` map in `package.json` defines the public API surface — don't import across generator `internal/` boundaries.\n- **Never edit `dist/` directly.** Modify source in `cli/`, `generators/`, `lib/`, etc., then rebuild with `npm run build` (or `npm run compile` for TS-only).\n\n## Key conventions\n\n- **ESM + TypeScript everywhere**; `\"type\": \"module\"` in `package.json`. Use `.ts`/`.mts`. Tests are `*.spec.ts` run by `expect-node` on node:test, importing `describe`, `it`, `expect` and `exnode` (mocks) from `expect-node`.\n- **Task groups**: define priorities as getters returning the result of `this.as<Priority>TaskGroup({...})`. Never call tasks directly — the Yeoman environment orchestrates them.\n- **Config access**: prefer `this.jhipsterConfig` (persists to `.yo-rc.json`), `this.jhipsterConfigWithDefaults` (read-only with defaults applied), and the `application`/`entity`/`field`/`relationship` context objects injected into tasks. Derived booleans (e.g. `entity.dtoMapstruct`, `field.fieldTypeInteger`) belong in `preparing*` priorities, not in templates.\n- **Writing files**: use `this.writeFiles({ blocks, context })` with `condition` functions on blocks rather than branching inside templates. Use `editFile(path, transform)` or the needle APIs on `source` in `postWriting` to inject into already-written files.\n- **Templates**: EJS (`.ejs`). Two-space indent for template logic; generated file's own rules apply to content. Factor shared fragments into `.ejs` sub-templates included via `<%- include('../path', { ... }) -%>`.\n- **Commit messages** (enforced at review): imperative present tense, lowercase first letter, no trailing dot, header ≤100 chars. Do not reference issues in commit messages: GitHub adds every commit that mentions an issue (on each push, rebase and amend) to the issue timeline, and agents create many commits. Reference the issue in the pull request description instead (`Fix #1234`). Do not use `[ci skip]` or `[skip ci]`, even for docs-only commits: it blocks the required CI workflows.\n- **Tests required** for every feature or bug fix. When behavior touches generated output, update/extend snapshots rather than asserting strings by hand.\n- **Path aliases** for tests: `#testing` → `lib/testing/index.ts`, `#test-support` → `test/support/index.ts`.\n- **Node version**: CI and local must match `engines` in `package.json`; avoid APIs only in newer releases.\n\n## Opening pull requests\n\n- Open pull requests as draft (`gh pr create --draft`).\n- Use `.github/PULL_REQUEST_TEMPLATE.md` as the body: the description in place of its first comment, and its checklist kept.\n- Leave the \"I have personally reviewed, understood, and tested the changes\" item unchecked. The user checks it after reviewing the changes, and marks the pull request ready for review.\n\n## Reviewing pull requests\n\n- Post reviews as comments (`gh pr review --comment` or `gh pr comment`). Never submit a \"request changes\" review: it blocks the merge, and that decision belongs to a human reviewer alone.\n\n<!-- File: ARCHITECTURE.md (Tokens: ~3877 | Category: project-spec) -->\n# JHipster architecture\n\n## Yeoman basis\n\nInternally, JHipster uses [Yeoman](https://yeoman.io) as the core. JHipster is the [most popular generator of all time](https://yeoman.io/generators/).\n\n## File structure\n\n- `.blueprint` - development blueprint, used to generate and manage samples\n- `.devcontainer` - vscode's devcontainer definitions\n- `.github` - github configuration\n- `.vscode` - vscode's configuration\n- `bin` - jit executable and helper\n- `cli` - (exported) cli implementation\n- `generators/*` - (exported) generators\n  - `command.ts` - cli options, cli arguments definitions\n  - `generator.ts` - generator implementation\n  - `index.ts` - generator exports. Must re-export generator as default export and the command\n  - `internal` - non-exported supporting libs\n  - `resources` - supporting resources\n  - `jdl` - generator's jdl specifications\n  - `support` - (exported) exported supporting libs\n  - `templates` - templates folder\n- `lib` - (exported) shared libraries, utilities, types and jdl parser\n- `rfcs` - [RFCs](CONTRIBUTING.md#rfcs)\n- `test` - package tests\n\n## Lifecycle\n\n- [CLI entry point](https://github.com/jhipster/generator-jhipster/blob/main/cli/jhipster.cjs)\n- [Basic environment validation](https://github.com/jhipster/generator-jhipster/blob/main/cli/cli.ts)\n- [Cli arguments parsing and Environment bootstrap](https://github.com/jhipster/generator-jhipster/blob/main/cli/program.ts)\n  - Lookup for generators and blueprints\n  - Build CLI options and arguments definition\n  - Parse options and arguments\n- Run Generator (start the Environment) passing options and arguments\n- Run every task from the highest precedence priority until there is no more pending task\n\n### Priorities\n\n#### Initializing (yeoman)\n\nInitial generator information.\n\n- say generator specific hello\n- initial environment checks\n- argument and options loading\n\n```ts\nget [Generator.INITIALIZING]() {\n  return this.asInitializingTaskGroup() {\n    sayHelloTask() {\n      this.log.info('Welcome to your generator');\n    },\n    envChecks() {\n      checkNode();\n      checkDocker();\n    },\n    async loadOptions() {\n      this.parseJHipsterArguments(command.arguments);\n      this.parseJHipsterConfigs(command.configs);\n    },\n  }\n}\n```\n\n#### Prompting (yeoman)\n\nPrompt for configuration.\n\n```ts\nget [Generator.PROMPTING]() {\n  return this.asPromptingTaskGroup() {\n    async prompting() {\n      await this.prompt(this.prepareQuestions(command.configs));\n    },\n  }\n}\n```\n\n#### Configuring (yeoman)\n\nCheck and fix configurations:\n\n```ts\nget [Generator.CONFIGURING]() {\n  return this.asConfiguringTaskGroup() {\n    checkConfig() {\n      if (this.jhipsterConfigWithDefaults.reactive && this.jhipsterConfigWithDefaults.cacheProvider !== 'no') {\n        this.log.warn(\"Reactive applications doesn't support cache. Disabling\");\n        this.jhipsterConfig.cacheProvider = 'no';\n      }\n    },\n  }\n}\n```\n\n#### Composing (base)\n\nCompose with other generators:\n\n```ts\nget [Generator.COMPOSING]() {\n  return this.asComposingTaskGroup() {\n    async composing() {\n      if (this.jhipsterConfigWithDefaults.clientFramework === 'angular') {\n        await this.composeWithJHipster('angular');\n      }\n    },\n  }\n}\n```\n\n#### Loading (base)\n\nLoad configuration:\n\n```ts\nget [Generator.LOADING]() {\n  return this.asLoadingTaskGroup() {\n    loading({ application }) {\n      application.myCustomConfig = this.jhipsterConfig.myCustomConfig;\n      application.myBlueprintCustomConfig = this.blueprintConfig.myBlueprintCustomConfig;\n    },\n  }\n}\n```\n\n#### Preparing (base)\n\nGenerate properties to improve understanding:\n\n```ts\nget [Generator.PREPARING]() {\n  return this.asPreparingTaskGroup() {\n    preparing({ application }) {\n      application.myCustomConfigFoo = this.jhipsterConfig.myCustomConfig === 'foo';\n      application.myCustomConfigBar = this.jhipsterConfig.myCustomConfig === 'bar';\n      application.myCustomConfigNo = !this.jhipsterConfig.myCustomConfig || this.jhipsterConfig.myCustomConfig === 'no';\n    },\n  }\n}\n```\n\n#### Custom objects (base-core)\n\nA generator declares its own objects with the `customObjects` feature, a list of objects (`{ name, before }`), and\nimplements a getter of each name giving an array of the objects. Each object gets three priorities before its `before`\npriority (the post preparing one by default, so after the preparing priority), in the order the objects are declared,\neach with the array of the objects (`service`):\n\n- `loading<Name>`: its tasks load the objects;\n- `preparing<Name>`: its tasks prepare them;\n- `postPreparing<Name>`: its tasks use the prepared objects.\n\nThe objects are written in two priorities of their own, with every custom object of the generator by name:\n`writingObjects` (`Generator.WRITING_OBJECTS`), after the writing priority and before the post writing one, and\n`postWritingObjects` (`Generator.POST_WRITING_OBJECTS`), after the post writing priority, with the `source` too. A\ngenerator declaring the names of its custom objects as the `customObjectNames` type gets them typed, with the type of\ntheir getters, through `asWritingObjectsTaskGroup` and `asPostWritingObjectsTaskGroup`.\n\nTo share the objects with the other generators declaring them, the getter reads them from the context\n(`getContextData`), and each phase runs for every generator before the next one. While the objects are prepared, a\ndefault (`mutateData`) reading a property not yet set waits for it, and is applied before the post preparing, like the\napplication ones. An application generator gives the phases the `application`, and they run before its entity priorities. A workspaces generator runs\nthem after its workspaces priorities, before the default priority, and gives them the `deployment` and its\n`applications`. `Generator.objectPriority(name, phase)` gives the priority of a phase:\n\n```ts\nexport default class extends Generator {\n  constructor(args, options, features) {\n    super(args, options, { ...features, customObjects: [{ name: 'service' }] });\n  }\n\n  get service() {\n    return this.getContextData('my-blueprint:service', { factory: () => [{}] });\n  }\n\n  get [Generator.objectPriority('service', 'loading')]() {\n    return {\n      loading({ service: [service] }) {\n        service.name = 'Book';\n      },\n    };\n  }\n\n  get [Generator.objectPriority('service', 'preparing')]() {\n    return {\n      preparing({ service }) {\n        for (const each of service) {\n          each.className = `${each.name}Service`;\n        }\n      },\n    };\n  }\n\n  // The names of the custom objects, for the writing objects tasks to get them typed.\n  declare readonly customObjectNames: readonly ['service'];\n\n  get [Generator.WRITING_OBJECTS]() {\n    return this.asWritingObjectsTaskGroup({\n      async writeServices({ application, service }) {\n        for (const each of service) {\n          await this.writeFiles({ sections: serviceFiles, context: { ...application, service: each } });\n        }\n      },\n    });\n  }\n}\n```\n\n#### Objects of the application (base-application)\n\nThe `objects` of the `.yo-rc.json` file declare the objects of an application by name, out of the `generator-jhipster`\nkey: each with its `type`, `documentation`, `annotations` and `fields`, a field with its `type`, `documentation`,\n`validations` and `annotations`. A type is a type of the JDL or an enum, a reference to an entity\n(`{ \"$ref\": \".jhipster/Order.json\" }`) or to an object (`{ \"$ref\": \"#/objects/Quote\" }`), or an array of the type of its\nitems:\n\n- `getObjectConfig(name)` gives the configuration of an object as declared;\n- `getObject(name)` gives the object, with its `name`, and the objects and the entities it references embedded in place of\n  their reference, each the same instance wherever it is referenced, an entity the one the application prepares; a\n  reference with other fields (`{ \"$ref\": \"#/objects/Quote\", \"documentation\": \"...\" }`) gives a copy of the referenced\n  one with the fields merged over it, the objects and the entities it references kept;\n- `findObjects(type)` gives the objects of a type, sorted by name.\n\nThe type of an object is the name of the custom object handling it: its getter gives `findObjects(<name>)`, and its\n`before` priority is the default one, the entities being prepared by then:\n\n```ts\nexport default class extends BaseApplicationGenerator {\n  constructor(args, options, features) {\n    super(args, options, { ...features, customObjects: [{ name: 'service', before: 'default' }] });\n  }\n\n  get service() {\n    return this.findObjects('service');\n  }\n}\n```\n\n#### Configuring each entity (base-application)\n\nConfigure and check entity's configuration:\n\n```ts\nget [Generator.CONFIGURING_EACH_ENTITY]() {\n  return this.asConfiguringEachEntityTaskGroup() {\n    configuring({ application, entityConfig }) {\n      if (application.searchEngineNo && entityConfig.searchEngine && entityConfig.searchEngine !== 'no') {\n        this.log.warn(\"Search engine cannot be enabled at entity because it's disabled at application\");\n        entityConfig.searchEngine = 'no';\n      }\n    },\n  }\n}\n```\n\n#### Loading entities (base-application)\n\nUsually empty the entire entity configuration is loaded by default.\n\n#### Preparing each entity (base-application)\n\nGenerate properties to improve understanding at the entity level:\n\n```ts\nget [Generator.PREPARING_EACH_ENTITY]() {\n  return this.asPreparingEachEntityTaskGroup() {\n    preparing({ application, entity }) {\n      entity.dtoMapstruct = entity.dto === 'mapstruct';\n    },\n  }\n}\n```\n\n#### Preparing each entity field (base-application)\n\nGenerate properties to improve understanding at the field level:\n\n```ts\nget [Generator.PREPARING_EACH_ENTITY_FIELD]() {\n  return this.asPreparingEachEntityFieldTaskGroup() {\n    preparing({ application, entity, field }) {\n      field.technologyFieldTypeIntegerMap = field.fieldType === 'Integer';\n    },\n  }\n}\n```\n\n#### Preparing each entity relationship (base-application)\n\nGenerate properties to improve understanding at the relationship level:\n\n```ts\nget [Generator.PREPARING_EACH_ENTITY_RELATIONSHIP]() {\n  return this.asPreparingEachEntityRelationshipTaskGroup() {\n    preparing({ application, entity, relationship }) {\n      relationship.technologyRelationshipDbName = relationship.relationshipTypeOneToOne ? 'foo' : 'bar';\n    },\n  };\n}\n```\n\n#### Default (yeoman)\n\nGenerate properties to improve understanding that depends on others' properties:\n\n```ts\nget [Generator.DEFAULT]() {\n  return this.asDefaultTaskGroup() {\n    preparing({ application, entities }) {\n      application.hasEntityFieldInteger = entities.some(entity => entity.fields.some(field => field.fieldTypeInteger));\n    },\n  };\n}\n```\n\n#### Writing (yeoman)\n\nWrite files to the in-memory file system.\n\nThere are a lot of APIs to write files, copy files, and delete files.\nThe `writeFiles()` method is the most used in official generators.\n\n```ts\nget [Generator.WRITING]() {\n  return this.asWritingTaskGroup({\n    async writingTask({ application }) {\n      await this.writeFiles({\n        blocks: [\n          {\n            condition: ctx => ctx.shouldWrite,\n            templates: ['template.file'],\n          }\n        ],\n        context: application,\n      });\n    },\n  });\n}\n```\n\n#### Writing entities (base-application)\n\nWrite entity files to the in-memory file system.\n\nWriting entities is a separate priority to keep the workflow sane when using options like `--skip-application` and `--single-entity`.\n\n```ts\nget [Generator.WRITING_ENTITIES]() {\n  return this.asWritingTaskGroup({\n    async writingTask({ application, entities }) {\n      for (const entity of entities) {\n        await this.writeFiles({\n          blocks: [\n            {\n              condition: ctx => ctx.shouldWrite,\n              templates: ['entity.template.file'],\n            }\n          ],\n          context: { ...application, ...entity },\n        });\n      }\n    },\n  });\n}\n```\n\n#### Post writing (base)\n\nInjects code in the generated source.\n\n##### Injecting code with provided apis (needles)\n\nJHipster adds APIs for code injection:\n\n```ts\nget [Generator.POST_WRITING]() {\n  return this.asPostWritingTaskGroup({\n    postWritingTask({ source }) {\n      source.someProvidedInjectionApi({ code: 'some code' });\n    }\n  });\n}\n```\n\n##### Custom code injection\n\nEvery file can be edited manually.\n\n```ts\nget [Generator.POST_WRITING]() {\n  return this.asPostWritingTaskGroup({\n    postWritingTask({ source }) {\n      this.editFile('path/to/some/file', content => content.replaceAll('some content', 'another content'));\n    }\n  });\n}\n```\n\n#### Install (yeoman)\n\nUsually empty.\nInstall task is queued by detecting `package.json` changes.\n\n#### End (yeoman)\n\nPrint generator result and info:\n\n```ts\nget [Generator.END]() {\n  return this.asEndTaskGroup() {\n    preparing({ application }) {\n      this.log.success('Tech application generated successfully');\n      this.log.log(`Start the application running 'npm run start:app'`);\n    },\n  };\n}\n```\n\n## Blueprints\n\nBlueprint support allows customizing the generation process.\n\nA Blueprint package can include any number of sub-generators, each can be a replacement blueprint, a side-by-side blueprint, or a stand alone blueprint.\n\n- Normal blueprints will completely replace the blueprinted sub-generator with a replacement.\n- Side by side blueprint doesn't change the generation process, it customizes it.\n- Stand alone blueprint doesn't hook into a sub-generator.\n\nExamples:\n\n- [Micronaut](https://github.com/jhipster/generator-jhipster-micronaut) has a [server](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/server) replacement blueprint, an [angular](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/angular), [client](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/client), [cypress](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/cypress), [docker](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/docker) and [react](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/react) side by side blueprints, and a [micronaut-cache](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/micronaut-cache) stand alone blueprint\n\nMore information can be found at:\n\n[Extending and customizing](https://www.jhipster.tech/modules/extending-and-customizing/)\n[Creating a stand alone Blueprint](https://www.jhipster.tech/modules/creating-a-module/)\n[Creating a blueprint](https://www.jhipster.tech/modules/creating-a-blueprint/)\n\n### Blueprint scope\n\nA blueprint belongs to the project whose `.yo-rc.json` stores it ([RFC-7](rfcs/7-jhipster-rfc-blueprint-scope.md)):\n\n- `--blueprints` applies to the project the command runs in, `--global-blueprints` to every project the run generates, the ones in other folders included.\n- A generator composed in another folder (`composeWithJHipster` with a `destinationRoot`) uses the blueprints of the `.yo-rc.json` of that folder, unless they are passed to it.\n- The `jdl` generator is not blueprinted: the applications of a jdl use the blueprints their jdl declares.\n\n### Blueprint lifecycle\n\n#### Replacement blueprint\n\n| Priority     | Blueprinted sub-gen                   | Blueprint sub-gen              |\n| ------------ | ------------------------------------- | ------------------------------ |\n| beforeQueue  | composes with blueprints/dependencies | composes with dependencies     |\n| initializing | X                                     | replacement initializing tasks |\n| prompting    | X                                     | replacement prompting tasks    |\n| ...          | X                                     | ...                            |\n\n#### Side by side blueprint\n\n| Priority     | Blueprinted sub-gen                   | Blueprint sub-gen             | Another blueprint sub-gen     |\n| ------------ | ------------------------------------- | ----------------------------- | ----------------------------- |\n| beforeQueue  | composes with blueprints/dependencies | composes with dependencies    | composes with dependencies    |\n| initializing | initializing tasks                    | additional initializing tasks | additional initializing tasks |\n| prompting    | prompting tasks                       | additional prompting tasks    | additional prompting tasks    |\n| ...          | ...                                   | ...                           | ...                           |\n\n#### Stand alone blueprint\n\n| Priority     | Blueprint sub-gen          |\n| ------------ | -------------------------- |\n| beforeQueue  | composes with dependencies |\n| initializing | initializing tasks         |\n| prompting    | prompting tasks            |\n| ...          | ...                        |\n\n## Generator Hierarchy\n\n### GeneratorBaseCore\n\nAdds custom APIs to `yeoman-generator` and customizes the behavior.\n\n### GeneratorBase\n\nAdds Blueprint composing APIs.\n\n### GeneratorApplication\n\nAdds Entities related apis.\n\n<!-- File: CLAUDE.md (Tokens: ~26 | Category: claude-rule) -->\nSee [`AGENTS.md`](./AGENTS.md) at the repository root for the canonical AI agent instructions for this codebase.\n\n<!-- File: .github/copilot-instructions.md (Tokens: ~26 | Category: copilot-instructions) -->\nSee [`AGENTS.md`](../AGENTS.md) at the repository root for the canonical AI agent instructions for this codebase.\n</yakaai_skills>"}