diff --git a/CHANGELOG.md b/CHANGELOG.md index ebc6ecc..ac9d416 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ CHANGELOG for 1.x =================== +## v1.8.1 - (2026-10-12) +### Added +- `docs/rules.md` : the project rules checked by Smart App (PHP, PHPStan, JavaScript), each with what is checked and why, including the + reasons why `npm` is our main package manager, why Yarn is excluded and why pnpm is only accepted. + +### Changed +- `docs/front_code_validation.md` : commands moved from `yarn` to `npm` (`npm install --save-dev`, `npm run`, `npx`), with a reminder + that `npm` is the package manager declared in `packageManager`, linking to [docs/rules.md](docs/rules.md#jspackage-manager). + ## v1.8.0 - (2026-09-23) ### TODO When updating The DAST scans (OWASP ZAP) moved to the stack-agnostic Standard Security Gitlab Package diff --git a/docs/front_code_validation.md b/docs/front_code_validation.md index 75cafb1..e0c0c84 100644 --- a/docs/front_code_validation.md +++ b/docs/front_code_validation.md @@ -6,6 +6,9 @@ without Symfony (Vanilla Javascript, Typescript, Full Vue, Vue SPA, ...). > **Documentation only.** This bundle ships no front configuration: nothing below is copied by the recipe. This page states the > principle and the reference setup each project type applies. +> **Package manager.** The commands below use `npm`, the package manager we use and declare in the `packageManager` field of +> `package.json`. See [`js.package-manager`](rules.md#jspackage-manager) for why, and for what is accepted instead. + ## Tool responsibilities | Tool | Scope | @@ -82,7 +85,7 @@ This section is the framework agnostic base. Each following section adds what a Command to run to add the dependencies to your `package.json`: ```sh -yarn add --dev eslint @eslint/js eslint-config-prettier prettier +npm install --save-dev eslint @eslint/js eslint-config-prettier prettier ``` List of the commands to add in the `package.json` for each tool, plus the global validation one: @@ -94,7 +97,7 @@ List of the commands to add in the `package.json` for each tool, plus the global "lint:baseline": "rm -f eslint-suppressions.json && eslint . --suppress-all", "format": "prettier --write .", "format:check": "prettier --check .", - "validation": "yarn lint:check; s=$?; yarn format:check && exit $s" + "validation": "npm run lint:check; s=$?; npm run format:check && exit $s" } ``` @@ -177,11 +180,11 @@ export default defineConfig([ Extra packages to add: -`yarn add --dev eslint-plugin-vue vue-eslint-parser` +`npm install --save-dev eslint-plugin-vue vue-eslint-parser` > `vue-eslint-parser`, the parser that splits a `.vue` file to expose its template and its script to ESLint, is a peer dependency -> of `eslint-plugin-vue`. It has to be declared if the project uses yarn instead of pnpm, as the former doesn't install peer deps -> by default. +> of `eslint-plugin-vue` that the config imports directly, so it is declared explicitly. npm and pnpm install peer deps by default, +> Yarn doesn't, which is one of the reasons why it is [excluded](rules.md#jspackage-manager). Impact on the ESLint config, `.vue` added to the linted extensions and the preset spread after the JS rules: @@ -221,7 +224,7 @@ that means rewriting every existing template for no functional gain, and which t Extra package to add: -`yarn add --dev globals` +`npm install --save-dev globals` The scope of the `lint` and `format` commands must be narrowed to the only directory holding front code, `assets`, which gives in `package.json`: @@ -232,7 +235,7 @@ The scope of the `lint` and `format` commands must be narrowed to the only direc "lint:baseline": "rm -f eslint-suppressions.json && eslint assets --suppress-all", "format": "prettier --write assets", "format:check": "prettier --check assets", - "validation": "yarn lint:check; s=$?; yarn format:check && exit $s" + "validation": "npm run lint:check; s=$?; npm run format:check && exit $s" } ``` @@ -299,7 +302,7 @@ subject to both: Extra package to add: -`yarn add --dev prettier-plugin-tailwindcss` +`npm install --save-dev prettier-plugin-tailwindcss` The official class sorter enforces one canonical order for the utility classes, which removes any debate on where a class goes. @@ -332,7 +335,7 @@ Impact on the Prettier config: Extra package to add: -`yarn add --dev @vue/eslint-config-typescript` +`npm install --save-dev @vue/eslint-config-typescript` [This config](https://github.com/vuejs/eslint-config-typescript), still the one of the create-vue TypeScript template, wires `typescript-eslint` on the `.vue` files. @@ -363,7 +366,7 @@ code. - [Bulk suppressions](https://eslint.org/docs/latest/use/suppressions): `eslint-suppressions.json` counts existing violations per file and rule, only new ones fail. Same principle as the [PHPStan baseline](phpstan.md). -- `yarn lint:baseline` regenerates it from scratch (`--suppress-all` never removes entries). Review its diff before committing. +- `npm run lint:baseline` regenerates it from scratch (`--suppress-all` never removes entries). Review its diff before committing. - Violation fixed → entry obsolete → `lint:check` exits with code 2 → regenerate. - Only `error` rules are recorded. @@ -374,10 +377,10 @@ There is no proper "baseline" in Prettier but there is a similar alternative cal The `requirePragma: true` config option restricts it to files starting with a `@format` pragma ([options](https://prettier.io/docs/options#require-pragma): "gradually transitioning large, unformatted codebases"). -- Opt a file in: `yarn prettier --write --no-require-pragma --insert-pragma ` (`--insert-pragma` alone does nothing, +- Opt a file in: `npx prettier --write --no-require-pragma --insert-pragma ` (`--insert-pragma` alone does nothing, `requirePragma` wins). - Marker: `` in `.vue`, `/** @format */` in `.js` and `.css`. -- Then `yarn lint:baseline`: formatting fixes `vue/first-attribute-linebreak`, its entries become obsolete. +- Then `npm run lint:baseline`: formatting fixes `vue/first-attribute-linebreak`, its entries become obsolete. - Remove the option once every file is formatted. ### Prettier: one-shot formatting commit @@ -387,7 +390,7 @@ with few front files, low sensitivity, and few people and open branches on it. T as every open branch will have to be rebased over the reformatted files. 1. Commit the config, merge open branches. -2. One commit with `yarn format`, nothing else. +2. One commit with `npm run format`, nothing else. 3. Safety net: `prettier --debug-check` on the same scope reports any file whose meaning might change. 4. Once merged (squash or rebase changes the hash), add the commit hash to `.git-blame-ignore-revs`. Each dev runs `git config blame.ignoreRevsFile .git-blame-ignore-revs` (PhpStorm follows it). GitLab: *Blame preferences › Ignore specific revisions*. diff --git a/docs/rules.md b/docs/rules.md new file mode 100644 index 0000000..7b70db3 --- /dev/null +++ b/docs/rules.md @@ -0,0 +1,76 @@ +# Project rules + +The rules every SMARTBOOSTER repository is checked against by Smart App. + +Each rule is evaluated on the files repository and ends up : +- **compliant**, +- **non compliant**, +- **not applicable** (the repository has no such file) +- **unknown** (a file is unreadable, or the production version is not declared). + +Rules are grouped by category, the subject of their code (`phpstan.level` → `phpstan`). The PHP rules are not applicable without +`composer.json`, the JavaScript rules without `package.json`. + +## PHP + +### `php.composer-require` + +**Check :** `require.php` in `composer.json` accepts the whole minor of `PHP_VERSION`, and only that one (`~8.4.0`, `8.4.*`). +A wider constraint (`>=8.1`, `^8.4`) is not compliant. + +**Why :** Composer must only resolve dependencies for the PHP version that runs in production. + +### `php.composer-platform` + +**Check :** `config.platform.php` in `composer.json` is in the production minor (`8.4.0` for `PHP_VERSION=8.4`). + +**Why :** Composer resolves dependencies for the production version, not for the one of the machine that runs the install. + +## PHPStan + +### `phpstan.level` + +**Check :** The PHPStan config file declares `level: 10`. A level only given on the command line (Makefile, CI) does not count, +and `max` is not accepted. + +**Why :** The highest level catches type errors before production. `max` moves with PHPStan versions: a level is tested before being +imposed, so we declare `10` explicitly. + +See [PHPStan](phpstan.md) for the setup of a new project and the level migration workflow of a legacy one. + +## JavaScript + +### `js.package-manager` + +**Check :** One single lock file next to `package.json`: `package-lock.json` (npm) or `pnpm-lock.yaml` (pnpm), never `yarn.lock`. +The `packageManager` field is mandatory and names the same manager as the lock (`npm@11.6.2`). + +**Why :** One manager and its lock install the same dependency versions everywhere; two managers sharing a repository do not. +`packageManager` makes the choice explicit and lets Corepack pin the version. + +> `npm` is the main package manager that we decide to use because it is the only one that comes natively with Node: installing +> Node gives the matching npm, with nothing else to install or to keep aligned on the Docker image, the CI and the production host. +> +> Yarn and pnpm are not shipped with Node. They go through [Corepack](https://github.com/nodejs/corepack), a shim bundled with +> Node up to 24 but opt-in (`corepack enable`) and no longer distributed from Node 25, or through a global install that we would +> have to pin everywhere. This is why `packageManager` is mandatory: it states which manager and which exact version the project +> expects, and it is what Corepack reads to pin it. +> +> **Why Yarn is excluded.** We only ever used Yarn Classic (1.x), a line that is frozen upstream: it no longer evolves, and a +> modern Yarn is not native either (Corepack, another config model). It also has rough edges we ran into: it does not install +> peer dependencies by default (see the `vue-eslint-parser` note in [front code validation](front_code_validation.md)). +> +> **Why pnpm is accepted.** We use it to try this manager on our internal projects. We do not use it on Clever Cloud instances, +> because it is not provided by default on the PHP scalers, unlike npm. + +### `js.node-engine` + +**Check :** `engines.node` in `package.json` accepts the major of `NODE_VERSION` and refuses the others (`24.x`, `^24.11`). + +**Why :** JavaScript dependencies must be installed for the Node version that runs in production. + +### `js.engine-strict` + +**Check :** `engine-strict=true` in `.npmrc`. + +**Why :** Without it `engines.node` is only a warning: npm installs anyway on a Node version the project refuses.