const postcss = require('postcss') import { ProcessOptions, LazyResult } from 'postcss' import trimPlugin from './stylePlugins/trim' import scopedPlugin from './stylePlugins/scoped' import { processors, StylePreprocessor, StylePreprocessorResults } from './styleProcessors' export interface StyleCompileOptions { source: string filename: string id: string map?: any scoped?: boolean trim?: boolean preprocessLang?: string preprocessOptions?: any postcssOptions?: any postcssPlugins?: any[] } export interface AsyncStyleCompileOptions extends StyleCompileOptions { isAsync?: boolean } export interface StyleCompileResults { code: string map: any | void rawResult: LazyResult | void errors: string[] } export function compileStyle( options: StyleCompileOptions ): StyleCompileResults { return doCompileStyle({ ...options, isAsync: false }) } export function compileStyleAsync( options: StyleCompileOptions ): Promise { return Promise.resolve(doCompileStyle({ ...options, isAsync: true })) } export function doCompileStyle( options: AsyncStyleCompileOptions ): StyleCompileResults { const { filename, id, scoped = true, trim = true, preprocessLang, postcssOptions, postcssPlugins } = options const preprocessor = preprocessLang && processors[preprocessLang] const preProcessedSource = preprocessor && preprocess(options, preprocessor) const map = preProcessedSource ? preProcessedSource.map : options.map const source = preProcessedSource ? preProcessedSource.code : options.source const plugins = (postcssPlugins || []).slice() if (trim) { plugins.push(trimPlugin()) } if (scoped) { plugins.push(scopedPlugin(id)) } const postCSSOptions: ProcessOptions = { ...postcssOptions, to: filename, from: filename } if (map) { postCSSOptions.map = { inline: false, annotation: false, prev: map } } let result, code, outMap const errors: any[] = [] if (preProcessedSource && preProcessedSource.errors.length) { errors.push(...preProcessedSource.errors) } try { result = postcss(plugins).process(source, postCSSOptions) // In async mode, return a promise. if (options.isAsync) { return result .then( (result: LazyResult): StyleCompileResults => ({ code: result.css || '', map: result.map && result.map.toJSON(), errors, rawResult: result }) ) .catch( (error: Error): StyleCompileResults => ({ code: '', map: undefined, errors: [...errors, error.message], rawResult: undefined }) ) } // force synchronous transform (we know we only have sync plugins) code = result.css outMap = result.map } catch (e) { errors.push(e) } return { code: code || ``, map: outMap && outMap.toJSON(), errors, rawResult: result } } function preprocess( options: StyleCompileOptions, preprocessor: StylePreprocessor ): StylePreprocessorResults { return preprocessor.render( options.source, options.map, Object.assign( { filename: options.filename }, options.preprocessOptions ) ) }