@limenet-ch/baseline 2.10.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -111,7 +111,7 @@ State lives in `.baseline.json` at the project root (a JS project has no `config
111
111
  | Check | Relationship to the Laravel runner |
112
112
  | --- | --- |
113
113
  | `nodeVersion` | identical |
114
- | `hardensNpmSupplyChain` | identical |
114
+ | `hardensNpmSupplyChain` | also requires `.npmrc` to exempt `@limenet-ch/baseline` from the cooldown (`min-release-age-exclude[]=@limenet-ch/baseline`, or a glob covering it), so a baseline fix lands without the 7-day wait |
115
115
  | `hasEditorconfig` | identical |
116
116
  | `biomeUsesLocalSchema` | identical |
117
117
  | `doesNotHaveCopilotOrJunieAgentFiles` | identical |
@@ -124,7 +124,7 @@ State lives in `.baseline.json` at the project root (a JS project has no `config
124
124
  | `hasCiJobs` | same GitLab CI templates, without the `php` job |
125
125
  | `hasTrivyConfig` | identical, canonical config included: its `vendor/**`, `storage/logs/` and `.ddev/` skips are inert in a JS project |
126
126
  | `ciSetsNodeVersion` | **npm-only**: the Laravel runner does not register it |
127
- | `isCiLintComplete` | asserts the JS toolchain in the npm script, not pint/phpstan in a composer script |
127
+ | `isCiLintComplete` | asserts the JS toolchain in the npm script, not pint/phpstan in a composer script: `tsc` plus whichever linter is installed (`biome` for `@biomejs/biome`, `eslint` for `eslint`), failing if neither is |
128
128
  | `callsBaseline` | hooks the `ci-lint` npm script, since npm has no `post-update-cmd` |
129
129
  | `doesNotExcludeUnknownChecks` | identical, against this runner's smaller registry: a name only the Laravel runner knows is as dead here as one that exists nowhere |
130
130
  | `usesReleaseIt` | **inverted**: fails if `@release-it/bumper` is configured, because `package.json` is already release-it's source of truth |
@@ -158,7 +158,7 @@ This package validates your Laravel installation against the following checks:
158
158
  - 🔧 **`hasRectorConfigWithSets()`** - Validates Rector `withSets([LaravelBaselineSetList::REMOVE_DEFAULT_DOCBLOCKS, LaravelSetList::LARAVEL_*])` is configured with all required sets *(appends call to rector.php)*
159
159
  - 🔧 **`hasRectorConfigWithPaths()`** - Validates Rector `withPaths([app, database, routes, tests])` is configured *(appends call to rector.php)*
160
160
  - 🔧 **`hasRectorConfigWithPestSet()`** - Validates Rector `withSets([PestSetList::CODING_STYLE])` is configured when Pest 5+ and Rector are both present *(appends call to rector.php; warns if not applicable)*
161
- - 🔧 **`hasRectorConfigWithSkip()`** - Validates Rector `withSkip()` contains required skipped rules (always: 6 Laravel rules plus `StringToClassConstantRector`, which maps the Laravel 5.2-era string events context-free and so rewrites any matching literal — `view('auth.login')` becomes `Illuminate\Auth\Events\Login::class`; Laravel 13+: `TablePropertyToTableAttributeRector`; `AddGenericBuilderToScopesRector`, new in rector-laravel 2.6 and shipped in `LARAVEL_TYPE_DECLARATIONS`, which downgrades an already-correct `Builder<$this>` to `Builder<static>`; when server.php exists: `ServerVariableToRequestFacadeRector`) *(appends an imported `withSkip()` call, or merges the missing classes into one that already exists)*
161
+ - 🔧 **`hasRectorConfigWithSkip()`** - Validates Rector `withSkip()` contains required skipped rules (always: 6 Laravel rules plus `StringToClassConstantRector`, which maps the Laravel 5.2-era string events context-free and so rewrites any matching literal — `view('auth.login')` becomes `Illuminate\Auth\Events\Login::class`; Laravel 13+: `TablePropertyToTableAttributeRector`; `AddGenericBuilderToScopesRector`, new in rector-laravel 2.6 and shipped in `LARAVEL_TYPE_DECLARATIONS`, which downgrades an already-correct `Builder<$this>` to `Builder<static>`; `MigrateToSimplifiedAttributeRector`, which rewrites working `getFooAttribute()`/`setFooAttribute()` accessors into a single `Attribute` method; when server.php exists: `ServerVariableToRequestFacadeRector`) *(appends an imported `withSkip()` call, or merges the missing classes into one that already exists)*
162
162
 
163
163
  ### IDE & Developer Tools
164
164
  - 🔧 **`hasEditorconfig()`** - Validates `.editorconfig` exists with required settings (`root = true`, `charset`, `end_of_line`, `indent_style`, `insert_final_newline`, `trim_trailing_whitespace`) *(creates `.editorconfig` with canonical content if missing or incomplete)*
@@ -1,5 +1,6 @@
1
+ import { posix } from 'node:path';
1
2
  import { policy } from '../policy.js';
2
- import { parseNpmrc, upsertNpmrc } from '../support/npmrc.js';
3
+ import { appendNpmrcList, npmrcList, parseNpmrc, upsertNpmrc } from '../support/npmrc.js';
3
4
  import { guaranteesAtLeast } from '../support/versions.js';
4
5
  import { FixableCheck } from './check.js';
5
6
  export class HardensNpmSupplyChainCheck extends FixableCheck {
@@ -51,17 +52,26 @@ export class HardensNpmSupplyChainCheck extends FixableCheck {
51
52
  return 'fail';
52
53
  }
53
54
  }
55
+ // Patterns are minimatch globs matched against the package name, the same
56
+ // way npm applies them, so an existing `@scope/*` counts as covering it.
57
+ const excluded = npmrcList(npmrcContents, 'min-release-age-exclude');
58
+ const notExcluded = policy()
59
+ .strings('npm.minReleaseAgeExclude.js')
60
+ .filter((name) => !excluded.some((pattern) => posix.matchesGlob(name, pattern)));
61
+ for (const name of notExcluded) {
62
+ this.comment(`.npmrc does not exempt ${name} from the cooldown: add "min-release-age-exclude[]=${name}" so baseline fixes reach this project on release rather than ${minReleaseAgeDays} days later`);
63
+ }
54
64
  if (dry) {
55
- return 'pass';
65
+ return notExcluded.length === 0 ? 'pass' : 'fail';
56
66
  }
57
67
  if (npm === null || npmTooLow) {
58
68
  packageJson.engines = { ...packageJson.engines, npm: constraint };
59
69
  this.project.writeJson('package.json', packageJson);
60
70
  }
61
- this.project.write('.npmrc', upsertNpmrc(npmrcContents, {
71
+ this.project.write('.npmrc', appendNpmrcList(upsertNpmrc(npmrcContents, {
62
72
  'engine-strict': 'true',
63
73
  'min-release-age': String(minReleaseAgeDays),
64
- }));
74
+ }), 'min-release-age-exclude', notExcluded));
65
75
  return this.fix(true);
66
76
  }
