oxlint-plugin-react-doctor 0.2.5 → 0.2.6
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.d.ts +0 -40
- package/dist/index.js +13 -106
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -529,26 +529,6 @@ declare const REACT_DOCTOR_RULES: readonly [{
|
|
|
529
529
|
readonly recommendation?: string;
|
|
530
530
|
readonly create: (context: RuleContext) => RuleVisitors;
|
|
531
531
|
};
|
|
532
|
-
}, {
|
|
533
|
-
readonly key: "react-doctor/design-no-bold-heading";
|
|
534
|
-
readonly id: "design-no-bold-heading";
|
|
535
|
-
readonly source: "react-doctor";
|
|
536
|
-
readonly originallyExternal: false;
|
|
537
|
-
readonly framework: "global";
|
|
538
|
-
readonly category: "Architecture";
|
|
539
|
-
readonly severity: "warn";
|
|
540
|
-
readonly rule: {
|
|
541
|
-
readonly framework: "global";
|
|
542
|
-
readonly category: "Architecture";
|
|
543
|
-
readonly id: string;
|
|
544
|
-
readonly severity: RuleSeverity;
|
|
545
|
-
readonly requires?: ReadonlyArray<string>;
|
|
546
|
-
readonly disabledBy?: ReadonlyArray<string>;
|
|
547
|
-
readonly tags?: ReadonlyArray<string>;
|
|
548
|
-
readonly defaultEnabled?: boolean;
|
|
549
|
-
readonly recommendation?: string;
|
|
550
|
-
readonly create: (context: RuleContext) => RuleVisitors;
|
|
551
|
-
};
|
|
552
532
|
}, {
|
|
553
533
|
readonly key: "react-doctor/design-no-em-dash-in-jsx-text";
|
|
554
534
|
readonly id: "design-no-em-dash-in-jsx-text";
|
|
@@ -6315,26 +6295,6 @@ declare const RULES: readonly [{
|
|
|
6315
6295
|
readonly recommendation?: string;
|
|
6316
6296
|
readonly create: (context: RuleContext) => RuleVisitors;
|
|
6317
6297
|
};
|
|
6318
|
-
}, {
|
|
6319
|
-
readonly key: "react-doctor/design-no-bold-heading";
|
|
6320
|
-
readonly id: "design-no-bold-heading";
|
|
6321
|
-
readonly source: "react-doctor";
|
|
6322
|
-
readonly originallyExternal: false;
|
|
6323
|
-
readonly framework: "global";
|
|
6324
|
-
readonly category: "Architecture";
|
|
6325
|
-
readonly severity: "warn";
|
|
6326
|
-
readonly rule: {
|
|
6327
|
-
readonly framework: "global";
|
|
6328
|
-
readonly category: "Architecture";
|
|
6329
|
-
readonly id: string;
|
|
6330
|
-
readonly severity: RuleSeverity;
|
|
6331
|
-
readonly requires?: ReadonlyArray<string>;
|
|
6332
|
-
readonly disabledBy?: ReadonlyArray<string>;
|
|
6333
|
-
readonly tags?: ReadonlyArray<string>;
|
|
6334
|
-
readonly defaultEnabled?: boolean;
|
|
6335
|
-
readonly recommendation?: string;
|
|
6336
|
-
readonly create: (context: RuleContext) => RuleVisitors;
|
|
6337
|
-
};
|
|
6338
6298
|
}, {
|
|
6339
6299
|
readonly key: "react-doctor/design-no-em-dash-in-jsx-text";
|
|
6340
6300
|
readonly id: "design-no-em-dash-in-jsx-text";
|
package/dist/index.js
CHANGED
|
@@ -3527,19 +3527,6 @@ const controlHasAssociatedLabel = defineRule({
|
|
|
3527
3527
|
}
|
|
3528
3528
|
});
|
|
3529
3529
|
const LONG_TRANSITION_DURATION_THRESHOLD_MS = 1e3;
|
|
3530
|
-
const HEADING_TAG_NAMES = new Set([
|
|
3531
|
-
"h1",
|
|
3532
|
-
"h2",
|
|
3533
|
-
"h3",
|
|
3534
|
-
"h4",
|
|
3535
|
-
"h5",
|
|
3536
|
-
"h6"
|
|
3537
|
-
]);
|
|
3538
|
-
const HEAVY_HEADING_TAILWIND_WEIGHTS = new Set([
|
|
3539
|
-
"font-bold",
|
|
3540
|
-
"font-extrabold",
|
|
3541
|
-
"font-black"
|
|
3542
|
-
]);
|
|
3543
3530
|
const VAGUE_BUTTON_LABELS = new Set([
|
|
3544
3531
|
"continue",
|
|
3545
3532
|
"submit",
|
|
@@ -3609,85 +3596,6 @@ const getOpeningElementTagName = (openingElement) => {
|
|
|
3609
3596
|
return null;
|
|
3610
3597
|
};
|
|
3611
3598
|
//#endregion
|
|
3612
|
-
//#region src/plugin/rules/react-ui/utils/get-class-name-literal.ts
|
|
3613
|
-
const getClassNameLiteral = (classAttribute) => {
|
|
3614
|
-
if (!isNodeOfType(classAttribute, "JSXAttribute")) return null;
|
|
3615
|
-
if (!classAttribute.value) return null;
|
|
3616
|
-
if (isNodeOfType(classAttribute.value, "Literal") && typeof classAttribute.value.value === "string") return classAttribute.value.value;
|
|
3617
|
-
if (isNodeOfType(classAttribute.value, "JSXExpressionContainer")) {
|
|
3618
|
-
const expression = classAttribute.value.expression;
|
|
3619
|
-
if (isNodeOfType(expression, "Literal") && typeof expression.value === "string") return expression.value;
|
|
3620
|
-
if (isNodeOfType(expression, "TemplateLiteral") && expression.quasis?.length === 1) return expression.quasis[0].value?.raw ?? null;
|
|
3621
|
-
}
|
|
3622
|
-
return null;
|
|
3623
|
-
};
|
|
3624
|
-
//#endregion
|
|
3625
|
-
//#region src/plugin/rules/react-ui/no-bold-heading.ts
|
|
3626
|
-
const getInlineStyleObjectExpression = (jsxAttribute) => {
|
|
3627
|
-
if (!isNodeOfType(jsxAttribute, "JSXAttribute")) return null;
|
|
3628
|
-
if (!isNodeOfType(jsxAttribute.name, "JSXIdentifier") || jsxAttribute.name.name !== "style") return null;
|
|
3629
|
-
if (!isNodeOfType(jsxAttribute.value, "JSXExpressionContainer")) return null;
|
|
3630
|
-
const expression = jsxAttribute.value.expression;
|
|
3631
|
-
if (!isNodeOfType(expression, "ObjectExpression")) return null;
|
|
3632
|
-
return expression;
|
|
3633
|
-
};
|
|
3634
|
-
const getStylePropertyKeyName = (objectProperty) => {
|
|
3635
|
-
if (!isNodeOfType(objectProperty, "Property")) return null;
|
|
3636
|
-
if (isNodeOfType(objectProperty.key, "Identifier")) return objectProperty.key.name;
|
|
3637
|
-
if (isNodeOfType(objectProperty.key, "Literal") && typeof objectProperty.key.value === "string") return objectProperty.key.value;
|
|
3638
|
-
return null;
|
|
3639
|
-
};
|
|
3640
|
-
const getStylePropertyNumericValue = (objectProperty) => {
|
|
3641
|
-
if (!isNodeOfType(objectProperty, "Property")) return null;
|
|
3642
|
-
const valueNode = objectProperty.value;
|
|
3643
|
-
if (!valueNode) return null;
|
|
3644
|
-
if (isNodeOfType(valueNode, "Literal") && typeof valueNode.value === "number") return valueNode.value;
|
|
3645
|
-
if (isNodeOfType(valueNode, "Literal") && typeof valueNode.value === "string") {
|
|
3646
|
-
const parsed = parseFloat(valueNode.value);
|
|
3647
|
-
return Number.isFinite(parsed) ? parsed : null;
|
|
3648
|
-
}
|
|
3649
|
-
return null;
|
|
3650
|
-
};
|
|
3651
|
-
const noBoldHeading = defineRule({
|
|
3652
|
-
id: "design-no-bold-heading",
|
|
3653
|
-
tags: ["design", "test-noise"],
|
|
3654
|
-
severity: "warn",
|
|
3655
|
-
category: "Architecture",
|
|
3656
|
-
recommendation: "Use `font-semibold` (600) or `font-medium` (500) on headings — 700+ crushes letter counter shapes at display sizes",
|
|
3657
|
-
create: (context) => ({ JSXOpeningElement(openingNode) {
|
|
3658
|
-
const tagName = getOpeningElementTagName(openingNode);
|
|
3659
|
-
if (!tagName || !HEADING_TAG_NAMES.has(tagName)) return;
|
|
3660
|
-
const classAttribute = findJsxAttribute(openingNode.attributes ?? [], "className");
|
|
3661
|
-
if (classAttribute) {
|
|
3662
|
-
const classNameLiteral = getClassNameLiteral(classAttribute);
|
|
3663
|
-
if (classNameLiteral) {
|
|
3664
|
-
for (const tailwindWeightToken of HEAVY_HEADING_TAILWIND_WEIGHTS) if (new RegExp(`(?:^|\\s)${tailwindWeightToken}(?:$|\\s|:)`).test(classNameLiteral)) {
|
|
3665
|
-
context.report({
|
|
3666
|
-
node: classAttribute,
|
|
3667
|
-
message: `${tailwindWeightToken} on <${tagName}> crushes counter shapes at display sizes — use font-semibold (600) or font-medium (500)`
|
|
3668
|
-
});
|
|
3669
|
-
return;
|
|
3670
|
-
}
|
|
3671
|
-
}
|
|
3672
|
-
}
|
|
3673
|
-
const styleAttribute = findJsxAttribute(openingNode.attributes ?? [], "style");
|
|
3674
|
-
if (!styleAttribute) return;
|
|
3675
|
-
const styleObject = getInlineStyleObjectExpression(styleAttribute);
|
|
3676
|
-
if (!styleObject) return;
|
|
3677
|
-
for (const objectProperty of styleObject.properties ?? []) {
|
|
3678
|
-
if (getStylePropertyKeyName(objectProperty) !== "fontWeight") continue;
|
|
3679
|
-
const numericWeight = getStylePropertyNumericValue(objectProperty);
|
|
3680
|
-
if (numericWeight !== null && numericWeight >= 700) {
|
|
3681
|
-
context.report({
|
|
3682
|
-
node: objectProperty,
|
|
3683
|
-
message: `fontWeight: ${numericWeight} on <${tagName}> crushes counter shapes at display sizes — use 500 or 600`
|
|
3684
|
-
});
|
|
3685
|
-
return;
|
|
3686
|
-
}
|
|
3687
|
-
}
|
|
3688
|
-
} })
|
|
3689
|
-
});
|
|
3690
|
-
//#endregion
|
|
3691
3599
|
//#region src/plugin/rules/react-ui/utils/is-inside-excluded-typography-ancestor.ts
|
|
3692
3600
|
const isInsideExcludedTypographyAncestor = (jsxTextNode) => {
|
|
3693
3601
|
let cursor = jsxTextNode.parent;
|
|
@@ -3721,6 +3629,19 @@ const noEmDashInJsxText = defineRule({
|
|
|
3721
3629
|
} })
|
|
3722
3630
|
});
|
|
3723
3631
|
//#endregion
|
|
3632
|
+
//#region src/plugin/rules/react-ui/utils/get-class-name-literal.ts
|
|
3633
|
+
const getClassNameLiteral = (classAttribute) => {
|
|
3634
|
+
if (!isNodeOfType(classAttribute, "JSXAttribute")) return null;
|
|
3635
|
+
if (!classAttribute.value) return null;
|
|
3636
|
+
if (isNodeOfType(classAttribute.value, "Literal") && typeof classAttribute.value.value === "string") return classAttribute.value.value;
|
|
3637
|
+
if (isNodeOfType(classAttribute.value, "JSXExpressionContainer")) {
|
|
3638
|
+
const expression = classAttribute.value.expression;
|
|
3639
|
+
if (isNodeOfType(expression, "Literal") && typeof expression.value === "string") return expression.value;
|
|
3640
|
+
if (isNodeOfType(expression, "TemplateLiteral") && expression.quasis?.length === 1) return expression.quasis[0].value?.raw ?? null;
|
|
3641
|
+
}
|
|
3642
|
+
return null;
|
|
3643
|
+
};
|
|
3644
|
+
//#endregion
|
|
3724
3645
|
//#region src/plugin/rules/react-ui/utils/collect-axis-shorthand-pairs.ts
|
|
3725
3646
|
const collectAxisShorthandPairs = (classNameValue, horizontalPattern, verticalPattern) => {
|
|
3726
3647
|
const horizontalValues = /* @__PURE__ */ new Set();
|
|
@@ -29881,20 +29802,6 @@ const reactDoctorRules = [
|
|
|
29881
29802
|
category: "Accessibility"
|
|
29882
29803
|
}
|
|
29883
29804
|
},
|
|
29884
|
-
{
|
|
29885
|
-
key: "react-doctor/design-no-bold-heading",
|
|
29886
|
-
id: "design-no-bold-heading",
|
|
29887
|
-
source: "react-doctor",
|
|
29888
|
-
originallyExternal: false,
|
|
29889
|
-
framework: "global",
|
|
29890
|
-
category: "Architecture",
|
|
29891
|
-
severity: "warn",
|
|
29892
|
-
rule: {
|
|
29893
|
-
...noBoldHeading,
|
|
29894
|
-
framework: "global",
|
|
29895
|
-
category: "Architecture"
|
|
29896
|
-
}
|
|
29897
|
-
},
|
|
29898
29805
|
{
|
|
29899
29806
|
key: "react-doctor/design-no-em-dash-in-jsx-text",
|
|
29900
29807
|
id: "design-no-em-dash-in-jsx-text",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oxlint-plugin-react-doctor",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
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",
|