Skip to content

Commit

Permalink
fix(no-invalid-selectors): stop false-positives (html, non-select calls)
Browse files Browse the repository at this point in the history
  • Loading branch information
david-at-frog committed Sep 24, 2019
1 parent 6f62e86 commit 3f60624
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 48 deletions.
126 changes: 78 additions & 48 deletions lib/rules/no-invalid-selectors.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
const { isJQuery, detectJQueryCollections, resolve } = require('../util')
const CSSselect = require('css-select')

const selectorMethods = [
"add",
"addBack",
"children",
"closest",
"filter",
"find",
"has",
"is",
"next",
"nextAll",
"nextUntil",
"not",
"parent",
"parents",
"parentsUntil",
"prev",
"prevAll",
"prevUntil",
"siblings"
]

const jQueryPseudoClasses = [
'animated',
'button',
Expand Down Expand Up @@ -31,10 +53,6 @@ const jQueryPseudoFunctions = [
'lt'
]

const jQueryPseudoAttributeComparators = [
'!='
]

const otherPseudoCorrections = [
'hover'
]
Expand Down Expand Up @@ -78,58 +96,70 @@ module.exports = {
create: detectJQueryCollections((
context,
{ foundAPositiveMatch }
) => ({
"CallExpression:exit": node => {
const optionsObject = {
...{ allowJQueryExtensions: false },
...(context.options.filter(option => typeof option === 'object')[0] || {})
}
) => {
const optionsObject = {
...{allowJQueryExtensions: false},
...(context.options.filter(option => typeof option === 'object')[0] || {})
}

const { allowJQueryExtensions } = optionsObject
const { allowJQueryExtensions } = optionsObject

if (
!(isJQuery(node.callee) || foundAPositiveMatch(node)) ||
!Array.isArray(node.arguments) ||
node.arguments.length < 1
) {
return
}
return ({
"CallExpression:exit": node => {
if (
!(isJQuery(node.callee) || foundAPositiveMatch(node)) ||
!Array.isArray(node.arguments) ||
node.arguments.length < 1
) {
return
}

const maybeSelector = resolve()(node.arguments[0], context)
if (
node.callee.type === "MemberExpression" &&
!selectorMethods.includes(node.callee.property.name)
) {
return
}

if (typeof maybeSelector !== "string") {
return
}
const maybeSelector = resolve()(node.arguments[0], context)

const selector = maybeSelector
let correctedSelector = selector
if (
typeof maybeSelector !== "string" ||
maybeSelector.indexOf('<') === 0
) {
return
}

if (allowJQueryExtensions) {
jQueryPseudoFunctions.forEach(pseudoFunc => {
correctedSelector = correctedSelector.replace(RegExp(`/:${pseudoFunc}\\b/`, "g"), ':not')
})
jQueryPseudoClasses.forEach(pseudoClass => {
correctedSelector = correctedSelector.replace(RegExp(`:${pseudoClass}\\b`, "g"), ':empty')
})
}
const selector = maybeSelector
let correctedSelector = selector

otherPseudoCorrections.forEach(pseudoClass => {
correctedSelector = correctedSelector.replace(RegExp(`:${pseudoClass}\\b`, "g"), ':empty')
})
if (allowJQueryExtensions) {
jQueryPseudoFunctions.forEach(pseudoFunc => {
correctedSelector = correctedSelector.replace(RegExp(`/:${pseudoFunc}\\b/`, "g"), ':not')
})
jQueryPseudoClasses.forEach(pseudoClass => {
correctedSelector = correctedSelector.replace(RegExp(`:${pseudoClass}\\b`, "g"), ':empty')
})
}

try {
CSSselect.compile(correctedSelector)
return;
} catch (error) {
context.report({
node: node.arguments[0],
data: {
method: isJQuery(node.callee) ? "$()" : `$.fn.${node.callee.property.name}()`,
selector: selector
},
messageId: 'no-invalid-selectors'
otherPseudoCorrections.forEach(pseudoClass => {
correctedSelector = correctedSelector.replace(RegExp(`:${pseudoClass}\\b`, "g"), ':empty')
})

try {
CSSselect.compile(correctedSelector)
return;
} catch (error) {
context.report({
node: node.arguments[0],
data: {
method: isJQuery(node.callee) ? "$()" : `$.fn.${node.callee.property.name}()`,
selector: selector
},
messageId: 'no-invalid-selectors'
})
}
}
}
}))
})
})
}
6 changes: 6 additions & 0 deletions test/lib/rules/jquery-compat/no-invalid-selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ ruleTester.run('jquery-compat/no-invalid-selectors', rules['no-invalid-selectors
allowJQueryExtensions: false
}
]
},
{
code: `$foo.append('div:first')`
},
{
code: `$('<span>div:first</span>')`
}
]),
invalid: selectorMethods
Expand Down

0 comments on commit 3f60624

Please sign in to comment.