@imranbarbhuiya/oxc-config 0.1.13 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -106,8 +106,7 @@ Add scripts to `package.json`:
106
106
  - `node` contains Node.js rules
107
107
  - `module` contains ECMAScript module rules
108
108
  - `typescript` contains TypeScript and type-aware rules
109
- - `jsx` contains JSX rules
110
- - `react` contains React rules and includes JSX
109
+ - `react` contains React and JSX rules
111
110
  - `native` contains React Native rules and includes React
112
111
  - `next` contains Next.js rules
113
112
  - `edge` contains edge-runtime rules
package/dist/native.d.ts CHANGED
@@ -1,11 +1,6 @@
1
1
  //#region src/native.d.ts
2
2
  declare const config: {
3
3
  extends: {
4
- extends: {
5
- plugins: ("eslint" | "react" | "unicorn" | "typescript" | "oxc" | "import" | "jsdoc" | "jest" | "vitest" | "jsx-a11y" | "nextjs" | "react-perf" | "promise" | "node" | "vue")[];
6
- jsPlugins: import("oxlint").ExternalPluginEntry[];
7
- rules: import("oxlint").DummyRuleMap;
8
- }[];
9
4
  plugins: ("eslint" | "react" | "unicorn" | "typescript" | "oxc" | "import" | "jsdoc" | "jest" | "vitest" | "jsx-a11y" | "nextjs" | "react-perf" | "promise" | "node" | "vue")[];
10
5
  jsPlugins: import("oxlint").ExternalPluginEntry[];
11
6
  env: {
@@ -0,0 +1,5 @@
1
+ //#region src/plugins/react.d.ts
2
+ declare const _default: import("@oxlint/plugins").Plugin;
3
+ //#endregion
4
+ export { _default as default };
5
+ //# sourceMappingURL=react.d.ts.map
@@ -0,0 +1,369 @@
1
+ import { definePlugin, defineRule } from "@oxlint/plugins";
2
+
3
+ //#region src/plugins/react.ts
4
+ const REL_TAGS = /* @__PURE__ */ new Set([
5
+ "a",
6
+ "area",
7
+ "form",
8
+ "link"
9
+ ]);
10
+ const REL_VALUES = /* @__PURE__ */ new Map([
11
+ ["alternate", /* @__PURE__ */ new Set([
12
+ "link",
13
+ "area",
14
+ "a"
15
+ ])],
16
+ ["apple-touch-icon", /* @__PURE__ */ new Set(["link"])],
17
+ ["apple-touch-startup-image", /* @__PURE__ */ new Set(["link"])],
18
+ ["author", /* @__PURE__ */ new Set([
19
+ "link",
20
+ "area",
21
+ "a"
22
+ ])],
23
+ ["bookmark", /* @__PURE__ */ new Set(["area", "a"])],
24
+ ["canonical", /* @__PURE__ */ new Set(["link"])],
25
+ ["dns-prefetch", /* @__PURE__ */ new Set(["link"])],
26
+ ["external", /* @__PURE__ */ new Set([
27
+ "area",
28
+ "a",
29
+ "form"
30
+ ])],
31
+ ["help", /* @__PURE__ */ new Set([
32
+ "link",
33
+ "area",
34
+ "a",
35
+ "form"
36
+ ])],
37
+ ["icon", /* @__PURE__ */ new Set(["link"])],
38
+ ["license", /* @__PURE__ */ new Set([
39
+ "link",
40
+ "area",
41
+ "a",
42
+ "form"
43
+ ])],
44
+ ["manifest", /* @__PURE__ */ new Set(["link"])],
45
+ ["mask-icon", /* @__PURE__ */ new Set(["link"])],
46
+ ["modulepreload", /* @__PURE__ */ new Set(["link"])],
47
+ ["next", /* @__PURE__ */ new Set([
48
+ "link",
49
+ "area",
50
+ "a",
51
+ "form"
52
+ ])],
53
+ ["nofollow", /* @__PURE__ */ new Set([
54
+ "area",
55
+ "a",
56
+ "form"
57
+ ])],
58
+ ["noopener", /* @__PURE__ */ new Set([
59
+ "area",
60
+ "a",
61
+ "form"
62
+ ])],
63
+ ["noreferrer", /* @__PURE__ */ new Set([
64
+ "area",
65
+ "a",
66
+ "form"
67
+ ])],
68
+ ["opener", /* @__PURE__ */ new Set([
69
+ "area",
70
+ "a",
71
+ "form"
72
+ ])],
73
+ ["pingback", /* @__PURE__ */ new Set(["link"])],
74
+ ["preconnect", /* @__PURE__ */ new Set(["link"])],
75
+ ["prefetch", /* @__PURE__ */ new Set(["link"])],
76
+ ["preload", /* @__PURE__ */ new Set(["link"])],
77
+ ["prerender", /* @__PURE__ */ new Set(["link"])],
78
+ ["prev", /* @__PURE__ */ new Set([
79
+ "link",
80
+ "area",
81
+ "a",
82
+ "form"
83
+ ])],
84
+ ["search", /* @__PURE__ */ new Set([
85
+ "link",
86
+ "area",
87
+ "a",
88
+ "form"
89
+ ])],
90
+ ["shortcut", /* @__PURE__ */ new Set(["link"])],
91
+ ["shortcut icon", /* @__PURE__ */ new Set(["link"])],
92
+ ["stylesheet", /* @__PURE__ */ new Set(["link"])],
93
+ ["tag", /* @__PURE__ */ new Set(["area", "a"])]
94
+ ]);
95
+ function isJsxSibling(node) {
96
+ return node.type === "JSXElement" || node.type === "JSXExpressionContainer";
97
+ }
98
+ function isFunction(node) {
99
+ return node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
100
+ }
101
+ function attrName(attribute) {
102
+ if (attribute.name.type === "JSXIdentifier") return attribute.name.name;
103
+ return `${attribute.name.namespace.name}:${attribute.name.name.name}`;
104
+ }
105
+ function memberName(member) {
106
+ if (member.key.type === "Identifier") return member.key.name;
107
+ if (member.key.type === "Literal" && typeof member.key.value === "string") return member.key.value;
108
+ return "unknown";
109
+ }
110
+ function patternType(pattern) {
111
+ if (!("typeAnnotation" in pattern)) return void 0;
112
+ const annotation = pattern.typeAnnotation;
113
+ if (annotation === void 0 || annotation === null || typeof annotation !== "object") return void 0;
114
+ if (!("type" in annotation) || annotation.type !== "TSTypeAnnotation") return void 0;
115
+ return annotation.typeAnnotation;
116
+ }
117
+ function paramType(fn) {
118
+ if (fn.params.length === 0) return void 0;
119
+ const param = fn.params[0];
120
+ if (param.type === "TSParameterProperty") return patternType(param.parameter);
121
+ if (param.type === "RestElement") return void 0;
122
+ if (param.type === "AssignmentPattern") return patternType(param.left);
123
+ return patternType(param);
124
+ }
125
+ function unwrapType(type) {
126
+ let current = type;
127
+ while (current.type === "TSParenthesizedType") current = current.typeAnnotation;
128
+ return current;
129
+ }
130
+ function isReadonlyWrapper(type) {
131
+ return type.type === "TSTypeReference" && type.typeName.type === "Identifier" && type.typeName.name === "Readonly";
132
+ }
133
+ function enclosingFunction(node) {
134
+ let current = node.parent;
135
+ while (current) {
136
+ if (isFunction(current)) return current;
137
+ current = current.parent;
138
+ }
139
+ }
140
+ const jsxNewline = defineRule({
141
+ meta: {
142
+ type: "layout",
143
+ docs: { description: "Prevent blank lines between adjacent JSX siblings" },
144
+ fixable: "code",
145
+ messages: { prevent: "JSX element should not start in a new line" }
146
+ },
147
+ createOnce(context) {
148
+ function check(children) {
149
+ for (let index = 0; index < children.length - 2; index++) {
150
+ const current = children[index];
151
+ const between = children[index + 1];
152
+ const next = children[index + 2];
153
+ if (!isJsxSibling(current) || !isJsxSibling(next) || between.type !== "JSXText") continue;
154
+ if (!/\n\s*\n/.test(between.value)) continue;
155
+ context.report({
156
+ node: next,
157
+ messageId: "prevent",
158
+ fix(fixer) {
159
+ return fixer.replaceText(between, context.sourceCode.getText(between).replace(/\n\s*\n/, "\n"));
160
+ }
161
+ });
162
+ }
163
+ }
164
+ return {
165
+ JSXElement(node) {
166
+ check(node.children);
167
+ },
168
+ JSXFragment(node) {
169
+ check(node.children);
170
+ }
171
+ };
172
+ }
173
+ });
174
+ const jsxSortProps = defineRule({
175
+ meta: {
176
+ type: "layout",
177
+ docs: { description: "Sort JSX props alphabetically" },
178
+ fixable: "code",
179
+ messages: { sortPropsByAlpha: "Props should be sorted alphabetically" }
180
+ },
181
+ createOnce(context) {
182
+ return { JSXOpeningElement(node) {
183
+ let group = [];
184
+ function flush() {
185
+ if (group.length < 2) {
186
+ group = [];
187
+ return;
188
+ }
189
+ const sorted = group.toSorted((left, right) => {
190
+ const leftName = attrName(left);
191
+ const rightName = attrName(right);
192
+ if (leftName === rightName) return 0;
193
+ return leftName < rightName ? -1 : 1;
194
+ });
195
+ if (group.every((attribute, index) => attribute === sorted[index])) {
196
+ group = [];
197
+ return;
198
+ }
199
+ const texts = sorted.map((attribute) => context.sourceCode.getText(attribute));
200
+ context.report({
201
+ node: group[0],
202
+ messageId: "sortPropsByAlpha",
203
+ fix(fixer) {
204
+ return group.map((attribute, index) => fixer.replaceText(attribute, texts[index] ?? ""));
205
+ }
206
+ });
207
+ group = [];
208
+ }
209
+ for (const attribute of node.attributes) {
210
+ if (attribute.type === "JSXSpreadAttribute") {
211
+ flush();
212
+ continue;
213
+ }
214
+ group.push(attribute);
215
+ }
216
+ flush();
217
+ } };
218
+ }
219
+ });
220
+ const noInvalidHtmlAttribute = defineRule({
221
+ meta: {
222
+ type: "suggestion",
223
+ docs: { description: "Disallow invalid HTML rel attribute values" },
224
+ messages: {
225
+ emptyIsMeaningless: "An empty “rel” attribute is meaningless.",
226
+ neverValid: "“{{value}}” is never a valid “rel” attribute value.",
227
+ notAlone: "“shortcut” must be directly followed by “icon”.",
228
+ notValidFor: "“{{value}}” is not a valid “rel” attribute value for <{{tag}}>.",
229
+ onlyMeaningfulFor: "The “rel” attribute only has meaning on the tags: \"<link>\", \"<a>\", \"<area>\", \"<form>\""
230
+ }
231
+ },
232
+ createOnce(context) {
233
+ return { JSXAttribute(node) {
234
+ if (node.name.type !== "JSXIdentifier" || node.name.name !== "rel") return;
235
+ if (node.parent.type !== "JSXOpeningElement" || node.parent.name.type !== "JSXIdentifier") return;
236
+ const tag = node.parent.name.name;
237
+ if (tag !== tag.toLowerCase()) return;
238
+ if (!REL_TAGS.has(tag)) {
239
+ context.report({
240
+ node: node.name,
241
+ messageId: "onlyMeaningfulFor"
242
+ });
243
+ return;
244
+ }
245
+ if (node.value === null) {
246
+ context.report({
247
+ node: node.name,
248
+ messageId: "emptyIsMeaningless"
249
+ });
250
+ return;
251
+ }
252
+ let literal;
253
+ if (node.value.type === "Literal" && typeof node.value.value === "string") literal = node.value;
254
+ if (node.value.type === "JSXExpressionContainer" && node.value.expression.type === "Literal" && typeof node.value.expression.value === "string") literal = node.value.expression;
255
+ if (literal === void 0) return;
256
+ if (!literal.value.trim()) {
257
+ context.report({
258
+ node: literal,
259
+ messageId: "emptyIsMeaningless"
260
+ });
261
+ return;
262
+ }
263
+ const values = literal.value.trim().split(/\s+/);
264
+ for (const value of values) {
265
+ const allowed = REL_VALUES.get(value);
266
+ if (allowed === void 0) {
267
+ context.report({
268
+ node: literal,
269
+ messageId: "neverValid",
270
+ data: { value }
271
+ });
272
+ continue;
273
+ }
274
+ if (!allowed.has(tag)) context.report({
275
+ node: literal,
276
+ messageId: "notValidFor",
277
+ data: {
278
+ value,
279
+ tag
280
+ }
281
+ });
282
+ }
283
+ if (values.includes("shortcut") && !values.includes("icon")) context.report({
284
+ node: literal,
285
+ messageId: "notAlone"
286
+ });
287
+ } };
288
+ }
289
+ });
290
+ const preferReadOnlyProps = defineRule({
291
+ meta: {
292
+ type: "suggestion",
293
+ docs: { description: "Require component props type members to be readonly" },
294
+ fixable: "code",
295
+ messages: { readOnlyProp: "Prop '{{name}}' should be read-only." }
296
+ },
297
+ createOnce(context) {
298
+ const types = /* @__PURE__ */ new Map();
299
+ const jsxFns = /* @__PURE__ */ new Set();
300
+ function checkMembers(members) {
301
+ for (const member of members) {
302
+ if (member.type !== "TSPropertySignature" || member.readonly) continue;
303
+ context.report({
304
+ node: member,
305
+ messageId: "readOnlyProp",
306
+ data: { name: memberName(member) },
307
+ fix(fixer) {
308
+ return fixer.insertTextBefore(member, "readonly ");
309
+ }
310
+ });
311
+ }
312
+ }
313
+ function checkType(type, seen = /* @__PURE__ */ new Set()) {
314
+ const current = unwrapType(type);
315
+ if (isReadonlyWrapper(current)) return;
316
+ if (current.type === "TSTypeLiteral") {
317
+ checkMembers(current.members);
318
+ return;
319
+ }
320
+ if (current.type === "TSIntersectionType") {
321
+ for (const item of current.types) checkType(item, seen);
322
+ return;
323
+ }
324
+ if (current.type !== "TSTypeReference" || current.typeName.type !== "Identifier") return;
325
+ const name = current.typeName.name;
326
+ if (seen.has(name)) return;
327
+ seen.add(name);
328
+ const resolved = types.get(name);
329
+ if (resolved === void 0) return;
330
+ if (resolved.type === "TSInterfaceBody") checkMembers(resolved.body);
331
+ else checkType(resolved, seen);
332
+ }
333
+ return {
334
+ TSTypeAliasDeclaration(node) {
335
+ types.set(node.id.name, node.typeAnnotation);
336
+ },
337
+ TSInterfaceDeclaration(node) {
338
+ types.set(node.id.name, node.body);
339
+ },
340
+ JSXElement(node) {
341
+ const fn = enclosingFunction(node);
342
+ if (fn) jsxFns.add(fn);
343
+ },
344
+ JSXFragment(node) {
345
+ const fn = enclosingFunction(node);
346
+ if (fn) jsxFns.add(fn);
347
+ },
348
+ "Program:exit"() {
349
+ for (const fn of jsxFns) {
350
+ const type = paramType(fn);
351
+ if (type) checkType(type);
352
+ }
353
+ }
354
+ };
355
+ }
356
+ });
357
+ var react_default = definePlugin({
358
+ meta: { name: "eslint-plugin-mahir-react" },
359
+ rules: {
360
+ "jsx-newline": jsxNewline,
361
+ "jsx-sort-props": jsxSortProps,
362
+ "no-invalid-html-attribute": noInvalidHtmlAttribute,
363
+ "prefer-read-only-props": preferReadOnlyProps
364
+ }
365
+ });
366
+
367
+ //#endregion
368
+ export { react_default as default };
369
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react.js","names":[],"sources":["../../src/plugins/react.ts"],"sourcesContent":["import { definePlugin, defineRule } from '@oxlint/plugins';\n\nimport type { ESTree } from '@oxlint/plugins';\n\nconst REL_TAGS = new Set(['a', 'area', 'form', 'link']);\n\nconst REL_VALUES = new Map<string, Set<string>>([\n\t['alternate', new Set(['link', 'area', 'a'])],\n\t['apple-touch-icon', new Set(['link'])],\n\t['apple-touch-startup-image', new Set(['link'])],\n\t['author', new Set(['link', 'area', 'a'])],\n\t['bookmark', new Set(['area', 'a'])],\n\t['canonical', new Set(['link'])],\n\t['dns-prefetch', new Set(['link'])],\n\t['external', new Set(['area', 'a', 'form'])],\n\t['help', new Set(['link', 'area', 'a', 'form'])],\n\t['icon', new Set(['link'])],\n\t['license', new Set(['link', 'area', 'a', 'form'])],\n\t['manifest', new Set(['link'])],\n\t['mask-icon', new Set(['link'])],\n\t['modulepreload', new Set(['link'])],\n\t['next', new Set(['link', 'area', 'a', 'form'])],\n\t['nofollow', new Set(['area', 'a', 'form'])],\n\t['noopener', new Set(['area', 'a', 'form'])],\n\t['noreferrer', new Set(['area', 'a', 'form'])],\n\t['opener', new Set(['area', 'a', 'form'])],\n\t['pingback', new Set(['link'])],\n\t['preconnect', new Set(['link'])],\n\t['prefetch', new Set(['link'])],\n\t['preload', new Set(['link'])],\n\t['prerender', new Set(['link'])],\n\t['prev', new Set(['link', 'area', 'a', 'form'])],\n\t['search', new Set(['link', 'area', 'a', 'form'])],\n\t['shortcut', new Set(['link'])],\n\t['shortcut icon', new Set(['link'])],\n\t['stylesheet', new Set(['link'])],\n\t['tag', new Set(['area', 'a'])],\n]);\n\nfunction isJsxSibling(node: ESTree.JSXChild) {\n\treturn node.type === 'JSXElement' || node.type === 'JSXExpressionContainer';\n}\n\nfunction isFunction(node: ESTree.Node): node is ESTree.Function | ESTree.ArrowFunctionExpression {\n\treturn (\n\t\tnode.type === 'FunctionDeclaration' || node.type === 'FunctionExpression' || node.type === 'ArrowFunctionExpression'\n\t);\n}\n\nfunction attrName(attribute: ESTree.JSXAttribute) {\n\tif (attribute.name.type === 'JSXIdentifier') return attribute.name.name;\n\treturn `${attribute.name.namespace.name}:${attribute.name.name.name}`;\n}\n\nfunction memberName(member: ESTree.TSPropertySignature) {\n\tif (member.key.type === 'Identifier') return member.key.name;\n\tif (member.key.type === 'Literal' && typeof member.key.value === 'string') return member.key.value;\n\treturn 'unknown';\n}\n\nfunction patternType(pattern: ESTree.Node): ESTree.TSType | undefined {\n\tif (!('typeAnnotation' in pattern)) return undefined;\n\tconst annotation = pattern.typeAnnotation;\n\tif (annotation === undefined || annotation === null || typeof annotation !== 'object') return undefined;\n\tif (!('type' in annotation) || annotation.type !== 'TSTypeAnnotation') return undefined;\n\treturn annotation.typeAnnotation;\n}\n\nfunction paramType(fn: ESTree.Function | ESTree.ArrowFunctionExpression) {\n\tif (fn.params.length === 0) return undefined;\n\tconst param = fn.params[0];\n\tif (param.type === 'TSParameterProperty') return patternType(param.parameter);\n\tif (param.type === 'RestElement') return undefined;\n\tif (param.type === 'AssignmentPattern') return patternType(param.left);\n\treturn patternType(param);\n}\n\nfunction unwrapType(type: ESTree.TSType): ESTree.TSType {\n\tlet current = type;\n\twhile (current.type === 'TSParenthesizedType') current = current.typeAnnotation;\n\treturn current;\n}\n\nfunction isReadonlyWrapper(type: ESTree.TSType) {\n\treturn type.type === 'TSTypeReference' && type.typeName.type === 'Identifier' && type.typeName.name === 'Readonly';\n}\n\nfunction enclosingFunction(node: ESTree.Node) {\n\tlet current: ESTree.Node | null | undefined = node.parent;\n\twhile (current) {\n\t\tif (isFunction(current)) return current;\n\t\tcurrent = current.parent;\n\t}\n\treturn undefined;\n}\n\nconst jsxNewline = defineRule({\n\tmeta: {\n\t\ttype: 'layout',\n\t\tdocs: {\n\t\t\tdescription: 'Prevent blank lines between adjacent JSX siblings',\n\t\t},\n\t\tfixable: 'code',\n\t\tmessages: {\n\t\t\tprevent: 'JSX element should not start in a new line',\n\t\t},\n\t},\n\tcreateOnce(context) {\n\t\tfunction check(children: ESTree.JSXChild[]) {\n\t\t\tfor (let index = 0; index < children.length - 2; index++) {\n\t\t\t\tconst current = children[index];\n\t\t\t\tconst between = children[index + 1];\n\t\t\t\tconst next = children[index + 2];\n\t\t\t\tif (!isJsxSibling(current) || !isJsxSibling(next) || between.type !== 'JSXText') continue;\n\t\t\t\tif (!/\\n\\s*\\n/.test(between.value)) continue;\n\t\t\t\tcontext.report({\n\t\t\t\t\tnode: next,\n\t\t\t\t\tmessageId: 'prevent',\n\t\t\t\t\tfix(fixer) {\n\t\t\t\t\t\treturn fixer.replaceText(between, context.sourceCode.getText(between).replace(/\\n\\s*\\n/, '\\n'));\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tJSXElement(node) {\n\t\t\t\tcheck(node.children);\n\t\t\t},\n\t\t\tJSXFragment(node) {\n\t\t\t\tcheck(node.children);\n\t\t\t},\n\t\t};\n\t},\n});\n\nconst jsxSortProps = defineRule({\n\tmeta: {\n\t\ttype: 'layout',\n\t\tdocs: {\n\t\t\tdescription: 'Sort JSX props alphabetically',\n\t\t},\n\t\tfixable: 'code',\n\t\tmessages: {\n\t\t\tsortPropsByAlpha: 'Props should be sorted alphabetically',\n\t\t},\n\t},\n\tcreateOnce(context) {\n\t\treturn {\n\t\t\tJSXOpeningElement(node) {\n\t\t\t\tlet group: ESTree.JSXAttribute[] = [];\n\t\t\t\tfunction flush() {\n\t\t\t\t\tif (group.length < 2) {\n\t\t\t\t\t\tgroup = [];\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst sorted = group.toSorted((left, right) => {\n\t\t\t\t\t\tconst leftName = attrName(left);\n\t\t\t\t\t\tconst rightName = attrName(right);\n\t\t\t\t\t\tif (leftName === rightName) return 0;\n\t\t\t\t\t\treturn leftName < rightName ? -1 : 1;\n\t\t\t\t\t});\n\t\t\t\t\tif (group.every((attribute, index) => attribute === sorted[index])) {\n\t\t\t\t\t\tgroup = [];\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst texts = sorted.map((attribute) => context.sourceCode.getText(attribute));\n\t\t\t\t\tcontext.report({\n\t\t\t\t\t\tnode: group[0],\n\t\t\t\t\t\tmessageId: 'sortPropsByAlpha',\n\t\t\t\t\t\tfix(fixer) {\n\t\t\t\t\t\t\treturn group.map((attribute, index) => fixer.replaceText(attribute, texts[index] ?? ''));\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\tgroup = [];\n\t\t\t\t}\n\t\t\t\tfor (const attribute of node.attributes) {\n\t\t\t\t\tif (attribute.type === 'JSXSpreadAttribute') {\n\t\t\t\t\t\tflush();\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tgroup.push(attribute);\n\t\t\t\t}\n\t\t\t\tflush();\n\t\t\t},\n\t\t};\n\t},\n});\n\nconst noInvalidHtmlAttribute = defineRule({\n\tmeta: {\n\t\ttype: 'suggestion',\n\t\tdocs: {\n\t\t\tdescription: 'Disallow invalid HTML rel attribute values',\n\t\t},\n\t\tmessages: {\n\t\t\temptyIsMeaningless: 'An empty “rel” attribute is meaningless.',\n\t\t\tneverValid: '“{{value}}” is never a valid “rel” attribute value.',\n\t\t\tnotAlone: '“shortcut” must be directly followed by “icon”.',\n\t\t\tnotValidFor: '“{{value}}” is not a valid “rel” attribute value for <{{tag}}>.',\n\t\t\tonlyMeaningfulFor: 'The “rel” attribute only has meaning on the tags: \"<link>\", \"<a>\", \"<area>\", \"<form>\"',\n\t\t},\n\t},\n\tcreateOnce(context) {\n\t\treturn {\n\t\t\tJSXAttribute(node) {\n\t\t\t\tif (node.name.type !== 'JSXIdentifier' || node.name.name !== 'rel') return;\n\t\t\t\tif (node.parent.type !== 'JSXOpeningElement' || node.parent.name.type !== 'JSXIdentifier') return;\n\t\t\t\tconst tag = node.parent.name.name;\n\t\t\t\tif (tag !== tag.toLowerCase()) return;\n\t\t\t\tif (!REL_TAGS.has(tag)) {\n\t\t\t\t\tcontext.report({ node: node.name, messageId: 'onlyMeaningfulFor' });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (node.value === null) {\n\t\t\t\t\tcontext.report({ node: node.name, messageId: 'emptyIsMeaningless' });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet literal: ESTree.StringLiteral | undefined;\n\t\t\t\tif (node.value.type === 'Literal' && typeof node.value.value === 'string') literal = node.value;\n\t\t\t\tif (\n\t\t\t\t\tnode.value.type === 'JSXExpressionContainer' &&\n\t\t\t\t\tnode.value.expression.type === 'Literal' &&\n\t\t\t\t\ttypeof node.value.expression.value === 'string'\n\t\t\t\t) {\n\t\t\t\t\tliteral = node.value.expression;\n\t\t\t\t}\n\t\t\t\tif (literal === undefined) return;\n\t\t\t\tif (!literal.value.trim()) {\n\t\t\t\t\tcontext.report({ node: literal, messageId: 'emptyIsMeaningless' });\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst values = literal.value.trim().split(/\\s+/);\n\t\t\t\tfor (const value of values) {\n\t\t\t\t\tconst allowed = REL_VALUES.get(value);\n\t\t\t\t\tif (allowed === undefined) {\n\t\t\t\t\t\tcontext.report({ node: literal, messageId: 'neverValid', data: { value } });\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif (!allowed.has(tag)) {\n\t\t\t\t\t\tcontext.report({ node: literal, messageId: 'notValidFor', data: { value, tag } });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (values.includes('shortcut') && !values.includes('icon')) {\n\t\t\t\t\tcontext.report({ node: literal, messageId: 'notAlone' });\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n});\n\nconst preferReadOnlyProps = defineRule({\n\tmeta: {\n\t\ttype: 'suggestion',\n\t\tdocs: {\n\t\t\tdescription: 'Require component props type members to be readonly',\n\t\t},\n\t\tfixable: 'code',\n\t\tmessages: {\n\t\t\treadOnlyProp: \"Prop '{{name}}' should be read-only.\",\n\t\t},\n\t},\n\tcreateOnce(context) {\n\t\tconst types = new Map<string, ESTree.TSType | ESTree.TSInterfaceBody>();\n\t\tconst jsxFns = new Set<ESTree.Function | ESTree.ArrowFunctionExpression>();\n\t\tfunction checkMembers(members: ESTree.TSSignature[]) {\n\t\t\tfor (const member of members) {\n\t\t\t\tif (member.type !== 'TSPropertySignature' || member.readonly) continue;\n\t\t\t\tcontext.report({\n\t\t\t\t\tnode: member,\n\t\t\t\t\tmessageId: 'readOnlyProp',\n\t\t\t\t\tdata: { name: memberName(member) },\n\t\t\t\t\tfix(fixer) {\n\t\t\t\t\t\treturn fixer.insertTextBefore(member, 'readonly ');\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tfunction checkType(type: ESTree.TSType, seen = new Set<string>()) {\n\t\t\tconst current = unwrapType(type);\n\t\t\tif (isReadonlyWrapper(current)) return;\n\t\t\tif (current.type === 'TSTypeLiteral') {\n\t\t\t\tcheckMembers(current.members);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (current.type === 'TSIntersectionType') {\n\t\t\t\tfor (const item of current.types) checkType(item, seen);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (current.type !== 'TSTypeReference' || current.typeName.type !== 'Identifier') return;\n\t\t\tconst name = current.typeName.name;\n\t\t\tif (seen.has(name)) return;\n\t\t\tseen.add(name);\n\t\t\tconst resolved = types.get(name);\n\t\t\tif (resolved === undefined) return;\n\t\t\tif (resolved.type === 'TSInterfaceBody') checkMembers(resolved.body);\n\t\t\telse checkType(resolved, seen);\n\t\t}\n\t\treturn {\n\t\t\tTSTypeAliasDeclaration(node) {\n\t\t\t\ttypes.set(node.id.name, node.typeAnnotation);\n\t\t\t},\n\t\t\tTSInterfaceDeclaration(node) {\n\t\t\t\ttypes.set(node.id.name, node.body);\n\t\t\t},\n\t\t\tJSXElement(node) {\n\t\t\t\tconst fn = enclosingFunction(node);\n\t\t\t\tif (fn) jsxFns.add(fn);\n\t\t\t},\n\t\t\tJSXFragment(node) {\n\t\t\t\tconst fn = enclosingFunction(node);\n\t\t\t\tif (fn) jsxFns.add(fn);\n\t\t\t},\n\t\t\t'Program:exit'() {\n\t\t\t\tfor (const fn of jsxFns) {\n\t\t\t\t\tconst type = paramType(fn);\n\t\t\t\t\tif (type) checkType(type);\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t},\n});\n\nexport default definePlugin({\n\tmeta: {\n\t\tname: 'eslint-plugin-mahir-react',\n\t},\n\trules: {\n\t\t'jsx-newline': jsxNewline,\n\t\t'jsx-sort-props': jsxSortProps,\n\t\t'no-invalid-html-attribute': noInvalidHtmlAttribute,\n\t\t'prefer-read-only-props': preferReadOnlyProps,\n\t},\n});\n"],"mappings":"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"}
package/dist/react.d.ts CHANGED
@@ -1,10 +1,5 @@
1
1
  //#region src/react.d.ts
2
2
  declare const config: {
3
- extends: {
4
- plugins: ("eslint" | "react" | "unicorn" | "typescript" | "oxc" | "import" | "jsdoc" | "jest" | "vitest" | "jsx-a11y" | "nextjs" | "react-perf" | "promise" | "node" | "vue")[];
5
- jsPlugins: import("oxlint").ExternalPluginEntry[];
6
- rules: import("oxlint").DummyRuleMap;
7
- }[];
8
3
  plugins: ("eslint" | "react" | "unicorn" | "typescript" | "oxc" | "import" | "jsdoc" | "jest" | "vitest" | "jsx-a11y" | "nextjs" | "react-perf" | "promise" | "node" | "vue")[];
9
4
  jsPlugins: import("oxlint").ExternalPluginEntry[];
10
5
  env: {
package/dist/react.js CHANGED
@@ -1,12 +1,10 @@
1
- import { nativePlugins, packagePlugin } from "./config.js";
2
- import config$1 from "./jsx.js";
1
+ import { localPlugin, nativePlugins } from "./config.js";
3
2
  import { defineConfig } from "oxlint";
4
3
 
5
4
  //#region src/react.ts
6
5
  const config = defineConfig({
7
- extends: [config$1],
8
6
  plugins: nativePlugins,
9
- jsPlugins: [packagePlugin("react-js", "eslint-plugin-react")],
7
+ jsPlugins: [localPlugin("mahir-react", "./plugins/react.js")],
10
8
  env: {
11
9
  browser: true,
12
10
  serviceworker: true
@@ -19,43 +17,59 @@ const config = defineConfig({
19
17
  "react/purity": 2,
20
18
  "react/refs": 2,
21
19
  "react/set-state-in-render": 2,
22
- "react-js/boolean-prop-naming": 2,
23
20
  "react/button-has-type": 2,
24
21
  "react/hook-use-state": 2,
25
22
  "react/iframe-missing-sandbox": 2,
26
- "react-js/no-access-state-in-setstate": 2,
27
- "react-js/no-arrow-function-lifecycle": 2,
23
+ "react/jsx-boolean-value": [2, "never"],
24
+ "react/jsx-curly-brace-presence": [2, {
25
+ children: "never",
26
+ props: "never"
27
+ }],
28
+ "react/jsx-fragments": [2, "syntax"],
29
+ "react/jsx-key": [2, {
30
+ checkFragmentShorthand: true,
31
+ checkKeyMustBeforeSpread: true,
32
+ warnOnDuplicates: false
33
+ }],
34
+ "react/jsx-no-comment-textnodes": 2,
35
+ "react/jsx-no-constructed-context-values": 2,
36
+ "react/jsx-no-duplicate-props": 2,
37
+ "react/jsx-no-script-url": 2,
38
+ "react/jsx-no-undef": 2,
39
+ "react/jsx-no-useless-fragment": [2, { allowExpressions: true }],
40
+ "react/jsx-pascal-case": [2, { ignore: [
41
+ "h{}",
42
+ "h2",
43
+ "h3",
44
+ "h4",
45
+ "h5",
46
+ "h6",
47
+ "p",
48
+ "a",
49
+ "ul",
50
+ "ol",
51
+ "li",
52
+ "img",
53
+ "div",
54
+ "span",
55
+ "dl",
56
+ "dt",
57
+ "dd"
58
+ ] }],
28
59
  "react/no-children-prop": 2,
29
60
  "react/no-danger": 2,
30
61
  "react/no-danger-with-children": 2,
31
- "react-js/no-deprecated": 2,
32
- "react/no-did-mount-set-state": 2,
33
- "react/no-did-update-set-state": 2,
34
- "react/no-direct-mutation-state": 2,
35
62
  "react/no-find-dom-node": 2,
36
- "react-js/no-invalid-html-attribute": 2,
37
- "react/no-is-mounted": 2,
38
63
  "react/no-namespace": 2,
39
- "react/no-redundant-should-component-update": 2,
40
64
  "react/no-render-return-value": 2,
41
- "react/no-set-state": 2,
42
- "react/no-string-refs": 2,
43
- "react/no-this-in-sfc": 2,
44
- "react-js/no-typos": 2,
45
65
  "react/no-unknown-property": 2,
46
- "react/no-unsafe": 2,
47
66
  "react/no-unstable-nested-components": 2,
48
- "react-js/no-unused-class-component-methods": 2,
49
- "react-js/no-unused-state": 2,
50
- "react/no-will-update-set-state": 2,
51
- "react/prefer-es6-class": 2,
52
- "react-js/prefer-read-only-props": 2,
53
- "react-js/prefer-stateless-function": [2, { ignorePureComponents: true }],
54
- "react/require-render-return": 2,
55
- "react-js/sort-comp": 2,
56
- "react/state-in-constructor": [2, "always"],
57
- "react-js/static-property-placement": 2,
58
- "react/void-dom-elements-no-children": 2
67
+ "react/void-dom-elements-no-children": 2,
68
+ "mahir-react/jsx-newline": 2,
69
+ "mahir-react/jsx-sort-props": 2,
70
+ "mahir-react/no-invalid-html-attribute": 2,
71
+ "mahir-react/prefer-read-only-props": 2,
72
+ "unicorn/consistent-function-scoping": 0
59
73
  }
60
74
  });
61
75
 
package/dist/react.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"react.js","names":["jsx"],"sources":["../src/react.ts"],"sourcesContent":["import { defineConfig } from 'oxlint';\n\nimport { nativePlugins, packagePlugin } from './config.js';\nimport jsx from './jsx.js';\n\nimport type { OxlintConfig } from 'oxlint';\n\nconst rules: NonNullable<OxlintConfig['rules']> = {\n\t'react/exhaustive-deps': 2,\n\t'react/rules-of-hooks': 2,\n\t'react/immutability': 2,\n\t'react/purity': 2,\n\t'react/refs': 2,\n\t'react/set-state-in-render': 2,\n\t'react-js/boolean-prop-naming': 2,\n\t'react/button-has-type': 2,\n\t'react/hook-use-state': 2,\n\t'react/iframe-missing-sandbox': 2,\n\t'react-js/no-access-state-in-setstate': 2,\n\t'react-js/no-arrow-function-lifecycle': 2,\n\t'react/no-children-prop': 2,\n\t'react/no-danger': 2,\n\t'react/no-danger-with-children': 2,\n\t'react-js/no-deprecated': 2,\n\t'react/no-did-mount-set-state': 2,\n\t'react/no-did-update-set-state': 2,\n\t'react/no-direct-mutation-state': 2,\n\t'react/no-find-dom-node': 2,\n\t'react-js/no-invalid-html-attribute': 2,\n\t'react/no-is-mounted': 2,\n\t'react/no-namespace': 2,\n\t'react/no-redundant-should-component-update': 2,\n\t'react/no-render-return-value': 2,\n\t'react/no-set-state': 2,\n\t'react/no-string-refs': 2,\n\t'react/no-this-in-sfc': 2,\n\t'react-js/no-typos': 2,\n\t'react/no-unknown-property': 2,\n\t'react/no-unsafe': 2,\n\t'react/no-unstable-nested-components': 2,\n\t'react-js/no-unused-class-component-methods': 2,\n\t'react-js/no-unused-state': 2,\n\t'react/no-will-update-set-state': 2,\n\t'react/prefer-es6-class': 2,\n\t'react-js/prefer-read-only-props': 2,\n\t'react-js/prefer-stateless-function': [\n\t\t2,\n\t\t{\n\t\t\tignorePureComponents: true,\n\t\t},\n\t],\n\t'react/require-render-return': 2,\n\t'react-js/sort-comp': 2,\n\t'react/state-in-constructor': [2, 'always'],\n\t'react-js/static-property-placement': 2,\n\t'react/void-dom-elements-no-children': 2,\n};\n\nconst config = defineConfig({\n\textends: [jsx],\n\tplugins: nativePlugins,\n\tjsPlugins: [packagePlugin('react-js', 'eslint-plugin-react')],\n\tenv: {\n\t\tbrowser: true,\n\t\tserviceworker: true,\n\t},\n\tsettings: {\n\t\treact: {\n\t\t\tversion: '19.0.0',\n\t\t},\n\t},\n\trules,\n});\n\nexport default config;\n"],"mappings":";;;;;AA0DA,MAAM,SAAS,aAAa;CAC3B,SAAS,CAACA,QAAG;CACb,SAAS;CACT,WAAW,CAAC,cAAc,YAAY,qBAAqB,CAAC;CAC5D,KAAK;EACJ,SAAS;EACT,eAAe;CAChB;CACA,UAAU,EACT,OAAO,EACN,SAAS,SACV,EACD;CACA;EA/DA,yBAAyB;EACzB,wBAAwB;EACxB,sBAAsB;EACtB,gBAAgB;EAChB,cAAc;EACd,6BAA6B;EAC7B,gCAAgC;EAChC,yBAAyB;EACzB,wBAAwB;EACxB,gCAAgC;EAChC,wCAAwC;EACxC,wCAAwC;EACxC,0BAA0B;EAC1B,mBAAmB;EACnB,iCAAiC;EACjC,0BAA0B;EAC1B,gCAAgC;EAChC,iCAAiC;EACjC,kCAAkC;EAClC,0BAA0B;EAC1B,sCAAsC;EACtC,uBAAuB;EACvB,sBAAsB;EACtB,8CAA8C;EAC9C,gCAAgC;EAChC,sBAAsB;EACtB,wBAAwB;EACxB,wBAAwB;EACxB,qBAAqB;EACrB,6BAA6B;EAC7B,mBAAmB;EACnB,uCAAuC;EACvC,8CAA8C;EAC9C,4BAA4B;EAC5B,kCAAkC;EAClC,0BAA0B;EAC1B,mCAAmC;EACnC,sCAAsC,CACrC,GACA,EACC,sBAAsB,KACvB,CACD;EACA,+BAA+B;EAC/B,sBAAsB;EACtB,8BAA8B,CAAC,GAAG,QAAQ;EAC1C,sCAAsC;EACtC,uCAAuC;CAgBnC;AACL,CAAC"}
1
+ {"version":3,"file":"react.js","names":[],"sources":["../src/react.ts"],"sourcesContent":["import { defineConfig } from 'oxlint';\n\nimport { localPlugin, nativePlugins } from './config.js';\n\nimport type { OxlintConfig } from 'oxlint';\n\nconst rules: NonNullable<OxlintConfig['rules']> = {\n\t'react/exhaustive-deps': 2,\n\t'react/rules-of-hooks': 2,\n\t'react/immutability': 2,\n\t'react/purity': 2,\n\t'react/refs': 2,\n\t'react/set-state-in-render': 2,\n\t'react/button-has-type': 2,\n\t'react/hook-use-state': 2,\n\t'react/iframe-missing-sandbox': 2,\n\t'react/jsx-boolean-value': [2, 'never'],\n\t'react/jsx-curly-brace-presence': [\n\t\t2,\n\t\t{\n\t\t\tchildren: 'never',\n\t\t\tprops: 'never',\n\t\t},\n\t],\n\t'react/jsx-fragments': [2, 'syntax'],\n\t'react/jsx-key': [\n\t\t2,\n\t\t{\n\t\t\tcheckFragmentShorthand: true,\n\t\t\tcheckKeyMustBeforeSpread: true,\n\t\t\twarnOnDuplicates: false,\n\t\t},\n\t],\n\t'react/jsx-no-comment-textnodes': 2,\n\t'react/jsx-no-constructed-context-values': 2,\n\t'react/jsx-no-duplicate-props': 2,\n\t'react/jsx-no-script-url': 2,\n\t'react/jsx-no-undef': 2,\n\t'react/jsx-no-useless-fragment': [\n\t\t2,\n\t\t{\n\t\t\tallowExpressions: true,\n\t\t},\n\t],\n\t'react/jsx-pascal-case': [\n\t\t2,\n\t\t{\n\t\t\tignore: ['h{}', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'a', 'ul', 'ol', 'li', 'img', 'div', 'span', 'dl', 'dt', 'dd'],\n\t\t},\n\t],\n\t'react/no-children-prop': 2,\n\t'react/no-danger': 2,\n\t'react/no-danger-with-children': 2,\n\t'react/no-find-dom-node': 2,\n\t'react/no-namespace': 2,\n\t'react/no-render-return-value': 2,\n\t'react/no-unknown-property': 2,\n\t'react/no-unstable-nested-components': 2,\n\t'react/void-dom-elements-no-children': 2,\n\t'mahir-react/jsx-newline': 2,\n\t'mahir-react/jsx-sort-props': 2,\n\t'mahir-react/no-invalid-html-attribute': 2,\n\t'mahir-react/prefer-read-only-props': 2,\n\t'unicorn/consistent-function-scoping': 0,\n};\n\nconst config = defineConfig({\n\tplugins: nativePlugins,\n\tjsPlugins: [localPlugin('mahir-react', './plugins/react.js')],\n\tenv: {\n\t\tbrowser: true,\n\t\tserviceworker: true,\n\t},\n\tsettings: {\n\t\treact: {\n\t\t\tversion: '19.0.0',\n\t\t},\n\t},\n\trules,\n});\n\nexport default config;\n"],"mappings":";;;;AAkEA,MAAM,SAAS,aAAa;CAC3B,SAAS;CACT,WAAW,CAAC,YAAY,eAAe,oBAAoB,CAAC;CAC5D,KAAK;EACJ,SAAS;EACT,eAAe;CAChB;CACA,UAAU,EACT,OAAO,EACN,SAAS,SACV,EACD;CACA;EAvEA,yBAAyB;EACzB,wBAAwB;EACxB,sBAAsB;EACtB,gBAAgB;EAChB,cAAc;EACd,6BAA6B;EAC7B,yBAAyB;EACzB,wBAAwB;EACxB,gCAAgC;EAChC,2BAA2B,CAAC,GAAG,OAAO;EACtC,kCAAkC,CACjC,GACA;GACC,UAAU;GACV,OAAO;EACR,CACD;EACA,uBAAuB,CAAC,GAAG,QAAQ;EACnC,iBAAiB,CAChB,GACA;GACC,wBAAwB;GACxB,0BAA0B;GAC1B,kBAAkB;EACnB,CACD;EACA,kCAAkC;EAClC,2CAA2C;EAC3C,gCAAgC;EAChC,2BAA2B;EAC3B,sBAAsB;EACtB,iCAAiC,CAChC,GACA,EACC,kBAAkB,KACnB,CACD;EACA,yBAAyB,CACxB,GACA,EACC,QAAQ;GAAC;GAAO;GAAM;GAAM;GAAM;GAAM;GAAM;GAAK;GAAK;GAAM;GAAM;GAAM;GAAO;GAAO;GAAQ;GAAM;GAAM;EAAI,EACjH,CACD;EACA,0BAA0B;EAC1B,mBAAmB;EACnB,iCAAiC;EACjC,0BAA0B;EAC1B,sBAAsB;EACtB,gCAAgC;EAChC,6BAA6B;EAC7B,uCAAuC;EACvC,uCAAuC;EACvC,2BAA2B;EAC3B,8BAA8B;EAC9B,yCAAyC;EACzC,sCAAsC;EACtC,uCAAuC;CAenC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imranbarbhuiya/oxc-config",
3
- "version": "0.1.13",
3
+ "version": "0.2.0",
4
4
  "description": "Shared Oxlint and Oxfmt configs for JavaScript and TypeScript projects",
5
5
  "keywords": [
6
6
  "config",
@@ -50,9 +50,6 @@
50
50
  "jsdoc": [
51
51
  "./dist/jsdoc.d.ts"
52
52
  ],
53
- "jsx": [
54
- "./dist/jsx.d.ts"
55
- ],
56
53
  "module": [
57
54
  "./dist/module.d.ts"
58
55
  ],
@@ -119,11 +116,6 @@
119
116
  "import": "./dist/jsdoc.js",
120
117
  "default": "./dist/jsdoc.js"
121
118
  },
122
- "./jsx": {
123
- "types": "./dist/jsx.d.ts",
124
- "import": "./dist/jsx.js",
125
- "default": "./dist/jsx.js"
126
- },
127
119
  "./module": {
128
120
  "types": "./dist/module.d.ts",
129
121
  "import": "./dist/module.js",
@@ -198,7 +190,6 @@
198
190
  "eslint": "^10.9.1",
199
191
  "eslint-plugin-jsdoc": "^64.2.1",
200
192
  "eslint-plugin-n": "^18.3.0",
201
- "eslint-plugin-react": "^7.37.5",
202
193
  "eslint-plugin-sonarjs": "^4.2.0",
203
194
  "eslint-plugin-tsdoc": "^0.5.2",
204
195
  "nypm": "^0.6.9",
package/dist/jsx.d.ts DELETED
@@ -1,9 +0,0 @@
1
- //#region src/jsx.d.ts
2
- declare const config: {
3
- plugins: ("eslint" | "react" | "unicorn" | "typescript" | "oxc" | "import" | "jsdoc" | "jest" | "vitest" | "jsx-a11y" | "nextjs" | "react-perf" | "promise" | "node" | "vue")[];
4
- jsPlugins: import("oxlint").ExternalPluginEntry[];
5
- rules: import("oxlint").DummyRuleMap;
6
- };
7
- //#endregion
8
- export { config as default };
9
- //# sourceMappingURL=jsx.d.ts.map
package/dist/jsx.js DELETED
@@ -1,76 +0,0 @@
1
- import { nativePlugins, packagePlugin } from "./config.js";
2
- import { defineConfig } from "oxlint";
3
-
4
- //#region src/jsx.ts
5
- const config = defineConfig({
6
- plugins: nativePlugins,
7
- jsPlugins: [packagePlugin("react-js", "eslint-plugin-react")],
8
- rules: {
9
- "react/jsx-boolean-value": 0,
10
- "react-js/jsx-boolean-value": [2, "never"],
11
- "react-js/jsx-closing-bracket-location": [2, "line-aligned"],
12
- "react-js/jsx-closing-tag-location": 2,
13
- "react/jsx-curly-brace-presence": 0,
14
- "react-js/jsx-curly-brace-presence": [2, {
15
- children: "never",
16
- props: "never"
17
- }],
18
- "react-js/jsx-equals-spacing": [2, "never"],
19
- "react-js/jsx-first-prop-new-line": [2, "multiline-multiprop"],
20
- "react/jsx-fragments": [2, "syntax"],
21
- "react/jsx-key": [2, {
22
- checkFragmentShorthand: true,
23
- checkKeyMustBeforeSpread: true,
24
- warnOnDuplicates: false
25
- }],
26
- "react-js/jsx-max-props-per-line": [2, {
27
- maximum: 3,
28
- when: "multiline"
29
- }],
30
- "react-js/jsx-newline": [2, { prevent: true }],
31
- "react-js/jsx-no-bind": [2, {
32
- allowArrowFunctions: true,
33
- allowBind: false,
34
- ignoreRefs: true
35
- }],
36
- "react/jsx-no-comment-textnodes": 2,
37
- "react/jsx-no-constructed-context-values": 2,
38
- "react/jsx-no-duplicate-props": 2,
39
- "react/jsx-no-script-url": 2,
40
- "react/jsx-no-undef": 2,
41
- "react/jsx-no-useless-fragment": [2, { allowExpressions: true }],
42
- "react/jsx-pascal-case": [2, { ignore: [
43
- "h{}",
44
- "h2",
45
- "h3",
46
- "h4",
47
- "h5",
48
- "h6",
49
- "p",
50
- "a",
51
- "ul",
52
- "ol",
53
- "li",
54
- "img",
55
- "div",
56
- "span",
57
- "dl",
58
- "dt",
59
- "dd"
60
- ] }],
61
- "react-js/jsx-sort-props": 2,
62
- "react-js/jsx-tag-spacing": [2, {
63
- afterOpening: "never",
64
- beforeSelfClosing: "always",
65
- closingSlash: "never"
66
- }],
67
- "react-js/jsx-uses-react": 2,
68
- "react-js/jsx-uses-vars": 2,
69
- "react-js/sort-default-props": 2,
70
- "unicorn/consistent-function-scoping": 0
71
- }
72
- });
73
-
74
- //#endregion
75
- export { config as default };
76
- //# sourceMappingURL=jsx.js.map
package/dist/jsx.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"jsx.js","names":[],"sources":["../src/jsx.ts"],"sourcesContent":["import { defineConfig } from 'oxlint';\n\nimport { nativePlugins, packagePlugin } from './config.js';\n\nimport type { OxlintConfig } from 'oxlint';\n\nconst rules: NonNullable<OxlintConfig['rules']> = {\n\t'react/jsx-boolean-value': 0,\n\t'react-js/jsx-boolean-value': [2, 'never'],\n\t'react-js/jsx-closing-bracket-location': [2, 'line-aligned'],\n\t'react-js/jsx-closing-tag-location': 2,\n\t'react/jsx-curly-brace-presence': 0,\n\t'react-js/jsx-curly-brace-presence': [\n\t\t2,\n\t\t{\n\t\t\tchildren: 'never',\n\t\t\tprops: 'never',\n\t\t},\n\t],\n\t'react-js/jsx-equals-spacing': [2, 'never'],\n\t'react-js/jsx-first-prop-new-line': [2, 'multiline-multiprop'],\n\t'react/jsx-fragments': [2, 'syntax'],\n\t'react/jsx-key': [\n\t\t2,\n\t\t{\n\t\t\tcheckFragmentShorthand: true,\n\t\t\tcheckKeyMustBeforeSpread: true,\n\t\t\twarnOnDuplicates: false,\n\t\t},\n\t],\n\t'react-js/jsx-max-props-per-line': [\n\t\t2,\n\t\t{\n\t\t\tmaximum: 3,\n\t\t\twhen: 'multiline',\n\t\t},\n\t],\n\t'react-js/jsx-newline': [\n\t\t2,\n\t\t{\n\t\t\tprevent: true,\n\t\t},\n\t],\n\t'react-js/jsx-no-bind': [\n\t\t2,\n\t\t{\n\t\t\tallowArrowFunctions: true,\n\t\t\tallowBind: false,\n\t\t\tignoreRefs: true,\n\t\t},\n\t],\n\t'react/jsx-no-comment-textnodes': 2,\n\t'react/jsx-no-constructed-context-values': 2,\n\t'react/jsx-no-duplicate-props': 2,\n\t'react/jsx-no-script-url': 2,\n\t'react/jsx-no-undef': 2,\n\t'react/jsx-no-useless-fragment': [\n\t\t2,\n\t\t{\n\t\t\tallowExpressions: true,\n\t\t},\n\t],\n\t'react/jsx-pascal-case': [\n\t\t2,\n\t\t{\n\t\t\tignore: ['h{}', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'a', 'ul', 'ol', 'li', 'img', 'div', 'span', 'dl', 'dt', 'dd'],\n\t\t},\n\t],\n\t'react-js/jsx-sort-props': 2,\n\t'react-js/jsx-tag-spacing': [\n\t\t2,\n\t\t{\n\t\t\tafterOpening: 'never',\n\t\t\tbeforeSelfClosing: 'always',\n\t\t\tclosingSlash: 'never',\n\t\t},\n\t],\n\t'react-js/jsx-uses-react': 2,\n\t'react-js/jsx-uses-vars': 2,\n\t'react-js/sort-default-props': 2,\n\t'unicorn/consistent-function-scoping': 0,\n};\n\nconst config = defineConfig({\n\tplugins: nativePlugins,\n\tjsPlugins: [packagePlugin('react-js', 'eslint-plugin-react')],\n\trules,\n});\n\nexport default config;\n"],"mappings":";;;;AAmFA,MAAM,SAAS,aAAa;CAC3B,SAAS;CACT,WAAW,CAAC,cAAc,YAAY,qBAAqB,CAAC;CAC5D;EA/EA,2BAA2B;EAC3B,8BAA8B,CAAC,GAAG,OAAO;EACzC,yCAAyC,CAAC,GAAG,cAAc;EAC3D,qCAAqC;EACrC,kCAAkC;EAClC,qCAAqC,CACpC,GACA;GACC,UAAU;GACV,OAAO;EACR,CACD;EACA,+BAA+B,CAAC,GAAG,OAAO;EAC1C,oCAAoC,CAAC,GAAG,qBAAqB;EAC7D,uBAAuB,CAAC,GAAG,QAAQ;EACnC,iBAAiB,CAChB,GACA;GACC,wBAAwB;GACxB,0BAA0B;GAC1B,kBAAkB;EACnB,CACD;EACA,mCAAmC,CAClC,GACA;GACC,SAAS;GACT,MAAM;EACP,CACD;EACA,wBAAwB,CACvB,GACA,EACC,SAAS,KACV,CACD;EACA,wBAAwB,CACvB,GACA;GACC,qBAAqB;GACrB,WAAW;GACX,YAAY;EACb,CACD;EACA,kCAAkC;EAClC,2CAA2C;EAC3C,gCAAgC;EAChC,2BAA2B;EAC3B,sBAAsB;EACtB,iCAAiC,CAChC,GACA,EACC,kBAAkB,KACnB,CACD;EACA,yBAAyB,CACxB,GACA,EACC,QAAQ;GAAC;GAAO;GAAM;GAAM;GAAM;GAAM;GAAM;GAAK;GAAK;GAAM;GAAM;GAAM;GAAO;GAAO;GAAQ;GAAM;GAAM;EAAI,EACjH,CACD;EACA,2BAA2B;EAC3B,4BAA4B,CAC3B,GACA;GACC,cAAc;GACd,mBAAmB;GACnB,cAAc;EACf,CACD;EACA,2BAA2B;EAC3B,0BAA0B;EAC1B,+BAA+B;EAC/B,uCAAuC;CAMnC;AACL,CAAC"}