UNPKG

lml-main

Version:

This is now a mono repository published into many standalone packages.

309 lines (298 loc) 11.2 kB
var postcss = require('postcss'); var gonzales = require('gonzales-pe'); var Input = require('postcss/lib/input'); var math = require('mathjs'); var DEFAULT_RAWS_ROOT = { semicolon: false, after: '' }; var DEFAULT_RAWS_RULE = { before: '', between: ' ', semicolon: false, after: '' }; var DEFAULT_RAWS_DECL = { before: '', between: ': ', semicolon: false }; function process( source, node, parent, input, selector ) { if (node.type === 'stylesheet') { // Create and set parameters for Root node var root = postcss.root(); root.source = { start: node.start, end: node.end, input: input }; root.raws = DEFAULT_RAWS_ROOT; for (var i = 0; i < node.content.length; i++) { process(source, node.content[i], root, input, selector); } return root; } else if (node.type === 'ruleset') { // Loop to find the deepest ruleset node var pseudoClassFirst = false; for (var rContent = 0; rContent < node.content.length; rContent++ ) { if (node.content[rContent].type === 'block') { // Create Rule node var rule = postcss.rule(); // Object to store raws for Rule var rRaws = {}; // Looking for all block nodes in current ruleset node for ( var rCurrentContent = 0; rCurrentContent < node.content.length; rCurrentContent++ ) { if (node.content[rCurrentContent].type === 'block') { process( source, node.content[rCurrentContent], rule, input ); } else if (node.content[rCurrentContent].type === 'space') { if (!rRaws.between) { rRaws.between = node .content[rCurrentContent].content; } else { rRaws.between += node .content[rCurrentContent].content; } } } if (rule.nodes.length !== 0) { // Write selector to Rule, and remove last whitespace if (selector.slice(-1) === ',') { rule.selector = selector.slice(0, -1); } else { rule.selector = selector; } if (selector.charAt(0) === ' ') { rule.selector = selector.substring(1); } // Set parameters for Rule node rule.parent = parent; rule.source = { start: node.start, end: node.end, input: input }; if (Object.keys(rRaws).length > 0) { rule.raws = rRaws; } else { rule.raws = DEFAULT_RAWS_RULE; } parent.nodes.push(rule); } for ( var bNextContent = 0; bNextContent < node.content[rContent].length; bNextContent++ ) { if (node.content[rContent] .content[bNextContent].type === 'ruleset') { // Add to selector value of current node process( source, node.content[rContent].content[bNextContent], parent, input, selector ); } } } else if (node.content[rContent].type === 'selector') { /* Get current selector name It's always have same path, so it's easier to get it without recursion */ selector += ' '; for ( var sCurrentContent = 0; sCurrentContent < node.content[rContent].length; sCurrentContent++ ) { if (node.content[rContent] .content[sCurrentContent].type === 'id') { selector += '#'; } else if (node.content[rContent] .content[sCurrentContent].type === 'class') { selector += '.'; } else if (node.content[rContent] .content[sCurrentContent].type === 'typeSelector') { if (node.content[rContent] .content[sCurrentContent + 1] && node.content[rContent] .content[sCurrentContent + 1] .type === 'pseudoClass' && pseudoClassFirst) { selector = selector.slice(0, -1); selector += ', '; } else { pseudoClassFirst = true; } } else if (node.content[rContent] .content[sCurrentContent].type === 'pseudoClass') { selector += ':'; } selector += node.content[rContent] .content[sCurrentContent].content; } } } } else if (node.type === 'block') { // Looking for declaration node in block node for (var bContent = 0; bContent < node.content.length; bContent++) { if (node.content[bContent].type === 'declaration') { process( source, node.content[bContent], parent, input ); } } global.blockValue = ''; } else if (node.type === 'declaration') { var isBlockInside = false; // Create Declaration node var decl = postcss.decl(); // Object to store raws for Declaration var dRaws = {}; // Looking for property and value node in declaration node for (var dContent = 0; dContent < node.content.length; dContent++) { if (node.content[dContent].type === 'property') { decl.prop = ''; process( source, node.content[dContent], decl, input ); } else if (node.content[dContent].type === 'propertyDelimiter') { if (!dRaws.between) { dRaws.between = node.content[dContent].content; } else { dRaws.between += node.content[dContent].content; } } else if (node.content[dContent].type === 'space') { if (!dRaws.between) { dRaws.between = node.content[dContent].content; } else { dRaws.between += node.content[dContent].content; } } if (node.content[dContent].type === 'value') { if (node.content[dContent].content[0].type === 'block') { isBlockInside = true; global.blockValue = node.content[0].content[0].content; process( source, node.content[dContent].content[0], parent, input ); } else if (node.content[dContent].content[0].type === 'color') { decl.value = '#'; process( source, node.content[dContent], decl ); } else if (node.content[dContent] .content[0].type === 'number') { if (node.content[dContent].content.length > 1) { decl.value = ''; for ( var dCurrentContent = 0; dCurrentContent < node.content[dContent] .content.length; dCurrentContent++ ) { decl.value += node.content[dContent] .content[dCurrentContent]; } decl.value = math.eval(decl.value).toString(); } else { process( source, node.content[dContent], decl ); } } else { process( source, node.content[dContent], decl ); } } } if (!isBlockInside) { // Set parameters for Declaration node decl.source = { start: node.start, end: node.end, input: input }; decl.parent = parent; if (Object.keys(dRaws) > 0) { dRaws.before = ''; decl.raws = dRaws; } else { decl.raws = DEFAULT_RAWS_DECL; } parent.nodes.push(decl); } } else if (node.type === 'property') { // Set property for Declaration node if (global.blockValue && global.blockValue.length > 0) { parent.prop += global.blockValue + '-'; parent.prop += node.content[0].content; } else { parent.prop += node.content[0].content; } } else if (node.type === 'value') { if (!parent.value) { parent.value = ''; } // Set value for Declaration node if (node.content[0].content.constructor === Array) { for ( var vContent = 0; vContent < node.content[0].content.length; vContent++ ) { parent.value += node.content[0].content[vContent].content; } } else { parent.value += node.content[0].content; } } return null; } module.exports = function sassToPostCssTree( source, opts ) { var data = { node: gonzales.parse(source, { syntax: 'sass' }), input: new Input(source, opts), parent: null, selector: '' }; return process( source, data.node, data.parent, data.input, data.selector); };