lib/adapters/css.js (115 lines of code) (raw):

const fs = require("fs") const _ = require("lodash") const mkdirp = require("mkdirp") const header = require("../utils").header module.exports = (theme) => { var settings = _.filter(theme.settings, t => { return t["scope"] != null }) var convertAttributes = a => { var attributes = {} switch (a.fontStyle) { case "bold": attributes["font-weight"] = "bold" break; case "italic": attributes["font-style"] = "italic" break; case "underline": attributes["text-decoration"] = "underline" break; } if (a.foreground) { attributes["color"] = a.foreground } if (a.background) { attributes["background-color"] = a.background } if (a.content) { attributes["content"] = a.content } return attributes } var generateScopeClass = (scope, classes) => { var candidate = "pl-" + scope.split(".").map( s => { return s[0]}).join("") var suffix = "" var cssClass = candidate + "" + suffix while(classes.indexOf(cssClass) >= 0) { var suffix = suffix || 0 suffix++ cssClass = candidate + "" + suffix } classes.push(cssClass) return cssClass } var selectorsByStyle = {}, combinatorScopes = new Set(), classes = [], classesByScope = {} settings.map( t => { var style = convertAttributes(t.settings) var selectors = t.scope.split(",").map( s => { return s.trim() }) if (selectors.length != 0 && selectors != ["none"]) { selectorsByStyle[JSON.stringify(style)] = _.union(selectorsByStyle[JSON.stringify(style)], selectors) selectors.map( selector => { var scopes = selector.split(" ") if(scopes.length >= 2) { combinatorScopes = _.union(combinatorScopes, scopes) } }) } }) _.map(selectorsByStyle, (selectors, style) => { style = JSON.parse(style) var scopesWithoutClasses = _.difference(_.uniq(_.flattenDeep(selectors.map( l => { return l.split(" ") }))), Object.keys(classesByScope)) var sharedScopes = _.difference(scopesWithoutClasses, combinatorScopes) var uniqueScopes = _.intersection(scopesWithoutClasses, combinatorScopes) if (sharedScopes.length > 0) { var cssClass = generateScopeClass(sharedScopes.sort()[0], classes) sharedScopes.map( scope => { classesByScope[scope] = cssClass }) } uniqueScopes.map( scope => { classesByScope[scope] = generateScopeClass(scope, classes) }) }) rules = _.flatMap(selectorsByStyle, (selectors, style) => { style = JSON.parse(style) var scopeSelectorsByCss = _.groupBy(selectors, selector => { var scopes = selector.split(" ") classes = scopes.map( s => { return classesByScope[s] }) return classes.map( c => { return "." + c }).join(" ") }) var content if (style.content) { content = style.content; delete style.content; } const styles = [{ "style": style, "selectors": _.map(scopeSelectorsByCss, (scopes, css) => { return { "css": css, "scopes": scopes }}) }] if (content) { styles.push({ "style": { "content": "\"" + content.replace(/"/g, "\\22 ") + "\"", }, "selectors": _.map(scopeSelectorsByCss, (scopes, css) => { return { "css": css + "::before", "scopes": scopes }}) }) } return styles }) var output = header(theme) rules.map(rule => { if (Object.keys(rule.style).length != 0) { output += rule.selectors.map( selector => { return selector.css + " /* " + selector.scopes.join(", ") + " */" }).join(",\n") output += " {\n" output += _.map(rule.style, (v, k) => { return " " + k + ": " + v + ";" }).join("\n") output += "\n}\n\n" } }) mkdirp.sync("build/css") fs.writeFileSync("build/css/" + theme.filename + ".map.json", JSON.stringify(classesByScope)) fs.writeFileSync("build/css/" + theme.filename + ".css", output) }