oxlint-plugin-react-doctor 0.2.18-dev.8e7fb33 → 0.2.18-dev.abbb042
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/dist/index.js +41 -73
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -23680,6 +23680,35 @@ const noUsememoSimpleExpression = defineRule({
|
|
|
23680
23680
|
});
|
|
23681
23681
|
//#endregion
|
|
23682
23682
|
//#region src/plugin/rules/design/no-wide-letter-spacing.ts
|
|
23683
|
+
const getJsxAttributeStringValue = (attributeValue) => {
|
|
23684
|
+
if (!attributeValue) return null;
|
|
23685
|
+
if (isNodeOfType(attributeValue, "Literal") && typeof attributeValue.value === "string") return attributeValue.value;
|
|
23686
|
+
if (isNodeOfType(attributeValue, "JSXExpressionContainer")) {
|
|
23687
|
+
const expression = attributeValue.expression;
|
|
23688
|
+
if (isNodeOfType(expression, "Literal") && typeof expression.value === "string") return expression.value;
|
|
23689
|
+
}
|
|
23690
|
+
return null;
|
|
23691
|
+
};
|
|
23692
|
+
const isTruthyBooleanJsxAttribute = (attributeValue) => {
|
|
23693
|
+
if (attributeValue === null) return true;
|
|
23694
|
+
if (isNodeOfType(attributeValue, "JSXExpressionContainer")) {
|
|
23695
|
+
const expression = attributeValue.expression;
|
|
23696
|
+
return isNodeOfType(expression, "Literal") && expression.value === true;
|
|
23697
|
+
}
|
|
23698
|
+
return false;
|
|
23699
|
+
};
|
|
23700
|
+
const hasUppercaseSiblingProp = (styleAttribute) => {
|
|
23701
|
+
const openingElement = styleAttribute.parent;
|
|
23702
|
+
if (!openingElement || !isNodeOfType(openingElement, "JSXOpeningElement")) return false;
|
|
23703
|
+
for (const attribute of openingElement.attributes ?? []) {
|
|
23704
|
+
if (!isNodeOfType(attribute, "JSXAttribute")) continue;
|
|
23705
|
+
if (!isNodeOfType(attribute.name, "JSXIdentifier")) continue;
|
|
23706
|
+
const attributeName = attribute.name.name;
|
|
23707
|
+
if (attributeName === "uppercase" && isTruthyBooleanJsxAttribute(attribute.value)) return true;
|
|
23708
|
+
if (attributeName === "textTransform" && getJsxAttributeStringValue(attribute.value) === "uppercase") return true;
|
|
23709
|
+
}
|
|
23710
|
+
return false;
|
|
23711
|
+
};
|
|
23683
23712
|
const noWideLetterSpacing = defineRule({
|
|
23684
23713
|
id: "no-wide-letter-spacing",
|
|
23685
23714
|
title: "Wide letter spacing on body text",
|
|
@@ -23689,6 +23718,7 @@ const noWideLetterSpacing = defineRule({
|
|
|
23689
23718
|
create: (context) => ({ JSXAttribute(node) {
|
|
23690
23719
|
const expression = getInlineStyleExpression(node);
|
|
23691
23720
|
if (!expression) return;
|
|
23721
|
+
if (hasUppercaseSiblingProp(node)) return;
|
|
23692
23722
|
let isUppercase = false;
|
|
23693
23723
|
let letterSpacingProperty = null;
|
|
23694
23724
|
let letterSpacingEm = null;
|
|
@@ -26808,76 +26838,22 @@ const rerenderTransitionsScroll = defineRule({
|
|
|
26808
26838
|
} })
|
|
26809
26839
|
});
|
|
26810
26840
|
//#endregion
|
|
26841
|
+
//#region src/plugin/utils/define-retired-rule.ts
|
|
26842
|
+
const defineRetiredRule = (rule) => defineRule({
|
|
26843
|
+
...rule,
|
|
26844
|
+
defaultEnabled: false,
|
|
26845
|
+
lifecycle: "retired",
|
|
26846
|
+
create: () => ({})
|
|
26847
|
+
});
|
|
26848
|
+
//#endregion
|
|
26811
26849
|
//#region src/plugin/rules/react-native/rn-animate-layout-property.ts
|
|
26812
|
-
const
|
|
26813
|
-
"width",
|
|
26814
|
-
"height",
|
|
26815
|
-
"top",
|
|
26816
|
-
"left",
|
|
26817
|
-
"right",
|
|
26818
|
-
"bottom",
|
|
26819
|
-
"minWidth",
|
|
26820
|
-
"minHeight",
|
|
26821
|
-
"maxWidth",
|
|
26822
|
-
"maxHeight",
|
|
26823
|
-
"margin",
|
|
26824
|
-
"marginTop",
|
|
26825
|
-
"marginBottom",
|
|
26826
|
-
"marginLeft",
|
|
26827
|
-
"marginRight",
|
|
26828
|
-
"marginHorizontal",
|
|
26829
|
-
"marginVertical",
|
|
26830
|
-
"padding",
|
|
26831
|
-
"paddingTop",
|
|
26832
|
-
"paddingBottom",
|
|
26833
|
-
"paddingLeft",
|
|
26834
|
-
"paddingRight",
|
|
26835
|
-
"paddingHorizontal",
|
|
26836
|
-
"paddingVertical",
|
|
26837
|
-
"flex",
|
|
26838
|
-
"flexBasis",
|
|
26839
|
-
"flexGrow",
|
|
26840
|
-
"flexShrink",
|
|
26841
|
-
"borderWidth",
|
|
26842
|
-
"borderTopWidth",
|
|
26843
|
-
"borderBottomWidth",
|
|
26844
|
-
"borderLeftWidth",
|
|
26845
|
-
"borderRightWidth",
|
|
26846
|
-
"fontSize",
|
|
26847
|
-
"lineHeight",
|
|
26848
|
-
"letterSpacing"
|
|
26849
|
-
]);
|
|
26850
|
-
const findReturnedObject = (callback) => {
|
|
26851
|
-
if (!isNodeOfType(callback, "ArrowFunctionExpression") && !isNodeOfType(callback, "FunctionExpression")) return null;
|
|
26852
|
-
const body = callback.body;
|
|
26853
|
-
if (isNodeOfType(body, "ObjectExpression")) return body;
|
|
26854
|
-
if (!isNodeOfType(body, "BlockStatement")) return null;
|
|
26855
|
-
for (const stmt of body.body ?? []) if (isNodeOfType(stmt, "ReturnStatement") && isNodeOfType(stmt.argument, "ObjectExpression")) return stmt.argument;
|
|
26856
|
-
return null;
|
|
26857
|
-
};
|
|
26858
|
-
const rnAnimateLayoutProperty = defineRule({
|
|
26850
|
+
const rnAnimateLayoutProperty = defineRetiredRule({
|
|
26859
26851
|
id: "rn-animate-layout-property",
|
|
26860
26852
|
title: "Animating a layout property",
|
|
26861
26853
|
tags: ["test-noise"],
|
|
26862
26854
|
requires: ["react-native"],
|
|
26863
|
-
severity: "
|
|
26864
|
-
recommendation: "
|
|
26865
|
-
create: (context) => ({ CallExpression(node) {
|
|
26866
|
-
if (!isNodeOfType(node.callee, "Identifier") || node.callee.name !== "useAnimatedStyle") return;
|
|
26867
|
-
const callback = node.arguments?.[0];
|
|
26868
|
-
if (!callback) return;
|
|
26869
|
-
const returnedObject = findReturnedObject(callback);
|
|
26870
|
-
if (!returnedObject) return;
|
|
26871
|
-
for (const property of returnedObject.properties ?? []) {
|
|
26872
|
-
if (!isNodeOfType(property, "Property")) continue;
|
|
26873
|
-
if (!isNodeOfType(property.key, "Identifier")) continue;
|
|
26874
|
-
if (!REANIMATED_LAYOUT_KEYS.has(property.key.name)) continue;
|
|
26875
|
-
context.report({
|
|
26876
|
-
node: property,
|
|
26877
|
-
message: `Your users see stutter when useAnimatedStyle animates "${property.key.name}" on the layout thread.`
|
|
26878
|
-
});
|
|
26879
|
-
}
|
|
26880
|
-
} })
|
|
26855
|
+
severity: "warn",
|
|
26856
|
+
recommendation: "Reanimated useAnimatedStyle runs on the UI thread; layout-affecting properties driven by animation helpers, interpolate, or shared values are valid."
|
|
26881
26857
|
});
|
|
26882
26858
|
//#endregion
|
|
26883
26859
|
//#region src/plugin/rules/react-native/rn-animation-reaction-as-derived.ts
|
|
@@ -28204,14 +28180,6 @@ const rnNoSingleElementStyleArray = defineRule({
|
|
|
28204
28180
|
} })
|
|
28205
28181
|
});
|
|
28206
28182
|
//#endregion
|
|
28207
|
-
//#region src/plugin/utils/define-retired-rule.ts
|
|
28208
|
-
const defineRetiredRule = (rule) => defineRule({
|
|
28209
|
-
...rule,
|
|
28210
|
-
defaultEnabled: false,
|
|
28211
|
-
lifecycle: "retired",
|
|
28212
|
-
create: () => ({})
|
|
28213
|
-
});
|
|
28214
|
-
//#endregion
|
|
28215
28183
|
//#region src/plugin/rules/react-native/rn-prefer-content-inset-adjustment.ts
|
|
28216
28184
|
const rnPreferContentInsetAdjustment = defineRetiredRule({
|
|
28217
28185
|
id: "rn-prefer-content-inset-adjustment",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oxlint-plugin-react-doctor",
|
|
3
|
-
"version": "0.2.18-dev.
|
|
3
|
+
"version": "0.2.18-dev.abbb042",
|
|
4
4
|
"description": "oxlint plugin for React Doctor: diagnose React codebases for security, performance, correctness, accessibility, bundle-size, and architecture issues",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"accessibility",
|