67
77
  }
@@ -1 +1 @@
1
- {"version":3,"file":"hardens-npm-supply-chain-check.js","sourceRoot":"","sources":["../../src/checks/hardens-npm-supply-chain-check.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hardens-npm-supply-chain-check.js","sourceRoot":"","sources":["../../src/checks/hardens-npm-supply-chain-check.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,9 @@ import { Check, type CheckResult } from './check.js';
3
3
  * The JS counterpart of the PHP runner's isCiLintComplete: same intent, different
4
4
  * toolchain — the linter and type checker must actually run in `ci-lint`, not
5
5
  * just be installed.
6
+ *
7
+ * Which linter is the project's choice: every one it installs has to run, and it
8
+ * has to install at least one.
6
9
  */
7
10
  export declare class IsCiLintCompleteCheck extends Check {
8
11
  static readonly checkName = "isCiLintComplete";
@@ -4,18 +4,33 @@ import { Check } from './check.js';
4
4
  * The JS counterpart of the PHP runner's isCiLintComplete: same intent, different
5
5
  * toolchain — the linter and type checker must actually run in `ci-lint`, not
6
6
  * just be installed.
7
+ *
8
+ * Which linter is the project's choice: every one it installs has to run, and it
9
+ * has to install at least one.
7
10
  */
8
11
  export class IsCiLintCompleteCheck extends Check {
9
12
  static checkName = 'isCiLintComplete';
10
13
  check() {
11
- const script = this.project.readJson('package.json')?.scripts?.['ci-lint'];
14
+ const packageJson = this.project.readJson('package.json');
15
+ const script = packageJson?.scripts?.['ci-lint'];
12
16
  if (script === undefined) {
13
17
  this.comment('Missing ci-lint script in package.json: Add "ci-lint" to scripts section');
14
18
  return 'fail';
15
19
  }
16
- for (const required of policy().strings('ciLint.required.js')) {
17
- if (!script.includes(required)) {
18
- this.comment(`Incomplete ci-lint script in package.json: it must run "${required}"`);
20
+ const linters = policy().stringMap('ciLint.linters.js');
21
+ const installed = Object.keys(linters).filter((name) => packageJson?.dependencies?.[name] !== undefined ||
22
+ packageJson?.devDependencies?.[name] !== undefined);
23
+ if (installed.length === 0) {
24
+ this.comment(`No linter in package.json: install one of ${Object.keys(linters).join(', ')} and run it in the ci-lint script`);
25
+ return 'fail';
26
+ }
27
+ const required = [
28
+ ...installed.map((name) => linters[name]),
29
+ ...policy().strings('ciLint.required.js'),
30
+ ];
31
+ for (const command of required) {
32
+ if (!script.includes(command)) {
33
+ this.comment(`Incomplete ci-lint script in package.json: it must run "${command}"`);
19
34
  return 'fail';
20
35
  }
21
36
  }
@@ -1 +1 @@
1
- {"version":3,"file":"is-ci-lint-complete-check.js","sourceRoot":"","sources":["../../src/checks/is-ci-lint-complete-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,KAAK,EAAoB,MAAM,YAAY,CAAA;AAMpD;;;;GAIG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC5C,MAAM,CAAmB,SAAS,GAAG,kBAAkB,CAAA;IAEvD,KAAK;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAc,cAAc,CAAC,EAAE,OAAO,EAAE,CAAC,SAAS,CAAC,CAAA;QAEvF,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,CAAC,OAAO,CAAC,0EAA0E,CAAC,CAAA;YAExF,OAAO,MAAM,CAAA;QACjB,CAAC;QAED,KAAK,MAAM,QAAQ,IAAI,MAAM,EAAE,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,CAAC;YAC5D,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7B,IAAI,CAAC,OAAO,CAAC,2DAA2D,QAAQ,GAAG,CAAC,CAAA;gBAEpF,OAAO,MAAM,CAAA;YACjB,CAAC;QACL,CAAC;QAED,OAAO,MAAM,CAAA;IACjB,CAAC;CACJ"}
1
+ {"version":3,"file":"is-ci-lint-complete-check.js","sourceRoot":"","sources":["../../src/checks/is-ci-lint-complete-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAE,KAAK,EAAoB,MAAM,YAAY,CAAA;AAQpD;;;;;;;GAOG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC5C,MAAM,CAAmB,SAAS,GAAG,kBAAkB,CAAA;IAEvD,KAAK;QACD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAc,cAAc,CAAC,CAAA;QACtE,MAAM,MAAM,GAAG,WAAW,EAAE,OAAO,EAAE,CAAC,SAAS,CAAC,CAAA;QAEhD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACvB,IAAI,CAAC,OAAO,CAAC,0EAA0E,CAAC,CAAA;YAExF,OAAO,MAAM,CAAA;QACjB,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAA;QACvD,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CACzC,CAAC,IAAI,EAAE,EAAE,CACL,WAAW,EAAE,YAAY,EAAE,CAAC,IAAI,CAAC,KAAK,SAAS;YAC/C,WAAW,EAAE,eAAe,EAAE,CAAC,IAAI,CAAC,KAAK,SAAS,CACzD,CAAA;QAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,OAAO,CACR,6CAA6C,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,mCAAmC,CAClH,CAAA;YAED,OAAO,MAAM,CAAA;QACjB,CAAC;QAED,MAAM,QAAQ,GAAG;YACb,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAW,CAAC;YACnD,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,oBAAoB,CAAC;SAC5C,CAAA;QAED,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC7B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC5B,IAAI,CAAC,OAAO,CAAC,2DAA2D,OAAO,GAAG,CAAC,CAAA;gBAEnF,OAAO,MAAM,CAAA;YACjB,CAAC;QACL,CAAC;QAED,OAAO,MAAM,CAAA;IACjB,CAAC;CACJ"}
@@ -8,3 +8,10 @@ export declare function parseNpmrc(contents: string | null): Record<string, stri
8
8
  * lines and comments survive.
9
9
  */
10
10
  export declare function upsertNpmrc(contents: string | null, entries: Record<string, string>): string;
11
+ /**
12
+ * Every value of a list-valued key, written either `key[]=value` (npm's form) or
13
+ * as a repeated `key=value`. parseNpmrc() keeps only the last of those.
14
+ */
15
+ export declare function npmrcList(contents: string | null, key: string): string[];
16
+ /** Append `key[]=value` for each value, after whatever the file already holds. */
17
+ export declare function appendNpmrcList(contents: string, key: string, values: string[]): string;
@@ -33,4 +33,28 @@ export function upsertNpmrc(contents, entries) {
33
33
  }
34
34
  return `${lines.join('\n')}\n`;
35
35
  }
36
+ /**
37
+ * Every value of a list-valued key, written either `key[]=value` (npm's form) or
38
+ * as a repeated `key=value`. parseNpmrc() keeps only the last of those.
39
+ */
40
+ export function npmrcList(contents, key) {
41
+ const values = [];
42
+ for (const rawLine of (contents ?? '').split('\n')) {
43
+ const line = rawLine.trim();
44
+ const separator = line.indexOf('=');
45
+ if (line.startsWith('#') || line.startsWith(';') || separator === -1) {
46
+ continue;
47
+ }
48
+ const lineKey = line.slice(0, separator).trim();
49
+ if (lineKey === key || lineKey === `${key}[]`) {
50
+ values.push(line.slice(separator + 1).trim());
51
+ }
52
+ }
53
+ return values;
54
+ }
55
+ /** Append `key[]=value` for each value, after whatever the file already holds. */
56
+ export function appendNpmrcList(contents, key, values) {
57
+ const lines = contents.replace(/\n+$/, '').split('\n');
58
+ return `${[...lines, ...values.map((value) => `${key}[]=${value}`)].join('\n')}\n`;
59
+ }
36
60
  //# sourceMappingURL=npmrc.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"npmrc.js","sourceRoot":"","sources":["../../src/support/npmrc.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,QAAuB;IAC9C,MAAM,MAAM,GAA2B,EAAE,CAAA;IAEzC,KAAK,MAAM,OAAO,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAA;QAE3B,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACrF,SAAQ;QACZ,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QAEnC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAC9E,CAAC;IAED,OAAO,MAAM,CAAA;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,QAAuB,EAAE,OAA+B;IAChF,MAAM,QAAQ,GAAG,QAAQ,IAAI,EAAE,CAAA;IAC/B,MAAM,KAAK,GAAG,QAAQ,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAE7E,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,GAAG,GAAG,GAAG,IAAI,KAAK,EAAE,CAAA;QAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE,EAAE,CACxC,IAAI,MAAM,CAAC,QAAQ,GAAG,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CACxF,CAAA;QAED,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACpB,CAAC;aAAM,CAAC;YACJ,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,CAAA;QACvB,CAAC;IACL,CAAC;IAED,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAA;AAClC,CAAC"}
1
+ {"version":3,"file":"npmrc.js","sourceRoot":"","sources":["../../src/support/npmrc.ts"],"names":[],"mappings":"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"}
@@ -96,6 +96,8 @@ Produce a written summary:
96
96
  ones the developer approves. Never cross a version constraint automatically.
97
97
  - **Respect the install cooldown.** `.npmrc` sets `min-release-age`, so a version published within
98
98
  that window is deliberately skipped. Do not lower or bypass it to pull in a fresh release.
99
+ Packages listed under `min-release-age-exclude[]` (at least `@limenet-ch/baseline`) are exempt
100
+ and resolve to their newest version right away.
99
101
  - **Keep Biome's `$schema` in sync.** If `biome` is installed and its version changed, update the
100
102
  `$schema` URL in `biome.json` to match the new version (e.g.
101
103
  `https://biomejs.dev/schemas/<new-version>/schema.json`). Skip this if there is no `biome.json` or
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@limenet-ch/baseline",
3
- "version": "2.10.0",
3
+ "version": "2.12.0",
4
4
  "description": "A highly opinionated baseline for JS/TS projects.",
5
5
  "keywords": [
6
6
  "baseline",
@@ -51,17 +51,17 @@
51
51
  },
52
52
  "dependencies": {
53
53
  "semver": "^7.8.5",
54
- "yaml": "^2.9.0"
54
+ "yaml": "^2.9.1"
55
55
  },
56
56
  "devDependencies": {
57
- "@biomejs/biome": "^2.5.10",
58
- "@release-it/bumper": "^8.0.0",
59
- "@release-it/conventional-changelog": "^12.0.0",
57
+ "@biomejs/biome": "^2.5.14",
58
+ "@release-it/bumper": "^8.0.1",
59
+ "@release-it/conventional-changelog": "^12.0.2",
60
60
  "@types/node": "^24.10.1",
61
61
  "@types/semver": "^7.8.0",
62
62
  "conventional-changelog-conventionalcommits": "^10.4.0",
63
- "release-it": "^21.0.2",
63
+ "release-it": "^21.1.0",
64
64
  "typescript": "^7.0.2",
65
- "vitest": "^4.1.11"
65
+ "vitest": "^5.0.2"
66
66
  }
67
67
  }
@@ -7,6 +7,9 @@
7
7
  "minMajor": "12",
8
8
  "constraint": "^12",
9
9
  "minReleaseAgeDays": 7,
10
+ "minReleaseAgeExclude": {
11
+ "js": ["@limenet-ch/baseline"]
12
+ },
10
13
  "engineStrict": true
11
14
  },
12
15
  "biome": {
@@ -104,7 +107,13 @@
104
107
  "ciLint": {
105
108
  "required": {
106
109
  "php": ["pint --parallel", "phpstan"],
107
- "js": ["biome", "tsc"]
110
+ "js": ["tsc"]
111
+ },
112
+ "linters": {
113
+ "js": {
114
+ "@biomejs/biome": "biome",
115
+ "eslint": "eslint"
116
+ }
108
117
  },
109
118
  "baselineCommand": {
110
119
  "js": "baseline check"
@@ -42,7 +42,13 @@
42
42
  "npm": {
43
43
  "type": "object",
44
44
  "additionalProperties": false,
45
- "required": ["minMajor", "constraint", "minReleaseAgeDays", "engineStrict"],
45
+ "required": [
46
+ "minMajor",
47
+ "constraint",
48
+ "minReleaseAgeDays",
49
+ "minReleaseAgeExclude",
50
+ "engineStrict"
51
+ ],
46
52
  "properties": {
47
53
  "minMajor": { "type": "string", "pattern": "^\\d+$" },
48
54
  "constraint": {
@@ -54,6 +60,15 @@
54
60
  "minimum": 0,
55
61
  "description": "Install-time cooldown in days: npm skips versions younger than this."
56
62
  },
63
+ "minReleaseAgeExclude": {
64
+ "type": "object",
65
+ "additionalProperties": false,
66
+ "required": ["js"],
67
+ "description": "Packages .npmrc must exempt from the cooldown via min-release-age-exclude[]. js only: it is the npm runner itself, which a Laravel project never installs, and a baseline fix should not wait a week to reach its consumers.",
68
+ "properties": {
69
+ "js": { "type": "array", "items": { "type": "string" } }
70
+ }
71
+ },
57
72
  "engineStrict": {
58
73
  "type": "boolean",
59
74
  "description": "Whether .npmrc must set engine-strict, making the engines requirement enforced rather than advisory."
@@ -197,7 +212,7 @@
197
212
  "ciLint": {
198
213
  "type": "object",
199
214
  "additionalProperties": false,
200
- "required": ["required", "baselineCommand"],
215
+ "required": ["required", "linters", "baselineCommand"],
201
216
  "properties": {
202
217
  "required": {
203
218
  "type": "object",
@@ -209,6 +224,19 @@
209
224
  "js": { "type": "array", "items": { "type": "string" } }
210
225
  }
211
226
  },
227
+ "linters": {
228
+ "type": "object",
229
+ "additionalProperties": false,
230
+ "required": ["js"],
231
+ "description": "Linter package => the command ci-lint must run when that package is installed. At least one must be installed.",
232
+ "properties": {
233
+ "js": {
234
+ "type": "object",
235
+ "additionalProperties": { "type": "string" },
236
+ "minProperties": 1
237
+ }
238
+ }
239
+ },
212
240
  "baselineCommand": {
213
241
  "type": "object",
214
242
  "additionalProperties": false,