Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: custom ESLint rule to disable sorting for ref attribute to keep it as last property in JSX to ensure it is up-to-date #7669

Merged
merged 22 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
be5b936
chore: custom ESLint rule to disable sorting for ref attribute to kee…
Elijbet Sep 3, 2023
b7fe662
Merge branch 'main' into elijbet/7659-custom-eslint-rule-enforce-ref-…
Elijbet Sep 6, 2023
92955a7
Merge branch 'main' into elijbet/7659-custom-eslint-rule-enforce-ref-…
Elijbet Oct 10, 2023
5e73981
Merge branch 'main' into elijbet/7659-custom-eslint-rule-enforce-ref-…
Elijbet Oct 11, 2023
3ea96d1
testing against a good and bad case
Elijbet Oct 11, 2023
90b2cde
type JSXAttribute, JSXSpreadAttribute, JSXOpeningElement
Elijbet Oct 11, 2023
612020c
Merge branch 'main' into elijbet/7659-custom-eslint-rule-enforce-ref-…
Elijbet Oct 11, 2023
1541324
cleanup
Elijbet Oct 11, 2023
8512f83
Merge branch 'main' into elijbet/7659-custom-eslint-rule-enforce-ref-…
Elijbet Oct 11, 2023
f9d5bd5
reword and cleanup
Elijbet Oct 11, 2023
0cd6bbc
config and docs
Elijbet Oct 12, 2023
a151897
Merge branch 'main' into elijbet/7659-custom-eslint-rule-enforce-ref-…
Elijbet Oct 12, 2023
f2ea7cc
Merge branch 'main' into elijbet/7659-custom-eslint-rule-enforce-ref-…
Elijbet Oct 12, 2023
c3b02aa
README.md
Elijbet Oct 12, 2023
ec1361b
Merge branch 'main' into elijbet/7659-custom-eslint-rule-enforce-ref-…
Elijbet Oct 12, 2023
99238fa
cleanup
Elijbet Oct 12, 2023
3ebeb9e
Merge branch 'main' into elijbet/7659-custom-eslint-rule-enforce-ref-…
Elijbet Oct 29, 2023
e9b6b54
Merge branch 'main' into elijbet/7659-custom-eslint-rule-enforce-ref-…
Elijbet Nov 2, 2023
6376f32
Provide more context to README, rule description, doc file, error mes…
Elijbet Nov 2, 2023
5a50fc6
minor tweaks in doc wording
Elijbet Nov 2, 2023
e81d735
typo
Elijbet Nov 2, 2023
74a9b65
Merge branch 'main' into elijbet/7659-custom-eslint-rule-enforce-ref-…
Elijbet Nov 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Rule } from "eslint";
import type { JSXAttribute, JSXSpreadAttribute, JSXOpeningElement } from "@babel/types";

const rule: Rule.RuleModule = {
meta: {
docs: {
description: "Ensure that the ref attribute is placed as the last property in JSX elements to keep it up-to-date",
Elijbet marked this conversation as resolved.
Show resolved Hide resolved
category: "Best Practices",
recommended: true,
},
fixable: "code",
schema: [],
type: "problem",
},

// https://unpkg.com/browse/@babel/[email protected]/lib/index.d.ts
Elijbet marked this conversation as resolved.
Show resolved Hide resolved
// export interface JSXAttribute extends BaseNode {
// type: "JSXAttribute";
// name: JSXIdentifier | JSXNamespacedName;
// value: JSXElement | JSXFragment | StringLiteral | JSXExpressionContainer | null;
// }

create(context): Rule.RuleListener {
return {
JSXIdentifier(node) {
const openingElement = node.parent as JSXOpeningElement;
if (openingElement.type === "JSXOpeningElement") {
const attributes: string[] = [];

openingElement.attributes.forEach((attr: JSXAttribute | JSXSpreadAttribute) => {
if (attr.type === "JSXAttribute" && attr.name?.type === "JSXIdentifier") {
attributes.push(attr.name.name);
}
});

const refAttribute = attributes.find((attr: string) => attr === "ref");

console.log("refAttribute", refAttribute);
Elijbet marked this conversation as resolved.
Show resolved Hide resolved

if (refAttribute && attributes.indexOf(refAttribute) !== attributes.length - 1) {
context.report({
node,
message: `The "ref" attribute should be placed as the last property in JSX elements.`,
Elijbet marked this conversation as resolved.
Show resolved Hide resolved
});
}
}
},
};
},
};

export default rule;
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// @ts-nocheck
@Component({ tag: "sample-tag" })
export class SampleTag {
render() {
return (
<Host>
<div
class="some-class"
Elijbet marked this conversation as resolved.
Show resolved Hide resolved
id={`${guid}-element`}
onClick={() => {
/* click! */
}}
ref={(el: HTMLDivElement): void => {
/* refEl */
}}
>
test
</div>
</Host>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import rule from "../../../../src/rules/enforce-ref-last-prop";
import { ruleTester } from "stencil-eslint-core";
import * as path from "path";
import * as fs from "fs";

const projectPath = path.resolve(__dirname, "../../../tsconfig.json");

describe("enforce-ref-last-prop rule", () => {
const files = {
good: path.resolve(__dirname, "enforce-ref-last-prop.good.tsx"),
wrong: path.resolve(__dirname, "enforce-ref-last-prop.wrong.tsx"),
};
ruleTester(projectPath).run("enforce-ref-last-prop", rule, {
valid: [
{
code: fs.readFileSync(files.good, "utf8"),
filename: files.good,
},
],

invalid: [
{
code: fs.readFileSync(files.wrong, "utf8"),
filename: files.wrong,
errors: 1,
},
],
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// @ts-nocheck
@Component({ tag: "sample-tag" })
export class SampleTag {
render() {
return (
<Host>
<div
ref={(el: HTMLDivElement): void => {
/* refEl */
}}
class="some-class"
id={`${guid}-element`}
onClick={() => {
/* click! */
}}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tabIndex should go here to match the good case.

>
test
</div>
</Host>
);
}
}
Loading