-
Notifications
You must be signed in to change notification settings - Fork 833
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add custom Emotion css eslint plugin for non-logical properties
- Loading branch information
Showing
4 changed files
with
135 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
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
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,63 @@ | ||
module.exports = { | ||
meta: { | ||
type: 'problem', | ||
docs: { | ||
description: 'Enforce using CSS logical properties in our Emotion CSS', | ||
}, | ||
}, | ||
create: function (context) { | ||
return { | ||
TaggedTemplateExpression(node) { | ||
if (node.tag?.name !== 'css') return; // We only want to check Emotion css`` template literals | ||
|
||
const lintNonLogicalProperty = (property) => { | ||
context.report({ | ||
node, | ||
message: `Prefer the CSS logical property for ${property} - @see src/global_styling/functions/logicals.ts`, | ||
}); | ||
}; | ||
|
||
const templateContents = node.quasi?.quasis || []; | ||
templateContents.forEach((cssNode) => { | ||
const stringLiteral = cssNode?.value?.raw; | ||
if (!stringLiteral) return; | ||
|
||
const propertiesToFlag = { | ||
// sizing - catches min/max as well | ||
width: 'width:', | ||
height: /(?<!line-)height:/, | ||
// positioning - catches padding/margin/border sides as well | ||
top: 'top:', | ||
right: 'right:', | ||
bottom: 'bottom:', | ||
left: 'left:', | ||
// border side specific properties | ||
'border sides': /border-(top|right|bottom|left)-(color|style|width):/, | ||
// text-align | ||
'text-align left': 'text-align: left', | ||
'text-align right': 'text-align: right', | ||
// overflow | ||
'overflow-x': 'overflow-x:', | ||
'overflow-y': 'overflow-y:', | ||
}; | ||
const properties = Object.values(propertiesToFlag); | ||
const propertyNames = Object.keys(propertiesToFlag); | ||
|
||
for (let i = 0; i < properties.length; i++) { | ||
const property = properties[i]; | ||
|
||
if (typeof property === 'string') { | ||
if (stringLiteral.includes(property)) { | ||
return lintNonLogicalProperty(propertyNames[i]); | ||
} | ||
} else { | ||
if (stringLiteral.match(property)) { | ||
return lintNonLogicalProperty(propertyNames[i]); | ||
} | ||
} | ||
} | ||
}); | ||
}, | ||
}; | ||
}, | ||
}; |
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,70 @@ | ||
import rule from './css_logical_properties.js'; | ||
const RuleTester = require('eslint').RuleTester; | ||
|
||
const ruleTester = new RuleTester({ | ||
parser: require.resolve('babel-eslint'), | ||
}); | ||
|
||
const valid = [ | ||
`css\` | ||
inline-size: 50px; | ||
inline-start-end: 10px; | ||
\``, | ||
'`width: 50px; left: 10px;`', // This is not in css``, so it's fine | ||
'css`line-height: 20px`', // Make sure we don't incorrectly catch line-height | ||
]; | ||
|
||
const getErrorMessage = (property) => | ||
`Prefer the CSS logical property for ${property} - @see src/global_styling/functions/logicals.ts`; | ||
|
||
const invalid = [ | ||
{ | ||
code: 'css`height: 50px;`', | ||
errors: [{ message: getErrorMessage('height') }], | ||
}, | ||
{ | ||
code: 'css`max-height: 50px;`', | ||
errors: [{ message: getErrorMessage('height') }], | ||
}, | ||
{ | ||
code: 'css`width: 50px;`', | ||
errors: [{ message: getErrorMessage('width') }], | ||
}, | ||
{ | ||
code: 'css`min-width: 50px;`', | ||
errors: [{ message: getErrorMessage('width') }], | ||
}, | ||
{ | ||
code: 'css`top: 0;`', | ||
errors: [{ message: getErrorMessage('top') }], | ||
}, | ||
{ | ||
code: 'css`padding-right: 0;`', | ||
errors: [{ message: getErrorMessage('right') }], | ||
}, | ||
{ | ||
code: 'css`margin-bottom: 0;`', | ||
errors: [{ message: getErrorMessage('bottom') }], | ||
}, | ||
{ | ||
code: 'css`border-left: 1px solid green;`', | ||
errors: [{ message: getErrorMessage('left') }], | ||
}, | ||
{ | ||
code: 'css`border-left-color: red;`', | ||
errors: [{ message: getErrorMessage('border sides') }], | ||
}, | ||
{ | ||
code: 'css`text-align: left;`', | ||
errors: [{ message: getErrorMessage('text-align left') }], | ||
}, | ||
{ | ||
code: 'css`overflow-y: hidden;`', | ||
errors: [{ message: getErrorMessage('overflow-y') }], | ||
}, | ||
]; | ||
|
||
ruleTester.run('css_logical_properties', rule, { | ||
valid, | ||
invalid, | ||
}); |