mirror of
https://github.com/atom/atom.git
synced 2026-04-28 03:01:47 -04:00
Use clear-cut library for specificity
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
"dependencies": {
|
||||
"async": "0.2.6",
|
||||
"bootstrap": "git://github.com/twbs/bootstrap.git#v3.0.0",
|
||||
"clear-cut": "0.1.0",
|
||||
"coffee-script": "1.6.2",
|
||||
"coffeestack": "0.6.0",
|
||||
"emissary": "0.6.0",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
_ = require 'underscore-plus'
|
||||
fsUtils = require './fs-utils'
|
||||
|
||||
Specificity = require '../vendor/specificity'
|
||||
{specificity} = require 'clear-cut'
|
||||
PEG = require 'pegjs'
|
||||
|
||||
### Internal ###
|
||||
@@ -19,7 +19,7 @@ class BindingSet
|
||||
|
||||
constructor: (selector, commandsByKeystrokes, @index, @name) ->
|
||||
BindingSet.parser ?= PEG.buildParser(fsUtils.read(require.resolve './keystroke-pattern.pegjs'))
|
||||
@specificity = Specificity(selector)
|
||||
@specificity = specificity(selector)
|
||||
@selector = selector.replace(/!important/g, '')
|
||||
@commandsByKeystrokes = @normalizeCommandsByKeystrokes(commandsByKeystrokes)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
_ = require 'underscore-plus'
|
||||
Specificity = require '../vendor/specificity'
|
||||
{specificity} = require 'clear-cut'
|
||||
{$, $$} = require './space-pen-extensions'
|
||||
fsUtils = require './fs-utils'
|
||||
{Emitter} = require 'emissary'
|
||||
@@ -76,7 +76,7 @@ class Syntax
|
||||
name: name
|
||||
selector: selector,
|
||||
properties: properties,
|
||||
specificity: Specificity(selector),
|
||||
specificity: specificity(selector),
|
||||
index: @scopedPropertiesIndex++
|
||||
)
|
||||
|
||||
|
||||
232
vendor/slick.js
vendored
232
vendor/slick.js
vendored
@@ -1,232 +0,0 @@
|
||||
// changed at the bottom to export the Slick object
|
||||
|
||||
/*
|
||||
---
|
||||
name: Slick.Parser
|
||||
description: Standalone CSS3 Selector parser
|
||||
provides: Slick.Parser
|
||||
...
|
||||
*/
|
||||
|
||||
;(function(){
|
||||
|
||||
var parsed,
|
||||
separatorIndex,
|
||||
combinatorIndex,
|
||||
reversed,
|
||||
cache = {},
|
||||
reverseCache = {},
|
||||
reUnescape = /\\/g;
|
||||
|
||||
var parse = function(expression, isReversed){
|
||||
if (expression == null) return null;
|
||||
if (expression.Slick === true) return expression;
|
||||
expression = ('' + expression).replace(/^\s+|\s+$/g, '');
|
||||
reversed = !!isReversed;
|
||||
var currentCache = (reversed) ? reverseCache : cache;
|
||||
if (currentCache[expression]) return currentCache[expression];
|
||||
parsed = {
|
||||
Slick: true,
|
||||
expressions: [],
|
||||
raw: expression,
|
||||
reverse: function(){
|
||||
return parse(this.raw, true);
|
||||
}
|
||||
};
|
||||
separatorIndex = -1;
|
||||
while (expression != (expression = expression.replace(regexp, parser)));
|
||||
parsed.length = parsed.expressions.length;
|
||||
return currentCache[parsed.raw] = (reversed) ? reverse(parsed) : parsed;
|
||||
};
|
||||
|
||||
var reverseCombinator = function(combinator){
|
||||
if (combinator === '!') return ' ';
|
||||
else if (combinator === ' ') return '!';
|
||||
else if ((/^!/).test(combinator)) return combinator.replace(/^!/, '');
|
||||
else return '!' + combinator;
|
||||
};
|
||||
|
||||
var reverse = function(expression){
|
||||
var expressions = expression.expressions;
|
||||
for (var i = 0; i < expressions.length; i++){
|
||||
var exp = expressions[i];
|
||||
var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combinator)};
|
||||
|
||||
for (var j = 0; j < exp.length; j++){
|
||||
var cexp = exp[j];
|
||||
if (!cexp.reverseCombinator) cexp.reverseCombinator = ' ';
|
||||
cexp.combinator = cexp.reverseCombinator;
|
||||
delete cexp.reverseCombinator;
|
||||
}
|
||||
|
||||
exp.reverse().push(last);
|
||||
}
|
||||
return expression;
|
||||
};
|
||||
|
||||
var escapeRegExp = function(string){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steven Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License
|
||||
return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function(match){
|
||||
return '\\' + match;
|
||||
});
|
||||
};
|
||||
|
||||
var regexp = new RegExp(
|
||||
/*
|
||||
#!/usr/bin/env ruby
|
||||
puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'')
|
||||
__END__
|
||||
"(?x)^(?:\
|
||||
\\s* ( , ) \\s* # Separator \n\
|
||||
| \\s* ( <combinator>+ ) \\s* # Combinator \n\
|
||||
| ( \\s+ ) # CombinatorChildren \n\
|
||||
| ( <unicode>+ | \\* ) # Tag \n\
|
||||
| \\# ( <unicode>+ ) # ID \n\
|
||||
| \\. ( <unicode>+ ) # ClassName \n\
|
||||
| # Attribute \n\
|
||||
\\[ \
|
||||
\\s* (<unicode1>+) (?: \
|
||||
\\s* ([*^$!~|]?=) (?: \
|
||||
\\s* (?:\
|
||||
([\"']?)(.*?)\\9 \
|
||||
)\
|
||||
) \
|
||||
)? \\s* \
|
||||
\\](?!\\]) \n\
|
||||
| :+ ( <unicode>+ )(?:\
|
||||
\\( (?:\
|
||||
(?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\
|
||||
) \\)\
|
||||
)?\
|
||||
)"
|
||||
*/
|
||||
"^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\([^)]+\\)|[^()]*)+))\\))?)"
|
||||
.replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']')
|
||||
.replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
|
||||
.replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])')
|
||||
);
|
||||
|
||||
function parser(
|
||||
rawMatch,
|
||||
|
||||
separator,
|
||||
combinator,
|
||||
combinatorChildren,
|
||||
|
||||
tagName,
|
||||
id,
|
||||
className,
|
||||
|
||||
attributeKey,
|
||||
attributeOperator,
|
||||
attributeQuote,
|
||||
attributeValue,
|
||||
|
||||
pseudoMarker,
|
||||
pseudoClass,
|
||||
pseudoQuote,
|
||||
pseudoClassQuotedValue,
|
||||
pseudoClassValue
|
||||
){
|
||||
if (separator || separatorIndex === -1){
|
||||
parsed.expressions[++separatorIndex] = [];
|
||||
combinatorIndex = -1;
|
||||
if (separator) return '';
|
||||
}
|
||||
|
||||
if (combinator || combinatorChildren || combinatorIndex === -1){
|
||||
combinator = combinator || ' ';
|
||||
var currentSeparator = parsed.expressions[separatorIndex];
|
||||
if (reversed && currentSeparator[combinatorIndex])
|
||||
currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(combinator);
|
||||
currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'};
|
||||
}
|
||||
|
||||
var currentParsed = parsed.expressions[separatorIndex][combinatorIndex];
|
||||
|
||||
if (tagName){
|
||||
currentParsed.tag = tagName.replace(reUnescape, '');
|
||||
|
||||
} else if (id){
|
||||
currentParsed.id = id.replace(reUnescape, '');
|
||||
|
||||
} else if (className){
|
||||
className = className.replace(reUnescape, '');
|
||||
|
||||
if (!currentParsed.classList) currentParsed.classList = [];
|
||||
if (!currentParsed.classes) currentParsed.classes = [];
|
||||
currentParsed.classList.push(className);
|
||||
currentParsed.classes.push({
|
||||
value: className,
|
||||
regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)')
|
||||
});
|
||||
|
||||
} else if (pseudoClass){
|
||||
pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue;
|
||||
pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '') : null;
|
||||
|
||||
if (!currentParsed.pseudos) currentParsed.pseudos = [];
|
||||
currentParsed.pseudos.push({
|
||||
key: pseudoClass.replace(reUnescape, ''),
|
||||
value: pseudoClassValue,
|
||||
type: pseudoMarker.length == 1 ? 'class' : 'element'
|
||||
});
|
||||
|
||||
} else if (attributeKey){
|
||||
attributeKey = attributeKey.replace(reUnescape, '');
|
||||
attributeValue = (attributeValue || '').replace(reUnescape, '');
|
||||
|
||||
var test, regexp;
|
||||
|
||||
switch (attributeOperator){
|
||||
case '^=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) ); break;
|
||||
case '$=' : regexp = new RegExp( escapeRegExp(attributeValue) +'$' ); break;
|
||||
case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +'(\\s|$)' ); break;
|
||||
case '|=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) +'(-|$)' ); break;
|
||||
case '=' : test = function(value){
|
||||
return attributeValue == value;
|
||||
}; break;
|
||||
case '*=' : test = function(value){
|
||||
return value && value.indexOf(attributeValue) > -1;
|
||||
}; break;
|
||||
case '!=' : test = function(value){
|
||||
return attributeValue != value;
|
||||
}; break;
|
||||
default : test = function(value){
|
||||
return !!value;
|
||||
};
|
||||
}
|
||||
|
||||
if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = function(){
|
||||
return false;
|
||||
};
|
||||
|
||||
if (!test) test = function(value){
|
||||
return value && regexp.test(value);
|
||||
};
|
||||
|
||||
if (!currentParsed.attributes) currentParsed.attributes = [];
|
||||
currentParsed.attributes.push({
|
||||
key: attributeKey,
|
||||
operator: attributeOperator,
|
||||
value: attributeValue,
|
||||
test: test
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
// Slick NS
|
||||
|
||||
var Slick = (this.Slick || {});
|
||||
|
||||
Slick.parse = function(expression){
|
||||
return parse(expression);
|
||||
};
|
||||
|
||||
Slick.escapeRegExp = escapeRegExp;
|
||||
|
||||
this.exports = Slick
|
||||
|
||||
}).apply(module);
|
||||
34
vendor/specificity.js
vendored
34
vendor/specificity.js
vendored
@@ -1,34 +0,0 @@
|
||||
// source: MooTools DOM branch -> https://raw.github.com/arian/DOM/matcher-specificity/Source/specificity.js
|
||||
// changed to be compatible with our require system
|
||||
// change line
|
||||
// for (var ii = nots.length; ii--;) s += this.specificity(nots[ii]);
|
||||
// for (var ii = nots.length; ii--;) s += nots[ii];
|
||||
|
||||
var Slick = require('./slick');
|
||||
|
||||
module.exports = function(selector){
|
||||
var parsed = Slick.parse(selector);
|
||||
var expressions = parsed.expressions;
|
||||
var specificity = -1;
|
||||
for (var j = 0; j < expressions.length; j++){
|
||||
var b = 0, c = 0, d = 0, s = 0, nots = [];
|
||||
for (var i = 0; i < expressions[j].length; i++){
|
||||
var expression = expressions[j][i], pseudos = expression.pseudos;
|
||||
if (expression.id) b++;
|
||||
if (expression.attributes) c += expression.attributes.length;
|
||||
if (expression.classes) c += expression.classes.length;
|
||||
if (expression.tag && expression.tag != '*') d++;
|
||||
if (pseudos){
|
||||
d += pseudos.length;
|
||||
for (var p = 0; p < pseudos.length; p++) if (pseudos[p].key == 'not'){
|
||||
nots.push(pseudos[p].value);
|
||||
d--;
|
||||
}
|
||||
}
|
||||
}
|
||||
s = b * 1e6 + c * 1e3 + d;
|
||||
for (var ii = nots.length; ii--;) s += nots[ii];
|
||||
if (s > specificity) specificity = s;
|
||||
}
|
||||
return specificity;
|
||||
};
|
||||
Reference in New Issue
Block a user