|
function( |
|
a /* input string */ |
|
){ |
|
a |
|
/* Invoke `replace` method storing its name into `a`: */ |
|
[a='replace']( |
|
/* Get rid of escaped chars and make sure we can use `\w` later: |
|
replace dash, and anything that is not basic ASCII into alphanumeric |
|
chars. |
|
Range should be NUL (\x00) to DEL (\x7F) but it would be hard |
|
to edit. Anyway these "omitted" chars makes selector syntax invalid. */ |
|
/\\.|-|[^ -~]/g |
|
/* Omit 2nd arg. "undefined" is a perfectly well alphanumeric string */ |
|
) |
|
/* We can safely match braces and quotes now. Replace again: */ |
|
[a]( |
|
/* :not() itself doesn't counts in specificity, but its contents does. |
|
Chopping it off. Braces are left in string - that's ok, it will not be |
|
matched by any of the following regexps if it doesn't preceeded by |
|
pseudoclass. |
|
Plus sign is placed in order to leave these braces separated |
|
":foo:not(bar)" -> ":foo(bar)" may be occured otherwise. |
|
At the same time erase single and double quoted strings. |
|
Replace it into plus sign is safely enough. */ |
|
/:not\b|("|').*?\1/g, |
|
'+' |
|
) |
|
/* No more strings (that may be confused with tag, class or id). |
|
It's time for final replace. */ |
|
[a]( |
|
/* Pretty big and tangled regexp. |
|
|
|
`(#)?\w+` |
|
Matches "foo" and "#foo", i.e., tag name or id, and pass it |
|
as 2nd argument. |
|
If it's an id declaration, "#" also will be passed as 3rd argument. |
|
|
|
`[.:]\w+(\s*\(.*?\))?` |
|
Matches class or pseudoclass with optionally following whitespaces |
|
and braces with anything within. |
|
As expressions like ".:pseudo" and ".class(foo)" or ":..class" |
|
may never be encountered in valid CSS selector, we can freely use one |
|
regexp "chunk" for classes and pseudoclasses. |
|
|
|
`\[.*?]` |
|
Matches attribute selector. */ |
|
|
|
/((#)?\w+)|[.:]\w+(\s*\(.*?\))?|\[.*?]/g, |
|
|
|
/* Function as a replacer.*/ |
|
function( |
|
$, /* Unused argument. Named `$` as ECMA advices */ |
|
t, /* Contents of 1st brace pair. */ |
|
i /* Contents of 2nd brace pair. */ |
|
){ |
|
/* If id was matched, `i` is not `undefined`. |
|
If id or tag was matched, `t` is not `undefined`. (That is, |
|
if class, pseudoclass or attr was mathced, `t` is `undefined`). |
|
Shift 1 by 16, 8 or 0 positions left depending on what |
|
was matched and add result (0x10000, 0x100 or 0x1 respectively) |
|
to `a`. (Remember? We have already set `a = 0`) |
|
I hope, no one ever uses 256 class names in one selector. */ |
|
a += 1 << 8 * (i ? 2 : !t) |
|
}, |
|
|
|
/* 3rd argument will be ignored by .replace |
|
But it's the nice place to assign 0 to `a` */ |
|
a = 0 |
|
); |
|
/* After all parse passes finished, return `a`. It is the specificity */ |
|
return a |
|
} |
It's just awesome.
Save 2 bytes by the way:
function(a,b){a[b='replace'](/\\.|-|[^ -~]/g,a=0)[b](/:not\b|("|').*?\1/g,'+')[b](/(#)?\w+|(::?\w+(?:\s*\(.*?\))?|\[.*?]|\.\w+)/g,function($,i,c){a+=1<<8*(i?2:!!c)});return a}