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<StyleCompileResults> {
|
|
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
|
|
)
|
|
)
|
|
}
|