@ploaness/config 1.0.0 → 1.2.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/dist/eslint.js CHANGED
@@ -10,19 +10,23 @@
10
10
  //
11
11
  // Philosophy: maximum-explicit. The build should be hard to satisfy by accident, so that code which
12
12
  // passes is verbose, explicit and readable by construction.
13
- import { REEXPORT_CONFIG_FILES } from '@ploaness/governance';
13
+ import nextPlugin from '@next/eslint-plugin-next';
14
+ import { APPLICATION_JSX_IGNORES, ENVIRONMENT_READ_EXEMPTIONS, REEXPORT_CONFIG_FILES, } from '@ploaness/governance';
14
15
  //
15
16
  // The framework-neutral half - the caps, the explicitness rules, the naming ban, the suppression
16
17
  // discipline, the mock ban - lives in ./eslint-core.js and is shared with the ploaness repository's own
17
18
  // lint run. What stays here is what is genuinely about Payload and Next: the generated mount, the
18
19
  // collection configs, the environment module, the a11y layer, and the test-integrity block.
19
- import jsxA11y from 'eslint-plugin-jsx-a11y';
20
20
  import testingLibrary from 'eslint-plugin-testing-library';
21
- import { baseLayers, compose, guidelineRules, immutabilityBlock, NO_INHERITANCE, NO_MOCK_PROPERTIES, NO_NETWORK_GUARD_ESCAPE, prettierLast, processConfigBlock, specEnvironmentBlock, testIdiomRules, testIntegrityRules, testSuiteSyntaxRules, typeAwareParsing, vitestPlugin, } from './eslint-core.js';
21
+ import { baseLayers, compose, guidelineRules, hookContextBlock, immutabilityBlock, NO_INHERITANCE, NO_MOCK_PROPERTIES, NO_NETWORK_GUARD_ESCAPE, prettierLast, processConfigBlock, specEnvironmentBlock, testIdiomRules, testIntegrityRules, testSuiteSyntaxRules, typeAwareParsing, vitestPlugin, withoutWarnings, } from './eslint-core.js';
22
+ import { SECURITY_RESTRICTIONS } from './eslint-security.js';
22
23
  import { projectSettings as settings } from './project-settings.js';
24
+ // Where a Payload project writes its hooks, and therefore the one place `req.context` is written.
25
+ const PAYLOAD_HOOK_FILES = ['src/hooks/**'];
23
26
  const NO_INLINE_CONFIG_FUNCTIONS_SELECTOR = 'ArrowFunctionExpression, FunctionExpression';
24
- const NO_INLINE_CONFIG_FUNCTIONS_MESSAGE = 'No inline functions in collection/global/field/block configs. Define behavior (access, hooks, ' +
25
- 'validate) in src/access or src/lib so it is unit-tested, then import it by reference.';
27
+ const NO_INLINE_CONFIG_FUNCTIONS_MESSAGE = 'No inline functions in collection/global/field/block configs. Define access and pure rules in ' +
28
+ 'src/access or src/lib, where the unit suite covers them, and a hook or validator that needs the ' +
29
+ 'request in src/hooks; then import it by reference.';
26
30
  // `unicorn/prefer-export-from` rewrites `import x from 'y'` + `export default x` into
27
31
  // `export { default } from 'y'` - and it AUTOFIXES, so `ploaness format` turned a correctly wired
28
32
  // project into one the `wiring` gate then rejected, every time it ran. Two rules this harness owns,
