@cascivo/eslint-config 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) cascivo contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ <!-- generated by scripts/readme/generate.ts — edit readme.body.md, not this file -->
2
+
3
+ <div align="center">
4
+ <a href="https://cascivo.com"><img src="https://cascivo.com/favicon.svg" width="72" height="72" alt="cascivo logo"></a>
5
+ <h1>@cascivo/eslint-config</h1>
6
+ <p><strong>Flat ESLint config for apps using cascivo — reconciles the signal-based reactivity contract with eslint-plugin-react-hooks 7</strong></p>
7
+
8
+ [![npm](https://img.shields.io/npm/v/%40cascivo%2Feslint-config?style=flat-square&color=0079bf)](https://www.npmjs.com/package/@cascivo/eslint-config)
9
+ [![downloads](https://img.shields.io/npm/dm/%40cascivo%2Feslint-config?style=flat-square&color=0079bf)](https://www.npmjs.com/package/@cascivo/eslint-config)
10
+ [![license](https://img.shields.io/npm/l/%40cascivo%2Feslint-config?style=flat-square&color=0079bf)](https://github.com/cascivo/cascivo/blob/main/LICENSE)
11
+ ![types](https://img.shields.io/badge/types-included-0079bf?style=flat-square&logo=typescript&logoColor=white)
12
+
13
+ [npm](https://www.npmjs.com/package/@cascivo/eslint-config) · [cascivo.com](https://cascivo.com) · [Docs](https://cascivo.com/docs) · [Storybook](https://storybook.cascivo.com) · [GitHub](https://github.com/cascivo/cascivo)
14
+
15
+ </div>
16
+
17
+ ---
18
+
19
+ ## Install
20
+
21
+ ```sh
22
+ pnpm add @cascivo/eslint-config
23
+ ```
24
+
25
+ ---
26
+
27
+ [cascivo.com](https://cascivo.com) · [Docs](https://cascivo.com/docs) · [Storybook](https://storybook.cascivo.com) · [GitHub](https://github.com/cascivo/cascivo) · AI agents: read [`llms.txt`](https://cascivo.com/llms.txt) (install steps + component index, plain text) or use [`@cascivo/mcp`](https://github.com/cascivo/cascivo/tree/main/packages/mcp) and [`registry.json`](https://github.com/cascivo/cascivo/blob/main/registry.json) · MIT
28
+
29
+ <div align="center"><a href="https://cascivo.com"><img src="https://cascivo.com/favicon.svg" width="28" height="28" alt="cascivo"></a></div>
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@cascivo/eslint-config",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "description": "Flat ESLint config for apps using cascivo — reconciles the signal-based reactivity contract with eslint-plugin-react-hooks 7",
6
+ "keywords": [
7
+ "cascivo",
8
+ "design-system",
9
+ "eslint",
10
+ "eslint-config",
11
+ "react",
12
+ "react-hooks",
13
+ "signals"
14
+ ],
15
+ "homepage": "https://github.com/cascivo/cascivo/tree/main/packages/eslint-config#readme",
16
+ "bugs": "https://github.com/cascivo/cascivo/issues",
17
+ "license": "MIT",
18
+ "author": "urbanisierung",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/cascivo/cascivo.git",
22
+ "directory": "packages/eslint-config"
23
+ },
24
+ "files": [
25
+ "src/**/*.js",
26
+ "src/**/*.d.ts",
27
+ "!src/**/*.test.js"
28
+ ],
29
+ "type": "module",
30
+ "exports": {
31
+ "./package.json": "./package.json",
32
+ ".": {
33
+ "types": "./src/index.d.ts",
34
+ "default": "./src/index.js"
35
+ }
36
+ },
37
+ "publishConfig": {
38
+ "access": "public",
39
+ "provenance": true
40
+ },
41
+ "scripts": {
42
+ "build": "echo 'eslint-config: plain ESM, no build'",
43
+ "test": "node --test src/index.test.js"
44
+ }
45
+ }
package/src/index.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Flat-config fragments for apps using cascivo.
3
+ *
4
+ * Typed loosely on purpose: ESLint's flat-config object type lives in `eslint`, which this
5
+ * package deliberately does not depend on — it ships plain data, so it stays installable
6
+ * next to any ESLint 9+ without a version handshake.
7
+ */
8
+
9
+ /** A single ESLint flat-config object. */
10
+ export interface CascadeFlatConfig {
11
+ name?: string
12
+ files?: string[]
13
+ rules?: Record<string, unknown>
14
+ linterOptions?: Record<string, unknown>
15
+ }
16
+
17
+ /**
18
+ * Turns off `react-hooks/immutability`, which reports cascivo's mandatory signal-write
19
+ * idiom (`signal.value = next`) as an error under `eslint-plugin-react-hooks@7`'s
20
+ * `recommended-latest`. Applies to all files — signal writes live in your own page code,
21
+ * not only in vendored source.
22
+ */
23
+ export declare const cascivoSignals: CascadeFlatConfig
24
+
25
+ /**
26
+ * Scopes host stylistic rules off source vendored by `cascivo add`. Copy-paste path only.
27
+ *
28
+ * @param glob Your `outputDir` from `cascivo.config.ts`. Defaults to `src/components/ui/**`.
29
+ */
30
+ export declare function cascivoVendoredSource(glob?: string): CascadeFlatConfig
31
+
32
+ /** Both fragments. Spread last in your flat config — last-wins. */
33
+ declare const cascivo: CascadeFlatConfig[]
34
+ export default cascivo
package/src/index.js ADDED
@@ -0,0 +1,108 @@
1
+ /**
2
+ * `@cascivo/eslint-config` — flat-config fragments for apps that use cascivo.
3
+ *
4
+ * ## Why this package exists
5
+ *
6
+ * `eslint-plugin-react-hooks@7` ships `react-hooks/immutability`, enabled by default in
7
+ * `recommended-latest`. It reports any write to a value returned from a hook — which is
8
+ * exactly cascivo's mandatory state idiom:
9
+ *
10
+ * ```
11
+ * error Error: This value cannot be modified
12
+ * Modifying a value returned from a hook is not allowed.
13
+ * onValueChange={(v) => (env.value = v)}
14
+ * ^^^ `env` cannot be modified
15
+ * ```
16
+ *
17
+ * `docs/AI-RULES.md` says "Local state -> `useSignal(initial)` … Never `useState`", and
18
+ * `docs/HEADLESS.md`'s canonical example is `onClick={() => (open.value = !open.value)}`.
19
+ * So a stock 2026 React app lints the documented idiom as an error on every piece of state
20
+ * the adopter wrote. One reported build hit this 8 times across 3 files — every lint error
21
+ * in the app, and nothing else.
22
+ *
23
+ * ## Why the rule is turned off rather than narrowed
24
+ *
25
+ * A signal write through `.value` is a deliberate mutation of a live reactive cell; that is
26
+ * the whole point of the primitive. The rule cannot distinguish it from an accidental
27
+ * mutation of `useState` output, and it has no allowlist option for hook names. There is no
28
+ * narrower mechanism, so the honest thing is to turn it off and say what that costs:
29
+ * **you lose the rule's protection against genuinely mutating React state elsewhere in the
30
+ * file.** If that matters more to you than ergonomics, drop `cascivoSignals` and write
31
+ * `signal.value = x` behind a `// eslint-disable-next-line` at each site instead.
32
+ *
33
+ * ## Usage
34
+ *
35
+ * ```js
36
+ * // eslint.config.js
37
+ * import cascivo from '@cascivo/eslint-config'
38
+ *
39
+ * export default [
40
+ * // …your existing config…
41
+ * ...cascivo,
42
+ * ]
43
+ * ```
44
+ *
45
+ * Spread it AFTER the configs it adjusts — flat config is last-wins.
46
+ *
47
+ * Prefer the pieces individually when you only vendor source, or only use the package:
48
+ *
49
+ * ```js
50
+ * import { cascivoSignals, cascivoVendoredSource } from '@cascivo/eslint-config'
51
+ * export default [...yourConfig, cascivoSignals, cascivoVendoredSource()]
52
+ * ```
53
+ */
54
+
55
+ /**
56
+ * Reconciles `eslint-plugin-react-hooks@7` with cascivo's signal-based reactivity.
57
+ *
58
+ * Applies everywhere by default — signal writes live in *your* page and component code,
59
+ * not just in vendored files, so a directory-scoped override cannot cover them. That is
60
+ * precisely why the pre-existing `src/components/ui/**` recipe did not help prebuilt-path
61
+ * (Path B) adopters, who have no such directory at all.
62
+ */
63
+ export const cascivoSignals = {
64
+ name: 'cascivo/signals',
65
+ rules: {
66
+ // See the module header for the full rationale and what turning this off costs.
67
+ 'react-hooks/immutability': 'off',
68
+ },
69
+ }
70
+
71
+ /**
72
+ * Host stylistic rules scoped off source you vendored with `cascivo add`.
73
+ *
74
+ * Only relevant on the copy-paste path (Path A). `cascivo update` re-copies these files, so
75
+ * any in-place style fixes are undone on the next update — scoping the rules off is the
76
+ * durable move. Correctness rules stay on.
77
+ *
78
+ * @param {string} [glob] Your `outputDir` from `cascivo.config.ts`, as a glob.
79
+ */
80
+ export function cascivoVendoredSource(glob = 'src/components/ui/**') {
81
+ return {
82
+ name: 'cascivo/vendored-source',
83
+ files: [glob],
84
+ rules: {
85
+ // Style: `T[]` vs `Array<T>`, import ordering, generic-param naming (`Row` vs
86
+ // `TRow`), method-signature style — cascivo does not adopt these.
87
+ '@typescript-eslint/array-type': 'off',
88
+ '@typescript-eslint/naming-convention': 'off',
89
+ '@typescript-eslint/method-signature-style': 'off',
90
+ 'sort-imports': 'off',
91
+ 'import/order': 'off',
92
+ // Opinionated / misfires on legitimate cascivo patterns:
93
+ 'react/no-array-index-key': 'off', // stable-content lists key by index intentionally
94
+ 'no-shadow': 'off', // false-positives on TS declaration merging (compound components)
95
+ 'no-control-regex': 'off', // e.g. the log viewer strips ANSI escapes (\x1b) on purpose
96
+ },
97
+ linterOptions: {
98
+ // cascivo's rule-scoped `eslint-disable` directives may target rule ids your config
99
+ // doesn't define — don't report them as "unused".
100
+ reportUnusedDisableDirectives: 'off',
101
+ },
102
+ }
103
+ }
104
+
105
+ /** Both fragments, in the order flat config wants them. Spread last. */
106
+ const cascivo = [cascivoSignals, cascivoVendoredSource()]
107
+
108
+ export default cascivo