oxlint-plugin-react-native 0.0.1 → 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 +3 -1
- package/dist/index.js +14 -14
- package/dist/rules/no-color-literals.js +6 -6
- package/dist/rules/no-inline-styles.js +6 -6
- package/dist/rules/no-raw-text.js +24 -24
- package/dist/rules/no-single-element-style-arrays.js +7 -7
- package/dist/rules/no-unused-styles.js +48 -7
- package/dist/rules/sort-styles.js +17 -17
- package/dist/util/Components.js +16 -16
- package/dist/util/stylesheet.js +99 -57
- package/package.json +18 -6
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Lint rules for [React Native](https://reactnative.dev/) projects, built for [Oxlint](https://github.com/oxc-project/oxc).
|
|
4
4
|
|
|
5
|
+
Rules are based on [eslint-plugin-react-native](https://github.com/Intellicode/eslint-plugin-react-native) by Intellicode, ported to Oxlint. This plugin may evolve with new rules, improvements, or updates over time.
|
|
6
|
+
|
|
5
7
|
---
|
|
6
8
|
|
|
7
9
|
## Installation
|
|
@@ -50,7 +52,7 @@ In your Oxlint config (e.g. `.oxlintrc.json`), register the plugin by **name** a
|
|
|
50
52
|
| [no-inline-styles](docs/no-inline-styles.md) | Disallow inline style objects; prefer `StyleSheet.create` | — |
|
|
51
53
|
| [no-raw-text](docs/no-raw-text.md) | Require text inside `<Text>` (or allowed components) | — |
|
|
52
54
|
| [no-single-element-style-arrays](docs/no-single-element-style-arrays.md) | Disallow single-element style arrays (`style={[x]}`) | ✅ |
|
|
53
|
-
| [no-unused-styles](docs/no-unused-styles.md) | Report unused styles from `StyleSheet.create` |
|
|
55
|
+
| [no-unused-styles](docs/no-unused-styles.md) | Report unused styles from `StyleSheet.create` | ✅ |
|
|
54
56
|
| [sort-styles](docs/sort-styles.md) | Enforce order of class names and style properties | ✅ |
|
|
55
57
|
|
|
56
58
|
Each rule is documented in the [docs](docs/) folder with examples and options.
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { eslintCompatPlugin } from
|
|
2
|
-
import noUnusedStyles from
|
|
3
|
-
import noInlineStyles from
|
|
4
|
-
import noColorLiterals from
|
|
5
|
-
import sortStyles from
|
|
6
|
-
import noRawText from
|
|
7
|
-
import noSingleElementStyleArrays from
|
|
1
|
+
import { eslintCompatPlugin } from "@oxlint/plugins";
|
|
2
|
+
import noUnusedStyles from "./rules/no-unused-styles.js";
|
|
3
|
+
import noInlineStyles from "./rules/no-inline-styles.js";
|
|
4
|
+
import noColorLiterals from "./rules/no-color-literals.js";
|
|
5
|
+
import sortStyles from "./rules/sort-styles.js";
|
|
6
|
+
import noRawText from "./rules/no-raw-text.js";
|
|
7
|
+
import noSingleElementStyleArrays from "./rules/no-single-element-style-arrays.js";
|
|
8
8
|
const allRules = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
"no-unused-styles": noUnusedStyles,
|
|
10
|
+
"no-inline-styles": noInlineStyles,
|
|
11
|
+
"no-color-literals": noColorLiterals,
|
|
12
|
+
"sort-styles": sortStyles,
|
|
13
|
+
"no-raw-text": noRawText,
|
|
14
|
+
"no-single-element-style-arrays": noSingleElementStyleArrays,
|
|
15
15
|
};
|
|
16
16
|
export default eslintCompatPlugin({
|
|
17
|
-
meta: { name:
|
|
17
|
+
meta: { name: "oxlint-plugin-react-native" },
|
|
18
18
|
rules: allRules,
|
|
19
19
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { detect } from
|
|
2
|
-
import { StyleSheets, astHelpers } from
|
|
3
|
-
import * as util from
|
|
1
|
+
import { detect } from "../util/Components.js";
|
|
2
|
+
import { StyleSheets, astHelpers } from "../util/stylesheet.js";
|
|
3
|
+
import * as util from "util";
|
|
4
4
|
const rule = detect((context) => {
|
|
5
5
|
let styleSheets;
|
|
6
6
|
return {
|
|
@@ -24,7 +24,7 @@ const rule = detect((context) => {
|
|
|
24
24
|
styleSheets.addColorLiterals(literals);
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
|
-
|
|
27
|
+
"Program:exit": () => {
|
|
28
28
|
const colorLiterals = styleSheets.getColorLiterals();
|
|
29
29
|
if (colorLiterals) {
|
|
30
30
|
colorLiterals.forEach((style) => {
|
|
@@ -32,7 +32,7 @@ const rule = detect((context) => {
|
|
|
32
32
|
const expression = util.inspect(style.expression);
|
|
33
33
|
context.report({
|
|
34
34
|
node: style.node,
|
|
35
|
-
message:
|
|
35
|
+
message: "Color literal: {{expression}}",
|
|
36
36
|
data: { expression },
|
|
37
37
|
});
|
|
38
38
|
}
|
|
@@ -45,5 +45,5 @@ export default {
|
|
|
45
45
|
meta: {
|
|
46
46
|
schema: [],
|
|
47
47
|
},
|
|
48
|
-
createOnce: rule
|
|
48
|
+
createOnce: rule,
|
|
49
49
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { detect } from
|
|
2
|
-
import { StyleSheets, astHelpers } from
|
|
3
|
-
import * as util from
|
|
1
|
+
import { detect } from "../util/Components.js";
|
|
2
|
+
import { StyleSheets, astHelpers } from "../util/stylesheet.js";
|
|
3
|
+
import * as util from "util";
|
|
4
4
|
const rule = detect((context) => {
|
|
5
5
|
// Setup state per-file (createOnce)
|
|
6
6
|
let styleSheets;
|
|
@@ -14,7 +14,7 @@ const rule = detect((context) => {
|
|
|
14
14
|
styleSheets.addObjectExpressions(styles);
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
|
-
|
|
17
|
+
"Program:exit": () => {
|
|
18
18
|
const inlineStyles = styleSheets.getObjectExpressions();
|
|
19
19
|
if (inlineStyles) {
|
|
20
20
|
inlineStyles.forEach((style) => {
|
|
@@ -22,7 +22,7 @@ const rule = detect((context) => {
|
|
|
22
22
|
const expression = util.inspect(style.expression);
|
|
23
23
|
context.report({
|
|
24
24
|
node: style.node,
|
|
25
|
-
message:
|
|
25
|
+
message: "Inline style: {{expression}}",
|
|
26
26
|
data: { expression },
|
|
27
27
|
});
|
|
28
28
|
}
|
|
@@ -35,5 +35,5 @@ export default {
|
|
|
35
35
|
meta: {
|
|
36
36
|
schema: [],
|
|
37
37
|
},
|
|
38
|
-
createOnce: rule
|
|
38
|
+
createOnce: rule,
|
|
39
39
|
};
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
const elementName = (node) => {
|
|
2
2
|
const reversedIdentifiers = [];
|
|
3
|
-
if (node.type ===
|
|
4
|
-
node.openingElement.type ===
|
|
3
|
+
if (node.type === "JSXElement" &&
|
|
4
|
+
node.openingElement.type === "JSXOpeningElement") {
|
|
5
5
|
let object = node.openingElement.name;
|
|
6
|
-
while (object.type ===
|
|
7
|
-
if (object.property.type ===
|
|
6
|
+
while (object.type === "JSXMemberExpression") {
|
|
7
|
+
if (object.property.type === "JSXIdentifier") {
|
|
8
8
|
reversedIdentifiers.push(object.property.name);
|
|
9
9
|
}
|
|
10
10
|
object = object.object;
|
|
11
11
|
}
|
|
12
|
-
if (object.type ===
|
|
12
|
+
if (object.type === "JSXIdentifier") {
|
|
13
13
|
reversedIdentifiers.push(object.name);
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
return reversedIdentifiers.reverse().join(
|
|
16
|
+
return reversedIdentifiers.reverse().join(".");
|
|
17
17
|
};
|
|
18
18
|
const hasAllowedParent = (parent, allowedElements) => {
|
|
19
19
|
let curNode = parent;
|
|
20
20
|
while (curNode) {
|
|
21
|
-
if (curNode.type ===
|
|
21
|
+
if (curNode.type === "JSXElement") {
|
|
22
22
|
const name = elementName(curNode);
|
|
23
23
|
if (allowedElements.includes(name)) {
|
|
24
24
|
return true;
|
|
@@ -36,50 +36,50 @@ const rule = (context) => {
|
|
|
36
36
|
const options = context.options[0] || {};
|
|
37
37
|
const skippedElements = options.skip ? options.skip : [];
|
|
38
38
|
_allowedElements = [
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
"Text",
|
|
40
|
+
"TSpan",
|
|
41
|
+
"StyledText",
|
|
42
|
+
"Animated.Text",
|
|
43
43
|
].concat(skippedElements);
|
|
44
44
|
}
|
|
45
45
|
return _allowedElements;
|
|
46
46
|
}
|
|
47
47
|
const report = (node) => {
|
|
48
|
-
const errorValue = node.type ===
|
|
48
|
+
const errorValue = node.type === "TemplateLiteral"
|
|
49
49
|
? `TemplateLiteral: ${node.expressions[0].name}`
|
|
50
50
|
: node.value.trim();
|
|
51
|
-
const formattedErrorValue = errorValue.length > 0 ? `Raw text (${errorValue})` :
|
|
51
|
+
const formattedErrorValue = errorValue.length > 0 ? `Raw text (${errorValue})` : "Whitespace(s)";
|
|
52
52
|
context.report({
|
|
53
53
|
node,
|
|
54
54
|
message: `${formattedErrorValue} cannot be used outside of a <Text> tag`,
|
|
55
55
|
});
|
|
56
56
|
};
|
|
57
|
-
const hasOnlyLineBreak = (value) => /^[\r\n\t\f\v]+$/.test(value.replace(/ /g,
|
|
57
|
+
const hasOnlyLineBreak = (value) => /^[\r\n\t\f\v]+$/.test(value.replace(/ /g, ""));
|
|
58
58
|
const getValidation = (node) => !hasAllowedParent(node.parent, getAllowedElements());
|
|
59
59
|
return {
|
|
60
60
|
Literal(node) {
|
|
61
61
|
const parentType = node.parent.type;
|
|
62
|
-
const onlyFor = [
|
|
63
|
-
if (typeof node.value !==
|
|
62
|
+
const onlyFor = ["JSXExpressionContainer", "JSXElement"];
|
|
63
|
+
if (typeof node.value !== "string" ||
|
|
64
64
|
hasOnlyLineBreak(node.value) ||
|
|
65
65
|
!onlyFor.includes(parentType) ||
|
|
66
|
-
(node.parent.parent && node.parent.parent.type ===
|
|
66
|
+
(node.parent.parent && node.parent.parent.type === "JSXAttribute"))
|
|
67
67
|
return;
|
|
68
|
-
const isStringLiteral = parentType ===
|
|
68
|
+
const isStringLiteral = parentType === "JSXExpressionContainer";
|
|
69
69
|
if (getValidation(isStringLiteral ? node.parent : node)) {
|
|
70
70
|
report(node);
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
73
|
JSXText(node) {
|
|
74
|
-
if (typeof node.value !==
|
|
74
|
+
if (typeof node.value !== "string" || hasOnlyLineBreak(node.value))
|
|
75
75
|
return;
|
|
76
76
|
if (getValidation(node)) {
|
|
77
77
|
report(node);
|
|
78
78
|
}
|
|
79
79
|
},
|
|
80
80
|
TemplateLiteral(node) {
|
|
81
|
-
if (node.parent.type !==
|
|
82
|
-
(node.parent.parent && node.parent.parent.type ===
|
|
81
|
+
if (node.parent.type !== "JSXExpressionContainer" ||
|
|
82
|
+
(node.parent.parent && node.parent.parent.type === "JSXAttribute"))
|
|
83
83
|
return;
|
|
84
84
|
if (getValidation(node.parent)) {
|
|
85
85
|
report(node);
|
|
@@ -91,12 +91,12 @@ export default {
|
|
|
91
91
|
meta: {
|
|
92
92
|
schema: [
|
|
93
93
|
{
|
|
94
|
-
type:
|
|
94
|
+
type: "object",
|
|
95
95
|
properties: {
|
|
96
96
|
skip: {
|
|
97
|
-
type:
|
|
97
|
+
type: "array",
|
|
98
98
|
items: {
|
|
99
|
-
type:
|
|
99
|
+
type: "string",
|
|
100
100
|
},
|
|
101
101
|
},
|
|
102
102
|
},
|
|
@@ -2,7 +2,7 @@ const rule = (context) => {
|
|
|
2
2
|
function reportNode(JSXExpressionNode) {
|
|
3
3
|
context.report({
|
|
4
4
|
node: JSXExpressionNode,
|
|
5
|
-
message:
|
|
5
|
+
message: "Single element style arrays are not necessary and cause unnecessary re-renders",
|
|
6
6
|
fix(fixer) {
|
|
7
7
|
const realStyleNode = JSXExpressionNode.value.expression.elements[0];
|
|
8
8
|
const styleSource = context.sourceCode.getText(realStyleNode);
|
|
@@ -15,11 +15,11 @@ const rule = (context) => {
|
|
|
15
15
|
// --------------------------------------------------------------------------
|
|
16
16
|
return {
|
|
17
17
|
JSXAttribute(node) {
|
|
18
|
-
if (node.name.name !==
|
|
18
|
+
if (node.name.name !== "style")
|
|
19
19
|
return;
|
|
20
20
|
if (!node.value.expression)
|
|
21
21
|
return;
|
|
22
|
-
if (node.value.expression.type !==
|
|
22
|
+
if (node.value.expression.type !== "ArrayExpression")
|
|
23
23
|
return;
|
|
24
24
|
if (node.value.expression.elements.length === 1) {
|
|
25
25
|
reportNode(node);
|
|
@@ -30,12 +30,12 @@ const rule = (context) => {
|
|
|
30
30
|
export default {
|
|
31
31
|
meta: {
|
|
32
32
|
docs: {
|
|
33
|
-
description:
|
|
34
|
-
category:
|
|
33
|
+
description: "Disallow single element style arrays. These cause unnecessary re-renders as the identity of the array always changes",
|
|
34
|
+
category: "Stylistic Issues",
|
|
35
35
|
recommended: false,
|
|
36
|
-
url:
|
|
36
|
+
url: "",
|
|
37
37
|
},
|
|
38
|
-
fixable:
|
|
38
|
+
fixable: "code",
|
|
39
39
|
},
|
|
40
40
|
createOnce: rule,
|
|
41
41
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { detect } from
|
|
2
|
-
import { StyleSheets, astHelpers } from
|
|
1
|
+
import { detect } from "../util/Components.js";
|
|
2
|
+
import { StyleSheets, astHelpers } from "../util/stylesheet.js";
|
|
3
3
|
const rule = detect((context, components) => {
|
|
4
4
|
let styleSheets;
|
|
5
5
|
let styleReferences;
|
|
@@ -9,12 +9,40 @@ const rule = detect((context, components) => {
|
|
|
9
9
|
const styles = unusedStyles[key];
|
|
10
10
|
styles.forEach((node) => {
|
|
11
11
|
const message = [
|
|
12
|
-
|
|
12
|
+
"Unused style detected: ",
|
|
13
13
|
key,
|
|
14
|
-
|
|
14
|
+
".",
|
|
15
15
|
node.key.name,
|
|
16
|
-
].join(
|
|
17
|
-
context.report({
|
|
16
|
+
].join("");
|
|
17
|
+
context.report({
|
|
18
|
+
node,
|
|
19
|
+
message,
|
|
20
|
+
fix(fixer) {
|
|
21
|
+
const parent = node.parent;
|
|
22
|
+
if (!parent || !parent.properties) {
|
|
23
|
+
return fixer.remove(node);
|
|
24
|
+
}
|
|
25
|
+
const properties = parent.properties;
|
|
26
|
+
const index = properties.indexOf(node);
|
|
27
|
+
if (index === -1)
|
|
28
|
+
return fixer.remove(node);
|
|
29
|
+
let removeStart;
|
|
30
|
+
let removeEnd;
|
|
31
|
+
if (index === 0) {
|
|
32
|
+
removeStart = node.range[0];
|
|
33
|
+
removeEnd =
|
|
34
|
+
properties.length > 1
|
|
35
|
+
? properties[1].range[0]
|
|
36
|
+
: node.range[1];
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const prev = properties[index - 1];
|
|
40
|
+
removeStart = prev.range[1];
|
|
41
|
+
removeEnd = node.range[1];
|
|
42
|
+
}
|
|
43
|
+
return fixer.removeRange([removeStart, removeEnd]);
|
|
44
|
+
},
|
|
45
|
+
});
|
|
18
46
|
});
|
|
19
47
|
}
|
|
20
48
|
});
|
|
@@ -36,10 +64,22 @@ const rule = detect((context, components) => {
|
|
|
36
64
|
const styles = astHelpers.getStyleDeclarations(node);
|
|
37
65
|
if (styleSheetName) {
|
|
38
66
|
styleSheets.add(styleSheetName, styles);
|
|
67
|
+
if (astHelpers.isStyleSheetExported(node)) {
|
|
68
|
+
styleSheets.markAsExported(styleSheetName);
|
|
69
|
+
}
|
|
39
70
|
}
|
|
40
71
|
}
|
|
41
72
|
},
|
|
42
|
-
|
|
73
|
+
ExportNamedDeclaration: function (node) {
|
|
74
|
+
if (node.specifiers) {
|
|
75
|
+
for (const spec of node.specifiers) {
|
|
76
|
+
const name = spec.local && spec.local.name;
|
|
77
|
+
if (name)
|
|
78
|
+
styleSheets.markAsExported(name);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"Program:exit": function () {
|
|
43
83
|
const list = components.all();
|
|
44
84
|
if (Object.keys(list).length > 0) {
|
|
45
85
|
styleReferences.forEach((reference) => {
|
|
@@ -53,6 +93,7 @@ const rule = detect((context, components) => {
|
|
|
53
93
|
export default {
|
|
54
94
|
meta: {
|
|
55
95
|
schema: [],
|
|
96
|
+
fixable: "code",
|
|
56
97
|
},
|
|
57
98
|
createOnce: rule,
|
|
58
99
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { astHelpers } from
|
|
1
|
+
import { astHelpers } from "../util/stylesheet.js";
|
|
2
2
|
const rule = (context) => {
|
|
3
3
|
// Defer context.options and context.sourceCode to visitor (oxlint forbids in createOnce).
|
|
4
4
|
function sort(array, order) {
|
|
5
5
|
return [...array].sort((a, b) => {
|
|
6
|
-
const identifierA = astHelpers.getStylePropertyIdentifier(a) ||
|
|
7
|
-
const identifierB = astHelpers.getStylePropertyIdentifier(b) ||
|
|
6
|
+
const identifierA = astHelpers.getStylePropertyIdentifier(a) || "";
|
|
7
|
+
const identifierB = astHelpers.getStylePropertyIdentifier(b) || "";
|
|
8
8
|
let sortOrder = 0;
|
|
9
9
|
if (astHelpers.isEitherShortHand(identifierA, identifierB)) {
|
|
10
10
|
return a.range[0] - b.range[0];
|
|
@@ -15,7 +15,7 @@ const rule = (context) => {
|
|
|
15
15
|
else if (identifierA > identifierB) {
|
|
16
16
|
sortOrder = 1;
|
|
17
17
|
}
|
|
18
|
-
return sortOrder * (order ===
|
|
18
|
+
return sortOrder * (order === "asc" ? 1 : -1);
|
|
19
19
|
});
|
|
20
20
|
}
|
|
21
21
|
function report(array, type, node, prev, current, order, sourceCode) {
|
|
@@ -50,12 +50,12 @@ const rule = (context) => {
|
|
|
50
50
|
for (let i = 1; i < array.length; i += 1) {
|
|
51
51
|
const previous = array[i - 1];
|
|
52
52
|
const current = array[i];
|
|
53
|
-
if (previous.type !==
|
|
53
|
+
if (previous.type !== "Property" || current.type !== "Property") {
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
|
-
const prevName = astHelpers.getStylePropertyIdentifier(previous) ||
|
|
57
|
-
const currentName = astHelpers.getStylePropertyIdentifier(current) ||
|
|
58
|
-
const oneIsShorthandForTheOther = arrayName ===
|
|
56
|
+
const prevName = astHelpers.getStylePropertyIdentifier(previous) || "";
|
|
57
|
+
const currentName = astHelpers.getStylePropertyIdentifier(current) || "";
|
|
58
|
+
const oneIsShorthandForTheOther = arrayName === "style properties" &&
|
|
59
59
|
astHelpers.isEitherShortHand(prevName, currentName);
|
|
60
60
|
if (!oneIsShorthandForTheOther && !isValidOrder(prevName, currentName)) {
|
|
61
61
|
return report(array, arrayName, node, previous, current, order, sourceCode);
|
|
@@ -64,11 +64,11 @@ const rule = (context) => {
|
|
|
64
64
|
}
|
|
65
65
|
return {
|
|
66
66
|
CallExpression: function (node) {
|
|
67
|
-
const order = context.options[0] ||
|
|
67
|
+
const order = context.options[0] || "asc";
|
|
68
68
|
const options = context.options[1] || {};
|
|
69
69
|
const { ignoreClassNames, ignoreStyleProperties } = options;
|
|
70
70
|
const sourceCode = context.sourceCode;
|
|
71
|
-
const isValidOrder = order ===
|
|
71
|
+
const isValidOrder = order === "asc"
|
|
72
72
|
? (a, b) => a <= b
|
|
73
73
|
: (a, b) => a >= b;
|
|
74
74
|
if (!astHelpers.isStyleSheetDeclaration(node, context.settings)) {
|
|
@@ -77,7 +77,7 @@ const rule = (context) => {
|
|
|
77
77
|
const classDefinitionsChunks = astHelpers.getStyleDeclarationsChunks(node);
|
|
78
78
|
if (!ignoreClassNames) {
|
|
79
79
|
classDefinitionsChunks.forEach((classDefinitions) => {
|
|
80
|
-
checkIsSorted(classDefinitions,
|
|
80
|
+
checkIsSorted(classDefinitions, "class names", node, order, options, sourceCode, isValidOrder);
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
83
|
if (ignoreStyleProperties)
|
|
@@ -90,7 +90,7 @@ const rule = (context) => {
|
|
|
90
90
|
}
|
|
91
91
|
const stylePropertyChunks = astHelpers.getPropertiesChunks(styleProperties);
|
|
92
92
|
stylePropertyChunks.forEach((stylePropertyChunk) => {
|
|
93
|
-
checkIsSorted(stylePropertyChunk,
|
|
93
|
+
checkIsSorted(stylePropertyChunk, "style properties", node, order, options, sourceCode, isValidOrder);
|
|
94
94
|
});
|
|
95
95
|
});
|
|
96
96
|
});
|
|
@@ -99,19 +99,19 @@ const rule = (context) => {
|
|
|
99
99
|
};
|
|
100
100
|
export default {
|
|
101
101
|
meta: {
|
|
102
|
-
fixable:
|
|
102
|
+
fixable: "code",
|
|
103
103
|
schema: [
|
|
104
104
|
{
|
|
105
|
-
enum: [
|
|
105
|
+
enum: ["asc", "desc"],
|
|
106
106
|
},
|
|
107
107
|
{
|
|
108
|
-
type:
|
|
108
|
+
type: "object",
|
|
109
109
|
properties: {
|
|
110
110
|
ignoreClassNames: {
|
|
111
|
-
type:
|
|
111
|
+
type: "boolean",
|
|
112
112
|
},
|
|
113
113
|
ignoreStyleProperties: {
|
|
114
|
-
type:
|
|
114
|
+
type: "boolean",
|
|
115
115
|
},
|
|
116
116
|
},
|
|
117
117
|
additionalProperties: false,
|
package/dist/util/Components.js
CHANGED
|
@@ -3,7 +3,7 @@ export class Components {
|
|
|
3
3
|
this.list = {};
|
|
4
4
|
}
|
|
5
5
|
getId(node) {
|
|
6
|
-
return node ? node.range.join(
|
|
6
|
+
return node ? node.range.join(":") : "";
|
|
7
7
|
}
|
|
8
8
|
add(node, confidence) {
|
|
9
9
|
const id = this.getId(node);
|
|
@@ -76,22 +76,22 @@ export function componentRule(rule, context) {
|
|
|
76
76
|
isReturningJSX: function (node) {
|
|
77
77
|
let property;
|
|
78
78
|
switch (node.type) {
|
|
79
|
-
case
|
|
80
|
-
property =
|
|
79
|
+
case "ReturnStatement":
|
|
80
|
+
property = "argument";
|
|
81
81
|
break;
|
|
82
|
-
case
|
|
83
|
-
property =
|
|
82
|
+
case "ArrowFunctionExpression":
|
|
83
|
+
property = "body";
|
|
84
84
|
break;
|
|
85
85
|
default:
|
|
86
86
|
return false;
|
|
87
87
|
}
|
|
88
88
|
const returnsJSX = node[property] &&
|
|
89
|
-
(node[property].type ===
|
|
90
|
-
node[property].type ===
|
|
89
|
+
(node[property].type === "JSXElement" ||
|
|
90
|
+
node[property].type === "JSXFragment");
|
|
91
91
|
const returnsReactCreateElement = node[property] &&
|
|
92
92
|
node[property].callee &&
|
|
93
93
|
node[property].callee.property &&
|
|
94
|
-
node[property].callee.property.name ===
|
|
94
|
+
node[property].callee.property.name === "createElement";
|
|
95
95
|
return Boolean(returnsJSX || returnsReactCreateElement);
|
|
96
96
|
},
|
|
97
97
|
getParentComponent: function (_n) {
|
|
@@ -112,7 +112,7 @@ export function componentRule(rule, context) {
|
|
|
112
112
|
},
|
|
113
113
|
getParentES6Component: function (_n) {
|
|
114
114
|
let scope = (context.sourceCode || context).getScope(_n);
|
|
115
|
-
while (scope && scope.type !==
|
|
115
|
+
while (scope && scope.type !== "class") {
|
|
116
116
|
scope = scope.upper;
|
|
117
117
|
}
|
|
118
118
|
const node = scope && scope.block;
|
|
@@ -126,8 +126,8 @@ export function componentRule(rule, context) {
|
|
|
126
126
|
while (scope) {
|
|
127
127
|
const node = scope.block;
|
|
128
128
|
const isFunction = /Function/.test(node.type);
|
|
129
|
-
const isNotMethod = !node.parent || node.parent.type !==
|
|
130
|
-
const isNotArgument = !node.parent || node.parent.type !==
|
|
129
|
+
const isNotMethod = !node.parent || node.parent.type !== "MethodDefinition";
|
|
130
|
+
const isNotArgument = !node.parent || node.parent.type !== "CallExpression";
|
|
131
131
|
if (isFunction && isNotMethod && isNotArgument) {
|
|
132
132
|
return node;
|
|
133
133
|
}
|
|
@@ -144,10 +144,10 @@ export function componentRule(rule, context) {
|
|
|
144
144
|
const componentPath = [];
|
|
145
145
|
while (currentNode) {
|
|
146
146
|
if (currentNode.property &&
|
|
147
|
-
currentNode.property.type ===
|
|
147
|
+
currentNode.property.type === "Identifier") {
|
|
148
148
|
componentPath.push(currentNode.property.name);
|
|
149
149
|
}
|
|
150
|
-
if (currentNode.object && currentNode.object.type ===
|
|
150
|
+
if (currentNode.object && currentNode.object.type === "Identifier") {
|
|
151
151
|
componentPath.push(currentNode.object.name);
|
|
152
152
|
}
|
|
153
153
|
currentNode = currentNode.object;
|
|
@@ -171,9 +171,9 @@ export function componentRule(rule, context) {
|
|
|
171
171
|
let defInScope;
|
|
172
172
|
const { defs } = variableInScope;
|
|
173
173
|
for (i = 0, j = defs.length; i < j; i++) {
|
|
174
|
-
if (defs[i].type ===
|
|
175
|
-
defs[i].type ===
|
|
176
|
-
defs[i].type ===
|
|
174
|
+
if (defs[i].type === "ClassName" ||
|
|
175
|
+
defs[i].type === "FunctionName" ||
|
|
176
|
+
defs[i].type === "Variable") {
|
|
177
177
|
defInScope = defs[i];
|
|
178
178
|
break;
|
|
179
179
|
}
|
package/dist/util/stylesheet.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export class StyleSheets {
|
|
2
2
|
constructor() {
|
|
3
|
+
this.exportedNames = new Set();
|
|
3
4
|
this.styleSheets = {};
|
|
4
5
|
this.colorLiterals = [];
|
|
5
6
|
this.objectExpressions = [];
|
|
@@ -7,8 +8,11 @@ export class StyleSheets {
|
|
|
7
8
|
add(styleSheetName, properties) {
|
|
8
9
|
this.styleSheets[styleSheetName] = properties;
|
|
9
10
|
}
|
|
11
|
+
markAsExported(styleSheetName) {
|
|
12
|
+
this.exportedNames.add(styleSheetName);
|
|
13
|
+
}
|
|
10
14
|
markAsUsed(fullyQualifiedName) {
|
|
11
|
-
const nameSplit = fullyQualifiedName.split(
|
|
15
|
+
const nameSplit = fullyQualifiedName.split(".");
|
|
12
16
|
const styleSheetName = nameSplit[0];
|
|
13
17
|
const styleSheetProperty = nameSplit[1];
|
|
14
18
|
if (this.styleSheets[styleSheetName]) {
|
|
@@ -16,7 +20,13 @@ export class StyleSheets {
|
|
|
16
20
|
}
|
|
17
21
|
}
|
|
18
22
|
getUnusedReferences() {
|
|
19
|
-
|
|
23
|
+
const result = {};
|
|
24
|
+
for (const [name, properties] of Object.entries(this.styleSheets)) {
|
|
25
|
+
if (properties.length > 0 && !this.exportedNames.has(name)) {
|
|
26
|
+
result[name] = properties;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
20
30
|
}
|
|
21
31
|
addColorLiterals(expressions) {
|
|
22
32
|
this.colorLiterals = this.colorLiterals.concat(expressions);
|
|
@@ -33,11 +43,11 @@ export class StyleSheets {
|
|
|
33
43
|
}
|
|
34
44
|
let currentContent;
|
|
35
45
|
const getSourceCode = (node) => currentContent.sourceCode.getText(node);
|
|
36
|
-
const getStyleSheetObjectNames = (settings) => settings[
|
|
46
|
+
const getStyleSheetObjectNames = (settings) => settings["react-native/style-sheet-object-names"] || ["StyleSheet"];
|
|
37
47
|
export const astHelpers = {
|
|
38
48
|
containsStyleSheetObject: function (node, objectNames) {
|
|
39
49
|
return Boolean(node &&
|
|
40
|
-
node.type ===
|
|
50
|
+
node.type === "CallExpression" &&
|
|
41
51
|
node.callee &&
|
|
42
52
|
node.callee.object &&
|
|
43
53
|
node.callee.object.name &&
|
|
@@ -47,7 +57,7 @@ export const astHelpers = {
|
|
|
47
57
|
return Boolean(node &&
|
|
48
58
|
node.callee &&
|
|
49
59
|
node.callee.property &&
|
|
50
|
-
node.callee.property.name ===
|
|
60
|
+
node.callee.property.name === "create");
|
|
51
61
|
},
|
|
52
62
|
isStyleSheetDeclaration: function (node, settings) {
|
|
53
63
|
const objectNames = getStyleSheetObjectNames(settings);
|
|
@@ -59,19 +69,41 @@ export const astHelpers = {
|
|
|
59
69
|
return node.parent.id.name;
|
|
60
70
|
}
|
|
61
71
|
},
|
|
72
|
+
/**
|
|
73
|
+
* Returns true if the StyleSheet.create call is part of an export, so its
|
|
74
|
+
* styles may be used in other files and should not be reported as unused.
|
|
75
|
+
*/
|
|
76
|
+
isStyleSheetExported: function (node) {
|
|
77
|
+
if (!node)
|
|
78
|
+
return false;
|
|
79
|
+
// export default StyleSheet.create(...)
|
|
80
|
+
if (node.parent && node.parent.type === "ExportDefaultDeclaration")
|
|
81
|
+
return true;
|
|
82
|
+
const declarator = node.parent;
|
|
83
|
+
if (!declarator || declarator.type !== "VariableDeclarator")
|
|
84
|
+
return false;
|
|
85
|
+
const declaration = declarator.parent;
|
|
86
|
+
if (!declaration)
|
|
87
|
+
return false;
|
|
88
|
+
// export const styles = StyleSheet.create(...)
|
|
89
|
+
if (declaration.parent &&
|
|
90
|
+
declaration.parent.type === "ExportNamedDeclaration")
|
|
91
|
+
return true;
|
|
92
|
+
return false;
|
|
93
|
+
},
|
|
62
94
|
getStyleDeclarations: function (node) {
|
|
63
95
|
if (node &&
|
|
64
|
-
node.type ===
|
|
96
|
+
node.type === "CallExpression" &&
|
|
65
97
|
node.arguments &&
|
|
66
98
|
node.arguments[0] &&
|
|
67
99
|
node.arguments[0].properties) {
|
|
68
|
-
return node.arguments[0].properties.filter((property) => property.type ===
|
|
100
|
+
return node.arguments[0].properties.filter((property) => property.type === "Property");
|
|
69
101
|
}
|
|
70
102
|
return [];
|
|
71
103
|
},
|
|
72
104
|
getStyleDeclarationsChunks: function (node) {
|
|
73
105
|
if (node &&
|
|
74
|
-
node.type ===
|
|
106
|
+
node.type === "CallExpression" &&
|
|
75
107
|
node.arguments &&
|
|
76
108
|
node.arguments[0] &&
|
|
77
109
|
node.arguments[0].properties) {
|
|
@@ -80,7 +112,7 @@ export const astHelpers = {
|
|
|
80
112
|
let chunk = [];
|
|
81
113
|
for (let i = 0; i < properties.length; i += 1) {
|
|
82
114
|
const property = properties[i];
|
|
83
|
-
if (property.type ===
|
|
115
|
+
if (property.type === "Property") {
|
|
84
116
|
chunk.push(property);
|
|
85
117
|
}
|
|
86
118
|
else if (chunk.length) {
|
|
@@ -100,7 +132,7 @@ export const astHelpers = {
|
|
|
100
132
|
let chunk = [];
|
|
101
133
|
for (let i = 0; i < properties.length; i += 1) {
|
|
102
134
|
const property = properties[i];
|
|
103
|
-
if (property.type ===
|
|
135
|
+
if (property.type === "Property") {
|
|
104
136
|
chunk.push(property);
|
|
105
137
|
}
|
|
106
138
|
else if (chunk.length) {
|
|
@@ -116,19 +148,19 @@ export const astHelpers = {
|
|
|
116
148
|
getExpressionIdentifier: function (node) {
|
|
117
149
|
if (node) {
|
|
118
150
|
switch (node.type) {
|
|
119
|
-
case
|
|
151
|
+
case "Identifier":
|
|
120
152
|
return node.name;
|
|
121
|
-
case
|
|
153
|
+
case "Literal":
|
|
122
154
|
return node.value;
|
|
123
|
-
case
|
|
155
|
+
case "TemplateLiteral":
|
|
124
156
|
return node.quasis.reduce((result, quasi, index) => result +
|
|
125
157
|
quasi.value.cooked +
|
|
126
|
-
astHelpers.getExpressionIdentifier(node.expressions[index]),
|
|
158
|
+
astHelpers.getExpressionIdentifier(node.expressions[index]), "");
|
|
127
159
|
default:
|
|
128
|
-
return
|
|
160
|
+
return "";
|
|
129
161
|
}
|
|
130
162
|
}
|
|
131
|
-
return
|
|
163
|
+
return "";
|
|
132
164
|
},
|
|
133
165
|
getStylePropertyIdentifier: function (node) {
|
|
134
166
|
if (node && node.key) {
|
|
@@ -136,10 +168,10 @@ export const astHelpers = {
|
|
|
136
168
|
}
|
|
137
169
|
},
|
|
138
170
|
isStyleAttribute: function (node) {
|
|
139
|
-
return Boolean(node.type ===
|
|
171
|
+
return Boolean(node.type === "JSXAttribute" &&
|
|
140
172
|
node.name &&
|
|
141
173
|
node.name.name &&
|
|
142
|
-
node.name.name.toLowerCase().includes(
|
|
174
|
+
node.name.name.toLowerCase().includes("style"));
|
|
143
175
|
},
|
|
144
176
|
collectStyleObjectExpressions: function (node, context) {
|
|
145
177
|
currentContent = context;
|
|
@@ -161,7 +193,7 @@ export const astHelpers = {
|
|
|
161
193
|
const styleReferenceContainers = node.expression.elements;
|
|
162
194
|
return astHelpers.collectColorLiteralsFromContainers(styleReferenceContainers);
|
|
163
195
|
}
|
|
164
|
-
if (node.type ===
|
|
196
|
+
if (node.type === "ObjectExpression") {
|
|
165
197
|
return astHelpers.getColorLiteralsFromNode(node);
|
|
166
198
|
}
|
|
167
199
|
return astHelpers.getColorLiteralsFromNode(node.expression);
|
|
@@ -188,17 +220,21 @@ export const astHelpers = {
|
|
|
188
220
|
return [];
|
|
189
221
|
}
|
|
190
222
|
switch (node.type) {
|
|
191
|
-
case
|
|
223
|
+
case "MemberExpression":
|
|
192
224
|
styleReference = astHelpers.getStyleReferenceFromExpression(node);
|
|
193
225
|
return [styleReference];
|
|
194
|
-
case
|
|
226
|
+
case "LogicalExpression":
|
|
195
227
|
leftStyleReferences = astHelpers.getStyleReferenceFromNode(node.left);
|
|
196
228
|
rightStyleReferences = astHelpers.getStyleReferenceFromNode(node.right);
|
|
197
|
-
return []
|
|
198
|
-
|
|
229
|
+
return []
|
|
230
|
+
.concat(leftStyleReferences)
|
|
231
|
+
.concat(rightStyleReferences);
|
|
232
|
+
case "ConditionalExpression":
|
|
199
233
|
leftStyleReferences = astHelpers.getStyleReferenceFromNode(node.consequent);
|
|
200
234
|
rightStyleReferences = astHelpers.getStyleReferenceFromNode(node.alternate);
|
|
201
|
-
return []
|
|
235
|
+
return []
|
|
236
|
+
.concat(leftStyleReferences)
|
|
237
|
+
.concat(rightStyleReferences);
|
|
202
238
|
default:
|
|
203
239
|
return [];
|
|
204
240
|
}
|
|
@@ -209,19 +245,21 @@ export const astHelpers = {
|
|
|
209
245
|
if (!node) {
|
|
210
246
|
return [];
|
|
211
247
|
}
|
|
212
|
-
if (node.type ===
|
|
248
|
+
if (node.type === "ObjectExpression") {
|
|
213
249
|
return [astHelpers.getStyleObjectFromExpression(node)];
|
|
214
250
|
}
|
|
215
251
|
switch (node.type) {
|
|
216
|
-
case
|
|
252
|
+
case "LogicalExpression":
|
|
217
253
|
leftStyleObjectExpression = astHelpers.getStyleObjectExpressionFromNode(node.left);
|
|
218
|
-
rightStyleObjectExpression =
|
|
254
|
+
rightStyleObjectExpression =
|
|
255
|
+
astHelpers.getStyleObjectExpressionFromNode(node.right);
|
|
219
256
|
return []
|
|
220
257
|
.concat(leftStyleObjectExpression)
|
|
221
258
|
.concat(rightStyleObjectExpression);
|
|
222
|
-
case
|
|
259
|
+
case "ConditionalExpression":
|
|
223
260
|
leftStyleObjectExpression = astHelpers.getStyleObjectExpressionFromNode(node.consequent);
|
|
224
|
-
rightStyleObjectExpression =
|
|
261
|
+
rightStyleObjectExpression =
|
|
262
|
+
astHelpers.getStyleObjectExpressionFromNode(node.alternate);
|
|
225
263
|
return []
|
|
226
264
|
.concat(leftStyleObjectExpression)
|
|
227
265
|
.concat(rightStyleObjectExpression);
|
|
@@ -235,27 +273,31 @@ export const astHelpers = {
|
|
|
235
273
|
if (!node) {
|
|
236
274
|
return [];
|
|
237
275
|
}
|
|
238
|
-
if (node.type ===
|
|
276
|
+
if (node.type === "ObjectExpression") {
|
|
239
277
|
return [astHelpers.getColorLiteralsFromExpression(node)];
|
|
240
278
|
}
|
|
241
279
|
switch (node.type) {
|
|
242
|
-
case
|
|
280
|
+
case "LogicalExpression":
|
|
243
281
|
leftColorLiterals = astHelpers.getColorLiteralsFromNode(node.left);
|
|
244
282
|
rightColorLiterals = astHelpers.getColorLiteralsFromNode(node.right);
|
|
245
|
-
return []
|
|
246
|
-
|
|
283
|
+
return []
|
|
284
|
+
.concat(leftColorLiterals)
|
|
285
|
+
.concat(rightColorLiterals);
|
|
286
|
+
case "ConditionalExpression":
|
|
247
287
|
leftColorLiterals = astHelpers.getColorLiteralsFromNode(node.consequent);
|
|
248
288
|
rightColorLiterals = astHelpers.getColorLiteralsFromNode(node.alternate);
|
|
249
|
-
return []
|
|
289
|
+
return []
|
|
290
|
+
.concat(leftColorLiterals)
|
|
291
|
+
.concat(rightColorLiterals);
|
|
250
292
|
default:
|
|
251
293
|
return [];
|
|
252
294
|
}
|
|
253
295
|
},
|
|
254
296
|
hasArrayOfStyleReferences: function (node) {
|
|
255
297
|
return (node &&
|
|
256
|
-
Boolean(node.type ===
|
|
298
|
+
Boolean(node.type === "JSXExpressionContainer" &&
|
|
257
299
|
node.expression &&
|
|
258
|
-
node.expression.type ===
|
|
300
|
+
node.expression.type === "ArrayExpression"));
|
|
259
301
|
},
|
|
260
302
|
getStyleReferenceFromExpression: function (node) {
|
|
261
303
|
const result = [];
|
|
@@ -267,7 +309,7 @@ export const astHelpers = {
|
|
|
267
309
|
if (property) {
|
|
268
310
|
result.push(property);
|
|
269
311
|
}
|
|
270
|
-
return result.join(
|
|
312
|
+
return result.join(".");
|
|
271
313
|
},
|
|
272
314
|
getStyleObjectFromExpression: function (node) {
|
|
273
315
|
const obj = {};
|
|
@@ -277,27 +319,27 @@ export const astHelpers = {
|
|
|
277
319
|
if (!p.value || !p.key) {
|
|
278
320
|
return;
|
|
279
321
|
}
|
|
280
|
-
if (p.value.type ===
|
|
322
|
+
if (p.value.type === "Literal") {
|
|
281
323
|
invalid = true;
|
|
282
324
|
obj[p.key.name] = p.value.value;
|
|
283
325
|
}
|
|
284
|
-
else if (p.value.type ===
|
|
326
|
+
else if (p.value.type === "ConditionalExpression") {
|
|
285
327
|
const innerNode = p.value;
|
|
286
|
-
if (innerNode.consequent.type ===
|
|
287
|
-
innerNode.alternate.type ===
|
|
328
|
+
if (innerNode.consequent.type === "Literal" ||
|
|
329
|
+
innerNode.alternate.type === "Literal") {
|
|
288
330
|
invalid = true;
|
|
289
331
|
obj[p.key.name] = getSourceCode(innerNode);
|
|
290
332
|
}
|
|
291
333
|
}
|
|
292
|
-
else if (p.value.type ===
|
|
293
|
-
p.value.operator ===
|
|
294
|
-
p.value.argument.type ===
|
|
334
|
+
else if (p.value.type === "UnaryExpression" &&
|
|
335
|
+
p.value.operator === "-" &&
|
|
336
|
+
p.value.argument.type === "Literal") {
|
|
295
337
|
invalid = true;
|
|
296
338
|
obj[p.key.name] = -1 * p.value.argument.value;
|
|
297
339
|
}
|
|
298
|
-
else if (p.value.type ===
|
|
299
|
-
p.value.operator ===
|
|
300
|
-
p.value.argument.type ===
|
|
340
|
+
else if (p.value.type === "UnaryExpression" &&
|
|
341
|
+
p.value.operator === "+" &&
|
|
342
|
+
p.value.argument.type === "Literal") {
|
|
301
343
|
invalid = true;
|
|
302
344
|
obj[p.key.name] = p.value.argument.value;
|
|
303
345
|
}
|
|
@@ -312,15 +354,15 @@ export const astHelpers = {
|
|
|
312
354
|
node.properties.forEach((p) => {
|
|
313
355
|
if (p.key &&
|
|
314
356
|
p.key.name &&
|
|
315
|
-
p.key.name.toLowerCase().indexOf(
|
|
316
|
-
if (p.value.type ===
|
|
357
|
+
p.key.name.toLowerCase().indexOf("color") !== -1) {
|
|
358
|
+
if (p.value.type === "Literal") {
|
|
317
359
|
invalid = true;
|
|
318
360
|
obj[p.key.name] = p.value.value;
|
|
319
361
|
}
|
|
320
|
-
else if (p.value.type ===
|
|
362
|
+
else if (p.value.type === "ConditionalExpression") {
|
|
321
363
|
const innerNode = p.value;
|
|
322
|
-
if (innerNode.consequent.type ===
|
|
323
|
-
innerNode.alternate.type ===
|
|
364
|
+
if (innerNode.consequent.type === "Literal" ||
|
|
365
|
+
innerNode.alternate.type === "Literal") {
|
|
324
366
|
invalid = true;
|
|
325
367
|
obj[p.key.name] = getSourceCode(innerNode);
|
|
326
368
|
}
|
|
@@ -343,17 +385,17 @@ export const astHelpers = {
|
|
|
343
385
|
getPotentialStyleReferenceFromMemberExpression: function (node) {
|
|
344
386
|
if (node &&
|
|
345
387
|
node.object &&
|
|
346
|
-
node.object.type ===
|
|
388
|
+
node.object.type === "Identifier" &&
|
|
347
389
|
node.object.name &&
|
|
348
390
|
node.property &&
|
|
349
|
-
node.property.type ===
|
|
391
|
+
node.property.type === "Identifier" &&
|
|
350
392
|
node.property.name &&
|
|
351
|
-
node.parent.type !==
|
|
352
|
-
return [node.object.name, node.property.name].join(
|
|
393
|
+
node.parent.type !== "MemberExpression") {
|
|
394
|
+
return [node.object.name, node.property.name].join(".");
|
|
353
395
|
}
|
|
354
396
|
},
|
|
355
397
|
isEitherShortHand: function (property1, property2) {
|
|
356
|
-
const shorthands = [
|
|
398
|
+
const shorthands = ["margin", "padding", "border", "flex"];
|
|
357
399
|
if (shorthands.includes(property1)) {
|
|
358
400
|
return property2.startsWith(property1);
|
|
359
401
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oxlint-plugin-react-native",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "React Native specific linting rules for Oxlint",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"oxlint",
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"format": "oxfmt",
|
|
33
33
|
"format:check": "oxfmt --check",
|
|
34
34
|
"test": "jest",
|
|
35
|
-
"test:watch": "jest --watch"
|
|
35
|
+
"test:watch": "jest --watch",
|
|
36
|
+
"release": "semantic-release"
|
|
36
37
|
},
|
|
37
38
|
"dependencies": {
|
|
38
39
|
"@oxlint/plugins": "1.43.0"
|
|
@@ -41,15 +42,26 @@
|
|
|
41
42
|
"@babel/core": "7.29.0",
|
|
42
43
|
"@babel/preset-env": "7.29.0",
|
|
43
44
|
"@babel/preset-typescript": "7.28.5",
|
|
45
|
+
"@commitlint/cli": "^20.4.1",
|
|
46
|
+
"@commitlint/config-conventional": "^20.4.1",
|
|
47
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
48
|
+
"@semantic-release/git": "^10.0.1",
|
|
44
49
|
"@types/jest": "30.0.0",
|
|
45
|
-
"@types/node": "25.2.
|
|
50
|
+
"@types/node": "25.2.3",
|
|
51
|
+
"commitlint": "^20.4.1",
|
|
46
52
|
"jest": "30.2.0",
|
|
47
|
-
"oxfmt": "^0.
|
|
48
|
-
"oxlint": "1.
|
|
49
|
-
"oxlint-tsgolint": "^0.
|
|
53
|
+
"oxfmt": "^0.31.0",
|
|
54
|
+
"oxlint": "1.46.0",
|
|
55
|
+
"oxlint-tsgolint": "^0.12.0",
|
|
56
|
+
"semantic-release": "^25.0.3",
|
|
50
57
|
"typescript": "5.9.3"
|
|
51
58
|
},
|
|
52
59
|
"peerDependencies": {
|
|
53
60
|
"oxlint": ">=1.0.0"
|
|
61
|
+
},
|
|
62
|
+
"commitlint": {
|
|
63
|
+
"extends": [
|
|
64
|
+
"@commitlint/config-conventional"
|
|
65
|
+
]
|
|
54
66
|
}
|
|
55
67
|
}
|