@@ -38,10 +42,7 @@ export default compose(
38
42
  // ── What is never linted ────────────────────────────────────────────────────────────────────
39
43
  {
40
44
  ignores: [
41
- '.next/**',
42
- 'node_modules/**',
43
- 'coverage/**',
44
- 'pgadmin/**',
45
+ ...APPLICATION_JSX_IGNORES,
45
46
  '**/*.d.ts',
46
47
  'src/payload-types.ts',
47
48
  ...settings.generatedArtefacts,
@@ -60,7 +61,6 @@ export default compose(
60
61
  // parsing error rather than a finding, on every run, with no edit a project is permitted to make
61
62
  // that would clear it: `include` is dictated and this config is re-exported verbatim. Biome and
62
63
  // the conventions gate still read these files.
63
- '.*/**',
64
64
  ],
65
65
  }, ...baseLayers,
66
66
  // Type-aware parsing against the consuming project's own tsconfig, plus the shared rule set.
@@ -74,6 +74,10 @@ immutabilityBlock(['**/*.ts', '**/*.tsx'], [...settings.frameworkGlue, 'src/payl
74
74
  processConfigBlock(),
75
75
  // And the spec's, which is to vary the environment rather than to fix it. Same ordering constraint.
76
76
  specEnvironmentBlock(),
77
+ // The hook directories, where Payload's per-request state is written. `src/hooks` is the layer the
78
+ // project layout names for hooks; a hook written into `src/lib` is the pure floor claiming to be pure
79
+ // and is held to the full rule.
80
+ hookContextBlock(PAYLOAD_HOOK_FILES),
77
81
  // ── Documenting comment blocks on hand-written modules. Default-safe: every src/ TypeScript module
78
82
  // is in scope, with only the app/route layer, scripts, and generated files exempted (they carry
79
83
  // no reusable API). A new logic directory is therefore held to the rule the moment it exists. ──
@@ -105,15 +109,29 @@ specEnvironmentBlock(),
105
109
  '@typescript-eslint/explicit-module-boundary-types': 'off',
106
110
  },
107
111
  },
108
- // ── Accessibility: lint JSX for a11y defects - missing alt text, unlabeled controls, invalid or
109
- // misused ARIA, click handlers with no keyboard equivalent, non-focusable interactive elements.
110
- // This is pure static analysis, so it is deterministic (never flaky) and the baseline every site
111
- // needs. What it CANNOT see (it does not render): color contrast, focus order, real keyboard
112
- // navigation - those need a browser and are covered by axe-in-e2e (see AGENTS.md testing policy).
112
+ // Application JSX accessibility is owned by the Oxlint gate. Its rule registry also generates
113
+ // Biome's matching exclusions, while this configuration keeps the remaining typed checks.
114
+ // ── Core Web Vitals: the static half of a measurement no gate can take. A vitals score, like a
115
+ // Lighthouse score, moves between two runs of an unchanged tree and would measure `next dev`'s
116
+ // on-demand compiler rather than the application, which is why neither is a gate. The CAUSES of a
117
+ // bad score are static and known - a raw `<img>` where `next/image` would size and lazy-load it, a
118
+ // synchronous `<script>`, an `<a>` for an internal route, a Google font with no `display` - and
119
+ // Next publishes exactly that list as its core-web-vitals preset. The preset is mounted whole and
120
+ // raised through `withoutWarnings`, because it leaves 14 of its 22 rules at `warn` and a warning is
121
+ // not a verdict here; nothing is turned off, so this is the preset by name and provenance rather
122
+ // than a hand copy of it that would go stale on the next Next.
123
+ //
124
+ // `src/**` only, because the rules judge what the application renders and serves. A component
125
+ // test rendering an `<img>` under jsdom serves nothing, for the same reason test code is not held
126
+ // to the bundle budget. `.ts` is in beside `.tsx` because three of the rules are not JSX rules at
127
+ // all: a module variable assigned, a `document` imported into a page, a relative
128
+ // `location.assign`.
129
+ //
130
+ // The version is tied to the `next` pin in pins.json - `pins-agree.spec.ts` holds the joint -
131
+ // since the two are published together and the rules describe one release's semantics.
113
132
  {
114
- files: ['**/*.tsx'],
115
- plugins: { 'jsx-a11y': jsxA11y },
116
- rules: jsxA11y.flatConfigs.recommended.rules,
133
+ ...withoutWarnings(nextPlugin.configs['core-web-vitals']),
134
+ files: ['src/**/*.ts', 'src/**/*.tsx'],
117
135
  },
118
136
  // ── Generated Payload mount only: relax type-safety the framework legitimately defeats.
119
137
  // Scoped to `src/app/(payload)/**` (the create-payload-app scaffold + API re-exports), NOT all
@@ -159,6 +177,7 @@ specEnvironmentBlock(),
159
177
  rules: {
160
178
  'no-restricted-syntax': [
161
179
  ...NO_INHERITANCE,
180
+ ...SECURITY_RESTRICTIONS,
162
181
  {
163
182
  selector: NO_INLINE_CONFIG_FUNCTIONS_SELECTOR,
164
183
  message: NO_INLINE_CONFIG_FUNCTIONS_MESSAGE,
@@ -177,7 +196,7 @@ specEnvironmentBlock(),
177
196
  // `environment.ts` could have validated.
178
197
  {
179
198
  files: ['src/**/*.ts'],
180
- ignores: ['src/lib/environment.ts', 'src/proxy.ts'],
199
+ ignores: [...ENVIRONMENT_READ_EXEMPTIONS],
181
200
  rules: {
182
201
  // `NO_MOCK_PROPERTIES` is spread in beside the env rule because this key REPLACES the base
183
202
  // setting rather than adding to it - naming only the env restriction here switched the
@@ -223,11 +242,37 @@ specEnvironmentBlock(),
223
242
  // test must contain a real assertion. The testing-library rules keep component tests user-facing
224
243
  // (query by role/text); assertions use the @testing-library/jest-dom matchers, which a project
225
244
  // registers in a `vitest.setup.ts` of its own if it writes component tests.
226
- // Scoped to the Vitest suite (`tests/int` + `tests/unit`); Playwright e2e specs use a different
227
- // runner (and its own unconditional `forbidOnly`), so these Vitest/RTL rules do not apply there.
245
+ // Scoped to every directory `vitest.ts` collects - `tests/int`, `tests/unit` and `tests/component`
246
+ // - because a suite the runner runs and the linter does not reach is a suite held to no standard.
247
+ // The component directory was missed for exactly that reason, and the rules that name it in the
248
+ // sentence above were the ones it escaped: a consumer's component specs ran under a jsdom suite
249
+ // this harness mandates while every `testing-library/*` rule, `no-disabled-tests`,
250
+ // `no-commented-out-tests` and the literal-assertion ban passed over them. Playwright e2e specs
251
+ // use a different runner, with its own unconditional `forbidOnly`, so these rules stay out of it.
228
252
  {
229
- files: ['tests/int/**/*.ts', 'tests/int/**/*.tsx', 'tests/unit/**/*.ts', 'tests/unit/**/*.tsx'],
253
+ files: [
254
+ 'tests/int/**/*.ts',
255
+ 'tests/int/**/*.tsx',
256
+ 'tests/unit/**/*.ts',
257
+ 'tests/unit/**/*.tsx',
258
+ 'tests/component/**/*.ts',
259
+ 'tests/component/**/*.tsx',
260
+ ],
230
261
  plugins: { vitest: vitestPlugin, 'testing-library': testingLibrary },
262
+ // The plugin decides what a query IS by name, matching `/^(get|query|find)(All)?By.+$/`, and in its
263
+ // default "aggressive" mode it treats every match as one - a deliberate reach, so that a project's
264
+ // own `findByLabel` wrapper is linted like the built-in it wraps. In a Payload project that reach
265
+ // lands on the framework: `payload.findByID(...)` matches, so every read in an integration spec is
266
+ // reported as an unhandled query. The autofix then compounds it, inserting `await` in front of the
267
+ // ARGUMENT rather than the call, so `ploaness format` turns a correct spec into one that no longer
268
+ // type-checks. An agent meeting that has no true repair available and the cheap escapes - a
269
+ // suppression, a weakened test - are the ones the integrity rules above exist to prevent.
270
+ //
271
+ // Switching the setting off narrows detection to the built-in Testing Library names, which is
272
+ // exactly the set these rules were written for. What it costs is that a project's own custom query
273
+ // helper is no longer linted; the harness already asks specs to query by role and text, so that is
274
+ // a small surface, and it is the half of the reach that cannot tell a query from a database read.
275
+ settings: { 'testing-library/custom-queries': 'off' },
231
276
  rules: {
232
277
  // A test must actually run and actually assert. The rules live in eslint-core.js, because the
233
278
  // ploaness repository's own suite is held to them too.
@@ -253,7 +298,11 @@ specEnvironmentBlock(),
253
298
  {
254
299
  files: ['tests/e2e/**/*.ts', 'tests/e2e/**/*.tsx'],
255
300
  rules: {
256
- 'no-restricted-syntax': [...NO_INHERITANCE, ...NO_NETWORK_GUARD_ESCAPE],
301
+ 'no-restricted-syntax': [
302
+ ...NO_INHERITANCE,
303
+ ...SECURITY_RESTRICTIONS,
304
+ ...NO_NETWORK_GUARD_ESCAPE,
305
+ ],
257
306
  },
258
307
  },
259
308
  // ── Formatting is Biome's job - disable every conflicting stylistic rule (must stay last) ────
@@ -1 +1 @@
1
- {"version":3,"file":"eslint.js","sourceRoot":"","sources":["../src/eslint.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"eslint.js","sourceRoot":"","sources":["../src/eslint.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"project-settings.d.ts","sourceRoot":"","sources":["../src/project-settings.ts"],"names":[],"mappings":"AAOA,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAelE,eAAO,MAAM,eAAe,EAAE,QAA0C,CAAA"}
1
+ {"version":3,"file":"project-settings.d.ts","sourceRoot":"","sources":["../src/project-settings.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,QAAQ,EACd,MAAM,sBAAsB,CAAA;AA6C7B,eAAO,MAAM,eAAe,EAAE,QAAqC,CAAA"}
@@ -1,23 +1,47 @@
1
- // The consuming project's declared settings, read once from the package.json in the working directory.
2
- //
3
- // Three shipped configurations need them - the Vitest config, the Playwright config, and the constants
4
- // the managed accessibility sweep imports - and none of them may carry a second copy of this reader. A
5
- // value the harness both writes and judges is declared once; the same holds for the value it reads.
1
+ // Read the consumer's settings from the working directory, where its tools are invoked.
6
2
  import { readFileSync } from 'node:fs';
7
3
  import path from 'node:path';
8
- import { readSettings } from '@ploaness/governance';
4
+ import { ploanessBlock, readMemberSettings, readSettings, } from '@ploaness/governance';
9
5
  // A project whose package.json cannot be read gets the defaults, which are the strict end of every
10
6
  // setting. Failing to parse must never be the thing that loosens a threshold.
11
7
  // `unknown` rather than the parse's own `any`: `readSettings` narrows every field it reads, so handing
12
8
  // it an `any` would only move the narrowing somewhere nothing checks it.
13
- const readPackageJson = () => {
14
- const manifest = path.join(process.cwd(), 'package.json');
9
+ const readPackageJson = (directory) => {
15
10
  try {
16
- return JSON.parse(readFileSync(manifest, 'utf8'));
11
+ return JSON.parse(readFileSync(path.join(directory, 'package.json'), 'utf8'));
17
12
  }
18
13
  catch {
19
14
  return {};
20
15
  }
21
16
  };
22
- export const projectSettings = readSettings(readPackageJson());
17
+ // What marks the repository root of a workspace. `pnpm-workspace.yaml` rather than `.git`, because it
18
+ // is the file that makes a directory a workspace root at all, and because a member checked out on its
19
+ // own is then correctly read as its own root rather than inheriting from whatever encloses it.
20
+ const WORKSPACE_MARKER = 'pnpm-workspace.yaml';
21
+ // Upwards from the member until the marker is found or the filesystem root is reached. Recursive
22
+ // rather than a loop, because this repository bans the mutable binding a loop would need.
23
+ const workspaceRootAbove = (directory) => {
24
+ const parent = path.dirname(directory);
25
+ if (parent === directory) {
26
+ return undefined;
27
+ }
28
+ try {
29
+ readFileSync(path.join(parent, WORKSPACE_MARKER), 'utf8');
30
+ return parent;
31
+ }
32
+ catch {
33
+ return workspaceRootAbove(parent);
34
+ }
35
+ };
36
+ const settingsFor = (member) => {
37
+ const own = readPackageJson(member);
38
+ const repositoryRoot = workspaceRootAbove(member);
39
+ if (repositoryRoot === undefined) {
40
+ // The ordinary case: one package, which is its own repository. Layering a block onto itself would
41
+ // append every additive list to a copy of itself rather than leaving it alone.
42
+ return readSettings(own);
43
+ }
44
+ return readMemberSettings(ploanessBlock(readPackageJson(repositoryRoot)), ploanessBlock(own));
45
+ };
46
+ export const projectSettings = settingsFor(process.cwd());
23
47
  //# sourceMappingURL=project-settings.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"project-settings.js","sourceRoot":"","sources":["../src/project-settings.ts"],"names":[],"mappings":"AAAA,uGAAuG;AACvG,EAAE;AACF,uGAAuG;AACvG,uGAAuG;AACvG,oGAAoG;AACpG,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAiB,MAAM,sBAAsB,CAAA;AAElE,mGAAmG;AACnG,8EAA8E;AAC9E,uGAAuG;AACvG,yEAAyE;AACzE,MAAM,eAAe,GAAG,GAAY,EAAE;IACpC,MAAM,QAAQ,GAAW,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC,CAAA;IACjE,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAA;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAa,YAAY,CAAC,eAAe,EAAE,CAAC,CAAA"}
1
+ {"version":3,"file":"project-settings.js","sourceRoot":"","sources":["../src/project-settings.ts"],"names":[],"mappings":"AAAA,wFAAwF;AACxF,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,YAAY,GAEb,MAAM,sBAAsB,CAAA;AAE7B,mGAAmG;AACnG,8EAA8E;AAC9E,uGAAuG;AACvG,yEAAyE;AACzE,MAAM,eAAe,GAAG,CAAC,SAAiB,EAAW,EAAE;IACrD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAA;IAC/E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC,CAAA;AAED,sGAAsG;AACtG,sGAAsG;AACtG,+FAA+F;AAC/F,MAAM,gBAAgB,GAAW,qBAAqB,CAAA;AAEtD,iGAAiG;AACjG,0FAA0F;AAC1F,MAAM,kBAAkB,GAAG,CAAC,SAAiB,EAAsB,EAAE;IACnE,MAAM,MAAM,GAAW,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IAC9C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,IAAI,CAAC;QACH,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC,CAAA;QACzD,OAAO,MAAM,CAAA;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,kBAAkB,CAAC,MAAM,CAAC,CAAA;IACnC,CAAC;AACH,CAAC,CAAA;AAED,MAAM,WAAW,GAAG,CAAC,MAAc,EAAY,EAAE;IAC/C,MAAM,GAAG,GAAY,eAAe,CAAC,MAAM,CAAC,CAAA;IAC5C,MAAM,cAAc,GAAuB,kBAAkB,CAAC,MAAM,CAAC,CAAA;IACrE,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;QACjC,kGAAkG;QAClG,+EAA+E;QAC/E,OAAO,YAAY,CAAC,GAAG,CAAC,CAAA;IAC1B,CAAC;IACD,OAAO,kBAAkB,CAAC,aAAa,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC,EAAE,aAAa,CAAC,GAAG,CAAC,CAAC,CAAA;AAC/F,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAa,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ploaness/config",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "Analyzer and tool configurations owned by ploaness: ESLint, Biome, TypeScript, Vitest, Stylelint, dependency-cruiser, knip.",
5
5
  "license": "MIT",
6
6
  "author": "Herman Ciechanowiec <herman@ciechanowiec.eu>",
@@ -78,27 +78,27 @@
78
78
  "@axe-core/playwright": "4.13.0",
79
79
  "@eslint-community/eslint-plugin-eslint-comments": "4.7.2",
80
80
  "@eslint/js": "10.0.1",
81
+ "@next/eslint-plugin-next": "16.3.4",
81
82
  "@playwright/test": "1.62.1",
82
- "@ploaness/governance": "1.0.0",
83
+ "@ploaness/governance": "1.2.0",
83
84
  "@testing-library/jest-dom": "7.0.1",
84
85
  "@testing-library/react": "16.3.3",
85
- "@testing-library/user-event": "14.6.6",
86
+ "@testing-library/user-event": "14.6.7",
86
87
  "@vitejs/plugin-react": "6.1.1",
87
88
  "@vitest/eslint-plugin": "1.6.27",
88
89
  "eslint": "10.9.1",
89
90
  "eslint-config-prettier": "10.1.8",
90
91
  "eslint-plugin-functional": "10.0.0",
91
92
  "eslint-plugin-jsdoc": "64.2.1",
92
- "eslint-plugin-jsx-a11y": "6.10.2",
93
93
  "eslint-plugin-regexp": "3.2.0",
94
94
  "eslint-plugin-sonarjs": "4.2.0",
95
95
  "eslint-plugin-testing-library": "7.16.2",
96
- "eslint-plugin-unicorn": "73.0.0",
96
+ "eslint-plugin-unicorn": "74.0.0",
97
97
  "fast-check": "4.9.0",
98
- "globals": "17.11.0",
98
+ "globals": "17.12.0",
99
99
  "jsdom": "30.0.1",
100
100
  "stylelint-config-standard": "40.0.0",
101
- "typescript-eslint": "8.68.0",
101
+ "typescript-eslint": "8.69.0",
102
102
  "vitest": "4.1.11"
103
103
  },
104
104
  "engines": {
@@ -108,7 +108,7 @@
108
108
  "access": "public"
109
109
  },
110
110
  "devDependencies": {
111
- "@types/node": "26.4.0",
111
+ "@types/node": "26.4.1",
112
112
  "typescript": "6.0.3"
113
113
  },
114
114
  "scripts": {
package/pins.json CHANGED
@@ -22,7 +22,7 @@
22
22
  "requiredFor": ["payload", "application"],
23
23
  "why": "What any Next application renders with, whether or not Payload is mounted inside it. A public frontend has the same build, the same client bundle and the same React version to agree about.",
24
24
  "versions": {
25
- "next": "16.3.3",
25
+ "next": "16.3.4",
26
26
  "react": "19.2.8",
27
27
  "react-dom": "19.2.8",
28
28
  "@types/react": "19.2.18",
@@ -34,7 +34,7 @@
34
34
  "requiredFor": ["payload", "application", "library"],
35
35
  "why": "The definitions describing the runtime every governed package compiles against. Pinned for the toolchain's reason rather than the framework's: a type package is an input to tsc, so a patch release changes what type-checks while the project stays unchanged.",
36
36
  "versions": {
37
- "@types/node": "26.4.0"
37
+ "@types/node": "26.4.1"
38
38
  }
39
39
  },
40
40
  {
package/stylelint.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "reportDescriptionlessDisables": true,
6
6
  "reportNeedlessDisables": true,
7
7
  "reportInvalidScopeDisables": true,
8
- "$comment": "at-rule-no-unknown lists the Tailwind v4 at-rules because they are a CSS dialect a Payload project may legitimately be written in, not a carve-out for one repository's files. A project that uses no Tailwind never writes one, so the list costs it nothing, and a typo such as @theem still fails. The whole list is named rather than the subset one project happened to need: a missing entry sends the next project back to a config file it is not allowed to own, which is the wall this list exists to remove. import-notation follows for the same reason and is not a relaxation - Tailwind v4 mandates the string form (@import \"tailwindcss\"), so the url form the standard config wants cannot be written at all; the rule still enforces one notation, and the one it enforces is now the one that can exist. lightness-notation and hue-degree-notation are set to the NUMBER form rather than turned off, for the same reason the at-rules above are listed: ploaness admits Tailwind deliberately, and the generator most Tailwind projects theme with writes oklch(1 0 0) rather than oklch(100% 0deg). Demanding the percentage form failed every such project on CSS it never hand-wrote. One notation is still enforced; it is now the one that can actually exist. selector-id-pattern keeps kebab-case for every id a project names and admits the double-underscore roots a framework mounts into - Next renders #__next, and a stylesheet that has to reach it cannot rename it. Turning the rule off would have surrendered the ids a project does choose.",
8
+ "$comment": "at-rule-no-unknown lists the Tailwind v4 at-rules because they are a CSS dialect a Payload project may legitimately be written in, not a carve-out for one repository's files. A project that uses no Tailwind never writes one, so the list costs it nothing, and a typo such as @theem still fails. The whole list is named rather than the subset one project happened to need: a missing entry sends the next project back to a config file it is not allowed to own, which is the wall this list exists to remove. at-rule-prelude-no-invalid has its own ignore list, so it retains the standard config's media allowance and adds apply: the CSS syntax patch models an abandoned proposal whose prelude is a dashed identifier, while Tailwind writes a utility list. Other at-rule preludes remain validated. import-notation follows for the same reason and is not a relaxation - Tailwind v4 mandates the string form (@import \"tailwindcss\"), so the url form the standard config wants cannot be written at all; the rule still enforces one notation, and the one it enforces is now the one that can exist. lightness-notation and hue-degree-notation are set to the NUMBER form rather than turned off, for the same reason the at-rules above are listed: ploaness admits Tailwind deliberately, and the generator most Tailwind projects theme with writes oklch(1 0 0) rather than oklch(100% 0deg). Demanding the percentage form failed every such project on CSS it never hand-wrote. One notation is still enforced; it is now the one that can actually exist. selector-id-pattern keeps kebab-case for every id a project names and admits the double-underscore roots a framework mounts into - Next renders #__next, and a stylesheet that has to reach it cannot rename it. Turning the rule off would have surrendered the ids a project does choose.",
9
9
  "rules": {
10
10
  "at-rule-no-unknown": [
11
11
  true,
@@ -25,6 +25,7 @@
25
25
  ]
26
26
  }
27
27
  ],
28
+ "at-rule-prelude-no-invalid": [true, { "ignoreAtRules": ["media", "apply"] }],
28
29
  "import-notation": "string",
29
30
  "selector-pseudo-class-no-unknown": [
30
31
  true,