mirror of
https://github.com/hanzoai/postcss.git
synced 2026-09-24 17:01:56 +00:00
235 lines
8.5 KiB
JavaScript
235 lines
8.5 KiB
JavaScript
import LazyResult from './lazy-result'
|
||
|
||
/**
|
||
* Contains plugins to process CSS. Create one `Processor` instance,
|
||
* initialize its plugins, and then use that instance on numerous CSS files.
|
||
*
|
||
* @example
|
||
* const processor = postcss([autoprefixer, precss])
|
||
* processor.process(css1).then(result => console.log(result.css))
|
||
* processor.process(css2).then(result => console.log(result.css))
|
||
*/
|
||
class Processor {
|
||
/**
|
||
* @param {Array.<Plugin|pluginFunction>|Processor} plugins PostCSS plugins.
|
||
* See {@link Processor#use} for plugin format.
|
||
*/
|
||
constructor (plugins = []) {
|
||
/**
|
||
* Current PostCSS version.
|
||
*
|
||
* @type {string}
|
||
*
|
||
* @example
|
||
* if (result.processor.version.split('.')[0] !== '6') {
|
||
* throw new Error('This plugin works only with PostCSS 6')
|
||
* }
|
||
*/
|
||
this.version = '7.0.39'
|
||
/**
|
||
* Plugins added to this processor.
|
||
*
|
||
* @type {pluginFunction[]}
|
||
*
|
||
* @example
|
||
* const processor = postcss([autoprefixer, precss])
|
||
* processor.plugins.length //=> 2
|
||
*/
|
||
this.plugins = this.normalize(plugins)
|
||
}
|
||
|
||
/**
|
||
* Adds a plugin to be used as a CSS processor.
|
||
*
|
||
* PostCSS plugin can be in 4 formats:
|
||
* * A plugin created by {@link postcss.plugin} method.
|
||
* * A function. PostCSS will pass the function a @{link Root}
|
||
* as the first argument and current {@link Result} instance
|
||
* as the second.
|
||
* * An object with a `postcss` method. PostCSS will use that method
|
||
* as described in #2.
|
||
* * Another {@link Processor} instance. PostCSS will copy plugins
|
||
* from that instance into this one.
|
||
*
|
||
* Plugins can also be added by passing them as arguments when creating
|
||
* a `postcss` instance (see [`postcss(plugins)`]).
|
||
*
|
||
* Asynchronous plugins should return a `Promise` instance.
|
||
*
|
||
* @param {Plugin|pluginFunction|Processor} plugin PostCSS plugin
|
||
* or {@link Processor}
|
||
* with plugins.
|
||
*
|
||
* @example
|
||
* const processor = postcss()
|
||
* .use(autoprefixer)
|
||
* .use(precss)
|
||
*
|
||
* @return {Processes} Current processor to make methods chain.
|
||
*/
|
||
use (plugin) {
|
||
this.plugins = this.plugins.concat(this.normalize([plugin]))
|
||
return this
|
||
}
|
||
|
||
/**
|
||
* Parses source CSS and returns a {@link LazyResult} Promise proxy.
|
||
* Because some plugins can be asynchronous it doesn’t make
|
||
* any transformations. Transformations will be applied
|
||
* in the {@link LazyResult} methods.
|
||
*
|
||
* @param {string|toString|Result} css String with input CSS or any object
|
||
* with a `toString()` method,
|
||
* like a Buffer. Optionally, send
|
||
* a {@link Result} instance
|
||
* and the processor will take
|
||
* the {@link Root} from it.
|
||
* @param {processOptions} [opts] Options.
|
||
*
|
||
* @return {LazyResult} Promise proxy.
|
||
*
|
||
* @example
|
||
* processor.process(css, { from: 'a.css', to: 'a.out.css' })
|
||
* .then(result => {
|
||
* console.log(result.css)
|
||
* })
|
||
*/
|
||
process (css, opts = { }) {
|
||
if (this.plugins.length === 0 && opts.parser === opts.stringifier) {
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
if (typeof console !== 'undefined' && console.warn) {
|
||
console.warn(
|
||
'You did not set any plugins, parser, or stringifier. ' +
|
||
'Right now, PostCSS does nothing. Pick plugins for your case ' +
|
||
'on https://www.postcss.parts/ and use them in postcss.config.js.'
|
||
)
|
||
}
|
||
}
|
||
}
|
||
return new LazyResult(this, css, opts)
|
||
}
|
||
|
||
normalize (plugins) {
|
||
let normalized = []
|
||
for (let i of plugins) {
|
||
if (i.postcss === true) {
|
||
let plugin = i()
|
||
throw new Error(
|
||
'PostCSS plugin ' + plugin.postcssPlugin + ' requires PostCSS 8.\n' +
|
||
'Migration guide for end-users:\n' +
|
||
'https://github.com/postcss/postcss/wiki/PostCSS-8-for-end-users'
|
||
)
|
||
}
|
||
|
||
if (i.postcss) i = i.postcss
|
||
|
||
if (typeof i === 'object' && Array.isArray(i.plugins)) {
|
||
normalized = normalized.concat(i.plugins)
|
||
} else if (typeof i === 'function') {
|
||
normalized.push(i)
|
||
} else if (typeof i === 'object' && (i.parse || i.stringify)) {
|
||
if (process.env.NODE_ENV !== 'production') {
|
||
throw new Error(
|
||
'PostCSS syntaxes cannot be used as plugins. Instead, please use ' +
|
||
'one of the syntax/parser/stringifier options as outlined ' +
|
||
'in your PostCSS runner documentation.'
|
||
)
|
||
}
|
||
} else if (typeof i === 'object' && i.postcssPlugin) {
|
||
throw new Error(
|
||
'PostCSS plugin ' + i.postcssPlugin + ' requires PostCSS 8.\n' +
|
||
'Migration guide for end-users:\n' +
|
||
'https://github.com/postcss/postcss/wiki/PostCSS-8-for-end-users'
|
||
)
|
||
} else {
|
||
throw new Error(i + ' is not a PostCSS plugin')
|
||
}
|
||
}
|
||
return normalized
|
||
}
|
||
}
|
||
|
||
export default Processor
|
||
|
||
/**
|
||
* @callback builder
|
||
* @param {string} part Part of generated CSS connected to this node.
|
||
* @param {Node} node AST node.
|
||
* @param {"start"|"end"} [type] Node’s part type.
|
||
*/
|
||
|
||
/**
|
||
* @callback parser
|
||
*
|
||
* @param {string|toString} css String with input CSS or any object
|
||
* with toString() method, like a Buffer.
|
||
* @param {processOptions} [opts] Options with only `from` and `map` keys.
|
||
*
|
||
* @return {Root} PostCSS AST
|
||
*/
|
||
|
||
/**
|
||
* @callback stringifier
|
||
*
|
||
* @param {Node} node Start node for stringifing. Usually {@link Root}.
|
||
* @param {builder} builder Function to concatenate CSS from node’s parts
|
||
* or generate string and source map.
|
||
*
|
||
* @return {void}
|
||
*/
|
||
|
||
/**
|
||
* @typedef {object} syntax
|
||
* @property {parser} parse Function to generate AST by string.
|
||
* @property {stringifier} stringify Function to generate string by AST.
|
||
*/
|
||
|
||
/**
|
||
* @typedef {object} toString
|
||
* @property {function} toString
|
||
*/
|
||
|
||
/**
|
||
* @callback pluginFunction
|
||
* @param {Root} root Parsed input CSS.
|
||
* @param {Result} result Result to set warnings or check other plugins.
|
||
*/
|
||
|
||
/**
|
||
* @typedef {object} Plugin
|
||
* @property {function} postcss PostCSS plugin function.
|
||
*/
|
||
|
||
/**
|
||
* @typedef {object} processOptions
|
||
* @property {string} from The path of the CSS source file.
|
||
* You should always set `from`,
|
||
* because it is used in source map
|
||
* generation and syntax error messages.
|
||
* @property {string} to The path where you’ll put the output
|
||
* CSS file. You should always set `to`
|
||
* to generate correct source maps.
|
||
* @property {parser} parser Function to generate AST by string.
|
||
* @property {stringifier} stringifier Class to generate string by AST.
|
||
* @property {syntax} syntax Object with `parse` and `stringify`.
|
||
* @property {object} map Source map options.
|
||
* @property {boolean} map.inline Does source map should
|
||
* be embedded in the output
|
||
* CSS as a base64-encoded
|
||
* comment.
|
||
* @property {string|object|false|function} map.prev Source map content
|
||
* from a previous
|
||
* processing step
|
||
* (for example, Sass).
|
||
* PostCSS will try to find
|
||
* previous map automatically,
|
||
* so you could disable it by
|
||
* `false` value.
|
||
* @property {boolean} map.sourcesContent Does PostCSS should set
|
||
* the origin content to map.
|
||
* @property {string|false} map.annotation Does PostCSS should set
|
||
* annotation comment to map.
|
||
* @property {string} map.from Override `from` in map’s
|
||
* sources`.
|
||
*/
|