Fix bin/publish: copy docs.dist from project root

Fix bin/publish: use correct .env path for rspade_system
Fix bin/publish script: prevent grep exit code 1 from terminating script

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-10-21 02:08:33 +00:00
commit f6fac6c4bc
79758 changed files with 10547827 additions and 0 deletions

105
vendor/spatie/ignition/node_modules/microbundle/CHANGELOG.md generated vendored Executable file
View File

@@ -0,0 +1,105 @@
# microbundle
## 0.14.2
### Patch Changes
- [`dd0bdde`](https://github.com/developit/microbundle/commit/dd0bdde9c6ae7d0690fa73aead1c1744ae3b086a) [#904](https://github.com/developit/microbundle/pull/904) Thanks [@rschristian](https://github.com/rschristian)! - Added missing CLI doc for 'jsxImportSource' and correcting the Examples section of the '--help' output
## 0.14.1
### Patch Changes
- [`2a0ca88`](https://github.com/developit/microbundle/commit/2a0ca8843f34c3773bb41eb3f8f571fb6b2b2d52) [#882](https://github.com/developit/microbundle/pull/882) Thanks [@MiKr13](https://github.com/MiKr13)! - feat: :sparkles: Closes #497: preserve trailing newline in mangle.json
* [`26f382a`](https://github.com/developit/microbundle/commit/26f382a989e86fdcc5149f73f7b6c9d314a4bf37) [#895](https://github.com/developit/microbundle/pull/895) Thanks [@rschristian](https://github.com/rschristian)! - Completion message shows pkg's actual name, rather than safe name
## 0.14.0
### Minor Changes
- [`1b61029`](https://github.com/developit/microbundle/commit/1b6102966440bd7000e0e457f8c0b7eeb7e05593) [#867](https://github.com/developit/microbundle/pull/867) Thanks [@bouchenoiremarc](https://github.com/bouchenoiremarc)! - - Add support for Module Workers with a new `--workers` flag
### Patch Changes
- [`5e93a0e`](https://github.com/developit/microbundle/commit/5e93a0e4cc28ea8f080a08e3a8530b6bfdf25f42) [#853](https://github.com/developit/microbundle/pull/853) Thanks [@developit](https://github.com/developit)! - Fix crash when traversing `"exports"` objects (#852)
* [`96b85da`](https://github.com/developit/microbundle/commit/96b85da1e32b4ffbef9d83387ff399d8b3ee3852) [#887](https://github.com/developit/microbundle/pull/887) Thanks [@developit](https://github.com/developit)! - When using `--target node`, resolve "node" conditional Package Export keys, otherwise resolve "browser" keys.
- [`5d0465b`](https://github.com/developit/microbundle/commit/5d0465b39bccff31673d351fc9d29cb4c470407d) [#875](https://github.com/developit/microbundle/pull/875) Thanks [@dwightjack](https://github.com/dwightjack)! - Preserve terser annotations in compressed bundle
* [`b1a6374`](https://github.com/developit/microbundle/commit/b1a637486234a2ae784ccf0c512321e2d3efef7c) [#858](https://github.com/developit/microbundle/pull/858) Thanks [@bouchenoiremarc](https://github.com/bouchenoiremarc)! - - Allow the minify options `compress` and `mangle` to be set as booleans
- [`2980336`](https://github.com/developit/microbundle/commit/29803364fe54cc1a7a8543d61e694c90b4cdce6a) [#865](https://github.com/developit/microbundle/pull/865) Thanks [@rschristian](https://github.com/rschristian)! - Expands generateTypes flag to support libs with TS entrypoints
## 0.13.3
### Patch Changes
- [`3534815`](https://github.com/developit/microbundle/commit/3534815ddabecc080cdec42cd1f6009a81a48ec9) [#848](https://github.com/developit/microbundle/pull/848) Thanks [@developit](https://github.com/developit)! - Bugfix: preserve Terser annotations like `/*@__NOINLINE__*/` during Babel pass
## 0.13.2
### Patch Changes
- [`e3f1933`](https://github.com/developit/microbundle/commit/e3f1933773fd17bb1d97de0dad94d899acee7598) [#847](https://github.com/developit/microbundle/pull/847) Thanks [@developit](https://github.com/developit)! - - Upgrade to Terser [5.7](https://github.com/terser/terser/blob/master/CHANGELOG.md#v570) to re-enable support for `reduce_funcs:false` in `mangle.json` configuration.
* [`86371f0`](https://github.com/developit/microbundle/commit/86371f0db6386089c66cd474a7121d9dbee4c0cf) [#784](https://github.com/developit/microbundle/pull/784) Thanks [@rschristian](https://github.com/rschristian)! - Allows users to customize the modern output's filename using "exports" like they can with "esmodules"
## 0.13.1
### Patch Changes
- [`54402ac`](https://github.com/developit/microbundle/commit/54402ac43cc2f7ccb85fe5df2e9828c7f24091a0) [#830](https://github.com/developit/microbundle/pull/830) Thanks [@JounQin](https://github.com/JounQin)! - fix: add generateTypes cli option, check false value correctly
* [`edcd777`](https://github.com/developit/microbundle/commit/edcd777cfaedfdb436c62b5dcb3cff6291268e4c) [#823](https://github.com/developit/microbundle/pull/823) Thanks [@rschristian](https://github.com/rschristian)! - Ensures ambient type declaration for CSS Modules is included in the published bundle
- [`d87a5dc`](https://github.com/developit/microbundle/commit/d87a5dc286a1edba92ca3ec5b534807688c90854) Thanks [@developit](https://github.com/developit)! - - Fix `--sourcemap=false` to match `--no-sourcemap` and actually turn sourcemaps off.
* [`6f1a20f`](https://github.com/developit/microbundle/commit/6f1a20fa17467176f9bc1acc2b0f78784d28d110) [#777](https://github.com/developit/microbundle/pull/777) Thanks [@rschristian](https://github.com/rschristian)! - Fixing a bug that would cause a CSS file to be generated to match each JS build output
- [`25b73d2`](https://github.com/developit/microbundle/commit/25b73d22caeac7cf74b0533401318a5becc29c11) [#834](https://github.com/developit/microbundle/pull/834) Thanks [@cometkim](https://github.com/cometkim)! - Add support for configuration overrides using the `publishConfig` package.json field.
* [`0a4cddf`](https://github.com/developit/microbundle/commit/0a4cddf98ab54c41f0b2ece1d626e459f73c9997) [#842](https://github.com/developit/microbundle/pull/842) Thanks [@ForsakenHarmony](https://github.com/ForsakenHarmony)! - fix default extension to cjs for package.json "type":"module"
- [`4f7fbc4`](https://github.com/developit/microbundle/commit/4f7fbc4a0b9e03b9c33d10b21c66b8ddef7524a7) Thanks [@developit](https://github.com/developit)! - Fix `transform-fast-rest` to support referencing `...rest` params from within closures.
* [`0c91795`](https://github.com/developit/microbundle/commit/0c917959570c788929766c6f4cd55f3b49433920) [#841](https://github.com/developit/microbundle/pull/841) Thanks [@rschristian](https://github.com/rschristian)! - Ensures JS format is not included in CSS filename output
## 0.13.0
### Minor Changes
- [`bd5d15e`](https://github.com/developit/microbundle/commit/bd5d15e17c882f2090f519d342dd89e694456ab8) [#738](https://github.com/developit/microbundle/pull/738) Thanks [@wardpeet](https://github.com/wardpeet)! - Upgrade rollup to version latest and upgrade all its dependencies
* [`967f8d5`](https://github.com/developit/microbundle/commit/967f8d532785aa7bf8636c5a759759a3e72dcf56) [#769](https://github.com/developit/microbundle/pull/769) Thanks [@developit](https://github.com/developit)! - Add `--css inline` option. The default CSS output for all formats is now external files (as it was supposed to be).
- [`8142704`](https://github.com/developit/microbundle/commit/8142704399efe6b4f34219c711a3932431781b36) [#741](https://github.com/developit/microbundle/pull/741) Thanks [@whitetrefoil](https://github.com/whitetrefoil)! - Use user's typescript first, fallback to bundled
### Patch Changes
- [`12668b9`](https://github.com/developit/microbundle/commit/12668b993906a0267c53c3601ce89d1c0ddfbc27) [#687](https://github.com/developit/microbundle/pull/687) Thanks [@developit](https://github.com/developit)! - Add friendly microbundle-specific errors when modules can't be resolved.
* [`8b60fc8`](https://github.com/developit/microbundle/commit/8b60fc86cbc493e23230a58cd0c99e2e0c675974) [#754](https://github.com/developit/microbundle/pull/754) Thanks [@stipsan](https://github.com/stipsan)! - Enable sourcemaps for CSS
- [`fdafaf7`](https://github.com/developit/microbundle/commit/fdafaf7a4ad76b1757e2c0ff39050f8e11e2f1d5) [#764](https://github.com/developit/microbundle/pull/764) Thanks [@bakerkretzmar](https://github.com/bakerkretzmar)! - Add support for generating inline sourcemaps
* [`52a1771`](https://github.com/developit/microbundle/commit/52a177190eb45791cb4b44d4bf04732b8b98d9c3) [#768](https://github.com/developit/microbundle/pull/768) Thanks [@developit](https://github.com/developit)! - Add ambient typescript declaration for CSS Modules
## 0.12.4
### Patch Changes
- [`ffcc9d9`](https://github.com/developit/microbundle/commit/ffcc9d9b7d9518ae2fa31b2af4d1fd4f98599560) [#713](https://github.com/developit/microbundle/pull/713) Thanks [@developit](https://github.com/developit)! - Support [extending a UMD global](https://rollupjs.org/guide/en/#outputextend) by prefixing the package.json `"amdName"` field (eg: `"global.xyz"`).
* [`0527862`](https://github.com/developit/microbundle/commit/052786223edce8258c73a72a49238e41e5b24850) [#722](https://github.com/developit/microbundle/pull/722) Thanks [@developit](https://github.com/developit)! - Support "esm" (`-f esm`) as an alias of "es" format.
- [`d08f977`](https://github.com/developit/microbundle/commit/d08f977aa6b19b267cf8d12861cc5cc34380d025) [#702](https://github.com/developit/microbundle/pull/702) Thanks [@wardpeet](https://github.com/wardpeet)! - Use @babel/preset-env with bugfixes instead of preset-modules to enable "Optional chaining" & "nullish coalescing" by default.
* [`d33a7ba`](https://github.com/developit/microbundle/commit/d33a7ba2f5475e870d1a0f659b0c3ec0c459a850) [#731](https://github.com/developit/microbundle/pull/731) Thanks [@vaneenige](https://github.com/vaneenige)! - Add jsxImportSource flag for new JSX runtime
- [`0fec414`](https://github.com/developit/microbundle/commit/0fec41493c39669270ba2b58401dc591e551d96d) [#716](https://github.com/developit/microbundle/pull/716) Thanks [@wardpeet](https://github.com/wardpeet)! - Don't transpile generators and async for Node
* [`ba1c047`](https://github.com/developit/microbundle/commit/ba1c047512356e0e48911f5f037be798c5c2b9eb) [#701](https://github.com/developit/microbundle/pull/701) Thanks [@wardpeet](https://github.com/wardpeet)! - re-enable unpkg alias for umd bundles as described in the readme
- [`3488411`](https://github.com/developit/microbundle/commit/34884116e21408305b337a9f6267f6c2ddc9e72d) [#700](https://github.com/developit/microbundle/pull/700) Thanks [@wardpeet](https://github.com/wardpeet)! - Disable warnings for node's builtin-modules when using node as a target environment.

21
vendor/spatie/ignition/node_modules/microbundle/LICENSE generated vendored Executable file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017-present Jason Miller
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

386
vendor/spatie/ignition/node_modules/microbundle/README.md generated vendored Executable file
View File

@@ -0,0 +1,386 @@
<p align="center">
<img src="https://i.imgur.com/LMEgZMh.gif" width="597" alt="microbundle">
</p>
<h1 align="center">
Microbundle
<a href="https://www.npmjs.org/package/microbundle"><img src="https://img.shields.io/npm/v/microbundle.svg?style=flat" alt="npm"></a> <a href="https://travis-ci.org/developit/microbundle"><img src="https://travis-ci.org/developit/microbundle.svg?branch=master" alt="travis"></a>
</h1>
<p align="center">The <strong>zero-configuration</strong> bundler for <em>tiny modules</em>, powered by <a href="https://github.com/rollup/rollup">Rollup</a>.</p>
---
<p align="center">
<strong>Guide → </strong>
<a href="#setup">Setup</a> ✯
<a href="#formats">Formats</a> ✯
<a href="#modern">Modern Mode</a> ✯
<a href="#usage">Usage &amp; Configuration</a> ✯
<a href="#options">All Options</a>
</p>
---
## ✨ Features <a name="features"></a>
- **One dependency** to bundle your library using only a `package.json`
- Support for ESnext & async/await _(via [Babel] & [async-to-promises])_
- Produces tiny, optimized code for all inputs
- Supports multiple entry modules _(`cli.js` + `index.js`, etc)_
- Creates multiple output formats for each entry _(<abbr title="CommonJS (node)">CJS</abbr>, <abbr title="Universal Module Definition">UMD</abbr> & <abbr title="ECMAScript Modules">ESM</abbr>)_
- 0 configuration TypeScript support
- Built-in Terser compression & gzipped bundle size tracking
## 🔧 Installation & Setup <a name="setup"></a> <a name="installation"></a>
1**Install** by running: `npm i -D microbundle`
2**Set up** your `package.json`:
```jsonc
{
"name": "foo", // your package name
"type": "module",
"source": "src/foo.js", // your source code
"exports": {
"require": "./dist/foo.cjs", // used for require() in Node 12+
"default": "./dist/foo.modern.js" // where to generate the modern bundle (see below)
},
"main": "./dist/foo.cjs", // where to generate the CommonJS bundle
"module": "./dist/foo.module.js", // where to generate the ESM bundle
"unpkg": "./dist/foo.umd.js", // where to generate the UMD bundle (also aliased as "umd:main")
"scripts": {
"build": "microbundle", // compiles "source" to "main"/"module"/"unpkg"
"dev": "microbundle watch" // re-build when source files change
}
}
```
3**Try it out** by running `npm run build`.
## 💽 Output Formats <a name="formats"></a>
Microbundle produces <code title="ECMAScript Modules (import / export)">esm</code>, <code title="CommonJS (Node-style module.exports)">cjs</code>, <code title="Universal Module Definition (works everywhere)">umd</code> bundles with your code compiled to syntax that works pretty much everywhere.
While it's possible to customize the browser or Node versions you wish to support using a [browserslist configuration](https://github.com/browserslist/browserslist#browserslist-), the default setting is optimal and strongly recommended.
## 🤖 Modern Mode <a name="modern"></a>
In addition to the above formats, Microbundle also outputs a `modern` bundle specially designed to work in _all modern browsers_.
This bundle preserves most modern JS features when compiling your code, but ensures the result runs in 95% of web browsers without needing to be transpiled.
Specifically, it uses Babel's ["bugfixes" mode](https://babeljs.io/blog/2020/03/16/7.9.0#babelpreset-envs-bugfixes-option-11083httpsgithubcombabelbabelpull11083)
(previously known as [preset-modules](https://github.com/babel/preset-modules)) to target the set of browsers that support `<script type="module">` - that allows syntax like async/await, tagged templates, arrow functions, destructured and rest parameters, etc.
The result is generally smaller and faster to execute than the plain `esm` bundle.
Take the following source code for example:
```js
// Our source, "src/make-dom.js":
export default async function makeDom(tag, props, children) {
let el = document.createElement(tag);
el.append(...(await children));
return Object.assign(el, props);
}
```
Compiling the above using Microbundle produces the following `modern` and `esm` bundles:
<table>
<thead><tr>
<th align="left"><code>make-dom.modern.js</code> <sup>(117b)</sup></th>
<th align="left"><code>make-dom.module.js</code> <sup>(194b)</sup></th>
</tr></thead>
<tbody><tr valign="top"><td>
```js
export default async function (e, t, a) {
let n = document.createElement(e);
n.append(...(await a));
return Object.assign(n, t);
}
```
</td><td>
```js
export default function (e, t, r) {
try {
var n = document.createElement(e);
return Promise.resolve(r).then(function (e) {
return n.append.apply(n, e), Object.assign(n, t);
});
} catch (e) {
return Promise.reject(e);
}
}
```
</td></tbody></table>
**This is enabled by default.** All you have to do is add an `"exports"` field to your `package.json`:
```jsonc
{
"main": "./dist/foo.umd.js", // legacy UMD output (for Node & CDN use)
"module": "./dist/foo.module.js", // legacy ES Modules output (for bundlers)
"exports": "./dist/foo.modern.js", // modern ES2017 output
"scripts": {
"build": "microbundle src/foo.js"
}
}
```
The `"exports"` field can also be an object for packages with multiple entry modules:
```jsonc
{
"name": "foo",
"exports": {
".": "./dist/foo.modern.js", // import "foo" (the default)
"./lite": "./dist/lite.modern.js", // import "foo/lite"
"./full": "./dist/full.modern.js" // import "foo/full"
},
"scripts": {
"build": "microbundle src/*.js" // build foo.js, lite.js and full.js
}
}
```
## 📦 Usage & Configuration <a name="usage"></a>
Microbundle includes two commands - `build` (the default) and `watch`.
Neither require any options, but you can tailor things to suit your needs a bit if you like.
- **`microbundle`** bundles your code once and exits. (alias: `microbundle build`)
- **`microbundle watch`** bundles your code, then re-bundles when files change.
> Microbundle automatically determines which dependencies to inline into bundles based on your `package.json`.
>
> Read more about [How Microbundle decides which dependencies to bundle](https://github.com/developit/microbundle/wiki/How-Microbundle-decides-which-dependencies-to-bundle), including some example configurations.
### Specifying filenames in package.json
Unless overridden via the command line, microbundle uses the `source` property in your `package.json` to determine which of your JavaScript files to start bundling from (your "entry module").
The filenames and paths for generated bundles in each format are defined by the `main`, `umd:main`, `module` and `exports` properties in your `package.json`.
```jsonc
{
"source": "src/index.js", // input
"main": "dist/foo.js", // CommonJS output bundle
"umd:main": "dist/foo.umd.js", // UMD output bundle
"module": "dist/foo.m.js", // ES Modules output bundle
"exports": {
"require": "./dist/foo.js", // CommonJS output bundle
"default": "./dist/foo.modern.js", // Modern ES Modules output bundle
},
"types": "dist/foo.d.ts" // TypeScript typings directory
}
```
When deciding which bundle to use, Node.js 12+ and webpack 5+ will prefer the `exports` property, while older Node.js releases use the `main` property, and other bundlers prefer the `module` field.
For more information about the meaning of the different properties, refer to the [Node.js documentation](https://nodejs.org/api/packages.html#packages_package_entry_points).
For UMD builds, microbundle will use a camelCase version of the `name` field in your `package.json` as export name.
Alternatively, this can be explicitly by adding an `"amdName"` key in your `package.json`, or passing the `--name` command line argument.
### Usage with `{"type":"module"}` in `package.json`
Node.js 12.16+ adds a new "ES Module package", which can be enabled by adding `{"type":"module"}` to your package.json.
This property [changes the default source type](https://nodejs.org/api/packages.html#packages_determining_module_system) of `.js` files to be ES Modules instead of CommonJS.
When using `{"type":"module"}`, the file extension for CommonJS bundles generated by Microbundle must be changed to `.cjs`:
```jsonc
{
"type": "module",
"module": "dist/foo.js", // ES Module bundle
"main": "dist/foo.cjs", // CommonJS bundle
}
```
### Additional Configuration Options
Config also can be overridded by the [`publishConfig`](https://docs.npmjs.com/cli/v7/configuring-npm/package-json#publishconfig) property in your `package.json`.
```jsonc
{
"main": "src/index.ts", // this would be used in the dev environment (e.g. Jest)
"publishConfig": {
"source": "src/index.js", // input
"main": "dist/my-library.js", // output
},
"scripts": {
"build": "microbundle"
}
}
```
### Building a single bundle with fixed output name
By default Microbundle outputs multiple bundles, one bundle per format. A single bundle with a fixed output name can be built like this:
```bash
microbundle -i lib/main.js -o dist/bundle.js --no-pkg-main -f umd
```
### Using with TypeScript
Just point the input to a `.ts` file through either the cli or the `source` key in your `package.json` and youre done.
Microbundle will generally respect your TypeScript config defined in a `tsconfig.json` file with notable exceptions being the "[target](https://www.typescriptlang.org/tsconfig#target)" and "[module](https://www.typescriptlang.org/tsconfig#module)" settings. To ensure your TypeScript configuration matches the configuration that Microbundle uses internally it's strongly recommended that you set `"module": "ESNext"` and `"target": "ESNext"` in your `tsconfig.json`.
To ensure Microbundle does not process extraneous files, by default it only includes your entry point. If you want to include other files for compilation, such as ambient declarations, make sure to add either "[files](https://www.typescriptlang.org/tsconfig#files)" or "[include](https://www.typescriptlang.org/tsconfig#include)" into your `tsconfig.json`.
If you're using TypeScript with CSS Modules, you will want to set `"include": ["node_modules/microbundle/index.d.ts"]` in your `tsconfig.json` to tell TypeScript how to handle your CSS Module imports.
### CSS and CSS Modules
Importing CSS files is supported via `import "./foo.css"`. By default, generated CSS output is written to disk. The `--css inline` command line option will inline generated CSS into your bundles as a string, returning the CSS string from the import:
```js
// with the default external CSS:
import './foo.css'; // generates a minified .css file in the output directory
// with `microbundle --css inline`:
import css from './foo.css';
console.log(css); // the generated minified stylesheet
```
**CSS Modules:** CSS files with names ending in `.module.css` are treated as a [CSS Modules](https://github.com/css-modules/css-modules).
To instead treat imported `.css` files as modules, run Microbundle with `--css-modules true`. To disable CSS Modules for your project, pass `--no-css-modules` or `--css-modules false`.
The default scope name for CSS Modules is`_[name]__[local]__[hash:base64:5]` in watch mode, and `_[hash:base64:5]` for production builds.
This can be customized by passing the command line argument `--css-modules "[name]_[hash:base64:7]"`, using [these fields and naming conventions](https://github.com/webpack/loader-utils#interpolatename).
| flag | import | is css module? |
| ----- | ------------------------------ | :----------------: |
| null | import './my-file.css'; | :x: |
| null | import './my-file.module.css'; | :white_check_mark: |
| false | import './my-file.css'; | :x: |
| false | import './my-file.module.css'; | :x: |
| true | import './my-file.css'; | :white_check_mark: |
| true | import './my-file.module.css'; | :white_check_mark: |
### Building Module Workers
Microbundle is able to detect and bundle Module Workers when generating bundles in the
`es`, `umd` and `modern` formats. To use this feature, instantiate your Web Worker as follows:
```js
worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' });
// or simply:
worker = new Worker('./worker.js', { type: 'module' });
```
... then add the `--workers` flag to your build command:
```bash
microbundle --workers
```
For more information see
[@surma/rollup-plugin-off-main-thread](https://github.com/surma/rollup-plugin-off-main-thread#config).
### Mangling Properties
To achieve the smallest possible bundle size, libraries often wish to rename internal object properties or class members to smaller names - transforming `this._internalIdValue` to `this._i`. Microbundle doesn't do this by default, however it can be enabled by creating a `mangle.json` file (or a `"mangle"` property in your package.json). Within that file, you can specify a regular expression pattern to control which properties should be mangled. For example: to mangle all property names beginning an underscore:
```jsonc
{
"mangle": {
"regex": "^_"
}
}
```
It's also possible to configure repeatable short names for each mangled property, so that every build of your library has the same output. **See the wiki for a [complete guide to property mangling in Microbundle](https://github.com/developit/microbundle/wiki/mangle.json).**
### Defining build-time constants
The `--define` option can be used to inject or replace build-time constants when bundling. In addition to injecting string or number constants, prefixing the define name with `@` allows injecting JavaScript expressions.
| Build command | Source code | Output |
| -------------------------------------------- | ---------------------- | ----------------------- |
| `microbundle --define VERSION=2` | `console.log(VERSION)` | `console.log(2)` |
| `microbundle --define API_KEY='abc123'` | `console.log(API_KEY)` | `console.log("abc123")` |
| `microbundle --define @assign=Object.assign` | `assign(a, b)` | `Object.assign(a, b)` |
### All CLI Options <a name="options"></a>
```
Usage
$ microbundle <command> [options]
Available Commands
build Build once and exit
watch Rebuilds on any change
For more info, run any command with the `--help` flag
$ microbundle build --help
$ microbundle watch --help
Options
-v, --version Displays current version
-i, --entry Entry module(s)
-o, --output Directory to place build files into
-f, --format Only build specified formats (any of modern,esm,cjs,umd or iife) (default modern,esm,cjs,umd)
-w, --watch Rebuilds on any change (default false)
--pkg-main Outputs files analog to package.json main entries (default true)
--target Specify your target environment (node or web) (default web)
--external Specify external dependencies, or 'none' (default peerDependencies and dependencies in package.json)
--globals Specify globals dependencies, or 'none'
--define Replace constants with hard-coded values (use @key=exp to replace an expression)
--alias Map imports to different modules
--compress Compress output using Terser
--strict Enforce undefined global context and add "use strict"
--name Specify name exposed in UMD and IIFE builds
--cwd Use an alternative working directory (default .)
--sourcemap Generate source map (default true)
--raw Show raw byte size (default false)
--jsx A custom JSX pragma like React.createElement (default: h)
--jsxImportSource Declares the module specifier to be used for importing jsx factory functions
--tsconfig Specify the path to a custom tsconfig.json
--generateTypes Whether or not to generate types, if `types` or `typings` is set in `package.json` then it will default to be `true`
--css Where to output CSS: "inline" or "external" (default: "external")
--css-modules Configures .css to be treated as modules (default: null)
--workers Bundle module workers - see https://git.io/J3oSF (default false)
-h, --help Displays this message
Examples
$ microbundle build --globals react=React,jquery=$
$ microbundle build --define API_KEY=1234
$ microbundle build --alias react=preact/compat
$ microbundle watch --no-sourcemap # don't generate sourcemaps
$ microbundle build --tsconfig tsconfig.build.json
```
## 🛣 Roadmap
Here's what's coming up for Microbundle:
- [ ] [Multiple separate inputs->outputs](https://github.com/developit/microbundle/issues/50)
- [x] [TypeScript support](https://github.com/developit/microbundle/issues/5)
- [x] [Flowtype support](https://github.com/developit/microbundle/issues/5#issuecomment-351075881)
## 🔨 Built with Microbundle
- [Preact](https://github.com/preactjs/preact) Fast 3kB React alternative with the same modern API. Components & Virtual DOM.
- [Stockroom](https://github.com/developit/stockroom) Offload your store management to a worker easily.
- [Microenvi](https://github.com/fwilkerson/microenvi) Bundle, serve, and hot reload with one command.
- [Theme UI](https://github.com/system-ui/theme-ui) Build consistent, themeable React apps based on constraint-based design principles.
- [react-recomponent](https://github.com/philipp-spiess/react-recomponent) Reason-style reducer components for React using ES6 classes.
- [brazilian-utils](https://github.com/brazilian-utils/brazilian-utils) Utils library for specific Brazilian businesses.
- [react-hooks-lib](https://github.com/beizhedenglong/react-hooks-lib) A set of reusable react hooks.
- [mdx-deck-live-code](https://github.com/JReinhold/mdx-deck-live-code) A library for [mdx-deck](https://github.com/jxnblk/mdx-deck) to do live React and JS coding directly in slides.
- [react-router-ext](https://github.com/ri7nz/react-router-ext) An Extended [react-router-dom](https://github.com/ReactTraining/react-router/tree/master/packages/react-router-dom) with simple usage.
- [routex.js](https://github.com/alexhoma/routex.js) A dynamic routing library for Next.js.
- [hooked-form](https://github.com/JoviDeCroock/hooked-form) A lightweight form-management library for React.
- [goober](https://github.com/cristianbote/goober) Less than 1KB css-in-js alternative with a familiar API.
- [react-model](https://github.com/byte-fe/react-model) The next generation state management library for React
- [Teaful](https://github.com/teafuljs/teaful) Tiny, easy and powerful (P)React state management
## 🥂 License
[MIT](https://oss.ninja/mit/developit/)
[rollup]: https://github.com/rollup/rollup
[babel]: https://babeljs.io/
[async-to-promises]: https://github.com/rpetrich/babel-plugin-transform-async-to-promises

1218
vendor/spatie/ignition/node_modules/microbundle/dist/cli.js generated vendored Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

4
vendor/spatie/ignition/node_modules/microbundle/index.d.ts generated vendored Executable file
View File

@@ -0,0 +1,4 @@
declare module '*.module.css' {
const classes: { [key: string]: string };
export default classes;
}

View File

@@ -0,0 +1 @@
../autoprefixer/bin/autoprefixer

View File

@@ -0,0 +1 @@
../../../rollup/dist/bin/rollup

View File

@@ -0,0 +1 @@
../../../terser/bin/terser

View File

@@ -0,0 +1 @@
../../../typescript/bin/tsc

View File

@@ -0,0 +1 @@
../../../typescript/bin/tsserver

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright 2013 Andrey Sitnik <andrey@sitnik.ru>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env node
let mode = process.argv[2]
if (mode === '--info') {
process.stdout.write(require('../')().info() + '\n')
} else if (mode === '--version') {
process.stdout.write(
'autoprefixer ' + require('../package.json').version + '\n'
)
} else {
process.stdout.write(
'autoprefix\n' +
'\n' +
'Options:\n' +
' --info Show target browsers and used prefixes\n' +
' --version Show version number\n' +
' --help Show help\n' +
'\n' +
'Usage:\n' +
' autoprefixer --info\n'
)
}

View File

@@ -0,0 +1,974 @@
let unpack = require('caniuse-lite').feature
function browsersSort (a, b) {
a = a.split(' ')
b = b.split(' ')
if (a[0] > b[0]) {
return 1
} else if (a[0] < b[0]) {
return -1
} else {
return Math.sign(parseFloat(a[1]) - parseFloat(b[1]))
}
}
// Convert Can I Use data
function f (data, opts, callback) {
data = unpack(data)
if (!callback) {
;[callback, opts] = [opts, {}]
}
let match = opts.match || /\sx($|\s)/
let need = []
for (let browser in data.stats) {
let versions = data.stats[browser]
for (let version in versions) {
let support = versions[version]
if (support.match(match)) {
need.push(browser + ' ' + version)
}
}
}
callback(need.sort(browsersSort))
}
// Add data for all properties
let result = {}
function prefix (names, data) {
for (let name of names) {
result[name] = Object.assign({}, data)
}
}
function add (names, data) {
for (let name of names) {
result[name].browsers = result[name].browsers
.concat(data.browsers)
.sort(browsersSort)
}
}
module.exports = result
// Border Radius
f(require('caniuse-lite/data/features/border-radius'), browsers =>
prefix(
[
'border-radius',
'border-top-left-radius',
'border-top-right-radius',
'border-bottom-right-radius',
'border-bottom-left-radius'
],
{
mistakes: ['-khtml-', '-ms-', '-o-'],
feature: 'border-radius',
browsers
}
)
)
// Box Shadow
f(require('caniuse-lite/data/features/css-boxshadow'), browsers =>
prefix(['box-shadow'], {
mistakes: ['-khtml-'],
feature: 'css-boxshadow',
browsers
})
)
// Animation
f(require('caniuse-lite/data/features/css-animation'), browsers =>
prefix(
[
'animation',
'animation-name',
'animation-duration',
'animation-delay',
'animation-direction',
'animation-fill-mode',
'animation-iteration-count',
'animation-play-state',
'animation-timing-function',
'@keyframes'
],
{
mistakes: ['-khtml-', '-ms-'],
feature: 'css-animation',
browsers
}
)
)
// Transition
f(require('caniuse-lite/data/features/css-transitions'), browsers =>
prefix(
[
'transition',
'transition-property',
'transition-duration',
'transition-delay',
'transition-timing-function'
],
{
mistakes: ['-khtml-', '-ms-'],
browsers,
feature: 'css-transitions'
}
)
)
// Transform 2D
f(require('caniuse-lite/data/features/transforms2d'), browsers =>
prefix(['transform', 'transform-origin'], {
feature: 'transforms2d',
browsers
})
)
// Transform 3D
let transforms3d = require('caniuse-lite/data/features/transforms3d')
f(transforms3d, browsers => {
prefix(['perspective', 'perspective-origin'], {
feature: 'transforms3d',
browsers
})
return prefix(['transform-style'], {
mistakes: ['-ms-', '-o-'],
browsers,
feature: 'transforms3d'
})
})
f(transforms3d, { match: /y\sx|y\s#2/ }, browsers =>
prefix(['backface-visibility'], {
mistakes: ['-ms-', '-o-'],
feature: 'transforms3d',
browsers
})
)
// Gradients
let gradients = require('caniuse-lite/data/features/css-gradients')
f(gradients, { match: /y\sx/ }, browsers =>
prefix(
[
'linear-gradient',
'repeating-linear-gradient',
'radial-gradient',
'repeating-radial-gradient'
],
{
props: [
'background',
'background-image',
'border-image',
'mask',
'list-style',
'list-style-image',
'content',
'mask-image'
],
mistakes: ['-ms-'],
feature: 'css-gradients',
browsers
}
)
)
f(gradients, { match: /a\sx/ }, browsers => {
browsers = browsers.map(i => {
if (/firefox|op/.test(i)) {
return i
} else {
return `${i} old`
}
})
return add(
[
'linear-gradient',
'repeating-linear-gradient',
'radial-gradient',
'repeating-radial-gradient'
],
{
feature: 'css-gradients',
browsers
}
)
})
// Box sizing
f(require('caniuse-lite/data/features/css3-boxsizing'), browsers =>
prefix(['box-sizing'], {
feature: 'css3-boxsizing',
browsers
})
)
// Filter Effects
f(require('caniuse-lite/data/features/css-filters'), browsers =>
prefix(['filter'], {
feature: 'css-filters',
browsers
})
)
// filter() function
f(require('caniuse-lite/data/features/css-filter-function'), browsers =>
prefix(['filter-function'], {
props: [
'background',
'background-image',
'border-image',
'mask',
'list-style',
'list-style-image',
'content',
'mask-image'
],
feature: 'css-filter-function',
browsers
})
)
// Backdrop-filter
let backdrop = require('caniuse-lite/data/features/css-backdrop-filter')
f(backdrop, { match: /y\sx|y\s#2/ }, browsers =>
prefix(['backdrop-filter'], {
feature: 'css-backdrop-filter',
browsers
})
)
// element() function
f(require('caniuse-lite/data/features/css-element-function'), browsers =>
prefix(['element'], {
props: [
'background',
'background-image',
'border-image',
'mask',
'list-style',
'list-style-image',
'content',
'mask-image'
],
feature: 'css-element-function',
browsers
})
)
// Multicolumns
f(require('caniuse-lite/data/features/multicolumn'), browsers => {
prefix(
[
'columns',
'column-width',
'column-gap',
'column-rule',
'column-rule-color',
'column-rule-width',
'column-count',
'column-rule-style',
'column-span',
'column-fill'
],
{
feature: 'multicolumn',
browsers
}
)
let noff = browsers.filter(i => !/firefox/.test(i))
prefix(['break-before', 'break-after', 'break-inside'], {
feature: 'multicolumn',
browsers: noff
})
})
// User select
f(require('caniuse-lite/data/features/user-select-none'), browsers =>
prefix(['user-select'], {
mistakes: ['-khtml-'],
feature: 'user-select-none',
browsers
})
)
// Flexible Box Layout
let flexbox = require('caniuse-lite/data/features/flexbox')
f(flexbox, { match: /a\sx/ }, browsers => {
browsers = browsers.map(i => {
if (/ie|firefox/.test(i)) {
return i
} else {
return `${i} 2009`
}
})
prefix(['display-flex', 'inline-flex'], {
props: ['display'],
feature: 'flexbox',
browsers
})
prefix(['flex', 'flex-grow', 'flex-shrink', 'flex-basis'], {
feature: 'flexbox',
browsers
})
prefix(
[
'flex-direction',
'flex-wrap',
'flex-flow',
'justify-content',
'order',
'align-items',
'align-self',
'align-content'
],
{
feature: 'flexbox',
browsers
}
)
})
f(flexbox, { match: /y\sx/ }, browsers => {
add(['display-flex', 'inline-flex'], {
feature: 'flexbox',
browsers
})
add(['flex', 'flex-grow', 'flex-shrink', 'flex-basis'], {
feature: 'flexbox',
browsers
})
add(
[
'flex-direction',
'flex-wrap',
'flex-flow',
'justify-content',
'order',
'align-items',
'align-self',
'align-content'
],
{
feature: 'flexbox',
browsers
}
)
})
// calc() unit
f(require('caniuse-lite/data/features/calc'), browsers =>
prefix(['calc'], {
props: ['*'],
feature: 'calc',
browsers
})
)
// Background options
f(require('caniuse-lite/data/features/background-img-opts'), browsers =>
prefix(['background-origin', 'background-size'], {
feature: 'background-img-opts',
browsers
})
)
// background-clip: text
f(require('caniuse-lite/data/features/background-clip-text'), browsers =>
prefix(['background-clip'], {
feature: 'background-clip-text',
browsers
})
)
// Font feature settings
f(require('caniuse-lite/data/features/font-feature'), browsers =>
prefix(
[
'font-feature-settings',
'font-variant-ligatures',
'font-language-override'
],
{
feature: 'font-feature',
browsers
}
)
)
// CSS font-kerning property
f(require('caniuse-lite/data/features/font-kerning'), browsers =>
prefix(['font-kerning'], {
feature: 'font-kerning',
browsers
})
)
// Border image
f(require('caniuse-lite/data/features/border-image'), browsers =>
prefix(['border-image'], {
feature: 'border-image',
browsers
})
)
// Selection selector
f(require('caniuse-lite/data/features/css-selection'), browsers =>
prefix(['::selection'], {
selector: true,
feature: 'css-selection',
browsers
})
)
// Placeholder selector
f(require('caniuse-lite/data/features/css-placeholder'), browsers => {
prefix(['::placeholder'], {
selector: true,
feature: 'css-placeholder',
browsers: browsers.concat(['ie 10 old', 'ie 11 old', 'firefox 18 old'])
})
})
// Placeholder-shown selector
f(require('caniuse-lite/data/features/css-placeholder-shown'), browsers => {
prefix([':placeholder-shown'], {
selector: true,
feature: 'css-placeholder-shown',
browsers
})
})
// Hyphenation
f(require('caniuse-lite/data/features/css-hyphens'), browsers =>
prefix(['hyphens'], {
feature: 'css-hyphens',
browsers
})
)
// Fullscreen selector
let fullscreen = require('caniuse-lite/data/features/fullscreen')
f(fullscreen, browsers =>
prefix([':fullscreen'], {
selector: true,
feature: 'fullscreen',
browsers
})
)
f(fullscreen, { match: /x(\s#2|$)/ }, browsers =>
prefix(['::backdrop'], {
selector: true,
feature: 'fullscreen',
browsers
})
)
// Tab size
f(require('caniuse-lite/data/features/css3-tabsize'), browsers =>
prefix(['tab-size'], {
feature: 'css3-tabsize',
browsers
})
)
// Intrinsic & extrinsic sizing
let intrinsic = require('caniuse-lite/data/features/intrinsic-width')
let sizeProps = [
'width',
'min-width',
'max-width',
'height',
'min-height',
'max-height',
'inline-size',
'min-inline-size',
'max-inline-size',
'block-size',
'min-block-size',
'max-block-size',
'grid',
'grid-template',
'grid-template-rows',
'grid-template-columns',
'grid-auto-columns',
'grid-auto-rows'
]
f(intrinsic, browsers =>
prefix(['max-content', 'min-content'], {
props: sizeProps,
feature: 'intrinsic-width',
browsers
})
)
f(intrinsic, { match: /x|\s#4/ }, browsers =>
prefix(['fill', 'fill-available', 'stretch'], {
props: sizeProps,
feature: 'intrinsic-width',
browsers
})
)
f(intrinsic, { match: /x|\s#5/ }, browsers =>
prefix(['fit-content'], {
props: sizeProps,
feature: 'intrinsic-width',
browsers
})
)
// Zoom cursors
f(require('caniuse-lite/data/features/css3-cursors-newer'), browsers =>
prefix(['zoom-in', 'zoom-out'], {
props: ['cursor'],
feature: 'css3-cursors-newer',
browsers
})
)
// Grab cursors
f(require('caniuse-lite/data/features/css3-cursors-grab'), browsers =>
prefix(['grab', 'grabbing'], {
props: ['cursor'],
feature: 'css3-cursors-grab',
browsers
})
)
// Sticky position
f(require('caniuse-lite/data/features/css-sticky'), browsers =>
prefix(['sticky'], {
props: ['position'],
feature: 'css-sticky',
browsers
})
)
// Pointer Events
f(require('caniuse-lite/data/features/pointer'), browsers =>
prefix(['touch-action'], {
feature: 'pointer',
browsers
})
)
// Text decoration
let decoration = require('caniuse-lite/data/features/text-decoration')
f(decoration, browsers =>
prefix(
[
'text-decoration-style',
'text-decoration-color',
'text-decoration-line',
'text-decoration'
],
{
feature: 'text-decoration',
browsers
}
)
)
f(decoration, { match: /x.*#[235]/ }, browsers =>
prefix(['text-decoration-skip', 'text-decoration-skip-ink'], {
feature: 'text-decoration',
browsers
})
)
// Text Size Adjust
f(require('caniuse-lite/data/features/text-size-adjust'), browsers =>
prefix(['text-size-adjust'], {
feature: 'text-size-adjust',
browsers
})
)
// CSS Masks
f(require('caniuse-lite/data/features/css-masks'), browsers => {
prefix(
[
'mask-clip',
'mask-composite',
'mask-image',
'mask-origin',
'mask-repeat',
'mask-border-repeat',
'mask-border-source'
],
{
feature: 'css-masks',
browsers
}
)
prefix(
[
'mask',
'mask-position',
'mask-size',
'mask-border',
'mask-border-outset',
'mask-border-width',
'mask-border-slice'
],
{
feature: 'css-masks',
browsers
}
)
})
// CSS clip-path property
f(require('caniuse-lite/data/features/css-clip-path'), browsers =>
prefix(['clip-path'], {
feature: 'css-clip-path',
browsers
})
)
// Fragmented Borders and Backgrounds
f(require('caniuse-lite/data/features/css-boxdecorationbreak'), browsers =>
prefix(['box-decoration-break'], {
feature: 'css-boxdecorationbreak',
browsers
})
)
// CSS3 object-fit/object-position
f(require('caniuse-lite/data/features/object-fit'), browsers =>
prefix(['object-fit', 'object-position'], {
feature: 'object-fit',
browsers
})
)
// CSS Shapes
f(require('caniuse-lite/data/features/css-shapes'), browsers =>
prefix(['shape-margin', 'shape-outside', 'shape-image-threshold'], {
feature: 'css-shapes',
browsers
})
)
// CSS3 text-overflow
f(require('caniuse-lite/data/features/text-overflow'), browsers =>
prefix(['text-overflow'], {
feature: 'text-overflow',
browsers
})
)
// Viewport at-rule
f(require('caniuse-lite/data/features/css-deviceadaptation'), browsers =>
prefix(['@viewport'], {
feature: 'css-deviceadaptation',
browsers
})
)
// Resolution Media Queries
let resolut = require('caniuse-lite/data/features/css-media-resolution')
f(resolut, { match: /( x($| )|a #2)/ }, browsers =>
prefix(['@resolution'], {
feature: 'css-media-resolution',
browsers
})
)
// CSS text-align-last
f(require('caniuse-lite/data/features/css-text-align-last'), browsers =>
prefix(['text-align-last'], {
feature: 'css-text-align-last',
browsers
})
)
// Crisp Edges Image Rendering Algorithm
let crispedges = require('caniuse-lite/data/features/css-crisp-edges')
f(crispedges, { match: /y x|a x #1/ }, browsers =>
prefix(['pixelated'], {
props: ['image-rendering'],
feature: 'css-crisp-edges',
browsers
})
)
f(crispedges, { match: /a x #2/ }, browsers =>
prefix(['image-rendering'], {
feature: 'css-crisp-edges',
browsers
})
)
// Logical Properties
let logicalProps = require('caniuse-lite/data/features/css-logical-props')
f(logicalProps, browsers =>
prefix(
[
'border-inline-start',
'border-inline-end',
'margin-inline-start',
'margin-inline-end',
'padding-inline-start',
'padding-inline-end'
],
{
feature: 'css-logical-props',
browsers
}
)
)
f(logicalProps, { match: /x\s#2/ }, browsers =>
prefix(
[
'border-block-start',
'border-block-end',
'margin-block-start',
'margin-block-end',
'padding-block-start',
'padding-block-end'
],
{
feature: 'css-logical-props',
browsers
}
)
)
// CSS appearance
let appearance = require('caniuse-lite/data/features/css-appearance')
f(appearance, { match: /#2|x/ }, browsers =>
prefix(['appearance'], {
feature: 'css-appearance',
browsers
})
)
// CSS Scroll snap points
f(require('caniuse-lite/data/features/css-snappoints'), browsers =>
prefix(
[
'scroll-snap-type',
'scroll-snap-coordinate',
'scroll-snap-destination',
'scroll-snap-points-x',
'scroll-snap-points-y'
],
{
feature: 'css-snappoints',
browsers
}
)
)
// CSS Regions
f(require('caniuse-lite/data/features/css-regions'), browsers =>
prefix(['flow-into', 'flow-from', 'region-fragment'], {
feature: 'css-regions',
browsers
})
)
// CSS image-set
f(require('caniuse-lite/data/features/css-image-set'), browsers =>
prefix(['image-set'], {
props: [
'background',
'background-image',
'border-image',
'cursor',
'mask',
'mask-image',
'list-style',
'list-style-image',
'content'
],
feature: 'css-image-set',
browsers
})
)
// Writing Mode
let writingMode = require('caniuse-lite/data/features/css-writing-mode')
f(writingMode, { match: /a|x/ }, browsers =>
prefix(['writing-mode'], {
feature: 'css-writing-mode',
browsers
})
)
// Cross-Fade Function
f(require('caniuse-lite/data/features/css-cross-fade'), browsers =>
prefix(['cross-fade'], {
props: [
'background',
'background-image',
'border-image',
'mask',
'list-style',
'list-style-image',
'content',
'mask-image'
],
feature: 'css-cross-fade',
browsers
})
)
// Read Only selector
f(require('caniuse-lite/data/features/css-read-only-write'), browsers =>
prefix([':read-only', ':read-write'], {
selector: true,
feature: 'css-read-only-write',
browsers
})
)
// Text Emphasize
f(require('caniuse-lite/data/features/text-emphasis'), browsers =>
prefix(
[
'text-emphasis',
'text-emphasis-position',
'text-emphasis-style',
'text-emphasis-color'
],
{
feature: 'text-emphasis',
browsers
}
)
)
// CSS Grid Layout
let grid = require('caniuse-lite/data/features/css-grid')
f(grid, browsers => {
prefix(['display-grid', 'inline-grid'], {
props: ['display'],
feature: 'css-grid',
browsers
})
prefix(
[
'grid-template-columns',
'grid-template-rows',
'grid-row-start',
'grid-column-start',
'grid-row-end',
'grid-column-end',
'grid-row',
'grid-column',
'grid-area',
'grid-template',
'grid-template-areas',
'place-self'
],
{
feature: 'css-grid',
browsers
}
)
})
f(grid, { match: /a x/ }, browsers =>
prefix(['grid-column-align', 'grid-row-align'], {
feature: 'css-grid',
browsers
})
)
// CSS text-spacing
f(require('caniuse-lite/data/features/css-text-spacing'), browsers =>
prefix(['text-spacing'], {
feature: 'css-text-spacing',
browsers
})
)
// :any-link selector
f(require('caniuse-lite/data/features/css-any-link'), browsers =>
prefix([':any-link'], {
selector: true,
feature: 'css-any-link',
browsers
})
)
// unicode-bidi
let bidi = require('caniuse-lite/data/features/css-unicode-bidi')
f(bidi, browsers =>
prefix(['isolate'], {
props: ['unicode-bidi'],
feature: 'css-unicode-bidi',
browsers
})
)
f(bidi, { match: /y x|a x #2/ }, browsers =>
prefix(['plaintext'], {
props: ['unicode-bidi'],
feature: 'css-unicode-bidi',
browsers
})
)
f(bidi, { match: /y x/ }, browsers =>
prefix(['isolate-override'], {
props: ['unicode-bidi'],
feature: 'css-unicode-bidi',
browsers
})
)
// overscroll-behavior selector
let over = require('caniuse-lite/data/features/css-overscroll-behavior')
f(over, { match: /a #1/ }, browsers =>
prefix(['overscroll-behavior'], {
feature: 'css-overscroll-behavior',
browsers
})
)
// color-adjust
f(require('caniuse-lite/data/features/css-color-adjust'), browsers =>
prefix(['color-adjust'], {
feature: 'css-color-adjust',
browsers
})
)
// text-orientation
f(require('caniuse-lite/data/features/css-text-orientation'), browsers =>
prefix(['text-orientation'], {
feature: 'css-text-orientation',
browsers
})
)

View File

@@ -0,0 +1,35 @@
let Prefixer = require('./prefixer')
class AtRule extends Prefixer {
/**
* Clone and add prefixes for at-rule
*/
add (rule, prefix) {
let prefixed = prefix + rule.name
let already = rule.parent.some(
i => i.name === prefixed && i.params === rule.params
)
if (already) {
return undefined
}
let cloned = this.clone(rule, { name: prefixed })
return rule.parent.insertBefore(rule, cloned)
}
/**
* Clone node with prefixes
*/
process (node) {
let parent = this.parentPrefix(node)
for (let prefix of this.prefixes) {
if (!parent || parent === prefix) {
this.add(node, prefix)
}
}
}
}
module.exports = AtRule

View File

@@ -0,0 +1,95 @@
import { Plugin } from 'postcss'
import { Stats } from 'browserslist'
declare function autoprefixer<T extends string[]> (
...args: [...T, autoprefixer.Options]
): Plugin & autoprefixer.ExportedAPI
declare function autoprefixer (
browsers: string[],
options?: autoprefixer.Options
): Plugin & autoprefixer.ExportedAPI
declare function autoprefixer (
options?: autoprefixer.Options
): Plugin & autoprefixer.ExportedAPI
declare namespace autoprefixer {
type GridValue = 'autoplace' | 'no-autoplace'
interface Options {
/** environment for `Browserslist` */
env?: string
/** should Autoprefixer use Visual Cascade, if CSS is uncompressed */
cascade?: boolean
/** should Autoprefixer add prefixes. */
add?: boolean
/** should Autoprefixer [remove outdated] prefixes */
remove?: boolean
/** should Autoprefixer add prefixes for @supports parameters. */
supports?: boolean
/** should Autoprefixer add prefixes for flexbox properties */
flexbox?: boolean | 'no-2009'
/** should Autoprefixer add IE 10-11 prefixes for Grid Layout properties */
grid?: boolean | GridValue
/** custom usage statistics for > 10% in my stats browsers query */
stats?: Stats
/**
* list of queries for target browsers.
* Try to not use it.
* The best practice is to use `.browserslistrc` config or `browserslist` key in `package.json`
* to share target browsers with Babel, ESLint and Stylelint
*/
overrideBrowserslist?: string | string[]
/** do not raise error on unknown browser version in `Browserslist` config. */
ignoreUnknownVersions?: boolean
}
interface ExportedAPI {
/** Autoprefixer data */
data: {
browsers: { [browser: string]: object | undefined }
prefixes: { [prefixName: string]: object | undefined }
}
/** Autoprefixer default browsers */
defaults: string[]
/** Inspect with default Autoprefixer */
info(options?: { from?: string }): string
options: Options
browsers: string | string[]
}
/** Autoprefixer data */
let data: ExportedAPI['data']
/** Autoprefixer default browsers */
let defaults: ExportedAPI['defaults']
/** Inspect with default Autoprefixer */
let info: ExportedAPI['info']
let postcss: true
}
declare global {
namespace NodeJS {
interface ProcessEnv {
AUTOPREFIXER_GRID?: autoprefixer.GridValue
}
}
}
export = autoprefixer

View File

@@ -0,0 +1,161 @@
let browserslist = require('browserslist')
let { agents } = require('caniuse-lite')
let colorette = require('colorette')
let Browsers = require('./browsers')
let Prefixes = require('./prefixes')
let data = require('../data/prefixes')
let info = require('./info')
const WARNING =
'\n' +
' Replace Autoprefixer `browsers` option to Browserslist config.\n' +
' Use `browserslist` key in `package.json` or `.browserslistrc` file.\n' +
'\n' +
' Using `browsers` option can cause errors. Browserslist config can\n' +
' be used for Babel, Autoprefixer, postcss-normalize and other tools.\n' +
'\n' +
' If you really need to use option, rename it to `overrideBrowserslist`.\n' +
'\n' +
' Learn more at:\n' +
' https://github.com/browserslist/browserslist#readme\n' +
' https://twitter.com/browserslist\n' +
'\n'
function isPlainObject (obj) {
return Object.prototype.toString.apply(obj) === '[object Object]'
}
let cache = new Map()
function timeCapsule (result, prefixes) {
if (prefixes.browsers.selected.length === 0) {
return
}
if (prefixes.add.selectors.length > 0) {
return
}
if (Object.keys(prefixes.add).length > 2) {
return
}
/* istanbul ignore next */
result.warn(
'Greetings, time traveller. ' +
'We are in the golden age of prefix-less CSS, ' +
'where Autoprefixer is no longer needed for your stylesheet.'
)
}
module.exports = (...reqs) => {
let options
if (reqs.length === 1 && isPlainObject(reqs[0])) {
options = reqs[0]
reqs = undefined
} else if (reqs.length === 0 || (reqs.length === 1 && !reqs[0])) {
reqs = undefined
} else if (reqs.length <= 2 && (Array.isArray(reqs[0]) || !reqs[0])) {
options = reqs[1]
reqs = reqs[0]
} else if (typeof reqs[reqs.length - 1] === 'object') {
options = reqs.pop()
}
if (!options) {
options = {}
}
if (options.browser) {
throw new Error(
'Change `browser` option to `overrideBrowserslist` in Autoprefixer'
)
} else if (options.browserslist) {
throw new Error(
'Change `browserslist` option to `overrideBrowserslist` in Autoprefixer'
)
}
if (options.overrideBrowserslist) {
reqs = options.overrideBrowserslist
} else if (options.browsers) {
if (typeof console !== 'undefined' && console.warn) {
if (colorette.red) {
console.warn(
colorette.red(
WARNING.replace(/`[^`]+`/g, i => colorette.yellow(i.slice(1, -1)))
)
)
} else {
console.warn(WARNING)
}
}
reqs = options.browsers
}
let brwlstOpts = {
ignoreUnknownVersions: options.ignoreUnknownVersions,
stats: options.stats,
env: options.env
}
function loadPrefixes (opts) {
let d = module.exports.data
let browsers = new Browsers(d.browsers, reqs, opts, brwlstOpts)
let key = browsers.selected.join(', ') + JSON.stringify(options)
if (!cache.has(key)) {
cache.set(key, new Prefixes(d.prefixes, browsers, options))
}
return cache.get(key)
}
return {
postcssPlugin: 'autoprefixer',
prepare (result) {
let prefixes = loadPrefixes({
from: result.opts.from,
env: options.env
})
return {
OnceExit (root) {
timeCapsule(result, prefixes)
if (options.remove !== false) {
prefixes.processor.remove(root, result)
}
if (options.add !== false) {
prefixes.processor.add(root, result)
}
}
}
},
info (opts) {
opts = opts || {}
opts.from = opts.from || process.cwd()
return info(loadPrefixes(opts))
},
options,
browsers: reqs
}
}
module.exports.postcss = true
/**
* Autoprefixer data
*/
module.exports.data = { browsers: agents, prefixes: data }
/**
* Autoprefixer default browsers
*/
module.exports.defaults = browserslist.defaults
/**
* Inspect with default Autoprefixer
*/
module.exports.info = () => module.exports().info()

View File

@@ -0,0 +1,51 @@
function last (array) {
return array[array.length - 1]
}
let brackets = {
/**
* Parse string to nodes tree
*/
parse (str) {
let current = ['']
let stack = [current]
for (let sym of str) {
if (sym === '(') {
current = ['']
last(stack).push(current)
stack.push(current)
continue
}
if (sym === ')') {
stack.pop()
current = last(stack)
current.push('')
continue
}
current[current.length - 1] += sym
}
return stack[0]
},
/**
* Generate output string by nodes tree
*/
stringify (ast) {
let result = ''
for (let i of ast) {
if (typeof i === 'object') {
result += `(${brackets.stringify(i)})`
continue
}
result += i
}
return result
}
}
module.exports = brackets

View File

@@ -0,0 +1,79 @@
let browserslist = require('browserslist')
let agents = require('caniuse-lite').agents
let utils = require('./utils')
class Browsers {
/**
* Return all prefixes for default browser data
*/
static prefixes () {
if (this.prefixesCache) {
return this.prefixesCache
}
this.prefixesCache = []
for (let name in agents) {
this.prefixesCache.push(`-${agents[name].prefix}-`)
}
this.prefixesCache = utils
.uniq(this.prefixesCache)
.sort((a, b) => b.length - a.length)
return this.prefixesCache
}
/**
* Check is value contain any possible prefix
*/
static withPrefix (value) {
if (!this.prefixesRegexp) {
this.prefixesRegexp = new RegExp(this.prefixes().join('|'))
}
return this.prefixesRegexp.test(value)
}
constructor (data, requirements, options, browserslistOpts) {
this.data = data
this.options = options || {}
this.browserslistOpts = browserslistOpts || {}
this.selected = this.parse(requirements)
}
/**
* Return browsers selected by requirements
*/
parse (requirements) {
let opts = {}
for (let i in this.browserslistOpts) {
opts[i] = this.browserslistOpts[i]
}
opts.path = this.options.from
return browserslist(requirements, opts)
}
/**
* Return prefix for selected browser
*/
prefix (browser) {
let [name, version] = browser.split(' ')
let data = this.data[name]
let prefix = data.prefix_exceptions && data.prefix_exceptions[version]
if (!prefix) {
prefix = data.prefix
}
return `-${prefix}-`
}
/**
* Is browser is selected by requirements
*/
isSelected (browser) {
return this.selected.includes(browser)
}
}
module.exports = Browsers

View File

@@ -0,0 +1,187 @@
let Prefixer = require('./prefixer')
let Browsers = require('./browsers')
let utils = require('./utils')
class Declaration extends Prefixer {
/**
* Always true, because we already get prefixer by property name
*/
check (/* decl */) {
return true
}
/**
* Return prefixed version of property
*/
prefixed (prop, prefix) {
return prefix + prop
}
/**
* Return unprefixed version of property
*/
normalize (prop) {
return prop
}
/**
* Check `value`, that it contain other prefixes, rather than `prefix`
*/
otherPrefixes (value, prefix) {
for (let other of Browsers.prefixes()) {
if (other === prefix) {
continue
}
if (value.includes(other)) {
return true
}
}
return false
}
/**
* Set prefix to declaration
*/
set (decl, prefix) {
decl.prop = this.prefixed(decl.prop, prefix)
return decl
}
/**
* Should we use visual cascade for prefixes
*/
needCascade (decl) {
if (!decl._autoprefixerCascade) {
decl._autoprefixerCascade =
this.all.options.cascade !== false && decl.raw('before').includes('\n')
}
return decl._autoprefixerCascade
}
/**
* Return maximum length of possible prefixed property
*/
maxPrefixed (prefixes, decl) {
if (decl._autoprefixerMax) {
return decl._autoprefixerMax
}
let max = 0
for (let prefix of prefixes) {
prefix = utils.removeNote(prefix)
if (prefix.length > max) {
max = prefix.length
}
}
decl._autoprefixerMax = max
return decl._autoprefixerMax
}
/**
* Calculate indentation to create visual cascade
*/
calcBefore (prefixes, decl, prefix = '') {
let max = this.maxPrefixed(prefixes, decl)
let diff = max - utils.removeNote(prefix).length
let before = decl.raw('before')
if (diff > 0) {
before += Array(diff).fill(' ').join('')
}
return before
}
/**
* Remove visual cascade
*/
restoreBefore (decl) {
let lines = decl.raw('before').split('\n')
let min = lines[lines.length - 1]
this.all.group(decl).up(prefixed => {
let array = prefixed.raw('before').split('\n')
let last = array[array.length - 1]
if (last.length < min.length) {
min = last
}
})
lines[lines.length - 1] = min
decl.raws.before = lines.join('\n')
}
/**
* Clone and insert new declaration
*/
insert (decl, prefix, prefixes) {
let cloned = this.set(this.clone(decl), prefix)
if (!cloned) return undefined
let already = decl.parent.some(
i => i.prop === cloned.prop && i.value === cloned.value
)
if (already) {
return undefined
}
if (this.needCascade(decl)) {
cloned.raws.before = this.calcBefore(prefixes, decl, prefix)
}
return decl.parent.insertBefore(decl, cloned)
}
/**
* Did this declaration has this prefix above
*/
isAlready (decl, prefixed) {
let already = this.all.group(decl).up(i => i.prop === prefixed)
if (!already) {
already = this.all.group(decl).down(i => i.prop === prefixed)
}
return already
}
/**
* Clone and add prefixes for declaration
*/
add (decl, prefix, prefixes, result) {
let prefixed = this.prefixed(decl.prop, prefix)
if (
this.isAlready(decl, prefixed) ||
this.otherPrefixes(decl.value, prefix)
) {
return undefined
}
return this.insert(decl, prefix, prefixes, result)
}
/**
* Add spaces for visual cascade
*/
process (decl, result) {
if (!this.needCascade(decl)) {
super.process(decl, result)
return
}
let prefixes = super.process(decl, result)
if (!prefixes || !prefixes.length) {
return
}
this.restoreBefore(decl)
decl.raws.before = this.calcBefore(prefixes, decl)
}
/**
* Return list of prefixed properties to clean old prefixes
*/
old (prop, prefix) {
return [this.prefixed(prop, prefix)]
}
}
module.exports = Declaration

View File

@@ -0,0 +1,49 @@
let flexSpec = require('./flex-spec')
let Declaration = require('../declaration')
class AlignContent extends Declaration {
/**
* Change property name for 2012 spec
*/
prefixed (prop, prefix) {
let spec
;[spec, prefix] = flexSpec(prefix)
if (spec === 2012) {
return prefix + 'flex-line-pack'
}
return super.prefixed(prop, prefix)
}
/**
* Return property name by final spec
*/
normalize () {
return 'align-content'
}
/**
* Change value for 2012 spec and ignore prefix for 2009
*/
set (decl, prefix) {
let spec = flexSpec(prefix)[0]
if (spec === 2012) {
decl.value = AlignContent.oldValues[decl.value] || decl.value
return super.set(decl, prefix)
}
if (spec === 'final') {
return super.set(decl, prefix)
}
return undefined
}
}
AlignContent.names = ['align-content', 'flex-line-pack']
AlignContent.oldValues = {
'flex-end': 'end',
'flex-start': 'start',
'space-between': 'justify',
'space-around': 'distribute'
}
module.exports = AlignContent

View File

@@ -0,0 +1,46 @@
let flexSpec = require('./flex-spec')
let Declaration = require('../declaration')
class AlignItems extends Declaration {
/**
* Change property name for 2009 and 2012 specs
*/
prefixed (prop, prefix) {
let spec
;[spec, prefix] = flexSpec(prefix)
if (spec === 2009) {
return prefix + 'box-align'
}
if (spec === 2012) {
return prefix + 'flex-align'
}
return super.prefixed(prop, prefix)
}
/**
* Return property name by final spec
*/
normalize () {
return 'align-items'
}
/**
* Change value for 2009 and 2012 specs
*/
set (decl, prefix) {
let spec = flexSpec(prefix)[0]
if (spec === 2009 || spec === 2012) {
decl.value = AlignItems.oldValues[decl.value] || decl.value
}
return super.set(decl, prefix)
}
}
AlignItems.names = ['align-items', 'flex-align', 'box-align']
AlignItems.oldValues = {
'flex-end': 'end',
'flex-start': 'start'
}
module.exports = AlignItems

View File

@@ -0,0 +1,56 @@
let flexSpec = require('./flex-spec')
let Declaration = require('../declaration')
class AlignSelf extends Declaration {
check (decl) {
return (
decl.parent &&
!decl.parent.some(i => {
return i.prop && i.prop.startsWith('grid-')
})
)
}
/**
* Change property name for 2012 specs
*/
prefixed (prop, prefix) {
let spec
;[spec, prefix] = flexSpec(prefix)
if (spec === 2012) {
return prefix + 'flex-item-align'
}
return super.prefixed(prop, prefix)
}
/**
* Return property name by final spec
*/
normalize () {
return 'align-self'
}
/**
* Change value for 2012 spec and ignore prefix for 2009
*/
set (decl, prefix) {
let spec = flexSpec(prefix)[0]
if (spec === 2012) {
decl.value = AlignSelf.oldValues[decl.value] || decl.value
return super.set(decl, prefix)
}
if (spec === 'final') {
return super.set(decl, prefix)
}
return undefined
}
}
AlignSelf.names = ['align-self', 'flex-item-align']
AlignSelf.oldValues = {
'flex-end': 'end',
'flex-start': 'start'
}
module.exports = AlignSelf

View File

@@ -0,0 +1,17 @@
let Declaration = require('../declaration')
class Animation extends Declaration {
/**
* Dont add prefixes for modern values.
*/
check (decl) {
return !decl.value.split(/\s+/).some(i => {
let lower = i.toLowerCase()
return lower === 'reverse' || lower === 'alternate-reverse'
})
}
}
Animation.names = ['animation', 'animation-direction']
module.exports = Animation

View File

@@ -0,0 +1,23 @@
let Declaration = require('../declaration')
let utils = require('../utils')
class Appearance extends Declaration {
constructor (name, prefixes, all) {
super(name, prefixes, all)
if (this.prefixes) {
this.prefixes = utils.uniq(
this.prefixes.map(i => {
if (i === '-ms-') {
return '-webkit-'
}
return i
})
)
}
}
}
Appearance.names = ['appearance']
module.exports = Appearance

View File

@@ -0,0 +1,20 @@
let Declaration = require('../declaration')
let utils = require('../utils')
class BackdropFilter extends Declaration {
constructor (name, prefixes, all) {
super(name, prefixes, all)
if (this.prefixes) {
this.prefixes = utils.uniq(
this.prefixes.map(i => {
return i === '-ms-' ? '-webkit-' : i
})
)
}
}
}
BackdropFilter.names = ['backdrop-filter']
module.exports = BackdropFilter

View File

@@ -0,0 +1,24 @@
let Declaration = require('../declaration')
let utils = require('../utils')
class BackgroundClip extends Declaration {
constructor (name, prefixes, all) {
super(name, prefixes, all)
if (this.prefixes) {
this.prefixes = utils.uniq(
this.prefixes.map(i => {
return i === '-ms-' ? '-webkit-' : i
})
)
}
}
check (decl) {
return decl.value.toLowerCase() === 'text'
}
}
BackgroundClip.names = ['background-clip']
module.exports = BackgroundClip

View File

@@ -0,0 +1,23 @@
let Declaration = require('../declaration')
class BackgroundSize extends Declaration {
/**
* Duplication parameter for -webkit- browsers
*/
set (decl, prefix) {
let value = decl.value.toLowerCase()
if (
prefix === '-webkit-' &&
!value.includes(' ') &&
value !== 'contain' &&
value !== 'cover'
) {
decl.value = decl.value + ' ' + decl.value
}
return super.set(decl, prefix)
}
}
BackgroundSize.names = ['background-size']
module.exports = BackgroundSize

View File

@@ -0,0 +1,40 @@
let Declaration = require('../declaration')
class BlockLogical extends Declaration {
/**
* Use old syntax for -moz- and -webkit-
*/
prefixed (prop, prefix) {
if (prop.includes('-start')) {
return prefix + prop.replace('-block-start', '-before')
}
return prefix + prop.replace('-block-end', '-after')
}
/**
* Return property name by spec
*/
normalize (prop) {
if (prop.includes('-before')) {
return prop.replace('-before', '-block-start')
}
return prop.replace('-after', '-block-end')
}
}
BlockLogical.names = [
'border-block-start',
'border-block-end',
'margin-block-start',
'margin-block-end',
'padding-block-start',
'padding-block-end',
'border-before',
'border-after',
'margin-before',
'margin-after',
'padding-before',
'padding-after'
]
module.exports = BlockLogical

View File

@@ -0,0 +1,15 @@
let Declaration = require('../declaration')
class BorderImage extends Declaration {
/**
* Remove fill parameter for prefixed declarations
*/
set (decl, prefix) {
decl.value = decl.value.replace(/\s+fill(\s)/, '$1')
return super.set(decl, prefix)
}
}
BorderImage.names = ['border-image']
module.exports = BorderImage

View File

@@ -0,0 +1,40 @@
let Declaration = require('../declaration')
class BorderRadius extends Declaration {
/**
* Change syntax, when add Mozilla prefix
*/
prefixed (prop, prefix) {
if (prefix === '-moz-') {
return prefix + (BorderRadius.toMozilla[prop] || prop)
}
return super.prefixed(prop, prefix)
}
/**
* Return unprefixed version of property
*/
normalize (prop) {
return BorderRadius.toNormal[prop] || prop
}
}
BorderRadius.names = ['border-radius']
BorderRadius.toMozilla = {}
BorderRadius.toNormal = {}
for (let ver of ['top', 'bottom']) {
for (let hor of ['left', 'right']) {
let normal = `border-${ver}-${hor}-radius`
let mozilla = `border-radius-${ver}${hor}`
BorderRadius.names.push(normal)
BorderRadius.names.push(mozilla)
BorderRadius.toMozilla[normal] = mozilla
BorderRadius.toNormal[mozilla] = normal
}
}
module.exports = BorderRadius

View File

@@ -0,0 +1,63 @@
let Declaration = require('../declaration')
class BreakProps extends Declaration {
/**
* Change name for -webkit- and -moz- prefix
*/
prefixed (prop, prefix) {
return `${prefix}column-${prop}`
}
/**
* Return property name by final spec
*/
normalize (prop) {
if (prop.includes('inside')) {
return 'break-inside'
}
if (prop.includes('before')) {
return 'break-before'
}
return 'break-after'
}
/**
* Change prefixed value for avoid-column and avoid-page
*/
set (decl, prefix) {
if (
(decl.prop === 'break-inside' && decl.value === 'avoid-column') ||
decl.value === 'avoid-page'
) {
decl.value = 'avoid'
}
return super.set(decl, prefix)
}
/**
* Dont prefix some values
*/
insert (decl, prefix, prefixes) {
if (decl.prop !== 'break-inside') {
return super.insert(decl, prefix, prefixes)
}
if (/region/i.test(decl.value) || /page/i.test(decl.value)) {
return undefined
}
return super.insert(decl, prefix, prefixes)
}
}
BreakProps.names = [
'break-inside',
'page-break-inside',
'column-break-inside',
'break-before',
'page-break-before',
'column-break-before',
'break-after',
'page-break-after',
'column-break-after'
]
module.exports = BreakProps

View File

@@ -0,0 +1,21 @@
let Declaration = require('../declaration')
class ColorAdjust extends Declaration {
/**
* Change property name for WebKit-based browsers
*/
prefixed (prop, prefix) {
return prefix + 'print-color-adjust'
}
/**
* Return property name by spec
*/
normalize () {
return 'color-adjust'
}
}
ColorAdjust.names = ['color-adjust', 'print-color-adjust']
module.exports = ColorAdjust

View File

@@ -0,0 +1,35 @@
let list = require('postcss').list
let Value = require('../value')
class CrossFade extends Value {
replace (string, prefix) {
return list
.space(string)
.map(value => {
if (value.slice(0, +this.name.length + 1) !== this.name + '(') {
return value
}
let close = value.lastIndexOf(')')
let after = value.slice(close + 1)
let args = value.slice(this.name.length + 1, close)
if (prefix === '-webkit-') {
let match = args.match(/\d*.?\d+%?/)
if (match) {
args = args.slice(match[0].length).trim()
args += `, ${match[0]}`
} else {
args += ', 0.5'
}
}
return prefix + this.name + '(' + args + ')' + after
})
.join(' ')
}
}
CrossFade.names = ['cross-fade']
module.exports = CrossFade

View File

@@ -0,0 +1,65 @@
let flexSpec = require('./flex-spec')
let OldValue = require('../old-value')
let Value = require('../value')
class DisplayFlex extends Value {
constructor (name, prefixes) {
super(name, prefixes)
if (name === 'display-flex') {
this.name = 'flex'
}
}
/**
* Faster check for flex value
*/
check (decl) {
return decl.prop === 'display' && decl.value === this.name
}
/**
* Return value by spec
*/
prefixed (prefix) {
let spec, value
;[spec, prefix] = flexSpec(prefix)
if (spec === 2009) {
if (this.name === 'flex') {
value = 'box'
} else {
value = 'inline-box'
}
} else if (spec === 2012) {
if (this.name === 'flex') {
value = 'flexbox'
} else {
value = 'inline-flexbox'
}
} else if (spec === 'final') {
value = this.name
}
return prefix + value
}
/**
* Add prefix to value depend on flebox spec version
*/
replace (string, prefix) {
return this.prefixed(prefix)
}
/**
* Change value for old specs
*/
old (prefix) {
let prefixed = this.prefixed(prefix)
if (!prefixed) return undefined
return new OldValue(this.name, prefixed)
}
}
DisplayFlex.names = ['display-flex', 'inline-flex']
module.exports = DisplayFlex

View File

@@ -0,0 +1,21 @@
let Value = require('../value')
class DisplayGrid extends Value {
constructor (name, prefixes) {
super(name, prefixes)
if (name === 'display-grid') {
this.name = 'grid'
}
}
/**
* Faster check for flex value
*/
check (decl) {
return decl.prop === 'display' && decl.value === this.name
}
}
DisplayGrid.names = ['display-grid', 'inline-grid']
module.exports = DisplayGrid

View File

@@ -0,0 +1,14 @@
let Value = require('../value')
class FilterValue extends Value {
constructor (name, prefixes) {
super(name, prefixes)
if (name === 'filter-function') {
this.name = 'filter'
}
}
}
FilterValue.names = ['filter', 'filter-function']
module.exports = FilterValue

View File

@@ -0,0 +1,19 @@
let Declaration = require('../declaration')
class Filter extends Declaration {
/**
* Check is it Internet Explorer filter
*/
check (decl) {
let v = decl.value
return (
!v.toLowerCase().includes('alpha(') &&
!v.includes('DXImageTransform.Microsoft') &&
!v.includes('data:image/svg+xml')
)
}
}
Filter.names = ['filter']
module.exports = Filter

View File

@@ -0,0 +1,39 @@
let flexSpec = require('./flex-spec')
let Declaration = require('../declaration')
class FlexBasis extends Declaration {
/**
* Return property name by final spec
*/
normalize () {
return 'flex-basis'
}
/**
* Return flex property for 2012 spec
*/
prefixed (prop, prefix) {
let spec
;[spec, prefix] = flexSpec(prefix)
if (spec === 2012) {
return prefix + 'flex-preferred-size'
}
return super.prefixed(prop, prefix)
}
/**
* Ignore 2009 spec and use flex property for 2012
*/
set (decl, prefix) {
let spec
;[spec, prefix] = flexSpec(prefix)
if (spec === 2012 || spec === 'final') {
return super.set(decl, prefix)
}
return undefined
}
}
FlexBasis.names = ['flex-basis', 'flex-preferred-size']
module.exports = FlexBasis

View File

@@ -0,0 +1,72 @@
let flexSpec = require('./flex-spec')
let Declaration = require('../declaration')
class FlexDirection extends Declaration {
/**
* Return property name by final spec
*/
normalize () {
return 'flex-direction'
}
/**
* Use two properties for 2009 spec
*/
insert (decl, prefix, prefixes) {
let spec
;[spec, prefix] = flexSpec(prefix)
if (spec !== 2009) {
return super.insert(decl, prefix, prefixes)
}
let already = decl.parent.some(
i =>
i.prop === prefix + 'box-orient' || i.prop === prefix + 'box-direction'
)
if (already) {
return undefined
}
let v = decl.value
let orient, dir
if (v === 'inherit' || v === 'initial' || v === 'unset') {
orient = v
dir = v
} else {
orient = v.includes('row') ? 'horizontal' : 'vertical'
dir = v.includes('reverse') ? 'reverse' : 'normal'
}
let cloned = this.clone(decl)
cloned.prop = prefix + 'box-orient'
cloned.value = orient
if (this.needCascade(decl)) {
cloned.raws.before = this.calcBefore(prefixes, decl, prefix)
}
decl.parent.insertBefore(decl, cloned)
cloned = this.clone(decl)
cloned.prop = prefix + 'box-direction'
cloned.value = dir
if (this.needCascade(decl)) {
cloned.raws.before = this.calcBefore(prefixes, decl, prefix)
}
return decl.parent.insertBefore(decl, cloned)
}
/**
* Clean two properties for 2009 spec
*/
old (prop, prefix) {
let spec
;[spec, prefix] = flexSpec(prefix)
if (spec === 2009) {
return [prefix + 'box-orient', prefix + 'box-direction']
} else {
return super.old(prop, prefix)
}
}
}
FlexDirection.names = ['flex-direction', 'box-direction', 'box-orient']
module.exports = FlexDirection

View File

@@ -0,0 +1,53 @@
let flexSpec = require('./flex-spec')
let Declaration = require('../declaration')
class FlexFlow extends Declaration {
/**
* Use two properties for 2009 spec
*/
insert (decl, prefix, prefixes) {
let spec
;[spec, prefix] = flexSpec(prefix)
if (spec !== 2009) {
return super.insert(decl, prefix, prefixes)
}
let values = decl.value
.split(/\s+/)
.filter(i => i !== 'wrap' && i !== 'nowrap' && 'wrap-reverse')
if (values.length === 0) {
return undefined
}
let already = decl.parent.some(
i =>
i.prop === prefix + 'box-orient' || i.prop === prefix + 'box-direction'
)
if (already) {
return undefined
}
let value = values[0]
let orient = value.includes('row') ? 'horizontal' : 'vertical'
let dir = value.includes('reverse') ? 'reverse' : 'normal'
let cloned = this.clone(decl)
cloned.prop = prefix + 'box-orient'
cloned.value = orient
if (this.needCascade(decl)) {
cloned.raws.before = this.calcBefore(prefixes, decl, prefix)
}
decl.parent.insertBefore(decl, cloned)
cloned = this.clone(decl)
cloned.prop = prefix + 'box-direction'
cloned.value = dir
if (this.needCascade(decl)) {
cloned.raws.before = this.calcBefore(prefixes, decl, prefix)
}
return decl.parent.insertBefore(decl, cloned)
}
}
FlexFlow.names = ['flex-flow', 'box-direction', 'box-orient']
module.exports = FlexFlow

View File

@@ -0,0 +1,30 @@
let flexSpec = require('./flex-spec')
let Declaration = require('../declaration')
class Flex extends Declaration {
/**
* Return property name by final spec
*/
normalize () {
return 'flex'
}
/**
* Return flex property for 2009 and 2012 specs
*/
prefixed (prop, prefix) {
let spec
;[spec, prefix] = flexSpec(prefix)
if (spec === 2009) {
return prefix + 'box-flex'
}
if (spec === 2012) {
return prefix + 'flex-positive'
}
return super.prefixed(prop, prefix)
}
}
Flex.names = ['flex-grow', 'flex-positive']
module.exports = Flex

View File

@@ -0,0 +1,39 @@
let flexSpec = require('./flex-spec')
let Declaration = require('../declaration')
class FlexShrink extends Declaration {
/**
* Return property name by final spec
*/
normalize () {
return 'flex-shrink'
}
/**
* Return flex property for 2012 spec
*/
prefixed (prop, prefix) {
let spec
;[spec, prefix] = flexSpec(prefix)
if (spec === 2012) {
return prefix + 'flex-negative'
}
return super.prefixed(prop, prefix)
}
/**
* Ignore 2009 spec and use flex property for 2012
*/
set (decl, prefix) {
let spec
;[spec, prefix] = flexSpec(prefix)
if (spec === 2012 || spec === 'final') {
return super.set(decl, prefix)
}
return undefined
}
}
FlexShrink.names = ['flex-shrink', 'flex-negative']
module.exports = FlexShrink

View File

@@ -0,0 +1,19 @@
/**
* Return flexbox spec versions by prefix
*/
module.exports = function (prefix) {
let spec
if (prefix === '-webkit- 2009' || prefix === '-moz-') {
spec = 2009
} else if (prefix === '-ms-') {
spec = 2012
} else if (prefix === '-webkit-') {
spec = 'final'
}
if (prefix === '-webkit- 2009') {
prefix = '-webkit-'
}
return [spec, prefix]
}

View File

@@ -0,0 +1,19 @@
let flexSpec = require('./flex-spec')
let Declaration = require('../declaration')
class FlexWrap extends Declaration {
/**
* Don't add prefix for 2009 spec
*/
set (decl, prefix) {
let spec = flexSpec(prefix)[0]
if (spec !== 2009) {
return super.set(decl, prefix)
}
return undefined
}
}
FlexWrap.names = ['flex-wrap']
module.exports = FlexWrap

View File

@@ -0,0 +1,54 @@
let list = require('postcss').list
let flexSpec = require('./flex-spec')
let Declaration = require('../declaration')
class Flex extends Declaration {
/**
* Change property name for 2009 spec
*/
prefixed (prop, prefix) {
let spec
;[spec, prefix] = flexSpec(prefix)
if (spec === 2009) {
return prefix + 'box-flex'
}
return super.prefixed(prop, prefix)
}
/**
* Return property name by final spec
*/
normalize () {
return 'flex'
}
/**
* Spec 2009 supports only first argument
* Spec 2012 disallows unitless basis
*/
set (decl, prefix) {
let spec = flexSpec(prefix)[0]
if (spec === 2009) {
decl.value = list.space(decl.value)[0]
decl.value = Flex.oldValues[decl.value] || decl.value
return super.set(decl, prefix)
}
if (spec === 2012) {
let components = list.space(decl.value)
if (components.length === 3 && components[2] === '0') {
decl.value = components.slice(0, 2).concat('0px').join(' ')
}
}
return super.set(decl, prefix)
}
}
Flex.names = ['flex', 'box-flex']
Flex.oldValues = {
auto: '1',
none: '0'
}
module.exports = Flex

View File

@@ -0,0 +1,20 @@
let Selector = require('../selector')
class Fullscreen extends Selector {
/**
* Return different selectors depend on prefix
*/
prefixed (prefix) {
if (prefix === '-webkit-') {
return ':-webkit-full-screen'
}
if (prefix === '-moz-') {
return ':-moz-full-screen'
}
return `:${prefix}fullscreen`
}
}
Fullscreen.names = [':fullscreen']
module.exports = Fullscreen

View File

@@ -0,0 +1,429 @@
let parser = require('postcss-value-parser')
let range = require('normalize-range')
let OldValue = require('../old-value')
let Value = require('../value')
let utils = require('../utils')
let IS_DIRECTION = /top|left|right|bottom/gi
class Gradient extends Value {
/**
* Change degrees for webkit prefix
*/
replace (string, prefix) {
let ast = parser(string)
for (let node of ast.nodes) {
if (node.type === 'function' && node.value === this.name) {
node.nodes = this.newDirection(node.nodes)
node.nodes = this.normalize(node.nodes)
if (prefix === '-webkit- old') {
let changes = this.oldWebkit(node)
if (!changes) {
return false
}
} else {
node.nodes = this.convertDirection(node.nodes)
node.value = prefix + node.value
}
}
}
return ast.toString()
}
/**
* Replace first token
*/
replaceFirst (params, ...words) {
let prefix = words.map(i => {
if (i === ' ') {
return { type: 'space', value: i }
}
return { type: 'word', value: i }
})
return prefix.concat(params.slice(1))
}
/**
* Convert angle unit to deg
*/
normalizeUnit (str, full) {
let num = parseFloat(str)
let deg = (num / full) * 360
return `${deg}deg`
}
/**
* Normalize angle
*/
normalize (nodes) {
if (!nodes[0]) return nodes
if (/-?\d+(.\d+)?grad/.test(nodes[0].value)) {
nodes[0].value = this.normalizeUnit(nodes[0].value, 400)
} else if (/-?\d+(.\d+)?rad/.test(nodes[0].value)) {
nodes[0].value = this.normalizeUnit(nodes[0].value, 2 * Math.PI)
} else if (/-?\d+(.\d+)?turn/.test(nodes[0].value)) {
nodes[0].value = this.normalizeUnit(nodes[0].value, 1)
} else if (nodes[0].value.includes('deg')) {
let num = parseFloat(nodes[0].value)
num = range.wrap(0, 360, num)
nodes[0].value = `${num}deg`
}
if (nodes[0].value === '0deg') {
nodes = this.replaceFirst(nodes, 'to', ' ', 'top')
} else if (nodes[0].value === '90deg') {
nodes = this.replaceFirst(nodes, 'to', ' ', 'right')
} else if (nodes[0].value === '180deg') {
nodes = this.replaceFirst(nodes, 'to', ' ', 'bottom')
} else if (nodes[0].value === '270deg') {
nodes = this.replaceFirst(nodes, 'to', ' ', 'left')
}
return nodes
}
/**
* Replace old direction to new
*/
newDirection (params) {
if (params[0].value === 'to') {
return params
}
IS_DIRECTION.lastIndex = 0 // reset search index of global regexp
if (!IS_DIRECTION.test(params[0].value)) {
return params
}
params.unshift(
{
type: 'word',
value: 'to'
},
{
type: 'space',
value: ' '
}
)
for (let i = 2; i < params.length; i++) {
if (params[i].type === 'div') {
break
}
if (params[i].type === 'word') {
params[i].value = this.revertDirection(params[i].value)
}
}
return params
}
/**
* Look for at word
*/
isRadial (params) {
let state = 'before'
for (let param of params) {
if (state === 'before' && param.type === 'space') {
state = 'at'
} else if (state === 'at' && param.value === 'at') {
state = 'after'
} else if (state === 'after' && param.type === 'space') {
return true
} else if (param.type === 'div') {
break
} else {
state = 'before'
}
}
return false
}
/**
* Change new direction to old
*/
convertDirection (params) {
if (params.length > 0) {
if (params[0].value === 'to') {
this.fixDirection(params)
} else if (params[0].value.includes('deg')) {
this.fixAngle(params)
} else if (this.isRadial(params)) {
this.fixRadial(params)
}
}
return params
}
/**
* Replace `to top left` to `bottom right`
*/
fixDirection (params) {
params.splice(0, 2)
for (let param of params) {
if (param.type === 'div') {
break
}
if (param.type === 'word') {
param.value = this.revertDirection(param.value)
}
}
}
/**
* Add 90 degrees
*/
fixAngle (params) {
let first = params[0].value
first = parseFloat(first)
first = Math.abs(450 - first) % 360
first = this.roundFloat(first, 3)
params[0].value = `${first}deg`
}
/**
* Fix radial direction syntax
*/
fixRadial (params) {
let first = []
let second = []
let a, b, c, i, next
for (i = 0; i < params.length - 2; i++) {
a = params[i]
b = params[i + 1]
c = params[i + 2]
if (a.type === 'space' && b.value === 'at' && c.type === 'space') {
next = i + 3
break
} else {
first.push(a)
}
}
let div
for (i = next; i < params.length; i++) {
if (params[i].type === 'div') {
div = params[i]
break
} else {
second.push(params[i])
}
}
params.splice(0, i, ...second, div, ...first)
}
revertDirection (word) {
return Gradient.directions[word.toLowerCase()] || word
}
/**
* Round float and save digits under dot
*/
roundFloat (float, digits) {
return parseFloat(float.toFixed(digits))
}
/**
* Convert to old webkit syntax
*/
oldWebkit (node) {
let { nodes } = node
let string = parser.stringify(node.nodes)
if (this.name !== 'linear-gradient') {
return false
}
if (nodes[0] && nodes[0].value.includes('deg')) {
return false
}
if (
string.includes('px') ||
string.includes('-corner') ||
string.includes('-side')
) {
return false
}
let params = [[]]
for (let i of nodes) {
params[params.length - 1].push(i)
if (i.type === 'div' && i.value === ',') {
params.push([])
}
}
this.oldDirection(params)
this.colorStops(params)
node.nodes = []
for (let param of params) {
node.nodes = node.nodes.concat(param)
}
node.nodes.unshift(
{ type: 'word', value: 'linear' },
this.cloneDiv(node.nodes)
)
node.value = '-webkit-gradient'
return true
}
/**
* Change direction syntax to old webkit
*/
oldDirection (params) {
let div = this.cloneDiv(params[0])
if (params[0][0].value !== 'to') {
return params.unshift([
{ type: 'word', value: Gradient.oldDirections.bottom },
div
])
} else {
let words = []
for (let node of params[0].slice(2)) {
if (node.type === 'word') {
words.push(node.value.toLowerCase())
}
}
words = words.join(' ')
let old = Gradient.oldDirections[words] || words
params[0] = [{ type: 'word', value: old }, div]
return params[0]
}
}
/**
* Get div token from exists parameters
*/
cloneDiv (params) {
for (let i of params) {
if (i.type === 'div' && i.value === ',') {
return i
}
}
return { type: 'div', value: ',', after: ' ' }
}
/**
* Change colors syntax to old webkit
*/
colorStops (params) {
let result = []
for (let i = 0; i < params.length; i++) {
let pos
let param = params[i]
let item
if (i === 0) {
continue
}
let color = parser.stringify(param[0])
if (param[1] && param[1].type === 'word') {
pos = param[1].value
} else if (param[2] && param[2].type === 'word') {
pos = param[2].value
}
let stop
if (i === 1 && (!pos || pos === '0%')) {
stop = `from(${color})`
} else if (i === params.length - 1 && (!pos || pos === '100%')) {
stop = `to(${color})`
} else if (pos) {
stop = `color-stop(${pos}, ${color})`
} else {
stop = `color-stop(${color})`
}
let div = param[param.length - 1]
params[i] = [{ type: 'word', value: stop }]
if (div.type === 'div' && div.value === ',') {
item = params[i].push(div)
}
result.push(item)
}
return result
}
/**
* Remove old WebKit gradient too
*/
old (prefix) {
if (prefix === '-webkit-') {
let type = this.name === 'linear-gradient' ? 'linear' : 'radial'
let string = '-gradient'
let regexp = utils.regexp(
`-webkit-(${type}-gradient|gradient\\(\\s*${type})`,
false
)
return new OldValue(this.name, prefix + this.name, string, regexp)
} else {
return super.old(prefix)
}
}
/**
* Do not add non-webkit prefixes for list-style and object
*/
add (decl, prefix) {
let p = decl.prop
if (p.includes('mask')) {
if (prefix === '-webkit-' || prefix === '-webkit- old') {
return super.add(decl, prefix)
}
} else if (
p === 'list-style' ||
p === 'list-style-image' ||
p === 'content'
) {
if (prefix === '-webkit-' || prefix === '-webkit- old') {
return super.add(decl, prefix)
}
} else {
return super.add(decl, prefix)
}
return undefined
}
}
Gradient.names = [
'linear-gradient',
'repeating-linear-gradient',
'radial-gradient',
'repeating-radial-gradient'
]
Gradient.directions = {
top: 'bottom',
left: 'right',
bottom: 'top',
right: 'left'
}
// Direction to replace
Gradient.oldDirections = {
'top': 'left bottom, left top',
'left': 'right top, left top',
'bottom': 'left top, left bottom',
'right': 'left top, right top',
'top right': 'left bottom, right top',
'top left': 'right bottom, left top',
'right top': 'left bottom, right top',
'right bottom': 'left top, right bottom',
'bottom right': 'left top, right bottom',
'bottom left': 'right top, left bottom',
'left top': 'right bottom, left top',
'left bottom': 'right top, left bottom'
}
module.exports = Gradient

View File

@@ -0,0 +1,34 @@
let Declaration = require('../declaration')
let utils = require('./grid-utils')
class GridArea extends Declaration {
/**
* Translate grid-area to separate -ms- prefixed properties
*/
insert (decl, prefix, prefixes, result) {
if (prefix !== '-ms-') return super.insert(decl, prefix, prefixes)
let values = utils.parse(decl)
let [rowStart, rowSpan] = utils.translate(values, 0, 2)
let [columnStart, columnSpan] = utils.translate(values, 1, 3)
;[
['grid-row', rowStart],
['grid-row-span', rowSpan],
['grid-column', columnStart],
['grid-column-span', columnSpan]
].forEach(([prop, value]) => {
utils.insertDecl(decl, prop, value)
})
utils.warnTemplateSelectorNotFound(decl, result)
utils.warnIfGridRowColumnExists(decl, result)
return undefined
}
}
GridArea.names = ['grid-area']
module.exports = GridArea

View File

@@ -0,0 +1,28 @@
let Declaration = require('../declaration')
class GridColumnAlign extends Declaration {
/**
* Do not prefix flexbox values
*/
check (decl) {
return !decl.value.includes('flex-') && decl.value !== 'baseline'
}
/**
* Change property name for IE
*/
prefixed (prop, prefix) {
return prefix + 'grid-column-align'
}
/**
* Change IE property back
*/
normalize () {
return 'justify-self'
}
}
GridColumnAlign.names = ['grid-column-align']
module.exports = GridColumnAlign

View File

@@ -0,0 +1,47 @@
let Declaration = require('../declaration')
class GridEnd extends Declaration {
/**
* Change repeating syntax for IE
*/
insert (decl, prefix, prefixes, result) {
if (prefix !== '-ms-') return super.insert(decl, prefix, prefixes)
let clonedDecl = this.clone(decl)
let startProp = decl.prop.replace(/end$/, 'start')
let spanProp = prefix + decl.prop.replace(/end$/, 'span')
if (decl.parent.some(i => i.prop === spanProp)) {
return undefined
}
clonedDecl.prop = spanProp
if (decl.value.includes('span')) {
clonedDecl.value = decl.value.replace(/span\s/i, '')
} else {
let startDecl
decl.parent.walkDecls(startProp, d => {
startDecl = d
})
if (startDecl) {
let value = Number(decl.value) - Number(startDecl.value) + ''
clonedDecl.value = value
} else {
decl.warn(
result,
`Can not prefix ${decl.prop} (${startProp} is not found)`
)
}
}
decl.cloneBefore(clonedDecl)
return undefined
}
}
GridEnd.names = ['grid-row-end', 'grid-column-end']
module.exports = GridEnd

View File

@@ -0,0 +1,28 @@
let Declaration = require('../declaration')
class GridRowAlign extends Declaration {
/**
* Do not prefix flexbox values
*/
check (decl) {
return !decl.value.includes('flex-') && decl.value !== 'baseline'
}
/**
* Change property name for IE
*/
prefixed (prop, prefix) {
return prefix + 'grid-row-align'
}
/**
* Change IE property back
*/
normalize () {
return 'align-self'
}
}
GridRowAlign.names = ['grid-row-align']
module.exports = GridRowAlign

View File

@@ -0,0 +1,33 @@
let Declaration = require('../declaration')
let utils = require('./grid-utils')
class GridRowColumn extends Declaration {
/**
* Translate grid-row / grid-column to separate -ms- prefixed properties
*/
insert (decl, prefix, prefixes) {
if (prefix !== '-ms-') return super.insert(decl, prefix, prefixes)
let values = utils.parse(decl)
let [start, span] = utils.translate(values, 0, 1)
let hasStartValueSpan = values[0] && values[0].includes('span')
if (hasStartValueSpan) {
span = values[0].join('').replace(/\D/g, '')
}
;[
[decl.prop, start],
[`${decl.prop}-span`, span]
].forEach(([prop, value]) => {
utils.insertDecl(decl, prop, value)
})
return undefined
}
}
GridRowColumn.names = ['grid-row', 'grid-column']
module.exports = GridRowColumn

View File

@@ -0,0 +1,125 @@
let Declaration = require('../declaration')
let {
prefixTrackProp,
prefixTrackValue,
autoplaceGridItems,
getGridGap,
inheritGridGap
} = require('./grid-utils')
let Processor = require('../processor')
class GridRowsColumns extends Declaration {
/**
* Change property name for IE
*/
prefixed (prop, prefix) {
if (prefix === '-ms-') {
return prefixTrackProp({ prop, prefix })
}
return super.prefixed(prop, prefix)
}
/**
* Change IE property back
*/
normalize (prop) {
return prop.replace(/^grid-(rows|columns)/, 'grid-template-$1')
}
insert (decl, prefix, prefixes, result) {
if (prefix !== '-ms-') return super.insert(decl, prefix, prefixes)
let { parent, prop, value } = decl
let isRowProp = prop.includes('rows')
let isColumnProp = prop.includes('columns')
let hasGridTemplate = parent.some(
i => i.prop === 'grid-template' || i.prop === 'grid-template-areas'
)
/**
* Not to prefix rows declaration if grid-template(-areas) is present
*/
if (hasGridTemplate && isRowProp) {
return false
}
let processor = new Processor({ options: {} })
let status = processor.gridStatus(parent, result)
let gap = getGridGap(decl)
gap = inheritGridGap(decl, gap) || gap
let gapValue = isRowProp ? gap.row : gap.column
if ((status === 'no-autoplace' || status === true) && !hasGridTemplate) {
gapValue = null
}
let prefixValue = prefixTrackValue({
value,
gap: gapValue
})
/**
* Insert prefixes
*/
decl.cloneBefore({
prop: prefixTrackProp({ prop, prefix }),
value: prefixValue
})
let autoflow = parent.nodes.find(i => i.prop === 'grid-auto-flow')
let autoflowValue = 'row'
if (autoflow && !processor.disabled(autoflow, result)) {
autoflowValue = autoflow.value.trim()
}
if (status === 'autoplace') {
/**
* Show warning if grid-template-rows decl is not found
*/
let rowDecl = parent.nodes.find(i => i.prop === 'grid-template-rows')
if (!rowDecl && hasGridTemplate) {
return undefined
} else if (!rowDecl && !hasGridTemplate) {
decl.warn(
result,
'Autoplacement does not work without grid-template-rows property'
)
return undefined
}
/**
* Show warning if grid-template-columns decl is not found
*/
let columnDecl = parent.nodes.find(i => {
return i.prop === 'grid-template-columns'
})
if (!columnDecl && !hasGridTemplate) {
decl.warn(
result,
'Autoplacement does not work without grid-template-columns property'
)
}
/**
* Autoplace grid items
*/
if (isColumnProp && !hasGridTemplate) {
autoplaceGridItems(decl, result, gap, autoflowValue)
}
}
return undefined
}
}
GridRowsColumns.names = [
'grid-template-rows',
'grid-template-columns',
'grid-rows',
'grid-columns'
]
module.exports = GridRowsColumns

View File

@@ -0,0 +1,33 @@
let Declaration = require('../declaration')
class GridStart extends Declaration {
/**
* Do not add prefix for unsupported value in IE
*/
check (decl) {
let value = decl.value
return !value.includes('/') || value.includes('span')
}
/**
* Return a final spec property
*/
normalize (prop) {
return prop.replace('-start', '')
}
/**
* Change property name for IE
*/
prefixed (prop, prefix) {
let result = super.prefixed(prop, prefix)
if (prefix === '-ms-') {
result = result.replace('-start', '')
}
return result
}
}
GridStart.names = ['grid-row-start', 'grid-column-start']
module.exports = GridStart

View File

@@ -0,0 +1,84 @@
let Declaration = require('../declaration')
let {
parseGridAreas,
warnMissedAreas,
prefixTrackProp,
prefixTrackValue,
getGridGap,
warnGridGap,
inheritGridGap
} = require('./grid-utils')
function getGridRows (tpl) {
return tpl
.trim()
.slice(1, -1)
.split(/["']\s*["']?/g)
}
class GridTemplateAreas extends Declaration {
/**
* Translate grid-template-areas to separate -ms- prefixed properties
*/
insert (decl, prefix, prefixes, result) {
if (prefix !== '-ms-') return super.insert(decl, prefix, prefixes)
let hasColumns = false
let hasRows = false
let parent = decl.parent
let gap = getGridGap(decl)
gap = inheritGridGap(decl, gap) || gap
// remove already prefixed rows
// to prevent doubling prefixes
parent.walkDecls(/-ms-grid-rows/, i => i.remove())
// add empty tracks to rows
parent.walkDecls(/grid-template-(rows|columns)/, trackDecl => {
if (trackDecl.prop === 'grid-template-rows') {
hasRows = true
let { prop, value } = trackDecl
trackDecl.cloneBefore({
prop: prefixTrackProp({ prop, prefix }),
value: prefixTrackValue({ value, gap: gap.row })
})
} else {
hasColumns = true
}
})
let gridRows = getGridRows(decl.value)
if (hasColumns && !hasRows && gap.row && gridRows.length > 1) {
decl.cloneBefore({
prop: '-ms-grid-rows',
value: prefixTrackValue({
value: `repeat(${gridRows.length}, auto)`,
gap: gap.row
}),
raws: {}
})
}
// warnings
warnGridGap({
gap,
hasColumns,
decl,
result
})
let areas = parseGridAreas({
rows: gridRows,
gap
})
warnMissedAreas(areas, decl, result)
return decl
}
}
GridTemplateAreas.names = ['grid-template-areas']
module.exports = GridTemplateAreas

View File

@@ -0,0 +1,69 @@
let Declaration = require('../declaration')
let {
parseTemplate,
warnMissedAreas,
getGridGap,
warnGridGap,
inheritGridGap
} = require('./grid-utils')
class GridTemplate extends Declaration {
/**
* Translate grid-template to separate -ms- prefixed properties
*/
insert (decl, prefix, prefixes, result) {
if (prefix !== '-ms-') return super.insert(decl, prefix, prefixes)
if (decl.parent.some(i => i.prop === '-ms-grid-rows')) {
return undefined
}
let gap = getGridGap(decl)
/**
* we must insert inherited gap values in some cases:
* if we are inside media query && if we have no grid-gap value
*/
let inheritedGap = inheritGridGap(decl, gap)
let { rows, columns, areas } = parseTemplate({
decl,
gap: inheritedGap || gap
})
let hasAreas = Object.keys(areas).length > 0
let hasRows = Boolean(rows)
let hasColumns = Boolean(columns)
warnGridGap({
gap,
hasColumns,
decl,
result
})
warnMissedAreas(areas, decl, result)
if ((hasRows && hasColumns) || hasAreas) {
decl.cloneBefore({
prop: '-ms-grid-rows',
value: rows,
raws: {}
})
}
if (hasColumns) {
decl.cloneBefore({
prop: '-ms-grid-columns',
value: columns,
raws: {}
})
}
return decl
}
}
GridTemplate.names = ['grid-template']
module.exports = GridTemplate

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
let Declaration = require('../declaration')
class ImageRendering extends Declaration {
/**
* Add hack only for crisp-edges
*/
check (decl) {
return decl.value === 'pixelated'
}
/**
* Change property name for IE
*/
prefixed (prop, prefix) {
if (prefix === '-ms-') {
return '-ms-interpolation-mode'
}
return super.prefixed(prop, prefix)
}
/**
* Change property and value for IE
*/
set (decl, prefix) {
if (prefix !== '-ms-') return super.set(decl, prefix)
decl.prop = '-ms-interpolation-mode'
decl.value = 'nearest-neighbor'
return decl
}
/**
* Return property name by spec
*/
normalize () {
return 'image-rendering'
}
/**
* Warn on old value
*/
process (node, result) {
return super.process(node, result)
}
}
ImageRendering.names = ['image-rendering', 'interpolation-mode']
module.exports = ImageRendering

View File

@@ -0,0 +1,18 @@
let Value = require('../value')
class ImageSet extends Value {
/**
* Use non-standard name for WebKit and Firefox
*/
replace (string, prefix) {
let fixed = super.replace(string, prefix)
if (prefix === '-webkit-') {
fixed = fixed.replace(/("[^"]+"|'[^']+')(\s+\d+\w)/gi, 'url($1)$2')
}
return fixed
}
}
ImageSet.names = ['image-set']
module.exports = ImageSet

View File

@@ -0,0 +1,34 @@
let Declaration = require('../declaration')
class InlineLogical extends Declaration {
/**
* Use old syntax for -moz- and -webkit-
*/
prefixed (prop, prefix) {
return prefix + prop.replace('-inline', '')
}
/**
* Return property name by spec
*/
normalize (prop) {
return prop.replace(/(margin|padding|border)-(start|end)/, '$1-inline-$2')
}
}
InlineLogical.names = [
'border-inline-start',
'border-inline-end',
'margin-inline-start',
'margin-inline-end',
'padding-inline-start',
'padding-inline-end',
'border-start',
'border-end',
'margin-start',
'margin-end',
'padding-start',
'padding-end'
]
module.exports = InlineLogical

View File

@@ -0,0 +1,61 @@
let OldValue = require('../old-value')
let Value = require('../value')
function regexp (name) {
return new RegExp(`(^|[\\s,(])(${name}($|[\\s),]))`, 'gi')
}
class Intrinsic extends Value {
regexp () {
if (!this.regexpCache) this.regexpCache = regexp(this.name)
return this.regexpCache
}
isStretch () {
return (
this.name === 'stretch' ||
this.name === 'fill' ||
this.name === 'fill-available'
)
}
replace (string, prefix) {
if (prefix === '-moz-' && this.isStretch()) {
return string.replace(this.regexp(), '$1-moz-available$3')
}
if (prefix === '-webkit-' && this.isStretch()) {
return string.replace(this.regexp(), '$1-webkit-fill-available$3')
}
return super.replace(string, prefix)
}
old (prefix) {
let prefixed = prefix + this.name
if (this.isStretch()) {
if (prefix === '-moz-') {
prefixed = '-moz-available'
} else if (prefix === '-webkit-') {
prefixed = '-webkit-fill-available'
}
}
return new OldValue(this.name, prefixed, prefixed, regexp(prefixed))
}
add (decl, prefix) {
if (decl.prop.includes('grid') && prefix !== '-webkit-') {
return undefined
}
return super.add(decl, prefix)
}
}
Intrinsic.names = [
'max-content',
'min-content',
'fit-content',
'fill',
'fill-available',
'stretch'
]
module.exports = Intrinsic

View File

@@ -0,0 +1,54 @@
let flexSpec = require('./flex-spec')
let Declaration = require('../declaration')
class JustifyContent extends Declaration {
/**
* Change property name for 2009 and 2012 specs
*/
prefixed (prop, prefix) {
let spec
;[spec, prefix] = flexSpec(prefix)
if (spec === 2009) {
return prefix + 'box-pack'
}
if (spec === 2012) {
return prefix + 'flex-pack'
}
return super.prefixed(prop, prefix)
}
/**
* Return property name by final spec
*/
normalize () {
return 'justify-content'
}
/**
* Change value for 2009 and 2012 specs
*/
set (decl, prefix) {
let spec = flexSpec(prefix)[0]
if (spec === 2009 || spec === 2012) {
let value = JustifyContent.oldValues[decl.value] || decl.value
decl.value = value
if (spec !== 2009 || value !== 'distribute') {
return super.set(decl, prefix)
}
} else if (spec === 'final') {
return super.set(decl, prefix)
}
return undefined
}
}
JustifyContent.names = ['justify-content', 'flex-pack', 'box-pack']
JustifyContent.oldValues = {
'flex-end': 'end',
'flex-start': 'start',
'space-between': 'justify',
'space-around': 'distribute'
}
module.exports = JustifyContent

View File

@@ -0,0 +1,38 @@
let Declaration = require('../declaration')
class MaskBorder extends Declaration {
/**
* Return property name by final spec
*/
normalize () {
return this.name.replace('box-image', 'border')
}
/**
* Return flex property for 2012 spec
*/
prefixed (prop, prefix) {
let result = super.prefixed(prop, prefix)
if (prefix === '-webkit-') {
result = result.replace('border', 'box-image')
}
return result
}
}
MaskBorder.names = [
'mask-border',
'mask-border-source',
'mask-border-slice',
'mask-border-width',
'mask-border-outset',
'mask-border-repeat',
'mask-box-image',
'mask-box-image-source',
'mask-box-image-slice',
'mask-box-image-width',
'mask-box-image-outset',
'mask-box-image-repeat'
]
module.exports = MaskBorder

View File

@@ -0,0 +1,88 @@
let Declaration = require('../declaration')
class MaskComposite extends Declaration {
/**
* Prefix mask-composite for webkit
*/
insert (decl, prefix, prefixes) {
let isCompositeProp = decl.prop === 'mask-composite'
let compositeValues
if (isCompositeProp) {
compositeValues = decl.value.split(',')
} else {
compositeValues = decl.value.match(MaskComposite.regexp) || []
}
compositeValues = compositeValues.map(el => el.trim()).filter(el => el)
let hasCompositeValues = compositeValues.length
let compositeDecl
if (hasCompositeValues) {
compositeDecl = this.clone(decl)
compositeDecl.value = compositeValues
.map(value => MaskComposite.oldValues[value] || value)
.join(', ')
if (compositeValues.includes('intersect')) {
compositeDecl.value += ', xor'
}
compositeDecl.prop = prefix + 'mask-composite'
}
if (isCompositeProp) {
if (!hasCompositeValues) {
return undefined
}
if (this.needCascade(decl)) {
compositeDecl.raws.before = this.calcBefore(prefixes, decl, prefix)
}
return decl.parent.insertBefore(decl, compositeDecl)
}
let cloned = this.clone(decl)
cloned.prop = prefix + cloned.prop
if (hasCompositeValues) {
cloned.value = cloned.value.replace(MaskComposite.regexp, '')
}
if (this.needCascade(decl)) {
cloned.raws.before = this.calcBefore(prefixes, decl, prefix)
}
decl.parent.insertBefore(decl, cloned)
if (!hasCompositeValues) {
return decl
}
if (this.needCascade(decl)) {
compositeDecl.raws.before = this.calcBefore(prefixes, decl, prefix)
}
return decl.parent.insertBefore(decl, compositeDecl)
}
}
MaskComposite.names = ['mask', 'mask-composite']
MaskComposite.oldValues = {
add: 'source-over',
subtract: 'source-out',
intersect: 'source-in',
exclude: 'xor'
}
MaskComposite.regexp = new RegExp(
`\\s+(${Object.keys(MaskComposite.oldValues).join(
'|'
)})\\b(?!\\))\\s*(?=[,])`,
'ig'
)
module.exports = MaskComposite

View File

@@ -0,0 +1,42 @@
let flexSpec = require('./flex-spec')
let Declaration = require('../declaration')
class Order extends Declaration {
/**
* Change property name for 2009 and 2012 specs
*/
prefixed (prop, prefix) {
let spec
;[spec, prefix] = flexSpec(prefix)
if (spec === 2009) {
return prefix + 'box-ordinal-group'
}
if (spec === 2012) {
return prefix + 'flex-order'
}
return super.prefixed(prop, prefix)
}
/**
* Return property name by final spec
*/
normalize () {
return 'order'
}
/**
* Fix value for 2009 spec
*/
set (decl, prefix) {
let spec = flexSpec(prefix)[0]
if (spec === 2009 && /\d/.test(decl.value)) {
decl.value = (parseInt(decl.value) + 1).toString()
return super.set(decl, prefix)
}
return super.set(decl, prefix)
}
}
Order.names = ['order', 'flex-order', 'box-ordinal-group']
module.exports = Order

View File

@@ -0,0 +1,33 @@
let Declaration = require('../declaration')
class OverscrollBehavior extends Declaration {
/**
* Change property name for IE
*/
prefixed (prop, prefix) {
return prefix + 'scroll-chaining'
}
/**
* Return property name by spec
*/
normalize () {
return 'overscroll-behavior'
}
/**
* Change value for IE
*/
set (decl, prefix) {
if (decl.value === 'auto') {
decl.value = 'chained'
} else if (decl.value === 'none' || decl.value === 'contain') {
decl.value = 'none'
}
return super.set(decl, prefix)
}
}
OverscrollBehavior.names = ['overscroll-behavior', 'scroll-chaining']
module.exports = OverscrollBehavior

View File

@@ -0,0 +1,34 @@
let OldValue = require('../old-value')
let Value = require('../value')
class Pixelated extends Value {
/**
* Use non-standard name for WebKit and Firefox
*/
replace (string, prefix) {
if (prefix === '-webkit-') {
return string.replace(this.regexp(), '$1-webkit-optimize-contrast')
}
if (prefix === '-moz-') {
return string.replace(this.regexp(), '$1-moz-crisp-edges')
}
return super.replace(string, prefix)
}
/**
* Different name for WebKit and Firefox
*/
old (prefix) {
if (prefix === '-webkit-') {
return new OldValue(this.name, '-webkit-optimize-contrast')
}
if (prefix === '-moz-') {
return new OldValue(this.name, '-moz-crisp-edges')
}
return super.old(prefix)
}
}
Pixelated.names = ['pixelated']
module.exports = Pixelated

View File

@@ -0,0 +1,32 @@
let Declaration = require('../declaration')
let utils = require('./grid-utils')
class PlaceSelf extends Declaration {
/**
* Translate place-self to separate -ms- prefixed properties
*/
insert (decl, prefix, prefixes) {
if (prefix !== '-ms-') return super.insert(decl, prefix, prefixes)
// prevent doubling of prefixes
if (decl.parent.some(i => i.prop === '-ms-grid-row-align')) {
return undefined
}
let [[first, second]] = utils.parse(decl)
if (second) {
utils.insertDecl(decl, 'grid-row-align', first)
utils.insertDecl(decl, 'grid-column-align', second)
} else {
utils.insertDecl(decl, 'grid-row-align', first)
utils.insertDecl(decl, 'grid-column-align', first)
}
return undefined
}
}
PlaceSelf.names = ['place-self']
module.exports = PlaceSelf

View File

@@ -0,0 +1,17 @@
let Selector = require('../selector')
class PlaceholderShown extends Selector {
/**
* Return different selectors depend on prefix
*/
prefixed (prefix) {
if (prefix === '-ms-') {
return ':-ms-input-placeholder'
}
return `:${prefix}placeholder-shown`
}
}
PlaceholderShown.names = [':placeholder-shown']
module.exports = PlaceholderShown

View File

@@ -0,0 +1,33 @@
let Selector = require('../selector')
class Placeholder extends Selector {
/**
* Add old mozilla to possible prefixes
*/
possible () {
return super.possible().concat(['-moz- old', '-ms- old'])
}
/**
* Return different selectors depend on prefix
*/
prefixed (prefix) {
if (prefix === '-webkit-') {
return '::-webkit-input-placeholder'
}
if (prefix === '-ms-') {
return '::-ms-input-placeholder'
}
if (prefix === '-ms- old') {
return ':-ms-input-placeholder'
}
if (prefix === '-moz- old') {
return ':-moz-placeholder'
}
return `::${prefix}placeholder`
}
}
Placeholder.names = ['::placeholder']
module.exports = Placeholder

View File

@@ -0,0 +1,23 @@
let Declaration = require('../declaration')
class TextDecorationSkipInk extends Declaration {
/**
* Change prefix for ink value
*/
set (decl, prefix) {
if (decl.prop === 'text-decoration-skip-ink' && decl.value === 'auto') {
decl.prop = prefix + 'text-decoration-skip'
decl.value = 'ink'
return decl
} else {
return super.set(decl, prefix)
}
}
}
TextDecorationSkipInk.names = [
'text-decoration-skip-ink',
'text-decoration-skip'
]
module.exports = TextDecorationSkipInk

View File

@@ -0,0 +1,25 @@
let Declaration = require('../declaration')
const BASIC = [
'none',
'underline',
'overline',
'line-through',
'blink',
'inherit',
'initial',
'unset'
]
class TextDecoration extends Declaration {
/**
* Do not add prefixes for basic values.
*/
check (decl) {
return decl.value.split(/\s+/).some(i => !BASIC.includes(i))
}
}
TextDecoration.names = ['text-decoration']
module.exports = TextDecoration

View File

@@ -0,0 +1,14 @@
let Declaration = require('../declaration')
class TextEmphasisPosition extends Declaration {
set (decl, prefix) {
if (prefix === '-webkit-') {
decl.value = decl.value.replace(/\s*(right|left)\s*/i, '')
}
return super.set(decl, prefix)
}
}
TextEmphasisPosition.names = ['text-emphasis-position']
module.exports = TextEmphasisPosition

View File

@@ -0,0 +1,79 @@
let Declaration = require('../declaration')
class TransformDecl extends Declaration {
/**
* Recursively check all parents for @keyframes
*/
keyframeParents (decl) {
let { parent } = decl
while (parent) {
if (parent.type === 'atrule' && parent.name === 'keyframes') {
return true
}
;({ parent } = parent)
}
return false
}
/**
* Is transform contain 3D commands
*/
contain3d (decl) {
if (decl.prop === 'transform-origin') {
return false
}
for (let func of TransformDecl.functions3d) {
if (decl.value.includes(`${func}(`)) {
return true
}
}
return false
}
/**
* Replace rotateZ to rotate for IE 9
*/
set (decl, prefix) {
decl = super.set(decl, prefix)
if (prefix === '-ms-') {
decl.value = decl.value.replace(/rotatez/gi, 'rotate')
}
return decl
}
/**
* Don't add prefix for IE in keyframes
*/
insert (decl, prefix, prefixes) {
if (prefix === '-ms-') {
if (!this.contain3d(decl) && !this.keyframeParents(decl)) {
return super.insert(decl, prefix, prefixes)
}
} else if (prefix === '-o-') {
if (!this.contain3d(decl)) {
return super.insert(decl, prefix, prefixes)
}
} else {
return super.insert(decl, prefix, prefixes)
}
return undefined
}
}
TransformDecl.names = ['transform', 'transform-origin']
TransformDecl.functions3d = [
'matrix3d',
'translate3d',
'translateZ',
'scale3d',
'scaleZ',
'rotate3d',
'rotateX',
'rotateY',
'perspective'
]
module.exports = TransformDecl

View File

@@ -0,0 +1,28 @@
let Declaration = require('../declaration')
class UserSelect extends Declaration {
/**
* Change prefixed value for IE
*/
set (decl, prefix) {
if (prefix === '-ms-' && decl.value === 'contain') {
decl.value = 'element'
}
return super.set(decl, prefix)
}
/**
* Avoid prefixing all in IE
*/
insert (decl, prefix, prefixes) {
if (decl.value === 'all' && prefix === '-ms-') {
return undefined
} else {
return super.insert(decl, prefix, prefixes)
}
}
}
UserSelect.names = ['user-select']
module.exports = UserSelect

View File

@@ -0,0 +1,42 @@
let Declaration = require('../declaration')
class WritingMode extends Declaration {
insert (decl, prefix, prefixes) {
if (prefix === '-ms-') {
let cloned = this.set(this.clone(decl), prefix)
if (this.needCascade(decl)) {
cloned.raws.before = this.calcBefore(prefixes, decl, prefix)
}
let direction = 'ltr'
decl.parent.nodes.forEach(i => {
if (i.prop === 'direction') {
if (i.value === 'rtl' || i.value === 'ltr') direction = i.value
}
})
cloned.value = WritingMode.msValues[direction][decl.value] || decl.value
return decl.parent.insertBefore(decl, cloned)
}
return super.insert(decl, prefix, prefixes)
}
}
WritingMode.names = ['writing-mode']
WritingMode.msValues = {
ltr: {
'horizontal-tb': 'lr-tb',
'vertical-rl': 'tb-rl',
'vertical-lr': 'tb-lr'
},
rtl: {
'horizontal-tb': 'rl-tb',
'vertical-rl': 'bt-rl',
'vertical-lr': 'bt-lr'
}
}
module.exports = WritingMode

View File

@@ -0,0 +1,123 @@
let browserslist = require('browserslist')
function capitalize (str) {
return str.slice(0, 1).toUpperCase() + str.slice(1)
}
const NAMES = {
ie: 'IE',
ie_mob: 'IE Mobile',
ios_saf: 'iOS Safari',
op_mini: 'Opera Mini',
op_mob: 'Opera Mobile',
and_chr: 'Chrome for Android',
and_ff: 'Firefox for Android',
and_uc: 'UC for Android',
and_qq: 'QQ Browser',
kaios: 'KaiOS Browser',
baidu: 'Baidu Browser',
samsung: 'Samsung Internet'
}
function prefix (name, prefixes, note) {
let out = ` ${name}`
if (note) out += ' *'
out += ': '
out += prefixes.map(i => i.replace(/^-(.*)-$/g, '$1')).join(', ')
out += '\n'
return out
}
module.exports = function (prefixes) {
if (prefixes.browsers.selected.length === 0) {
return 'No browsers selected'
}
let versions = {}
for (let browser of prefixes.browsers.selected) {
let parts = browser.split(' ')
let name = parts[0]
let version = parts[1]
name = NAMES[name] || capitalize(name)
if (versions[name]) {
versions[name].push(version)
} else {
versions[name] = [version]
}
}
let out = 'Browsers:\n'
for (let browser in versions) {
let list = versions[browser]
list = list.sort((a, b) => parseFloat(b) - parseFloat(a))
out += ` ${browser}: ${list.join(', ')}\n`
}
let coverage = browserslist.coverage(prefixes.browsers.selected)
let round = Math.round(coverage * 100) / 100.0
out += `\nThese browsers account for ${round}% of all users globally\n`
let atrules = []
for (let name in prefixes.add) {
let data = prefixes.add[name]
if (name[0] === '@' && data.prefixes) {
atrules.push(prefix(name, data.prefixes))
}
}
if (atrules.length > 0) {
out += `\nAt-Rules:\n${atrules.sort().join('')}`
}
let selectors = []
for (let selector of prefixes.add.selectors) {
if (selector.prefixes) {
selectors.push(prefix(selector.name, selector.prefixes))
}
}
if (selectors.length > 0) {
out += `\nSelectors:\n${selectors.sort().join('')}`
}
let values = []
let props = []
let hadGrid = false
for (let name in prefixes.add) {
let data = prefixes.add[name]
if (name[0] !== '@' && data.prefixes) {
let grid = name.indexOf('grid-') === 0
if (grid) hadGrid = true
props.push(prefix(name, data.prefixes, grid))
}
if (!Array.isArray(data.values)) {
continue
}
for (let value of data.values) {
let grid = value.name.includes('grid')
if (grid) hadGrid = true
let string = prefix(value.name, value.prefixes, grid)
if (!values.includes(string)) {
values.push(string)
}
}
}
if (props.length > 0) {
out += `\nProperties:\n${props.sort().join('')}`
}
if (values.length > 0) {
out += `\nValues:\n${values.sort().join('')}`
}
if (hadGrid) {
out += '\n* - Prefixes will be added only on grid: true option.\n'
}
if (!atrules.length && !selectors.length && !props.length && !values.length) {
out +=
"\nAwesome! Your browsers don't require any vendor prefixes." +
'\nNow you can remove Autoprefixer from build steps.'
}
return out
}

View File

@@ -0,0 +1,67 @@
class OldSelector {
constructor (selector, prefix) {
this.prefix = prefix
this.prefixed = selector.prefixed(this.prefix)
this.regexp = selector.regexp(this.prefix)
this.prefixeds = selector
.possible()
.map(x => [selector.prefixed(x), selector.regexp(x)])
this.unprefixed = selector.name
this.nameRegexp = selector.regexp()
}
/**
* Is rule a hack without unprefixed version bottom
*/
isHack (rule) {
let index = rule.parent.index(rule) + 1
let rules = rule.parent.nodes
while (index < rules.length) {
let before = rules[index].selector
if (!before) {
return true
}
if (before.includes(this.unprefixed) && before.match(this.nameRegexp)) {
return false
}
let some = false
for (let [string, regexp] of this.prefixeds) {
if (before.includes(string) && before.match(regexp)) {
some = true
break
}
}
if (!some) {
return true
}
index += 1
}
return true
}
/**
* Does rule contain an unnecessary prefixed selector
*/
check (rule) {
if (!rule.selector.includes(this.prefixed)) {
return false
}
if (!rule.selector.match(this.regexp)) {
return false
}
if (this.isHack(rule)) {
return false
}
return true
}
}
module.exports = OldSelector

View File

@@ -0,0 +1,22 @@
let utils = require('./utils')
class OldValue {
constructor (unprefixed, prefixed, string, regexp) {
this.unprefixed = unprefixed
this.prefixed = prefixed
this.string = string || prefixed
this.regexp = regexp || utils.regexp(prefixed)
}
/**
* Check, that value contain old value
*/
check (value) {
if (value.includes(this.string)) {
return !!value.match(this.regexp)
}
return false
}
}
module.exports = OldValue

View File

@@ -0,0 +1,144 @@
let Browsers = require('./browsers')
let vendor = require('./vendor')
let utils = require('./utils')
/**
* Recursively clone objects
*/
function clone (obj, parent) {
let cloned = new obj.constructor()
for (let i of Object.keys(obj || {})) {
let value = obj[i]
if (i === 'parent' && typeof value === 'object') {
if (parent) {
cloned[i] = parent
}
} else if (i === 'source' || i === null) {
cloned[i] = value
} else if (Array.isArray(value)) {
cloned[i] = value.map(x => clone(x, cloned))
} else if (
i !== '_autoprefixerPrefix' &&
i !== '_autoprefixerValues' &&
i !== 'proxyCache'
) {
if (typeof value === 'object' && value !== null) {
value = clone(value, cloned)
}
cloned[i] = value
}
}
return cloned
}
class Prefixer {
/**
* Add hack to selected names
*/
static hack (klass) {
if (!this.hacks) {
this.hacks = {}
}
return klass.names.map(name => {
this.hacks[name] = klass
return this.hacks[name]
})
}
/**
* Load hacks for some names
*/
static load (name, prefixes, all) {
let Klass = this.hacks && this.hacks[name]
if (Klass) {
return new Klass(name, prefixes, all)
} else {
return new this(name, prefixes, all)
}
}
/**
* Clone node and clean autprefixer custom caches
*/
static clone (node, overrides) {
let cloned = clone(node)
for (let name in overrides) {
cloned[name] = overrides[name]
}
return cloned
}
constructor (name, prefixes, all) {
this.prefixes = prefixes
this.name = name
this.all = all
}
/**
* Find prefix in node parents
*/
parentPrefix (node) {
let prefix
if (typeof node._autoprefixerPrefix !== 'undefined') {
prefix = node._autoprefixerPrefix
} else if (node.type === 'decl' && node.prop[0] === '-') {
prefix = vendor.prefix(node.prop)
} else if (node.type === 'root') {
prefix = false
} else if (
node.type === 'rule' &&
node.selector.includes(':-') &&
/:(-\w+-)/.test(node.selector)
) {
prefix = node.selector.match(/:(-\w+-)/)[1]
} else if (node.type === 'atrule' && node.name[0] === '-') {
prefix = vendor.prefix(node.name)
} else {
prefix = this.parentPrefix(node.parent)
}
if (!Browsers.prefixes().includes(prefix)) {
prefix = false
}
node._autoprefixerPrefix = prefix
return node._autoprefixerPrefix
}
/**
* Clone node with prefixes
*/
process (node, result) {
if (!this.check(node)) {
return undefined
}
let parent = this.parentPrefix(node)
let prefixes = this.prefixes.filter(
prefix => !parent || parent === utils.removeNote(prefix)
)
let added = []
for (let prefix of prefixes) {
if (this.add(node, prefix, added.concat([prefix]), result)) {
added.push(prefix)
}
}
return added
}
/**
* Shortcut for Prefixer.clone
*/
clone (node, overrides) {
return Prefixer.clone(node, overrides)
}
}
module.exports = Prefixer

View File

@@ -0,0 +1,368 @@
let vendor = require('./vendor')
let Declaration = require('./declaration')
let Resolution = require('./resolution')
let Transition = require('./transition')
let Processor = require('./processor')
let Supports = require('./supports')
let Browsers = require('./browsers')
let Selector = require('./selector')
let AtRule = require('./at-rule')
let Value = require('./value')
let utils = require('./utils')
Selector.hack(require('./hacks/fullscreen'))
Selector.hack(require('./hacks/placeholder'))
Selector.hack(require('./hacks/placeholder-shown'))
Declaration.hack(require('./hacks/flex'))
Declaration.hack(require('./hacks/order'))
Declaration.hack(require('./hacks/filter'))
Declaration.hack(require('./hacks/grid-end'))
Declaration.hack(require('./hacks/animation'))
Declaration.hack(require('./hacks/flex-flow'))
Declaration.hack(require('./hacks/flex-grow'))
Declaration.hack(require('./hacks/flex-wrap'))
Declaration.hack(require('./hacks/grid-area'))
Declaration.hack(require('./hacks/place-self'))
Declaration.hack(require('./hacks/grid-start'))
Declaration.hack(require('./hacks/align-self'))
Declaration.hack(require('./hacks/appearance'))
Declaration.hack(require('./hacks/flex-basis'))
Declaration.hack(require('./hacks/mask-border'))
Declaration.hack(require('./hacks/mask-composite'))
Declaration.hack(require('./hacks/align-items'))
Declaration.hack(require('./hacks/user-select'))
Declaration.hack(require('./hacks/flex-shrink'))
Declaration.hack(require('./hacks/break-props'))
Declaration.hack(require('./hacks/color-adjust'))
Declaration.hack(require('./hacks/writing-mode'))
Declaration.hack(require('./hacks/border-image'))
Declaration.hack(require('./hacks/align-content'))
Declaration.hack(require('./hacks/border-radius'))
Declaration.hack(require('./hacks/block-logical'))
Declaration.hack(require('./hacks/grid-template'))
Declaration.hack(require('./hacks/inline-logical'))
Declaration.hack(require('./hacks/grid-row-align'))
Declaration.hack(require('./hacks/transform-decl'))
Declaration.hack(require('./hacks/flex-direction'))
Declaration.hack(require('./hacks/image-rendering'))
Declaration.hack(require('./hacks/backdrop-filter'))
Declaration.hack(require('./hacks/background-clip'))
Declaration.hack(require('./hacks/text-decoration'))
Declaration.hack(require('./hacks/justify-content'))
Declaration.hack(require('./hacks/background-size'))
Declaration.hack(require('./hacks/grid-row-column'))
Declaration.hack(require('./hacks/grid-rows-columns'))
Declaration.hack(require('./hacks/grid-column-align'))
Declaration.hack(require('./hacks/overscroll-behavior'))
Declaration.hack(require('./hacks/grid-template-areas'))
Declaration.hack(require('./hacks/text-emphasis-position'))
Declaration.hack(require('./hacks/text-decoration-skip-ink'))
Value.hack(require('./hacks/gradient'))
Value.hack(require('./hacks/intrinsic'))
Value.hack(require('./hacks/pixelated'))
Value.hack(require('./hacks/image-set'))
Value.hack(require('./hacks/cross-fade'))
Value.hack(require('./hacks/display-flex'))
Value.hack(require('./hacks/display-grid'))
Value.hack(require('./hacks/filter-value'))
let declsCache = new Map()
class Prefixes {
constructor (data, browsers, options = {}) {
this.data = data
this.browsers = browsers
this.options = options
;[this.add, this.remove] = this.preprocess(this.select(this.data))
this.transition = new Transition(this)
this.processor = new Processor(this)
}
/**
* Return clone instance to remove all prefixes
*/
cleaner () {
if (this.cleanerCache) {
return this.cleanerCache
}
if (this.browsers.selected.length) {
let empty = new Browsers(this.browsers.data, [])
this.cleanerCache = new Prefixes(this.data, empty, this.options)
} else {
return this
}
return this.cleanerCache
}
/**
* Select prefixes from data, which is necessary for selected browsers
*/
select (list) {
let selected = { add: {}, remove: {} }
for (let name in list) {
let data = list[name]
let add = data.browsers.map(i => {
let params = i.split(' ')
return {
browser: `${params[0]} ${params[1]}`,
note: params[2]
}
})
let notes = add
.filter(i => i.note)
.map(i => `${this.browsers.prefix(i.browser)} ${i.note}`)
notes = utils.uniq(notes)
add = add
.filter(i => this.browsers.isSelected(i.browser))
.map(i => {
let prefix = this.browsers.prefix(i.browser)
if (i.note) {
return `${prefix} ${i.note}`
} else {
return prefix
}
})
add = this.sort(utils.uniq(add))
if (this.options.flexbox === 'no-2009') {
add = add.filter(i => !i.includes('2009'))
}
let all = data.browsers.map(i => this.browsers.prefix(i))
if (data.mistakes) {
all = all.concat(data.mistakes)
}
all = all.concat(notes)
all = utils.uniq(all)
if (add.length) {
selected.add[name] = add
if (add.length < all.length) {
selected.remove[name] = all.filter(i => !add.includes(i))
}
} else {
selected.remove[name] = all
}
}
return selected
}
/**
* Sort vendor prefixes
*/
sort (prefixes) {
return prefixes.sort((a, b) => {
let aLength = utils.removeNote(a).length
let bLength = utils.removeNote(b).length
if (aLength === bLength) {
return b.length - a.length
} else {
return bLength - aLength
}
})
}
/**
* Cache prefixes data to fast CSS processing
*/
preprocess (selected) {
let add = {
'selectors': [],
'@supports': new Supports(Prefixes, this)
}
for (let name in selected.add) {
let prefixes = selected.add[name]
if (name === '@keyframes' || name === '@viewport') {
add[name] = new AtRule(name, prefixes, this)
} else if (name === '@resolution') {
add[name] = new Resolution(name, prefixes, this)
} else if (this.data[name].selector) {
add.selectors.push(Selector.load(name, prefixes, this))
} else {
let props = this.data[name].props
if (props) {
let value = Value.load(name, prefixes, this)
for (let prop of props) {
if (!add[prop]) {
add[prop] = { values: [] }
}
add[prop].values.push(value)
}
} else {
let values = (add[name] && add[name].values) || []
add[name] = Declaration.load(name, prefixes, this)
add[name].values = values
}
}
}
let remove = { selectors: [] }
for (let name in selected.remove) {
let prefixes = selected.remove[name]
if (this.data[name].selector) {
let selector = Selector.load(name, prefixes)
for (let prefix of prefixes) {
remove.selectors.push(selector.old(prefix))
}
} else if (name === '@keyframes' || name === '@viewport') {
for (let prefix of prefixes) {
let prefixed = `@${prefix}${name.slice(1)}`
remove[prefixed] = { remove: true }
}
} else if (name === '@resolution') {
remove[name] = new Resolution(name, prefixes, this)
} else {
let props = this.data[name].props
if (props) {
let value = Value.load(name, [], this)
for (let prefix of prefixes) {
let old = value.old(prefix)
if (old) {
for (let prop of props) {
if (!remove[prop]) {
remove[prop] = {}
}
if (!remove[prop].values) {
remove[prop].values = []
}
remove[prop].values.push(old)
}
}
}
} else {
for (let p of prefixes) {
let olds = this.decl(name).old(name, p)
if (name === 'align-self') {
let a = add[name] && add[name].prefixes
if (a) {
if (p === '-webkit- 2009' && a.includes('-webkit-')) {
continue
} else if (p === '-webkit-' && a.includes('-webkit- 2009')) {
continue
}
}
}
for (let prefixed of olds) {
if (!remove[prefixed]) {
remove[prefixed] = {}
}
remove[prefixed].remove = true
}
}
}
}
}
return [add, remove]
}
/**
* Declaration loader with caching
*/
decl (prop) {
if (!declsCache.has(prop)) {
declsCache.set(prop, Declaration.load(prop))
}
return declsCache.get(prop)
}
/**
* Return unprefixed version of property
*/
unprefixed (prop) {
let value = this.normalize(vendor.unprefixed(prop))
if (value === 'flex-direction') {
value = 'flex-flow'
}
return value
}
/**
* Normalize prefix for remover
*/
normalize (prop) {
return this.decl(prop).normalize(prop)
}
/**
* Return prefixed version of property
*/
prefixed (prop, prefix) {
prop = vendor.unprefixed(prop)
return this.decl(prop).prefixed(prop, prefix)
}
/**
* Return values, which must be prefixed in selected property
*/
values (type, prop) {
let data = this[type]
let global = data['*'] && data['*'].values
let values = data[prop] && data[prop].values
if (global && values) {
return utils.uniq(global.concat(values))
} else {
return global || values || []
}
}
/**
* Group declaration by unprefixed property to check them
*/
group (decl) {
let rule = decl.parent
let index = rule.index(decl)
let { length } = rule.nodes
let unprefixed = this.unprefixed(decl.prop)
let checker = (step, callback) => {
index += step
while (index >= 0 && index < length) {
let other = rule.nodes[index]
if (other.type === 'decl') {
if (step === -1 && other.prop === unprefixed) {
if (!Browsers.withPrefix(other.value)) {
break
}
}
if (this.unprefixed(other.prop) !== unprefixed) {
break
} else if (callback(other) === true) {
return true
}
if (step === +1 && other.prop === unprefixed) {
if (!Browsers.withPrefix(other.value)) {
break
}
}
}
index += step
}
return false
}
return {
up (callback) {
return checker(-1, callback)
},
down (callback) {
return checker(+1, callback)
}
}
}
}
module.exports = Prefixes

View File

@@ -0,0 +1,707 @@
let parser = require('postcss-value-parser')
let Value = require('./value')
let insertAreas = require('./hacks/grid-utils').insertAreas
const OLD_LINEAR = /(^|[^-])linear-gradient\(\s*(top|left|right|bottom)/i
const OLD_RADIAL = /(^|[^-])radial-gradient\(\s*\d+(\w*|%)\s+\d+(\w*|%)\s*,/i
const IGNORE_NEXT = /(!\s*)?autoprefixer:\s*ignore\s+next/i
const GRID_REGEX = /(!\s*)?autoprefixer\s*grid:\s*(on|off|(no-)?autoplace)/i
const SIZES = [
'width',
'height',
'min-width',
'max-width',
'min-height',
'max-height',
'inline-size',
'min-inline-size',
'max-inline-size',
'block-size',
'min-block-size',
'max-block-size'
]
function hasGridTemplate (decl) {
return decl.parent.some(
i => i.prop === 'grid-template' || i.prop === 'grid-template-areas'
)
}
function hasRowsAndColumns (decl) {
let hasRows = decl.parent.some(i => i.prop === 'grid-template-rows')
let hasColumns = decl.parent.some(i => i.prop === 'grid-template-columns')
return hasRows && hasColumns
}
class Processor {
constructor (prefixes) {
this.prefixes = prefixes
}
/**
* Add necessary prefixes
*/
add (css, result) {
// At-rules
let resolution = this.prefixes.add['@resolution']
let keyframes = this.prefixes.add['@keyframes']
let viewport = this.prefixes.add['@viewport']
let supports = this.prefixes.add['@supports']
css.walkAtRules(rule => {
if (rule.name === 'keyframes') {
if (!this.disabled(rule, result)) {
return keyframes && keyframes.process(rule)
}
} else if (rule.name === 'viewport') {
if (!this.disabled(rule, result)) {
return viewport && viewport.process(rule)
}
} else if (rule.name === 'supports') {
if (
this.prefixes.options.supports !== false &&
!this.disabled(rule, result)
) {
return supports.process(rule)
}
} else if (rule.name === 'media' && rule.params.includes('-resolution')) {
if (!this.disabled(rule, result)) {
return resolution && resolution.process(rule)
}
}
return undefined
})
// Selectors
css.walkRules(rule => {
if (this.disabled(rule, result)) return undefined
return this.prefixes.add.selectors.map(selector => {
return selector.process(rule, result)
})
})
function insideGrid (decl) {
return decl.parent.nodes.some(node => {
if (node.type !== 'decl') return false
let displayGrid =
node.prop === 'display' && /(inline-)?grid/.test(node.value)
let gridTemplate = node.prop.startsWith('grid-template')
let gridGap = /^grid-([A-z]+-)?gap/.test(node.prop)
return displayGrid || gridTemplate || gridGap
})
}
function insideFlex (decl) {
return decl.parent.some(node => {
return node.prop === 'display' && /(inline-)?flex/.test(node.value)
})
}
let gridPrefixes =
this.gridStatus(css, result) &&
this.prefixes.add['grid-area'] &&
this.prefixes.add['grid-area'].prefixes
css.walkDecls(decl => {
if (this.disabledDecl(decl, result)) return undefined
let parent = decl.parent
let prop = decl.prop
let value = decl.value
if (prop === 'grid-row-span') {
result.warn(
'grid-row-span is not part of final Grid Layout. Use grid-row.',
{ node: decl }
)
return undefined
} else if (prop === 'grid-column-span') {
result.warn(
'grid-column-span is not part of final Grid Layout. Use grid-column.',
{ node: decl }
)
return undefined
} else if (prop === 'display' && value === 'box') {
result.warn(
'You should write display: flex by final spec ' +
'instead of display: box',
{ node: decl }
)
return undefined
} else if (prop === 'text-emphasis-position') {
if (value === 'under' || value === 'over') {
result.warn(
'You should use 2 values for text-emphasis-position ' +
'For example, `under left` instead of just `under`.',
{ node: decl }
)
}
} else if (
/^(align|justify|place)-(items|content)$/.test(prop) &&
insideFlex(decl)
) {
if (value === 'start' || value === 'end') {
result.warn(
`${value} value has mixed support, consider using ` +
`flex-${value} instead`,
{ node: decl }
)
}
} else if (prop === 'text-decoration-skip' && value === 'ink') {
result.warn(
'Replace text-decoration-skip: ink to ' +
'text-decoration-skip-ink: auto, because spec had been changed',
{ node: decl }
)
} else {
if (gridPrefixes && this.gridStatus(decl, result)) {
if (decl.value === 'subgrid') {
result.warn('IE does not support subgrid', { node: decl })
}
if (/^(align|justify|place)-items$/.test(prop) && insideGrid(decl)) {
let fixed = prop.replace('-items', '-self')
result.warn(
`IE does not support ${prop} on grid containers. ` +
`Try using ${fixed} on child elements instead: ` +
`${decl.parent.selector} > * { ${fixed}: ${decl.value} }`,
{ node: decl }
)
} else if (
/^(align|justify|place)-content$/.test(prop) &&
insideGrid(decl)
) {
result.warn(`IE does not support ${decl.prop} on grid containers`, {
node: decl
})
} else if (prop === 'display' && decl.value === 'contents') {
result.warn(
'Please do not use display: contents; ' +
'if you have grid setting enabled',
{ node: decl }
)
return undefined
} else if (decl.prop === 'grid-gap') {
let status = this.gridStatus(decl, result)
if (
status === 'autoplace' &&
!hasRowsAndColumns(decl) &&
!hasGridTemplate(decl)
) {
result.warn(
'grid-gap only works if grid-template(-areas) is being ' +
'used or both rows and columns have been declared ' +
'and cells have not been manually ' +
'placed inside the explicit grid',
{ node: decl }
)
} else if (
(status === true || status === 'no-autoplace') &&
!hasGridTemplate(decl)
) {
result.warn(
'grid-gap only works if grid-template(-areas) is being used',
{ node: decl }
)
}
} else if (prop === 'grid-auto-columns') {
result.warn('grid-auto-columns is not supported by IE', {
node: decl
})
return undefined
} else if (prop === 'grid-auto-rows') {
result.warn('grid-auto-rows is not supported by IE', { node: decl })
return undefined
} else if (prop === 'grid-auto-flow') {
let hasRows = parent.some(i => i.prop === 'grid-template-rows')
let hasCols = parent.some(i => i.prop === 'grid-template-columns')
if (hasGridTemplate(decl)) {
result.warn('grid-auto-flow is not supported by IE', {
node: decl
})
} else if (value.includes('dense')) {
result.warn('grid-auto-flow: dense is not supported by IE', {
node: decl
})
} else if (!hasRows && !hasCols) {
result.warn(
'grid-auto-flow works only if grid-template-rows and ' +
'grid-template-columns are present in the same rule',
{ node: decl }
)
}
return undefined
} else if (value.includes('auto-fit')) {
result.warn('auto-fit value is not supported by IE', {
node: decl,
word: 'auto-fit'
})
return undefined
} else if (value.includes('auto-fill')) {
result.warn('auto-fill value is not supported by IE', {
node: decl,
word: 'auto-fill'
})
return undefined
} else if (prop.startsWith('grid-template') && value.includes('[')) {
result.warn(
'Autoprefixer currently does not support line names. ' +
'Try using grid-template-areas instead.',
{ node: decl, word: '[' }
)
}
}
if (value.includes('radial-gradient')) {
if (OLD_RADIAL.test(decl.value)) {
result.warn(
'Gradient has outdated direction syntax. ' +
'New syntax is like `closest-side at 0 0` ' +
'instead of `0 0, closest-side`.',
{ node: decl }
)
} else {
let ast = parser(value)
for (let i of ast.nodes) {
if (i.type === 'function' && i.value === 'radial-gradient') {
for (let word of i.nodes) {
if (word.type === 'word') {
if (word.value === 'cover') {
result.warn(
'Gradient has outdated direction syntax. ' +
'Replace `cover` to `farthest-corner`.',
{ node: decl }
)
} else if (word.value === 'contain') {
result.warn(
'Gradient has outdated direction syntax. ' +
'Replace `contain` to `closest-side`.',
{ node: decl }
)
}
}
}
}
}
}
}
if (value.includes('linear-gradient')) {
if (OLD_LINEAR.test(value)) {
result.warn(
'Gradient has outdated direction syntax. ' +
'New syntax is like `to left` instead of `right`.',
{ node: decl }
)
}
}
}
if (SIZES.includes(decl.prop)) {
if (!decl.value.includes('-fill-available')) {
if (decl.value.includes('fill-available')) {
result.warn(
'Replace fill-available to stretch, ' +
'because spec had been changed',
{ node: decl }
)
} else if (decl.value.includes('fill')) {
let ast = parser(value)
if (ast.nodes.some(i => i.type === 'word' && i.value === 'fill')) {
result.warn(
'Replace fill to stretch, because spec had been changed',
{ node: decl }
)
}
}
}
}
let prefixer
if (decl.prop === 'transition' || decl.prop === 'transition-property') {
// Transition
return this.prefixes.transition.add(decl, result)
} else if (decl.prop === 'align-self') {
// align-self flexbox or grid
let display = this.displayType(decl)
if (display !== 'grid' && this.prefixes.options.flexbox !== false) {
prefixer = this.prefixes.add['align-self']
if (prefixer && prefixer.prefixes) {
prefixer.process(decl)
}
}
if (this.gridStatus(decl, result) !== false) {
prefixer = this.prefixes.add['grid-row-align']
if (prefixer && prefixer.prefixes) {
return prefixer.process(decl, result)
}
}
} else if (decl.prop === 'justify-self') {
// justify-self flexbox or grid
if (this.gridStatus(decl, result) !== false) {
prefixer = this.prefixes.add['grid-column-align']
if (prefixer && prefixer.prefixes) {
return prefixer.process(decl, result)
}
}
} else if (decl.prop === 'place-self') {
prefixer = this.prefixes.add['place-self']
if (
prefixer &&
prefixer.prefixes &&
this.gridStatus(decl, result) !== false
) {
return prefixer.process(decl, result)
}
} else {
// Properties
prefixer = this.prefixes.add[decl.prop]
if (prefixer && prefixer.prefixes) {
return prefixer.process(decl, result)
}
}
return undefined
})
// Insert grid-area prefixes. We need to be able to store the different
// rules as a data and hack API is not enough for this
if (this.gridStatus(css, result)) {
insertAreas(css, this.disabled)
}
// Values
return css.walkDecls(decl => {
if (this.disabledValue(decl, result)) return
let unprefixed = this.prefixes.unprefixed(decl.prop)
let list = this.prefixes.values('add', unprefixed)
if (Array.isArray(list)) {
for (let value of list) {
if (value.process) value.process(decl, result)
}
}
Value.save(this.prefixes, decl)
})
}
/**
* Remove unnecessary pefixes
*/
remove (css, result) {
// At-rules
let resolution = this.prefixes.remove['@resolution']
css.walkAtRules((rule, i) => {
if (this.prefixes.remove[`@${rule.name}`]) {
if (!this.disabled(rule, result)) {
rule.parent.removeChild(i)
}
} else if (
rule.name === 'media' &&
rule.params.includes('-resolution') &&
resolution
) {
resolution.clean(rule)
}
})
// Selectors
for (let checker of this.prefixes.remove.selectors) {
css.walkRules((rule, i) => {
if (checker.check(rule)) {
if (!this.disabled(rule, result)) {
rule.parent.removeChild(i)
}
}
})
}
return css.walkDecls((decl, i) => {
if (this.disabled(decl, result)) return
let rule = decl.parent
let unprefixed = this.prefixes.unprefixed(decl.prop)
// Transition
if (decl.prop === 'transition' || decl.prop === 'transition-property') {
this.prefixes.transition.remove(decl)
}
// Properties
if (
this.prefixes.remove[decl.prop] &&
this.prefixes.remove[decl.prop].remove
) {
let notHack = this.prefixes.group(decl).down(other => {
return this.prefixes.normalize(other.prop) === unprefixed
})
if (unprefixed === 'flex-flow') {
notHack = true
}
if (decl.prop === '-webkit-box-orient') {
let hacks = { 'flex-direction': true, 'flex-flow': true }
if (!decl.parent.some(j => hacks[j.prop])) return
}
if (notHack && !this.withHackValue(decl)) {
if (decl.raw('before').includes('\n')) {
this.reduceSpaces(decl)
}
rule.removeChild(i)
return
}
}
// Values
for (let checker of this.prefixes.values('remove', unprefixed)) {
if (!checker.check) continue
if (!checker.check(decl.value)) continue
unprefixed = checker.unprefixed
let notHack = this.prefixes.group(decl).down(other => {
return other.value.includes(unprefixed)
})
if (notHack) {
rule.removeChild(i)
return
}
}
})
}
/**
* Some rare old values, which is not in standard
*/
withHackValue (decl) {
return decl.prop === '-webkit-background-clip' && decl.value === 'text'
}
/**
* Check for grid/flexbox options.
*/
disabledValue (node, result) {
if (this.gridStatus(node, result) === false && node.type === 'decl') {
if (node.prop === 'display' && node.value.includes('grid')) {
return true
}
}
if (this.prefixes.options.flexbox === false && node.type === 'decl') {
if (node.prop === 'display' && node.value.includes('flex')) {
return true
}
}
return this.disabled(node, result)
}
/**
* Check for grid/flexbox options.
*/
disabledDecl (node, result) {
if (this.gridStatus(node, result) === false && node.type === 'decl') {
if (node.prop.includes('grid') || node.prop === 'justify-items') {
return true
}
}
if (this.prefixes.options.flexbox === false && node.type === 'decl') {
let other = ['order', 'justify-content', 'align-items', 'align-content']
if (node.prop.includes('flex') || other.includes(node.prop)) {
return true
}
}
return this.disabled(node, result)
}
/**
* Check for control comment and global options
*/
disabled (node, result) {
if (!node) return false
if (node._autoprefixerDisabled !== undefined) {
return node._autoprefixerDisabled
}
if (node.parent) {
let p = node.prev()
if (p && p.type === 'comment' && IGNORE_NEXT.test(p.text)) {
node._autoprefixerDisabled = true
node._autoprefixerSelfDisabled = true
return true
}
}
let value = null
if (node.nodes) {
let status
node.each(i => {
if (i.type !== 'comment') return
if (/(!\s*)?autoprefixer:\s*(off|on)/i.test(i.text)) {
if (typeof status !== 'undefined') {
result.warn(
'Second Autoprefixer control comment ' +
'was ignored. Autoprefixer applies control ' +
'comment to whole block, not to next rules.',
{ node: i }
)
} else {
status = /on/i.test(i.text)
}
}
})
if (status !== undefined) {
value = !status
}
}
if (!node.nodes || value === null) {
if (node.parent) {
let isParentDisabled = this.disabled(node.parent, result)
if (node.parent._autoprefixerSelfDisabled === true) {
value = false
} else {
value = isParentDisabled
}
} else {
value = false
}
}
node._autoprefixerDisabled = value
return value
}
/**
* Normalize spaces in cascade declaration group
*/
reduceSpaces (decl) {
let stop = false
this.prefixes.group(decl).up(() => {
stop = true
return true
})
if (stop) {
return
}
let parts = decl.raw('before').split('\n')
let prevMin = parts[parts.length - 1].length
let diff = false
this.prefixes.group(decl).down(other => {
parts = other.raw('before').split('\n')
let last = parts.length - 1
if (parts[last].length > prevMin) {
if (diff === false) {
diff = parts[last].length - prevMin
}
parts[last] = parts[last].slice(0, -diff)
other.raws.before = parts.join('\n')
}
})
}
/**
* Is it flebox or grid rule
*/
displayType (decl) {
for (let i of decl.parent.nodes) {
if (i.prop !== 'display') {
continue
}
if (i.value.includes('flex')) {
return 'flex'
}
if (i.value.includes('grid')) {
return 'grid'
}
}
return false
}
/**
* Set grid option via control comment
*/
gridStatus (node, result) {
if (!node) return false
if (node._autoprefixerGridStatus !== undefined) {
return node._autoprefixerGridStatus
}
let value = null
if (node.nodes) {
let status
node.each(i => {
if (i.type !== 'comment') return
if (GRID_REGEX.test(i.text)) {
let hasAutoplace = /:\s*autoplace/i.test(i.text)
let noAutoplace = /no-autoplace/i.test(i.text)
if (typeof status !== 'undefined') {
result.warn(
'Second Autoprefixer grid control comment was ' +
'ignored. Autoprefixer applies control comments to the whole ' +
'block, not to the next rules.',
{ node: i }
)
} else if (hasAutoplace) {
status = 'autoplace'
} else if (noAutoplace) {
status = true
} else {
status = /on/i.test(i.text)
}
}
})
if (status !== undefined) {
value = status
}
}
if (node.type === 'atrule' && node.name === 'supports') {
let params = node.params
if (params.includes('grid') && params.includes('auto')) {
value = false
}
}
if (!node.nodes || value === null) {
if (node.parent) {
let isParentGrid = this.gridStatus(node.parent, result)
if (node.parent._autoprefixerSelfDisabled === true) {
value = false
} else {
value = isParentGrid
}
} else if (typeof this.prefixes.options.grid !== 'undefined') {
value = this.prefixes.options.grid
} else if (typeof process.env.AUTOPREFIXER_GRID !== 'undefined') {
if (process.env.AUTOPREFIXER_GRID === 'autoplace') {
value = 'autoplace'
} else {
value = true
}
} else {
value = false
}
}
node._autoprefixerGridStatus = value
return value
}
}
module.exports = Processor

View File

@@ -0,0 +1,97 @@
let Fraction = require('fraction.js')
let Prefixer = require('./prefixer')
let utils = require('./utils')
const REGEXP = /(min|max)-resolution\s*:\s*\d*\.?\d+(dppx|dpcm|dpi|x)/gi
const SPLIT = /(min|max)-resolution(\s*:\s*)(\d*\.?\d+)(dppx|dpcm|dpi|x)/i
class Resolution extends Prefixer {
/**
* Return prefixed query name
*/
prefixName (prefix, name) {
if (prefix === '-moz-') {
return name + '--moz-device-pixel-ratio'
} else {
return prefix + name + '-device-pixel-ratio'
}
}
/**
* Return prefixed query
*/
prefixQuery (prefix, name, colon, value, units) {
value = new Fraction(value)
// 1dpcm = 2.54dpi
// 1dppx = 96dpi
if (units === 'dpi') {
value = value.div(96)
} else if (units === 'dpcm') {
value = value.mul(2.54).div(96)
}
value = value.simplify()
if (prefix === '-o-') {
value = value.n + '/' + value.d
}
return this.prefixName(prefix, name) + colon + value
}
/**
* Remove prefixed queries
*/
clean (rule) {
if (!this.bad) {
this.bad = []
for (let prefix of this.prefixes) {
this.bad.push(this.prefixName(prefix, 'min'))
this.bad.push(this.prefixName(prefix, 'max'))
}
}
rule.params = utils.editList(rule.params, queries => {
return queries.filter(query => this.bad.every(i => !query.includes(i)))
})
}
/**
* Add prefixed queries
*/
process (rule) {
let parent = this.parentPrefix(rule)
let prefixes = parent ? [parent] : this.prefixes
rule.params = utils.editList(rule.params, (origin, prefixed) => {
for (let query of origin) {
if (
!query.includes('min-resolution') &&
!query.includes('max-resolution')
) {
prefixed.push(query)
continue
}
for (let prefix of prefixes) {
let processed = query.replace(REGEXP, str => {
let parts = str.match(SPLIT)
return this.prefixQuery(
prefix,
parts[1],
parts[2],
parts[3],
parts[4]
)
})
prefixed.push(processed)
}
prefixed.push(query)
}
return utils.uniq(prefixed)
})
}
}
module.exports = Resolution

View File

@@ -0,0 +1,150 @@
let { list } = require('postcss')
let OldSelector = require('./old-selector')
let Prefixer = require('./prefixer')
let Browsers = require('./browsers')
let utils = require('./utils')
class Selector extends Prefixer {
constructor (name, prefixes, all) {
super(name, prefixes, all)
this.regexpCache = new Map()
}
/**
* Is rule selectors need to be prefixed
*/
check (rule) {
if (rule.selector.includes(this.name)) {
return !!rule.selector.match(this.regexp())
}
return false
}
/**
* Return prefixed version of selector
*/
prefixed (prefix) {
return this.name.replace(/^(\W*)/, `$1${prefix}`)
}
/**
* Lazy loadRegExp for name
*/
regexp (prefix) {
if (!this.regexpCache.has(prefix)) {
let name = prefix ? this.prefixed(prefix) : this.name
this.regexpCache.set(
prefix,
new RegExp(`(^|[^:"'=])${utils.escapeRegexp(name)}`, 'gi')
)
}
return this.regexpCache.get(prefix)
}
/**
* All possible prefixes
*/
possible () {
return Browsers.prefixes()
}
/**
* Return all possible selector prefixes
*/
prefixeds (rule) {
if (rule._autoprefixerPrefixeds) {
if (rule._autoprefixerPrefixeds[this.name]) {
return rule._autoprefixerPrefixeds
}
} else {
rule._autoprefixerPrefixeds = {}
}
let prefixeds = {}
if (rule.selector.includes(',')) {
let ruleParts = list.comma(rule.selector)
let toProcess = ruleParts.filter(el => el.includes(this.name))
for (let prefix of this.possible()) {
prefixeds[prefix] = toProcess
.map(el => this.replace(el, prefix))
.join(', ')
}
} else {
for (let prefix of this.possible()) {
prefixeds[prefix] = this.replace(rule.selector, prefix)
}
}
rule._autoprefixerPrefixeds[this.name] = prefixeds
return rule._autoprefixerPrefixeds
}
/**
* Is rule already prefixed before
*/
already (rule, prefixeds, prefix) {
let index = rule.parent.index(rule) - 1
while (index >= 0) {
let before = rule.parent.nodes[index]
if (before.type !== 'rule') {
return false
}
let some = false
for (let key in prefixeds[this.name]) {
let prefixed = prefixeds[this.name][key]
if (before.selector === prefixed) {
if (prefix === key) {
return true
} else {
some = true
break
}
}
}
if (!some) {
return false
}
index -= 1
}
return false
}
/**
* Replace selectors by prefixed one
*/
replace (selector, prefix) {
return selector.replace(this.regexp(), `$1${this.prefixed(prefix)}`)
}
/**
* Clone and add prefixes for at-rule
*/
add (rule, prefix) {
let prefixeds = this.prefixeds(rule)
if (this.already(rule, prefixeds, prefix)) {
return
}
let cloned = this.clone(rule, { selector: prefixeds[this.name][prefix] })
rule.parent.insertBefore(rule, cloned)
}
/**
* Return function to fast find prefixed selector
*/
old (prefix) {
return new OldSelector(this, prefix)
}
}
module.exports = Selector

View File

@@ -0,0 +1,302 @@
let featureQueries = require('caniuse-lite/data/features/css-featurequeries.js')
let { feature } = require('caniuse-lite')
let { parse } = require('postcss')
let Browsers = require('./browsers')
let brackets = require('./brackets')
let Value = require('./value')
let utils = require('./utils')
let data = feature(featureQueries)
let supported = []
for (let browser in data.stats) {
let versions = data.stats[browser]
for (let version in versions) {
let support = versions[version]
if (/y/.test(support)) {
supported.push(browser + ' ' + version)
}
}
}
class Supports {
constructor (Prefixes, all) {
this.Prefixes = Prefixes
this.all = all
}
/**
* Return prefixer only with @supports supported browsers
*/
prefixer () {
if (this.prefixerCache) {
return this.prefixerCache
}
let filtered = this.all.browsers.selected.filter(i => {
return supported.includes(i)
})
let browsers = new Browsers(
this.all.browsers.data,
filtered,
this.all.options
)
this.prefixerCache = new this.Prefixes(
this.all.data,
browsers,
this.all.options
)
return this.prefixerCache
}
/**
* Parse string into declaration property and value
*/
parse (str) {
let parts = str.split(':')
let prop = parts[0]
let value = parts[1]
if (!value) value = ''
return [prop.trim(), value.trim()]
}
/**
* Create virtual rule to process it by prefixer
*/
virtual (str) {
let [prop, value] = this.parse(str)
let rule = parse('a{}').first
rule.append({ prop, value, raws: { before: '' } })
return rule
}
/**
* Return array of Declaration with all necessary prefixes
*/
prefixed (str) {
let rule = this.virtual(str)
if (this.disabled(rule.first)) {
return rule.nodes
}
let result = { warn: () => null }
let prefixer = this.prefixer().add[rule.first.prop]
prefixer && prefixer.process && prefixer.process(rule.first, result)
for (let decl of rule.nodes) {
for (let value of this.prefixer().values('add', rule.first.prop)) {
value.process(decl)
}
Value.save(this.all, decl)
}
return rule.nodes
}
/**
* Return true if brackets node is "not" word
*/
isNot (node) {
return typeof node === 'string' && /not\s*/i.test(node)
}
/**
* Return true if brackets node is "or" word
*/
isOr (node) {
return typeof node === 'string' && /\s*or\s*/i.test(node)
}
/**
* Return true if brackets node is (prop: value)
*/
isProp (node) {
return (
typeof node === 'object' &&
node.length === 1 &&
typeof node[0] === 'string'
)
}
/**
* Return true if prefixed property has no unprefixed
*/
isHack (all, unprefixed) {
let check = new RegExp(`(\\(|\\s)${utils.escapeRegexp(unprefixed)}:`)
return !check.test(all)
}
/**
* Return true if we need to remove node
*/
toRemove (str, all) {
let [prop, value] = this.parse(str)
let unprefixed = this.all.unprefixed(prop)
let cleaner = this.all.cleaner()
if (
cleaner.remove[prop] &&
cleaner.remove[prop].remove &&
!this.isHack(all, unprefixed)
) {
return true
}
for (let checker of cleaner.values('remove', unprefixed)) {
if (checker.check(value)) {
return true
}
}
return false
}
/**
* Remove all unnecessary prefixes
*/
remove (nodes, all) {
let i = 0
while (i < nodes.length) {
if (
!this.isNot(nodes[i - 1]) &&
this.isProp(nodes[i]) &&
this.isOr(nodes[i + 1])
) {
if (this.toRemove(nodes[i][0], all)) {
nodes.splice(i, 2)
continue
}
i += 2
continue
}
if (typeof nodes[i] === 'object') {
nodes[i] = this.remove(nodes[i], all)
}
i += 1
}
return nodes
}
/**
* Clean brackets with one child
*/
cleanBrackets (nodes) {
return nodes.map(i => {
if (typeof i !== 'object') {
return i
}
if (i.length === 1 && typeof i[0] === 'object') {
return this.cleanBrackets(i[0])
}
return this.cleanBrackets(i)
})
}
/**
* Add " or " between properties and convert it to brackets format
*/
convert (progress) {
let result = ['']
for (let i of progress) {
result.push([`${i.prop}: ${i.value}`])
result.push(' or ')
}
result[result.length - 1] = ''
return result
}
/**
* Compress value functions into a string nodes
*/
normalize (nodes) {
if (typeof nodes !== 'object') {
return nodes
}
nodes = nodes.filter(i => i !== '')
if (typeof nodes[0] === 'string') {
let firstNode = nodes[0].trim()
if (
firstNode.includes(':') ||
firstNode === 'selector' ||
firstNode === 'not selector'
) {
return [brackets.stringify(nodes)]
}
}
return nodes.map(i => this.normalize(i))
}
/**
* Add prefixes
*/
add (nodes, all) {
return nodes.map(i => {
if (this.isProp(i)) {
let prefixed = this.prefixed(i[0])
if (prefixed.length > 1) {
return this.convert(prefixed)
}
return i
}
if (typeof i === 'object') {
return this.add(i, all)
}
return i
})
}
/**
* Add prefixed declaration
*/
process (rule) {
let ast = brackets.parse(rule.params)
ast = this.normalize(ast)
ast = this.remove(ast, rule.params)
ast = this.add(ast, rule.params)
ast = this.cleanBrackets(ast)
rule.params = brackets.stringify(ast)
}
/**
* Check global options
*/
disabled (node) {
if (!this.all.options.grid) {
if (node.prop === 'display' && node.value.includes('grid')) {
return true
}
if (node.prop.includes('grid') || node.prop === 'justify-items') {
return true
}
}
if (this.all.options.flexbox === false) {
if (node.prop === 'display' && node.value.includes('flex')) {
return true
}
let other = ['order', 'justify-content', 'align-items', 'align-content']
if (node.prop.includes('flex') || other.includes(node.prop)) {
return true
}
}
return false
}
}
module.exports = Supports

View File

@@ -0,0 +1,329 @@
let { list } = require('postcss')
let parser = require('postcss-value-parser')
let Browsers = require('./browsers')
let vendor = require('./vendor')
class Transition {
constructor (prefixes) {
this.props = ['transition', 'transition-property']
this.prefixes = prefixes
}
/**
* Process transition and add prefixes for all necessary properties
*/
add (decl, result) {
let prefix, prop
let add = this.prefixes.add[decl.prop]
let vendorPrefixes = this.ruleVendorPrefixes(decl)
let declPrefixes = vendorPrefixes || (add && add.prefixes) || []
let params = this.parse(decl.value)
let names = params.map(i => this.findProp(i))
let added = []
if (names.some(i => i[0] === '-')) {
return
}
for (let param of params) {
prop = this.findProp(param)
if (prop[0] === '-') continue
let prefixer = this.prefixes.add[prop]
if (!prefixer || !prefixer.prefixes) continue
for (prefix of prefixer.prefixes) {
if (vendorPrefixes && !vendorPrefixes.some(p => prefix.includes(p))) {
continue
}
let prefixed = this.prefixes.prefixed(prop, prefix)
if (prefixed !== '-ms-transform' && !names.includes(prefixed)) {
if (!this.disabled(prop, prefix)) {
added.push(this.clone(prop, prefixed, param))
}
}
}
}
params = params.concat(added)
let value = this.stringify(params)
let webkitClean = this.stringify(
this.cleanFromUnprefixed(params, '-webkit-')
)
if (declPrefixes.includes('-webkit-')) {
this.cloneBefore(decl, `-webkit-${decl.prop}`, webkitClean)
}
this.cloneBefore(decl, decl.prop, webkitClean)
if (declPrefixes.includes('-o-')) {
let operaClean = this.stringify(this.cleanFromUnprefixed(params, '-o-'))
this.cloneBefore(decl, `-o-${decl.prop}`, operaClean)
}
for (prefix of declPrefixes) {
if (prefix !== '-webkit-' && prefix !== '-o-') {
let prefixValue = this.stringify(
this.cleanOtherPrefixes(params, prefix)
)
this.cloneBefore(decl, prefix + decl.prop, prefixValue)
}
}
if (value !== decl.value && !this.already(decl, decl.prop, value)) {
this.checkForWarning(result, decl)
decl.cloneBefore()
decl.value = value
}
}
/**
* Find property name
*/
findProp (param) {
let prop = param[0].value
if (/^\d/.test(prop)) {
for (let [i, token] of param.entries()) {
if (i !== 0 && token.type === 'word') {
return token.value
}
}
}
return prop
}
/**
* Does we already have this declaration
*/
already (decl, prop, value) {
return decl.parent.some(i => i.prop === prop && i.value === value)
}
/**
* Add declaration if it is not exist
*/
cloneBefore (decl, prop, value) {
if (!this.already(decl, prop, value)) {
decl.cloneBefore({ prop, value })
}
}
/**
* Show transition-property warning
*/
checkForWarning (result, decl) {
if (decl.prop !== 'transition-property') {
return
}
let isPrefixed = false
let hasAssociatedProp = false
decl.parent.each(i => {
if (i.type !== 'decl') {
return undefined
}
if (i.prop.indexOf('transition-') !== 0) {
return undefined
}
let values = list.comma(i.value)
// check if current Rule's transition-property comma separated value list needs prefixes
if (i.prop === 'transition-property') {
values.forEach(value => {
let lookup = this.prefixes.add[value]
if (lookup && lookup.prefixes && lookup.prefixes.length > 0) {
isPrefixed = true
}
})
return undefined
}
// check if another transition-* prop in current Rule has comma separated value list
hasAssociatedProp = hasAssociatedProp || values.length > 1
return false
})
if (isPrefixed && hasAssociatedProp) {
decl.warn(
result,
'Replace transition-property to transition, ' +
'because Autoprefixer could not support ' +
'any cases of transition-property ' +
'and other transition-*'
)
}
}
/**
* Process transition and remove all unnecessary properties
*/
remove (decl) {
let params = this.parse(decl.value)
params = params.filter(i => {
let prop = this.prefixes.remove[this.findProp(i)]
return !prop || !prop.remove
})
let value = this.stringify(params)
if (decl.value === value) {
return
}
if (params.length === 0) {
decl.remove()
return
}
let double = decl.parent.some(i => {
return i.prop === decl.prop && i.value === value
})
let smaller = decl.parent.some(i => {
return i !== decl && i.prop === decl.prop && i.value.length > value.length
})
if (double || smaller) {
decl.remove()
return
}
decl.value = value
}
/**
* Parse properties list to array
*/
parse (value) {
let ast = parser(value)
let result = []
let param = []
for (let node of ast.nodes) {
param.push(node)
if (node.type === 'div' && node.value === ',') {
result.push(param)
param = []
}
}
result.push(param)
return result.filter(i => i.length > 0)
}
/**
* Return properties string from array
*/
stringify (params) {
if (params.length === 0) {
return ''
}
let nodes = []
for (let param of params) {
if (param[param.length - 1].type !== 'div') {
param.push(this.div(params))
}
nodes = nodes.concat(param)
}
if (nodes[0].type === 'div') {
nodes = nodes.slice(1)
}
if (nodes[nodes.length - 1].type === 'div') {
nodes = nodes.slice(0, +-2 + 1 || undefined)
}
return parser.stringify({ nodes })
}
/**
* Return new param array with different name
*/
clone (origin, name, param) {
let result = []
let changed = false
for (let i of param) {
if (!changed && i.type === 'word' && i.value === origin) {
result.push({ type: 'word', value: name })
changed = true
} else {
result.push(i)
}
}
return result
}
/**
* Find or create separator
*/
div (params) {
for (let param of params) {
for (let node of param) {
if (node.type === 'div' && node.value === ',') {
return node
}
}
}
return { type: 'div', value: ',', after: ' ' }
}
cleanOtherPrefixes (params, prefix) {
return params.filter(param => {
let current = vendor.prefix(this.findProp(param))
return current === '' || current === prefix
})
}
/**
* Remove all non-webkit prefixes and unprefixed params if we have prefixed
*/
cleanFromUnprefixed (params, prefix) {
let remove = params
.map(i => this.findProp(i))
.filter(i => i.slice(0, prefix.length) === prefix)
.map(i => this.prefixes.unprefixed(i))
let result = []
for (let param of params) {
let prop = this.findProp(param)
let p = vendor.prefix(prop)
if (!remove.includes(prop) && (p === prefix || p === '')) {
result.push(param)
}
}
return result
}
/**
* Check property for disabled by option
*/
disabled (prop, prefix) {
let other = ['order', 'justify-content', 'align-self', 'align-content']
if (prop.includes('flex') || other.includes(prop)) {
if (this.prefixes.options.flexbox === false) {
return true
}
if (this.prefixes.options.flexbox === 'no-2009') {
return prefix.includes('2009')
}
}
return undefined
}
/**
* Check if transition prop is inside vendor specific rule
*/
ruleVendorPrefixes (decl) {
let { parent } = decl
if (parent.type !== 'rule') {
return false
} else if (!parent.selector.includes(':-')) {
return false
}
let selectors = Browsers.prefixes().filter(s =>
parent.selector.includes(':' + s)
)
return selectors.length > 0 ? selectors : false
}
}
module.exports = Transition

View File

@@ -0,0 +1,80 @@
let { list } = require('postcss')
module.exports = {
/**
* Throw special error, to tell beniary,
* that this error is from Autoprefixer.
*/
error (text) {
let err = new Error(text)
err.autoprefixer = true
throw err
},
/**
* Return array, that doesnt contain duplicates.
*/
uniq (array) {
return [...new Set(array)]
},
/**
* Return "-webkit-" on "-webkit- old"
*/
removeNote (string) {
if (!string.includes(' ')) {
return string
}
return string.split(' ')[0]
},
/**
* Escape RegExp symbols
*/
escapeRegexp (string) {
return string.replace(/[$()*+-.?[\\\]^{|}]/g, '\\$&')
},
/**
* Return regexp to check, that CSS string contain word
*/
regexp (word, escape = true) {
if (escape) {
word = this.escapeRegexp(word)
}
return new RegExp(`(^|[\\s,(])(${word}($|[\\s(,]))`, 'gi')
},
/**
* Change comma list
*/
editList (value, callback) {
let origin = list.comma(value)
let changed = callback(origin, [])
if (origin === changed) {
return value
}
let join = value.match(/,\s*/)
join = join ? join[0] : ', '
return changed.join(join)
},
/**
* Split the selector into parts.
* It returns 3 level deep array because selectors can be comma
* separated (1), space separated (2), and combined (3)
* @param {String} selector selector string
* @return {Array<Array<Array>>} 3 level deep array of split selector
* @see utils.test.js for examples
*/
splitSelector (selector) {
return list.comma(selector).map(i => {
return list.space(i).map(k => {
return k.split(/(?=\.|#)/g)
})
})
}
}

View File

@@ -0,0 +1,125 @@
let Prefixer = require('./prefixer')
let OldValue = require('./old-value')
let vendor = require('./vendor')
let utils = require('./utils')
class Value extends Prefixer {
/**
* Clone decl for each prefixed values
*/
static save (prefixes, decl) {
let prop = decl.prop
let result = []
for (let prefix in decl._autoprefixerValues) {
let value = decl._autoprefixerValues[prefix]
if (value === decl.value) {
continue
}
let item
let propPrefix = vendor.prefix(prop)
if (propPrefix === '-pie-') {
continue
}
if (propPrefix === prefix) {
item = decl.value = value
result.push(item)
continue
}
let prefixed = prefixes.prefixed(prop, prefix)
let rule = decl.parent
if (!rule.every(i => i.prop !== prefixed)) {
result.push(item)
continue
}
let trimmed = value.replace(/\s+/, ' ')
let already = rule.some(
i => i.prop === decl.prop && i.value.replace(/\s+/, ' ') === trimmed
)
if (already) {
result.push(item)
continue
}
let cloned = this.clone(decl, { value })
item = decl.parent.insertBefore(decl, cloned)
result.push(item)
}
return result
}
/**
* Is declaration need to be prefixed
*/
check (decl) {
let value = decl.value
if (!value.includes(this.name)) {
return false
}
return !!value.match(this.regexp())
}
/**
* Lazy regexp loading
*/
regexp () {
return this.regexpCache || (this.regexpCache = utils.regexp(this.name))
}
/**
* Add prefix to values in string
*/
replace (string, prefix) {
return string.replace(this.regexp(), `$1${prefix}$2`)
}
/**
* Get value with comments if it was not changed
*/
value (decl) {
if (decl.raws.value && decl.raws.value.value === decl.value) {
return decl.raws.value.raw
} else {
return decl.value
}
}
/**
* Save values with next prefixed token
*/
add (decl, prefix) {
if (!decl._autoprefixerValues) {
decl._autoprefixerValues = {}
}
let value = decl._autoprefixerValues[prefix] || this.value(decl)
let before
do {
before = value
value = this.replace(value, prefix)
if (value === false) return
} while (value !== before)
decl._autoprefixerValues[prefix] = value
}
/**
* Return function to fast find prefixed value
*/
old (prefix) {
return new OldValue(this.name, prefix + this.name)
}
}
module.exports = Value

View File

@@ -0,0 +1,14 @@
module.exports = {
prefix (prop) {
let match = prop.match(/^(-\w+-)/)
if (match) {
return match[0]
}
return ''
},
unprefixed (prop) {
return prop.replace(/^-\w+-/, '')
}
}

View File

@@ -0,0 +1 @@
../../../../../browserslist/cli.js

View File

@@ -0,0 +1,10 @@
{
"compilerOptions": {
"target": "es2018",
"module": "commonjs",
"allowJs": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true
}
}

View File

@@ -0,0 +1,415 @@
/**
Basic foreground colors.
[More colors here.](https://github.com/chalk/chalk/blob/master/readme.md#256-and-truecolor-color-support)
*/
declare type ForegroundColor =
| 'black'
| 'red'
| 'green'
| 'yellow'
| 'blue'
| 'magenta'
| 'cyan'
| 'white'
| 'gray'
| 'grey'
| 'blackBright'
| 'redBright'
| 'greenBright'
| 'yellowBright'
| 'blueBright'
| 'magentaBright'
| 'cyanBright'
| 'whiteBright';
/**
Basic background colors.
[More colors here.](https://github.com/chalk/chalk/blob/master/readme.md#256-and-truecolor-color-support)
*/
declare type BackgroundColor =
| 'bgBlack'
| 'bgRed'
| 'bgGreen'
| 'bgYellow'
| 'bgBlue'
| 'bgMagenta'
| 'bgCyan'
| 'bgWhite'
| 'bgGray'
| 'bgGrey'
| 'bgBlackBright'
| 'bgRedBright'
| 'bgGreenBright'
| 'bgYellowBright'
| 'bgBlueBright'
| 'bgMagentaBright'
| 'bgCyanBright'
| 'bgWhiteBright';
/**
Basic colors.
[More colors here.](https://github.com/chalk/chalk/blob/master/readme.md#256-and-truecolor-color-support)
*/
declare type Color = ForegroundColor | BackgroundColor;
declare type Modifiers =
| 'reset'
| 'bold'
| 'dim'
| 'italic'
| 'underline'
| 'inverse'
| 'hidden'
| 'strikethrough'
| 'visible';
declare namespace chalk {
/**
Levels:
- `0` - All colors disabled.
- `1` - Basic 16 colors support.
- `2` - ANSI 256 colors support.
- `3` - Truecolor 16 million colors support.
*/
type Level = 0 | 1 | 2 | 3;
interface Options {
/**
Specify the color support for Chalk.
By default, color support is automatically detected based on the environment.
Levels:
- `0` - All colors disabled.
- `1` - Basic 16 colors support.
- `2` - ANSI 256 colors support.
- `3` - Truecolor 16 million colors support.
*/
level?: Level;
}
/**
Return a new Chalk instance.
*/
type Instance = new (options?: Options) => Chalk;
/**
Detect whether the terminal supports color.
*/
interface ColorSupport {
/**
The color level used by Chalk.
*/
level: Level;
/**
Return whether Chalk supports basic 16 colors.
*/
hasBasic: boolean;
/**
Return whether Chalk supports ANSI 256 colors.
*/
has256: boolean;
/**
Return whether Chalk supports Truecolor 16 million colors.
*/
has16m: boolean;
}
interface ChalkFunction {
/**
Use a template string.
@remarks Template literals are unsupported for nested calls (see [issue #341](https://github.com/chalk/chalk/issues/341))
@example
```
import chalk = require('chalk');
log(chalk`
CPU: {red ${cpu.totalPercent}%}
RAM: {green ${ram.used / ram.total * 100}%}
DISK: {rgb(255,131,0) ${disk.used / disk.total * 100}%}
`);
```
@example
```
import chalk = require('chalk');
log(chalk.red.bgBlack`2 + 3 = {bold ${2 + 3}}`)
```
*/
(text: TemplateStringsArray, ...placeholders: unknown[]): string;
(...text: unknown[]): string;
}
interface Chalk extends ChalkFunction {
/**
Return a new Chalk instance.
*/
Instance: Instance;
/**
The color support for Chalk.
By default, color support is automatically detected based on the environment.
Levels:
- `0` - All colors disabled.
- `1` - Basic 16 colors support.
- `2` - ANSI 256 colors support.
- `3` - Truecolor 16 million colors support.
*/
level: Level;
/**
Use HEX value to set text color.
@param color - Hexadecimal value representing the desired color.
@example
```
import chalk = require('chalk');
chalk.hex('#DEADED');
```
*/
hex(color: string): Chalk;
/**
Use keyword color value to set text color.
@param color - Keyword value representing the desired color.
@example
```
import chalk = require('chalk');
chalk.keyword('orange');
```
*/
keyword(color: string): Chalk;
/**
Use RGB values to set text color.
*/
rgb(red: number, green: number, blue: number): Chalk;
/**
Use HSL values to set text color.
*/
hsl(hue: number, saturation: number, lightness: number): Chalk;
/**
Use HSV values to set text color.
*/
hsv(hue: number, saturation: number, value: number): Chalk;
/**
Use HWB values to set text color.
*/
hwb(hue: number, whiteness: number, blackness: number): Chalk;
/**
Use a [Select/Set Graphic Rendition](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters) (SGR) [color code number](https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit) to set text color.
30 <= code && code < 38 || 90 <= code && code < 98
For example, 31 for red, 91 for redBright.
*/
ansi(code: number): Chalk;
/**
Use a [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set text color.
*/
ansi256(index: number): Chalk;
/**
Use HEX value to set background color.
@param color - Hexadecimal value representing the desired color.
@example
```
import chalk = require('chalk');
chalk.bgHex('#DEADED');
```
*/
bgHex(color: string): Chalk;
/**
Use keyword color value to set background color.
@param color - Keyword value representing the desired color.
@example
```
import chalk = require('chalk');
chalk.bgKeyword('orange');
```
*/
bgKeyword(color: string): Chalk;
/**
Use RGB values to set background color.
*/
bgRgb(red: number, green: number, blue: number): Chalk;
/**
Use HSL values to set background color.
*/
bgHsl(hue: number, saturation: number, lightness: number): Chalk;
/**
Use HSV values to set background color.
*/
bgHsv(hue: number, saturation: number, value: number): Chalk;
/**
Use HWB values to set background color.
*/
bgHwb(hue: number, whiteness: number, blackness: number): Chalk;
/**
Use a [Select/Set Graphic Rendition](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters) (SGR) [color code number](https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit) to set background color.
30 <= code && code < 38 || 90 <= code && code < 98
For example, 31 for red, 91 for redBright.
Use the foreground code, not the background code (for example, not 41, nor 101).
*/
bgAnsi(code: number): Chalk;
/**
Use a [8-bit unsigned number](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) to set background color.
*/
bgAnsi256(index: number): Chalk;
/**
Modifier: Resets the current color chain.
*/
readonly reset: Chalk;
/**
Modifier: Make text bold.
*/
readonly bold: Chalk;
/**
Modifier: Emitting only a small amount of light.
*/
readonly dim: Chalk;
/**
Modifier: Make text italic. (Not widely supported)
*/
readonly italic: Chalk;
/**
Modifier: Make text underline. (Not widely supported)
*/
readonly underline: Chalk;
/**
Modifier: Inverse background and foreground colors.
*/
readonly inverse: Chalk;
/**
Modifier: Prints the text, but makes it invisible.
*/
readonly hidden: Chalk;
/**
Modifier: Puts a horizontal line through the center of the text. (Not widely supported)
*/
readonly strikethrough: Chalk;
/**
Modifier: Prints the text only when Chalk has a color support level > 0.
Can be useful for things that are purely cosmetic.
*/
readonly visible: Chalk;
readonly black: Chalk;
readonly red: Chalk;
readonly green: Chalk;
readonly yellow: Chalk;
readonly blue: Chalk;
readonly magenta: Chalk;
readonly cyan: Chalk;
readonly white: Chalk;
/*
Alias for `blackBright`.
*/
readonly gray: Chalk;
/*
Alias for `blackBright`.
*/
readonly grey: Chalk;
readonly blackBright: Chalk;
readonly redBright: Chalk;
readonly greenBright: Chalk;
readonly yellowBright: Chalk;
readonly blueBright: Chalk;
readonly magentaBright: Chalk;
readonly cyanBright: Chalk;
readonly whiteBright: Chalk;
readonly bgBlack: Chalk;
readonly bgRed: Chalk;
readonly bgGreen: Chalk;
readonly bgYellow: Chalk;
readonly bgBlue: Chalk;
readonly bgMagenta: Chalk;
readonly bgCyan: Chalk;
readonly bgWhite: Chalk;
/*
Alias for `bgBlackBright`.
*/
readonly bgGray: Chalk;
/*
Alias for `bgBlackBright`.
*/
readonly bgGrey: Chalk;
readonly bgBlackBright: Chalk;
readonly bgRedBright: Chalk;
readonly bgGreenBright: Chalk;
readonly bgYellowBright: Chalk;
readonly bgBlueBright: Chalk;
readonly bgMagentaBright: Chalk;
readonly bgCyanBright: Chalk;
readonly bgWhiteBright: Chalk;
}
}
/**
Main Chalk object that allows to chain styles together.
Call the last one as a method with a string argument.
Order doesn't matter, and later styles take precedent in case of a conflict.
This simply means that `chalk.red.yellow.green` is equivalent to `chalk.green`.
*/
declare const chalk: chalk.Chalk & chalk.ChalkFunction & {
supportsColor: chalk.ColorSupport | false;
Level: chalk.Level;
Color: Color;
ForegroundColor: ForegroundColor;
BackgroundColor: BackgroundColor;
Modifiers: Modifiers;
stderr: chalk.Chalk & {supportsColor: chalk.ColorSupport | false};
};
export = chalk;

View File

@@ -0,0 +1,9 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,335 @@
<h1 align="center">
<br>
<br>
<img width="320" src="media/logo.svg" alt="Chalk">
<br>
<br>
<br>
</h1>
> Terminal string styling done right
[![Build Status](https://travis-ci.org/chalk/chalk.svg?branch=master)](https://travis-ci.org/chalk/chalk) [![Coverage Status](https://coveralls.io/repos/github/chalk/chalk/badge.svg?branch=master)](https://coveralls.io/github/chalk/chalk?branch=master) [![npm dependents](https://badgen.net/npm/dependents/chalk)](https://www.npmjs.com/package/chalk?activeTab=dependents) [![Downloads](https://badgen.net/npm/dt/chalk)](https://www.npmjs.com/package/chalk) [![](https://img.shields.io/badge/unicorn-approved-ff69b4.svg)](https://www.youtube.com/watch?v=9auOCbH5Ns4) [![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/xojs/xo) ![TypeScript-ready](https://img.shields.io/npm/types/chalk.svg) [![run on repl.it](https://repl.it/badge/github/chalk/chalk)](https://repl.it/github/chalk/chalk)
<img src="https://cdn.jsdelivr.net/gh/chalk/ansi-styles@8261697c95bf34b6c7767e2cbe9941a851d59385/screenshot.svg" width="900">
<br>
---
<div align="center">
<p>
<p>
<sup>
Sindre Sorhus' open source work is supported by the community on <a href="https://github.com/sponsors/sindresorhus">GitHub Sponsors</a> and <a href="https://stakes.social/0x44d871aebF0126Bf646753E2C976Aa7e68A66c15">Dev</a>
</sup>
</p>
<sup>Special thanks to:</sup>
<br>
<br>
<a href="https://standardresume.co/tech">
<img src="https://sindresorhus.com/assets/thanks/standard-resume-logo.svg" width="160"/>
</a>
<br>
<br>
<a href="https://retool.com/?utm_campaign=sindresorhus">
<img src="https://sindresorhus.com/assets/thanks/retool-logo.svg" width="210"/>
</a>
<br>
<br>
<a href="https://doppler.com/?utm_campaign=github_repo&utm_medium=referral&utm_content=chalk&utm_source=github">
<div>
<img src="https://dashboard.doppler.com/imgs/logo-long.svg" width="240" alt="Doppler">
</div>
<b>All your environment variables, in one place</b>
<div>
<span>Stop struggling with scattered API keys, hacking together home-brewed tools,</span>
<br>
<span>and avoiding access controls. Keep your team and servers in sync with Doppler.</span>
</div>
</a>
</p>
</div>
---
<br>
## Highlights
- Expressive API
- Highly performant
- Ability to nest styles
- [256/Truecolor color support](#256-and-truecolor-color-support)
- Auto-detects color support
- Doesn't extend `String.prototype`
- Clean and focused
- Actively maintained
- [Used by ~50,000 packages](https://www.npmjs.com/browse/depended/chalk) as of January 1, 2020
## Install
```console
$ npm install chalk
```
## Usage
```js
const chalk = require('chalk');
console.log(chalk.blue('Hello world!'));
```
Chalk comes with an easy to use composable API where you just chain and nest the styles you want.
```js
const chalk = require('chalk');
const log = console.log;
// Combine styled and normal strings
log(chalk.blue('Hello') + ' World' + chalk.red('!'));
// Compose multiple styles using the chainable API
log(chalk.blue.bgRed.bold('Hello world!'));
// Pass in multiple arguments
log(chalk.blue('Hello', 'World!', 'Foo', 'bar', 'biz', 'baz'));
// Nest styles
log(chalk.red('Hello', chalk.underline.bgBlue('world') + '!'));
// Nest styles of the same type even (color, underline, background)
log(chalk.green(
'I am a green line ' +
chalk.blue.underline.bold('with a blue substring') +
' that becomes green again!'
));
// ES2015 template literal
log(`
CPU: ${chalk.red('90%')}
RAM: ${chalk.green('40%')}
DISK: ${chalk.yellow('70%')}
`);
// ES2015 tagged template literal
log(chalk`
CPU: {red ${cpu.totalPercent}%}
RAM: {green ${ram.used / ram.total * 100}%}
DISK: {rgb(255,131,0) ${disk.used / disk.total * 100}%}
`);
// Use RGB colors in terminal emulators that support it.
log(chalk.keyword('orange')('Yay for orange colored text!'));
log(chalk.rgb(123, 45, 67).underline('Underlined reddish color'));
log(chalk.hex('#DEADED').bold('Bold gray!'));
```
Easily define your own themes:
```js
const chalk = require('chalk');
const error = chalk.bold.red;
const warning = chalk.keyword('orange');
console.log(error('Error!'));
console.log(warning('Warning!'));
```
Take advantage of console.log [string substitution](https://nodejs.org/docs/latest/api/console.html#console_console_log_data_args):
```js
const name = 'Sindre';
console.log(chalk.green('Hello %s'), name);
//=> 'Hello Sindre'
```
## API
### chalk.`<style>[.<style>...](string, [string...])`
Example: `chalk.red.bold.underline('Hello', 'world');`
Chain [styles](#styles) and call the last one as a method with a string argument. Order doesn't matter, and later styles take precedent in case of a conflict. This simply means that `chalk.red.yellow.green` is equivalent to `chalk.green`.
Multiple arguments will be separated by space.
### chalk.level
Specifies the level of color support.
Color support is automatically detected, but you can override it by setting the `level` property. You should however only do this in your own code as it applies globally to all Chalk consumers.
If you need to change this in a reusable module, create a new instance:
```js
const ctx = new chalk.Instance({level: 0});
```
| Level | Description |
| :---: | :--- |
| `0` | All colors disabled |
| `1` | Basic color support (16 colors) |
| `2` | 256 color support |
| `3` | Truecolor support (16 million colors) |
### chalk.supportsColor
Detect whether the terminal [supports color](https://github.com/chalk/supports-color). Used internally and handled for you, but exposed for convenience.
Can be overridden by the user with the flags `--color` and `--no-color`. For situations where using `--color` is not possible, use the environment variable `FORCE_COLOR=1` (level 1), `FORCE_COLOR=2` (level 2), or `FORCE_COLOR=3` (level 3) to forcefully enable color, or `FORCE_COLOR=0` to forcefully disable. The use of `FORCE_COLOR` overrides all other color support checks.
Explicit 256/Truecolor mode can be enabled using the `--color=256` and `--color=16m` flags, respectively.
### chalk.stderr and chalk.stderr.supportsColor
`chalk.stderr` contains a separate instance configured with color support detected for `stderr` stream instead of `stdout`. Override rules from `chalk.supportsColor` apply to this too. `chalk.stderr.supportsColor` is exposed for convenience.
## Styles
### Modifiers
- `reset` - Resets the current color chain.
- `bold` - Make text bold.
- `dim` - Emitting only a small amount of light.
- `italic` - Make text italic. *(Not widely supported)*
- `underline` - Make text underline. *(Not widely supported)*
- `inverse`- Inverse background and foreground colors.
- `hidden` - Prints the text, but makes it invisible.
- `strikethrough` - Puts a horizontal line through the center of the text. *(Not widely supported)*
- `visible`- Prints the text only when Chalk has a color level > 0. Can be useful for things that are purely cosmetic.
### Colors
- `black`
- `red`
- `green`
- `yellow`
- `blue`
- `magenta`
- `cyan`
- `white`
- `blackBright` (alias: `gray`, `grey`)
- `redBright`
- `greenBright`
- `yellowBright`
- `blueBright`
- `magentaBright`
- `cyanBright`
- `whiteBright`
### Background colors
- `bgBlack`
- `bgRed`
- `bgGreen`
- `bgYellow`
- `bgBlue`
- `bgMagenta`
- `bgCyan`
- `bgWhite`
- `bgBlackBright` (alias: `bgGray`, `bgGrey`)
- `bgRedBright`
- `bgGreenBright`
- `bgYellowBright`
- `bgBlueBright`
- `bgMagentaBright`
- `bgCyanBright`
- `bgWhiteBright`
## Tagged template literal
Chalk can be used as a [tagged template literal](https://exploringjs.com/es6/ch_template-literals.html#_tagged-template-literals).
```js
const chalk = require('chalk');
const miles = 18;
const calculateFeet = miles => miles * 5280;
console.log(chalk`
There are {bold 5280 feet} in a mile.
In {bold ${miles} miles}, there are {green.bold ${calculateFeet(miles)} feet}.
`);
```
Blocks are delimited by an opening curly brace (`{`), a style, some content, and a closing curly brace (`}`).
Template styles are chained exactly like normal Chalk styles. The following three statements are equivalent:
```js
console.log(chalk.bold.rgb(10, 100, 200)('Hello!'));
console.log(chalk.bold.rgb(10, 100, 200)`Hello!`);
console.log(chalk`{bold.rgb(10,100,200) Hello!}`);
```
Note that function styles (`rgb()`, `hsl()`, `keyword()`, etc.) may not contain spaces between parameters.
All interpolated values (`` chalk`${foo}` ``) are converted to strings via the `.toString()` method. All curly braces (`{` and `}`) in interpolated value strings are escaped.
## 256 and Truecolor color support
Chalk supports 256 colors and [Truecolor](https://gist.github.com/XVilka/8346728) (16 million colors) on supported terminal apps.
Colors are downsampled from 16 million RGB values to an ANSI color format that is supported by the terminal emulator (or by specifying `{level: n}` as a Chalk option). For example, Chalk configured to run at level 1 (basic color support) will downsample an RGB value of #FF0000 (red) to 31 (ANSI escape for red).
Examples:
- `chalk.hex('#DEADED').underline('Hello, world!')`
- `chalk.keyword('orange')('Some orange text')`
- `chalk.rgb(15, 100, 204).inverse('Hello!')`
Background versions of these models are prefixed with `bg` and the first level of the module capitalized (e.g. `keyword` for foreground colors and `bgKeyword` for background colors).
- `chalk.bgHex('#DEADED').underline('Hello, world!')`
- `chalk.bgKeyword('orange')('Some orange text')`
- `chalk.bgRgb(15, 100, 204).inverse('Hello!')`
The following color models can be used:
- [`rgb`](https://en.wikipedia.org/wiki/RGB_color_model) - Example: `chalk.rgb(255, 136, 0).bold('Orange!')`
- [`hex`](https://en.wikipedia.org/wiki/Web_colors#Hex_triplet) - Example: `chalk.hex('#FF8800').bold('Orange!')`
- [`keyword`](https://www.w3.org/wiki/CSS/Properties/color/keywords) (CSS keywords) - Example: `chalk.keyword('orange').bold('Orange!')`
- [`hsl`](https://en.wikipedia.org/wiki/HSL_and_HSV) - Example: `chalk.hsl(32, 100, 50).bold('Orange!')`
- [`hsv`](https://en.wikipedia.org/wiki/HSL_and_HSV) - Example: `chalk.hsv(32, 100, 100).bold('Orange!')`
- [`hwb`](https://en.wikipedia.org/wiki/HWB_color_model) - Example: `chalk.hwb(32, 0, 50).bold('Orange!')`
- [`ansi`](https://en.wikipedia.org/wiki/ANSI_escape_code#3/4_bit) - Example: `chalk.ansi(31).bgAnsi(93)('red on yellowBright')`
- [`ansi256`](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) - Example: `chalk.bgAnsi256(194)('Honeydew, more or less')`
## Windows
If you're on Windows, do yourself a favor and use [Windows Terminal](https://github.com/microsoft/terminal) instead of `cmd.exe`.
## Origin story
[colors.js](https://github.com/Marak/colors.js) used to be the most popular string styling module, but it has serious deficiencies like extending `String.prototype` which causes all kinds of [problems](https://github.com/yeoman/yo/issues/68) and the package is unmaintained. Although there are other packages, they either do too much or not enough. Chalk is a clean and focused alternative.
## chalk for enterprise
Available as part of the Tidelift Subscription.
The maintainers of chalk and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/npm-chalk?utm_source=npm-chalk&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
## Related
- [chalk-cli](https://github.com/chalk/chalk-cli) - CLI for this module
- [ansi-styles](https://github.com/chalk/ansi-styles) - ANSI escape codes for styling strings in the terminal
- [supports-color](https://github.com/chalk/supports-color) - Detect whether a terminal supports color
- [strip-ansi](https://github.com/chalk/strip-ansi) - Strip ANSI escape codes
- [strip-ansi-stream](https://github.com/chalk/strip-ansi-stream) - Strip ANSI escape codes from a stream
- [has-ansi](https://github.com/chalk/has-ansi) - Check if a string has ANSI escape codes
- [ansi-regex](https://github.com/chalk/ansi-regex) - Regular expression for matching ANSI escape codes
- [wrap-ansi](https://github.com/chalk/wrap-ansi) - Wordwrap a string with ANSI escape codes
- [slice-ansi](https://github.com/chalk/slice-ansi) - Slice a string with ANSI escape codes
- [color-convert](https://github.com/qix-/color-convert) - Converts colors between different models
- [chalk-animation](https://github.com/bokub/chalk-animation) - Animate strings in the terminal
- [gradient-string](https://github.com/bokub/gradient-string) - Apply color gradients to strings
- [chalk-pipe](https://github.com/LitoMore/chalk-pipe) - Create chalk style schemes with simpler style strings
- [terminal-link](https://github.com/sindresorhus/terminal-link) - Create clickable links in the terminal
## Maintainers
- [Sindre Sorhus](https://github.com/sindresorhus)
- [Josh Junon](https://github.com/qix-)

View File

@@ -0,0 +1,229 @@
'use strict';
const ansiStyles = require('ansi-styles');
const {stdout: stdoutColor, stderr: stderrColor} = require('supports-color');
const {
stringReplaceAll,
stringEncaseCRLFWithFirstIndex
} = require('./util');
const {isArray} = Array;
// `supportsColor.level` → `ansiStyles.color[name]` mapping
const levelMapping = [
'ansi',
'ansi',
'ansi256',
'ansi16m'
];
const styles = Object.create(null);
const applyOptions = (object, options = {}) => {
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {
throw new Error('The `level` option should be an integer from 0 to 3');
}
// Detect level if not set manually
const colorLevel = stdoutColor ? stdoutColor.level : 0;
object.level = options.level === undefined ? colorLevel : options.level;
};
class ChalkClass {
constructor(options) {
// eslint-disable-next-line no-constructor-return
return chalkFactory(options);
}
}
const chalkFactory = options => {
const chalk = {};
applyOptions(chalk, options);
chalk.template = (...arguments_) => chalkTag(chalk.template, ...arguments_);
Object.setPrototypeOf(chalk, Chalk.prototype);
Object.setPrototypeOf(chalk.template, chalk);
chalk.template.constructor = () => {
throw new Error('`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.');
};
chalk.template.Instance = ChalkClass;
return chalk.template;
};
function Chalk(options) {
return chalkFactory(options);
}
for (const [styleName, style] of Object.entries(ansiStyles)) {
styles[styleName] = {
get() {
const builder = createBuilder(this, createStyler(style.open, style.close, this._styler), this._isEmpty);
Object.defineProperty(this, styleName, {value: builder});
return builder;
}
};
}
styles.visible = {
get() {
const builder = createBuilder(this, this._styler, true);
Object.defineProperty(this, 'visible', {value: builder});
return builder;
}
};
const usedModels = ['rgb', 'hex', 'keyword', 'hsl', 'hsv', 'hwb', 'ansi', 'ansi256'];
for (const model of usedModels) {
styles[model] = {
get() {
const {level} = this;
return function (...arguments_) {
const styler = createStyler(ansiStyles.color[levelMapping[level]][model](...arguments_), ansiStyles.color.close, this._styler);
return createBuilder(this, styler, this._isEmpty);
};
}
};
}
for (const model of usedModels) {
const bgModel = 'bg' + model[0].toUpperCase() + model.slice(1);
styles[bgModel] = {
get() {
const {level} = this;
return function (...arguments_) {
const styler = createStyler(ansiStyles.bgColor[levelMapping[level]][model](...arguments_), ansiStyles.bgColor.close, this._styler);
return createBuilder(this, styler, this._isEmpty);
};
}
};
}
const proto = Object.defineProperties(() => {}, {
...styles,
level: {
enumerable: true,
get() {
return this._generator.level;
},
set(level) {
this._generator.level = level;
}
}
});
const createStyler = (open, close, parent) => {
let openAll;
let closeAll;
if (parent === undefined) {
openAll = open;
closeAll = close;
} else {
openAll = parent.openAll + open;
closeAll = close + parent.closeAll;
}
return {
open,
close,
openAll,
closeAll,
parent
};
};
const createBuilder = (self, _styler, _isEmpty) => {
const builder = (...arguments_) => {
if (isArray(arguments_[0]) && isArray(arguments_[0].raw)) {
// Called as a template literal, for example: chalk.red`2 + 3 = {bold ${2+3}}`
return applyStyle(builder, chalkTag(builder, ...arguments_));
}
// Single argument is hot path, implicit coercion is faster than anything
// eslint-disable-next-line no-implicit-coercion
return applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' '));
};
// We alter the prototype because we must return a function, but there is
// no way to create a function with a different prototype
Object.setPrototypeOf(builder, proto);
builder._generator = self;
builder._styler = _styler;
builder._isEmpty = _isEmpty;
return builder;
};
const applyStyle = (self, string) => {
if (self.level <= 0 || !string) {
return self._isEmpty ? '' : string;
}
let styler = self._styler;
if (styler === undefined) {
return string;
}
const {openAll, closeAll} = styler;
if (string.indexOf('\u001B') !== -1) {
while (styler !== undefined) {
// Replace any instances already present with a re-opening code
// otherwise only the part of the string until said closing code
// will be colored, and the rest will simply be 'plain'.
string = stringReplaceAll(string, styler.close, styler.open);
styler = styler.parent;
}
}
// We can move both next actions out of loop, because remaining actions in loop won't have
// any/visible effect on parts we add here. Close the styling before a linebreak and reopen
// after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92
const lfIndex = string.indexOf('\n');
if (lfIndex !== -1) {
string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
}
return openAll + string + closeAll;
};
let template;
const chalkTag = (chalk, ...strings) => {
const [firstString] = strings;
if (!isArray(firstString) || !isArray(firstString.raw)) {
// If chalk() was called by itself or with a string,
// return the string itself as a string.
return strings.join(' ');
}
const arguments_ = strings.slice(1);
const parts = [firstString.raw[0]];
for (let i = 1; i < firstString.length; i++) {
parts.push(
String(arguments_[i - 1]).replace(/[{}\\]/g, '\\$&'),
String(firstString.raw[i])
);
}
if (template === undefined) {
template = require('./templates');
}
return template(chalk, parts.join(''));
};
Object.defineProperties(Chalk.prototype, styles);
const chalk = Chalk(); // eslint-disable-line new-cap
chalk.supportsColor = stdoutColor;
chalk.stderr = Chalk({level: stderrColor ? stderrColor.level : 0}); // eslint-disable-line new-cap
chalk.stderr.supportsColor = stderrColor;
module.exports = chalk;

Some files were not shown because too many files have changed in this diff Show More