Created
December 7, 2019 03:16
-
-
Save esr360/04b88700412599143b5b8a3274e9afd9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require('@babel/register')(); | |
require('jsdom-global')(); | |
const Sass = require('node-sass'); | |
const fs = require('fs'); | |
const mkdirp = require('mkdirp'); | |
const getDirName = require('path').dirname; | |
window.matchMedia = window.matchMedia || function() { | |
return { | |
matches : false, | |
addListener : function() {}, | |
removeListener: function() {} | |
} | |
} | |
const deepextend = require('deep-extend'); | |
const MODULES = {}; | |
const MODULES_PARENT_DIR = '/modules'; | |
const MODULE_CONFIG_FILENAME = 'config'; | |
const MODULE_STYLES_FILENAME = 'styles'; | |
module.exports = function(source) { | |
const THEME = this.query.theme; | |
const FILEPATH = this.resourcePath; | |
const FILENAME = FILEPATH.replace(/^.*[\\\/]/, ''); | |
let MODULE; | |
try { | |
MODULE = require(FILEPATH).default || {}; | |
} catch(error) { | |
MODULE = {}; | |
} | |
if (typeof MODULE === 'function') { | |
let NAMESPACE; | |
if (MODULE.defaultProps && MODULE.defaultProps.name) { | |
NAMESPACE = MODULE.defaultProps.name; | |
} | |
else if (this.context.endsWith('/modules')) { | |
NAMESPACE = MODULE.name; | |
} | |
if (NAMESPACE) { | |
if (typeof MODULE.config === 'function') { | |
MODULE.config = MODULE.config(THEME); | |
} | |
Object.assign(MODULE, { | |
config: deepextend(MODULE.config, THEME.modules && evalConfig(THEME.modules[NAMESPACE], THEME)) | |
}); | |
if (MODULE.styles) { | |
const STYLES = MODULE.styles({ | |
theme: THEME, | |
config: MODULE.config, | |
state: {} | |
}); | |
let TEMPLATE = ` | |
@import '../../Cell/Cell/dist/cell'; | |
@include module(${NAMESPACE}) { | |
//@Content | |
} | |
`; | |
const CSS = writeCSS(STYLES, TEMPLATE); | |
console.log(STYLES); | |
const COMPILED_CSS = Sass.renderSync({ | |
data: CSS, | |
outputStyle: 'expanded' | |
}); | |
mkdirp(getDirName(`dist/css/${NAMESPACE}.css`), () => { | |
fs.writeFile(`dist/css/${NAMESPACE}.css`, COMPILED_CSS.css, (err) => { | |
if (err) throw err; | |
}); | |
}); | |
} | |
} | |
} | |
return source; | |
} | |
/** | |
*/ | |
function writeCSS(STYLES, CSS) { | |
if (STYLES instanceof Array) { | |
STYLES.forEach(STYLE => CSS = writeCSS(STYLE, CSS)); | |
return CSS; | |
} | |
Object.entries(STYLES).forEach(style => { | |
const key = style[0]; let value = style[1]; | |
if (typeof value === 'object') { | |
CSS = CSS.replace(`//@Content`, `@include component(${key}, (${transformJStoSass(value)}));//@Content`); | |
} | |
else if (typeof value === 'function') { | |
const _CSS = transformJStoSass(value({ state: {}, context: {} })); | |
CSS = CSS.replace(`//@Content`, `@include component(${key}, (${_CSS}));//@Content`); | |
} | |
else { | |
CSS = CSS.replace(`//@Content`, `${key}: ${value};//@Content`); | |
} | |
}); | |
return CSS; | |
} | |
/** | |
* Evaluate module config properties | |
*/ | |
function evalConfig(config, theme) { | |
if (!config) { | |
return; | |
} | |
Object.entries(config).forEach(([key, value]) => { | |
if (typeof value === 'object') { | |
return evalConfig(value, theme); | |
} | |
else { | |
return (typeof value === 'function') ? config[key] = value(theme) : false; | |
} | |
}); | |
return config; | |
} | |
/** | |
* @param {*} url | |
*/ | |
export function isValidFile(url) { | |
return (/\.(js)(on(5)?|s)?$/.test(url)); | |
} | |
/** | |
* @param {*} json | |
*/ | |
export function transformJStoSass(json) { | |
return Object.keys(json).filter(key => isValidKey(key)).filter(key => json[key] !== '#').map(key => { | |
return `${key}: ${parseValue(json[key])},` | |
}).join('\n'); | |
} | |
/** | |
* @param {*} key | |
*/ | |
export function isValidKey(key) { | |
return /^[^$@:].*/.test(key); | |
} | |
/** | |
* @param {*} value | |
*/ | |
export function parseValue(value) { | |
if (typeof value === 'function') { | |
return '"[function]"' | |
} | |
if (value instanceof Array) { | |
return parseList(value); | |
} | |
else if (typeof value === 'object') { | |
return parseMap(value); | |
} | |
else if (valueShouldBeStringified(value)) { | |
return `"${value}"`; | |
} | |
else { | |
return value; | |
} | |
} | |
/** | |
* @param {*} list | |
*/ | |
export function parseList(list) { | |
return `(${list.map(value => parseValue(value)).join(',')})`; | |
} | |
/** | |
* @param {*} map | |
*/ | |
export function parseMap(map) { | |
const keys = Object.keys(map).map(key => { | |
try { | |
sass.renderSync({ | |
data: `$foo: (${key}: 'value');` | |
}); | |
return key; | |
} | |
catch(error) { | |
return `"${key}"`; | |
} | |
}); | |
return `(${keys.filter(key => isValidKey(key)).map(key => { | |
return `${key}: ${parseValue(map[key.replace(/"/g,"")])}`; | |
}).join(',')})`; | |
} | |
/** | |
* @param {*} value | |
*/ | |
export function valueShouldBeStringified(value) { | |
try { | |
Sass.renderSync({ | |
data: `$foo: (key: ${value});` | |
}); | |
return false; | |
} | |
catch(error) { | |
return true | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment