diff options
Diffstat (limited to 'node_modules/csso/lib/compressor/index.js')
| -rw-r--r-- | node_modules/csso/lib/compressor/index.js | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/node_modules/csso/lib/compressor/index.js b/node_modules/csso/lib/compressor/index.js new file mode 100644 index 00000000..6d3fdeba --- /dev/null +++ b/node_modules/csso/lib/compressor/index.js @@ -0,0 +1,186 @@ +var List = require('../utils/list'); +var clone = require('../utils/clone'); +var usageUtils = require('./usage'); +var clean = require('./clean'); +var compress = require('./compress'); +var restructureBlock = require('./restructure'); +var walkRules = require('../utils/walk').rules; + +function readRulesChunk(rules, specialComments) { + var buffer = new List(); + var nonSpaceTokenInBuffer = false; + var protectedComment; + + rules.nextUntil(rules.head, function(node, item, list) { + if (node.type === 'Comment') { + if (!specialComments || node.value.charAt(0) !== '!') { + list.remove(item); + return; + } + + if (nonSpaceTokenInBuffer || protectedComment) { + return true; + } + + list.remove(item); + protectedComment = node; + return; + } + + if (node.type !== 'Space') { + nonSpaceTokenInBuffer = true; + } + + buffer.insert(list.remove(item)); + }); + + return { + comment: protectedComment, + stylesheet: { + type: 'StyleSheet', + info: null, + rules: buffer + } + }; +} + +function compressChunk(ast, firstAtrulesAllowed, usageData, num, logger) { + logger('Compress block #' + num, null, true); + + var seed = 1; + walkRules(ast, function markStylesheets() { + if ('id' in this.stylesheet === false) { + this.stylesheet.firstAtrulesAllowed = firstAtrulesAllowed; + this.stylesheet.id = seed++; + } + }); + logger('init', ast); + + // remove redundant + clean(ast, usageData); + logger('clean', ast); + + // compress nodes + compress(ast, usageData); + logger('compress', ast); + + return ast; +} + +function getCommentsOption(options) { + var comments = 'comments' in options ? options.comments : 'exclamation'; + + if (typeof comments === 'boolean') { + comments = comments ? 'exclamation' : false; + } else if (comments !== 'exclamation' && comments !== 'first-exclamation') { + comments = false; + } + + return comments; +} + +function getRestructureOption(options) { + return 'restructure' in options ? options.restructure : + 'restructuring' in options ? options.restructuring : + true; +} + +function wrapBlock(block) { + return new List([{ + type: 'Ruleset', + selector: { + type: 'Selector', + selectors: new List([{ + type: 'SimpleSelector', + sequence: new List([{ + type: 'Identifier', + name: 'x' + }]) + }]) + }, + block: block + }]); +} + +module.exports = function compress(ast, options) { + ast = ast || { type: 'StyleSheet', info: null, rules: new List() }; + options = options || {}; + + var logger = typeof options.logger === 'function' ? options.logger : Function(); + var specialComments = getCommentsOption(options); + var restructuring = getRestructureOption(options); + var firstAtrulesAllowed = true; + var usageData = false; + var inputRules; + var outputRules = new List(); + var chunk; + var chunkNum = 1; + var chunkRules; + + if (options.clone) { + ast = clone(ast); + } + + if (ast.type === 'StyleSheet') { + inputRules = ast.rules; + ast.rules = outputRules; + } else { + inputRules = wrapBlock(ast); + } + + if (options.usage) { + usageData = usageUtils.buildIndex(options.usage); + } + + do { + chunk = readRulesChunk(inputRules, Boolean(specialComments)); + + compressChunk(chunk.stylesheet, firstAtrulesAllowed, usageData, chunkNum++, logger); + + // structure optimisations + if (restructuring) { + restructureBlock(chunk.stylesheet, usageData, logger); + } + + chunkRules = chunk.stylesheet.rules; + + if (chunk.comment) { + // add \n before comment if there is another content in outputRules + if (!outputRules.isEmpty()) { + outputRules.insert(List.createItem({ + type: 'Raw', + value: '\n' + })); + } + + outputRules.insert(List.createItem(chunk.comment)); + + // add \n after comment if chunk is not empty + if (!chunkRules.isEmpty()) { + outputRules.insert(List.createItem({ + type: 'Raw', + value: '\n' + })); + } + } + + if (firstAtrulesAllowed && !chunkRules.isEmpty()) { + var lastRule = chunkRules.last(); + + if (lastRule.type !== 'Atrule' || + (lastRule.name !== 'import' && lastRule.name !== 'charset')) { + firstAtrulesAllowed = false; + } + } + + if (specialComments !== 'exclamation') { + specialComments = false; + } + + outputRules.appendList(chunkRules); + } while (!inputRules.isEmpty()); + + return { + ast: ast + }; +}; |
