diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 00000000000..5054fa4cac8 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,387 @@ +# JHipster architecture + +## Yeoman basis + +Internally, JHipster uses [Yeoman](https://yeoman.io) as the core. JHipster is the [most popular generator of all time](https://yeoman.io/generators/). + +## File structure + +- `.blueprint` - development blueprint, used to generate and manage samples +- `.devcontainer` - vscode's devcontainer definitions +- `.github` - github configuration +- `.vscode` - vscode's configuration +- `bin` - jit executable and helper +- `cli` - (exported) cli implementation +- `generators/*` - (exported) generators + - `command.m[tj]s` - cli options, cli arguments definitions + - `generator.m[tj]s` - generator implementation + - `index.m[tj]s` - generator exports. Must re-export generator as default export and the command + - `internal` - non-exported supporting libs + - `resources` - supporting resources + - `jdl` - generator's jdl specifications + - `support` - (exported) exported supporting libs + - `templates` - templates folder +- `jdl` - (exported) jdl parser implementation +- `rfcs` - (RFCs)[CONTRIBUTING.md#rfcs] +- `test` - package tests +- `test-integration` - CI related stuff. Samples, scripts. + +## Lifecycle + +- [CLI entry point](https://github.com/jhipster/generator-jhipster/blob/main/cli/jhipster.cjs) +- [Basic environment validation](https://github.com/jhipster/generator-jhipster/blob/main/cli/cli.mjs) +- [Cli arguments parsing and Environment bootstrap](https://github.com/jhipster/generator-jhipster/blob/main/cli/program.mjs) + - Lookup for generators and blueprints + - Build CLI options and arguments definition + - Parse options and arguments +- Run Generator (start the Environment) passing options and arguments +- Run every task from the highest precedence priority until there is no more pending task + +### Priorities + +#### Initializing (yeoman) + +Initial generator information. + +- say generator specific hello +- initial environment checks +- argument and options loading + +```ts +get [Generator.INITIALIZING]() { + return this.asInitializingTaskGroup() { + sayHelloTask() { + this.log.info('Welcome to your generator'); + }, + envChecks() { + checkNode(); + checkDocker(); + }, + async loadOptions() { + this.parseJHipsterArguments(command.arguments); + this.parseJHipsterOptions(command.options); + }, + } +} +``` + +#### Prompting (yeoman) + +Prompt for configuration. + +```ts +get [Generator.PROMPTING]() { + return this.asPromptingTaskGroup() { + async prompting() { + await this.prompt(this.prepareQuestions(command.configs)); + }, + } +} +``` + +#### Configuring (yeoman) + +Check and fix configurations: + +```ts +get [Generator.CONFIGURING]() { + return this.asConfiguringTaskGroup() { + checkConfig() { + if (this.jhipsterConfigWithDefaults.reactive && this.jhipsterConfigWithDefaults.cacheProvider !== 'no') { + this.log.warn("Reactive applications doesn't support cache. Disabling"); + this.jhipsterConfig.cacheProvider = 'no'; + } + }, + } +} +``` + +#### Composing (base) + +Compose with other generators: + +```ts +get [Generator.COMPOSING]() { + return this.asComposingTaskGroup() { + async composing() { + if (this.jhipsterConfigWithDefaults.clientFramework === 'angular') { + await this.composeWithJHipster('angular'); + } + }, + } +} +``` + +#### Loading (base) + +Load configuration: + +```ts +get [Generator.LOADING]() { + return this.asLoadingTaskGroup() { + loading({ application }) { + application.myCustomConfig = this.jhipsterConfig.myCustomConfig; + application.myBlueprintCustomConfig = this.blueprintConfig.myBlueprintCustomConfig; + }, + } +} +``` + +#### Preparing (base) + +Generate properties to improve understanding: + +```ts +get [Generator.PREPARING]() { + return this.asPreparingTaskGroup() { + preparing({ application }) { + application.myCustomConfigFoo = this.jhipsterConfig.myCustomConfig === 'foo'; + application.myCustomConfigBar = this.jhipsterConfig.myCustomConfig === 'bar'; + application.myCustomConfigNo = !this.jhipsterConfig.myCustomConfig || this.jhipsterConfig.myCustomConfig === 'no'; + }, + } +} +``` + +#### Configuring each entity (base-application) + +Configure and check entity's configuration: + +```ts +get [Generator.CONFIGURING_EACH_ENTITY]() { + return this.asConfiguringEachEntityTaskGroup() { + configuring({ application, entityConfig }) { + if (application.searchEngineNo && entityConfig.searchEngine && entityConfig.searchEngine !== 'no') { + this.log.warn("Search engine cannot be enabled at entity because it's disabled at application"); + entityConfig.searchEngine = 'no'; + } + }, + } +} +``` + +#### Loading entities (base-application) + +Usually empty the entire entity configuration is loaded by default. + +#### Preparing each entity (base-application) + +Generate properties to improve understanding at the entity level: + +```ts +get [Generator.PREPARING_EACH_ENTITY]() { + return this.asPreparingEachEntityTaskGroup() { + preparing({ application, entity }) { + entity.dtoMapstruct = entity.dto === 'mapstruct'; + }, + } +} +``` + +#### Preparing each entity field (base-application) + +Generate properties to improve understanding at the field level: + +```ts +get [Generator.PREPARING_EACH_ENTITY_FIELD]() { + return this.asPreparingEachEntityFieldTaskGroup() { + preparing({ application, entity, field }) { + field.technologyFieldTypeIntegerMap = field.fieldType === 'Integer'; + }, + } +} +``` + +#### Preparing each entity relationship (base-application) + +Generate properties to improve understanding at the relationship level: + +```ts +get [Generator.PREPARING_EACH_ENTITY_RELATIONSHIP]() { + return this.asPreparingEachEntityRelationshipTaskGroup() { + preparing({ application, entity, relationship }) { + relationship.technologyRelationshipDbName = relationship.relationshipTypeOneToOne ? 'foo' : 'bar'; + }, + }; +} +``` + +#### Default (yeoman) + +Generate properties to improve understanding that depends on others' properties: + +```ts +get [Generator.DEFAULT]() { + return this.asDefaultTaskGroup() { + preparing({ application, entities }) { + application.hasEntityFieldInteger = entities.some(entity => entity.fields.some(field => field.fieldTypeInteger)); + }, + }; +} +``` + +#### Writing (yeoman) + +Write files to the in-memory file system. + +There are a lot of APIs to write files, copy files, and delete files. +The `writeFiles()` method is the most used in official generators. + +```ts +get [Generator.WRITING]() { + return this.asWritingTaskGroup({ + async writingTask({ application }) { + await this.writeFiles({ + blocks: [ + { + condition: ctx => ctx.shouldWrite, + templates: ['template.file'], + } + ], + context: application, + }); + }, + }); +} +``` + +#### Writing entities (base-application) + +Write entity files to the in-memory file system. + +Writing entities is a separate priority to keep the workflow sane when using options like `--skip-application` and `--single-entity`. + +```ts +get [Generator.WRITING_ENTITIES]() { + return this.asWritingTaskGroup({ + async writingTask({ application, entities }) { + for (const entity of entities) { + await this.writeFiles({ + blocks: [ + { + condition: ctx => ctx.shouldWrite, + templates: ['entity.template.file'], + } + ], + context: { ...application, ...entity }, + }); + } + }, + }); +} +``` + +#### Post writing (base) + +Injects code in the generated source. + +##### Injecting code with provided apis (needles) + +JHipster adds APIs for code injection: + +```ts +get [Generator.POST_WRITING]() { + return this.asPostWritingTaskGroup({ + postWritingTask({ source }) { + source.someProvidedInjectionApi({ code: 'some code' }); + } + }); +} +``` + +##### Custom code injection + +Every file can be edited manually. + +```ts +get [Generator.POST_WRITING]() { + return this.asPostWritingTaskGroup({ + postWritingTask({ source }) { + this.editFile('path/to/some/file', content => content.replaceAll('some content', 'another content')); + } + }); +} +``` + +#### Install (yeoman) + +Usually empty. +Install task is queued by detecting `package.json` changes. + +#### End (yeoman) + +Print generator result and info: + +```ts +get [Generator.END]() { + return this.asEndTaskGroup() { + preparing({ application }) { + this.log.success('Tech application generated successfully'); + this.log.log(`Start the application running 'npm run start:app'`); + }, + }; +} +``` + +## Blueprints + +Blueprint support allows to customize the generation process. + +A 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. + +- Normal blueprints will completely replace the blueprinted sub-generator with a replacement. +- Side by side blueprint doesn't change the generation process, it customizes it. +- Stand alone blueprint doesn't hook into a sub-generator. + +Examples: + +- [Micronaut](https://github.com/jhipster/generator-jhipster-micronaut) has a [server](https://github.com/jhipster/generator-jhipster-micronaut/tree/0818dd9d90f4a550e008133adc7fad6b17089caa/generators/server) replacement blueprint, a [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 + +More information can be found at: + +[Extending and customizing](https://www.jhipster.tech/modules/extending-and-customizing/) +[Creating a stand alone Blueprint](https://www.jhipster.tech/modules/creating-a-module/) +[Creating a blueprint](https://www.jhipster.tech/modules/creating-a-blueprint/) + +### Blueprint lifecycle + +#### Replacement blueprint + +| Priority | Blueprinted sub-gen | Blueprint sub-gen | +| ------------ | ------------------------------------- | ------------------------------ | +| beforeQueue | composes with blueprints/dependencies | composes with dependencies | +| initializing | X | replacement initializing tasks | +| prompting | X | replacement prompting tasks | +| ... | X | ... | + +#### Side by side blueprint + +| Priority | Blueprinted sub-gen | Blueprint sub-gen | Another blueprint sub-gen | +| ------------ | ------------------------------------- | ----------------------------- | ----------------------------- | +| beforeQueue | composes with blueprints/dependencies | composes with dependencies | composes with dependencies | +| initializing | initializing tasks | additional initializing tasks | additional initializing tasks | +| prompting | prompting tasks | additional prompting tasks | additional prompting tasks | +| ... | ... | ... | ... | + +#### Stand alone blueprint + +| Priority | Blueprint sub-gen | +| ------------ | -------------------------- | +| beforeQueue | composes with dependencies | +| initializing | initializing tasks | +| prompting | prompting tasks | +| ... | ... | + +## Generator Hierarchy + +### GeneratorBaseCore + +Adds custom APIS to `yeoman-generator` and customizes the behavior. + +### GeneratorBase + +Adds Blueprint composing APIS. + +### GeneratorApplication + +Adds Entities related apis. diff --git a/BLUEPRINTS.md b/BLUEPRINTS.md new file mode 100644 index 00000000000..5a48ffcec18 --- /dev/null +++ b/BLUEPRINTS.md @@ -0,0 +1,48 @@ +# JHipster Blueprints + +Blueprints allows to add new features or change current features. + +## Creating a Blueprint + +``` +jhipster generate-blueprint +``` + +When creating blueprints it's cleaner to have the blueprint forwarding to a custom generator and keep main generators like client/common/server with customizations. +Example [jOOQ Blueprint](https://github.com/jhipster/generator-jhipster-jooq/blob/ce48a06a2b031013383db01cc787bbe94aa2c683/generators/server/generator.mjs#L21) + +## Maintaining a Blueprint + +### Upgrading to a new JHipster version + +#### Upgrading and syncing the generated blueprint + +Each JHipster version brings updated dependencies. +You should regenerate the blueprint to update dependencies. + +``` +npx --package generator-jhipster@latest jhipster generate-blueprint +``` + +When updating from a minor JHipster version, you probably will want to ignore (press s) to every generator and test conflict. +Ignore (i option instead of s) will store the file at `.yo-resolve` so that following `generate-blueprint` executions will ignore those files by default. + +From time to time generate-blueprint may generate different code. +So regenerate every file ignoring `.yo-resolve` executing `jhipster generate-blueprint --skip-yo-resolve` and check the differences. + +### Blueprint dependencies + +`generator-jhipster` have every dependency using an exact version. +If the blueprint uses exact versions too, duplicated dependencies with different versions will be added to `node_modules`. +For this reason try to _avoid exact version at blueprint dependencies_ and disable auto updates since dependencies will be updated every time the blueprint is regenerated using `generate-blueprint`. + +### Upgrading from v7 to v8 + +- `entity-*` generators were dropped and the replacements are entity's specific priorities at the technology specific generator (server, angular, spring-data-relational, ...). + Motivation can be found at https://github.com/jhipster/generator-jhipster/blob/main/rfcs/4-jhipster-rfc-entity-as-core.md. +- priorities names are static constants at the generator class. + `get initializing() {}` -> `get [Generator.INITIALIZING]() {}` + Motivation can be found at https://github.com/jhipster/generator-jhipster/blob/main/rfcs/3-jhipster-rfc-unambiguous-priorities.md. +- many property migration can be warned by enabling `jhipster7Migration` feature at the constructor. +- needles are not implemented in the generator base anymore. + They are injected at source object provided at some priorities and used like https://github.com/jhipster/generator-jhipster/blob/6373c9c76e57d01c4c1451a276f0d78bfbdd2c42/generators/spring-cache/generator.mts#L97-L101 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 31481fdc369..67ae76eac92 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,7 +8,6 @@ Are you ready to contribute to JHipster? We'd love to have you on board, and we - [Feature Requests](#feature) - [RFCs](#rfcs) - [Submission Guidelines](#submit) -- [Generator development setup](#setup) - [Coding Rules](#rules) - [Git Commit Guidelines](#commit) @@ -95,333 +94,23 @@ Before you submit your pull request consider the following guidelines: - Search [GitHub](https://github.com/jhipster/generator-jhipster/pulls?utf8=%E2%9C%93&q=is%3Apr) for an open or closed Pull Request that relates to your submission. -- If you want to modify the JHipster generator, read our [Generator development setup](#setup) -- Make your changes in a new git branch - - ```shell - git checkout -b my-fix-branch main - ``` - -- Create your patch, **including appropriate test cases**. +- If you want to modify the JHipster generator, read our [Development Guide](DEVELOPMENT.md) - Follow our [Coding Rules](#rules). -- Generate a new JHipster project, and ensure that all tests pass - - ```shell - mvnw verify -Pprod - ``` - -- Test that the new project runs correctly: - - ```shell - mvnw spring-boot:run - ``` - -- You can generate our Continuous Integration (with GitHub Actions and Azure Pipelines) by following [this](#running-integration-tests-locally) - -- Commit your changes using a descriptive commit message that follows our - [commit message conventions](#commit-message-format). - - ```shell - git commit -a - ``` - - Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files. - -- Push your branch to GitHub: - - ```shell - git push origin my-fix-branch - ``` - - In GitHub, send a pull request to `jhipster/generator-jhipster:main`. -- If we suggest changes then - - - Make the required updates. - - Re-run the JHipster tests on your sample generated project to ensure tests are still passing. - - Rebase your branch and force push to your GitHub repository (this will update your Pull Request): - - ```shell - git rebase main -i - git push -f - ``` +- **Every CI tests must pass**. That's it! Thank you for your contribution! -#### Resolving merge conflicts ("This branch has conflicts that must be resolved") - -Sometimes your PR will have merge conflicts with the upstream repository's main branch. There are several ways to solve this but if not done correctly this can end up as a true nightmare. So here is one method that works quite well. - -- First, fetch the latest information from the main - - ```shell - git fetch upstream - ``` - -- Rebase your branch against the upstream/main - - ```shell - git rebase upstream/main - ``` - -- Git will stop rebasing at the first merge conflict and indicate which file is in conflict. Edit the file, resolve the conflict then - - ```shell - git add - git rebase --continue - ``` - -- The rebase will continue up to the next conflict. Repeat the previous step until all files are merged and the rebase ends successfully. -- Re-run the JHipster tests on your sample generated project to ensure tests are still passing. -- Force push to your GitHub repository (this will update your Pull Request) - - ```shell - git push -f - ``` - -#### After your pull request is merged - -After your pull request is merged, you can safely delete your branch and pull the changes -from the main (upstream) repository: - -- Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows: - - ```shell - git push origin --delete my-fix-branch - ``` - -- Check out the main branch: - - ```shell - git checkout main -f - ``` - -- Delete the local branch: - - ```shell - git branch -D my-fix-branch - ``` - -- Update your main with the latest upstream version: - - ```shell - git pull --ff upstream main - ``` - -## Generator development setup - -JHipster is a [Yeoman Generator](http://yeoman.io/), so you must follow the [Yeoman authoring documentation](http://yeoman.io/authoring/) in order to be able to run and test your changes. - -Here are the most important steps. - -### Fork the generator-jhipster project - -Go to the [generator-jhipster project](https://github.com/jhipster/generator-jhipster) and click on the "fork" button. You can then clone your own fork of the project, and start working on it. - -[Please read the GitHub forking documentation for more information](https://help.github.com/articles/fork-a-repo) - -### Set `jhipster` command to use the cloned project - -Since v8 `generator-jhipster` is written in typescript. -To run it you need to compile to javascript or use a just-in-time compilation. - -#### Running jit executable - -The executable is located at `bin/jhipster.cjs`. -You can alias it to `jhipster` command: - -```shell -alias jhipster="GLOBAL_PATH/generator-jhipster/bin/jhipster.cjs" -``` - -#### Globally linked compiled package - -In your cloned `generator-jhipster` project, run `npm ci` and then run `npm link`. - -`npm ci` will do a clean installation of all the project dependencies and compile sources. -`npm run build` can be used to compile sources after each change. - -`npm link` will make a symbolic link from the global `node_modules` version to point to this folder, so when we run `jhipster`, you will now use the development version of JHipster. - -### Test generating applications - -For testing, you will want to generate an application, and there is a specific issue here: for each application, JHipster installs a local version of itself. This is made to enable several applications to each use a specific JHipster version (application A uses JHipster 3.1.0, and application B uses JHipster 3.2.0). - -To overcome this you need to run `npm link generator-jhipster` on the generated project folder as well, so that the local version has a symbolic link to the development version of JHipster. -Also add the option `--skip-jhipster-dependencies` to generate the application ignoring the JHipster dependencies (otherwise a released version will be installed each time npm install/ci is called). You can later on re-add the dependency with the command `jhipster --no-skip-jhipster-dependencies`. - -To put it in a nutshell, you need to: - -1. run `npm link` on the `generator-jhipster` project (link globally) or configure jit executable -2. run `jhipster --skip-jhipster-dependencies` on the generated application folder - -You can execute `jhipster --install-path` to check where jhipster is being executed from. - -You can test your setup by making a small change in your cloned generator, and running again on an existing JHipster project: - -For projects with jhipster third party library (i.e. react-jhipster, etc.) you need to run `npm link` on the library project as well, then npm link the original framework (i.e. react) from the generated project to the library project `cd react-jhipster && npm link /node_modules/react`. - -```shell -jhipster -``` - -Depending on which parts of the generator you have changed, do not forget to run jhipster command with the proper arguments e.g. when updating the entity template run: - -```shell -jhipster -``` - -You should see your changes reflected in the generated project. - -Note: The generated project might not build properly in case the generator is using a -snapshot version of [jhipster/jhipster-bom](https://github.com/jhipster/jhipster-bom). This issue is mentioned in; https://github.com/jhipster/generator-jhipster/issues/9571. In -this case clone the jhipster/jhipster-bom project and build it using: - -```shell script -./mvnw clean install -Dgpg.skip=true -``` - -or on Windows: - -``` -.\mvnw.cmd clean install -D"gpg.skip=true" -``` - -### Use a text editor - -As modifying the JHipster generator includes modifying Java and JavaScript templates, most IDE will not work correctly. We recommend you use a text editor like [VSCode](https://code.visualstudio.com/) or [IntelliJ IDEA](https://www.jetbrains.com/idea/) to code your changes. The ESLint and EditorConfig extensions are recommended to help with respecting code conventions. - -### Use a debugger - -It is possible to debug JHipster's code using a Node.js debugger. To achieve this setup your debugger to launch `cli/jhipster.js`. - -#### Debugging with VSCode - -To start debugging JHipster with **VSCode**, open the generator code in your workspace and simply press F5 (or click the green arrow in the **Debug** menu reachable with Ctrl/Cmd+Shift+D). This will start the generator in debug mode and generate files in the [test-integration/samples/app-sample-dev](test-integration/samples/app-sample-dev) folder. - -It is also possible to debug sub generators by selecting one of the other debug options (for example `jhipster entity`). Those debug configurations are specified in the `.vscode/launch.json` file. - -## Generator tests and snapshots. - -Run every test with lint/prettier -`npm test` - -Run every test without lint/prettier -`npx esmocha` - -Update every test snapshot -`npm run update-snapshots` - -Run specific tests -`npx esmocha ` - -Run specific tests in series (improved error reporting) -`npx esmocha --no-parallel` - -Update specific test snapshot -`npm run update-snapshot -- ` or `npx esmocha --no-parallel --update-snapshot` - -Fixing lint and prettier errors -`npm run lint-fix` - -## Generating and testing samples - -Sample generating is provided by `generator-jhipster` local blueprint which we will refer as `dev blueprint`. -The dev blueprint is enabled by running jhipster in JIT mode (executing `./bin/jhipster.cjs` file relative to this file). - -### Generating samples using dev blueprint - -`jhipster generate-sample ng-default` will generate the `ng-default` sample at current folder. - -#### Daily builds samples - -Daily builds samples are prefixed with `daily-`. - -#### Samples folder - -A common samples folder will be used if `--global` option is used like `jhipster generate-sample ng-default --global`. -At first execution a prompt will ask for the samples folder, the chosen value will be reused at next executions. -At samples folder, a `jhipster-samples.code-workspace` is generated. It provides a single vscode workspace for `generator-jhipster` and samples generated at the samples folder. It's very used for quick looks. - -### Testing samples - -CI tests uses the following commands: - -``` -npm ci:backend:test -npm ci:frontend:test -npm run ci:e2e:package # Builds the application -npm run ci:e2e:prepare # Starts the application using docker -npm run ci:e2e:run # Runs e2e tests -``` - -## DX using vscode - -`generator-jhipster` add a series of vscode configurations for a better developer experience. - -### Development Containers - -Container is built using java, node and npm recommended by `generator-jhipster`. -Once up, you should have the stack maintainers recommends. - -### Execution shortcuts - -Shortcuts are provided to easily generate integration tests samples. - -- go to `Execute and Debug`. -- select the sample's github workflow. -- run the shortcut. -- select the sample. -- sample is generated at `../jhipster-samples/` folder relative the `generator-jhipster` folder. - -Some daily builds samples are available too. - -### Generators tests - -At test tab you can run and debug individual test. - -## Running integration tests locally - -You can run the builds locally by following below commands - -Go into the `test-integration` folder with `cd test-integration` from the generator source code root folder - -Run `./generate-sample.sh [folder] [sample_name:optional] [type of entity]` - -This will create a folder with configuration and entities. Then, you can generate manually a JHipster project and test it. - -Command name can be as below - - `list`: List all sample names - `generate`: Generate the sample - ## Coding Rules To ensure consistency throughout the source code, keep these rules in mind as you are working: - All features or bug fixes **must be tested** by one or more tests. -- All files must follow the [.editorconfig file](http://editorconfig.org/) located at the root of the JHipster generator project. Please note that generated projects use the same `.editorconfig` file, so that both the generator and the generated projects share the same configuration. -- Java files **must be** formatted using IntelliJ IDEA default code style. -- Generators JavaScript files **must follow** the eslint configuration defined at the project root, which is based on [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript). -- Any client side feature/change should be done for both Angular and react clients -- Web apps JavaScript files **must follow** [Google's JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html). -- Angular Typescript files **must follow** the [Official Angular style guide](https://angular.io/styleguide). -- React/Redux Typescript files **may follow** the [React/Redux Typescript guide](https://github.com/piotrwitek/react-redux-typescript-guide). +- Most files formatting are checked by prettier and eslint. +- EJS files use a two-space indentation for template logic and follow the generated file rules for the templating parts. Please ensure to run `npm run lint` and `npm test` on the project root before submitting a pull request. You can also run `npm run lint-fix` to fix some of the lint issues automatically. -## Template Guidelines - -The template engine used by yeoman is [EJS](http://ejs.co/), its syntax is fairly simple. -For simple code (few lines), logic can be embedded in the main file but if logic becomes more complex it's better to externalise the JS fragment to a sub template included by the first one and located in same folder. - -Sub templates should be named with the `ejs` extension because it's the default one, it enables editors to apply correct syntax highlighting and it enables us to use a very concise syntax: - - <%- include('../common/field_validators', {field, reactive}); -%> - -This statement means that [_persistClass_.java.jhi.jakarta_validation.ejs](generators/server/templates/entity/src/main/java/package/domain/_persistClass_.java.jhi.jakarta_validation.ejs) template includes [field_validators.ejs](generators/server/templates/entity/src/main/java/package/common/field_validators.ejs) sub template. - -Sub templates can be unit tested. - ## Git Commit Guidelines We have rules over how our git commit messages must be formatted. Please ensure to [squash](https://help.github.com/articles/about-git-rebase/#commands-available-while-rebasing) unnecessary commits so that your commit history is clean. diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 00000000000..dbf67e54032 --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,192 @@ +# JHipster development + +- [Generator development setup](#setup) + +## Generator development setup + +JHipster is a [Yeoman Generator](http://yeoman.io/), so you must follow the [Yeoman authoring documentation](http://yeoman.io/authoring/) in order to be able to run and test your changes. + +Here are the most important steps. + +### Fork the generator-jhipster project + +Go to the [generator-jhipster project](https://github.com/jhipster/generator-jhipster) and click on the "fork" button. You can then clone your own fork of the project, and start working on it. + +[Please read the GitHub forking documentation for more information](https://help.github.com/articles/fork-a-repo) + +### Set `jhipster` command to use the cloned project + +Since v8 `generator-jhipster` is written in TypeScript. +To run it you need to compile to JavaScript or use a just-in-time compilation. + +#### Runnning jit executable + +The executable is located at `bin/jhipster.cjs`. +You can alias it to `jhipster` command: + +```shell +alias jhipster="GLOBAL_PATH/generator-jhipster/bin/jhipster.cjs" +``` + +#### Globally linked compiled package + +In your cloned `generator-jhipster` project, run `npm ci` and then run `npm link`. + +`npm ci` will do a clean installation of all the project dependencies and compile sources. +`npm run build` can be used to compile sources after each change. + +`npm link` will make a symbolic link from the global `node_modules` version to point to this folder, so when we run `jhipster`, you will now use the development version of JHipster. + +### Test generating applications + +For testing, you will want to generate an application, and there is a specific issue here: for each application, JHipster installs a local version of itself. This is made to enable several applications to each use a specific JHipster version (application A uses JHipster 3.1.0, and application B uses JHipster 3.2.0). + +To overcome this you need to run `npm link generator-jhipster` on the generated project folder as well, so that the local version has a symbolic link to the development version of JHipster. +Also add the option `--skip-jhipster-dependencies` to generate the application ignoring the JHipster dependencies (otherwise a released version will be installed each time npm install/ci is called). You can later on re-add the dependency with the command `jhipster --no-skip-jhipster-dependencies`. + +To put it in a nutshell, you need to: + +1. Run `npm link` on the `generator-jhipster` project (link globally) or configure jit executable +2. Run `jhipster --skip-jhipster-dependencies` on the generated application folder + +You can execute `jhipster --install-path` to check where JHipster is being executed from. + +You can test your setup by making a small change in your cloned generator, and running again on an existing JHipster project: + +For projects with JHipster third-party libraries (i.e. react-jhipster, etc.), you need to run `npm link` on the library project as well, then `npm link` the original framework (i.e. react) from the generated project to the library project `cd react-jhipster && npm link /node_modules/react`. + +```shell +jhipster +``` + +Depending on which parts of the generator you have changed, do not forget to run the `jhipster` command with the proper arguments e.g. when updating the entity template run: + +```shell +jhipster --with-entities +``` + +You should see your changes reflected in the generated project. + +Note: The generated project might not build properly in case the generator is using a +snapshot version of [jhipster/jhipster-bom](https://github.com/jhipster/jhipster-bom). This issue is mentioned in; https://github.com/jhipster/generator-jhipster/issues/9571. In +this case clone the jhipster/jhipster-bom project and build it using: + +```shell script +./mvnw clean install -Dgpg.skip=true +``` + +or on Windows: + +``` +.\mvnw.cmd clean install -D"gpg.skip=true" +``` + +### Use a text editor + +As modifying the JHipster generator includes modifying Java and JavaScript templates, most IDE will not work correctly. We recommend you use a text editor like [VSCode](https://code.visualstudio.com/) or [IntelliJ IDEA](https://www.jetbrains.com/idea/) to code your changes. The ESLint and EditorConfig extensions are recommended to help with respecting code conventions. + +### Use a debugger + +It is possible to debug JHipster's code using a Node.js debugger. To achieve this setup your debugger to launch `cli/jhipster.js`. + +#### Debugging with VSCode + +To start debugging JHipster with **VSCode**, open the generator code in your workspace and simply press F5 (or click the green arrow in the **Debug** menu reachable with Ctrl/Cmd+Shift+D). This will start the generator in debug mode and generate files in the [test-integration/samples/app-sample-dev](test-integration/samples/app-sample-dev) folder. + +It is also possible to debug sub generators by selecting one of the other debug options (for example `jhipster entity`). Those debug configurations are specified in the `.vscode/launch.json` file. + +## Generator implementation + +### important config objects + +## Generator tests and snapshots + +Run every test with lint/prettier +`npm test` + +Run every test without lint/prettier +`npx esmocha` + +Update every test snapshot +`npm run update-snapshots` + +Run specific tests +`npx esmocha ` + +Run specific tests in series (improved error reporting) +`npx esmocha --no-parallel` + +Update specific test snapshot +`npm run update-snapshot -- ` or `npx esmocha --no-parallel --update-snapshot` + +Fixing lint and prettier errors +`npm run lint-fix` + +## Generating and testing samples + +Sample generating is provided by `generator-jhipster` local blueprint which we will refer as `dev blueprint`. +The dev blueprint is enabled by running jhipster in JIT mode (executing `./bin/jhipster.cjs` file relative to this file). + +### Generating samples using dev blueprint + +`jhipster generate-sample ng-default` will generate the `ng-default` sample at current folder. + +#### Daily builds samples + +Daily builds samples are prefixed with `daily-`. + +#### Samples folder + +A common samples folder will be used if `--global` option is used like `jhipster generate-sample ng-default --global`. +At first execution a prompt will ask for the samples folder, the choosen value will be reused at next executions. +At samples folder, a `jhipster-samples.code-workspace` is generated. It provides a single vscode workspace for `generator-jhipster` and samples generated at the samples folder. It's very used for quick looks. + +### Testing samples + +CI tests uses the following commands: + +``` +npm ci:backend:test +npm ci:frontend:test +npm run ci:e2e:package # Builds the application +npm run ci:e2e:prepare # Starts the application using docker +npm run ci:e2e:run # Runs e2e tests +``` + +## DX using vscode + +`generator-jhipster` add a series of vscode configurations for a better developer experience. + +### Development Containers + +A container is built using Java, Node, and npm as recommended by `generator-jhipster`. +Once up, you should have the stack maintainers recommends. + +### Execution shortcuts + +Shortcuts are provided to easily generate integration tests samples. + +- go to `Execute and Debug`. +- select the sample's github workflow. +- run the shortcut. +- select the sample. +- sample is generated at `../jhipster-samples/` folder relative the `generator-jhipster` folder. + +Some daily builds samples are available too. + +### Generators tests + +At test tab you can run and debug individual test. + +## Template Guidelines + +The template engine used by yeoman is [EJS](http://ejs.co/), its syntax is fairly simple. +For simple code (few lines), logic can be embedded in the main file but if logic becomes more complex it's better to externalise the JS fragment to a sub template included by the first one and located in same folder. + +Sub templates should be named with the `ejs` extension because it's the default one, it enables editors to apply correct syntax highlighting and it enables us to use a very concise syntax: + + <%- include('../common/field_validators', {field, reactive}); -%> + +This statement means that [_PersistClass_.java.jhi.jakarta_validation.ejs](generators/server/templates/entity/src/main/java/package/domain/_PersistClass_.java.jhi.jakarta_validation.ejs) template includes [field_validators.ejs](generators/server/templates/entity/src/main/java/package/common/field_validators.ejs) sub template. + +Sub templates can be unit tested. diff --git a/generators/app/README.md b/generators/app/README.md new file mode 100644 index 00000000000..ec988e69d4f --- /dev/null +++ b/generators/app/README.md @@ -0,0 +1,108 @@ +# app sub-generador + +`jhipster` command entrypoint, it composes with `common`, `languages`, `server`, and `client`. + +## Customizing + +JHipster implementation allows you to override almost every aspect of the generation process. + +[SQL/spring-data-relational customizations](https://github.com/jhipster/generator-jhipster/blob/skip_ci-architecture/generators/spring-data-relational/README.md#sqlspring-data-relational-sub-generador) + +### Application + +JDL doesn't support annotations, customizations must be done through local blueprint. + +`.blueprint/app/generator.mjs` (to create a local blueprint follow https://www.jhipster.tech/modules/creating-a-blueprint/#local-blueprints): + +```js +get [Generator.PREPARING]() { + return { + customize({ application }) { + application.baseNameHumanized = 'Custom application title'; + }, + }; +} +``` + +### Entities + +Every annotation is loaded as entities properties and will be used at generation process. + +```jdl +@CustomsProp1(customValue) +entity Bar {} +``` + +`.jhipster/Bar.json`: + +```json +{ + "name": "Bar", + "annotations": { + "customsProp1": "customValue" + } +} +``` + +#### Notable customizations + +##### Label + +``` +@EntityClassHumanized("Departamento") +@EntityClassPluralHumanized("Departamentos") +entity Department {} +``` + +##### Translation variant + +Translation variant allows different translations for the entity whenever applicable. + +```jdl +@EntityI18nVariant('female') +@EntityClassHumanized("Empresa") +@EntityClassPluralHumanized("Empresas") +entity Company {} +``` + +`female` variant is supported by `pt-br` locale. + +### Fields + +#### Notable customizations + +##### Label + +```jdl +entity Company { + @FieldNameHumanized('Company Name') + company_name +} +``` + +### Relationships + +#### Notable customizations + +##### Label + +```jdl +relationship ManyToOnly { + @RelationshipNameHumanized('Company user') Company{user} to User +} +``` + +##### Eager loading relationships + +Appliable to SQL/spring-data-relational with partial support at MongoDb/spring-data-mongodb. +Neo4j eager loads every relationship by default. + +JHipster UI uses only the id and `otherEntityFieldName` properties, by default only fields used by the UI will be fetched. + +```jdl +relationship OneToMany { + @RelationshipEagerLoad Bar to @RelationshipEagerLoad Foo +} +``` + +Related issues: (#23917)[https://github.com/jhipster/generator-jhipster/issues/23917] diff --git a/generators/app/USAGE b/generators/app/USAGE index 79267f9a915..2e3847ca81b 100644 --- a/generators/app/USAGE +++ b/generators/app/USAGE @@ -5,3 +5,6 @@ Example: jhipster This will compose jhipster:client, jhipster:server and jhipster:languages to scaffold a full application + +More information: + https://github.com/jhipster/generator-jhipster/tree/main/generators/app diff --git a/generators/liquibase/README.md b/generators/liquibase/README.md new file mode 100644 index 00000000000..7ab50f9e856 --- /dev/null +++ b/generators/liquibase/README.md @@ -0,0 +1,19 @@ +# SQL/spring-data-relational sub-generador + +Adds support to liquibase to SQL databases and Neo4j. + +## Customizing + +Customizing basics can be found at [Customizing](../app/README.md#customizing) + +### Notable relationships customizations + +#### OnUpdate/OnDelete + +```jdl +relationship ManyToOne { + A to @OnDelete("SET NULL") @OnUpdate("CASCADE") B +} +``` + +Allowed values: `NO ACTION | RESTRICT | CASCADE | SET NULL | SET DEFAULT` diff --git a/generators/spring-data-relational/README.md b/generators/spring-data-relational/README.md new file mode 100644 index 00000000000..a04bc8ccc8c --- /dev/null +++ b/generators/spring-data-relational/README.md @@ -0,0 +1,7 @@ +# SQL/spring-data-relational sub-generador + +Adds support to spring-data-relational and provides sql related utilities. + +## Customizing + +Customizing basics can be found at [Customizing](../app/README.md#customizing)