From 26105034da4fcce7ac883c899d781f016559310d Mon Sep 17 00:00:00 2001 From: ruki Date: Thu, 8 Nov 2018 00:38:48 +0800 Subject: switch to vuepress --- node_modules/postcss/docs/guidelines/plugin.md | 195 +++++++++++++++++++++ node_modules/postcss/docs/guidelines/runner.md | 143 +++++++++++++++ node_modules/postcss/docs/source-maps.md | 72 ++++++++ node_modules/postcss/docs/syntax.md | 231 +++++++++++++++++++++++++ 4 files changed, 641 insertions(+) create mode 100644 node_modules/postcss/docs/guidelines/plugin.md create mode 100644 node_modules/postcss/docs/guidelines/runner.md create mode 100644 node_modules/postcss/docs/source-maps.md create mode 100644 node_modules/postcss/docs/syntax.md (limited to 'node_modules/postcss/docs') diff --git a/node_modules/postcss/docs/guidelines/plugin.md b/node_modules/postcss/docs/guidelines/plugin.md new file mode 100644 index 00000000..4814b0fa --- /dev/null +++ b/node_modules/postcss/docs/guidelines/plugin.md @@ -0,0 +1,195 @@ +# PostCSS Plugin Guidelines + +A PostCSS plugin is a function that receives and, usually, +transforms a CSS AST from the PostCSS parser. + +The rules below are *mandatory* for all PostCSS plugins. + +See also [ClojureWerkz’s recommendations] for open source projects. + +[ClojureWerkz’s recommendations]: http://blog.clojurewerkz.org/blog/2013/04/20/how-to-make-your-open-source-project-really-awesome/ + +## 1. API + +### 1.1 Clear name with `postcss-` prefix + +The plugin’s purpose should be clear just by reading its name. +If you wrote a transpiler for CSS 4 Custom Media, `postcss-custom-media` +would be a good name. If you wrote a plugin to support mixins, +`postcss-mixins` would be a good name. + +The prefix `postcss-` shows that the plugin is part of the PostCSS ecosystem. + +This rule is not mandatory for plugins that can run as independent tools, +without the user necessarily knowing that it is powered by +PostCSS — for example, [cssnext] and [Autoprefixer]. + +[Autoprefixer]: https://github.com/postcss/autoprefixer +[cssnext]: http://cssnext.io/ + +### 1.2. Do one thing, and do it well + +Do not create multitool plugins. Several small, one-purpose plugins bundled into +a plugin pack is usually a better solution. + +For example, [cssnext] contains many small plugins, +one for each W3C specification. And [cssnano] contains a separate plugin +for each of its optimization. + +[cssnext]: http://cssnext.io/ +[cssnano]: https://github.com/ben-eb/cssnano + +### 1.3. Do not use mixins + +Preprocessors libraries like Compass provide an API with mixins. + +PostCSS plugins are different. +A plugin cannot be just a set of mixins for [postcss-mixins]. + +To achieve your goal, consider transforming valid CSS +or using custom at-rules and custom properties. + +[postcss-mixins]: https://github.com/postcss/postcss-mixins + +### 1.4. Create plugin by `postcss.plugin` + +By wrapping your function in this method, +you are hooking into a common plugin API: + +```js +module.exports = postcss.plugin('plugin-name', function (opts) { + return function (root, result) { + // Plugin code + }; +}); +``` + +## 2. Processing + +### 2.1. Plugin must be tested + +A CI service like [Travis] is also recommended for testing code in +different environments. You should test in (at least) Node.js [active LTS](https://github.com/nodejs/LTS) and current stable version. + +[Travis]: https://travis-ci.org/ + +### 2.2. Use asynchronous methods whenever possible + +For example, use `fs.writeFile` instead of `fs.writeFileSync`: + +```js +postcss.plugin('plugin-sprite', function (opts) { + return function (root, result) { + + return new Promise(function (resolve, reject) { + var sprite = makeSprite(); + fs.writeFile(opts.file, function (err) { + if ( err ) return reject(err); + resolve(); + }) + }); + + }; +}); +``` + +### 2.3. Set `node.source` for new nodes + +Every node must have a relevant `source` so PostCSS can generate +an accurate source map. + +So if you add new declaration based on some existing declaration, you should +clone the existing declaration in order to save that original `source`. + +```js +if ( needPrefix(decl.prop) ) { + decl.cloneBefore({ prop: '-webkit-' + decl.prop }); +} +``` + +You can also set `source` directly, copying from some existing node: + +```js +if ( decl.prop === 'animation' ) { + var keyframe = createAnimationByName(decl.value); + keyframes.source = decl.source; + decl.root().append(keyframes); +} +``` + +### 2.4. Use only the public PostCSS API + +PostCSS plugins must not rely on undocumented properties or methods, +which may be subject to change in any minor release. The public API +is described in [API docs]. + +[API docs]: http://api.postcss.org/ + +## 3. Errors + +### 3.1. Use `node.error` on CSS relevant errors + +If you have an error because of input CSS (like an unknown name +in a mixin plugin) you should use `node.error` to create an error +that includes source position: + +```js +if ( typeof mixins[name] === 'undefined' ) { + throw decl.error('Unknown mixin ' + name, { plugin: 'postcss-mixins' }); +} +``` + +### 3.2. Use `result.warn` for warnings + +Do not print warnings with `console.log` or `console.warn`, +because some PostCSS runner may not allow console output. + +```js +if ( outdated(decl.prop) ) { + result.warn(decl.prop + ' is outdated', { node: decl }); +} +``` + +If CSS input is a source of the warning, the plugin must set the `node` option. + +## 4. Documentation + +### 4.1. Document your plugin in English + +PostCSS plugins must have their `README.md` written in English. Do not be afraid +of your English skills, as the open source community will fix your errors. + +Of course, you are welcome to write documentation in other languages; +just name them appropriately (e.g. `README.ja.md`). + +### 4.2. Include input and output examples + +The plugin's `README.md` must contain example input and output CSS. +A clear example is the best way to describe how your plugin works. + +The first section of the `README.md` is a good place to put examples. +See [postcss-opacity](https://github.com/iamvdo/postcss-opacity) for an example. + +Of course, this guideline does not apply if your plugin does not +transform the CSS. + +### 4.3. Maintain a changelog + +PostCSS plugins must describe the changes of all their releases +in a separate file, such as `CHANGELOG.md`, `History.md`, or [GitHub Releases]. +Visit [Keep A Changelog] for more information about how to write one of these. + +Of course, you should be using [SemVer]. + +[Keep A Changelog]: http://keepachangelog.com/ +[GitHub Releases]: https://help.github.com/articles/creating-releases/ +[SemVer]: http://semver.org/ + +### 4.4. Include `postcss-plugin` keyword in `package.json` + +PostCSS plugins written for npm must have the `postcss-plugin` keyword +in their `package.json`. This special keyword will be useful for feedback about +the PostCSS ecosystem. + +For packages not published to npm, this is not mandatory, but is recommended +if the package format can contain keywords. diff --git a/node_modules/postcss/docs/guidelines/runner.md b/node_modules/postcss/docs/guidelines/runner.md new file mode 100644 index 00000000..83f20873 --- /dev/null +++ b/node_modules/postcss/docs/guidelines/runner.md @@ -0,0 +1,143 @@ +# PostCSS Runner Guidelines + +A PostCSS runner is a tool that processes CSS through a user-defined list +of plugins; for example, [`postcss-cli`] or [`gulp‑postcss`]. +These rules are mandatory for any such runners. + +For single-plugin tools, like [`gulp-autoprefixer`], +these rules are not mandatory but are highly recommended. + +See also [ClojureWerkz’s recommendations] for open source projects. + +[ClojureWerkz’s recommendations]: http://blog.clojurewerkz.org/blog/2013/04/20/how-to-make-your-open-source-project-really-awesome/ +[`gulp-autoprefixer`]: https://github.com/sindresorhus/gulp-autoprefixer +[`gulp‑postcss`]: https://github.com/w0rm/gulp-postcss +[`postcss-cli`]: https://github.com/postcss/postcss-cli + +## 1. API + +### 1.1. Accept functions in plugin parameters + +If your runner uses a config file, it must be written in JavaScript, so that +it can support plugins which accept a function, such as [`postcss-assets`]: + +```js +module.exports = [ + require('postcss-assets')({ + cachebuster: function (file) { + return fs.statSync(file).mtime.getTime().toString(16); + } + }) +]; +``` + +[`postcss-assets`]: https://github.com/borodean/postcss-assets + +## 2. Processing + +### 2.1. Set `from` and `to` processing options + +To ensure that PostCSS generates source maps and displays better syntax errors, +runners must specify the `from` and `to` options. If your runner does not handle +writing to disk (for example, a gulp transform), you should set both options +to point to the same file: + +```js +processor.process({ from: file.path, to: file.path }); +``` + +### 2.2. Use only the asynchronous API + +PostCSS runners must use only the asynchronous API. +The synchronous API is provided only for debugging, is slower, +and can’t work with asynchronous plugins. + +```js +processor.process(opts).then(function (result) { + // processing is finished +}); +``` + +### 2.3. Use only the public PostCSS API + +PostCSS runners must not rely on undocumented properties or methods, +which may be subject to change in any minor release. The public API +is described in [API docs]. + +[API docs]: http://api.postcss.org/ + +## 3. Output + +### 3.1. Don’t show JS stack for `CssSyntaxError` + +PostCSS runners must not show a stack trace for CSS syntax errors, +as the runner can be used by developers who are not familiar with JavaScript. +Instead, handle such errors gracefully: + +```js +processor.process(opts).catch(function (error) { + if ( error.name === 'CssSyntaxError' ) { + process.stderr.write(error.message + error.showSourceCode()); + } else { + throw error; + } +}); +``` + +### 3.2. Display `result.warnings()` + +PostCSS runners must output warnings from `result.warnings()`: + +```js +result.warnings().forEach(function (warn) { + process.stderr.write(warn.toString()); +}); +``` + +See also [postcss-log-warnings] and [postcss-messages] plugins. + +[postcss-log-warnings]: https://github.com/davidtheclark/postcss-log-warnings +[postcss-messages]: https://github.com/postcss/postcss-messages + +### 3.3. Allow the user to write source maps to different files + +PostCSS by default will inline source maps in the generated file; however, +PostCSS runners must provide an option to save the source map in a different +file: + +```js +if ( result.map ) { + fs.writeFile(opts.to + '.map', result.map.toString()); +} +``` + +## 4. Documentation + +### 4.1. Document your runner in English + +PostCSS runners must have their `README.md` written in English. Do not be afraid +of your English skills, as the open source community will fix your errors. + +Of course, you are welcome to write documentation in other languages; +just name them appropriately (e.g. `README.ja.md`). + +### 4.2. Maintain a changelog + +PostCSS runners must describe changes of all releases in a separate file, +such as `ChangeLog.md`, `History.md`, or with [GitHub Releases]. +Visit [Keep A Changelog] for more information on how to write one of these. + +Of course you should use [SemVer]. + +[Keep A Changelog]: http://keepachangelog.com/ +[GitHub Releases]: https://help.github.com/articles/creating-releases/ +[SemVer]: http://semver.org/ + +### 4.3. `postcss-runner` keyword in `package.json` + +PostCSS runners written for npm must have the `postcss-runner` keyword +in their `package.json`. This special keyword will be useful for feedback about +the PostCSS ecosystem. + +For packages not published to npm, this is not mandatory, but recommended +if the package format is allowed to contain keywords. diff --git a/node_modules/postcss/docs/source-maps.md b/node_modules/postcss/docs/source-maps.md new file mode 100644 index 00000000..6b8e56bb --- /dev/null +++ b/node_modules/postcss/docs/source-maps.md @@ -0,0 +1,72 @@ +# PostCSS and Source Maps + +PostCSS has great [source maps] support. It can read and interpret maps +from previous transformation steps, autodetect the format that you expect, +and output both external and inline maps. + +To ensure that you generate an accurate source map, you must indicate the input +and output CSS file paths — using the options `from` and `to`, respectively. + +To generate a new source map with the default options, simply set `map: true`. +This will generate an inline source map that contains the source content. +If you don’t want the map inlined, you can set `map.inline: false`. + +```js +processor + .process(css, { + from: 'app.sass.css', + to: 'app.css', + map: { inline: false }, + }) + .then(function (result) { + result.map //=> '{ "version":3, + // "file":"app.css", + // "sources":["app.sass"], + // "mappings":"AAAA,KAAI" }' + }); +``` + +If PostCSS finds source maps from a previous transformation, +it will automatically update that source map with the same options. + +## Options + +If you want more control over source map generation, you can define the `map` +option as an object with the following parameters: + +* `inline` boolean: indicates that the source map should be embedded + in the output CSS as a Base64-encoded comment. By default, it is `true`. + But if all previous maps are external, not inline, PostCSS will not embed + the map even if you do not set this option. + + If you have an inline source map, the `result.map` property will be empty, + as the source map will be contained within the text of `result.css`. + +* `prev` string, object, boolean or function: source map content from + a previous processing step (for example, Sass compilation). + PostCSS will try to read the previous source map automatically + (based on comments within the source CSS), but you can use this option + to identify it manually. If desired, you can omit the previous map + with `prev: false`. + +* `sourcesContent` boolean: indicates that PostCSS should set the origin + content (for example, Sass source) of the source map. By default, + it is `true`. But if all previous maps do not contain sources content, + PostCSS will also leave it out even if you do not set this option. + +* `annotation` boolean or string: indicates that PostCSS should add annotation + comments to the CSS. By default, PostCSS will always add a comment with a path + to the source map. PostCSS will not add annotations to CSS files that + do not contain any comments. + + By default, PostCSS presumes that you want to save the source map as + `opts.to + '.map'` and will use this path in the annotation comment. + A different path can be set by providing a string value for `annotation`. + + If you have set `inline: true`, annotation cannot be disabled. + +* `from` string: by default, PostCSS will set the `sources` property of the map + to the value of the `from` option. If you want to override this behaviour, you + can use `map.from` to explicitly set the source map's `sources` property. + +[source maps]: http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/ diff --git a/node_modules/postcss/docs/syntax.md b/node_modules/postcss/docs/syntax.md new file mode 100644 index 00000000..10818f72 --- /dev/null +++ b/node_modules/postcss/docs/syntax.md @@ -0,0 +1,231 @@ +# How to Write Custom Syntax + +PostCSS can transform styles in any syntax, and is not limited to just CSS. +By writing a custom syntax, you can transform styles in any desired format. + +Writing a custom syntax is much harder than writing a PostCSS plugin, but +it is an awesome adventure. + +There are 3 types of PostCSS syntax packages: + +* **Parser** to parse input string to node’s tree. +* **Stringifier** to generate output string by node’s tree. +* **Syntax** contains both parser and stringifier. + +## Syntax + +A good example of a custom syntax is [SCSS]. Some users may want to transform +SCSS sources with PostCSS plugins, for example if they need to add vendor +prefixes or change the property order. So this syntax should output SCSS from +an SCSS input. + +The syntax API is a very simple plain object, with `parse` & `stringify` +functions: + +```js +module.exports = { + parse: require('./parse'), + stringify: require('./stringify') +}; +``` + +[SCSS]: https://github.com/postcss/postcss-scss + +## Parser + +A good example of a parser is [Safe Parser], which parses malformed/broken CSS. +Because there is no point to generate broken output, this package only provides +a parser. + +The parser API is a function which receives a string & returns a [`Root`] node. +The second argument is a function which receives an object with PostCSS options. + +```js +var postcss = require('postcss'); + +module.exports = function (css, opts) { + var root = postcss.root(); + // Add other nodes to root + return root; +}; +``` + +[Safe Parser]: https://github.com/postcss/postcss-safe-parser +[`Root`]: http://api.postcss.org/Root.html + +### Main Theory + +There are many books about parsers; but do not worry because CSS syntax is +very easy, and so the parser will be much simpler than a programming language +parser. + +The default PostCSS parser contains two steps: + +1. [Tokenizer] which reads input string character by character and builds a + tokens array. For example, it joins space symbols to a `['space', '\n ']` + token, and detects strings to a `['string', '"\"{"']` token. +2. [Parser] which reads the tokens array, creates node instances and + builds a tree. + +[Tokenizer]: https://github.com/postcss/postcss/blob/master/lib/tokenize.es6 +[Parser]: https://github.com/postcss/postcss/blob/master/lib/parser.es6 + +### Performance + +Parsing input is often the most time consuming task in CSS processors. So it +is very important to have a fast parser. + +The main rule of optimization is that there is no performance without a +benchmark. You can look at [PostCSS benchmarks] to build your own. + +Of parsing tasks, the tokenize step will often take the most time, so its +performance should be prioritized. Unfortunately, classes, functions and +high level structures can slow down your tokenizer. Be ready to write dirty +code with repeated statements. This is why it is difficult to extend the +default [PostCSS tokenizer]; copy & paste will be a necessary evil. + +Second optimization is using character codes instead of strings. + +```js +// Slow +string[i] === '{'; + +// Fast +const OPEN_CURLY = 123; // `{' +string.charCodeAt(i) === OPEN_CURLY; +``` + +Third optimization is “fast jumps”. If you find open quotes, you can find +next closing quote much faster by `indexOf`: + +```js +// Simple jump +next = string.indexOf('"', currentPosition + 1); + +// Jump by RegExp +regexp.lastIndex = currentPosion + 1; +regexp.text(string); +next = regexp.lastIndex; +``` + +The parser can be a well written class. There is no need in copy-paste and +hardcore optimization there. You can extend the default [PostCSS parser]. + +[PostCSS benchmarks]: https://github.com/postcss/benchmark +[PostCSS tokenizer]: https://github.com/postcss/postcss/blob/master/lib/tokenize.es6 +[PostCSS parser]: https://github.com/postcss/postcss/blob/master/lib/parser.es6 + +### Node Source + +Every node should have `source` property to generate correct source map. +This property contains `start` and `end` properties with `{ line, column }`, +and `input` property with an [`Input`] instance. + +Your tokenizer should save the original position so that you can propagate +the values to the parser, to ensure that the source map is correctly updated. + +[`Input`]: https://github.com/postcss/postcss/blob/master/lib/input.es6 + +### Raw Values + +A good PostCSS parser should provide all information (including spaces symbols) +to generate byte-to-byte equal output. It is not so difficult, but respectful +for user input and allow integration smoke tests. + +A parser should save all additional symbols to `node.raws` object. +It is an open structure for you, you can add additional keys. +For example, [SCSS parser] saves comment types (`/* */` or `//`) +in `node.raws.inline`. + +The default parser cleans CSS values from comments and spaces. +It saves the original value with comments to `node.raws.value.raw` and uses it, +if the node value was not changed. + +[SCSS parser]: https://github.com/postcss/postcss-scss + +### Tests + +Of course, all parsers in the PostCSS ecosystem must have tests. + +If your parser just extends CSS syntax (like [SCSS] or [Safe Parser]), +you can use the [PostCSS Parser Tests]. It contains unit & integration tests. + +[PostCSS Parser Tests]: https://github.com/postcss/postcss-parser-tests + +## Stringifier + +A style guide generator is a good example of a stringifier. It generates output +HTML which contains CSS components. For this use case, a parser isn't necessary, +so the package should just contain a stringifier. + +The Stringifier API is little bit more complicated, than the parser API. +PostCSS generates a source map, so a stringifier can’t just return a string. +It must link every substring with its source node. + +A Stringifier is a function which receives [`Root`] node and builder callback. +Then it calls builder with every node’s string and node instance. + +```js +module.exports = function (root, builder) { + // Some magic + var string = decl.prop + ':' + decl.value + ';'; + builder(string, decl); + // Some science +}; +``` + +### Main Theory + +PostCSS [default stringifier] is just a class with a method for each node type +and many methods to detect raw properties. + +In most cases it will be enough just to extend this class, +like in [SCSS stringifier]. + +[default stringifier]: https://github.com/postcss/postcss/blob/master/lib/stringifier.es6 +[SCSS stringifier]: https://github.com/postcss/postcss-scss/blob/master/lib/scss-stringifier.es6 + +### Builder Function + +A builder function will be passed to `stringify` function as second argument. +For example, the default PostCSS stringifier class saves it +to `this.builder` property. + +Builder receives output substring and source node to append this substring +to the final output. + +Some nodes contain other nodes in the middle. For example, a rule has a `{` +at the beginning, many declarations inside and a closing `}`. + +For these cases, you should pass a third argument to builder function: +`'start'` or `'end'` string: + +```js +this.builder(rule.selector + '{', rule, 'start'); +// Stringify declarations inside +this.builder('}', rule, 'end'); +``` + +### Raw Values + +A good PostCSS custom syntax saves all symbols and provide byte-to-byte equal +output if there were no changes. + +This is why every node has `node.raws` object to store space symbol, etc. + +Be careful, because sometimes these raw properties will not be present; some +nodes may be built manually, or may lose their indentation when they are moved +to another parent node. + +This is why the default stringifier has a `raw()` method to autodetect raw +properties by other nodes. For example, it will look at other nodes to detect +indent size and them multiply it with the current node depth. + +### Tests + +A stringifier must have tests too. + +You can use unit and integration test cases from [PostCSS Parser Tests]. +Just compare input CSS with CSS after your parser and stringifier. + +[PostCSS Parser Tests]: https://github.com/postcss/postcss-parser-tests -- cgit v1.2.3