@ashstack/lint 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -1
- package/dist/lib/registry.js +1 -1
- package/dist/lib/rule-types/core.d.ts +18 -14
- package/dist/lib/rule-types/react-native.d.ts +58 -57
- package/dist/lib/rule-types/react.d.ts +28 -25
- package/dist/lib/types.d.ts +6 -0
- package/dist/react/index.js +1 -1
- package/dist/react-native/index.js +1 -1
- package/dist/react-native/rules/react-native/no-manual-memo.js +1 -1
- package/package.json +1 -1
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,
|
|
3
|
+
Strict shared [oxlint](https://oxc.rs) config: <!-- rule-counts -->118 rules on plain TypeScript, 201 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,6 +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
|
|
|
51
|
+
## Monorepos
|
|
52
|
+
|
|
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
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Drop the `extends` and the workspace keeps only the rules it names, with no
|
|
70
|
+
diagnostic that the rest are gone.
|
|
71
|
+
|
|
46
72
|
## What each entry adds
|
|
47
73
|
|
|
48
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.
|
package/dist/lib/registry.js
CHANGED
|
@@ -1 +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":{
|
|
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":{},"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:{}}];
|
|
@@ -1,4 +1,6 @@
|
|
|
1
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>];
|
|
2
4
|
/** Every rule id `core()` adds on top of the entry below it. */
|
|
3
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";
|
|
4
6
|
declare module "oxlint" {
|
|
@@ -8,23 +10,25 @@ declare module "oxlint" {
|
|
|
8
10
|
*
|
|
9
11
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackcoreno-comments
|
|
10
12
|
*/
|
|
11
|
-
"@ashstack/core/no-comments"?:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
"@ashstack/core/no-comments"?: RuleSetting<[
|
|
14
|
+
{
|
|
15
|
+
jsdoc?: "allow" | "report";
|
|
16
|
+
escapeHatch?: boolean;
|
|
17
|
+
budget?: number;
|
|
18
|
+
}
|
|
19
|
+
]>;
|
|
16
20
|
/**
|
|
17
21
|
* Require a variable, object property, type member or enum member to use one of the casings allowed for its kind.
|
|
18
22
|
*
|
|
19
23
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackcoreno-naming-convention
|
|
20
24
|
*/
|
|
21
|
-
"@ashstack/core/no-naming-convention"?:
|
|
25
|
+
"@ashstack/core/no-naming-convention"?: RuleSetting;
|
|
22
26
|
/**
|
|
23
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.
|
|
24
28
|
*
|
|
25
29
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackcoreno-packed-condition
|
|
26
30
|
*/
|
|
27
|
-
"@ashstack/core/no-packed-condition"?:
|
|
31
|
+
"@ashstack/core/no-packed-condition"?: RuleSetting<[number]>;
|
|
28
32
|
/**
|
|
29
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.
|
|
30
34
|
*
|
|
@@ -32,8 +36,7 @@ declare module "oxlint" {
|
|
|
32
36
|
*
|
|
33
37
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackcoreuse-design-system
|
|
34
38
|
*/
|
|
35
|
-
"@ashstack/core/use-design-system"?:
|
|
36
|
-
AllowWarnDeny,
|
|
39
|
+
"@ashstack/core/use-design-system"?: RuleSetting<[
|
|
37
40
|
{
|
|
38
41
|
dir?: string;
|
|
39
42
|
alias?: string;
|
|
@@ -45,7 +48,7 @@ declare module "oxlint" {
|
|
|
45
48
|
}>;
|
|
46
49
|
exempt?: Array<string>;
|
|
47
50
|
}
|
|
48
|
-
]
|
|
51
|
+
]>;
|
|
49
52
|
/**
|
|
50
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`.
|
|
51
54
|
*
|
|
@@ -53,20 +56,21 @@ declare module "oxlint" {
|
|
|
53
56
|
*
|
|
54
57
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackcorecomponents-tsx-only
|
|
55
58
|
*/
|
|
56
|
-
"@ashstack/core/components-tsx-only"?:
|
|
59
|
+
"@ashstack/core/components-tsx-only"?: RuleSetting<[{
|
|
57
60
|
dir?: string;
|
|
58
|
-
}]
|
|
61
|
+
}]>;
|
|
59
62
|
/**
|
|
60
63
|
* Disallow `new Intl.*` inside a function that renders JSX, unless the call already sits in `useMemo` or `useCallback`.
|
|
61
64
|
*
|
|
62
65
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackcorehoist-intl
|
|
63
66
|
*/
|
|
64
|
-
"@ashstack/core/hoist-intl"?:
|
|
67
|
+
"@ashstack/core/hoist-intl"?: RuleSetting;
|
|
65
68
|
/**
|
|
66
69
|
* Disallow `z.nativeEnum()` and any `z.union()` whose members are all `z.literal()` strings.
|
|
67
70
|
*
|
|
68
71
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackzodprefer-enum
|
|
69
72
|
*/
|
|
70
|
-
"@ashstack/zod/prefer-enum"?:
|
|
73
|
+
"@ashstack/zod/prefer-enum"?: RuleSetting;
|
|
71
74
|
}
|
|
72
75
|
}
|
|
76
|
+
export {};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
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>];
|
|
2
4
|
/** Every rule id `react-native()` adds on top of the entry below it. */
|
|
3
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";
|
|
4
6
|
declare module "oxlint" {
|
|
@@ -8,326 +10,325 @@ declare module "oxlint" {
|
|
|
8
10
|
*
|
|
9
11
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-keyboard-will-events
|
|
10
12
|
*/
|
|
11
|
-
"@ashstack/react-native/no-keyboard-will-events"?:
|
|
13
|
+
"@ashstack/react-native/no-keyboard-will-events"?: RuleSetting;
|
|
12
14
|
/**
|
|
13
15
|
* Disallow a React state setter inside a scroll handler prop. Scroll fires every frame, and so would the re-render.
|
|
14
16
|
*
|
|
15
17
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-scroll-position-state
|
|
16
18
|
*/
|
|
17
|
-
"@ashstack/react-native/no-scroll-position-state"?:
|
|
19
|
+
"@ashstack/react-native/no-scroll-position-state"?: RuleSetting;
|
|
18
20
|
/**
|
|
19
21
|
* Disallow conditional and logical entries inside a JSX `style` array. A falsy entry leaves a hole that breaks the Unistyles C++ proxy.
|
|
20
22
|
*
|
|
21
23
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-conditional-style-array
|
|
22
24
|
*/
|
|
23
|
-
"@ashstack/react-native/no-conditional-style-array"?:
|
|
25
|
+
"@ashstack/react-native/no-conditional-style-array"?: RuleSetting;
|
|
24
26
|
/**
|
|
25
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".
|
|
26
28
|
*
|
|
27
29
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-leaked-render
|
|
28
30
|
*/
|
|
29
|
-
"@ashstack/react-native/no-leaked-render"?:
|
|
31
|
+
"@ashstack/react-native/no-leaked-render"?: RuleSetting;
|
|
30
32
|
/**
|
|
31
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.
|
|
32
34
|
*
|
|
33
35
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-rn-image-network-source
|
|
34
36
|
*/
|
|
35
|
-
"@ashstack/react-native/no-rn-image-network-source"?:
|
|
37
|
+
"@ashstack/react-native/no-rn-image-network-source"?: RuleSetting;
|
|
36
38
|
/**
|
|
37
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.
|
|
38
40
|
*
|
|
39
41
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-redundant-view-nesting
|
|
40
42
|
*/
|
|
41
|
-
"@ashstack/react-native/no-redundant-view-nesting"?:
|
|
43
|
+
"@ashstack/react-native/no-redundant-view-nesting"?: RuleSetting;
|
|
42
44
|
/**
|
|
43
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.
|
|
44
46
|
*
|
|
45
47
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-rn-namespace-import
|
|
46
48
|
*/
|
|
47
|
-
"@ashstack/react-native/no-rn-namespace-import"?:
|
|
49
|
+
"@ashstack/react-native/no-rn-namespace-import"?: RuleSetting;
|
|
48
50
|
/**
|
|
49
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.
|
|
50
52
|
*
|
|
51
53
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-unlabeled-icon-pressable
|
|
52
54
|
*/
|
|
53
|
-
"@ashstack/react-native/no-unlabeled-icon-pressable"?:
|
|
55
|
+
"@ashstack/react-native/no-unlabeled-icon-pressable"?: RuleSetting;
|
|
54
56
|
/**
|
|
55
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.
|
|
56
58
|
*
|
|
57
59
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativehoist-stateless-function
|
|
58
60
|
*/
|
|
59
|
-
"@ashstack/react-native/hoist-stateless-function"?:
|
|
61
|
+
"@ashstack/react-native/hoist-stateless-function"?: RuleSetting;
|
|
60
62
|
/**
|
|
61
|
-
* 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.
|
|
62
|
-
*
|
|
63
|
-
* Enabled only when one of `babel-plugin-react-compiler`, `react-compiler-runtime`, `react-compiler-marker` is a dependency.
|
|
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. Assumes the compiler is on — pass `reactCompiler: false` to the entry and this rule turns off, since without it a hand-written memo is the only memo there is.
|
|
64
64
|
*
|
|
65
65
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-manual-memo
|
|
66
66
|
*/
|
|
67
|
-
"@ashstack/react-native/no-manual-memo"?:
|
|
67
|
+
"@ashstack/react-native/no-manual-memo"?: RuleSetting;
|
|
68
68
|
/**
|
|
69
69
|
* 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.
|
|
70
70
|
*
|
|
71
71
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreact-nativeno-dynamic-import
|
|
72
72
|
*/
|
|
73
|
-
"@ashstack/react-native/no-dynamic-import"?:
|
|
73
|
+
"@ashstack/react-native/no-dynamic-import"?: RuleSetting;
|
|
74
74
|
/**
|
|
75
75
|
* A Reanimated worklet hook cannot see `useUnistyles()` theme changes on the UI thread. Read the shared value from `useAnimatedTheme()` there instead.
|
|
76
76
|
*
|
|
77
77
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesanimated-theme
|
|
78
78
|
*/
|
|
79
|
-
"@ashstack/unistyles/animated-theme"?:
|
|
79
|
+
"@ashstack/unistyles/animated-theme"?: RuleSetting;
|
|
80
80
|
/**
|
|
81
81
|
* A raw component never subscribes its `contentContainerStyle` to theme or `rt` updates. Wrap the component with `withUnistyles` when the style depends on either.
|
|
82
82
|
*
|
|
83
83
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylescontent-container
|
|
84
84
|
*/
|
|
85
|
-
"@ashstack/unistyles/content-container"?:
|
|
85
|
+
"@ashstack/unistyles/content-container"?: RuleSetting;
|
|
86
86
|
/**
|
|
87
87
|
* 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`.
|
|
88
88
|
*
|
|
89
89
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesin-sheet
|
|
90
90
|
*/
|
|
91
|
-
"@ashstack/unistyles/in-sheet"?:
|
|
91
|
+
"@ashstack/unistyles/in-sheet"?: RuleSetting;
|
|
92
92
|
/**
|
|
93
93
|
* Disallow passing `useSafeAreaInsets()` values into a dynamic style function or an inline JSX style object. Read `rt.insets` inside `StyleSheet.create` instead.
|
|
94
94
|
*
|
|
95
95
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesinsets
|
|
96
96
|
*/
|
|
97
|
-
"@ashstack/unistyles/insets"?:
|
|
97
|
+
"@ashstack/unistyles/insets"?: RuleSetting;
|
|
98
98
|
/**
|
|
99
99
|
* Disallow hex and CSS-function colors inside `StyleSheet.create`. A raw color skips dark mode and never changes with the theme.
|
|
100
100
|
*
|
|
101
101
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesno-hardcoded-color
|
|
102
102
|
*/
|
|
103
|
-
"@ashstack/unistyles/no-hardcoded-color"?:
|
|
103
|
+
"@ashstack/unistyles/no-hardcoded-color"?: RuleSetting;
|
|
104
104
|
/**
|
|
105
105
|
* Require `theme.spacing` or `theme.sizing.scale` for spacing, radius and type values inside `StyleSheet.create`, instead of raw numbers.
|
|
106
106
|
*
|
|
107
107
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesno-hardcoded-spacing
|
|
108
108
|
*/
|
|
109
|
-
"@ashstack/unistyles/no-hardcoded-spacing"?:
|
|
109
|
+
"@ashstack/unistyles/no-hardcoded-spacing"?: RuleSetting;
|
|
110
110
|
/**
|
|
111
111
|
* 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.
|
|
112
112
|
*
|
|
113
113
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesno-margin
|
|
114
114
|
*/
|
|
115
|
-
"@ashstack/unistyles/no-margin"?:
|
|
115
|
+
"@ashstack/unistyles/no-margin"?: RuleSetting;
|
|
116
116
|
/**
|
|
117
117
|
* 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.
|
|
118
118
|
*
|
|
119
119
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesno-style-spread
|
|
120
120
|
*/
|
|
121
|
-
"@ashstack/unistyles/no-style-spread"?:
|
|
121
|
+
"@ashstack/unistyles/no-style-spread"?: RuleSetting;
|
|
122
122
|
/**
|
|
123
123
|
* 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.
|
|
124
124
|
*
|
|
125
125
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesno-unused-styles
|
|
126
126
|
*/
|
|
127
|
-
"@ashstack/unistyles/no-unused-styles"?:
|
|
127
|
+
"@ashstack/unistyles/no-unused-styles"?: RuleSetting;
|
|
128
128
|
/**
|
|
129
129
|
* Disallow passing `I18nManager.isRTL` from JSX into a dynamic style function. Unistyles tracks the dependency itself once the style reads `rt.rtl`.
|
|
130
130
|
*
|
|
131
131
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylesrtl-style-call
|
|
132
132
|
*/
|
|
133
|
-
"@ashstack/unistyles/rtl-style-call"?:
|
|
133
|
+
"@ashstack/unistyles/rtl-style-call"?: RuleSetting;
|
|
134
134
|
/**
|
|
135
135
|
* `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.
|
|
136
136
|
*
|
|
137
137
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylestheme-screen-component
|
|
138
138
|
*/
|
|
139
|
-
"@ashstack/unistyles/theme-screen-component"?:
|
|
139
|
+
"@ashstack/unistyles/theme-screen-component"?: RuleSetting;
|
|
140
140
|
/**
|
|
141
141
|
* Theme-dependent values belong in `StyleSheet.create`, not in a JSX `style` prop that reads a `useUnistyles()` theme.
|
|
142
142
|
*
|
|
143
143
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistylestheme-style-attr
|
|
144
144
|
*/
|
|
145
|
-
"@ashstack/unistyles/theme-style-attr"?:
|
|
145
|
+
"@ashstack/unistyles/theme-style-attr"?: RuleSetting;
|
|
146
146
|
/**
|
|
147
147
|
* Require `keyExtractor` and an explicit `recycleItems` on a Legend List. Without a key extractor the list keys its rows by index.
|
|
148
148
|
*
|
|
149
149
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listrequired-props
|
|
150
150
|
*/
|
|
151
|
-
"@ashstack/legend-list/required-props"?:
|
|
151
|
+
"@ashstack/legend-list/required-props"?: RuleSetting;
|
|
152
152
|
/**
|
|
153
153
|
* 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.
|
|
154
154
|
*
|
|
155
155
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listno-index-key-extractor
|
|
156
156
|
*/
|
|
157
|
-
"@ashstack/legend-list/no-index-key-extractor"?:
|
|
157
|
+
"@ashstack/legend-list/no-index-key-extractor"?: RuleSetting;
|
|
158
158
|
/**
|
|
159
159
|
* Disallow `key` on a Legend List, which remounts on any key change and loses its measurements and scroll position. Pass `dataKey` instead.
|
|
160
160
|
*
|
|
161
161
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listno-remount-key
|
|
162
162
|
*/
|
|
163
|
-
"@ashstack/legend-list/no-remount-key"?:
|
|
163
|
+
"@ashstack/legend-list/no-remount-key"?: RuleSetting;
|
|
164
164
|
/**
|
|
165
165
|
* 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.
|
|
166
166
|
*
|
|
167
167
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listno-inline-render-item-props
|
|
168
168
|
*/
|
|
169
|
-
"@ashstack/legend-list/no-inline-render-item-props"?:
|
|
169
|
+
"@ashstack/legend-list/no-inline-render-item-props"?: RuleSetting;
|
|
170
170
|
/**
|
|
171
171
|
* 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.
|
|
172
172
|
*
|
|
173
173
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listno-mixed-children
|
|
174
174
|
*/
|
|
175
|
-
"@ashstack/legend-list/no-mixed-children"?:
|
|
175
|
+
"@ashstack/legend-list/no-mixed-children"?: RuleSetting;
|
|
176
176
|
/**
|
|
177
177
|
* 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.
|
|
178
178
|
*
|
|
179
179
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listno-flex-in-content-container
|
|
180
180
|
*/
|
|
181
|
-
"@ashstack/legend-list/no-flex-in-content-container"?:
|
|
181
|
+
"@ashstack/legend-list/no-flex-in-content-container"?: RuleSetting;
|
|
182
182
|
/**
|
|
183
183
|
* Require `getItemType` when a row branches on `item.type`. Without it every layout shares one recycling pool and one size average.
|
|
184
184
|
*
|
|
185
185
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listtyped-items-need-item-type
|
|
186
186
|
*/
|
|
187
|
-
"@ashstack/legend-list/typed-items-need-item-type"?:
|
|
187
|
+
"@ashstack/legend-list/typed-items-need-item-type"?: RuleSetting;
|
|
188
188
|
/**
|
|
189
189
|
* A `ScrollView` mounts every child up front, so a mapped collection does not belong in its children.
|
|
190
190
|
*
|
|
191
191
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listno-scrollview-map
|
|
192
192
|
*/
|
|
193
|
-
"@ashstack/legend-list/no-scrollview-map"?:
|
|
193
|
+
"@ashstack/legend-list/no-scrollview-map"?: RuleSetting;
|
|
194
194
|
/**
|
|
195
195
|
* Disallow FlashList and FlatList props that Legend List v3 does not have. It ignores them rather than rejecting them, so the feature looks broken.
|
|
196
196
|
*
|
|
197
197
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-listno-unsupported-props
|
|
198
198
|
*/
|
|
199
|
-
"@ashstack/legend-list/no-unsupported-props"?:
|
|
199
|
+
"@ashstack/legend-list/no-unsupported-props"?: RuleSetting;
|
|
200
200
|
/**
|
|
201
201
|
* Write an observable with `.set(...)` or `.assign({...})`. Assigning or incrementing it with an operator is a silent no-op.
|
|
202
202
|
*
|
|
203
203
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-stateno-assignment
|
|
204
204
|
*/
|
|
205
|
-
"@ashstack/legend-state/no-assignment"?:
|
|
205
|
+
"@ashstack/legend-state/no-assignment"?: RuleSetting;
|
|
206
206
|
/**
|
|
207
207
|
* A variable initialized from `observable()` or `useObservable()` needs a trailing `$`. The other rules in this module key off that suffix.
|
|
208
208
|
*
|
|
209
209
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-statenaming
|
|
210
210
|
*/
|
|
211
|
-
"@ashstack/legend-state/naming"?:
|
|
211
|
+
"@ashstack/legend-state/naming"?: RuleSetting;
|
|
212
212
|
/**
|
|
213
213
|
* Never pass an observable to `observable()` or `useObservable()`. The wrapper is a second node, and reads and writes on it never reach the original.
|
|
214
214
|
*
|
|
215
215
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-stateno-nested-observable
|
|
216
216
|
*/
|
|
217
|
-
"@ashstack/legend-state/no-nested-observable"?:
|
|
217
|
+
"@ashstack/legend-state/no-nested-observable"?: RuleSetting;
|
|
218
218
|
/**
|
|
219
219
|
* Seeding `useState` from an observable's `get()` or `peek()` gives the value two owners. Read it with `useValue(...)` where it renders.
|
|
220
220
|
*
|
|
221
221
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-stateno-react-mirror
|
|
222
222
|
*/
|
|
223
|
-
"@ashstack/legend-state/no-react-mirror"?:
|
|
223
|
+
"@ashstack/legend-state/no-react-mirror"?: RuleSetting;
|
|
224
224
|
/**
|
|
225
225
|
* A `get()` placed directly in a JSX expression container is a plain read. The value renders once and never updates.
|
|
226
226
|
*
|
|
227
227
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-stateno-untracked-get-in-jsx
|
|
228
228
|
*/
|
|
229
|
-
"@ashstack/legend-state/no-untracked-get-in-jsx"?:
|
|
229
|
+
"@ashstack/legend-state/no-untracked-get-in-jsx"?: RuleSetting;
|
|
230
230
|
/**
|
|
231
231
|
* `peek()` never subscribes, so a selector or tracking callback that uses it never re-runs. Call `get()` there and keep `peek()` for handlers.
|
|
232
232
|
*
|
|
233
233
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-stateno-peek-in-selector
|
|
234
234
|
*/
|
|
235
|
-
"@ashstack/legend-state/no-peek-in-selector"?:
|
|
235
|
+
"@ashstack/legend-state/no-peek-in-selector"?: RuleSetting;
|
|
236
236
|
/**
|
|
237
237
|
* 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.
|
|
238
238
|
*
|
|
239
239
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-stateno-object-selector
|
|
240
240
|
*/
|
|
241
|
-
"@ashstack/legend-state/no-object-selector"?:
|
|
241
|
+
"@ashstack/legend-state/no-object-selector"?: RuleSetting;
|
|
242
242
|
/**
|
|
243
243
|
* Calling `observable()` inside a component or hook makes a new observable on every render. Use `useObservable()` or a module-level store instead.
|
|
244
244
|
*
|
|
245
245
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-stateno-observable-in-component
|
|
246
246
|
*/
|
|
247
|
-
"@ashstack/legend-state/no-observable-in-component"?:
|
|
247
|
+
"@ashstack/legend-state/no-observable-in-component"?: RuleSetting;
|
|
248
248
|
/**
|
|
249
249
|
* 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.
|
|
250
250
|
*
|
|
251
251
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedanimated-reaction-safety
|
|
252
252
|
*/
|
|
253
|
-
"@ashstack/reanimated/animated-reaction-safety"?:
|
|
253
|
+
"@ashstack/reanimated/animated-reaction-safety"?: RuleSetting;
|
|
254
254
|
/**
|
|
255
255
|
* An animated style only takes effect on an `Animated.*` component. A plain element applies it once at mount and then never updates.
|
|
256
256
|
*
|
|
257
257
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedanimated-style-needs-animated-component
|
|
258
258
|
*/
|
|
259
|
-
"@ashstack/reanimated/animated-style-needs-animated-component"?:
|
|
259
|
+
"@ashstack/reanimated/animated-style-needs-animated-component"?: RuleSetting;
|
|
260
260
|
/**
|
|
261
261
|
* An updater passed to `useAnimatedStyle` or `useAnimatedProps` must stay pure, so it may not write a shared value or call `scheduleOnRN`.
|
|
262
262
|
*
|
|
263
263
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedanimated-updater-purity
|
|
264
264
|
*/
|
|
265
|
-
"@ashstack/reanimated/animated-updater-purity"?:
|
|
265
|
+
"@ashstack/reanimated/animated-updater-purity"?: RuleSetting;
|
|
266
266
|
/**
|
|
267
267
|
* Animate `transform` and `opacity` in `useAnimatedStyle` and `useAnimatedProps`. Layout properties such as `width` or `margin` recalculate layout every frame.
|
|
268
268
|
*
|
|
269
269
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedgpu-properties-only
|
|
270
270
|
*/
|
|
271
|
-
"@ashstack/reanimated/gpu-properties-only"?:
|
|
271
|
+
"@ashstack/reanimated/gpu-properties-only"?: RuleSetting;
|
|
272
272
|
/**
|
|
273
273
|
* 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.
|
|
274
274
|
*
|
|
275
275
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedhoist-layout-animation-builder
|
|
276
276
|
*/
|
|
277
|
-
"@ashstack/reanimated/hoist-layout-animation-builder"?:
|
|
277
|
+
"@ashstack/reanimated/hoist-layout-animation-builder"?: RuleSetting;
|
|
278
278
|
/**
|
|
279
279
|
* 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.
|
|
280
280
|
*
|
|
281
281
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedinterpolate-needs-clamp
|
|
282
282
|
*/
|
|
283
|
-
"@ashstack/reanimated/interpolate-needs-clamp"?:
|
|
283
|
+
"@ashstack/reanimated/interpolate-needs-clamp"?: RuleSetting;
|
|
284
284
|
/**
|
|
285
285
|
* Shared values are read with `.get()` and written with `.set(...)`, never through `.value`. React Compiler cannot track a `.value` access.
|
|
286
286
|
*
|
|
287
287
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedno-shared-value-dot-value
|
|
288
288
|
*/
|
|
289
|
-
"@ashstack/reanimated/no-shared-value-dot-value"?:
|
|
289
|
+
"@ashstack/reanimated/no-shared-value-dot-value"?: RuleSetting;
|
|
290
290
|
/**
|
|
291
291
|
* A worklet that runs every frame must not send a React state setter through `scheduleOnRN`. That puts a Fabric commit on an animation frame.
|
|
292
292
|
*
|
|
293
293
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedno-react-state-from-continuous-worklet
|
|
294
294
|
*/
|
|
295
|
-
"@ashstack/reanimated/no-react-state-from-continuous-worklet"?:
|
|
295
|
+
"@ashstack/reanimated/no-react-state-from-continuous-worklet"?: RuleSetting;
|
|
296
296
|
/**
|
|
297
297
|
* Pass a computed `useSharedValue` initial value as a function. An eager call runs on every render while only the first result is kept.
|
|
298
298
|
*
|
|
299
299
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedprefer-lazy-shared-value-initializer
|
|
300
300
|
*/
|
|
301
|
-
"@ashstack/reanimated/prefer-lazy-shared-value-initializer"?:
|
|
301
|
+
"@ashstack/reanimated/prefer-lazy-shared-value-initializer"?: RuleSetting;
|
|
302
302
|
/**
|
|
303
303
|
* `scheduleOnRN` takes a function declared in RN Runtime scope. An inline callback can end up created on the wrong runtime.
|
|
304
304
|
*
|
|
305
305
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedschedule-on-rn-scope
|
|
306
306
|
*/
|
|
307
|
-
"@ashstack/reanimated/schedule-on-rn-scope"?:
|
|
307
|
+
"@ashstack/reanimated/schedule-on-rn-scope"?: RuleSetting;
|
|
308
308
|
/**
|
|
309
309
|
* 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.
|
|
310
310
|
*
|
|
311
311
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimatedshared-value-usage
|
|
312
312
|
*/
|
|
313
|
-
"@ashstack/reanimated/shared-value-usage"?:
|
|
313
|
+
"@ashstack/reanimated/shared-value-usage"?: RuleSetting;
|
|
314
314
|
/**
|
|
315
315
|
* 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.
|
|
316
316
|
*
|
|
317
317
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackturbo-imagerequire-resize
|
|
318
318
|
*/
|
|
319
|
-
"@ashstack/turbo-image/require-resize"?:
|
|
319
|
+
"@ashstack/turbo-image/require-resize"?: RuleSetting;
|
|
320
320
|
/**
|
|
321
321
|
* 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.
|
|
322
322
|
*
|
|
323
323
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackturbo-imagerequire-cache-policy
|
|
324
324
|
*/
|
|
325
|
-
"@ashstack/turbo-image/require-cache-policy"?:
|
|
325
|
+
"@ashstack/turbo-image/require-cache-policy"?: RuleSetting;
|
|
326
326
|
/**
|
|
327
327
|
* 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.
|
|
328
328
|
*
|
|
329
329
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackskiacanvas-opaque
|
|
330
330
|
*/
|
|
331
|
-
"@ashstack/skia/canvas-opaque"?:
|
|
331
|
+
"@ashstack/skia/canvas-opaque"?: RuleSetting;
|
|
332
332
|
}
|
|
333
333
|
}
|
|
334
|
+
export {};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
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>];
|
|
2
4
|
/** Every rule id `react()` adds on top of the entry below it. */
|
|
3
5
|
export type ReactRuleId = "@ashstack/react/no-unlabeled-icon-button" | "@ashstack/react/no-svg-without-title" | "@ashstack/query/no-inline-keys" | "@ashstack/query/no-deprecated-filters" | "@ashstack/query/require-destructured-hooks" | "@ashstack/query/no-fetch-in-query-fn" | "@ashstack/query/next-page-param-undefined" | "@ashstack/zustand/require-selector" | "@ashstack/i18n/no-bare-text" | "@ashstack/i18n/no-bare-attrs" | "@ashstack/i18n/no-bare-toast" | "@ashstack/tailwind/prefer-cn" | "@ashstack/tailwind/use-logical-classes" | "@ashstack/tanstack-router/require-selector" | "@ashstack/tanstack-router/no-search-casts" | "@ashstack/effects/no-derived-state" | "@ashstack/effects/no-chain-state-updates" | "@ashstack/effects/no-event-handler" | "@ashstack/effects/no-adjust-state-on-prop-change" | "@ashstack/effects/no-reset-all-state-on-prop-change" | "@ashstack/effects/no-pass-live-state-to-parent" | "@ashstack/effects/no-pass-data-to-parent" | "@ashstack/effects/no-external-store-subscription" | "@ashstack/effects/no-initialize-state";
|
|
4
6
|
declare module "oxlint" {
|
|
@@ -8,146 +10,147 @@ declare module "oxlint" {
|
|
|
8
10
|
*
|
|
9
11
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreactno-unlabeled-icon-button
|
|
10
12
|
*/
|
|
11
|
-
"@ashstack/react/no-unlabeled-icon-button"?:
|
|
13
|
+
"@ashstack/react/no-unlabeled-icon-button"?: RuleSetting;
|
|
12
14
|
/**
|
|
13
15
|
* Require an accessible name on an inline `<svg>`: a `<title>` child with content, an `aria-label`, or a marker that it is decorative. Every child counts, and a self-closing `<svg />` reports.
|
|
14
16
|
*
|
|
15
17
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreactno-svg-without-title
|
|
16
18
|
*/
|
|
17
|
-
"@ashstack/react/no-svg-without-title"?:
|
|
19
|
+
"@ashstack/react/no-svg-without-title"?: RuleSetting;
|
|
18
20
|
/**
|
|
19
21
|
* Disallow a query key written as an array literal at the call site instead of coming from a keys factory.
|
|
20
22
|
*
|
|
21
23
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackqueryno-inline-keys
|
|
22
24
|
*/
|
|
23
|
-
"@ashstack/query/no-inline-keys"?:
|
|
25
|
+
"@ashstack/query/no-inline-keys"?: RuleSetting;
|
|
24
26
|
/**
|
|
25
27
|
* Disallow the positional key argument that TanStack Query v5 removed from `invalidateQueries` and its sibling methods. The suggestion rewrites it to the filter-object form.
|
|
26
28
|
*
|
|
27
29
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackqueryno-deprecated-filters
|
|
28
30
|
*/
|
|
29
|
-
"@ashstack/query/no-deprecated-filters"?:
|
|
31
|
+
"@ashstack/query/no-deprecated-filters"?: RuleSetting;
|
|
30
32
|
/**
|
|
31
33
|
* Require destructuring the result of a hook imported from an `@/api/*.queries` or `@/api/*.mutations` module.
|
|
32
34
|
*
|
|
33
35
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackqueryrequire-destructured-hooks
|
|
34
36
|
*/
|
|
35
|
-
"@ashstack/query/require-destructured-hooks"?:
|
|
37
|
+
"@ashstack/query/require-destructured-hooks"?: RuleSetting;
|
|
36
38
|
/**
|
|
37
39
|
* Disallow a bare `fetch(` inside a `queryFn` or `mutationFn`.
|
|
38
40
|
*
|
|
39
41
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackqueryno-fetch-in-query-fn
|
|
40
42
|
*/
|
|
41
|
-
"@ashstack/query/no-fetch-in-query-fn"?:
|
|
43
|
+
"@ashstack/query/no-fetch-in-query-fn"?: RuleSetting;
|
|
42
44
|
/**
|
|
43
45
|
* Disallow `return null` in the body of a `getNextPageParam`.
|
|
44
46
|
*
|
|
45
47
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackquerynext-page-param-undefined
|
|
46
48
|
*/
|
|
47
|
-
"@ashstack/query/next-page-param-undefined"?:
|
|
49
|
+
"@ashstack/query/next-page-param-undefined"?: RuleSetting;
|
|
48
50
|
/**
|
|
49
51
|
* Require a selector on a store hook, rather than no arguments or `undefined` in its place.
|
|
50
52
|
*
|
|
51
53
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackzustandrequire-selector
|
|
52
54
|
*/
|
|
53
|
-
"@ashstack/zustand/require-selector"?:
|
|
55
|
+
"@ashstack/zustand/require-selector"?: RuleSetting;
|
|
54
56
|
/**
|
|
55
57
|
* Disallow a JSX element that carries no attributes and whose single child is plain literal text.
|
|
56
58
|
*
|
|
57
59
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacki18nno-bare-text
|
|
58
60
|
*/
|
|
59
|
-
"@ashstack/i18n/no-bare-text"?:
|
|
61
|
+
"@ashstack/i18n/no-bare-text"?: RuleSetting;
|
|
60
62
|
/**
|
|
61
63
|
* Disallow a plain string literal on a configurable list of user-visible JSX attributes, defaulting to placeholder, accessibilityLabel, accessibilityHint and title.
|
|
62
64
|
*
|
|
63
65
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacki18nno-bare-attrs
|
|
64
66
|
*/
|
|
65
|
-
"@ashstack/i18n/no-bare-attrs"?:
|
|
67
|
+
"@ashstack/i18n/no-bare-attrs"?: RuleSetting<[{
|
|
66
68
|
attributes?: Array<string>;
|
|
67
|
-
}]
|
|
69
|
+
}]>;
|
|
68
70
|
/**
|
|
69
71
|
* Disallow a `toast.*` call whose only argument is a string literal.
|
|
70
72
|
*
|
|
71
73
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacki18nno-bare-toast
|
|
72
74
|
*/
|
|
73
|
-
"@ashstack/i18n/no-bare-toast"?:
|
|
75
|
+
"@ashstack/i18n/no-bare-toast"?: RuleSetting;
|
|
74
76
|
/**
|
|
75
77
|
* Require a dynamic class value to go through `cn(...)` before it reaches a `class`, `className` or `*ClassName` prop. Reports both where the value reaches the prop and where a variable named after classes is declared.
|
|
76
78
|
*
|
|
77
79
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacktailwindprefer-cn
|
|
78
80
|
*/
|
|
79
|
-
"@ashstack/tailwind/prefer-cn"?:
|
|
81
|
+
"@ashstack/tailwind/prefer-cn"?: RuleSetting;
|
|
80
82
|
/**
|
|
81
83
|
* Require a logical Tailwind utility over its physical left/right twin, so a right-to-left layout mirrors. Reads class props and bindings named after classes, through variant prefixes and the `!` and `-` modifiers.
|
|
82
84
|
*
|
|
83
85
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacktailwinduse-logical-classes
|
|
84
86
|
*/
|
|
85
|
-
"@ashstack/tailwind/use-logical-classes"?:
|
|
87
|
+
"@ashstack/tailwind/use-logical-classes"?: RuleSetting;
|
|
86
88
|
/**
|
|
87
89
|
* Require a `select` on `useLocation`, `useRouterState` and non-strict `useSearch`, so a component reads the smallest router value it needs instead of re-rendering on every navigation.
|
|
88
90
|
*
|
|
89
91
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacktanstack-routerrequire-selector
|
|
90
92
|
*/
|
|
91
|
-
"@ashstack/tanstack-router/require-selector"?:
|
|
93
|
+
"@ashstack/tanstack-router/require-selector"?: RuleSetting;
|
|
92
94
|
/**
|
|
93
95
|
* Disallow an `as` assertion on a `useSearch()` result or on `router.state.location.search`. The route's `validateSearch` schema is what supplies the type.
|
|
94
96
|
*
|
|
95
97
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacktanstack-routerno-search-casts
|
|
96
98
|
*/
|
|
97
|
-
"@ashstack/tanstack-router/no-search-casts"?:
|
|
99
|
+
"@ashstack/tanstack-router/no-search-casts"?: RuleSetting;
|
|
98
100
|
/**
|
|
99
101
|
* Disallow storing derived state in an effect. [Why](https://react.dev/learn/you-might-not-need-an-effect#updating-state-based-on-props-or-state)
|
|
100
102
|
*
|
|
101
103
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-derived-state
|
|
102
104
|
*/
|
|
103
|
-
"@ashstack/effects/no-derived-state"?:
|
|
105
|
+
"@ashstack/effects/no-derived-state"?: RuleSetting;
|
|
104
106
|
/**
|
|
105
107
|
* Disallow chaining state changes in an effect. [Why](https://react.dev/learn/you-might-not-need-an-effect#chains-of-computations)
|
|
106
108
|
*
|
|
107
109
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-chain-state-updates
|
|
108
110
|
*/
|
|
109
|
-
"@ashstack/effects/no-chain-state-updates"?:
|
|
111
|
+
"@ashstack/effects/no-chain-state-updates"?: RuleSetting;
|
|
110
112
|
/**
|
|
111
113
|
* Disallow using state and an effect as an event handler. [Why](https://react.dev/learn/you-might-not-need-an-effect#sharing-logic-between-event-handlers)
|
|
112
114
|
*
|
|
113
115
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-event-handler
|
|
114
116
|
*/
|
|
115
|
-
"@ashstack/effects/no-event-handler"?:
|
|
117
|
+
"@ashstack/effects/no-event-handler"?: RuleSetting;
|
|
116
118
|
/**
|
|
117
119
|
* Disallow adjusting state in an effect when a prop changes. [Why](https://react.dev/learn/you-might-not-need-an-effect#adjusting-some-state-when-a-prop-changes)
|
|
118
120
|
*
|
|
119
121
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-adjust-state-on-prop-change
|
|
120
122
|
*/
|
|
121
|
-
"@ashstack/effects/no-adjust-state-on-prop-change"?:
|
|
123
|
+
"@ashstack/effects/no-adjust-state-on-prop-change"?: RuleSetting;
|
|
122
124
|
/**
|
|
123
125
|
* Disallow resetting all state in an effect when a prop changes. [Why](https://react.dev/learn/you-might-not-need-an-effect#resetting-all-state-when-a-prop-changes)
|
|
124
126
|
*
|
|
125
127
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-reset-all-state-on-prop-change
|
|
126
128
|
*/
|
|
127
|
-
"@ashstack/effects/no-reset-all-state-on-prop-change"?:
|
|
129
|
+
"@ashstack/effects/no-reset-all-state-on-prop-change"?: RuleSetting;
|
|
128
130
|
/**
|
|
129
131
|
* Disallow passing live state to parents in an effect. [Why](https://react.dev/learn/you-might-not-need-an-effect#notifying-parent-components-about-state-changes)
|
|
130
132
|
*
|
|
131
133
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-pass-live-state-to-parent
|
|
132
134
|
*/
|
|
133
|
-
"@ashstack/effects/no-pass-live-state-to-parent"?:
|
|
135
|
+
"@ashstack/effects/no-pass-live-state-to-parent"?: RuleSetting;
|
|
134
136
|
/**
|
|
135
137
|
* Disallow passing data to parents in an effect. [Why](https://react.dev/learn/you-might-not-need-an-effect#passing-data-to-the-parent)
|
|
136
138
|
*
|
|
137
139
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-pass-data-to-parent
|
|
138
140
|
*/
|
|
139
|
-
"@ashstack/effects/no-pass-data-to-parent"?:
|
|
141
|
+
"@ashstack/effects/no-pass-data-to-parent"?: RuleSetting;
|
|
140
142
|
/**
|
|
141
143
|
* Disallow subscribing to an external store in an effect. [Why](https://react.dev/learn/you-might-not-need-an-effect#subscribing-to-an-external-store)
|
|
142
144
|
*
|
|
143
145
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-external-store-subscription
|
|
144
146
|
*/
|
|
145
|
-
"@ashstack/effects/no-external-store-subscription"?:
|
|
147
|
+
"@ashstack/effects/no-external-store-subscription"?: RuleSetting;
|
|
146
148
|
/**
|
|
147
149
|
* Disallow initializing state in an effect. [Why](https://tkdodo.eu/blog/avoiding-hydration-mismatches-with-use-sync-external-store)
|
|
148
150
|
*
|
|
149
151
|
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-initialize-state
|
|
150
152
|
*/
|
|
151
|
-
"@ashstack/effects/no-initialize-state"?:
|
|
153
|
+
"@ashstack/effects/no-initialize-state"?: RuleSetting;
|
|
152
154
|
}
|
|
153
155
|
}
|
|
156
|
+
export {};
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -102,6 +102,12 @@ export type CoreOptions = {
|
|
|
102
102
|
zod?: boolean;
|
|
103
103
|
};
|
|
104
104
|
export type ReactOptions = CoreOptions & {
|
|
105
|
+
/**
|
|
106
|
+
* Is the React Compiler on? Defaults to `true` — every other React setting here assumes it.
|
|
107
|
+
* Set `false` and the four [`react-perf/` inline-prop rules](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#react)
|
|
108
|
+
* come back on, since without the compiler a fresh object, array, function or element in a prop really does re-render the child.
|
|
109
|
+
*/
|
|
110
|
+
reactCompiler?: boolean;
|
|
105
111
|
/** [`@ashstack/query/` rules](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackquery) — detected from `@tanstack/react-query` */
|
|
106
112
|
query?: boolean;
|
|
107
113
|
/** [`@ashstack/zustand/` rules](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackzustand) — detected from `zustand` */
|
package/dist/react/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import o from"../core/index.js";import{EFFECT_RULES as t,effectPlugin as a}from"../lib/effect-plugin.js";import{mergeConfigs as s}from"../lib/merge.js";import{composeModules as n}from"../lib/module.js";import{coreRegistry as c,reactRegistry as i}from"../lib/registry.js";const
|
|
1
|
+
import o from"../core/index.js";import{EFFECT_RULES as t,effectPlugin as a}from"../lib/effect-plugin.js";import{mergeConfigs as s}from"../lib/merge.js";import{composeModules as n}from"../lib/module.js";import{coreRegistry as c,reactRegistry as i}from"../lib/registry.js";const p={"eslint/no-empty":"off","eslint/no-empty-function":"off"},l={"react/error-boundaries":"error","react/globals":"error","react/immutability":"error","react/incompatible-library":"error","react/preserve-manual-memoization":"error","react/purity":"error","react/refs":"error","react/set-state-in-effect":"off","react/set-state-in-render":"error","react/static-components":"error","react/use-memo":"error","react/void-use-memo":"error","react/capitalized-calls":"error","react/exhaustive-effect-dependencies":"error","react/hooks":"error","react/memo-dependencies":"error","react/no-deriving-state-in-effects":"off","react/invariant":"error","react/rule-suppression":"error","react/syntax":"error","react/todo":"error","react/unsupported-syntax":"error"},f=(e)=>{const r=e?"off":"error";return{"react-perf/jsx-no-jsx-as-prop":r,"react-perf/jsx-no-new-array-as-prop":r,"react-perf/jsx-no-new-function-as-prop":r,"react-perf/jsx-no-new-object-as-prop":r,"react/jsx-no-constructed-context-values":r,"react/no-object-type-as-default-prop":r}},u=["**/routes/**","**/src/app/**","**/app/**/_layout.tsx","**/app/**/+*.tsx"],d={...p,"max-lines-per-function":["error",{max:120,skipBlankLines:!0,skipComments:!0}],"react/react-in-jsx-scope":"off","react/style-prop-object":"off","react/only-export-components":"off","react/rules-of-hooks":"error","react/exhaustive-deps":"error","react/button-has-type":"error","react/checked-requires-onchange-or-readonly":"error","react/iframe-missing-sandbox":"error","react/jsx-boolean-value":"error","react/jsx-key":"error","react/jsx-no-comment-textnodes":"error","react/jsx-no-duplicate-props":"error","react/jsx-no-target-blank":"error","react/jsx-no-useless-fragment":"error","react/no-array-index-key":"error","react/no-children-prop":"error","react/no-danger":"error","react/no-danger-with-children":"error","react/no-direct-mutation-state":"error","react/no-is-mounted":"error","react/no-render-return-value":"error","react/no-string-refs":"error","react/no-this-in-sfc":"error","react/no-unsafe":"error","react/no-unescaped-entities":"error","react/no-unstable-nested-components":["error",{allowAsProps:!0}],"react/require-render-return":"error","react/self-closing-comp":"error","react/void-dom-elements-no-children":"error",...l,"jsx-a11y/alt-text":"error","jsx-a11y/anchor-has-content":"error","jsx-a11y/anchor-is-valid":"error","jsx-a11y/click-events-have-key-events":"off","jsx-a11y/control-has-associated-label":"off","jsx-a11y/heading-has-content":"error","jsx-a11y/img-redundant-alt":"error","jsx-a11y/interactive-supports-focus":"error","jsx-a11y/label-has-associated-control":"error","jsx-a11y/no-aria-hidden-on-focusable":"error","jsx-a11y/no-autofocus":["error",{ignoreNonDOM:!0}],"jsx-a11y/no-noninteractive-element-interactions":"off","jsx-a11y/no-noninteractive-tabindex":"error","jsx-a11y/no-redundant-roles":"error","jsx-a11y/no-static-element-interactions":"error","jsx-a11y/prefer-tag-over-role":"off","jsx-a11y/role-has-required-aria-props":"error","jsx-a11y/role-supports-aria-props":"error","unicorn/filename-case":["error",{cases:{kebabCase:!0,pascalCase:!0}}]},react=(e={})=>{const r=n([...c,...i],e);return s(o(e),{plugins:["react","jsx-a11y","react-perf"],jsPlugins:[a,...r.jsPlugins],rules:{...d,...f(e.reactCompiler??!0),...t,...r.rules},overrides:[{files:u,rules:{"unicorn/filename-case":"off"}}]})};export{react};export default react;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{TEST_FILES as
|
|
1
|
+
import{TEST_FILES as r}from"../core/index.js";import{mergeConfigs as s}from"../lib/merge.js";import{composeModules as a}from"../lib/module.js";import{coreRegistry as o,reactNativeRegistry as i,reactRegistry as n}from"../lib/registry.js";import c from"../react/index.js";export const banGroups=[{packages:["react-native-gesture-handler"],restrictedImports:{paths:[{name:"react-native",importNames:["Pressable","TouchableOpacity","TouchableHighlight","TouchableWithoutFeedback","TouchableNativeFeedback"],message:"Import `Pressable` from `react-native-gesture-handler` so it cooperates with the gesture system instead of competing with it. Exception: inside a SwiftUI/Compose host view touches never reach `GestureHandlerRootView` — keep React Native's `Pressable` there and suppress this rule with the host named in the reason."}]}},{packages:["expo-router"],restrictedImports:{patterns:[{group:["@react-navigation/stack","@react-navigation/bottom-tabs"],message:"Use expo-router's `Stack` / `NativeTabs` instead of a raw react-navigation navigator."}]}},{packages:["expo-font"],restrictedImports:{paths:[{name:"expo-font",importNames:["useFonts","loadAsync"],message:"Declare the fonts in the `expo-font` config plugin so they load at build time, instead of `useFonts`/`loadAsync` at runtime."}]}},{packages:["react-native-quick-crypto"],restrictedImports:{paths:[{name:"crypto-js",message:"Use `react-native-quick-crypto` instead — `crypto-js` is pure JavaScript and runs orders of magnitude slower."}]}}];const p={"eslint/no-empty":"error","eslint/no-empty-function":"error"},m={"@ashstack/effects/no-event-handler":"off"},l=(e)=>e?{}:{"@ashstack/react-native/no-manual-memo":"off"},reactNative=(e={})=>{const t=a([...o,...n,...i],e,banGroups);return s(c(e),{jsPlugins:t.jsPlugins,globals:{__DEV__:"readonly"},rules:{...p,...m,"no-restricted-imports":["error",t.restricted],...t.rules,...l(e.reactCompiler??!0)},ignorePatterns:["**/.expo/**","**/android/**","**/ios/**"],overrides:[{files:r,rules:{"@ashstack/react-native/no-dynamic-import":"off","@ashstack/react-native/hoist-stateless-function":"off"}}]})};export{reactNative};export default reactNative;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{gate as m,problem as
|
|
1
|
+
import{gate as m,problem as u}from"../../../lib/ast.js";const l=new Set(["useMemo","useCallback","memo"]),c=/^why:/i,h=10,p=(e)=>e.type==="Identifier"&&l.has(e.name)?e.name:null,f=(e)=>{if(e.type!=="MemberExpression"||e.computed)return null;if(e.object.type!=="Identifier"||e.object.name!=="React")return null;const t=e.property.name;return l.has(t)?t:null},d=(e)=>{if(e.type!=="CallExpression")return null;const{callee:t}=e;if(t.type==="Identifier")return p(t);if(t.type==="MemberExpression")return f(t);return null},y=(e)=>{const t=[0];for(let o=0;o<e.length;o++)if(e.charCodeAt(o)===h)t.push(o+1);return t},w=(e,t)=>{let o=0,n=e.length-1;while(o<n){const s=Math.floor((o+n+1)/2);if((e[s]??0)<=t)o=s;else n=s-1}return o},b=(e,t)=>{const o=new Set;for(const n of e){if(!c.test(n.value.trim()))continue;for(let s=t(n.start);s<=t(n.end);s++)o.add(s)}return o};export const noManualMemo=u("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. Assumes the compiler is on — pass `reactCompiler: false` to the entry and this rule turns off, since without it a hand-written memo is the only memo there is.",{createOnce(e){let t=[];return{before(){t=[];return m(e,"useMemo","useCallback","memo")},CallExpression(o){const n=d(o);if(n!==null)t.push({node:o,name:n})},"Program:exit"(){if(t.length===0)return;const o=y(e.sourceCode.getText()),n=(r)=>w(o,r),s=b(e.sourceCode.getAllComments(),n);for(const{node:r,name:a}of t){const i=n(r.start);if(s.has(i)||s.has(i-1))continue;e.report({node:r,message:`The React Compiler memoises on a best-effort basis, not a guarantee, so a \`${a}\` is allowed where you know the cost is real: something rendered per row in a list, or a computation you measured as heavy. Add a \`// why:\` line directly above it naming which of the two applies. If neither does, delete the \`${a}\`.`})}}}}});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ashstack/lint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "ashStack shared oxlint configuration and custom rules. Entries: core, react, react-native, with per-library rule groups auto-detected from your dependencies. Consume from oxlint.config.mts.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|