aboutsummaryrefslogtreecommitdiff
path: root/node_modules/csso/lib/compressor/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/csso/lib/compressor/index.js')
-rw-r--r--node_modules/csso/lib/compressor/index.js186
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
+ };
+};