function each(list) { if (list.head === null) { return ''; } if (list.head === list.tail) { return translate(list.head.data); } return list.map(translate).join(''); } function eachDelim(list, delimeter) { if (list.head === null) { return ''; } if (list.head === list.tail) { return translate(list.head.data); } return list.map(translate).join(delimeter); } function translate(node) { switch (node.type) { case 'StyleSheet': return each(node.rules); case 'Atrule': var nodes = ['@', node.name]; if (node.expression && !node.expression.sequence.isEmpty()) { nodes.push(' ', translate(node.expression)); } if (node.block) { nodes.push('{', translate(node.block), '}'); } else { nodes.push(';'); } return nodes.join(''); case 'Ruleset': return translate(node.selector) + '{' + translate(node.block) + '}'; case 'Selector': return eachDelim(node.selectors, ','); case 'SimpleSelector': var nodes = node.sequence.map(function(node) { // add extra spaces around /deep/ combinator since comment beginning/ending may to be produced if (node.type === 'Combinator' && node.name === '/deep/') { return ' ' + translate(node) + ' '; } return translate(node); }); return nodes.join(''); case 'Block': return eachDelim(node.declarations, ';'); case 'Declaration': return translate(node.property) + ':' + translate(node.value); case 'Property': return node.name; case 'Value': return node.important ? each(node.sequence) + '!important' : each(node.sequence); case 'Attribute': var result = translate(node.name); var flagsPrefix = ' '; if (node.operator !== null) { result += node.operator; if (node.value !== null) { result += translate(node.value); // space between string and flags is not required if (node.value.type === 'String') { flagsPrefix = ''; } } } if (node.flags !== null) { result += flagsPrefix + node.flags; } return '[' + result + ']'; case 'FunctionalPseudo': return ':' + node.name + '(' + eachDelim(node.arguments, ',') + ')'; case 'Function': return node.name + '(' + eachDelim(node.arguments, ',') + ')'; case 'Negation': return ':not(' + eachDelim(node.sequence, ',') + ')'; case 'Braces': return node.open + each(node.sequence) + node.close; case 'Argument': case 'AtruleExpression': return each(node.sequence); case 'Url': return 'url(' + translate(node.value) + ')'; case 'Progid': return translate(node.value); case 'Combinator': return node.name; case 'Identifier': return node.name; case 'PseudoClass': return ':' + node.name; case 'PseudoElement': return '::' + node.name; case 'Class': return '.' + node.name; case 'Id': return '#' + node.name; case 'Hash': return '#' + node.value; case 'Dimension': return node.value + node.unit; case 'Nth': return node.value; case 'Number': return node.value; case 'String': return node.value; case 'Operator': return node.value; case 'Raw': return node.value; case 'Unknown': return node.value; case 'Percentage': return node.value + '%'; case 'Space': return ' '; case 'Comment': return '/*' + node.value + '*/'; default: throw new Error('Unknown node type: ' + node.type); } } module.exports = translate;