@ashstack/lint 0.4.0 → 0.5.1

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
@@ -1,6 +1,6 @@
1
1
  # @ashstack/lint
2
2
 
3
- Strict shared [oxlint](https://oxc.rs) config: <!-- rule-counts -->118 rules on plain TypeScript, 204 with React, 259 on React Native, 74 of them custom-built<!-- /rule-counts -->. Three entries, each containing the one before it: `core()`, `react()`, `react-native()`.
3
+ Strict shared [oxlint](https://oxc.rs) config: <!-- rule-counts -->118 rules on plain TypeScript, 202 with React, 257 on React Native, 74 of them custom-built<!-- /rule-counts -->. Three entries, each containing the one before it: `core()`, `react()`, `react-native()`.
4
4
 
5
5
  Library-specific rules ship only when you depend on that library, so nothing fires about code you don't have.
6
6
 
@@ -27,6 +27,11 @@ export default defineConfig({
27
27
  oxlint --type-aware --deny-warnings .
28
28
  ```
29
29
 
30
+ Keep the `defineConfig` wrapper. It is what types the `rules` block, so a wrong
31
+ rule option is a compile error and hovering a rule id shows what it does and
32
+ links to its section here. A bare `export default { ... }` gets neither, silently
33
+ — `satisfies OxlintConfig` works too if you would rather not wrap.
34
+
30
35
  Type-aware rules need the `oxlint-tsgolint` peer. Node 22.18+.
31
36
 
32
37
  Import the entry you use. There is no package root to import from, so nothing
@@ -43,15 +48,27 @@ import { reactNative } from "@ashstack/lint/react-native";
43
48
  Each entry also has a default export, and carries its own options type
44
49
  (`CoreOptions`, `ReactOptions`, `ReactNativeOptions`).
45
50
 
46
- `react()` adds nine rules from `eslint-plugin-react-you-might-not-need-an-effect`.
47
- It is an optional peer, because it unpacks to 218 KB that a backend or CLI on
48
- `core()` should not install. Add it for the effect rules; without it `react()`
49
- works and leaves those nine out.
51
+ ## Monorepos
50
52
 
51
- ```sh
52
- bun add -d eslint-plugin-react-you-might-not-need-an-effect
53
+ A nested config replaces the one above it rather than merging, so each workspace
54
+ config extends an entry itself. Its own `plugins` array is unioned with the
55
+ entry's, never swapped for it:
56
+
57
+ ```ts
58
+ // apps/backend/oxlint.config.mts — a backend that also renders JSX templates
59
+ import { core } from "@ashstack/lint/core";
60
+ import { defineConfig } from "oxlint";
61
+
62
+ export default defineConfig({
63
+ extends: [core()],
64
+ plugins: ["react", "jsx-a11y"],
65
+ rules: { "react/jsx-key": "error" },
66
+ });
53
67
  ```
54
68
 
69
+ Drop the `extends` and the workspace keeps only the rules it names, with no
70
+ diagnostic that the rest are gone.
71
+
55
72
  ## What each entry adds
56
73
 
57
74
  `core()` is a strict eslint / typescript / unicorn / promise / import base plus the `@ashstack/core/` convention rules. `react()` adds react, jsx-a11y, React Compiler and you-might-not-need-an-effect. `react-native()` adds the generic `@ashstack/react-native/` rules: leaked renders, view nesting, iOS-only keyboard events, remote images.
@@ -72,7 +89,7 @@ Import bans follow detection only; disable one by rule name.
72
89
 
73
90
  ## Opt-in rules
74
91
 
75
- Off by default, since they need a team decision first: `@ashstack/core/no-comments`, `use-design-system` and `components-tsx-only`.
92
+ <!-- opt-in -->Off by default, since they need a team decision first: `@ashstack/core/use-design-system` and `@ashstack/core/components-tsx-only`.<!-- /opt-in -->
76
93
 
77
94
  ## Rule reference
78
95
 
@@ -1,5 +1,4 @@
1
1
  import type { CoreOptions, OxlintConfig } from "../lib/types.js";
2
- export declare const coreModules: import("../lib/types.js").ModuleManifest[];
3
2
  /** Test code is a different kind of code: long tables of cases, and assertions that know more than the type does. */
4
3
  export declare const TEST_FILES: string[];
5
4
  /**
@@ -10,8 +9,11 @@ export declare const TEST_FILES: string[];
10
9
  * Some of the enabled `typescript/` rules are type-aware (`no-unnecessary-condition`,
11
10
  * `no-unsafe-type-assertion`, …): they only report when oxlint runs with
12
11
  * `--type-aware` and the `oxlint-tsgolint` peer installed.
12
+ *
13
+ * @see [every rule `core()` sets](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#core)
13
14
  */
14
15
  declare const core: (options?: CoreOptions) => OxlintConfig;
15
16
  export { core };
17
+ export type { CoreRuleId } from "../lib/rule-types/core.js";
16
18
  export type { CoreOptions, ModuleManifest } from "../lib/types.js";
17
19
  export default core;
@@ -1 +1 @@
1
- import{composeModules as o}from"../lib/module.js";import n from"./rules/core/index.js";import s from"./rules/zod/index.js";export const coreModules=[n,s];const t={"array-callback-return":["error",{allowImplicit:!0}],"constructor-super":"error","default-param-last":"error",eqeqeq:["error","always",{null:"ignore"}],"for-direction":"error","getter-return":"error","func-style":["error","expression"],"no-array-constructor":"error","no-async-promise-executor":"error","no-case-declarations":"error","no-class-assign":"error","no-compare-neg-zero":"error","no-cond-assign":"error","no-const-assign":"error","no-constant-condition":"error","no-control-regex":"error","no-debugger":"error","no-dupe-class-members":"error","no-dupe-else-if":"error","no-dupe-keys":"error","no-duplicate-case":"error","no-empty":"error","no-empty-character-class":"error","no-empty-pattern":"error","no-ex-assign":"error","no-extra-boolean-cast":"error","no-fallthrough":"error","no-func-assign":"error","no-global-assign":"error","no-import-assign":"error","no-irregular-whitespace":"error","no-loss-of-precision":"error","no-misleading-character-class":"error","no-negated-condition":"error","no-nested-ternary":"error","no-new-native-nonconstructor":"error","no-nonoctal-decimal-escape":"error","no-obj-calls":"error","no-param-reassign":"error","no-prototype-builtins":"error","no-redeclare":"off","no-regex-spaces":"error","no-self-assign":"error","no-setter-return":"error","no-shadow-restricted-names":"error","no-sparse-arrays":"error","no-this-before-super":"error","no-undef":"off","no-unreachable":"error","no-unsafe-finally":"error","no-unsafe-negation":"error","no-unsafe-optional-chaining":"error","no-unused-labels":"error","no-unused-private-class-members":"error","no-useless-catch":"error","no-useless-constructor":"error","no-useless-escape":"error","no-var":"error","no-with":"error","object-shorthand":["error","methods"],"prefer-rest-params":"error","require-yield":"error","use-isnan":"error","valid-typeof":"error","no-unused-vars":["error",{args:"after-used",argsIgnorePattern:"^_",caughtErrors:"all",caughtErrorsIgnorePattern:"^_",varsIgnorePattern:"^_",destructuredArrayIgnorePattern:"^_",ignoreRestSiblings:!0,fix:{imports:"safe-fix"}}],"no-use-before-define":"off",complexity:["error",{max:12}],"max-depth":["error",3],"max-params":["error",4],"max-lines":["error",{max:300,skipBlankLines:!0,skipComments:!0}],"max-lines-per-function":["error",{max:250,skipBlankLines:!0,skipComments:!0}],"eslint/no-await-in-loop":"error","eslint/no-console":"off","eslint/no-constant-binary-expression":"off","eslint/no-control-regex":"error","eslint/no-else-return":"error","eslint/no-empty":"error","eslint/no-empty-function":"error","eslint/no-new":"off","eslint/no-self-compare":"error","eslint/no-shadow":"error","eslint/no-template-curly-in-string":"error","eslint/no-unassigned-vars":"off","eslint/no-underscore-dangle":"off","eslint/no-unmodified-loop-condition":"off","eslint/no-unused-expressions":"off","eslint/no-useless-concat":"off","eslint/preserve-caught-error":"off","eslint/prefer-arrow-callback":"error","eslint/prefer-const":"error","eslint/prefer-template":"error","typescript/consistent-type-imports":"error","typescript/dot-notation":"error","typescript/no-confusing-void-expression":"error","typescript/no-empty-object-type":["error",{allowInterfaces:"with-single-extends"}],"typescript/no-explicit-any":"error","typescript/no-extra-non-null-assertion":"error","typescript/no-extraneous-class":"error","typescript/no-floating-promises":"off","typescript/no-import-type-side-effects":"error","typescript/no-misused-new":"error","typescript/no-misused-promises":["error",{checksVoidReturn:!1}],"typescript/no-namespace":"error","typescript/no-non-null-asserted-optional-chain":"error","typescript/no-non-null-assertion":"error","typescript/no-unnecessary-boolean-literal-compare":"error","typescript/no-unnecessary-condition":"error","typescript/no-unnecessary-type-assertion":"error","typescript/no-unnecessary-type-constraint":"error","typescript/no-unsafe-declaration-merging":"error","typescript/no-unsafe-function-type":"error","typescript/no-unsafe-type-assertion":"error","typescript/no-wrapper-object-types":"error","typescript/prefer-as-const":"error","typescript/prefer-namespace-keyword":"error","typescript/prefer-nullish-coalescing":"error","typescript/require-await":"error","typescript/switch-exhaustiveness-check":["error",{considerDefaultExhaustiveForUnions:!0}],"import/no-commonjs":"off","import/no-cycle":"error","import/no-duplicates":"error","import/no-named-as-default":"off","import/no-named-as-default-member":"off","import/no-self-import":"off","import/no-unassigned-import":"off","unicorn/consistent-function-scoping":"off","unicorn/no-array-reverse":"off","unicorn/no-array-sort":"off","unicorn/no-empty-file":"off","unicorn/no-new-array":"off","unicorn/no-useless-fallback-in-spread":"off","unicorn/no-useless-spread":"off","unicorn/prefer-add-event-listener":"off","unicorn/prefer-array-flat-map":"error","unicorn/prefer-date-now":"error","unicorn/prefer-logical-operator-over-ternary":"error","unicorn/prefer-node-protocol":"error","unicorn/prefer-optional-catch-binding":"error","unicorn/require-module-specifiers":"off","unicorn/throw-new-error":"error","promise/always-return":"off","promise/no-callback-in-promise":"off","promise/no-multiple-resolved":"off","promise/no-promise-in-callback":"off","oxc/no-async-endpoint-handlers":"off"};export const TEST_FILES=["**/*.test.ts","**/*.test.tsx","**/*.spec.ts","**/*.spec.tsx","**/__tests__/**","**/tests/**"];const core=(e={})=>{const r=o(coreModules,e);return{plugins:["eslint","typescript","import","unicorn","promise","oxc"],jsPlugins:r.jsPlugins,env:{builtin:!0,es2024:!0},categories:{correctness:"error",suspicious:"error",perf:"error",pedantic:"off",style:"off",restriction:"off",nursery:"off"},rules:{...t,...r.rules},overrides:[{files:["**/*.tsx"],rules:{"func-style":"off"}},{files:["**/*.d.ts"],rules:{"typescript/no-explicit-any":"off"}},{files:TEST_FILES,rules:{"max-lines":"off","max-lines-per-function":"off","typescript/await-thenable":"off","typescript/no-non-null-assertion":"off","typescript/no-unsafe-type-assertion":"off","typescript/require-await":"off","typescript/unbound-method":"off"}}]}};export{core};export default core;
1
+ import{composeModules as o}from"../lib/module.js";import{coreRegistry as n}from"../lib/registry.js";const s={"array-callback-return":["error",{allowImplicit:!0}],"constructor-super":"error","default-param-last":"error",eqeqeq:["error","always",{null:"ignore"}],"for-direction":"error","getter-return":"error","func-style":["error","expression"],"no-array-constructor":"error","no-async-promise-executor":"error","no-case-declarations":"error","no-class-assign":"error","no-compare-neg-zero":"error","no-cond-assign":"error","no-const-assign":"error","no-constant-condition":"error","no-control-regex":"error","no-debugger":"error","no-dupe-class-members":"error","no-dupe-else-if":"error","no-dupe-keys":"error","no-duplicate-case":"error","no-empty":"error","no-empty-character-class":"error","no-empty-pattern":"error","no-ex-assign":"error","no-extra-boolean-cast":"error","no-fallthrough":"error","no-func-assign":"error","no-global-assign":"error","no-import-assign":"error","no-irregular-whitespace":"error","no-loss-of-precision":"error","no-misleading-character-class":"error","no-negated-condition":"error","no-nested-ternary":"error","no-new-native-nonconstructor":"error","no-nonoctal-decimal-escape":"error","no-obj-calls":"error","no-param-reassign":"error","no-prototype-builtins":"error","no-redeclare":"off","no-regex-spaces":"error","no-self-assign":"error","no-setter-return":"error","no-shadow-restricted-names":"error","no-sparse-arrays":"error","no-this-before-super":"error","no-undef":"off","no-unreachable":"error","no-unsafe-finally":"error","no-unsafe-negation":"error","no-unsafe-optional-chaining":"error","no-unused-labels":"error","no-unused-private-class-members":"error","no-useless-catch":"error","no-useless-constructor":"error","no-useless-escape":"error","no-var":"error","no-with":"error","object-shorthand":["error","methods"],"prefer-rest-params":"error","require-yield":"error","use-isnan":"error","valid-typeof":"error","no-unused-vars":["error",{args:"after-used",argsIgnorePattern:"^_",caughtErrors:"all",caughtErrorsIgnorePattern:"^_",varsIgnorePattern:"^_",destructuredArrayIgnorePattern:"^_",ignoreRestSiblings:!0,fix:{imports:"safe-fix"}}],"no-use-before-define":"off",complexity:["error",{max:12}],"max-depth":["error",3],"max-params":["error",4],"max-lines":["error",{max:300,skipBlankLines:!0,skipComments:!0}],"max-lines-per-function":["error",{max:250,skipBlankLines:!0,skipComments:!0}],"eslint/no-await-in-loop":"error","eslint/no-console":"off","eslint/no-constant-binary-expression":"off","eslint/no-control-regex":"error","eslint/no-else-return":"error","eslint/no-empty":"error","eslint/no-empty-function":"error","eslint/no-new":"off","eslint/no-self-compare":"error","eslint/no-shadow":"error","eslint/no-template-curly-in-string":"error","eslint/no-unassigned-vars":"off","eslint/no-underscore-dangle":"off","eslint/no-unmodified-loop-condition":"off","eslint/no-unused-expressions":"off","eslint/no-useless-concat":"off","eslint/preserve-caught-error":"off","eslint/prefer-arrow-callback":"error","eslint/prefer-const":"error","eslint/prefer-template":"error","typescript/consistent-type-imports":"error","typescript/dot-notation":"error","typescript/no-confusing-void-expression":"error","typescript/no-empty-object-type":["error",{allowInterfaces:"with-single-extends"}],"typescript/no-explicit-any":"error","typescript/no-extra-non-null-assertion":"error","typescript/no-extraneous-class":"error","typescript/no-floating-promises":"off","typescript/no-import-type-side-effects":"error","typescript/no-misused-new":"error","typescript/no-misused-promises":["error",{checksVoidReturn:!1}],"typescript/no-namespace":"error","typescript/no-non-null-asserted-optional-chain":"error","typescript/no-non-null-assertion":"error","typescript/no-unnecessary-boolean-literal-compare":"error","typescript/no-unnecessary-condition":"error","typescript/no-unnecessary-type-assertion":"error","typescript/no-unnecessary-type-constraint":"error","typescript/no-unsafe-declaration-merging":"error","typescript/no-unsafe-function-type":"error","typescript/no-unsafe-type-assertion":"error","typescript/no-wrapper-object-types":"error","typescript/prefer-as-const":"error","typescript/prefer-namespace-keyword":"error","typescript/prefer-nullish-coalescing":"error","typescript/require-await":"error","typescript/switch-exhaustiveness-check":["error",{considerDefaultExhaustiveForUnions:!0}],"import/no-commonjs":"off","import/no-cycle":"error","import/no-duplicates":"error","import/no-named-as-default":"off","import/no-named-as-default-member":"off","import/no-self-import":"off","import/no-unassigned-import":"off","unicorn/consistent-function-scoping":"off","unicorn/no-array-reverse":"off","unicorn/no-array-sort":"off","unicorn/no-empty-file":"off","unicorn/no-new-array":"off","unicorn/no-useless-fallback-in-spread":"off","unicorn/no-useless-spread":"off","unicorn/prefer-add-event-listener":"off","unicorn/prefer-array-flat-map":"error","unicorn/prefer-date-now":"error","unicorn/prefer-logical-operator-over-ternary":"error","unicorn/prefer-node-protocol":"error","unicorn/prefer-optional-catch-binding":"error","unicorn/require-module-specifiers":"off","unicorn/throw-new-error":"error","promise/always-return":"off","promise/no-callback-in-promise":"off","promise/no-multiple-resolved":"off","promise/no-promise-in-callback":"off","oxc/no-async-endpoint-handlers":"off"};export const TEST_FILES=["**/*.test.ts","**/*.test.tsx","**/*.spec.ts","**/*.spec.tsx","**/__tests__/**","**/tests/**"];const core=(e={})=>{const r=o(n,e);return{plugins:["eslint","typescript","import","unicorn","promise","oxc"],jsPlugins:r.jsPlugins,env:{builtin:!0,es2024:!0},categories:{correctness:"error",suspicious:"error",perf:"error",pedantic:"off",style:"off",restriction:"off",nursery:"off"},rules:{...s,...r.rules},overrides:[{files:["**/*.tsx"],rules:{"func-style":"off"}},{files:["**/*.d.ts"],rules:{"typescript/no-explicit-any":"off"}},{files:TEST_FILES,rules:{"max-lines":"off","max-lines-per-function":"off","typescript/await-thenable":"off","typescript/no-non-null-assertion":"off","typescript/no-unsafe-type-assertion":"off","typescript/require-await":"off","typescript/unbound-method":"off"}}]}};export{core};export default core;
@@ -1 +1 @@
1
- import{fileURLToPath as e}from"node:url";const t="eslint-plugin-react-you-might-not-need-an-effect",r={"react-effect/no-derived-state":"error","react-effect/no-chain-state-updates":"error","react-effect/no-event-handler":"error","react-effect/no-adjust-state-on-prop-change":"error","react-effect/no-reset-all-state-on-prop-change":"error","react-effect/no-pass-live-state-to-parent":"error","react-effect/no-pass-data-to-parent":"error","react-effect/no-external-store-subscription":"error","react-effect/no-initialize-state":"error"};export const effectPlugin=()=>{try{return{present:!0,jsPlugins:[{name:"react-effect",specifier:e(import.meta.resolve(t))}],rules:r}}catch{return{present:!1,jsPlugins:[],rules:{}}}};
1
+ import{fileURLToPath as e}from"node:url";export const EFFECT_NAMESPACE="@ashstack/effects",EFFECT_SPECIFIER=e(new URL("../../vendor/react-effect/index.mjs",import.meta.url)),effectPlugin={name:EFFECT_NAMESPACE,specifier:EFFECT_SPECIFIER},EFFECT_RULES={"@ashstack/effects/no-derived-state":"error","@ashstack/effects/no-chain-state-updates":"error","@ashstack/effects/no-event-handler":"error","@ashstack/effects/no-adjust-state-on-prop-change":"error","@ashstack/effects/no-reset-all-state-on-prop-change":"error","@ashstack/effects/no-pass-live-state-to-parent":"error","@ashstack/effects/no-pass-data-to-parent":"error","@ashstack/effects/no-external-store-subscription":"error","@ashstack/effects/no-initialize-state":"error"};
@@ -1 +1 @@
1
- import{fileURLToPath as d}from"node:url";import{detect as r}from"./detect.js";export const defineModule=(e)=>e;const shortName=(e)=>e.meta.name.slice(10),p=(e,t)=>r(e.option===void 0?void 0:t[e.option],e.packages),u=(e)=>{const t=[];for(const[o,s]of Object.entries(e.rules)){if(s.meta.defaultOff)continue;if(s.meta.packages&&!r(void 0,s.meta.packages))continue;t.push(`${e.meta.name}/${o}`)}return t},i=(e,t)=>{e.paths.push(...t?.paths??[]);e.patterns.push(...t?.patterns??[])};export const composeModules=(e,t,o=[])=>{const s={jsPlugins:[],rules:{},restricted:{paths:[],patterns:[]}};for(const n of e){if(!p(n,t))continue;const c=u(n);if(c.length>0)s.jsPlugins.push(d(n.url));for(const a of c)s.rules[a]="error";i(s.restricted,n.restrictedImports)}for(const n of o){if(!r(void 0,n.packages))continue;i(s.restricted,n.restrictedImports)}return s};export{shortName};
1
+ import{fileURLToPath as d}from"node:url";import{detect as r}from"./detect.js";export const defineModule=(e)=>e;const shortName=(e)=>e.meta.name.slice(10),p=(e,t)=>r(e.option===void 0?void 0:t[e.option],e.packages),u=(e)=>{const t=[];for(const[o,s]of Object.entries(e.rules)){if(s.defaultOff)continue;if(s.packages&&!r(void 0,s.packages))continue;t.push(`${e.meta.name}/${o}`)}return t},i=(e,t)=>{e.paths.push(...t?.paths??[]);e.patterns.push(...t?.patterns??[])};export const composeModules=(e,t,o=[])=>{const s={jsPlugins:[],rules:{},restricted:{paths:[],patterns:[]}};for(const n of e){if(!p(n,t))continue;const c=u(n);if(c.length>0)s.jsPlugins.push(d(n.url));for(const a of c)s.rules[a]="error";i(s.restricted,n.restrictedImports)}for(const n of o){if(!r(void 0,n.packages))continue;i(s.restricted,n.restrictedImports)}return s};export{shortName};
@@ -0,0 +1 @@
1
+ const e=(t)=>new URL(t,import.meta.url).href;export const coreRegistry=[{meta:{name:"@ashstack/core"},url:e("../core/rules/core/index.js"),rules:{"no-comments":{},"no-naming-convention":{},"no-packed-condition":{},"use-design-system":{defaultOff:!0},"components-tsx-only":{defaultOff:!0},"hoist-intl":{}}},{meta:{name:"@ashstack/zod"},url:e("../core/rules/zod/index.js"),option:"zod",packages:["zod"],rules:{"prefer-enum":{}}}],reactRegistry=[{meta:{name:"@ashstack/react"},url:e("../react/rules/react/index.js"),rules:{"no-unlabeled-icon-button":{},"no-svg-without-title":{}}},{meta:{name:"@ashstack/query"},url:e("../react/rules/query/index.js"),option:"query",packages:["@tanstack/react-query"],rules:{"no-inline-keys":{},"no-deprecated-filters":{},"require-destructured-hooks":{},"no-fetch-in-query-fn":{},"next-page-param-undefined":{}}},{meta:{name:"@ashstack/zustand"},url:e("../react/rules/zustand/index.js"),option:"zustand",packages:["zustand"],rules:{"require-selector":{}}},{meta:{name:"@ashstack/i18n"},url:e("../react/rules/i18n/index.js"),option:"i18n",packages:["i18next","react-i18next","@lingui/core","react-intl","use-intl","next-intl","expo-localization"],rules:{"no-bare-text":{},"no-bare-attrs":{},"no-bare-toast":{}}},{meta:{name:"@ashstack/tailwind"},url:e("../react/rules/tailwind/index.js"),option:"tailwind",packages:["tailwindcss"],rules:{"prefer-cn":{},"use-logical-classes":{}}},{meta:{name:"@ashstack/tanstack-router"},url:e("../react/rules/tanstack-router/index.js"),option:"tanstackRouter",packages:["@tanstack/react-router"],rules:{"require-selector":{},"no-search-casts":{}}}],reactNativeRegistry=[{meta:{name:"@ashstack/react-native"},url:e("../react-native/rules/react-native/index.js"),restrictedImports:{paths:[{name:"react",importNames:["forwardRef"],message:"Accept `ref` as a regular prop and delete the `forwardRef` wrapper — React 19 passes `ref` like any other prop."},{name:"react",importNames:["useContext"],message:"Call `use(Context)` instead of `useContext(Context)`; React 19 replaces the hook with it."}],patterns:[{group:["expo-linear-gradient","react-native-linear-gradient"],message:"Apply the gradient through the `experimental_backgroundImage` style property instead of a gradient component."}]},rules:{"no-keyboard-will-events":{},"no-scroll-position-state":{},"no-conditional-style-array":{},"no-leaked-render":{},"no-rn-image-network-source":{},"no-redundant-view-nesting":{},"no-rn-namespace-import":{},"no-unlabeled-icon-pressable":{},"hoist-stateless-function":{},"no-manual-memo":{packages:["babel-plugin-react-compiler","react-compiler-runtime","react-compiler-marker"]},"no-dynamic-import":{}}},{meta:{name:"@ashstack/unistyles"},url:e("../react-native/rules/unistyles/index.js"),option:"unistyles",packages:["react-native-unistyles"],restrictedImports:{paths:[{name:"react-native",importNames:["StyleSheet"],message:"Import `StyleSheet` from `react-native-unistyles` instead of `react-native`."},{name:"react-native",importNames:["useWindowDimensions","Dimensions"],message:"Read screen size from `rt.screen` inside `StyleSheet.create`, or `UnistylesRuntime.screen` outside it, instead of the `Dimensions` APIs."},{name:"react-native",importNames:["SafeAreaView"],message:'Set `contentInsetAdjustmentBehavior="automatic"` on the scroll view, or apply `rt.insets` from `react-native-unistyles`, instead of `SafeAreaView`.'},{name:"react-native-safe-area-context",importNames:["useSafeAreaInsets","useSafeAreaFrame","SafeAreaView"],message:"Read safe-area values from `rt.insets`, or `UnistylesRuntime.insets` outside a stylesheet, in `react-native-unistyles`."}]},rules:{"animated-theme":{},"content-container":{},"in-sheet":{},insets:{},"no-hardcoded-color":{},"no-hardcoded-spacing":{},"no-margin":{},"no-style-spread":{},"no-unused-styles":{},"rtl-style-call":{},"theme-screen-component":{},"theme-style-attr":{}}},{meta:{name:"@ashstack/legend-list"},url:e("../react-native/rules/legend-list/index.js"),option:"legendList",packages:["@legendapp/list"],restrictedImports:{paths:[{name:"react-native",importNames:["FlatList","SectionList","VirtualizedList"],message:"Render this list with `LegendList` from `@legendapp/list/react-native`; a `ScrollView` plus `map` is fine for fewer than 20 static items."},{name:"@shopify/flash-list",message:"Import `LegendList` from `@legendapp/list/react-native` — Legend List replaced FlashList in this stack."}],patterns:[{group:["@legendapp/list"],message:"Import from the platform entrypoint `@legendapp/list/react-native`, not the package root."}]},rules:{"required-props":{},"no-index-key-extractor":{},"no-remount-key":{},"no-inline-render-item-props":{},"no-mixed-children":{},"no-flex-in-content-container":{},"typed-items-need-item-type":{},"no-scrollview-map":{},"no-unsupported-props":{}}},{meta:{name:"@ashstack/legend-state"},url:e("../react-native/rules/legend-state/index.js"),option:"legendState",packages:["@legendapp/state"],restrictedImports:{paths:[{name:"@legendapp/state/react",importNames:["use$","useSelector"],message:"Use `useValue` from `@legendapp/state/react`; `use$` and `useSelector` are deprecated."}]},rules:{"no-assignment":{},naming:{},"no-nested-observable":{},"no-react-mirror":{},"no-untracked-get-in-jsx":{},"no-peek-in-selector":{},"no-object-selector":{},"no-observable-in-component":{}}},{meta:{name:"@ashstack/reanimated"},url:e("../react-native/rules/reanimated/index.js"),option:"reanimated",packages:["react-native-reanimated"],restrictedImports:{paths:[{name:"react-native",importNames:["Animated"],message:"Use `react-native-reanimated` instead of React Native's `Animated` API."},{name:"react-native-reanimated",importNames:["runOnJS","runOnUI"],message:"Use `scheduleOnRN` and `scheduleOnUI` from `react-native-worklets`; `runOnJS` and `runOnUI` are deprecated."},{name:"react-native-worklets",importNames:["runOnJS","runOnUI"],message:"Use `scheduleOnRN` and `scheduleOnUI` from `react-native-worklets`; `runOnJS` and `runOnUI` are deprecated."}]},rules:{"animated-reaction-safety":{},"animated-style-needs-animated-component":{},"animated-updater-purity":{},"gpu-properties-only":{},"hoist-layout-animation-builder":{},"interpolate-needs-clamp":{},"no-shared-value-dot-value":{},"no-react-state-from-continuous-worklet":{},"prefer-lazy-shared-value-initializer":{},"schedule-on-rn-scope":{},"shared-value-usage":{}}},{meta:{name:"@ashstack/turbo-image"},url:e("../react-native/rules/turbo-image/index.js"),option:"turboImage",packages:["react-native-turbo-image"],rules:{"require-resize":{},"require-cache-policy":{}}},{meta:{name:"@ashstack/skia"},url:e("../react-native/rules/skia/index.js"),option:"skia",packages:["@shopify/react-native-skia"],restrictedImports:{paths:[{name:"@shopify/react-native-skia",importNames:["usePathValue","usePathInterpolation"],message:"Keep one stable `SkPath` buffer and mutate it inside `useDerivedValue`, with consumers reading the driving shared value. These legacy path-value hooks self-dirty Reanimated mappers and re-record idle canvases."}]},rules:{"canvas-opaque":{}}},{meta:{name:"@ashstack/keyboard"},url:e("../react-native/rules/keyboard/index.js"),option:"keyboard",packages:["react-native-keyboard-controller"],restrictedImports:{paths:[{name:"react-native",importNames:["KeyboardAvoidingView"],message:"Import `KeyboardAvoidingView` from `react-native-keyboard-controller` — same props, and it tracks the keyboard per frame instead of waiting for Android's post-animation `keyboardDidShow`. For a scrolling form use its `KeyboardAwareScrollView`; to just shift a view, use `rt.insets.ime`."}]},rules:{}}];
@@ -0,0 +1,76 @@
1
+ import type { AllowWarnDeny } from "oxlint";
2
+ /** A severity, or a severity followed by as many of the rule's options as you want to set. */
3
+ type RuleSetting<Options extends unknown[] = []> = AllowWarnDeny | [AllowWarnDeny, ...Partial<Options>];
4
+ /** Every rule id `core()` adds on top of the entry below it. */
5
+ export type CoreRuleId = "@ashstack/core/no-comments" | "@ashstack/core/no-naming-convention" | "@ashstack/core/no-packed-condition" | "@ashstack/core/use-design-system" | "@ashstack/core/components-tsx-only" | "@ashstack/core/hoist-intl" | "@ashstack/zod/prefer-enum";
6
+ declare module "oxlint" {
7
+ interface DummyRuleMap {
8
+ /**
9
+ * Disallow every comment that is neither a `// what: <fact>` line, a `// why:` marker, nor a tooling directive. The message names the refactoring that removes it: Rename, Extract Function, Guard Clause. Surviving `// what:` lines are held to one short line each, at most `budget` per file (default 2); `escapeHatch: false` removes that hatch, so no discretionary prose survives. A `// why:` line is the marker `@ashstack/react-native/no-manual-memo` requires above a kept `memo`: held to the same one-line shape, never counted against `budget`, and kept even with `escapeHatch: false`, so the two rules run together. With `jsdoc: "allow"`, a `/** *\/` block documenting the declaration directly beneath it is kept, while a floating one still reports.
10
+ *
11
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackcoreno-comments
12
+ */
13
+ "@ashstack/core/no-comments"?: RuleSetting<[
14
+ {
15
+ jsdoc?: "allow" | "report";
16
+ escapeHatch?: boolean;
17
+ budget?: number;
18
+ }
19
+ ]>;
20
+ /**
21
+ * Require a variable, object property, type member or enum member to use one of the casings allowed for its kind.
22
+ *
23
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackcoreno-naming-convention
24
+ */
25
+ "@ashstack/core/no-naming-convention"?: RuleSetting;
26
+ /**
27
+ * Require a condition to be split into named booleans once it holds too many boolean operators and comparisons. The option says how many, defaulting to 5.
28
+ *
29
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackcoreno-packed-condition
30
+ */
31
+ "@ashstack/core/no-packed-condition"?: RuleSetting<[number]>;
32
+ /**
33
+ * Disallow importing a raw primitive your design system already wraps. Wrapped components come from scanning the design-system directory, plus the explicit `use` map for names, paths and source modules the scan cannot infer. Files under the design-system directory (or `exempt`) are skipped.
34
+ *
35
+ * Off by default — opt in per project.
36
+ *
37
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackcoreuse-design-system
38
+ */
39
+ "@ashstack/core/use-design-system"?: RuleSetting<[
40
+ {
41
+ dir?: string;
42
+ alias?: string;
43
+ use?: Record<string, string | Array<string> | {
44
+ replaces: string | Array<string>;
45
+ from?: string;
46
+ path?: string;
47
+ reason?: string;
48
+ }>;
49
+ exempt?: Array<string>;
50
+ }
51
+ ]>;
52
+ /**
53
+ * Require every file under the components directory to render JSX or be a re-export barrel. `dir` says which directory, defaulting to `src/components`.
54
+ *
55
+ * Off by default — opt in per project.
56
+ *
57
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackcorecomponents-tsx-only
58
+ */
59
+ "@ashstack/core/components-tsx-only"?: RuleSetting<[{
60
+ dir?: string;
61
+ }]>;
62
+ /**
63
+ * Disallow `new Intl.*` inside a function that renders JSX, unless the call already sits in `useMemo` or `useCallback`.
64
+ *
65
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackcorehoist-intl
66
+ */
67
+ "@ashstack/core/hoist-intl"?: RuleSetting;
68
+ /**
69
+ * Disallow `z.nativeEnum()` and any `z.union()` whose members are all `z.literal()` strings.
70
+ *
71
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackzodprefer-enum
72
+ */
73
+ "@ashstack/zod/prefer-enum"?: RuleSetting;
74
+ }
75
+ }
76
+ export {};
@@ -0,0 +1 @@
1
+ export{};
@@ -0,0 +1,336 @@
1
+ import type { AllowWarnDeny } from "oxlint";
2
+ /** A severity, or a severity followed by as many of the rule's options as you want to set. */
3
+ type RuleSetting<Options extends unknown[] = []> = AllowWarnDeny | [AllowWarnDeny, ...Partial<Options>];
4
+ /** Every rule id `react-native()` adds on top of the entry below it. */
5
+ export type ReactNativeRuleId = "@ashstack/react-native/no-keyboard-will-events" | "@ashstack/react-native/no-scroll-position-state" | "@ashstack/react-native/no-conditional-style-array" | "@ashstack/react-native/no-leaked-render" | "@ashstack/react-native/no-rn-image-network-source" | "@ashstack/react-native/no-redundant-view-nesting" | "@ashstack/react-native/no-rn-namespace-import" | "@ashstack/react-native/no-unlabeled-icon-pressable" | "@ashstack/react-native/hoist-stateless-function" | "@ashstack/react-native/no-manual-memo" | "@ashstack/react-native/no-dynamic-import" | "@ashstack/unistyles/animated-theme" | "@ashstack/unistyles/content-container" | "@ashstack/unistyles/in-sheet" | "@ashstack/unistyles/insets" | "@ashstack/unistyles/no-hardcoded-color" | "@ashstack/unistyles/no-hardcoded-spacing" | "@ashstack/unistyles/no-margin" | "@ashstack/unistyles/no-style-spread" | "@ashstack/unistyles/no-unused-styles" | "@ashstack/unistyles/rtl-style-call" | "@ashstack/unistyles/theme-screen-component" | "@ashstack/unistyles/theme-style-attr" | "@ashstack/legend-list/required-props" | "@ashstack/legend-list/no-index-key-extractor" | "@ashstack/legend-list/no-remount-key" | "@ashstack/legend-list/no-inline-render-item-props" | "@ashstack/legend-list/no-mixed-children" | "@ashstack/legend-list/no-flex-in-content-container" | "@ashstack/legend-list/typed-items-need-item-type" | "@ashstack/legend-list/no-scrollview-map" | "@ashstack/legend-list/no-unsupported-props" | "@ashstack/legend-state/no-assignment" | "@ashstack/legend-state/naming" | "@ashstack/legend-state/no-nested-observable" | "@ashstack/legend-state/no-react-mirror" | "@ashstack/legend-state/no-untracked-get-in-jsx" | "@ashstack/legend-state/no-peek-in-selector" | "@ashstack/legend-state/no-object-selector" | "@ashstack/legend-state/no-observable-in-component" | "@ashstack/reanimated/animated-reaction-safety" | "@ashstack/reanimated/animated-style-needs-animated-component" | "@ashstack/reanimated/animated-updater-purity" | "@ashstack/reanimated/gpu-properties-only" | "@ashstack/reanimated/hoist-layout-animation-builder" | "@ashstack/reanimated/interpolate-needs-clamp" | "@ashstack/reanimated/no-shared-value-dot-value" | "@ashstack/reanimated/no-react-state-from-continuous-worklet" | "@ashstack/reanimated/prefer-lazy-shared-value-initializer" | "@ashstack/reanimated/schedule-on-rn-scope" | "@ashstack/reanimated/shared-value-usage" | "@ashstack/turbo-image/require-resize" | "@ashstack/turbo-image/require-cache-policy" | "@ashstack/skia/canvas-opaque";
6
+ declare module "oxlint" {
7
+ interface DummyRuleMap {
8
+ /**
9
+ * Disallow the `keyboardWill*` event names. They are iOS-only, so on Android the listener registers and never fires.
10
+ *
11
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-keyboard-will-events
12
+ */
13
+ "@ashstack/react-native/no-keyboard-will-events"?: RuleSetting;
14
+ /**
15
+ * Disallow a React state setter inside a scroll handler prop. Scroll fires every frame, and so would the re-render.
16
+ *
17
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-scroll-position-state
18
+ */
19
+ "@ashstack/react-native/no-scroll-position-state"?: RuleSetting;
20
+ /**
21
+ * Disallow conditional and logical entries inside a JSX `style` array. A falsy entry leaves a hole that breaks the Unistyles C++ proxy.
22
+ *
23
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-conditional-style-array
24
+ */
25
+ "@ashstack/react-native/no-conditional-style-array"?: RuleSetting;
26
+ /**
27
+ * Disallow a `&&` guard in JSX on a value this rule can see is a number or a string — a `.length`, a `.size`, arithmetic, a literal. The falsy left operand leaks into the output, and a bare `0` crashes React Native with "Text strings must be rendered within a <Text> component".
28
+ *
29
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-leaked-render
30
+ */
31
+ "@ashstack/react-native/no-leaked-render"?: RuleSetting;
32
+ /**
33
+ * Disallow a react-native `<Image>` with a network `{ uri }` source. It has no disk cache and no decode sizing, so the image re-downloads at full size on every cold start.
34
+ *
35
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-rn-image-network-source
36
+ */
37
+ "@ashstack/react-native/no-rn-image-network-source"?: RuleSetting;
38
+ /**
39
+ * Disallow a View or Animated.View that wraps an identical view when neither carries anything but a style. Every extra host view is a real node in the native tree.
40
+ *
41
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-redundant-view-nesting
42
+ */
43
+ "@ashstack/react-native/no-redundant-view-nesting"?: RuleSetting;
44
+ /**
45
+ * Disallow a namespace import of react-native and a re-export of its `Platform`. Both defeat Metro's platform shaking, so dead `Platform.OS` branches ship in both bundles.
46
+ *
47
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-rn-namespace-import
48
+ */
49
+ "@ashstack/react-native/no-rn-namespace-import"?: RuleSetting;
50
+ /**
51
+ * Require an accessible name on an icon-only touchable or an icon-only Expo UI `<Button>`. Without a label, hint or visible text, a screen reader cannot reach the control.
52
+ *
53
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-unlabeled-icon-pressable
54
+ */
55
+ "@ashstack/react-native/no-unlabeled-icon-pressable"?: RuleSetting;
56
+ /**
57
+ * Require module scope for a non-component function that reads nothing from the component around it. Out there it is created once, keeps a stable identity, and can be tested without rendering.
58
+ *
59
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativehoist-stateless-function
60
+ */
61
+ "@ashstack/react-native/hoist-stateless-function"?: RuleSetting;
62
+ /**
63
+ * Require a `// why:` line above every kept `useMemo`, `useCallback` and `memo`. The React Compiler memoises on a best-effort basis, not a guarantee, so a memo is allowed where the cost is real: something rendered per list row, or a computation measured as heavy. The `// why:` line names which of the two applies. `@ashstack/core/no-comments` keeps that line and never counts it against its `budget`, so both rules run together.
64
+ *
65
+ * Enabled only when one of `babel-plugin-react-compiler`, `react-compiler-runtime`, `react-compiler-marker` is a dependency.
66
+ *
67
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-manual-memo
68
+ */
69
+ "@ashstack/react-native/no-manual-memo"?: RuleSetting;
70
+ /**
71
+ * Disallow dynamic `import()` outside a `React.lazy` or `dynamic` wrapper. Metro inlines it into the same bundle, so nothing is deferred and the module is hidden from the typechecker.
72
+ *
73
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-dynamic-import
74
+ */
75
+ "@ashstack/react-native/no-dynamic-import"?: RuleSetting;
76
+ /**
77
+ * A Reanimated worklet hook cannot see `useUnistyles()` theme changes on the UI thread. Read the shared value from `useAnimatedTheme()` there instead.
78
+ *
79
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesanimated-theme
80
+ */
81
+ "@ashstack/unistyles/animated-theme"?: RuleSetting;
82
+ /**
83
+ * A raw component never subscribes its `contentContainerStyle` to theme or `rt` updates. Wrap the component with `withUnistyles` when the style depends on either.
84
+ *
85
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylescontent-container
86
+ */
87
+ "@ashstack/unistyles/content-container"?: RuleSetting;
88
+ /**
89
+ * Inside `StyleSheet.create`, require `rt` and theme values rather than Dimensions, PixelRatio, Appearance, I18nManager, StatusBar or `UnistylesRuntime`. It also covers logical spacing, `boxShadow`, `borderCurve` and a redundant `as const`.
90
+ *
91
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesin-sheet
92
+ */
93
+ "@ashstack/unistyles/in-sheet"?: RuleSetting;
94
+ /**
95
+ * Disallow passing `useSafeAreaInsets()` values into a dynamic style function or an inline JSX style object. Read `rt.insets` inside `StyleSheet.create` instead.
96
+ *
97
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesinsets
98
+ */
99
+ "@ashstack/unistyles/insets"?: RuleSetting;
100
+ /**
101
+ * Disallow hex and CSS-function colors inside `StyleSheet.create`. A raw color skips dark mode and never changes with the theme.
102
+ *
103
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesno-hardcoded-color
104
+ */
105
+ "@ashstack/unistyles/no-hardcoded-color"?: RuleSetting;
106
+ /**
107
+ * Require `theme.spacing` or `theme.sizing.scale` for spacing, radius and type values inside `StyleSheet.create`, instead of raw numbers.
108
+ *
109
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesno-hardcoded-spacing
110
+ */
111
+ "@ashstack/unistyles/no-hardcoded-spacing"?: RuleSetting;
112
+ /**
113
+ * Disallow non-negative `margin` inside `StyleSheet.create`; `gap` on the parent or `padding` on the element spaces children without leaving a hole when one is removed.
114
+ *
115
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesno-margin
116
+ */
117
+ "@ashstack/unistyles/no-margin"?: RuleSetting;
118
+ /**
119
+ * Disallow spreading a stylesheet style into another object. The spread reads through the Unistyles C++ proxy once, so the result stops reacting to the theme.
120
+ *
121
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesno-style-spread
122
+ */
123
+ "@ashstack/unistyles/no-style-spread"?: RuleSetting;
124
+ /**
125
+ * Disallow stylesheet keys that nothing in the file reads. A computed key, a computed read, or a sheet that leaves the module skips the whole file.
126
+ *
127
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesno-unused-styles
128
+ */
129
+ "@ashstack/unistyles/no-unused-styles"?: RuleSetting;
130
+ /**
131
+ * Disallow passing `I18nManager.isRTL` from JSX into a dynamic style function. Unistyles tracks the dependency itself once the style reads `rt.rtl`.
132
+ *
133
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesrtl-style-call
134
+ */
135
+ "@ashstack/unistyles/rtl-style-call"?: RuleSetting;
136
+ /**
137
+ * `theme.screen.*` is a snapshot taken at module initialization, so a component that reads it never sees the current size. `useUnistyles().rt.screen` and `useWindowDimensions` do.
138
+ *
139
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylestheme-screen-component
140
+ */
141
+ "@ashstack/unistyles/theme-screen-component"?: RuleSetting;
142
+ /**
143
+ * Theme-dependent values belong in `StyleSheet.create`, not in a JSX `style` prop that reads a `useUnistyles()` theme.
144
+ *
145
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylestheme-style-attr
146
+ */
147
+ "@ashstack/unistyles/theme-style-attr"?: RuleSetting;
148
+ /**
149
+ * Require `keyExtractor` and an explicit `recycleItems` on a Legend List. Without a key extractor the list keys its rows by index.
150
+ *
151
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listrequired-props
152
+ */
153
+ "@ashstack/legend-list/required-props"?: RuleSetting;
154
+ /**
155
+ * Disallow a `keyExtractor` that uses its index parameter. Cached sizes and recycled row state hang off the key, so a prepend points every measurement at the wrong item.
156
+ *
157
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listno-index-key-extractor
158
+ */
159
+ "@ashstack/legend-list/no-index-key-extractor"?: RuleSetting;
160
+ /**
161
+ * Disallow `key` on a Legend List, which remounts on any key change and loses its measurements and scroll position. Pass `dataKey` instead.
162
+ *
163
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listno-remount-key
164
+ */
165
+ "@ashstack/legend-list/no-remount-key"?: RuleSetting;
166
+ /**
167
+ * Disallow inline object and array literals on props nested inside `renderItem`. A row whose props take a new identity every render can never be skipped.
168
+ *
169
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listno-inline-render-item-props
170
+ */
171
+ "@ashstack/legend-list/no-inline-render-item-props"?: RuleSetting;
172
+ /**
173
+ * Disallow passing both `data` and real children to a Legend List. The combination is unsupported and one of the two is dropped without a warning.
174
+ *
175
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listno-mixed-children
176
+ */
177
+ "@ashstack/legend-list/no-mixed-children"?: RuleSetting;
178
+ /**
179
+ * Disallow `flex` in a Legend List's `contentContainerStyle`, where it sizes the scrolled content to the viewport and the list ends up measuring zero height.
180
+ *
181
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listno-flex-in-content-container
182
+ */
183
+ "@ashstack/legend-list/no-flex-in-content-container"?: RuleSetting;
184
+ /**
185
+ * Require `getItemType` when a row branches on `item.type`. Without it every layout shares one recycling pool and one size average.
186
+ *
187
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listtyped-items-need-item-type
188
+ */
189
+ "@ashstack/legend-list/typed-items-need-item-type"?: RuleSetting;
190
+ /**
191
+ * A `ScrollView` mounts every child up front, so a mapped collection does not belong in its children.
192
+ *
193
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listno-scrollview-map
194
+ */
195
+ "@ashstack/legend-list/no-scrollview-map"?: RuleSetting;
196
+ /**
197
+ * Disallow FlashList and FlatList props that Legend List v3 does not have. It ignores them rather than rejecting them, so the feature looks broken.
198
+ *
199
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listno-unsupported-props
200
+ */
201
+ "@ashstack/legend-list/no-unsupported-props"?: RuleSetting;
202
+ /**
203
+ * Write an observable with `.set(...)` or `.assign({...})`. Assigning or incrementing it with an operator is a silent no-op.
204
+ *
205
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-stateno-assignment
206
+ */
207
+ "@ashstack/legend-state/no-assignment"?: RuleSetting;
208
+ /**
209
+ * A variable initialized from `observable()` or `useObservable()` needs a trailing `$`. The other rules in this module key off that suffix.
210
+ *
211
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-statenaming
212
+ */
213
+ "@ashstack/legend-state/naming"?: RuleSetting;
214
+ /**
215
+ * Never pass an observable to `observable()` or `useObservable()`. The wrapper is a second node, and reads and writes on it never reach the original.
216
+ *
217
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-stateno-nested-observable
218
+ */
219
+ "@ashstack/legend-state/no-nested-observable"?: RuleSetting;
220
+ /**
221
+ * Seeding `useState` from an observable's `get()` or `peek()` gives the value two owners. Read it with `useValue(...)` where it renders.
222
+ *
223
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-stateno-react-mirror
224
+ */
225
+ "@ashstack/legend-state/no-react-mirror"?: RuleSetting;
226
+ /**
227
+ * A `get()` placed directly in a JSX expression container is a plain read. The value renders once and never updates.
228
+ *
229
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-stateno-untracked-get-in-jsx
230
+ */
231
+ "@ashstack/legend-state/no-untracked-get-in-jsx"?: RuleSetting;
232
+ /**
233
+ * `peek()` never subscribes, so a selector or tracking callback that uses it never re-runs. Call `get()` there and keep `peek()` for handlers.
234
+ *
235
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-stateno-peek-in-selector
236
+ */
237
+ "@ashstack/legend-state/no-peek-in-selector"?: RuleSetting;
238
+ /**
239
+ * A `useValue` selector that builds a new object or array returns a fresh identity every run. The component then re-renders on every store change.
240
+ *
241
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-stateno-object-selector
242
+ */
243
+ "@ashstack/legend-state/no-object-selector"?: RuleSetting;
244
+ /**
245
+ * Calling `observable()` inside a component or hook makes a new observable on every render. Use `useObservable()` or a module-level store instead.
246
+ *
247
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-stateno-observable-in-component
248
+ */
249
+ "@ashstack/legend-state/no-observable-in-component"?: RuleSetting;
250
+ /**
251
+ * A `useAnimatedReaction` result callback loops forever if it writes a shared value the prepare callback reads. Guard `scheduleOnRN` there on the current result differing from the previous one.
252
+ *
253
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedanimated-reaction-safety
254
+ */
255
+ "@ashstack/reanimated/animated-reaction-safety"?: RuleSetting;
256
+ /**
257
+ * An animated style only takes effect on an `Animated.*` component. A plain element applies it once at mount and then never updates.
258
+ *
259
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedanimated-style-needs-animated-component
260
+ */
261
+ "@ashstack/reanimated/animated-style-needs-animated-component"?: RuleSetting;
262
+ /**
263
+ * An updater passed to `useAnimatedStyle` or `useAnimatedProps` must stay pure, so it may not write a shared value or call `scheduleOnRN`.
264
+ *
265
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedanimated-updater-purity
266
+ */
267
+ "@ashstack/reanimated/animated-updater-purity"?: RuleSetting;
268
+ /**
269
+ * Animate `transform` and `opacity` in `useAnimatedStyle` and `useAnimatedProps`. Layout properties such as `width` or `margin` recalculate layout every frame.
270
+ *
271
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedgpu-properties-only
272
+ */
273
+ "@ashstack/reanimated/gpu-properties-only"?: RuleSetting;
274
+ /**
275
+ * A layout animation belongs at module scope, or inside a memo when it depends on component values. The `entering`/`exiting`/`layout` props otherwise rebuild it on every render.
276
+ *
277
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedhoist-layout-animation-builder
278
+ */
279
+ "@ashstack/reanimated/hoist-layout-animation-builder"?: RuleSetting;
280
+ /**
281
+ * Give `interpolate()` a fourth argument that clamps. Without one, or with `EXTEND` or `IDENTITY`, the output keeps going past the ends of the input range.
282
+ *
283
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedinterpolate-needs-clamp
284
+ */
285
+ "@ashstack/reanimated/interpolate-needs-clamp"?: RuleSetting;
286
+ /**
287
+ * Shared values are read with `.get()` and written with `.set(...)`, never through `.value`. React Compiler cannot track a `.value` access.
288
+ *
289
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedno-shared-value-dot-value
290
+ */
291
+ "@ashstack/reanimated/no-shared-value-dot-value"?: RuleSetting;
292
+ /**
293
+ * A worklet that runs every frame must not send a React state setter through `scheduleOnRN`. That puts a Fabric commit on an animation frame.
294
+ *
295
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedno-react-state-from-continuous-worklet
296
+ */
297
+ "@ashstack/reanimated/no-react-state-from-continuous-worklet"?: RuleSetting;
298
+ /**
299
+ * Pass a computed `useSharedValue` initial value as a function. An eager call runs on every render while only the first result is kept.
300
+ *
301
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedprefer-lazy-shared-value-initializer
302
+ */
303
+ "@ashstack/reanimated/prefer-lazy-shared-value-initializer"?: RuleSetting;
304
+ /**
305
+ * `scheduleOnRN` takes a function declared in RN Runtime scope. An inline callback can end up created on the wrong runtime.
306
+ *
307
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedschedule-on-rn-scope
308
+ */
309
+ "@ashstack/reanimated/schedule-on-rn-scope"?: RuleSetting;
310
+ /**
311
+ * Destructuring a shared value or mutating what its `get()` returned detaches it from Reanimated reactivity. Reading or writing one while JSX evaluates also makes render impure.
312
+ *
313
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedshared-value-usage
314
+ */
315
+ "@ashstack/reanimated/shared-value-usage"?: RuleSetting;
316
+ /**
317
+ * Require `resize` on a TurboImage so the native decoder downsamples before the bitmap reaches memory. A full-resolution decode wastes tens of megabytes and stalls the first frame.
318
+ *
319
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackturbo-imagerequire-resize
320
+ */
321
+ "@ashstack/turbo-image/require-resize"?: RuleSetting;
322
+ /**
323
+ * Require `cachePolicy` on a TurboImage. Without one the image is re-fetched over the network on every cold start, so an already-scrolled feed costs its bandwidth again.
324
+ *
325
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackturbo-imagerequire-cache-policy
326
+ */
327
+ "@ashstack/turbo-image/require-cache-policy"?: RuleSetting;
328
+ /**
329
+ * Require an explicit `opaque` prop on a Skia `<Canvas>`. A fullscreen animated canvas wants it on; anything that needs transparency or a view transform wants it off.
330
+ *
331
+ * @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackskiacanvas-opaque
332
+ */
333
+ "@ashstack/skia/canvas-opaque"?: RuleSetting;
334
+ }
335
+ }
336
+ export {};
@@ -0,0 +1 @@
1
+ export{};