specificity
Advanced tools
Comparing version 0.3.2 to 0.4.0
{ | ||
"name": "specificity", | ||
"version": "0.3.2", | ||
"version": "0.4.0", | ||
"description": "Calculate the specificity of a CSS selector", | ||
@@ -22,3 +22,4 @@ "keywords": [ | ||
}, | ||
"main": "specificity", | ||
"main": "dist/specificity", | ||
"module": "dist/specificity.mjs", | ||
"bin": { | ||
@@ -28,8 +29,11 @@ "specificity": "./bin/specificity" | ||
"scripts": { | ||
"test": "mocha test/test.js" | ||
"prepare": "rollup --config", | ||
"test": "mocha test/test.js --require esm" | ||
}, | ||
"devDependencies": { | ||
"mocha": "2.5.x" | ||
"esm": "^3.0.71", | ||
"mocha": "^5.2.0", | ||
"rollup": "^0.62.0" | ||
}, | ||
"types": "specificity.d.ts" | ||
} |
125
readme.md
# Specificity Calculator | ||
A JavaScript module for calculating and comparing the [specificity of CSS selectors](http://www.w3.org/TR/css3-selectors/#specificity). The module is used on the [Specificity Calculator](http://specificity.keegan.st/) website. | ||
A JavaScript module for calculating and comparing the [specificity of CSS selectors](https://www.w3.org/TR/selectors-3/#specificity). The module is used on the [Specificity Calculator](https://specificity.keegan.st/) website. | ||
Specificity Calculator is built for CSS Selectors Level 3. Specificity Calculator isn’t a CSS validator. If you enter invalid selectors it will return incorrect results. For example, the [negation pseudo-class](http://www.w3.org/TR/css3-selectors/#negation) may only take a simple selector as an argument. Using a psuedo-element or combinator as an argument for `:not()` is invalid CSS3 so Specificity Calculator will return incorrect results. | ||
Specificity Calculator is built for CSS Selectors Level 3. Specificity Calculator isn’t a CSS validator. If you enter invalid selectors it will return incorrect results. For example, the [negation pseudo-class](https://www.w3.org/TR/selectors-3/#negation) may only take a simple selector as an argument. Using a psuedo-element or combinator as an argument for `:not()` is invalid CSS so Specificity Calculator will return incorrect results. | ||
## Supported runtime environments | ||
## Front-end usage | ||
The module is provided in two formats: an ECMAScript (ES) module in `dist/specificity.mjs`, and a Universal Module Definition (UMD) in `dist/specificity.js`. This enables support for the following runtime environments: | ||
**Browser** | ||
* Directly loaded ES module | ||
* ES module in a precompiled script (using a bundler like Webpack or Rollup) | ||
* Global variable | ||
**Node.js** | ||
* ES module | ||
* CommonJS module | ||
### Browser usage as a directly loaded ES module | ||
```html | ||
<script type="module"> | ||
import { calculate } from './specificity/dist/specificity.mjs'; | ||
calculate('ul#nav li.active a'); | ||
</script> | ||
``` | ||
### Browser usage as an ES module in a precompiled script | ||
Bundlers like [Webpack and Rollup](https://github.com/rollup/rollup/wiki/pkg.module) import from the `module` field in `package.json`, which is set to the ES module artefact, `dist/specificity.mjs`. | ||
```js | ||
SPECIFICITY.calculate('ul#nav li.active a'); // [{ specificity: '0,1,1,3' }] | ||
import { calculate } from 'specificity'; | ||
calculate('ul#nav li.active a'); | ||
``` | ||
## Node.js usage | ||
### Browser usage as a global variable | ||
The UMD artefact, `dist/specificity.js`, sets a global variable, `SPECIFICITY`. | ||
```html | ||
<script src="./specificity/dist/specificity.js"></script> | ||
<script> | ||
SPECIFICITY.calculate('ul#nav li.active a'); | ||
</script> | ||
``` | ||
### Node.js usage as an ES module | ||
The `main` field in `package.json` has an extensionless value, `dist/specificity`. This allows Node.js to use either the ES module, in `dist/specificity.mjs`, or the CommonJS module, in `dist/specificity.js`. | ||
When Node.js is run with the `--experimental-modules` [flag](https://nodejs.org/api/esm.html) or an [ES module loader](https://www.npmjs.com/package/esm), it will use the ES module artefact. | ||
```js | ||
var specificity = require('specificity'); | ||
specificity.calculate('ul#nav li.active a'); // [{ specificity: '0,1,1,3' }] | ||
import { calculate } from 'specificity'; | ||
calculate('ul#nav li.active a'); | ||
``` | ||
## Passing in multiple selectors | ||
### Node.js usage as a CommonJS module | ||
You can use comma separation to pass in multiple selectors: | ||
Otherwise, Node.js will use the UMD artefact, which contains a CommonJS module definition. | ||
```js | ||
SPECIFICITY.calculate('ul#nav li.active a, body.ie7 .col_3 h2 ~ h2'); // [{ specificity: '0,1,1,3' }, { specificity: '0,0,2,3' }] | ||
const { calculate } = require('specificity'); | ||
calculate('ul#nav li.active a'); | ||
``` | ||
## Return values | ||
## Calculate function | ||
The `specificity.calculate` function returns an array containing a result object for each selector input. Each result object has the following properties: | ||
The `calculate` function returns an array containing a result object for each selector input. Each result object has the following properties: | ||
@@ -41,9 +88,7 @@ * `selector`: the input | ||
```js | ||
var specificity = require('../'), | ||
result = specificity.calculate('ul#nav li.active a'); | ||
calculate('ul#nav li.active a'); | ||
console.log(result); | ||
/* result = | ||
[ { | ||
/* | ||
[ | ||
{ | ||
selector: 'ul#nav li.active a', | ||
@@ -59,9 +104,31 @@ specificity: '0,1,1,3', | ||
] | ||
} ] | ||
} | ||
] | ||
*/ | ||
``` | ||
You can use comma separation to pass in multiple selectors: | ||
```js | ||
calculate('ul#nav li.active a, body.ie7 .col_3 h2 ~ h2'); | ||
/* | ||
[ | ||
{ | ||
selector: 'ul#nav li.active a', | ||
specificity: '0,1,1,3', | ||
... | ||
}, | ||
{ | ||
selector: 'body.ie7 .col_3 h2 ~ h2', | ||
specificity: '0,0,2,3', | ||
... | ||
} | ||
] | ||
*/ | ||
``` | ||
## Comparing two selectors | ||
Specificity Calculator also exposes a `compare` function. This function accepts two CSS selectors or specificity arrays, `a` and `b`. | ||
Specificity Calculator also exports a `compare` function. This function accepts two CSS selectors or specificity arrays, `a` and `b`. | ||
@@ -73,7 +140,7 @@ * It returns `-1` if `a` has a lower specificity than `b` | ||
```js | ||
SPECIFICITY.compare('div', '.active'); // -1 | ||
SPECIFICITY.compare('#main', 'div'); // 1 | ||
SPECIFICITY.compare('span', 'div'); // 0 | ||
SPECIFICITY.compare('span', [0,0,0,1]); // 0 | ||
SPECIFICITY.compare('#main > div', [0,1,0,1]); // 0 | ||
compare('div', '.active'); // -1 | ||
compare('#main', 'div'); // 1 | ||
compare('span', 'div'); // 0 | ||
compare('span', [0, 0, 0, 1]); // 0 | ||
compare('#main > div', [0, 1, 0, 1]); // 0 | ||
``` | ||
@@ -83,6 +150,8 @@ | ||
You can pass the `SPECIFICITY.compare` function to `Array.prototype.sort` to sort an array of CSS selectors by specificity. | ||
You can pass the `compare` function to `Array.prototype.sort` to sort an array of CSS selectors by specificity. | ||
```js | ||
['#main', 'p', '.active'].sort(SPECIFICITY.compare); // ['p', '.active', '#main'] | ||
import { compare } from 'specificity'; | ||
['#main', 'p', '.active'].sort(compare); // ['p', '.active', '#main'] | ||
``` | ||
@@ -92,3 +161,3 @@ | ||
Run `npm install specificity` to install the module locally, or `npm install -g specificity` for global installation. You may need to elevate permissions by `sudo` for the latter. Run `specificity` without arguments to learn about its usage: | ||
Run `npm install specificity` to install the module locally, or `npm install -g specificity` for global installation. Run `specificity` without arguments to learn about its usage: | ||
@@ -95,0 +164,0 @@ ```bash |
@@ -1,56 +0,53 @@ | ||
declare module "specificity" { | ||
export = specificity; | ||
namespace specificity { | ||
/** | ||
* Specificity arrays always have 4 numbers (integers) for quick comparison | ||
* comparing from left to right, the next number only has to be checked if | ||
* two numbers of the same index are equal. | ||
*/ | ||
type SpecificityArray = [number, number, number, number]; | ||
/** | ||
* Specificity arrays always have 4 numbers (integers) for quick comparison | ||
* comparing from left to right, the next number only has to be checked if | ||
* two numbers of the same index are equal. | ||
*/ | ||
export type SpecificityArray = [number, number, number, number]; | ||
/** | ||
* A result of parsing a selector into an array of parts. | ||
* Calculating a specificity array is a matter of summing | ||
* over all the parts and adding the values to the right | ||
* bucket in a specificity array. | ||
* | ||
* @interface Part | ||
*/ | ||
interface Part { | ||
selector: string; | ||
type: "a" | "b" | "c"; | ||
index: number; | ||
length: number; | ||
} | ||
/** | ||
* Returned by the calculate function. Represents the results | ||
* of parsing and calculating the specificity of a selector. | ||
* | ||
* @interface Specificity | ||
*/ | ||
interface Specificity { | ||
selector: string; | ||
specificity: string; | ||
specificityArray: SpecificityArray; | ||
parts: Array<Part>; | ||
} | ||
/** | ||
* Calculates the specificity for the given selector string. | ||
* If the string contains a comma, each selector will be parsed | ||
* separately. | ||
* | ||
* @returns A list of specificity objects one for each selector in the | ||
* selector string. | ||
*/ | ||
function calculate(selector: string): Array<Specificity>; | ||
/** | ||
* A result of parsing a selector into an array of parts. | ||
* Calculating a specificity array is a matter of summing | ||
* over all the parts and adding the values to the right | ||
* bucket in a specificity array. | ||
* | ||
* @interface Part | ||
*/ | ||
export interface Part { | ||
selector: string; | ||
type: 'a' | 'b' | 'c'; | ||
index: number; | ||
length: number; | ||
} | ||
/** | ||
* Compares two selectors. If a string, the string cannot contain a comma. | ||
* | ||
* @returns A value less than 0 if selector a is less specific than selector b. | ||
* A value more than 0 if selector a is more specific than selector b. | ||
* 0 if the two selectors have the same specificity. | ||
*/ | ||
function compare(a: string | SpecificityArray, b: string | SpecificityArray): -1 | 0 | 1; | ||
} | ||
} | ||
/** | ||
* Returned by the calculate function. Represents the results | ||
* of parsing and calculating the specificity of a selector. | ||
* | ||
* @interface Specificity | ||
*/ | ||
export interface Specificity { | ||
selector: string; | ||
specificity: string; | ||
specificityArray: SpecificityArray; | ||
parts: Array<Part>; | ||
} | ||
/** | ||
* Calculates the specificity for the given selector string. | ||
* If the string contains a comma, each selector will be parsed | ||
* separately. | ||
* | ||
* @returns A list of specificity objects one for each selector in the | ||
* selector string. | ||
*/ | ||
export function calculate(selector: string): Array<Specificity>; | ||
/** | ||
* Compares two selectors. If a string, the string cannot contain a comma. | ||
* | ||
* @returns A value less than 0 if selector a is less specific than selector b. | ||
* A value more than 0 if selector a is more specific than selector b. | ||
* 0 if the two selectors have the same specificity. | ||
*/ | ||
export function compare(a: string | SpecificityArray, b: string | SpecificityArray): -1 | 0 | 1; |
@@ -1,232 +0,220 @@ | ||
var SPECIFICITY = (function() { | ||
var calculate, | ||
calculateSingle, | ||
compare; | ||
// Calculate the specificity for a selector by dividing it into simple selectors and counting them | ||
var calculate = function(input) { | ||
var selectors, | ||
selector, | ||
i, | ||
len, | ||
results = []; | ||
// Calculate the specificity for a selector by dividing it into simple selectors and counting them | ||
calculate = function(input) { | ||
var selectors, | ||
selector, | ||
i, | ||
len, | ||
results = []; | ||
// Separate input by commas | ||
selectors = input.split(','); | ||
// Separate input by commas | ||
selectors = input.split(','); | ||
for (i = 0, len = selectors.length; i < len; i += 1) { | ||
selector = selectors[i]; | ||
if (selector.length > 0) { | ||
results.push(calculateSingle(selector)); | ||
} | ||
for (i = 0, len = selectors.length; i < len; i += 1) { | ||
selector = selectors[i]; | ||
if (selector.length > 0) { | ||
results.push(calculateSingle(selector)); | ||
} | ||
} | ||
return results; | ||
}; | ||
return results; | ||
}; | ||
/** | ||
* Calculates the specificity of CSS selectors | ||
* http://www.w3.org/TR/css3-selectors/#specificity | ||
* | ||
* Returns an object with the following properties: | ||
* - selector: the input | ||
* - specificity: e.g. 0,1,0,0 | ||
* - parts: array with details about each part of the selector that counts towards the specificity | ||
* - specificityArray: e.g. [0, 1, 0, 0] | ||
*/ | ||
calculateSingle = function(input) { | ||
var selector = input, | ||
findMatch, | ||
typeCount = { | ||
'a': 0, | ||
'b': 0, | ||
'c': 0 | ||
}, | ||
parts = [], | ||
// The following regular expressions assume that selectors matching the preceding regular expressions have been removed | ||
attributeRegex = /(\[[^\]]+\])/g, | ||
idRegex = /(#[^\#\s\+>~\.\[:]+)/g, | ||
classRegex = /(\.[^\s\+>~\.\[:]+)/g, | ||
pseudoElementRegex = /(::[^\s\+>~\.\[:]+|:first-line|:first-letter|:before|:after)/gi, | ||
// A regex for pseudo classes with brackets - :nth-child(), :nth-last-child(), :nth-of-type(), :nth-last-type(), :lang() | ||
pseudoClassWithBracketsRegex = /(:[\w-]+\([^\)]*\))/gi, | ||
// A regex for other pseudo classes, which don't have brackets | ||
pseudoClassRegex = /(:[^\s\+>~\.\[:]+)/g, | ||
elementRegex = /([^\s\+>~\.\[:]+)/g; | ||
/** | ||
* Calculates the specificity of CSS selectors | ||
* http://www.w3.org/TR/css3-selectors/#specificity | ||
* | ||
* Returns an object with the following properties: | ||
* - selector: the input | ||
* - specificity: e.g. 0,1,0,0 | ||
* - parts: array with details about each part of the selector that counts towards the specificity | ||
* - specificityArray: e.g. [0, 1, 0, 0] | ||
*/ | ||
var calculateSingle = function(input) { | ||
var selector = input, | ||
findMatch, | ||
typeCount = { | ||
'a': 0, | ||
'b': 0, | ||
'c': 0 | ||
}, | ||
parts = [], | ||
// The following regular expressions assume that selectors matching the preceding regular expressions have been removed | ||
attributeRegex = /(\[[^\]]+\])/g, | ||
idRegex = /(#[^\#\s\+>~\.\[:]+)/g, | ||
classRegex = /(\.[^\s\+>~\.\[:]+)/g, | ||
pseudoElementRegex = /(::[^\s\+>~\.\[:]+|:first-line|:first-letter|:before|:after)/gi, | ||
// A regex for pseudo classes with brackets - :nth-child(), :nth-last-child(), :nth-of-type(), :nth-last-type(), :lang() | ||
pseudoClassWithBracketsRegex = /(:[\w-]+\([^\)]*\))/gi, | ||
// A regex for other pseudo classes, which don't have brackets | ||
pseudoClassRegex = /(:[^\s\+>~\.\[:]+)/g, | ||
elementRegex = /([^\s\+>~\.\[:]+)/g; | ||
// Find matches for a regular expression in a string and push their details to parts | ||
// Type is "a" for IDs, "b" for classes, attributes and pseudo-classes and "c" for elements and pseudo-elements | ||
findMatch = function(regex, type) { | ||
var matches, i, len, match, index, length; | ||
if (regex.test(selector)) { | ||
matches = selector.match(regex); | ||
for (i = 0, len = matches.length; i < len; i += 1) { | ||
typeCount[type] += 1; | ||
match = matches[i]; | ||
index = selector.indexOf(match); | ||
length = match.length; | ||
parts.push({ | ||
selector: input.substr(index, length), | ||
type: type, | ||
index: index, | ||
length: length | ||
}); | ||
// Replace this simple selector with whitespace so it won't be counted in further simple selectors | ||
selector = selector.replace(match, Array(length + 1).join(' ')); | ||
} | ||
// Find matches for a regular expression in a string and push their details to parts | ||
// Type is "a" for IDs, "b" for classes, attributes and pseudo-classes and "c" for elements and pseudo-elements | ||
findMatch = function(regex, type) { | ||
var matches, i, len, match, index, length; | ||
if (regex.test(selector)) { | ||
matches = selector.match(regex); | ||
for (i = 0, len = matches.length; i < len; i += 1) { | ||
typeCount[type] += 1; | ||
match = matches[i]; | ||
index = selector.indexOf(match); | ||
length = match.length; | ||
parts.push({ | ||
selector: input.substr(index, length), | ||
type: type, | ||
index: index, | ||
length: length | ||
}); | ||
// Replace this simple selector with whitespace so it won't be counted in further simple selectors | ||
selector = selector.replace(match, Array(length + 1).join(' ')); | ||
} | ||
}; | ||
} | ||
}; | ||
// Replace escaped characters with plain text, using the "A" character | ||
// https://www.w3.org/TR/CSS21/syndata.html#characters | ||
(function() { | ||
var replaceWithPlainText = function(regex) { | ||
var matches, i, len, match; | ||
if (regex.test(selector)) { | ||
matches = selector.match(regex); | ||
for (i = 0, len = matches.length; i < len; i += 1) { | ||
match = matches[i]; | ||
selector = selector.replace(match, Array(match.length + 1).join('A')); | ||
} | ||
// Replace escaped characters with plain text, using the "A" character | ||
// https://www.w3.org/TR/CSS21/syndata.html#characters | ||
(function() { | ||
var replaceWithPlainText = function(regex) { | ||
var matches, i, len, match; | ||
if (regex.test(selector)) { | ||
matches = selector.match(regex); | ||
for (i = 0, len = matches.length; i < len; i += 1) { | ||
match = matches[i]; | ||
selector = selector.replace(match, Array(match.length + 1).join('A')); | ||
} | ||
}, | ||
// Matches a backslash followed by six hexadecimal digits followed by an optional single whitespace character | ||
escapeHexadecimalRegex = /\\[0-9A-Fa-f]{6}\s?/g, | ||
// Matches a backslash followed by fewer than six hexadecimal digits followed by a mandatory single whitespace character | ||
escapeHexadecimalRegex2 = /\\[0-9A-Fa-f]{1,5}\s/g, | ||
// Matches a backslash followed by any character | ||
escapeSpecialCharacter = /\\./g; | ||
} | ||
}, | ||
// Matches a backslash followed by six hexadecimal digits followed by an optional single whitespace character | ||
escapeHexadecimalRegex = /\\[0-9A-Fa-f]{6}\s?/g, | ||
// Matches a backslash followed by fewer than six hexadecimal digits followed by a mandatory single whitespace character | ||
escapeHexadecimalRegex2 = /\\[0-9A-Fa-f]{1,5}\s/g, | ||
// Matches a backslash followed by any character | ||
escapeSpecialCharacter = /\\./g; | ||
replaceWithPlainText(escapeHexadecimalRegex); | ||
replaceWithPlainText(escapeHexadecimalRegex2); | ||
replaceWithPlainText(escapeSpecialCharacter); | ||
}()); | ||
replaceWithPlainText(escapeHexadecimalRegex); | ||
replaceWithPlainText(escapeHexadecimalRegex2); | ||
replaceWithPlainText(escapeSpecialCharacter); | ||
}()); | ||
// Remove the negation psuedo-class (:not) but leave its argument because specificity is calculated on its argument | ||
(function() { | ||
var regex = /:not\(([^\)]*)\)/g; | ||
if (regex.test(selector)) { | ||
selector = selector.replace(regex, ' $1 '); | ||
} | ||
}()); | ||
// Remove the negation psuedo-class (:not) but leave its argument because specificity is calculated on its argument | ||
(function() { | ||
var regex = /:not\(([^\)]*)\)/g; | ||
if (regex.test(selector)) { | ||
selector = selector.replace(regex, ' $1 '); | ||
} | ||
}()); | ||
// Remove anything after a left brace in case a user has pasted in a rule, not just a selector | ||
(function() { | ||
var regex = /{[^]*/gm, | ||
matches, i, len, match; | ||
if (regex.test(selector)) { | ||
matches = selector.match(regex); | ||
for (i = 0, len = matches.length; i < len; i += 1) { | ||
match = matches[i]; | ||
selector = selector.replace(match, Array(match.length + 1).join(' ')); | ||
} | ||
// Remove anything after a left brace in case a user has pasted in a rule, not just a selector | ||
(function() { | ||
var regex = /{[^]*/gm, | ||
matches, i, len, match; | ||
if (regex.test(selector)) { | ||
matches = selector.match(regex); | ||
for (i = 0, len = matches.length; i < len; i += 1) { | ||
match = matches[i]; | ||
selector = selector.replace(match, Array(match.length + 1).join(' ')); | ||
} | ||
}()); | ||
} | ||
}()); | ||
// Add attribute selectors to parts collection (type b) | ||
findMatch(attributeRegex, 'b'); | ||
// Add attribute selectors to parts collection (type b) | ||
findMatch(attributeRegex, 'b'); | ||
// Add ID selectors to parts collection (type a) | ||
findMatch(idRegex, 'a'); | ||
// Add ID selectors to parts collection (type a) | ||
findMatch(idRegex, 'a'); | ||
// Add class selectors to parts collection (type b) | ||
findMatch(classRegex, 'b'); | ||
// Add class selectors to parts collection (type b) | ||
findMatch(classRegex, 'b'); | ||
// Add pseudo-element selectors to parts collection (type c) | ||
findMatch(pseudoElementRegex, 'c'); | ||
// Add pseudo-element selectors to parts collection (type c) | ||
findMatch(pseudoElementRegex, 'c'); | ||
// Add pseudo-class selectors to parts collection (type b) | ||
findMatch(pseudoClassWithBracketsRegex, 'b'); | ||
findMatch(pseudoClassRegex, 'b'); | ||
// Add pseudo-class selectors to parts collection (type b) | ||
findMatch(pseudoClassWithBracketsRegex, 'b'); | ||
findMatch(pseudoClassRegex, 'b'); | ||
// Remove universal selector and separator characters | ||
selector = selector.replace(/[\*\s\+>~]/g, ' '); | ||
// Remove universal selector and separator characters | ||
selector = selector.replace(/[\*\s\+>~]/g, ' '); | ||
// Remove any stray dots or hashes which aren't attached to words | ||
// These may be present if the user is live-editing this selector | ||
selector = selector.replace(/[#\.]/g, ' '); | ||
// Remove any stray dots or hashes which aren't attached to words | ||
// These may be present if the user is live-editing this selector | ||
selector = selector.replace(/[#\.]/g, ' '); | ||
// The only things left should be element selectors (type c) | ||
findMatch(elementRegex, 'c'); | ||
// The only things left should be element selectors (type c) | ||
findMatch(elementRegex, 'c'); | ||
// Order the parts in the order they appear in the original selector | ||
// This is neater for external apps to deal with | ||
parts.sort(function(a, b) { | ||
return a.index - b.index; | ||
}); | ||
// Order the parts in the order they appear in the original selector | ||
// This is neater for external apps to deal with | ||
parts.sort(function(a, b) { | ||
return a.index - b.index; | ||
}); | ||
return { | ||
selector: input, | ||
specificity: '0,' + typeCount.a.toString() + ',' + typeCount.b.toString() + ',' + typeCount.c.toString(), | ||
specificityArray: [0, typeCount.a, typeCount.b, typeCount.c], | ||
parts: parts | ||
}; | ||
return { | ||
selector: input, | ||
specificity: '0,' + typeCount.a.toString() + ',' + typeCount.b.toString() + ',' + typeCount.c.toString(), | ||
specificityArray: [0, typeCount.a, typeCount.b, typeCount.c], | ||
parts: parts | ||
}; | ||
}; | ||
/** | ||
* Compares two CSS selectors for specificity | ||
* Alternatively you can replace one of the CSS selectors with a specificity array | ||
* | ||
* - it returns -1 if a has a lower specificity than b | ||
* - it returns 1 if a has a higher specificity than b | ||
* - it returns 0 if a has the same specificity than b | ||
*/ | ||
compare = function(a, b) { | ||
var aSpecificity, | ||
bSpecificity, | ||
i; | ||
/** | ||
* Compares two CSS selectors for specificity | ||
* Alternatively you can replace one of the CSS selectors with a specificity array | ||
* | ||
* - it returns -1 if a has a lower specificity than b | ||
* - it returns 1 if a has a higher specificity than b | ||
* - it returns 0 if a has the same specificity than b | ||
*/ | ||
var compare = function(a, b) { | ||
var aSpecificity, | ||
bSpecificity, | ||
i; | ||
if (typeof a ==='string') { | ||
if (a.indexOf(',') !== -1) { | ||
throw 'Invalid CSS selector'; | ||
} else { | ||
aSpecificity = calculateSingle(a)['specificityArray']; | ||
} | ||
} else if (Array.isArray(a)) { | ||
if (a.filter(function(e) { return (typeof e === 'number'); }).length !== 4) { | ||
throw 'Invalid specificity array'; | ||
} else { | ||
aSpecificity = a; | ||
} | ||
if (typeof a ==='string') { | ||
if (a.indexOf(',') !== -1) { | ||
throw 'Invalid CSS selector'; | ||
} else { | ||
throw 'Invalid CSS selector or specificity array'; | ||
aSpecificity = calculateSingle(a)['specificityArray']; | ||
} | ||
} else if (Array.isArray(a)) { | ||
if (a.filter(function(e) { return (typeof e === 'number'); }).length !== 4) { | ||
throw 'Invalid specificity array'; | ||
} else { | ||
aSpecificity = a; | ||
} | ||
} else { | ||
throw 'Invalid CSS selector or specificity array'; | ||
} | ||
if (typeof b ==='string') { | ||
if (b.indexOf(',') !== -1) { | ||
throw 'Invalid CSS selector'; | ||
} else { | ||
bSpecificity = calculateSingle(b)['specificityArray']; | ||
} | ||
} else if (Array.isArray(b)) { | ||
if (b.filter(function(e) { return (typeof e === 'number'); }).length !== 4) { | ||
throw 'Invalid specificity array'; | ||
} else { | ||
bSpecificity = b; | ||
} | ||
if (typeof b ==='string') { | ||
if (b.indexOf(',') !== -1) { | ||
throw 'Invalid CSS selector'; | ||
} else { | ||
throw 'Invalid CSS selector or specificity array'; | ||
bSpecificity = calculateSingle(b)['specificityArray']; | ||
} | ||
} else if (Array.isArray(b)) { | ||
if (b.filter(function(e) { return (typeof e === 'number'); }).length !== 4) { | ||
throw 'Invalid specificity array'; | ||
} else { | ||
bSpecificity = b; | ||
} | ||
} else { | ||
throw 'Invalid CSS selector or specificity array'; | ||
} | ||
for (i = 0; i < 4; i += 1) { | ||
if (aSpecificity[i] < bSpecificity[i]) { | ||
return -1; | ||
} else if (aSpecificity[i] > bSpecificity[i]) { | ||
return 1; | ||
} | ||
for (i = 0; i < 4; i += 1) { | ||
if (aSpecificity[i] < bSpecificity[i]) { | ||
return -1; | ||
} else if (aSpecificity[i] > bSpecificity[i]) { | ||
return 1; | ||
} | ||
} | ||
return 0; | ||
}; | ||
return 0; | ||
}; | ||
return { | ||
calculate: calculate, | ||
compare: compare | ||
}; | ||
}()); | ||
// Export for Node JS | ||
if (typeof exports !== 'undefined') { | ||
exports.calculate = SPECIFICITY.calculate; | ||
exports.compare = SPECIFICITY.compare; | ||
} | ||
export { | ||
calculate, | ||
compare | ||
}; |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
35634
10
749
177
3
1