Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Prevent adjacent inline elements not separated by whitespace.
- Loading branch information
Showing
3 changed files
with
159 additions
and
1 deletion.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/** | ||
* @fileoverview Prevent adjacent inline elements not separated by whitespace. | ||
* @author Sean Hayes | ||
*/ | ||
'use strict'; | ||
|
||
// ------------------------------------------------------------------------------ | ||
// Helpers | ||
// ------------------------------------------------------------------------------ | ||
|
||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements | ||
var inlineNames = ('a b big i small tt abbr acronym cite code dfn em kbd strong' + | ||
' samp time var bdo br img map object q script span sub sup button input' + | ||
' label select textarea').split(' '); | ||
var nbsp = ' '; | ||
|
||
function isInline(node) { | ||
if (node.type === 'Literal') { | ||
// Regular whitespace will be removed. | ||
var raw = node.raw.trim(); | ||
// To properly separate inline elements, each end of the literal will need | ||
// a . | ||
return !(raw.startsWith(nbsp) && raw.endsWith(nbsp)); | ||
} | ||
if (node.type !== 'JSXElement') { | ||
// Skip. | ||
return false; | ||
} | ||
var name = node.openingElement.name.name; | ||
if (inlineNames.indexOf(name) > -1) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
var ERROR = 'Child elements which render as inline HTML elements should be' + | ||
' separated by a space or wrapped in block level elements.'; | ||
|
||
// ------------------------------------------------------------------------------ | ||
// Rule Definition | ||
// ------------------------------------------------------------------------------ | ||
|
||
module.exports = { | ||
ERROR: ERROR, | ||
meta: { | ||
docs: { | ||
description: 'Prevent adjacent inline elements not separated by whitespace.', | ||
category: 'Best Practices', | ||
recommended: false | ||
}, | ||
schema: [] | ||
}, | ||
create: function(context) { | ||
function validate(node) { | ||
var currentIsInline = false; | ||
var previousIsInline = false; | ||
for (var i = 0; i < node.children.length; i++) { | ||
currentIsInline = isInline(node.children[i]); | ||
if (previousIsInline && currentIsInline) { | ||
context.report({ | ||
node: node, | ||
message: ERROR | ||
}); | ||
return; | ||
} | ||
previousIsInline = currentIsInline; | ||
} | ||
|
||
} | ||
return { | ||
JSXElement: function(node) { | ||
validate(node); | ||
}, | ||
CallExpression: function(node) { | ||
validate(node); | ||
} | ||
}; | ||
} | ||
}; |
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,78 @@ | ||
/** | ||
* @fileoverview Tests for no-adjacent-inline-elements | ||
* @author Sean Hayes | ||
*/ | ||
|
||
'use strict'; | ||
|
||
// ----------------------------------------------------------------------------- | ||
// Requirements | ||
// ----------------------------------------------------------------------------- | ||
|
||
var rule = require('../../../lib/rules/no-adjacent-inline-elements'); | ||
var RuleTester = require('eslint').RuleTester; | ||
|
||
var ERROR = rule.ERROR; | ||
|
||
var parserOptions = { | ||
ecmaVersion: 6, | ||
ecmaFeatures: { | ||
experimentalObjectRestSpread: true, | ||
jsx: true | ||
} | ||
}; | ||
|
||
// ----------------------------------------------------------------------------- | ||
// Tests | ||
// ----------------------------------------------------------------------------- | ||
|
||
var ruleTester = new RuleTester(); | ||
ruleTester.run('no-adjacent-inline-elements', rule, { | ||
valid: [ | ||
{ | ||
code: '<div />;', | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: '<div><div></div><div></div></div>;', | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: '<div><p></p><div></div></div>;', | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: '<div><p></p><a></a></div>;', | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: '<div><a></a> <a></a></div>;', | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: '<div><a></a> some text <a></a></div>;', | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: '<div><ul><li><a></a></li><li><a></a></li></ul></div>;', | ||
parserOptions: parserOptions | ||
} | ||
], | ||
invalid: [ | ||
{ | ||
code: '<div><a></a><a></a></div>;', | ||
errors: [{message: ERROR}], | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: '<div><a></a><span></span></div>;', | ||
errors: [{message: ERROR}], | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: '<div><a></a> some text <a></a></div>;', | ||
errors: [{message: ERROR}], | ||
parserOptions: parserOptions | ||
} | ||
] | ||
}); |