@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 +25 -8
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.js +1 -1
- package/dist/lib/effect-plugin.js +1 -1
- package/dist/lib/module.js +1 -1
- package/dist/lib/registry.js +1 -0
- package/dist/lib/rule-types/core.d.ts +76 -0
- package/dist/lib/rule-types/core.js +1 -0
- package/dist/lib/rule-types/react-native.d.ts +336 -0
- package/dist/lib/rule-types/react-native.js +1 -0
- package/dist/lib/rule-types/react.d.ts +156 -0
- package/dist/lib/rule-types/react.js +1 -0
- package/dist/lib/types.d.ts +36 -13
- package/dist/modules.js +1 -0
- package/dist/react/index.d.ts +4 -1
- package/dist/react/index.js +1 -1
- package/dist/react-native/index.d.ts +5 -1
- package/dist/react-native/index.js +1 -1
- package/package.json +3 -7
- package/vendor/react-effect/LICENSE +21 -0
- package/vendor/react-effect/README.md +25 -0
- package/vendor/react-effect/index.mjs +559 -0
|
@@ -0,0 +1,156 @@
|
|
|
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()` adds on top of the entry below it. */
|
|
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";
|
|
6
|
+
declare module "oxlint" {
|
|
7
|
+
interface DummyRuleMap {
|
|
8
|
+
/**
|
|
9
|
+
* Require an accessible name on an icon-only `<button>` or `<Button>`. Without a label, visible text or image alt text, a screen reader cannot reach the control.
|
|
10
|
+
*
|
|
11
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreactno-unlabeled-icon-button
|
|
12
|
+
*/
|
|
13
|
+
"@ashstack/react/no-unlabeled-icon-button"?: RuleSetting;
|
|
14
|
+
/**
|
|
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.
|
|
16
|
+
*
|
|
17
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreactno-svg-without-title
|
|
18
|
+
*/
|
|
19
|
+
"@ashstack/react/no-svg-without-title"?: RuleSetting;
|
|
20
|
+
/**
|
|
21
|
+
* Disallow a query key written as an array literal at the call site instead of coming from a keys factory.
|
|
22
|
+
*
|
|
23
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackqueryno-inline-keys
|
|
24
|
+
*/
|
|
25
|
+
"@ashstack/query/no-inline-keys"?: RuleSetting;
|
|
26
|
+
/**
|
|
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.
|
|
28
|
+
*
|
|
29
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackqueryno-deprecated-filters
|
|
30
|
+
*/
|
|
31
|
+
"@ashstack/query/no-deprecated-filters"?: RuleSetting;
|
|
32
|
+
/**
|
|
33
|
+
* Require destructuring the result of a hook imported from an `@/api/*.queries` or `@/api/*.mutations` module.
|
|
34
|
+
*
|
|
35
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackqueryrequire-destructured-hooks
|
|
36
|
+
*/
|
|
37
|
+
"@ashstack/query/require-destructured-hooks"?: RuleSetting;
|
|
38
|
+
/**
|
|
39
|
+
* Disallow a bare `fetch(` inside a `queryFn` or `mutationFn`.
|
|
40
|
+
*
|
|
41
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackqueryno-fetch-in-query-fn
|
|
42
|
+
*/
|
|
43
|
+
"@ashstack/query/no-fetch-in-query-fn"?: RuleSetting;
|
|
44
|
+
/**
|
|
45
|
+
* Disallow `return null` in the body of a `getNextPageParam`.
|
|
46
|
+
*
|
|
47
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackquerynext-page-param-undefined
|
|
48
|
+
*/
|
|
49
|
+
"@ashstack/query/next-page-param-undefined"?: RuleSetting;
|
|
50
|
+
/**
|
|
51
|
+
* Require a selector on a store hook, rather than no arguments or `undefined` in its place.
|
|
52
|
+
*
|
|
53
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackzustandrequire-selector
|
|
54
|
+
*/
|
|
55
|
+
"@ashstack/zustand/require-selector"?: RuleSetting;
|
|
56
|
+
/**
|
|
57
|
+
* Disallow a JSX element that carries no attributes and whose single child is plain literal text.
|
|
58
|
+
*
|
|
59
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacki18nno-bare-text
|
|
60
|
+
*/
|
|
61
|
+
"@ashstack/i18n/no-bare-text"?: RuleSetting;
|
|
62
|
+
/**
|
|
63
|
+
* Disallow a plain string literal on a configurable list of user-visible JSX attributes, defaulting to placeholder, accessibilityLabel, accessibilityHint and title.
|
|
64
|
+
*
|
|
65
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacki18nno-bare-attrs
|
|
66
|
+
*/
|
|
67
|
+
"@ashstack/i18n/no-bare-attrs"?: RuleSetting<[{
|
|
68
|
+
attributes?: Array<string>;
|
|
69
|
+
}]>;
|
|
70
|
+
/**
|
|
71
|
+
* Disallow a `toast.*` call whose only argument is a string literal.
|
|
72
|
+
*
|
|
73
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacki18nno-bare-toast
|
|
74
|
+
*/
|
|
75
|
+
"@ashstack/i18n/no-bare-toast"?: RuleSetting;
|
|
76
|
+
/**
|
|
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.
|
|
78
|
+
*
|
|
79
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacktailwindprefer-cn
|
|
80
|
+
*/
|
|
81
|
+
"@ashstack/tailwind/prefer-cn"?: RuleSetting;
|
|
82
|
+
/**
|
|
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.
|
|
84
|
+
*
|
|
85
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacktailwinduse-logical-classes
|
|
86
|
+
*/
|
|
87
|
+
"@ashstack/tailwind/use-logical-classes"?: RuleSetting;
|
|
88
|
+
/**
|
|
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.
|
|
90
|
+
*
|
|
91
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacktanstack-routerrequire-selector
|
|
92
|
+
*/
|
|
93
|
+
"@ashstack/tanstack-router/require-selector"?: RuleSetting;
|
|
94
|
+
/**
|
|
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.
|
|
96
|
+
*
|
|
97
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacktanstack-routerno-search-casts
|
|
98
|
+
*/
|
|
99
|
+
"@ashstack/tanstack-router/no-search-casts"?: RuleSetting;
|
|
100
|
+
/**
|
|
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)
|
|
102
|
+
*
|
|
103
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-derived-state
|
|
104
|
+
*/
|
|
105
|
+
"@ashstack/effects/no-derived-state"?: RuleSetting;
|
|
106
|
+
/**
|
|
107
|
+
* Disallow chaining state changes in an effect. [Why](https://react.dev/learn/you-might-not-need-an-effect#chains-of-computations)
|
|
108
|
+
*
|
|
109
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-chain-state-updates
|
|
110
|
+
*/
|
|
111
|
+
"@ashstack/effects/no-chain-state-updates"?: RuleSetting;
|
|
112
|
+
/**
|
|
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)
|
|
114
|
+
*
|
|
115
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-event-handler
|
|
116
|
+
*/
|
|
117
|
+
"@ashstack/effects/no-event-handler"?: RuleSetting;
|
|
118
|
+
/**
|
|
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)
|
|
120
|
+
*
|
|
121
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-adjust-state-on-prop-change
|
|
122
|
+
*/
|
|
123
|
+
"@ashstack/effects/no-adjust-state-on-prop-change"?: RuleSetting;
|
|
124
|
+
/**
|
|
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)
|
|
126
|
+
*
|
|
127
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-reset-all-state-on-prop-change
|
|
128
|
+
*/
|
|
129
|
+
"@ashstack/effects/no-reset-all-state-on-prop-change"?: RuleSetting;
|
|
130
|
+
/**
|
|
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)
|
|
132
|
+
*
|
|
133
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-pass-live-state-to-parent
|
|
134
|
+
*/
|
|
135
|
+
"@ashstack/effects/no-pass-live-state-to-parent"?: RuleSetting;
|
|
136
|
+
/**
|
|
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)
|
|
138
|
+
*
|
|
139
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-pass-data-to-parent
|
|
140
|
+
*/
|
|
141
|
+
"@ashstack/effects/no-pass-data-to-parent"?: RuleSetting;
|
|
142
|
+
/**
|
|
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)
|
|
144
|
+
*
|
|
145
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-external-store-subscription
|
|
146
|
+
*/
|
|
147
|
+
"@ashstack/effects/no-external-store-subscription"?: RuleSetting;
|
|
148
|
+
/**
|
|
149
|
+
* Disallow initializing state in an effect. [Why](https://tkdodo.eu/blog/avoiding-hydration-mismatches-with-use-sync-external-store)
|
|
150
|
+
*
|
|
151
|
+
* @see https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackeffectsno-initialize-state
|
|
152
|
+
*/
|
|
153
|
+
"@ashstack/effects/no-initialize-state"?: RuleSetting;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{};
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -69,25 +69,48 @@ export interface ModuleManifest {
|
|
|
69
69
|
/** import bans that ship with (and only with) this module */
|
|
70
70
|
restrictedImports?: RestrictedImports;
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* What a config needs from a module: the plugin file to hand oxlint, and the
|
|
74
|
+
* two flags per rule that decide whether it is on. Generated into
|
|
75
|
+
* `lib/registry.ts` from the manifests, so a config never imports rule code
|
|
76
|
+
* that oxlint is going to load from the path anyway.
|
|
77
|
+
*/
|
|
78
|
+
export interface ModuleMeta {
|
|
79
|
+
meta: {
|
|
80
|
+
name: `@ashstack/${string}`;
|
|
81
|
+
};
|
|
82
|
+
/** Absolute URL of the module's plugin file. */
|
|
83
|
+
url: string;
|
|
84
|
+
/** Enable when one of these is a dependency; absent = always on. */
|
|
85
|
+
packages?: string[];
|
|
86
|
+
/** Key in the entry options that forces the module on/off; absent = auto-only. */
|
|
87
|
+
option?: string;
|
|
88
|
+
restrictedImports?: RestrictedImports;
|
|
89
|
+
/** Rule name to the flags that gate it: off unless asked for, or gated on its own dependency. */
|
|
90
|
+
rules: Record<string, {
|
|
91
|
+
defaultOff?: boolean;
|
|
92
|
+
packages?: string[];
|
|
93
|
+
}>;
|
|
94
|
+
}
|
|
72
95
|
/** A ban-only group: import bans gated on a library, with no rules of its own. */
|
|
73
96
|
export interface BanGroup {
|
|
74
97
|
packages: string[];
|
|
75
98
|
restrictedImports: RestrictedImports;
|
|
76
99
|
}
|
|
77
100
|
export type CoreOptions = {
|
|
78
|
-
/** `@ashstack/zod/` rules — detected from `zod` */
|
|
101
|
+
/** [`@ashstack/zod/` rules](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackzod) — detected from `zod` */
|
|
79
102
|
zod?: boolean;
|
|
80
103
|
};
|
|
81
104
|
export type ReactOptions = CoreOptions & {
|
|
82
|
-
/** `@ashstack/query/` rules — detected from `@tanstack/react-query` */
|
|
105
|
+
/** [`@ashstack/query/` rules](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackquery) — detected from `@tanstack/react-query` */
|
|
83
106
|
query?: boolean;
|
|
84
|
-
/** `@ashstack/zustand/` rules — detected from `zustand` */
|
|
107
|
+
/** [`@ashstack/zustand/` rules](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackzustand) — detected from `zustand` */
|
|
85
108
|
zustand?: boolean;
|
|
86
|
-
/** `@ashstack/i18n/` rules — detected from i18next/lingui/react-intl/use-intl/next-intl/expo-localization */
|
|
109
|
+
/** [`@ashstack/i18n/` rules](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacki18n) — detected from i18next/lingui/react-intl/use-intl/next-intl/expo-localization */
|
|
87
110
|
i18n?: boolean;
|
|
88
|
-
/** `@ashstack/tailwind/` rules — detected from `tailwindcss` */
|
|
111
|
+
/** [`@ashstack/tailwind/` rules](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacktailwind) — detected from `tailwindcss` */
|
|
89
112
|
tailwind?: boolean;
|
|
90
|
-
/** `@ashstack/tanstack-router/` rules — detected from `@tanstack/react-router` */
|
|
113
|
+
/** [`@ashstack/tanstack-router/` rules](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacktanstack-router) — detected from `@tanstack/react-router` */
|
|
91
114
|
tanstackRouter?: boolean;
|
|
92
115
|
};
|
|
93
116
|
/**
|
|
@@ -96,19 +119,19 @@ export type ReactOptions = CoreOptions & {
|
|
|
96
119
|
* by name in your `rules` block.
|
|
97
120
|
*/
|
|
98
121
|
export type ReactNativeOptions = ReactOptions & {
|
|
99
|
-
/** `@ashstack/unistyles/` rules + StyleSheet/Dimensions/SafeArea import bans — `react-native-unistyles` */
|
|
122
|
+
/** [`@ashstack/unistyles/` rules](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackunistyles) + StyleSheet/Dimensions/SafeArea import bans — `react-native-unistyles` */
|
|
100
123
|
unistyles?: boolean;
|
|
101
|
-
/** `@ashstack/legend-list/` rules + FlatList/FlashList bans — `@legendapp/list` */
|
|
124
|
+
/** [`@ashstack/legend-list/` rules](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-list) + FlatList/FlashList bans — `@legendapp/list` */
|
|
102
125
|
legendList?: boolean;
|
|
103
|
-
/** `@ashstack/legend-state/` rules + use$/useSelector ban — `@legendapp/state` */
|
|
126
|
+
/** [`@ashstack/legend-state/` rules](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstacklegend-state) + use$/useSelector ban — `@legendapp/state` */
|
|
104
127
|
legendState?: boolean;
|
|
105
|
-
/** `@ashstack/reanimated/` rules + Animated/runOnJS bans — `react-native-reanimated` */
|
|
128
|
+
/** [`@ashstack/reanimated/` rules](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackreanimated) + Animated/runOnJS bans — `react-native-reanimated` */
|
|
106
129
|
reanimated?: boolean;
|
|
107
|
-
/** `@ashstack/turbo-image/` rules — `react-native-turbo-image` */
|
|
130
|
+
/** [`@ashstack/turbo-image/` rules](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackturbo-image) — `react-native-turbo-image` */
|
|
108
131
|
turboImage?: boolean;
|
|
109
|
-
/** `@ashstack/skia/` rules — `@shopify/react-native-skia` */
|
|
132
|
+
/** [`@ashstack/skia/` rules](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackskia) — `@shopify/react-native-skia` */
|
|
110
133
|
skia?: boolean;
|
|
111
|
-
/** `@ashstack/keyboard` import bans — `react-native-keyboard-controller` */
|
|
134
|
+
/** [`@ashstack/keyboard` import bans](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#ashstackkeyboard) — `react-native-keyboard-controller` */
|
|
112
135
|
keyboard?: boolean;
|
|
113
136
|
};
|
|
114
137
|
/** The config object an entry returns: oxlint's own shape, so `defineConfig({ extends: [core()] })` typechecks. */
|
package/dist/modules.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import o from"./core/rules/core/index.js";import r from"./core/rules/zod/index.js";import e from"./react-native/rules/keyboard/index.js";import t from"./react-native/rules/legend-list/index.js";import m from"./react-native/rules/legend-state/index.js";import d from"./react-native/rules/react-native/index.js";import i from"./react-native/rules/reanimated/index.js";import u from"./react-native/rules/skia/index.js";import l from"./react-native/rules/turbo-image/index.js";import p from"./react-native/rules/unistyles/index.js";import M from"./react/rules/i18n/index.js";import a from"./react/rules/query/index.js";import f from"./react/rules/react/index.js";import s from"./react/rules/tailwind/index.js";import n from"./react/rules/tanstack-router/index.js";import c from"./react/rules/zustand/index.js";export const coreModules=[o,r],reactModules=[f,a,c,M,s,n],reactNativeModules=[d,p,t,m,i,l,u,e];
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import type { OxlintConfig, ReactOptions } from "../lib/types.js";
|
|
2
|
-
export declare const reactModules: import("../lib/types.js").ModuleManifest[];
|
|
3
2
|
/**
|
|
4
3
|
* React (web) entry — everything in core plus react, jsx-a11y, React Compiler
|
|
5
4
|
* diagnostics, you-might-not-need-an-effect, and the auto-detected library
|
|
6
5
|
* modules (query, zustand, i18n).
|
|
6
|
+
*
|
|
7
|
+
* @see [every rule `react()` sets](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#react)
|
|
7
8
|
*/
|
|
8
9
|
declare const react: (options?: ReactOptions) => OxlintConfig;
|
|
9
10
|
export { react };
|
|
11
|
+
export type { CoreRuleId } from "../lib/rule-types/core.js";
|
|
12
|
+
export type { ReactRuleId } from "../lib/rule-types/react.js";
|
|
10
13
|
export type { ReactOptions, ModuleManifest } from "../lib/types.js";
|
|
11
14
|
export default react;
|
package/dist/react/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
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 l={"eslint/no-empty":"off","eslint/no-empty-function":"off"},u={"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"},p=["**/routes/**","**/src/app/**","**/app/**/_layout.tsx","**/app/**/+*.tsx"],f={...l,"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-constructed-context-values":"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",...u,"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=(r={})=>{const e=n([...c,...i],r);return s(o(r),{plugins:["react","jsx-a11y","react-perf"],jsPlugins:[a,...e.jsPlugins],rules:{...f,...t,...e.rules},overrides:[{files:p,rules:{"unicorn/filename-case":"off"}}]})};export{react};export default react;
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import type { BanGroup, OxlintConfig, ReactNativeOptions } from "../lib/types.js";
|
|
2
|
-
export declare const reactNativeModules: import("../lib/types.js").ModuleManifest[];
|
|
3
2
|
export declare const banGroups: BanGroup[];
|
|
4
3
|
/**
|
|
5
4
|
* React Native / Expo entry — everything in react plus generic RN rules, with
|
|
6
5
|
* per-library modules (unistyles, legendList, legendState, reanimated,
|
|
7
6
|
* turboImage, skia, keyboard) auto-detected from your dependencies. Your
|
|
8
7
|
* `rules` block always overrides.
|
|
8
|
+
*
|
|
9
|
+
* @see [every rule `react-native()` sets](https://github.com/AlshehriAli0/ashStack/blob/main/packages/lint/RULES.md#react-native)
|
|
9
10
|
*/
|
|
10
11
|
declare const reactNative: (options?: ReactNativeOptions) => OxlintConfig;
|
|
11
12
|
export { reactNative };
|
|
13
|
+
export type { CoreRuleId } from "../lib/rule-types/core.js";
|
|
14
|
+
export type { ReactRuleId } from "../lib/rule-types/react.js";
|
|
15
|
+
export type { ReactNativeRuleId } from "../lib/rule-types/react-native.js";
|
|
12
16
|
export type { ReactNativeOptions, ModuleManifest } from "../lib/types.js";
|
|
13
17
|
export default reactNative;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{TEST_FILES as
|
|
1
|
+
import{TEST_FILES as s}from"../core/index.js";import{mergeConfigs as r}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"},reactNative=(t={})=>{const e=a([...o,...n,...i],t,banGroups);return r(c(t),{jsPlugins:e.jsPlugins,globals:{__DEV__:"readonly"},rules:{...p,...m,"no-restricted-imports":["error",e.restricted],...e.rules},ignorePatterns:["**/.expo/**","**/android/**","**/ios/**"],overrides:[{files:s,rules:{"@ashstack/react-native/no-dynamic-import":"off","@ashstack/react-native/hoist-stateless-function":"off"}}]})};export{reactNative};export default reactNative;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ashstack/lint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
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",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"files": [
|
|
41
41
|
"dist",
|
|
42
|
+
"vendor",
|
|
42
43
|
"!dist/index.js",
|
|
43
44
|
"!dist/index.d.ts"
|
|
44
45
|
],
|
|
@@ -47,15 +48,11 @@
|
|
|
47
48
|
},
|
|
48
49
|
"peerDependencies": {
|
|
49
50
|
"oxlint": ">=1.79.0",
|
|
50
|
-
"oxlint-tsgolint": ">=7.0.0"
|
|
51
|
-
"eslint-plugin-react-you-might-not-need-an-effect": "^1.0.1"
|
|
51
|
+
"oxlint-tsgolint": ">=7.0.0"
|
|
52
52
|
},
|
|
53
53
|
"peerDependenciesMeta": {
|
|
54
54
|
"oxlint-tsgolint": {
|
|
55
55
|
"optional": true
|
|
56
|
-
},
|
|
57
|
-
"eslint-plugin-react-you-might-not-need-an-effect": {
|
|
58
|
-
"optional": true
|
|
59
56
|
}
|
|
60
57
|
},
|
|
61
58
|
"scripts": {
|
|
@@ -63,7 +60,6 @@
|
|
|
63
60
|
},
|
|
64
61
|
"devDependencies": {
|
|
65
62
|
"@types/node": "^22.10.0",
|
|
66
|
-
"eslint-plugin-react-you-might-not-need-an-effect": "^1.0.1",
|
|
67
63
|
"typescript": "^7.0.2"
|
|
68
64
|
}
|
|
69
65
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Nick van Dyke
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the “Software”), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# eslint-plugin-react-you-might-not-need-an-effect
|
|
2
|
+
|
|
3
|
+
Vendored verbatim at **1.0.2**, MIT, from
|
|
4
|
+
https://github.com/NickvanDyke/eslint-plugin-react-you-might-not-need-an-effect
|
|
5
|
+
|
|
6
|
+
`index.mjs` is its published `dist/index.mjs`, unmodified. `LICENSE` is its own.
|
|
7
|
+
|
|
8
|
+
## Why it is here
|
|
9
|
+
|
|
10
|
+
Depending on the package installs 12.3 MB across 60 packages, because it
|
|
11
|
+
declares `eslint` as a non-optional peer and npm installs peers. Its code never
|
|
12
|
+
imports eslint — oxlint loads it through its own plugin bridge — so the whole
|
|
13
|
+
ESLint tree sat in every consumer's `node_modules` without ever running. The
|
|
14
|
+
file itself is 32 KB and imports only `globals`, which stays a dependency.
|
|
15
|
+
|
|
16
|
+
## Updating
|
|
17
|
+
|
|
18
|
+
npm pack eslint-plugin-react-you-might-not-need-an-effect@<version>
|
|
19
|
+
tar xzf eslint-plugin-*.tgz
|
|
20
|
+
bun run vendor:effects --from=package/dist/index.mjs
|
|
21
|
+
|
|
22
|
+
Then update the version above. `scripts/vendor-effects.ts` drops the config
|
|
23
|
+
presets and the `globals` import they need, and refuses to write a file that
|
|
24
|
+
still imports anything. `tests/effects.test.ts` fails if the rule ids this
|
|
25
|
+
package enables stop matching the ones the file exports.
|