diff options
Diffstat (limited to 'node_modules/csso/lib/compressor/restructure/prepare')
4 files changed, 223 insertions, 0 deletions
diff --git a/node_modules/csso/lib/compressor/restructure/prepare/createDeclarationIndexer.js b/node_modules/csso/lib/compressor/restructure/prepare/createDeclarationIndexer.js new file mode 100644 index 00000000..c5235309 --- /dev/null +++ b/node_modules/csso/lib/compressor/restructure/prepare/createDeclarationIndexer.js @@ -0,0 +1,32 @@ +var translate = require('../../../utils/translate.js'); + +function Index() { + this.seed = 0; + this.map = Object.create(null); +} + +Index.prototype.resolve = function(str) { + var index = this.map[str]; + + if (!index) { + index = ++this.seed; + this.map[str] = index; + } + + return index; +}; + +module.exports = function createDeclarationIndexer() { + var names = new Index(); + var values = new Index(); + + return function markDeclaration(node) { + var property = node.property.name; + var value = translate(node.value); + + node.id = names.resolve(property) + (values.resolve(value) << 12); + node.length = property.length + 1 + value.length; + + return node; + }; +}; diff --git a/node_modules/csso/lib/compressor/restructure/prepare/index.js b/node_modules/csso/lib/compressor/restructure/prepare/index.js new file mode 100644 index 00000000..075dc5f1 --- /dev/null +++ b/node_modules/csso/lib/compressor/restructure/prepare/index.js @@ -0,0 +1,44 @@ +var resolveKeyword = require('../../../utils/names.js').keyword; +var walkRules = require('../../../utils/walk.js').rules; +var translate = require('../../../utils/translate.js'); +var createDeclarationIndexer = require('./createDeclarationIndexer.js'); +var processSelector = require('./processSelector.js'); + +function walk(node, markDeclaration, usageData) { + switch (node.type) { + case 'Ruleset': + node.block.declarations.each(markDeclaration); + processSelector(node, usageData); + break; + + case 'Atrule': + if (node.expression) { + node.expression.id = translate(node.expression); + } + + // compare keyframe selectors by its values + // NOTE: still no clarification about problems with keyframes selector grouping (issue #197) + if (resolveKeyword(node.name).name === 'keyframes') { + node.block.avoidRulesMerge = true; /* probably we don't need to prevent those merges for @keyframes + TODO: need to be checked */ + node.block.rules.each(function(ruleset) { + ruleset.selector.selectors.each(function(simpleselector) { + simpleselector.compareMarker = simpleselector.id; + }); + }); + } + break; + } +}; + +module.exports = function prepare(ast, usageData) { + var markDeclaration = createDeclarationIndexer(); + + walkRules(ast, function(node) { + walk(node, markDeclaration, usageData); + }); + + return { + declaration: markDeclaration + }; +}; diff --git a/node_modules/csso/lib/compressor/restructure/prepare/processSelector.js b/node_modules/csso/lib/compressor/restructure/prepare/processSelector.js new file mode 100644 index 00000000..56c46b56 --- /dev/null +++ b/node_modules/csso/lib/compressor/restructure/prepare/processSelector.js @@ -0,0 +1,99 @@ +var translate = require('../../../utils/translate.js'); +var specificity = require('./specificity.js'); + +var nonFreezePseudoElements = { + 'first-letter': true, + 'first-line': true, + 'after': true, + 'before': true +}; +var nonFreezePseudoClasses = { + 'link': true, + 'visited': true, + 'hover': true, + 'active': true, + 'first-letter': true, + 'first-line': true, + 'after': true, + 'before': true +}; + +module.exports = function freeze(node, usageData) { + var pseudos = Object.create(null); + var hasPseudo = false; + + node.selector.selectors.each(function(simpleSelector) { + var tagName = '*'; + var scope = 0; + + simpleSelector.sequence.some(function(node) { + switch (node.type) { + case 'Class': + if (usageData && usageData.scopes) { + var classScope = usageData.scopes[node.name] || 0; + + if (scope !== 0 && classScope !== scope) { + throw new Error('Selector can\'t has classes from different scopes: ' + translate(simpleSelector)); + } + + scope = classScope; + } + break; + + case 'PseudoClass': + if (!nonFreezePseudoClasses.hasOwnProperty(node.name)) { + pseudos[node.name] = true; + hasPseudo = true; + } + break; + + case 'PseudoElement': + if (!nonFreezePseudoElements.hasOwnProperty(node.name)) { + pseudos[node.name] = true; + hasPseudo = true; + } + break; + + case 'FunctionalPseudo': + pseudos[node.name] = true; + hasPseudo = true; + break; + + case 'Negation': + pseudos.not = true; + hasPseudo = true; + break; + + case 'Identifier': + tagName = node.name; + break; + + case 'Attribute': + if (node.flags) { + pseudos['[' + node.flags + ']'] = true; + hasPseudo = true; + } + break; + + case 'Combinator': + tagName = '*'; + break; + } + }); + + simpleSelector.id = translate(simpleSelector); + simpleSelector.compareMarker = specificity(simpleSelector).toString(); + + if (scope) { + simpleSelector.compareMarker += ':' + scope; + } + + if (tagName !== '*') { + simpleSelector.compareMarker += ',' + tagName; + } + }); + + if (hasPseudo) { + node.pseudoSignature = Object.keys(pseudos).sort().join(','); + } +}; diff --git a/node_modules/csso/lib/compressor/restructure/prepare/specificity.js b/node_modules/csso/lib/compressor/restructure/prepare/specificity.js new file mode 100644 index 00000000..506c3373 --- /dev/null +++ b/node_modules/csso/lib/compressor/restructure/prepare/specificity.js @@ -0,0 +1,48 @@ +module.exports = function specificity(simpleSelector) { + var A = 0; + var B = 0; + var C = 0; + + simpleSelector.sequence.each(function walk(data) { + switch (data.type) { + case 'SimpleSelector': + case 'Negation': + data.sequence.each(walk); + break; + + case 'Id': + A++; + break; + + case 'Class': + case 'Attribute': + case 'FunctionalPseudo': + B++; + break; + + case 'Identifier': + if (data.name !== '*') { + C++; + } + break; + + case 'PseudoElement': + C++; + break; + + case 'PseudoClass': + var name = data.name.toLowerCase(); + if (name === 'before' || + name === 'after' || + name === 'first-line' || + name === 'first-letter') { + C++; + } else { + B++; + } + break; + } + }); + + return [A, B, C]; +}; |
