Diff
checker
Texto
Texto
Imagens
Documentos
Excel
Pastas
Legal
Enterprise
Aplicativo para desktop
Preços
Fazer login
Baixar o Diffchecker Desktop
Comparar texto
Encontre a diferença entre dois arquivos de texto
Ferramentas
Histórico
Editor live
Recolher inalteradas
Sem quebra de linha
Layout
Dividido
Unificado
Nível de detalhe
Inteligente
Palavra
Caractere
Realce de sintaxe
Escolher sintaxe
Ignorar
Transformar texto
Ir à primeira mudança
Editar entrada
Diffchecker Desktop
A maneira mais segura de usar o Diffchecker. Obtenha o aplicativo Diffchecker Desktop: seus diffs nunca saem do seu computador!
Obter Desktop
Untitled diff
Criado
há 11 anos
O diff nunca expira
Limpar
Exportar
Compartilhar
Explicar
8 remoções
Linhas
Total
Removido
Caracteres
Total
Removido
Para continuar usando este recurso, atualize para
Diff
checker
Pro
Ver preços
382 linhas
Copiar tudo
27 adições
Linhas
Total
Adicionado
Caracteres
Total
Adicionado
Para continuar usando este recurso, atualize para
Diff
checker
Pro
Ver preços
398 linhas
Copiar tudo
module.exports = {
module.exports = {
name: 'sort-order',
name: 'sort-order',
runBefore: 'space-before-closing-brace',
runBefore: 'space-before-closing-brace',
syntax: ['css', 'less', 'sass', 'scss'],
syntax: ['css', 'less', 'sass', 'scss'],
/**
/**
* Sets handler value.
* Sets handler value.
*
*
* @param {Array} value Option value
* @param {Array} value Option value
* @returns {Array}
* @returns {Array}
*/
*/
setValue: function(value) {
setValue: function(value) {
if (!Array.isArray(value)) throw new Error('The option accepts only array of properties.');
if (!Array.isArray(value)) throw new Error('The option accepts only array of properties.');
var order = {};
var order = {};
if (typeof value[0] === 'string') {
if (typeof value[0] === 'string') {
value.forEach(function(prop, propIndex) {
value.forEach(function(prop, propIndex) {
order[prop] = { group: 0, prop: propIndex };
order[prop] = { group: 0, prop: propIndex };
});
});
} else {
} else {
value.forEach(function(group, groupIndex) {
value.forEach(function(group, groupIndex) {
Copiar
Copiado
Copiar
Copiado
var groupComment,
isComment = /\/\*(.*?)\*\//g;
group.forEach(function(prop, propIndex) {
group.forEach(function(prop, propIndex) {
Copiar
Copiado
Copiar
Copiado
order[prop] = { group: groupIndex, prop: propIndex };
if (isComment.test(prop)) {
groupComment = prop.replace(isComment, '$1');
} else {
order[prop] = {
comment: groupComment,
group: groupIndex,
prop: propIndex
};
}
});
});
});
});
}
}
return order;
return order;
},
},
/**
/**
* Processes tree node.
* Processes tree node.
* @param {String} nodeType
* @param {String} nodeType
* @param {node} node
* @param {node} node
*/
*/
process: function(nodeType, node) {
process: function(nodeType, node) {
var _this = this;
var _this = this;
// Types of nodes that can be sorted:
// Types of nodes that can be sorted:
var NODES = ['atruleb', 'atruler', 'atrules', 'commentML', 'commentSL',
var NODES = ['atruleb', 'atruler', 'atrules', 'commentML', 'commentSL',
'declaration', 's', 'include'];
'declaration', 's', 'include'];
// Spaces and comments:
// Spaces and comments:
var SC = ['commentML', 'commentSL', 's'];
var SC = ['commentML', 'commentSL', 's'];
var currentNode;
var currentNode;
// Sort order of properties:
// Sort order of properties:
var order = this.getValue('sort-order');
var order = this.getValue('sort-order');
var syntax = this.getSyntax();
var syntax = this.getSyntax();
// List of declarations that should be sorted:
// List of declarations that should be sorted:
var sorted = [];
var sorted = [];
// list of nodes that should be removed from parent node:
// list of nodes that should be removed from parent node:
var deleted = [];
var deleted = [];
// List of spaces and comments that go before declaration/@-rule:
// List of spaces and comments that go before declaration/@-rule:
var sc0 = [];
var sc0 = [];
// Value to search in sort order: either a declaration's property name
// Value to search in sort order: either a declaration's property name
// (e.g. `color`), or @-rule's special keyword (e.g. `$import`):
// (e.g. `color`), or @-rule's special keyword (e.g. `$import`):
var propertyName;
var propertyName;
// Index to place the nodes that shouldn't be sorted
// Index to place the nodes that shouldn't be sorted
var lastGroupIndex = order['...'] ? order['...'].group : Infinity;
var lastGroupIndex = order['...'] ? order['...'].group : Infinity;
var lastPropertyIndex = order['...'] ? order['...'].prop : Infinity;
var lastPropertyIndex = order['...'] ? order['...'].prop : Infinity;
// Counters for loops:
// Counters for loops:
var i;
var i;
var l;
var l;
var j;
var j;
var nl;
var nl;
/**
/**
* Check if there are any comments or spaces before
* Check if there are any comments or spaces before
* the declaration/@-rule.
* the declaration/@-rule.
* @returns {Array} List of nodes with spaces and comments
* @returns {Array} List of nodes with spaces and comments
*/
*/
var checkSC0 = function() {
var checkSC0 = function() {
// List of nodes with spaces and comments:
// List of nodes with spaces and comments:
var sc = [];
var sc = [];
// List of nodes that can be later deleted from parent node:
// List of nodes that can be later deleted from parent node:
var d = [];
var d = [];
for (; i < l; i++) {
for (; i < l; i++) {
currentNode = node[i];
currentNode = node[i];
// If there is no node left,
// If there is no node left,
// stop and do nothing with previously found spaces/comments:
// stop and do nothing with previously found spaces/comments:
if (!currentNode) {
if (!currentNode) {
return false;
return false;
}
}
// Remove any empty lines:
// Remove any empty lines:
if (currentNode[0] === 's') {
if (currentNode[0] === 's') {
currentNode[1] = currentNode[1].replace(/\n[\s\t\n\r]*\n/, '\n');
currentNode[1] = currentNode[1].replace(/\n[\s\t\n\r]*\n/, '\n');
}
}
// If the node is declaration or @-rule, stop and return all
// If the node is declaration or @-rule, stop and return all
// found nodes with spaces and comments (if there are any):
// found nodes with spaces and comments (if there are any):
if (SC.indexOf(currentNode[0]) === -1) break;
if (SC.indexOf(currentNode[0]) === -1) break;
sc.push(currentNode);
sc.push(currentNode);
d.push(i);
d.push(i);
}
}
deleted = deleted.concat(d);
deleted = deleted.concat(d);
return sc;
return sc;
};
};
/**
/**
* Check if there are any comments or spaces after
* Check if there are any comments or spaces after
* the declaration/@-rule.
* the declaration/@-rule.
* @returns {Array} List of nodes with spaces and comments
* @returns {Array} List of nodes with spaces and comments
* @private
* @private
*/
*/
var checkSC1 = function() {
var checkSC1 = function() {
// List of nodes with spaces and comments:
// List of nodes with spaces and comments:
var sc = [];
var sc = [];
// List of nodes that can be later deleted from parent node:
// List of nodes that can be later deleted from parent node:
var d = [];
var d = [];
// Position of `\n` symbol inside a node with spaces:
// Position of `\n` symbol inside a node with spaces:
var lbIndex;
var lbIndex;
// Check every next node:
// Check every next node:
for (; i < l; i++) {
for (; i < l; i++) {
currentNode = node[i + 1];
currentNode = node[i + 1];
// If there is no node, or it is nor spaces neither comment, stop:
// If there is no node, or it is nor spaces neither comment, stop:
if (!currentNode || SC.indexOf(currentNode[0]) === -1) break;
if (!currentNode || SC.indexOf(currentNode[0]) === -1) break;
// Remove any empty lines:
// Remove any empty lines:
if (currentNode[0] === 's') {
if (currentNode[0] === 's') {
currentNode[1] = currentNode[1].replace(/\n[\s\t\n\r]*\n/, '\n');
currentNode[1] = currentNode[1].replace(/\n[\s\t\n\r]*\n/, '\n');
}
}
if (['commentML', 'commentSL'].indexOf(currentNode[0]) > -1) {
if (['commentML', 'commentSL'].indexOf(currentNode[0]) > -1) {
sc.push(currentNode);
sc.push(currentNode);
d.push(i + 1);
d.push(i + 1);
continue;
continue;
}
}
lbIndex = currentNode[1].indexOf('\n');
lbIndex = currentNode[1].indexOf('\n');
// If there are any line breaks in a node with spaces, stop and
// If there are any line breaks in a node with spaces, stop and
// split the node into two: one with spaces before line break
// split the node into two: one with spaces before line break
// and one with `\n` symbol and everything that goes after.
// and one with `\n` symbol and everything that goes after.
// Combine the first one with declaration/@-rule's node:
// Combine the first one with declaration/@-rule's node:
if (lbIndex > -1) {
if (lbIndex > -1) {
// TODO: Don't push an empty array
// TODO: Don't push an empty array
sc.push(['s', currentNode[1].substring(0, lbIndex)]);
sc.push(['s', currentNode[1].substring(0, lbIndex)]);
currentNode[1] = currentNode[1].substring(lbIndex);
currentNode[1] = currentNode[1].substring(lbIndex);
break;
break;
}
}
sc.push(currentNode);
sc.push(currentNode);
d.push(i + 1);
d.push(i + 1);
}
}
deleted = deleted.concat(d);
deleted = deleted.concat(d);
return sc;
return sc;
};
};
/**
/**
* Combine declaration/@-rule's node with other relevant information:
* Combine declaration/@-rule's node with other relevant information:
* property index, semicolon, spaces and comments.
* property index, semicolon, spaces and comments.
* @returns {Object} Extended node
* @returns {Object} Extended node
*/
*/
var extendNode = function() {
var extendNode = function() {
currentNode = node[i];
currentNode = node[i];
var nextNode = node[i + 1];
var nextNode = node[i + 1];
// Object containing current node, all corresponding spaces,
// Object containing current node, all corresponding spaces,
// comments and other information:
// comments and other information:
var extendedNode;
var extendedNode;
// Check if current node's property name is in sort order.
// Check if current node's property name is in sort order.
// If it is, save information about its indices:
// If it is, save information about its indices:
var orderProperty = order[propertyName];
var orderProperty = order[propertyName];
extendedNode = {
extendedNode = {
i: i,
i: i,
node: currentNode,
node: currentNode,
sc0: sc0,
sc0: sc0,
sc1: [],
sc1: [],
sc2: [],
sc2: [],
Copiar
Copiado
Copiar
Copiado
delim: []
delim: []
,
groupComment: orderProperty.comment
};
};
// If the declaration's property is in order's list, save its
// If the declaration's property is in order's list, save its
// group and property indices. Otherwise set them to 10000, so
// group and property indices. Otherwise set them to 10000, so
// declaration appears at the bottom of a sorted list:
// declaration appears at the bottom of a sorted list:
extendedNode.groupIndex = orderProperty && orderProperty.group > -1 ?
extendedNode.groupIndex = orderProperty && orderProperty.group > -1 ?
orderProperty.group : lastGroupIndex;
orderProperty.group : lastGroupIndex;
extendedNode.propertyIndex = orderProperty && orderProperty.prop > -1 ?
extendedNode.propertyIndex = orderProperty && orderProperty.prop > -1 ?
orderProperty.prop : lastPropertyIndex;
orderProperty.prop : lastPropertyIndex;
// Mark current node to remove it later from parent node:
// Mark current node to remove it later from parent node:
deleted.push(i);
deleted.push(i);
extendedNode.sc1 = checkSC1();
extendedNode.sc1 = checkSC1();
if (extendedNode.sc1.length) {
if (extendedNode.sc1.length) {
currentNode = node[i];
currentNode = node[i];
nextNode = node[i + 1];
nextNode = node[i + 1];
}
}
// If there is `;` right after the declaration, save it with the
// If there is `;` right after the declaration, save it with the
// declaration and mark it for removing from parent node:
// declaration and mark it for removing from parent node:
if (currentNode && nextNode && nextNode[0] === 'declDelim') {
if (currentNode && nextNode && nextNode[0] === 'declDelim') {
extendedNode.delim.push(nextNode);
extendedNode.delim.push(nextNode);
deleted.push(i + 1);
deleted.push(i + 1);
i++;
i++;
if (syntax === 'sass') return extendedNode;
if (syntax === 'sass') return extendedNode;
// Save spaces and comments which follow right after the declaration
// Save spaces and comments which follow right after the declaration
// and mark them for removing from parent node:
// and mark them for removing from parent node:
extendedNode.sc2 = checkSC1();
extendedNode.sc2 = checkSC1();
}
}
return extendedNode;
return extendedNode;
};
};
/**
/**
* Sorts properties alphabetically.
* Sorts properties alphabetically.
*
*
* @param {Object} a First extended node
* @param {Object} a First extended node
* @param {Object} b Second extended node
* @param {Object} b Second extended node
* @returns {Number} `-1` if properties should go in order `a, b`. `1`
* @returns {Number} `-1` if properties should go in order `a, b`. `1`
* if properties should go in order `b, a`.
* if properties should go in order `b, a`.
*/
*/
var sortLeftovers = function(a, b) {
var sortLeftovers = function(a, b) {
var prefixes = ['-webkit-', '-moz-', '-ms-', '-o-', ''];
var prefixes = ['-webkit-', '-moz-', '-ms-', '-o-', ''];
var prefixesRegExp = /^(-webkit-|-moz-|-ms-|-o-)(.*)$/;
var prefixesRegExp = /^(-webkit-|-moz-|-ms-|-o-)(.*)$/;
// Get property name (i.e. `color`, `-o-animation`):
// Get property name (i.e. `color`, `-o-animation`):
a = a.node[1][1][1];
a = a.node[1][1][1];
b = b.node[1][1][1];
b = b.node[1][1][1];
// Get prefix and unprefixed part. For example:
// Get prefix and unprefixed part. For example:
// ['-o-animation', '-o-', 'animation']
// ['-o-animation', '-o-', 'animation']
// ['color', '', 'color']
// ['color', '', 'color']
a = a.match(prefixesRegExp) || [a, '', a];
a = a.match(prefixesRegExp) || [a, '', a];
b = b.match(prefixesRegExp) || [b, '', b];
b = b.match(prefixesRegExp) || [b, '', b];
if (a[2] !== b[2]) {
if (a[2] !== b[2]) {
// If unprefixed parts are different (i.e. `border` and
// If unprefixed parts are different (i.e. `border` and
// `color`), compare them:
// `color`), compare them:
return a[2] < b[2] ? -1 : 1;
return a[2] < b[2] ? -1 : 1;
} else {
} else {
// If unprefixed parts are identical (i.e. `border` in
// If unprefixed parts are identical (i.e. `border` in
// `-moz-border` and `-o-border`), compare prefixes (they
// `-moz-border` and `-o-border`), compare prefixes (they
// should go in the same order they are set in `prefixes` array):
// should go in the same order they are set in `prefixes` array):
return prefixes.indexOf(a[1]) < prefixes.indexOf(b[1]) ? -1 : 1;
return prefixes.indexOf(a[1]) < prefixes.indexOf(b[1]) ? -1 : 1;
}
}
};
};
// TODO: Think it through!
// TODO: Think it through!
// Sort properties only inside blocks:
// Sort properties only inside blocks:
if (nodeType !== 'block') return;
if (nodeType !== 'block') return;
// Check every child node.
// Check every child node.
// If it is declaration (property-value pair, e.g. `color: tomato`),
// If it is declaration (property-value pair, e.g. `color: tomato`),
// or @-rule (e.g. `@include nani`),
// or @-rule (e.g. `@include nani`),
// combine it with spaces, semicolon and comments and move them from
// combine it with spaces, semicolon and comments and move them from
// current node to a separate list for further sorting:
// current node to a separate list for further sorting:
for (i = 0, l = node.length; i < l; i++) {
for (i = 0, l = node.length; i < l; i++) {
if (NODES.indexOf(node[i][0]) === -1) continue;
if (NODES.indexOf(node[i][0]) === -1) continue;
// Save preceding spaces and comments, if there are any, and mark
// Save preceding spaces and comments, if there are any, and mark
// them for removing from parent node:
// them for removing from parent node:
sc0 = checkSC0();
sc0 = checkSC0();
if (!sc0) continue;
if (!sc0) continue;
// If spaces/comments are the last nodes, stop and go to sorting:
// If spaces/comments are the last nodes, stop and go to sorting:
if (!node[i]) {
if (!node[i]) {
deleted.splice(deleted.length - sc0.length, deleted.length + 1);
deleted.splice(deleted.length - sc0.length, deleted.length + 1);
break;
break;
}
}
// Check if the node needs to be sorted:
// Check if the node needs to be sorted:
// it should be a special @-rule (e.g. `@include`) or a declaration
// it should be a special @-rule (e.g. `@include`) or a declaration
// with a valid property (e.g. `color` or `$width`).
// with a valid property (e.g. `color` or `$width`).
// If not, proceed with the next node:
// If not, proceed with the next node:
propertyName = null;
propertyName = null;
// Look for includes:
// Look for includes:
if (node[i][0] === 'include') {
if (node[i][0] === 'include') {
propertyName = '$include';
propertyName = '$include';
} else {
} else {
for (j = 1, nl = node[i].length; j < nl; j++) {
for (j = 1, nl = node[i].length; j < nl; j++) {
currentNode = node[i][j];
currentNode = node[i][j];
if (currentNode[0] === 'property') {
if (currentNode[0] === 'property') {
propertyName = currentNode[1][0] === 'variable' ?
propertyName = currentNode[1][0] === 'variable' ?
'$variable' : currentNode[1][1];
'$variable' : currentNode[1][1];
break;
break;
} else if (currentNode[0] === 'atkeyword' &&
} else if (currentNode[0] === 'atkeyword' &&
currentNode[1][1] === 'import') { // Look for imports
currentNode[1][1] === 'import') { // Look for imports
propertyName = '$import';
propertyName = '$import';
break;
break;
}
}
}
}
}
}
// If current node is not property-value pair or import or include,
// If current node is not property-value pair or import or include,
// skip it and continue with the next node:
// skip it and continue with the next node:
if (!propertyName) {
if (!propertyName) {
deleted.splice(deleted.length - sc0.length, deleted.length + 1);
deleted.splice(deleted.length - sc0.length, deleted.length + 1);
continue;
continue;
}
}
// Make an extended node and move it to a separate list for further
// Make an extended node and move it to a separate list for further
// sorting:
// sorting:
sorted.push(extendNode());
sorted.push(extendNode());
}
}
// Remove all nodes, that were moved to a `sorted` list, from parent node:
// Remove all nodes, that were moved to a `sorted` list, from parent node:
for (i = deleted.length - 1; i > -1; i--) {
for (i = deleted.length - 1; i > -1; i--) {
node.splice(deleted[i], 1);
node.splice(deleted[i], 1);
}
}
// Sort declarations saved for sorting:
// Sort declarations saved for sorting:
sorted.sort(function(a, b) {
sorted.sort(function(a, b) {
// If a's group index is higher than b's group index, in a sorted
// If a's group index is higher than b's group index, in a sorted
// list a appears after b:
// list a appears after b:
if (a.groupIndex !== b.groupIndex) return a.groupIndex - b.groupIndex;
if (a.groupIndex !== b.groupIndex) return a.groupIndex - b.groupIndex;
// If a and b belong to leftovers and `sort-order-fallback` option
// If a and b belong to leftovers and `sort-order-fallback` option
// is set to `abc`, sort properties alphabetically:
// is set to `abc`, sort properties alphabetically:
if (a.groupIndex === lastGroupIndex &&
if (a.groupIndex === lastGroupIndex &&
_this.getValue('sort-order-fallback')) {
_this.getValue('sort-order-fallback')) {
return sortLeftovers(a, b);
return sortLeftovers(a, b);
}
}
// If a and b have the same group index, and a's property index is
// 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
// higher than b's property index, in a sorted list a appears after
// b:
// b:
if (a.propertyIndex !== b.propertyIndex) return a.propertyIndex - b.propertyIndex;
if (a.propertyIndex !== b.propertyIndex) return a.propertyIndex - b.propertyIndex;
// If a and b have the same group index and the same property index,
// 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
// in a sorted list they appear in the same order they were in
// original array:
// original array:
return a.i - b.i;
return a.i - b.i;
});
});
// Build all nodes back together. First go sorted declarations, then
// Build all nodes back together. First go sorted declarations, then
// everything else:
// everything else:
if (sorted.length > 0) {
if (sorted.length > 0) {
for (i = sorted.length - 1, l = -1; i > l; i--) {
for (i = sorted.length - 1, l = -1; i > l; i--) {
currentNode = sorted[i];
currentNode = sorted[i];
var prevNode = sorted[i - 1];
var prevNode = sorted[i - 1];
sc0 = currentNode.sc0;
sc0 = currentNode.sc0;
var sc1 = currentNode.sc1;
var sc1 = currentNode.sc1;
var sc2 = currentNode.sc2;
var sc2 = currentNode.sc2;
Copiar
Copiado
Copiar
Copiado
Text moved to lines 379-382
sc0.reverse();
// Divide declarations from different groups with
group comments (if defined) and/or
an empty line:
sc1.reverse();
if (
(currentNode.groupComment && !prevNode) || (
prevNode && currentNode.groupIndex > prevNode.groupIndex)
)
{
sc2.reverse();
// Divide declarations from different groups with
an empty line:
if (
prevNode && currentNode.groupIndex > prevNode.groupIndex)
{
if (sc0[0] && sc0[0][0] === 's' &&
if (sc0[0] && sc0[0][0] === 's' &&
(this.syntax === 'sass' ||
(this.syntax === 'sass' ||
sc0[0][1].match(/\n/g) &&
sc0[0][1].match(/\n/g) &&
sc0[0][1].match(/\n/g).length < 2)) {
sc0[0][1].match(/\n/g).length < 2)) {
Copiar
Copiado
Copiar
Copiado
sc0[0][1] = '\n' + sc0[0][1]
;
if (currentNode.groupComment) {
if (!sc0[1] || (sc0[1] && !currentNode.groupComment.match(sc0[1][1]))) {
sc0.unshift([SC[0], currentNode.groupComment]);
sc0.unshift(sc0[sc0.length - 1]);
}
}
sc0.unshift(sc0[sc0.length - 1])
;
}
}
}
}
Copiar
Copiado
Copiar
Copiado
Text moved from lines 352-355
sc0.reverse();
sc1.reverse();
sc2.reverse();
for (j = 0, nl = sc2.length; j < nl; j++) {
for (j = 0, nl = sc2.length; j < nl; j++) {
node.unshift(sc2[j]);
node.unshift(sc2[j]);
}
}
if (currentNode.delim.length > 0) node.unshift(['declDelim']);
if (currentNode.delim.length > 0) node.unshift(['declDelim']);
for (j = 0, nl = sc1.length; j < nl; j++) {
for (j = 0, nl = sc1.length; j < nl; j++) {
node.unshift(sc1[j]);
node.unshift(sc1[j]);
}
}
node.unshift(currentNode.node);
node.unshift(currentNode.node);
Copiar
Copiado
Copiar
Copiado
for (j = 0, nl = sc0.length; j < nl; j++) {
for (j = 0, nl = sc0.length; j < nl; j++) {
node.unshift(sc0[j]);
node.unshift(sc0[j]);
}
}
}
}
}
}
}
}
};
};
Diferenças salvas
Texto original
Abrir arquivo
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 {String} nodeType * @param {node} node */ process: function(nodeType, node) { var _this = this; // Types of nodes that can be sorted: var NODES = ['atruleb', 'atruler', 'atrules', 'commentML', 'commentSL', 'declaration', 's', 'include']; // Spaces and comments: var SC = ['commentML', 'commentSL', 's']; 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; /** * 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[i]; // If there is no node left, // stop and do nothing with previously found spaces/comments: if (!currentNode) { return false; } // Remove any empty lines: if (currentNode[0] === 's') { currentNode[1] = currentNode[1].replace(/\n[\s\t\n\r]*\n/, '\n'); } // 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[0]) === -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[i + 1]; // If there is no node, or it is nor spaces neither comment, stop: if (!currentNode || SC.indexOf(currentNode[0]) === -1) break; // Remove any empty lines: if (currentNode[0] === 's') { currentNode[1] = currentNode[1].replace(/\n[\s\t\n\r]*\n/, '\n'); } if (['commentML', 'commentSL'].indexOf(currentNode[0]) > -1) { sc.push(currentNode); d.push(i + 1); continue; } lbIndex = currentNode[1].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 sc.push(['s', currentNode[1].substring(0, lbIndex)]); currentNode[1] = currentNode[1].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[i]; var nextNode = node[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[i]; nextNode = node[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[0] === 'declDelim') { 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[1][1][1]; b = b.node[1][1][1]; // 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 (nodeType !== '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[i][0]) === -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[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[i][0] === 'include') { propertyName = '$include'; } else { for (j = 1, nl = node[i].length; j < nl; j++) { currentNode = node[i][j]; if (currentNode[0] === 'property') { propertyName = currentNode[1][0] === 'variable' ? '$variable' : currentNode[1][1]; break; } else if (currentNode[0] === 'atkeyword' && currentNode[1][1] === '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.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(); sc1.reverse(); sc2.reverse(); // Divide declarations from different groups with an empty line: if (prevNode && currentNode.groupIndex > prevNode.groupIndex) { if (sc0[0] && sc0[0][0] === 's' && (this.syntax === 'sass' || sc0[0][1].match(/\n/g) && sc0[0][1].match(/\n/g).length < 2)) { sc0[0][1] = '\n' + sc0[0][1]; } } for (j = 0, nl = sc2.length; j < nl; j++) { node.unshift(sc2[j]); } if (currentNode.delim.length > 0) node.unshift(['declDelim']); for (j = 0, nl = sc1.length; j < nl; j++) { node.unshift(sc1[j]); } node.unshift(currentNode.node); for (j = 0, nl = sc0.length; j < nl; j++) { node.unshift(sc0[j]); } } } } };
Texto alterado
Abrir arquivo
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) { var groupComment, isComment = /\/\*(.*?)\*\//g; group.forEach(function(prop, propIndex) { if (isComment.test(prop)) { groupComment = prop.replace(isComment, '$1'); } else { order[prop] = { comment: groupComment, group: groupIndex, prop: propIndex }; } }); }); } return order; }, /** * Processes tree node. * @param {String} nodeType * @param {node} node */ process: function(nodeType, node) { var _this = this; // Types of nodes that can be sorted: var NODES = ['atruleb', 'atruler', 'atrules', 'commentML', 'commentSL', 'declaration', 's', 'include']; // Spaces and comments: var SC = ['commentML', 'commentSL', 's']; 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; /** * 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[i]; // If there is no node left, // stop and do nothing with previously found spaces/comments: if (!currentNode) { return false; } // Remove any empty lines: if (currentNode[0] === 's') { currentNode[1] = currentNode[1].replace(/\n[\s\t\n\r]*\n/, '\n'); } // 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[0]) === -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[i + 1]; // If there is no node, or it is nor spaces neither comment, stop: if (!currentNode || SC.indexOf(currentNode[0]) === -1) break; // Remove any empty lines: if (currentNode[0] === 's') { currentNode[1] = currentNode[1].replace(/\n[\s\t\n\r]*\n/, '\n'); } if (['commentML', 'commentSL'].indexOf(currentNode[0]) > -1) { sc.push(currentNode); d.push(i + 1); continue; } lbIndex = currentNode[1].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 sc.push(['s', currentNode[1].substring(0, lbIndex)]); currentNode[1] = currentNode[1].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[i]; var nextNode = node[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: [], groupComment: orderProperty.comment }; // 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[i]; nextNode = node[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[0] === 'declDelim') { 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[1][1][1]; b = b.node[1][1][1]; // 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 (nodeType !== '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[i][0]) === -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[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[i][0] === 'include') { propertyName = '$include'; } else { for (j = 1, nl = node[i].length; j < nl; j++) { currentNode = node[i][j]; if (currentNode[0] === 'property') { propertyName = currentNode[1][0] === 'variable' ? '$variable' : currentNode[1][1]; break; } else if (currentNode[0] === 'atkeyword' && currentNode[1][1] === '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.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; // Divide declarations from different groups with group comments (if defined) and/or an empty line: if ((currentNode.groupComment && !prevNode) || (prevNode && currentNode.groupIndex > prevNode.groupIndex)) { if (sc0[0] && sc0[0][0] === 's' && (this.syntax === 'sass' || sc0[0][1].match(/\n/g) && sc0[0][1].match(/\n/g).length < 2)) { if (currentNode.groupComment) { if (!sc0[1] || (sc0[1] && !currentNode.groupComment.match(sc0[1][1]))) { sc0.unshift([SC[0], currentNode.groupComment]); sc0.unshift(sc0[sc0.length - 1]); } } sc0.unshift(sc0[sc0.length - 1]); } } sc0.reverse(); sc1.reverse(); sc2.reverse(); for (j = 0, nl = sc2.length; j < nl; j++) { node.unshift(sc2[j]); } if (currentNode.delim.length > 0) node.unshift(['declDelim']); for (j = 0, nl = sc1.length; j < nl; j++) { node.unshift(sc1[j]); } node.unshift(currentNode.node); for (j = 0, nl = sc0.length; j < nl; j++) { node.unshift(sc0[j]); } } } } };
Encontrar Diferença