| var falseFunc = require("boolbase").falseFunc; | 
|   | 
| //https://github.com/slevithan/XRegExp/blob/master/src/xregexp.js#L469 | 
| var reChars = /[-[\]{}()*+?.,\\^$|#\s]/g; | 
|   | 
| /* | 
|     attribute selectors | 
| */ | 
| var attributeRules = { | 
|     __proto__: null, | 
|     equals: function(next, data, options) { | 
|         var name = data.name; | 
|         var value = data.value; | 
|         var adapter = options.adapter; | 
|   | 
|         if (data.ignoreCase) { | 
|             value = value.toLowerCase(); | 
|   | 
|             return function equalsIC(elem) { | 
|                 var attr = adapter.getAttributeValue(elem, name); | 
|                 return attr != null && attr.toLowerCase() === value && next(elem); | 
|             }; | 
|         } | 
|   | 
|         return function equals(elem) { | 
|             return adapter.getAttributeValue(elem, name) === value && next(elem); | 
|         }; | 
|     }, | 
|     hyphen: function(next, data, options) { | 
|         var name = data.name; | 
|         var value = data.value; | 
|         var len = value.length; | 
|         var adapter = options.adapter; | 
|   | 
|         if (data.ignoreCase) { | 
|             value = value.toLowerCase(); | 
|   | 
|             return function hyphenIC(elem) { | 
|                 var attr = adapter.getAttributeValue(elem, name); | 
|                 return ( | 
|                     attr != null && | 
|                     (attr.length === len || attr.charAt(len) === "-") && | 
|                     attr.substr(0, len).toLowerCase() === value && | 
|                     next(elem) | 
|                 ); | 
|             }; | 
|         } | 
|   | 
|         return function hyphen(elem) { | 
|             var attr = adapter.getAttributeValue(elem, name); | 
|             return ( | 
|                 attr != null && | 
|                 attr.substr(0, len) === value && | 
|                 (attr.length === len || attr.charAt(len) === "-") && | 
|                 next(elem) | 
|             ); | 
|         }; | 
|     }, | 
|     element: function(next, data, options) { | 
|         var name = data.name; | 
|         var value = data.value; | 
|         var adapter = options.adapter; | 
|   | 
|         if (/\s/.test(value)) { | 
|             return falseFunc; | 
|         } | 
|   | 
|         value = value.replace(reChars, "\\$&"); | 
|   | 
|         var pattern = "(?:^|\\s)" + value + "(?:$|\\s)", | 
|             flags = data.ignoreCase ? "i" : "", | 
|             regex = new RegExp(pattern, flags); | 
|   | 
|         return function element(elem) { | 
|             var attr = adapter.getAttributeValue(elem, name); | 
|             return attr != null && regex.test(attr) && next(elem); | 
|         }; | 
|     }, | 
|     exists: function(next, data, options) { | 
|         var name = data.name; | 
|         var adapter = options.adapter; | 
|   | 
|         return function exists(elem) { | 
|             return adapter.hasAttrib(elem, name) && next(elem); | 
|         }; | 
|     }, | 
|     start: function(next, data, options) { | 
|         var name = data.name; | 
|         var value = data.value; | 
|         var len = value.length; | 
|         var adapter = options.adapter; | 
|   | 
|         if (len === 0) { | 
|             return falseFunc; | 
|         } | 
|   | 
|         if (data.ignoreCase) { | 
|             value = value.toLowerCase(); | 
|   | 
|             return function startIC(elem) { | 
|                 var attr = adapter.getAttributeValue(elem, name); | 
|                 return attr != null && attr.substr(0, len).toLowerCase() === value && next(elem); | 
|             }; | 
|         } | 
|   | 
|         return function start(elem) { | 
|             var attr = adapter.getAttributeValue(elem, name); | 
|             return attr != null && attr.substr(0, len) === value && next(elem); | 
|         }; | 
|     }, | 
|     end: function(next, data, options) { | 
|         var name = data.name; | 
|         var value = data.value; | 
|         var len = -value.length; | 
|         var adapter = options.adapter; | 
|   | 
|         if (len === 0) { | 
|             return falseFunc; | 
|         } | 
|   | 
|         if (data.ignoreCase) { | 
|             value = value.toLowerCase(); | 
|   | 
|             return function endIC(elem) { | 
|                 var attr = adapter.getAttributeValue(elem, name); | 
|                 return attr != null && attr.substr(len).toLowerCase() === value && next(elem); | 
|             }; | 
|         } | 
|   | 
|         return function end(elem) { | 
|             var attr = adapter.getAttributeValue(elem, name); | 
|             return attr != null && attr.substr(len) === value && next(elem); | 
|         }; | 
|     }, | 
|     any: function(next, data, options) { | 
|         var name = data.name; | 
|         var value = data.value; | 
|         var adapter = options.adapter; | 
|   | 
|         if (value === "") { | 
|             return falseFunc; | 
|         } | 
|   | 
|         if (data.ignoreCase) { | 
|             var regex = new RegExp(value.replace(reChars, "\\$&"), "i"); | 
|   | 
|             return function anyIC(elem) { | 
|                 var attr = adapter.getAttributeValue(elem, name); | 
|                 return attr != null && regex.test(attr) && next(elem); | 
|             }; | 
|         } | 
|   | 
|         return function any(elem) { | 
|             var attr = adapter.getAttributeValue(elem, name); | 
|             return attr != null && attr.indexOf(value) >= 0 && next(elem); | 
|         }; | 
|     }, | 
|     not: function(next, data, options) { | 
|         var name = data.name; | 
|         var value = data.value; | 
|         var adapter = options.adapter; | 
|   | 
|         if (value === "") { | 
|             return function notEmpty(elem) { | 
|                 return !!adapter.getAttributeValue(elem, name) && next(elem); | 
|             }; | 
|         } else if (data.ignoreCase) { | 
|             value = value.toLowerCase(); | 
|   | 
|             return function notIC(elem) { | 
|                 var attr = adapter.getAttributeValue(elem, name); | 
|                 return attr != null && attr.toLowerCase() !== value && next(elem); | 
|             }; | 
|         } | 
|   | 
|         return function not(elem) { | 
|             return adapter.getAttributeValue(elem, name) !== value && next(elem); | 
|         }; | 
|     } | 
| }; | 
|   | 
| module.exports = { | 
|     compile: function(next, data, options) { | 
|         if (options && options.strict && (data.ignoreCase || data.action === "not")) { | 
|             throw new Error("Unsupported attribute selector"); | 
|         } | 
|         return attributeRules[data.action](next, data, options); | 
|     }, | 
|     rules: attributeRules | 
| }; |