install gulp
This commit is contained in:
+73
@@ -0,0 +1,73 @@
|
||||
var gonzales = require('gonzales-pe');
|
||||
|
||||
module.exports = {
|
||||
name: 'always-semicolon',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: { boolean: [true] },
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
var nodeWithoutSemicolon;
|
||||
|
||||
if (!node.is('block')) return;
|
||||
|
||||
mainLoop:
|
||||
for (var i = node.length; i--;) {
|
||||
var currentNode = node.get(i);
|
||||
|
||||
// Skip nodes that already have `;` at the end:
|
||||
if (currentNode.is('declarationDelimiter')) break;
|
||||
|
||||
// Add semicolon only after declarations and includes.
|
||||
// If current node is include, insert semicolon right into it.
|
||||
// If it's declaration, look for value node:
|
||||
if (currentNode.is('include')) {
|
||||
nodeWithoutSemicolon = currentNode;
|
||||
} else if (currentNode.is('declaration')) {
|
||||
nodeWithoutSemicolon = currentNode.last('value');
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if there are spaces and comments at the end of the node:
|
||||
for (var j = nodeWithoutSemicolon.length; j--; ) {
|
||||
var lastNode = nodeWithoutSemicolon.get(j);
|
||||
|
||||
// If the node's last child is block, do not add semicolon:
|
||||
// TODO: Add syntax check and run the code only for scss
|
||||
if (lastNode.is('block')) {
|
||||
break mainLoop;
|
||||
} else if (!lastNode.is('space') &&
|
||||
!lastNode.is('multilineComment') &&
|
||||
!lastNode.is('singlelineComment')) {
|
||||
j++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var declDelim = gonzales.createNode({ type: 'declarationDelimiter', content: ';' });
|
||||
nodeWithoutSemicolon.insert(j, declDelim);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('block')) return;
|
||||
|
||||
for (var i = node.length; i--;) {
|
||||
var nodeItem = node.get(i);
|
||||
if (nodeItem.is('declarationDelimiter')) return true;
|
||||
if (nodeItem.is('declaration')) return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
module.exports = (function() {
|
||||
var syntax;
|
||||
var value;
|
||||
|
||||
function processNode(node, level) {
|
||||
level = level || 0;
|
||||
|
||||
// XXX: Hack for braces
|
||||
if (node.is('braces') || node.is('id')) return;
|
||||
|
||||
for (var i = 0; i < node.length; i++) {
|
||||
var n = node.get(i);
|
||||
if (!n) continue;
|
||||
|
||||
if (syntax === 'sass' && n.is('block')) {
|
||||
processSassBlock(n, level, value);
|
||||
}
|
||||
|
||||
// Continue only with space nodes inside {...}:
|
||||
if (syntax !== 'sass' && level !== 0 && n.is('space')) {
|
||||
processSpaceNode(n, level, value);
|
||||
}
|
||||
|
||||
if (n.is('block') || n.is('atrulers')) level++;
|
||||
|
||||
processNode(n, level);
|
||||
}
|
||||
}
|
||||
|
||||
function processSassBlock(node, level, value) {
|
||||
var spaces;
|
||||
var whitespaceNode;
|
||||
var i;
|
||||
|
||||
for (i = node.length; i--;) {
|
||||
whitespaceNode = node.get(i);
|
||||
|
||||
if (!whitespaceNode.is('space')) continue;
|
||||
|
||||
if (whitespaceNode.content === '\n') continue;
|
||||
|
||||
spaces = whitespaceNode.content.replace(/[ \t]/gm, '');
|
||||
spaces += new Array(level + 2).join(value);
|
||||
whitespaceNode.content = spaces;
|
||||
}
|
||||
}
|
||||
|
||||
function processSpaceNode(node, level, value) {
|
||||
var spaces;
|
||||
|
||||
// Remove all whitespaces and tabs, leave only new lines:
|
||||
spaces = node.content.replace(/[ \t]/gm, '');
|
||||
|
||||
if (!spaces) return;
|
||||
|
||||
spaces += new Array(level + 1).join(value);
|
||||
node.content = spaces;
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'block-indent',
|
||||
|
||||
runBefore: 'sort-order',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: {
|
||||
number: true,
|
||||
string: /^[ \t]*$/
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function process(node) {
|
||||
var spaces;
|
||||
var whitespaceNode;
|
||||
var i;
|
||||
|
||||
if (!node.is('stylesheet')) return;
|
||||
|
||||
syntax = this.getSyntax();
|
||||
value = this.getValue('block-indent');
|
||||
|
||||
|
||||
for (i = node.length; i--;) {
|
||||
whitespaceNode = node.get(i);
|
||||
|
||||
if (!whitespaceNode.is('space')) continue;
|
||||
|
||||
spaces = whitespaceNode.content.replace(/\n[ \t]+/gm, '\n');
|
||||
|
||||
if (spaces === '') {
|
||||
node.remove(i);
|
||||
} else {
|
||||
whitespaceNode.content = spaces;
|
||||
}
|
||||
}
|
||||
|
||||
processNode(node);
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
var result = [];
|
||||
|
||||
// Continue only with non-empty {...} blocks:
|
||||
if (!node.is('atrulers') && !node.is('block') || !node.length)
|
||||
return;
|
||||
|
||||
for (var i = node.length; i--;) {
|
||||
var whitespaceNode = node.get(i);
|
||||
if (!whitespaceNode.is('space')) continue;
|
||||
|
||||
var spaces = whitespaceNode.content;
|
||||
var lastIndex = spaces.lastIndexOf('\n');
|
||||
|
||||
// Do not continue if there is no line break:
|
||||
if (lastIndex < 0) continue;
|
||||
|
||||
// Number of spaces from beginning of line:
|
||||
var spacesLength = spaces.slice(lastIndex + 1).length + 1;
|
||||
result.push(new Array(spacesLength).join(' '));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
})();
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
module.exports = {
|
||||
name: 'color-case',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: { string: /^lower|upper$/ },
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (!node.is('color')) return;
|
||||
|
||||
node.content = this.getValue('color-case') === 'lower' ?
|
||||
node.content.toLowerCase() :
|
||||
node.content.toUpperCase();
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('color')) return;
|
||||
|
||||
if (node.content.match(/^[^A-F]*[a-f][^A-F]*$/)) {
|
||||
return 'lower';
|
||||
} else if (node.content.match(/^[^a-f]*[A-F][^a-f]*$/)) {
|
||||
return 'upper';
|
||||
}
|
||||
}
|
||||
};
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
module.exports = {
|
||||
name: 'color-shorthand',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: { boolean: [true, false] },
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (!node.is('color')) return;
|
||||
|
||||
node.content = this.getValue('color-shorthand') ?
|
||||
node.content.replace(/(\w)\1(\w)\2(\w)\3/i, '$1$2$3') :
|
||||
node.content.replace(/^(\w)(\w)(\w)$/, '$1$1$2$2$3$3');
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('color')) return;
|
||||
|
||||
if (node.content.match(/^\w{3}$/)) {
|
||||
return true;
|
||||
} else if (node.content.match(/^(\w)\1(\w)\2(\w)\3$/)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
module.exports = {
|
||||
name: 'element-case',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: { string: /^lower|upper$/ },
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (!node.is('selector') &&
|
||||
!node.is('arguments')) return;
|
||||
|
||||
var value = this.getValue('element-case');
|
||||
|
||||
node.forEach('simpleSelector', function(selector) {
|
||||
selector.forEach('ident', function(ident) {
|
||||
ident.content = value === 'lower' ?
|
||||
ident.content.toLowerCase() :
|
||||
ident.content.toUpperCase();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('selector') &&
|
||||
!node.is('arguments')) return;
|
||||
|
||||
var variants = [];
|
||||
|
||||
node.forEach('simpleSelector', function(selector) {
|
||||
selector.forEach('ident', function(ident) {
|
||||
if (ident.content.match(/^[a-z]+$/)) {
|
||||
variants.push('lower');
|
||||
} else if (ident.content.match(/^[A-Z]+$/)) {
|
||||
variants.push('upper');
|
||||
}
|
||||
});
|
||||
});
|
||||
return variants;
|
||||
}
|
||||
};
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
var gonzales = require('gonzales-pe');
|
||||
|
||||
module.exports = {
|
||||
name: 'eof-newline',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: { boolean: [true, false] },
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (!node.is('stylesheet')) return;
|
||||
|
||||
var lastChild = node.last();
|
||||
if (!lastChild.is('space')) {
|
||||
lastChild = gonzales.createNode({ type: 'space', content: '' });
|
||||
node.content.push(lastChild);
|
||||
}
|
||||
lastChild.content = lastChild.content.replace(/\n$/, '');
|
||||
if (this.getValue('eof-newline')) lastChild.content += '\n';
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('stylesheet')) return;
|
||||
|
||||
var lastChild = node.last();
|
||||
if (lastChild.is('space') && lastChild.content.indexOf('\n') !== -1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
module.exports = {
|
||||
name: 'leading-zero',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: { boolean: [true, false] },
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (!node.is('number')) return;
|
||||
|
||||
if (this.getValue('leading-zero')) {
|
||||
if (node.content[0] === '.')
|
||||
node.content = '0' + node.content;
|
||||
} else {
|
||||
node.content = node.content.replace(/^0+(?=\.)/, '');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('number')) return;
|
||||
|
||||
if (node.content.match(/^\.[0-9]+/)) {
|
||||
return false;
|
||||
} else if (node.content.match(/^0\.[0-9]+/)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
module.exports = {
|
||||
name: 'quotes',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: { string: /^single|double$/ },
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (!node.is('string')) return;
|
||||
|
||||
var value = this.getValue('quotes');
|
||||
|
||||
if (node.content[0] === '"' && value === 'single') {
|
||||
node.content = node.content
|
||||
.replace(/\\"/g, '"') // unescape all escaped double quotes
|
||||
.replace(/([^\\])'/g, '$1\\\'') // escape all the single quotes
|
||||
.replace(/^"|"$/g, '\''); // replace the first and the last quote
|
||||
|
||||
} else if (node.content[0] === '\'' && value === 'double') {
|
||||
node.content = node.content
|
||||
.replace(/\\'/g, '\'') // unescape all escaped single quotes
|
||||
.replace(/([^\\])"/g, '$1\\\"') // escape all the double quotes
|
||||
.replace(/^'|'$/g, '"'); // replace the first and the last quote
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('string')) return;
|
||||
|
||||
if (node.content[0] === '"') {
|
||||
return 'double';
|
||||
} else if (node.content[0] === '\'') {
|
||||
return 'single';
|
||||
}
|
||||
}
|
||||
};
|
||||
Generated
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
module.exports = (function() {
|
||||
function processNode(node) {
|
||||
removeEmptyRulesets(node);
|
||||
mergeAdjacentWhitespace(node);
|
||||
}
|
||||
|
||||
function removeEmptyRulesets(stylesheet) {
|
||||
stylesheet.forEach('ruleset', function(ruleset, i) {
|
||||
var block = ruleset.first('block');
|
||||
processNode(block);
|
||||
if (isEmptyBlock(block)) stylesheet.remove(i);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removing ruleset nodes from tree may result in two adjacent whitespace
|
||||
* nodes which is not correct AST:
|
||||
* [space, ruleset, space] => [space, space]
|
||||
* To ensure correctness of further processing we should merge such nodes
|
||||
* into one:
|
||||
* [space, space] => [space]
|
||||
*/
|
||||
function mergeAdjacentWhitespace(node) {
|
||||
var i = node.content.length - 1;
|
||||
while (i-- > 0) {
|
||||
if (node.get(i).is('space') && node.get(i + 1).is('space')) {
|
||||
node.get(i).content += node.get(i + 1).content;
|
||||
node.remove(i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Block is considered empty when it has nothing but spaces.
|
||||
*/
|
||||
function isEmptyBlock(node) {
|
||||
if (!node.length) return true;
|
||||
|
||||
return !node.content.some(function(node) {
|
||||
return !node.is('space');
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'remove-empty-rulesets',
|
||||
|
||||
runBefore: 'block-indent',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: { boolean: [true] },
|
||||
|
||||
/**
|
||||
* Remove rulesets with no declarations.
|
||||
*
|
||||
* @param {String} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (!node.is('stylesheet')) return;
|
||||
|
||||
processNode(node);
|
||||
},
|
||||
|
||||
detectDefault: true,
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
* This option is treated as `true` by default, but any trailing space would invalidate it.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('atrulers') && !node.is('block')) return;
|
||||
|
||||
if (node.length === 0 ||
|
||||
(node.length === 1 && node.first().is('space'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
Generated
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
name: 'sort-order-fallback',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: { string: /^abc$/ },
|
||||
|
||||
process: function() {}
|
||||
};
|
||||
+388
@@ -0,0 +1,388 @@
|
||||
var gonzales = require('gonzales-pe');
|
||||
|
||||
module.exports = {
|
||||
name: 'sort-order',
|
||||
|
||||
runBefore: 'space-before-closing-brace',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
/**
|
||||
* Sets handler value.
|
||||
*
|
||||
* @param {Array} value Option value
|
||||
* @returns {Array}
|
||||
*/
|
||||
setValue: function(value) {
|
||||
if (!Array.isArray(value)) throw new Error('The option accepts only array of properties.');
|
||||
|
||||
var order = {};
|
||||
|
||||
if (typeof value[0] === 'string') {
|
||||
value.forEach(function(prop, propIndex) {
|
||||
order[prop] = { group: 0, prop: propIndex };
|
||||
});
|
||||
} else {
|
||||
value.forEach(function(group, groupIndex) {
|
||||
group.forEach(function(prop, propIndex) {
|
||||
order[prop] = { group: groupIndex, prop: propIndex };
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return order;
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
var _this = this;
|
||||
// Types of nodes that can be sorted:
|
||||
var NODES = ['atruleb', 'atruler', 'atrules', 'multilineComment', 'singlelineComment',
|
||||
'declaration', 'space', 'include'];
|
||||
// Spaces and comments:
|
||||
var SC = ['multilineComment', 'singlelineComment', 'space'];
|
||||
|
||||
var currentNode;
|
||||
// Sort order of properties:
|
||||
var order = this.getValue('sort-order');
|
||||
var syntax = this.getSyntax();
|
||||
// List of declarations that should be sorted:
|
||||
var sorted = [];
|
||||
// list of nodes that should be removed from parent node:
|
||||
var deleted = [];
|
||||
// List of spaces and comments that go before declaration/@-rule:
|
||||
var sc0 = [];
|
||||
// Value to search in sort order: either a declaration's property name
|
||||
// (e.g. `color`), or @-rule's special keyword (e.g. `$import`):
|
||||
var propertyName;
|
||||
|
||||
// Index to place the nodes that shouldn't be sorted
|
||||
var lastGroupIndex = order['...'] ? order['...'].group : Infinity;
|
||||
var lastPropertyIndex = order['...'] ? order['...'].prop : Infinity;
|
||||
|
||||
// Counters for loops:
|
||||
var i;
|
||||
var l;
|
||||
var j;
|
||||
var nl;
|
||||
|
||||
/**
|
||||
* Remove empty lines in space node.
|
||||
* @param {node} node Space node.
|
||||
*/
|
||||
var removeEmptyLines = function(node) {
|
||||
node.content = node.content.replace(/\n[\s\t\n\r]*\n/, '\n');
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if there are any comments or spaces before
|
||||
* the declaration/@-rule.
|
||||
* @returns {Array} List of nodes with spaces and comments
|
||||
*/
|
||||
var checkSC0 = function() {
|
||||
// List of nodes with spaces and comments:
|
||||
var sc = [];
|
||||
// List of nodes that can be later deleted from parent node:
|
||||
var d = [];
|
||||
|
||||
for (; i < l; i++) {
|
||||
currentNode = node.get(i);
|
||||
// If there is no node left,
|
||||
// stop and do nothing with previously found spaces/comments:
|
||||
if (!currentNode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the node is declaration or @-rule, stop and return all
|
||||
// found nodes with spaces and comments (if there are any):
|
||||
if (SC.indexOf(currentNode.type) === -1) break;
|
||||
|
||||
sc.push(currentNode);
|
||||
d.push(i);
|
||||
}
|
||||
|
||||
deleted = deleted.concat(d);
|
||||
|
||||
return sc;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if there are any comments or spaces after
|
||||
* the declaration/@-rule.
|
||||
* @returns {Array} List of nodes with spaces and comments
|
||||
* @private
|
||||
*/
|
||||
var checkSC1 = function() {
|
||||
// List of nodes with spaces and comments:
|
||||
var sc = [];
|
||||
// List of nodes that can be later deleted from parent node:
|
||||
var d = [];
|
||||
// Position of `\n` symbol inside a node with spaces:
|
||||
var lbIndex;
|
||||
|
||||
// Check every next node:
|
||||
for (; i < l; i++) {
|
||||
currentNode = node.get(i + 1);
|
||||
// If there is no node, or it is nor spaces neither comment, stop:
|
||||
if (!currentNode || SC.indexOf(currentNode.type) === -1) break;
|
||||
|
||||
if (currentNode.is('multilineComment') || currentNode.is('singlelineComment')) {
|
||||
sc.push(currentNode);
|
||||
d.push(i + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
lbIndex = currentNode.content.indexOf('\n');
|
||||
|
||||
// If there are any line breaks in a node with spaces, stop and
|
||||
// split the node into two: one with spaces before line break
|
||||
// and one with `\n` symbol and everything that goes after.
|
||||
// Combine the first one with declaration/@-rule's node:
|
||||
if (lbIndex > -1) {
|
||||
// TODO: Don't push an empty array
|
||||
var s = currentNode.content.substring(0, lbIndex);
|
||||
var space = gonzales.createNode({ type: 's', content: s });
|
||||
sc.push(space);
|
||||
currentNode.content = currentNode.content.substring(lbIndex);
|
||||
break;
|
||||
}
|
||||
|
||||
sc.push(currentNode);
|
||||
d.push(i + 1);
|
||||
}
|
||||
|
||||
deleted = deleted.concat(d);
|
||||
|
||||
return sc;
|
||||
};
|
||||
|
||||
/**
|
||||
* Combine declaration/@-rule's node with other relevant information:
|
||||
* property index, semicolon, spaces and comments.
|
||||
* @returns {Object} Extended node
|
||||
*/
|
||||
var extendNode = function() {
|
||||
currentNode = node.get(i);
|
||||
var nextNode = node.get(i + 1);
|
||||
// Object containing current node, all corresponding spaces,
|
||||
// comments and other information:
|
||||
var extendedNode;
|
||||
// Check if current node's property name is in sort order.
|
||||
// If it is, save information about its indices:
|
||||
var orderProperty = order[propertyName];
|
||||
|
||||
extendedNode = {
|
||||
i: i,
|
||||
node: currentNode,
|
||||
sc0: sc0,
|
||||
sc1: [],
|
||||
sc2: [],
|
||||
delim: []
|
||||
};
|
||||
|
||||
// If the declaration's property is in order's list, save its
|
||||
// group and property indices. Otherwise set them to 10000, so
|
||||
// declaration appears at the bottom of a sorted list:
|
||||
|
||||
extendedNode.groupIndex = orderProperty && orderProperty.group > -1 ?
|
||||
orderProperty.group : lastGroupIndex;
|
||||
extendedNode.propertyIndex = orderProperty && orderProperty.prop > -1 ?
|
||||
orderProperty.prop : lastPropertyIndex;
|
||||
|
||||
// Mark current node to remove it later from parent node:
|
||||
deleted.push(i);
|
||||
|
||||
extendedNode.sc1 = checkSC1();
|
||||
|
||||
if (extendedNode.sc1.length) {
|
||||
currentNode = node.get(i);
|
||||
nextNode = node.get(i + 1);
|
||||
}
|
||||
|
||||
// If there is `;` right after the declaration, save it with the
|
||||
// declaration and mark it for removing from parent node:
|
||||
if (currentNode && nextNode && nextNode.is('declarationDelimiter')) {
|
||||
extendedNode.delim.push(nextNode);
|
||||
deleted.push(i + 1);
|
||||
i++;
|
||||
|
||||
if (syntax === 'sass') return extendedNode;
|
||||
|
||||
// Save spaces and comments which follow right after the declaration
|
||||
// and mark them for removing from parent node:
|
||||
extendedNode.sc2 = checkSC1();
|
||||
}
|
||||
|
||||
return extendedNode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sorts properties alphabetically.
|
||||
*
|
||||
* @param {Object} a First extended node
|
||||
* @param {Object} b Second extended node
|
||||
* @returns {Number} `-1` if properties should go in order `a, b`. `1`
|
||||
* if properties should go in order `b, a`.
|
||||
*/
|
||||
var sortLeftovers = function(a, b) {
|
||||
var prefixes = ['-webkit-', '-moz-', '-ms-', '-o-', ''];
|
||||
var prefixesRegExp = /^(-webkit-|-moz-|-ms-|-o-)(.*)$/;
|
||||
|
||||
// Get property name (i.e. `color`, `-o-animation`):
|
||||
a = a.node.get(0).get(0).content;
|
||||
b = b.node.get(0).get(0).content;
|
||||
|
||||
// Get prefix and unprefixed part. For example:
|
||||
// ['-o-animation', '-o-', 'animation']
|
||||
// ['color', '', 'color']
|
||||
a = a.match(prefixesRegExp) || [a, '', a];
|
||||
b = b.match(prefixesRegExp) || [b, '', b];
|
||||
|
||||
if (a[2] !== b[2]) {
|
||||
// If unprefixed parts are different (i.e. `border` and
|
||||
// `color`), compare them:
|
||||
return a[2] < b[2] ? -1 : 1;
|
||||
} else {
|
||||
// If unprefixed parts are identical (i.e. `border` in
|
||||
// `-moz-border` and `-o-border`), compare prefixes (they
|
||||
// should go in the same order they are set in `prefixes` array):
|
||||
return prefixes.indexOf(a[1]) < prefixes.indexOf(b[1]) ? -1 : 1;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Think it through!
|
||||
// Sort properties only inside blocks:
|
||||
if (!node.is('block')) return;
|
||||
|
||||
// Check every child node.
|
||||
// If it is declaration (property-value pair, e.g. `color: tomato`),
|
||||
// or @-rule (e.g. `@include nani`),
|
||||
// combine it with spaces, semicolon and comments and move them from
|
||||
// current node to a separate list for further sorting:
|
||||
for (i = 0, l = node.length; i < l; i++) {
|
||||
if (NODES.indexOf(node.get(i).type) === -1) continue;
|
||||
|
||||
// Save preceding spaces and comments, if there are any, and mark
|
||||
// them for removing from parent node:
|
||||
sc0 = checkSC0();
|
||||
if (!sc0) continue;
|
||||
|
||||
// If spaces/comments are the last nodes, stop and go to sorting:
|
||||
if (!node.get(i)) {
|
||||
deleted.splice(deleted.length - sc0.length, deleted.length + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
// Check if the node needs to be sorted:
|
||||
// it should be a special @-rule (e.g. `@include`) or a declaration
|
||||
// with a valid property (e.g. `color` or `$width`).
|
||||
// If not, proceed with the next node:
|
||||
propertyName = null;
|
||||
// Look for includes:
|
||||
if (node.get(i).is('include')) {
|
||||
propertyName = '$include';
|
||||
} else {
|
||||
for (j = 0, nl = node.get(i).length; j < nl; j++) {
|
||||
currentNode = node.get(i).get(j);
|
||||
if (!currentNode) continue;
|
||||
|
||||
if (currentNode.is('property')) {
|
||||
propertyName = currentNode.get(0).is('variable') ?
|
||||
'$variable' : currentNode.get(0).content;
|
||||
break;
|
||||
} else if (currentNode.is('atkeyword') &&
|
||||
currentNode.get(0).content === 'import') { // Look for imports
|
||||
propertyName = '$import';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If current node is not property-value pair or import or include,
|
||||
// skip it and continue with the next node:
|
||||
if (!propertyName) {
|
||||
deleted.splice(deleted.length - sc0.length, deleted.length + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make an extended node and move it to a separate list for further
|
||||
// sorting:
|
||||
sorted.push(extendNode());
|
||||
}
|
||||
|
||||
// Remove all nodes, that were moved to a `sorted` list, from parent node:
|
||||
for (i = deleted.length - 1; i > -1; i--) {
|
||||
node.content.splice(deleted[i], 1);
|
||||
}
|
||||
|
||||
// Sort declarations saved for sorting:
|
||||
sorted.sort(function(a, b) {
|
||||
// If a's group index is higher than b's group index, in a sorted
|
||||
// list a appears after b:
|
||||
if (a.groupIndex !== b.groupIndex) return a.groupIndex - b.groupIndex;
|
||||
|
||||
// If a and b belong to leftovers and `sort-order-fallback` option
|
||||
// is set to `abc`, sort properties alphabetically:
|
||||
if (a.groupIndex === lastGroupIndex &&
|
||||
_this.getValue('sort-order-fallback')) {
|
||||
return sortLeftovers(a, b);
|
||||
}
|
||||
|
||||
// If a and b have the same group index, and a's property index is
|
||||
// higher than b's property index, in a sorted list a appears after
|
||||
// b:
|
||||
if (a.propertyIndex !== b.propertyIndex) return a.propertyIndex - b.propertyIndex;
|
||||
|
||||
// If a and b have the same group index and the same property index,
|
||||
// in a sorted list they appear in the same order they were in
|
||||
// original array:
|
||||
return a.i - b.i;
|
||||
});
|
||||
|
||||
// Build all nodes back together. First go sorted declarations, then
|
||||
// everything else:
|
||||
if (sorted.length > 0) {
|
||||
for (i = sorted.length - 1, l = -1; i > l; i--) {
|
||||
currentNode = sorted[i];
|
||||
var prevNode = sorted[i - 1];
|
||||
sc0 = currentNode.sc0;
|
||||
var sc1 = currentNode.sc1;
|
||||
var sc2 = currentNode.sc2;
|
||||
|
||||
sc0.reverse().map(removeEmptyLines);
|
||||
sc1.reverse().map(removeEmptyLines);
|
||||
sc2.reverse().map(removeEmptyLines);
|
||||
|
||||
// Divide declarations from different groups with an empty line:
|
||||
if (prevNode && currentNode.groupIndex > prevNode.groupIndex) {
|
||||
if (sc0[0] && sc0[0].is('space') &&
|
||||
(this.syntax === 'sass' ||
|
||||
sc0[0].content.match(/\n/g) &&
|
||||
sc0[0].content.match(/\n/g).length < 2)) {
|
||||
sc0[0].content = '\n' + sc0[0].content;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0, nl = sc2.length; j < nl; j++) {
|
||||
node.content.unshift(sc2[j]);
|
||||
}
|
||||
if (currentNode.delim.length > 0) {
|
||||
var delim = this.syntax === 'sass' ? '\n' : ';';
|
||||
var declDelim = gonzales.createNode({ type: 'declarationDelimiter', content: delim });
|
||||
node.content.unshift(declDelim);
|
||||
}
|
||||
for (j = 0, nl = sc1.length; j < nl; j++) {
|
||||
node.content.unshift(sc1[j]);
|
||||
}
|
||||
node.content.unshift(currentNode.node);
|
||||
|
||||
for (j = 0, nl = sc0.length; j < nl; j++) {
|
||||
node.content.unshift(sc0[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
var gonzales = require('gonzales-pe');
|
||||
|
||||
module.exports = {
|
||||
name: 'space-after-colon',
|
||||
|
||||
runBefore: 'block-indent',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: {
|
||||
number: true,
|
||||
string: /^[ \t\n]*$/
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (!node.is('declaration')) return;
|
||||
|
||||
var value = this.getValue('space-after-colon');
|
||||
|
||||
for (var i = node.length; i--;) {
|
||||
if (!node.get(i).is('propertyDelimiter')) continue;
|
||||
|
||||
if (this.getSyntax() === 'sass' && !node.get(i - 1)) break;
|
||||
|
||||
// Remove any spaces after colon:
|
||||
if (node.get(i + 1).is('space')) node.remove(i + 1);
|
||||
// If the value set in config is not empty, add spaces:
|
||||
var space = gonzales.createNode({ type: 'space', content: value });
|
||||
if (value !== '') node.insert(i + 1, space);
|
||||
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('declaration')) return;
|
||||
|
||||
for (var i = node.length; i--;) {
|
||||
if (!node.get(i).is('propertyDelimiter')) continue;
|
||||
|
||||
if (node.get(i + 1).is('space')) {
|
||||
return node.get(i + 1).content;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Generated
Vendored
+60
@@ -0,0 +1,60 @@
|
||||
var gonzales = require('gonzales-pe');
|
||||
|
||||
module.exports = {
|
||||
name: 'space-after-combinator',
|
||||
|
||||
runBefore: 'block-indent',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: {
|
||||
number: true,
|
||||
string: /^[ \t\n]*$/
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (!node.is('selector')) return;
|
||||
|
||||
var value = this.getValue('space-after-combinator');
|
||||
|
||||
node.forEach('simpleSelector', function(simpleSelector) {
|
||||
simpleSelector.forEach('combinator', function(combinator, i) {
|
||||
if (simpleSelector.get(i + 1).is('space')) {
|
||||
simpleSelector.get(i + 1).content = value;
|
||||
} else {
|
||||
var space = gonzales.createNode({ type: 'space', content: value });
|
||||
simpleSelector.insert(i + 1, space);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('selector')) return;
|
||||
|
||||
var variants = [];
|
||||
|
||||
node.forEach('simpleSelector', function(simpleSelector) {
|
||||
simpleSelector.forEach('combinator', function(combinator, i) {
|
||||
if (simpleSelector.get(i + 1).is('space')) {
|
||||
variants.push(simpleSelector.get(i + 1).content);
|
||||
} else {
|
||||
variants.push('');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return variants;
|
||||
}
|
||||
};
|
||||
|
||||
Generated
Vendored
+49
@@ -0,0 +1,49 @@
|
||||
var gonzales = require('gonzales-pe');
|
||||
|
||||
module.exports = {
|
||||
name: 'space-after-opening-brace',
|
||||
|
||||
runBefore: 'block-indent',
|
||||
|
||||
syntax: ['css', 'less', 'scss'],
|
||||
|
||||
accepts: {
|
||||
number: true,
|
||||
string: /^[ \t\n]*$/
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
// If found block node stop at the next one for space check
|
||||
if (!node.is('block') && !node.is('atrulers')) return;
|
||||
|
||||
var value = this.getValue('space-after-opening-brace');
|
||||
|
||||
if (node.first() &&
|
||||
node.first().is('space')) {
|
||||
node.first().content = value;
|
||||
} else if (value !== '') {
|
||||
var space = gonzales.createNode({ type: 'space', content: value });
|
||||
node.insert(0, space);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('block') && !node.is('atrulers')) return;
|
||||
|
||||
if (node.first().is('space')) {
|
||||
return node.first().content;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
};
|
||||
Generated
Vendored
+62
@@ -0,0 +1,62 @@
|
||||
var gonzales = require('gonzales-pe');
|
||||
|
||||
module.exports = {
|
||||
name: 'space-after-selector-delimiter',
|
||||
|
||||
runBefore: 'block-indent',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: {
|
||||
number: true,
|
||||
string: /^[ \t\n]*$/
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (!node.is('selector')) return;
|
||||
|
||||
var value = this.getValue('space-after-selector-delimiter');
|
||||
|
||||
node.forEach('delimiter', function(delimiter, i) {
|
||||
var nextNode = node.get(i + 1);
|
||||
|
||||
if (nextNode.is('space')) {
|
||||
nextNode.content = value;
|
||||
} else if (nextNode.first().is('space')) {
|
||||
nextNode.first().content = value;
|
||||
} else {
|
||||
var space = gonzales.createNode({ type: 'space', content: value });
|
||||
nextNode.insert(0, space);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('selector')) return;
|
||||
|
||||
var variants = [];
|
||||
|
||||
node.forEach('delimiter', function(delimiter, i) {
|
||||
var nextNode = node.get(i + 1);
|
||||
if (nextNode && nextNode.is('space')) {
|
||||
variants.push(nextNode.content);
|
||||
} else if (nextNode.first() && nextNode.first().is('space')) {
|
||||
variants.push(nextNode.first().content);
|
||||
} else {
|
||||
variants.push('');
|
||||
}
|
||||
});
|
||||
|
||||
return variants;
|
||||
}
|
||||
};
|
||||
Generated
Vendored
+103
@@ -0,0 +1,103 @@
|
||||
var gonzales = require('gonzales-pe');
|
||||
|
||||
module.exports = (function() {
|
||||
var valueFromSettings;
|
||||
var blockIndent;
|
||||
|
||||
function getLastWhitespaceNode(node) {
|
||||
var lastNode = node.last();
|
||||
|
||||
if (!lastNode || !lastNode.content) return null;
|
||||
|
||||
if (lastNode.is('block')) return null;
|
||||
if (lastNode.is('space')) return lastNode;
|
||||
|
||||
return getLastWhitespaceNode(lastNode);
|
||||
}
|
||||
|
||||
function processBlock(x, level) {
|
||||
level = level || 0;
|
||||
|
||||
// XXX: Hack for braces
|
||||
if (x.is('braces') || x.is('id')) return;
|
||||
|
||||
x.forEach(function(node) {
|
||||
if (!node.is('block') &&
|
||||
!node.is('atrulers')) return processBlock(node, level);
|
||||
|
||||
level++;
|
||||
|
||||
var value = valueFromSettings;
|
||||
if (value.indexOf('\n') > -1) {
|
||||
// TODO: Check that it works for '' block indent value <tg>
|
||||
if (blockIndent) {
|
||||
value += new Array(level).join(blockIndent);
|
||||
}
|
||||
}
|
||||
|
||||
// If found block node stop at the next one for space check
|
||||
// For the pre-block node, find its last (the deepest) child
|
||||
var whitespaceNode = getLastWhitespaceNode(node);
|
||||
|
||||
// If it's spaces, modify this node
|
||||
// If it's something different from spaces, add a space node to the end
|
||||
if (whitespaceNode) {
|
||||
whitespaceNode.content = value;
|
||||
} else if (value !== '') {
|
||||
var space = gonzales.createNode({ type: 'space', content: value });
|
||||
node.content.push(space);
|
||||
}
|
||||
|
||||
processBlock(node, level);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
name: 'space-before-closing-brace',
|
||||
|
||||
runBefore: 'tab-size',
|
||||
|
||||
syntax: ['css', 'less', 'scss'],
|
||||
|
||||
accepts: {
|
||||
number: true,
|
||||
string: /^[ \t\n]*$/
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
valueFromSettings = this.getValue('space-before-closing-brace');
|
||||
blockIndent = this.getValue('block-indent');
|
||||
|
||||
if (!node.is('stylesheet')) return;
|
||||
|
||||
processBlock(node);
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('block') && !node.is('atrulers')) return;
|
||||
|
||||
var variants = [];
|
||||
|
||||
// For the block node, find its last (the deepest) child
|
||||
var whitespaceNode = getLastWhitespaceNode(node);
|
||||
if (whitespaceNode) {
|
||||
variants.push(whitespaceNode.content);
|
||||
} else {
|
||||
variants.push('');
|
||||
}
|
||||
|
||||
return variants;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
Generated
Vendored
+60
@@ -0,0 +1,60 @@
|
||||
var gonzales = require('gonzales-pe');
|
||||
|
||||
module.exports = {
|
||||
name: 'space-before-colon',
|
||||
|
||||
runBefore: 'block-indent',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: {
|
||||
number: true,
|
||||
string: /^[ \t\n]*$/
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (!node.is('declaration')) return;
|
||||
|
||||
var value = this.getValue('space-before-colon');
|
||||
var syntax = this.getSyntax();
|
||||
|
||||
node.forEach('propertyDelimiter', function(delimiter, i) {
|
||||
if (syntax === 'sass' && !node.get(i - 1)) return;
|
||||
|
||||
// Remove any spaces before colon:
|
||||
if (node.get(i - 1).is('space')) {
|
||||
node.remove(--i);
|
||||
}
|
||||
|
||||
// If the value set in config is not empty, add spaces:
|
||||
var space = gonzales.createNode({ type: 'space', content: value });
|
||||
if (value !== '') node.insert(i, space);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('declaration')) return;
|
||||
|
||||
var result;
|
||||
|
||||
node.forEach('propertyDelimiter', function(delimiter, i) {
|
||||
if (node.get(i - 1).is('space')) {
|
||||
result = node.get(i - 1).content;
|
||||
} else {
|
||||
result = '';
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
Generated
Vendored
+68
@@ -0,0 +1,68 @@
|
||||
var gonzales = require('gonzales-pe');
|
||||
|
||||
module.exports = {
|
||||
name: 'space-before-combinator',
|
||||
|
||||
runBefore: 'block-indent',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: {
|
||||
number: true,
|
||||
string: /^[ \t\n]*$/
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (!node.is('selector')) return;
|
||||
|
||||
var value = this.getValue('space-before-combinator');
|
||||
|
||||
node.forEach(function(simpleSelector) {
|
||||
var notFirst = false;
|
||||
|
||||
simpleSelector.forEach(function(n, i) {
|
||||
if (!n.is('space') && !n.is('combinator')) notFirst = true;
|
||||
|
||||
// If combinator is the first thing in selector,
|
||||
// do not add extra spaces:
|
||||
if (!n.is('combinator') || !notFirst) return;
|
||||
|
||||
if (simpleSelector.get(i - 1).is('space')) {
|
||||
simpleSelector.get(i - 1).content = value;
|
||||
} else {
|
||||
var space = gonzales.createNode({ type: 'space', content: value });
|
||||
simpleSelector.insert(i, space);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('selector')) return;
|
||||
|
||||
var variants = [];
|
||||
|
||||
node.forEach(function(simpleSelector) {
|
||||
simpleSelector.forEach('combinator', function(combinator, i) {
|
||||
if (simpleSelector.get(i - 1).is('space')) {
|
||||
variants.push(simpleSelector.get(i - 1).content);
|
||||
} else {
|
||||
variants.push('');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return variants;
|
||||
}
|
||||
};
|
||||
|
||||
Generated
Vendored
+99
@@ -0,0 +1,99 @@
|
||||
var gonzales = require('gonzales-pe');
|
||||
|
||||
module.exports = (function() {
|
||||
/**
|
||||
* Gets the last (the deepest) whitespace node.
|
||||
*
|
||||
* @param {node} node
|
||||
* @returns {node|undefined} If no whitespace node is found, returns
|
||||
* `undefined`
|
||||
*/
|
||||
function getLastWhitespaceNode(node) {
|
||||
if (typeof node !== 'object') return;
|
||||
if (node.is('space')) return node;
|
||||
|
||||
return getLastWhitespaceNode(node.last());
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'space-before-opening-brace',
|
||||
|
||||
runBefore: 'block-indent',
|
||||
|
||||
syntax: ['css', 'less', 'scss'],
|
||||
|
||||
accepts: {
|
||||
number: true,
|
||||
string: /^[ \t\n]*$/
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
var value = this.getValue('space-before-opening-brace');
|
||||
|
||||
// XXX: Hack for braces
|
||||
if (node.is('braces') || node.is('id')) return;
|
||||
|
||||
node.forEach(function(block, i) {
|
||||
// If found block node stop at the next one for space check:
|
||||
if (!block.is('block') && !block.is('atrulers')) return;
|
||||
|
||||
// For the pre-block node, find its last (the deepest) child:
|
||||
// TODO: Exclude nodes with braces (for example, arguments)
|
||||
var previousNode = node.get(i - 1);
|
||||
var whitespaceNode = getLastWhitespaceNode(previousNode);
|
||||
|
||||
// If it's spaces, modify this node.
|
||||
// If it's something different from spaces, add a space node to
|
||||
// the end:
|
||||
if (whitespaceNode) {
|
||||
whitespaceNode.content = value;
|
||||
} else if (value !== '') {
|
||||
var space = gonzales.createNode({ type: 'space', content: value });
|
||||
if (previousNode && previousNode.is('atrulerq')) {
|
||||
previousNode.content.push(space);
|
||||
} else {
|
||||
node.insert(i, space);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
var variants = [];
|
||||
|
||||
// XXX: Hack for braces
|
||||
if (node.is('braces') || node.is('id')) return [];
|
||||
|
||||
node.forEach(function(block, i) {
|
||||
// If found block node stop at the next one for space check:
|
||||
if (!block.is('block') && !block.is('atrulers')) return;
|
||||
|
||||
// For the pre-block node, find its last (the deepest) child:
|
||||
// TODO: Exclude nodes with braces (for example, arguments)
|
||||
var previousNode = node.get(i - 1);
|
||||
var whitespaceNode = getLastWhitespaceNode(previousNode);
|
||||
|
||||
// If it's spaces, modify this node.
|
||||
// If it's something different from spaces, add a space node to
|
||||
// the end:
|
||||
if (whitespaceNode) {
|
||||
variants.push(whitespaceNode.content);
|
||||
} else {
|
||||
variants.push('');
|
||||
}
|
||||
});
|
||||
|
||||
return variants;
|
||||
}
|
||||
};
|
||||
})();
|
||||
Generated
Vendored
+57
@@ -0,0 +1,57 @@
|
||||
var gonzales = require('gonzales-pe');
|
||||
|
||||
module.exports = {
|
||||
name: 'space-before-selector-delimiter',
|
||||
|
||||
runBefore: 'block-indent',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: {
|
||||
number: true,
|
||||
string: /^[ \t\n]*$/
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (!node.is('selector')) return;
|
||||
|
||||
var value = this.getValue('space-before-selector-delimiter');
|
||||
|
||||
node.forEach('delimiter', function(delim, i) {
|
||||
var previousNode = node.get(i - 1);
|
||||
if (previousNode.last().is('space')) {
|
||||
previousNode.last().content = value;
|
||||
} else {
|
||||
var space = gonzales.createNode({ type: 'space', content: value });
|
||||
previousNode.content.push(space);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('selector')) return;
|
||||
|
||||
var variants = [];
|
||||
|
||||
node.forEach('delimiter', function(delim, i) {
|
||||
var previousNode = node.get(i - 1);
|
||||
if (previousNode.last().is('space')) {
|
||||
variants.push(previousNode.last().content);
|
||||
} else {
|
||||
variants.push('');
|
||||
}
|
||||
});
|
||||
|
||||
return variants;
|
||||
}
|
||||
};
|
||||
Generated
Vendored
+97
@@ -0,0 +1,97 @@
|
||||
var gonzales = require('gonzales-pe');
|
||||
|
||||
module.exports = (function() {
|
||||
function getDeclarationEnd(node, i) {
|
||||
for (;i < node.length; i++) {
|
||||
if (!node.get(i + 1) || typeof node.get(i + 1) === 'string') {
|
||||
return 0;
|
||||
} else if (node.get(i + 1).is('space')) {
|
||||
if (node.get(i + 1).content.indexOf('\n') > -1) {
|
||||
if (node.get(i + 2) && node.get(i + 2).is('declaration')) {
|
||||
return i;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else if (node.get(i + 2) && node.get(i + 2).is('multilineComment')) {
|
||||
if (node.get(i + 3) && node.get(i + 3).is('declaration')) {
|
||||
return i + 2;
|
||||
} else if (node.get(i + 3) && node.get(i + 3).is('space')) {
|
||||
if (node.get(i + 4) && node.get(i + 4).is('declaration')) {
|
||||
return i + 2;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else if (node.get(i + 2) && node.get(i + 2).is('declaration')) {
|
||||
return i;
|
||||
}
|
||||
} else if (node.get(i + 1).is('declaration')) {
|
||||
return i;
|
||||
} else if (node.get(i + 1).is('multilineComment')) {
|
||||
if (node.get(i + 2) && node.get(i + 2).is('declaration')) {
|
||||
return i + 1;
|
||||
} else if (node.get(i + 2) && node.get(i + 2).is('space')) {
|
||||
if (node.get(i + 3) && node.get(i + 3).is('declaration')) {
|
||||
return i + 1;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'space-between-declarations',
|
||||
|
||||
runBefore: 'block-indent',
|
||||
|
||||
syntax: ['css', 'less', 'scss'],
|
||||
|
||||
accepts: {
|
||||
number: true,
|
||||
string: /^[ \t\n]*$/
|
||||
},
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
var value = this.getValue('space-between-declarations');
|
||||
|
||||
// TODO: Limit nodes to blocks, stylesheet, etc.
|
||||
// XXX: Hack for braces
|
||||
if (node.is('braces') || node.is('id')) return;
|
||||
|
||||
for (var i = 0, l = node.length; i < l; i++) {
|
||||
if (!node.get(i) || !node.get(i).is('declarationDelimiter')) continue;
|
||||
|
||||
// Grom user's point of view "declaration" includes semicolons
|
||||
// and comments placed on the same line.
|
||||
// So group those things together:
|
||||
var declarationEnd = getDeclarationEnd(node, i);
|
||||
if (!declarationEnd) {
|
||||
continue;
|
||||
} else {
|
||||
i = declarationEnd;
|
||||
}
|
||||
|
||||
var nextNode = node.get(i + 1);
|
||||
if (nextNode.is('space')) {
|
||||
nextNode.content = value;
|
||||
} else {
|
||||
i++;
|
||||
l++;
|
||||
var space = gonzales.createNode({ type: 'space', content: value });
|
||||
node.insert(i, space);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
module.exports = (function() {
|
||||
/**
|
||||
* Trim trailing spaces on each line.
|
||||
* @private
|
||||
* @param {String} string Spaceful string
|
||||
* @returns {String}
|
||||
*/
|
||||
function trim(string) {
|
||||
return string.replace(/[ \t]+\n/g, '\n');
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'strip-spaces',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: { boolean: [true] },
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (node.is('space')) {
|
||||
node.content = trim(node.content);
|
||||
} else if (node.is('stylesheet')) {
|
||||
var lastChild = node.last();
|
||||
if (lastChild.is('space')) {
|
||||
lastChild.content = trim(lastChild.content)
|
||||
.replace(/[ \t]+$/, '')
|
||||
.replace(/[\n]+/g, '\n');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
detectDefault: true,
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
* This option is treated as `true` by default, but any trailing space would invalidate it.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (node.is('space') &&
|
||||
node.content.match(/[ \t]\n/)) {
|
||||
return false;
|
||||
} else if (node.is('stylesheet')) {
|
||||
var lastChild = node.last();
|
||||
if (lastChild.is('space') &&
|
||||
lastChild.content !== '\n' &&
|
||||
lastChild.content.match(/^[ \n\t]+$/)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
module.exports = {
|
||||
name: 'tab-size',
|
||||
|
||||
runBefore: 'vendor-prefix-align',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: { number: true },
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (!node.is('space')) return;
|
||||
node.content = node.content.replace(/\t/, this.getValue('tab-size'));
|
||||
}
|
||||
};
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
module.exports = {
|
||||
name: 'unitless-zero',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: { boolean: [true] },
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
var UNITS = ['cm', 'em', 'ex', 'pt', 'px'];
|
||||
|
||||
if (!node.is('value') && !node.is('braces')) return;
|
||||
|
||||
node.forEach(function(value) {
|
||||
if (typeof value === 'string') return;
|
||||
|
||||
if (value.is('dimension')) {
|
||||
var unit = value.first('ident').content;
|
||||
if (value.first('number').content === '0' &&
|
||||
UNITS.indexOf(unit) !== -1) {
|
||||
value.remove(1);
|
||||
}
|
||||
} else if (value.is('percentage')) {
|
||||
// XXX(tonyganch): There is a bug in Gonzales when in Less,
|
||||
// percentage's content is not wrapped as an array but actually
|
||||
// type of node's content is object. This bug has already been
|
||||
// fixed in newer versions of Gonzales so the issue should be
|
||||
// gone after update of dependencies and csscomb@4.0 release.
|
||||
// This hack is here as a hotfix for csscomb@3.1 and must be
|
||||
// removed once csscom@4.0 is released. See #389.
|
||||
var number;
|
||||
if (!Array.isArray(value.content) &&
|
||||
value.content.is('number')) {
|
||||
number = value.content;
|
||||
} else {
|
||||
number = value.first('number').content;
|
||||
}
|
||||
|
||||
if (number === '0') {
|
||||
value.type = 'number';
|
||||
value.content = number;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
var result;
|
||||
|
||||
// If we see a zero with unit and it is not degree, then we don’t have an option
|
||||
|
||||
if (node.is('percentage') && node.first('number').content[1] === '0') {
|
||||
result = false;
|
||||
} else if (node.is('dimension') &&
|
||||
node.first('number').content === '0' &&
|
||||
node.first('ident').content !== 'deg') {
|
||||
result = false;
|
||||
}
|
||||
|
||||
// If we see a zero and previous node is not percentage or dimension, then we have an option
|
||||
if (node.is('number') &&
|
||||
node.content === '0' &&
|
||||
this._prev !== 'percentage' &&
|
||||
this._prev !== 'dimension') {
|
||||
result = true;
|
||||
}
|
||||
|
||||
// Store the previous nodeType
|
||||
this._prev = node.type;
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
Generated
Vendored
+436
@@ -0,0 +1,436 @@
|
||||
var gonzales = require('gonzales-pe');
|
||||
|
||||
module.exports = (function() {
|
||||
// Vendor prefixes list:
|
||||
var PREFIXES = [
|
||||
'webkit',
|
||||
'khtml',
|
||||
'moz',
|
||||
'ms',
|
||||
'o'
|
||||
];
|
||||
|
||||
var oneline;
|
||||
|
||||
/**
|
||||
* Makes namespace from property name.
|
||||
*
|
||||
* @param {String} propertyName
|
||||
* @returns {String|undefined}
|
||||
*/
|
||||
function makeNamespace(propertyName) {
|
||||
var info = getPrefixInfo(propertyName);
|
||||
return info && info.baseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates object which contains info about vendor prefix used in propertyName.
|
||||
*
|
||||
* @param {String} propertyName property name
|
||||
* @param {String} [namespace=''] namespace name
|
||||
* @param {Number} [extraSymbols=0] extra symbols count
|
||||
* @returns {Object|undefined}
|
||||
*/
|
||||
function getPrefixInfo(propertyName, namespace, extraSymbols) {
|
||||
var baseName = propertyName;
|
||||
var prefixLength = 0;
|
||||
|
||||
namespace = namespace || '';
|
||||
extraSymbols = extraSymbols || 0;
|
||||
|
||||
if (!propertyName) return;
|
||||
|
||||
PREFIXES.some(function(prefix) {
|
||||
prefix = '-' + prefix + '-';
|
||||
if (propertyName.indexOf(prefix) !== 0) return;
|
||||
|
||||
baseName = baseName.substr(prefix.length);
|
||||
prefixLength = prefix.length;
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return {
|
||||
id: namespace + baseName,
|
||||
baseName: baseName,
|
||||
prefixLength: prefixLength,
|
||||
extra: extraSymbols
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns extra indent for item in arguments
|
||||
*
|
||||
* @param {Array} nodes nodes to process
|
||||
* @returns {Number|undefined}
|
||||
*/
|
||||
function extraIndent(nodes) {
|
||||
if (!nodes || !nodes.length) return;
|
||||
|
||||
var node;
|
||||
var crPos;
|
||||
var tabPos;
|
||||
var result = 0;
|
||||
|
||||
for (var i = nodes.length; i--;) {
|
||||
node = nodes[i];
|
||||
|
||||
if (!node.content) {
|
||||
crPos = -1;
|
||||
} else {
|
||||
crPos = node.content.lastIndexOf('\n');
|
||||
tabPos = node.content.lastIndexOf('\t');
|
||||
if (tabPos > crPos) crPos = tabPos;
|
||||
}
|
||||
|
||||
if (crPos !== -1)
|
||||
oneline = false;
|
||||
|
||||
if (node.is('space')) {
|
||||
result += node.content.length - crPos - 1;
|
||||
if (crPos !== -1)
|
||||
break;
|
||||
}
|
||||
if (node.is('multilineComment')) {
|
||||
if (crPos === -1) {
|
||||
result += node.content.length + 4 /* comment symbols length */ ;
|
||||
} else {
|
||||
result += node.content.length - crPos + 1 /* only last comment symbols length - 1(not count \n)*/;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for extra indent function for `property` node.
|
||||
*
|
||||
* @param {Array} nodes all nodes
|
||||
* @param {Number} i position in nodes array
|
||||
*/
|
||||
function extraIndentProperty(nodes, i) {
|
||||
var subset = [];
|
||||
while (i--) {
|
||||
if (!nodes.get(i) || nodes.get(i).is('declarationDelimiter'))
|
||||
break;
|
||||
subset.unshift(nodes.get(i));
|
||||
}
|
||||
return extraIndent(subset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for extra indent function for val-node.
|
||||
*
|
||||
* @param {Array} nodes all nodes
|
||||
* @param {Number} i position in nodes array
|
||||
*/
|
||||
function extraIndentVal(nodes, i) {
|
||||
var subset = [];
|
||||
var declaration = nodes.get(i);
|
||||
if (!declaration.is('declaration')) return;
|
||||
|
||||
for (var x = declaration.length; x--;) {
|
||||
if (!declaration.get(x).is('value')) continue;
|
||||
|
||||
x--;
|
||||
|
||||
while (!declaration.get(x).is('propertyDelimiter')) {
|
||||
subset.push(declaration.get(x));
|
||||
x--;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
return extraIndent(subset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks across nodes, and call payload for every node that pass selector check.
|
||||
*
|
||||
* @param {Object} args arguments in form of:
|
||||
* {
|
||||
* node: {object} current node,
|
||||
* selector: {function} propertyName selector
|
||||
* payload: {function} work to do with gathered info
|
||||
* namespaceSelector: {function} selector for namespace
|
||||
* getExtraSymbols: {Number} extra symbols count
|
||||
* }
|
||||
*/
|
||||
function walk(args) {
|
||||
args.node.forEach(function(item, i) {
|
||||
var name = args.selector(item);
|
||||
var namespace = args.namespaceSelector && makeNamespace(args.namespaceSelector(item));
|
||||
var extraSymbols = args.getExtraSymbols(args.node, i);
|
||||
|
||||
var info = name && getPrefixInfo(name, namespace, extraSymbols);
|
||||
if (!info) return;
|
||||
args.payload(info, i);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns property name.
|
||||
* e.g.
|
||||
* for: 'color: #fff'
|
||||
* returns string: 'color'
|
||||
*
|
||||
* @param {node} node
|
||||
* @returns {String|undefined}
|
||||
*/
|
||||
function getPropertyName(node) {
|
||||
if (!node.is('declaration')) return;
|
||||
// TODO: Check that it's not a variable
|
||||
return node.get(0).get(0).content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns property value name.
|
||||
* e.g.
|
||||
* for: '-webkit-transition: -webkit-transform 150ms linear'
|
||||
* returns string: '-webkit-transform', and
|
||||
* for: 'background: -webkit-linear-gradient(...)'
|
||||
* returns string: '-webkit-linear-gradient'
|
||||
*
|
||||
* @param {node} node
|
||||
* @returns {String|undefined}
|
||||
*/
|
||||
function getValName(node) {
|
||||
if (!node.is('declaration')) return;
|
||||
|
||||
var value = node.first('value');
|
||||
if (value.get(0).is('ident')) return value.get(0).content;
|
||||
if (value.get(0).is('function')) return value.get(0).get(0).content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates dict which contains info about items align.
|
||||
*
|
||||
* @param {Object} info,
|
||||
* @param {Object} dict,
|
||||
*/
|
||||
function updateDict(info, dict) {
|
||||
if (info.prefixLength === 0 && info.extra === 0) return;
|
||||
|
||||
var indent = dict[info.id] || { prefixLength: 0, extra: 0 };
|
||||
|
||||
dict[info.id] = indent.prefixLength + indent.extra > info.prefixLength + info.extra ?
|
||||
indent :
|
||||
{
|
||||
prefixLength: info.prefixLength,
|
||||
extra: info.extra,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns string with correct number of spaces for info.baseName property.
|
||||
*
|
||||
* @param {Object} info,
|
||||
* @param {Object} dict,
|
||||
* @param {String} whitespaceNode
|
||||
* @returns {String}
|
||||
*/
|
||||
function updateIndent(info, dict, whitespaceNode) {
|
||||
var item = dict[info.id];
|
||||
if (!item)
|
||||
return whitespaceNode;
|
||||
|
||||
var crPos = whitespaceNode.lastIndexOf('\n');
|
||||
var tabPos = whitespaceNode.lastIndexOf('\t');
|
||||
if (tabPos > crPos) crPos = tabPos;
|
||||
|
||||
var firstPart = whitespaceNode.substr(0, crPos + 1 );
|
||||
var extraIndent = new Array(
|
||||
(item.prefixLength - info.prefixLength) +
|
||||
(item.extra - info.extra) +
|
||||
whitespaceNode.length - firstPart.length +
|
||||
1).join(' ');
|
||||
|
||||
return firstPart.concat(extraIndent);
|
||||
}
|
||||
|
||||
return {
|
||||
name: 'vendor-prefix-align',
|
||||
|
||||
syntax: ['css', 'less', 'sass', 'scss'],
|
||||
|
||||
accepts: { boolean: [true] },
|
||||
|
||||
/**
|
||||
* Processes tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
process: function(node) {
|
||||
if (!node.is('block')) return;
|
||||
oneline = true;
|
||||
|
||||
var dict = {};
|
||||
|
||||
// Gathering Info
|
||||
walk({
|
||||
node: node,
|
||||
selector: getPropertyName,
|
||||
getExtraSymbols: extraIndentProperty,
|
||||
payload: function(info) {
|
||||
updateDict(info, dict);
|
||||
}
|
||||
});
|
||||
|
||||
walk({
|
||||
node: node,
|
||||
selector: getValName,
|
||||
namespaceSelector: getPropertyName,
|
||||
getExtraSymbols: extraIndentVal,
|
||||
payload: function(info) {
|
||||
updateDict(info, dict);
|
||||
}
|
||||
});
|
||||
|
||||
if (oneline && this.getSyntax() !== 'sass') return;
|
||||
|
||||
// Update nodes
|
||||
walk({
|
||||
node: node,
|
||||
selector: getValName,
|
||||
namespaceSelector: getPropertyName,
|
||||
getExtraSymbols: extraIndentVal,
|
||||
payload: function(info, i) {
|
||||
for (var x = node.get(i).length; x--;) {
|
||||
if (node.get(i).get(x).is('value')) break;
|
||||
}
|
||||
|
||||
if (!node.get(i).get(x - 1).is('space')) {
|
||||
var space = gonzales.createNode({ type: 'space', content: '' });
|
||||
node.get(i).insert(x, space);
|
||||
++x;
|
||||
}
|
||||
|
||||
node.get(i).get(x - 1).content = updateIndent(info, dict, node.get(i).get(x - 1).content);
|
||||
}
|
||||
});
|
||||
|
||||
if (this.getSyntax() === 'sass') return;
|
||||
|
||||
walk({
|
||||
node: node,
|
||||
selector: getPropertyName,
|
||||
getExtraSymbols: extraIndentProperty,
|
||||
payload: function(info, i) {
|
||||
// `node.get(i - 1)` can be either space or comment:
|
||||
var whitespaceNode = node.get(i - 1);
|
||||
if (!whitespaceNode) return;
|
||||
// If it's a comment, insert an empty space node:
|
||||
if (!whitespaceNode.is('space')) {
|
||||
whitespaceNode = gonzales.createNode({ type: 'space', content: '' });
|
||||
node.insert(i - 1, whitespaceNode);
|
||||
}
|
||||
whitespaceNode.content = updateIndent(info, dict, whitespaceNode.content);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Detects the value of an option at the tree node.
|
||||
*
|
||||
* @param {node} node
|
||||
*/
|
||||
detect: function(node) {
|
||||
if (!node.is('block')) return;
|
||||
|
||||
var result = {
|
||||
true: 0,
|
||||
false: 0
|
||||
};
|
||||
|
||||
var maybePrefix = false;
|
||||
var prevPrefixLength = false;
|
||||
var prevProp;
|
||||
var prevSum;
|
||||
var partialResult = null;
|
||||
|
||||
var getResult = function(node, sum, info, i) {
|
||||
var prop = info.baseName;
|
||||
|
||||
// If this is the last item in a row and we have a result, then catch it
|
||||
if (prop !== prevProp && partialResult !== null) {
|
||||
if (partialResult) {
|
||||
result.true++;
|
||||
} else {
|
||||
result.false++;
|
||||
}
|
||||
partialResult = null;
|
||||
}
|
||||
|
||||
if (prop === prevProp && info.prefixLength !== prevPrefixLength) {
|
||||
maybePrefix = true;
|
||||
} else {
|
||||
maybePrefix = false;
|
||||
}
|
||||
|
||||
if (maybePrefix && partialResult !== false) {
|
||||
// If there is prefixed prop, check if the prefixes are aligned,
|
||||
// but only if we hadn't already catched that it is false
|
||||
if (sum === prevSum) {
|
||||
partialResult = true;
|
||||
} else {
|
||||
partialResult = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.length === i + 3 && partialResult !== null) {
|
||||
// If we're at the last property and have a result, catch it
|
||||
if (partialResult) {
|
||||
result.true++;
|
||||
} else {
|
||||
result.false++;
|
||||
}
|
||||
}
|
||||
|
||||
prevPrefixLength = info.prefixLength;
|
||||
prevProp = prop;
|
||||
prevSum = sum;
|
||||
};
|
||||
|
||||
// Gathering Info
|
||||
walk({
|
||||
node: node,
|
||||
selector: getPropertyName,
|
||||
getExtraSymbols: extraIndentProperty,
|
||||
payload: function(info, i) {
|
||||
if (node.get(i - 1) && node.get(i - 1).content) {
|
||||
var sum = node.get(i - 1).content.
|
||||
replace(/^[ \t]*\n+/, '').length + info.prefixLength;
|
||||
getResult(node, sum, info, i);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
walk({
|
||||
node: node,
|
||||
selector: getValName,
|
||||
getExtraSymbols: extraIndentVal,
|
||||
payload: function(info, i) {
|
||||
for (var x = node.get(i).length; x--;) {
|
||||
if (node.get(i).get(x).is('value')) break;
|
||||
}
|
||||
|
||||
if (node.get(i).get(x - 1)) {
|
||||
var sum = node.get(i).get(x - 1).content
|
||||
.replace(/^[ \t]*\n+/, '').length + info.prefixLength;
|
||||
getResult(node, sum, info, i);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (result.true > 0 || result.false > 0) {
|
||||
if (result.true >= result.false) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user