-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
set up aphrodite add style lint rule
- Loading branch information
1 parent
717bfea
commit ddb29e9
Showing
5 changed files
with
218 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
packages/eslint-plugin-khan/docs/aphrodite-add-style-variable-name.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Naming convention for addStyle variable (aphrodite-add-style-variable-name) | ||
|
||
The variable name when using `addStyle` should be the same as the tag argument in the format `styledTag`. | ||
|
||
This is useful so that Aphrodite styled elements can be mapped to HTML elements for static code analysis. For example, if the addStyle variables are consistently named, we are able to provide custom component mapping to `eslint-plugin-jsx-a11y` so that it can identify linting issues based on the underlying HTML tag. | ||
|
||
## Rule Details | ||
|
||
The following are considered warnings: | ||
|
||
```ts | ||
const div = addStyle("div"); | ||
``` | ||
|
||
```ts | ||
const foo = addStyle("span"); | ||
``` | ||
|
||
```ts | ||
const container = addStyle("div"); | ||
``` | ||
|
||
The following are not considered warnings: | ||
|
||
```ts | ||
const styledDiv = addStyle("div"); | ||
``` | ||
|
||
```ts | ||
const styledSpan = addStyle("span"); | ||
``` | ||
|
||
```ts | ||
const styledImg = addStyle("img"); | ||
``` |
73 changes: 73 additions & 0 deletions
73
packages/eslint-plugin-khan/src/rules/aphrodite-add-style-variable-name.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import {TSESTree, ESLintUtils} from "@typescript-eslint/utils"; | ||
|
||
import type {MyPluginDocs} from "../types"; | ||
|
||
const createRule = ESLintUtils.RuleCreator<MyPluginDocs>( | ||
(name) => | ||
`https://github.com/Khan/wonder-stuff/blob/main/packages/eslint-plugin-khan/docs/${name}.md`, | ||
); | ||
|
||
type Options = []; | ||
type MessageIds = "errorString"; | ||
|
||
const message = `Variable name "{{ variableName }}" does not match tag name "{{ tagName }}". Variable name should be "{{ expectedName }}"`; | ||
|
||
export default createRule<Options, MessageIds>({ | ||
name: "aphrodite-add-style-variable-name", | ||
meta: { | ||
docs: { | ||
description: | ||
"Ensure variable names match the tag name passed to addStyle and follow the format: styledTag (ie. styledDiv, styledImg)", | ||
recommended: true, | ||
}, | ||
messages: { | ||
errorString: message, | ||
}, | ||
schema: [], | ||
type: "problem", | ||
}, | ||
defaultOptions: [], | ||
create(context) { | ||
return { | ||
VariableDeclarator(node: TSESTree.VariableDeclarator) { | ||
// Check if addStyle is being called | ||
if ( | ||
node.init && | ||
node.init.type === "CallExpression" && | ||
node.init.callee.type === "Identifier" && | ||
node.init.callee.name === "addStyle" | ||
) { | ||
// Get variable name for the addStyle return value | ||
const variableName = | ||
node.id.type === "Identifier" ? node.id.name : null; | ||
|
||
// Get the tag name that was passed into addStyle | ||
const firstArg = node.init.arguments[0]; | ||
if ( | ||
firstArg && | ||
firstArg.type === "Literal" && | ||
typeof firstArg.value === "string" | ||
) { | ||
const tagName = firstArg.value; | ||
const expectedName = `styled${tagName | ||
.charAt(0) | ||
.toUpperCase()}${tagName.slice(1)}`; | ||
|
||
// Check if the variable name matches the expected pattern | ||
if (variableName !== expectedName) { | ||
context.report({ | ||
node: node.id, | ||
messageId: "errorString", | ||
data: { | ||
variableName, | ||
tagName, | ||
expectedName, | ||
}, | ||
}); | ||
} | ||
} | ||
} | ||
}, | ||
}; | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
107 changes: 107 additions & 0 deletions
107
packages/eslint-plugin-khan/test/rules/aphrodite-add-style-variable-name.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import {RuleTester} from "@typescript-eslint/rule-tester"; | ||
|
||
import {rules} from "../../src/index"; | ||
|
||
const ruleTester = new RuleTester({ | ||
languageOptions: { | ||
parserOptions: { | ||
ecmaVersion: 6, | ||
sourceType: "module", | ||
ecmaFeatures: {}, | ||
}, | ||
}, | ||
linterOptions: { | ||
// NOTE(kevinb): Avoids 'TypeError: Expected a Boolean' error | ||
// when running the tests. | ||
reportUnusedDisableDirectives: true, | ||
}, | ||
}); | ||
|
||
const ruleName = "aphrodite-add-style-variable-name"; | ||
const rule = rules[ruleName]; | ||
|
||
ruleTester.run(ruleName, rule, { | ||
valid: [ | ||
{ | ||
code: `const styledDiv = addStyle("div")`, | ||
}, | ||
{ | ||
code: `const styledSpan = addStyle("span")`, | ||
}, | ||
{ | ||
code: `const styledImg = addStyle("img")`, | ||
}, | ||
{ | ||
code: `const styledUl = addStyle("ul")`, | ||
}, | ||
{ | ||
code: `const styledOl = addStyle("ol")`, | ||
}, | ||
{ | ||
code: `const styledLi = addStyle("li")`, | ||
}, | ||
{ | ||
code: `const styledButton = addStyle("button")`, | ||
}, | ||
{ | ||
code: `const styledP = addStyle("p")`, | ||
}, | ||
{ | ||
code: `const styledSup = addStyle("sup")`, | ||
}, | ||
], | ||
invalid: [ | ||
{ | ||
code: `const foo = addStyle("div")`, | ||
errors: [ | ||
{ | ||
messageId: "errorString", | ||
data: { | ||
variableName: "foo", | ||
tagName: "div", | ||
expectedName: "styledDiv", | ||
}, | ||
}, | ||
], | ||
}, | ||
{ | ||
code: `const div = addStyle("div")`, | ||
errors: [ | ||
{ | ||
messageId: "errorString", | ||
data: { | ||
variableName: "div", | ||
tagName: "div", | ||
expectedName: "styledDiv", | ||
}, | ||
}, | ||
], | ||
}, | ||
{ | ||
code: `const span = addStyle("span")`, | ||
errors: [ | ||
{ | ||
messageId: "errorString", | ||
data: { | ||
variableName: "span", | ||
tagName: "span", | ||
expectedName: "styledSpan", | ||
}, | ||
}, | ||
], | ||
}, | ||
{ | ||
code: `const p = addStyle("p")`, | ||
errors: [ | ||
{ | ||
messageId: "errorString", | ||
data: { | ||
variableName: "p", | ||
tagName: "p", | ||
expectedName: "styledP", | ||
}, | ||
}, | ||
], | ||
}, | ||
], | ||
}); |