code:
# css-what

[![Build Status](https://img.shields.io/github/workflow/status/fb55/css-what/Node.js%20CI/master)](https://github.com/fb55/css-what/actions/workflows/nodejs-test.yml)
[![Coverage](https://img.shields.io/coveralls/github/fb55/css-what/master)](https://coveralls.io/github/fb55/css-what?branch=master)

A CSS selector parser.

## Example

```js
import * as CSSwhat from "css-what";

CSSwhat.parse("foo[bar]:baz")

~> [
    [
        { type: "tag", name: "foo" },
        {
            type: "attribute",
            name: "bar",
            action: "exists",
            value: "",
            ignoreCase: null
        },
        { type: "pseudo", name: "baz", data: null }
    ]
]
```

## API

**`CSSwhat.parse(selector)` - Parses `selector`.**

The function returns a two-dimensional array. The first array represents selectors separated by commas (eg. `sub1, sub2`), the second contains the relevant tokens for that selector. Possible token types are:

| name                | properties                              | example       | output                                                                                |
| ------------------- | --------------------------------------- | ------------- | ---------------------------------------------------------------------------------------- |
| `tag`               | `name`                                  | `div`         | `{ type: 'tag', name: 'div' }`                                                           |
| `universal`         | -                                       | `*`           | `{ type: 'universal' }`                                                                  |
| `pseudo`            | `name`, `data`                          | `:name(data)` | `{ type: 'pseudo', name: 'name', data: 'data' }`                                         |
| `pseudo`            | `name`, `data`                          | `:name`       | `{ type: 'pseudo', name: 'name', data: null }`                                           |
| `pseudo-element`    | `name`                                  | `::name`      | `{ type: 'pseudo-element', name: 'name' }`                                               |
| `attribute`         | `name`, `action`, `value`, `ignoreCase` | `[attr]`      | `{ type: 'attribute', name: 'attr', action: 'exists', value: '', ignoreCase: false }`    |
| `attribute`         | `name`, `action`, `value`, `ignoreCase` | `[attr=val]`  | `{ type: 'attribute', name: 'attr', action: 'equals', value: 'val', ignoreCase: false }` |
| `attribute`         | `name`, `action`, `value`, `ignoreCase` | `[attr^=val]` | `{ type: 'attribute', name: 'attr', action: 'start', value: 'val', ignoreCase: false }`  |
| `attribute`         | `name`, `action`, `value`, `ignoreCase` | `[attr$=val]` | `{ type: 'attribute', name: 'attr', action: 'end', value: 'val', ignoreCase: false }`    |
| `child`             | -                                       | `>`           | `{ type: 'child' }`                                                                      |
| `parent`            | -                                       | `<`           | `{ type: 'parent' }`                                                                     |
| `sibling`           | -                                       | `~`           | `{ type: 'sibling' }`                                                                    |
| `adjacent`          | -                                       | `+`           | `{ type: 'adjacent' }`                                                                   |
| `descendant`        | -                                       |               | `{ type: 'descendant' }`                                                                 |
| `column-combinator` | -                                       | `\|\|`        | `{ type: 'column-combinator' }`                                                          |

**`CSSwhat.stringify(selector)` - Turns `selector` back into a string.**

---

License: BSD-2-Clause

## Security contact information

To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security).
Tidelift will coordinate the fix and disclosure.

## `css-what` for enterprise

Available as part of the Tidelift Subscription

The maintainers of `css-what` 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-css-what?utm_source=npm-css-what&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)


code:
Copyright Mathias Bynens <https://mathiasbynens.be/>

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.

license: mit


code:
# cssesc [![Build status](https://travis-ci.org/mathiasbynens/cssesc.svg?branch=master)](https://travis-ci.org/mathiasbynens/cssesc) [![Code coverage status](https://img.shields.io/codecov/c/github/mathiasbynens/cssesc.svg)](https://codecov.io/gh/mathiasbynens/cssesc)

A JavaScript library for escaping CSS strings and identifiers while generating the shortest possible ASCII-only output.

This is a JavaScript library for [escaping text for use in CSS strings or identifiers](https://mathiasbynens.be/notes/css-escapes) while generating the shortest possible valid ASCII-only output. [Here’s an online demo.](https://mothereff.in/css-escapes)

[A polyfill for the CSSOM `CSS.escape()` method is available in a separate repository.](https://mths.be/cssescape) (In comparison, _cssesc_ is much more powerful.)

Feel free to fork if you see possible improvements!

## Installation

Via [npm](https://www.npmjs.com/):

```bash
npm install cssesc
```

In a browser:

```html
<script src="cssesc.js"></script>
```

In [Node.js](https://nodejs.org/):

```js
const cssesc = require('cssesc');
```

In Ruby using [the `ruby-cssesc` wrapper gem](https://github.com/borodean/ruby-cssesc):

```bash
gem install ruby-cssesc
```

```ruby
require 'ruby-cssesc'
CSSEsc.escape('I ♥ Ruby', is_identifier: true)
```

In Sass using [`sassy-escape`](https://github.com/borodean/sassy-escape):

```bash
gem install sassy-escape
```

```scss
body {
  content: escape('I ♥ Sass', $is-identifier: true);
}
```

## API

### `cssesc(value, options)`

This function takes a value and returns an escaped version of the value where any characters that are not printable ASCII symbols are escaped using the shortest possible (but valid) [escape sequences for use in CSS strings or identifiers](https://mathiasbynens.be/notes/css-escapes).

```js
cssesc('Ich ♥ Bücher');
// → 'Ich \\2665  B\\FC cher'

cssesc('foo 𝌆 bar');
// → 'foo \\1D306  bar'
```

By default, `cssesc` returns a string that can be used as part of a CSS string. If the target is a CSS identifier rather than a CSS string, use the `isIdentifier: true` setting (see below).

The optional `options` argument accepts an object with the following options:

#### `isIdentifier`

The default value for the `isIdentifier` option is `false`. This means that the input text will be escaped for use in a CSS string literal. If you want to use the result as a CSS identifier instead (in a selector, for example), set this option to `true`.

```js
cssesc('123a2b');
// → '123a2b'

cssesc('123a2b', {
  'isIdentifier': true
});
// → '\\31 23a2b'
```

#### `quotes`

The default value for the `quotes` option is `'single'`. This means that any occurences of `'` in the input text will be escaped as `\'`, so that the output can be used in a CSS string literal wrapped in single quotes.

```js
cssesc('Lorem ipsum "dolor" sit \'amet\' etc.');
// → 'Lorem ipsum "dolor" sit \\\'amet\\\' etc.'
// → "Lorem ipsum \"dolor\" sit \\'amet\\' etc."

cssesc('Lorem ipsum "dolor" sit \'amet\' etc.', {
  'quotes': 'single'
});
// → 'Lorem ipsum "dolor" sit \\\'amet\\\' etc.'
// → "Lorem ipsum \"dolor\" sit \\'amet\\' etc."
```

If you want to use the output as part of a CSS string literal wrapped in double quotes, set the `quotes` option to `'double'`.

```js
cssesc('Lorem ipsum "dolor" sit \'amet\' etc.', {
  'quotes': 'double'
});
// → 'Lorem ipsum \\"dolor\\" sit \'amet\' etc.'
// → "Lorem ipsum \\\"dolor\\\" sit 'amet' etc."
```

#### `wrap`

The `wrap` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, the output will be a valid CSS string literal wrapped in quotes. The type of quotes can be specified through the `quotes` setting.

```js
cssesc('Lorem ipsum "dolor" sit \'amet\' etc.', {
  'quotes': 'single',
  'wrap': true
});
// → '\'Lorem ipsum "dolor" sit \\\'amet\\\' etc.\''
// → "\'Lorem ipsum \"dolor\" sit \\\'amet\\\' etc.\'"

cssesc('Lorem ipsum "dolor" sit \'amet\' etc.', {
  'quotes': 'double',
  'wrap': true
});
// → '"Lorem ipsum \\"dolor\\" sit \'amet\' etc."'
// → "\"Lorem ipsum \\\"dolor\\\" sit \'amet\' etc.\""
```

#### `escapeEverything`

The `escapeEverything` option takes a boolean value (`true` or `false`), and defaults to `false` (disabled). When enabled, all the symbols in the output will be escaped, even printable ASCII symbols.

```js
cssesc('lolwat"foo\'bar', {
  'escapeEverything': true
});
// → '\\6C\\6F\\6C\\77\\61\\74\\"\\66\\6F\\6F\\\'\\62\\61\\72'
// → "\\6C\\6F\\6C\\77\\61\\74\\\"\\66\\6F\\6F\\'\\62\\61\\72"
```

#### Overriding the default options globally

The global default settings can be overridden by modifying the `css.options` object. This saves you from passing in an `options` object for every call to `encode` if you want to use the non-default setting.

```js
// Read the global default setting for `escapeEverything`:
cssesc.options.escapeEverything;
// → `false` by default

// Override the global default setting for `escapeEverything`:
cssesc.options.escapeEverything = true;

// Using the global default setting for `escapeEverything`, which is now `true`:
cssesc('foo © bar ≠ baz 𝌆 qux');
// → '\\66\\6F\\6F\\ \\A9\\ \\62\\61\\72\\ \\2260\\ \\62\\61\\7A\\ \\1D306\\ \\71\\75\\78'
```

### `cssesc.version`

A string representing the semantic version number.

### Using the `cssesc` binary

To use the `cssesc` binary in your shell, simply install cssesc globally using npm:

```bash
npm install -g cssesc
```

After that you will be able to escape text for use in CSS strings or identifiers from the command line:

```bash
$ cssesc 'föo ♥ bår 𝌆 baz'
f\F6o \2665  b\E5r \1D306  baz
```

If the output needs to be a CSS identifier rather than part of a string literal, use the `-i`/`--identifier` option:

```bash
$ cssesc --identifier 'föo ♥ bår 𝌆 baz'
f\F6o\ \2665\ b\E5r\ \1D306\ baz
```

See `cssesc --help` for the full list of options.

## Support

This library supports the Node.js and browser versions mentioned in [`.babelrc`](https://github.com/mathiasbynens/cssesc/blob/master/.babelrc). For a version that supports a wider variety of legacy browsers and environments out-of-the-box, [see v0.1.0](https://github.com/mathiasbynens/cssesc/releases/tag/v0.1.0).

## Author

| [![twitter/mathias](https://gravatar.com/avatar/24e08a9ea84deb17ae121074d0f17125?s=70)](https://twitter.com/mathias "Follow @mathias on Twitter") |
|---|
| [Mathias Bynens](https://mathiasbynens.be/) |

## License

This library is available under the [MIT](https://mths.be/mit) license.


code:
#!/usr/bin/env node
const fs = require('fs');
const cssesc = require('../cssesc.js');
const strings = process.argv.splice(2);
const stdin = process.stdin;
const options = {};
const log = console.log;

const main = function() {
	const option = strings[0];

	if (/^(?:-h|--help|undefined)$/.test(option)) {
		log(
			'cssesc v%s - https://mths.be/cssesc',
			cssesc.version
		);
		log([
			'\nUsage:\n',
			'\tcssesc [string]',
			'\tcssesc [-i | --identifier] [string]',
			'\tcssesc [-s | --single-quotes] [string]',
			'\tcssesc [-d | --double-quotes] [string]',
			'\tcssesc [-w | --wrap] [string]',
			'\tcssesc [-e | --escape-everything] [string]',
			'\tcssesc [-v | --version]',
			'\tcssesc [-h | --help]',
			'\nExamples:\n',
			'\tcssesc \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'',
			'\tcssesc --identifier \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'',
			'\tcssesc --escape-everything \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'',
			'\tcssesc --double-quotes --wrap \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\'',
			'\techo \'f\xF6o \u2665 b\xE5r \uD834\uDF06 baz\' | cssesc'
		].join('\n'));
		return process.exit(1);
	}

	if (/^(?:-v|--version)$/.test(option)) {
		log('v%s', cssesc.version);
		return process.exit(1);
	}

	strings.forEach(function(string) {
		// Process options
		if (/^(?:-i|--identifier)$/.test(string)) {
			options.isIdentifier = true;
			return;
		}
		if (/^(?:-s|--single-quotes)$/.test(string)) {
			options.quotes = 'single';
			return;
		}
		if (/^(?:-d|--double-quotes)$/.test(string)) {
			options.quotes = 'double';
			return;
		}
		if (/^(?:-w|--wrap)$/.test(string)) {
			options.wrap = true;
			return;
		}
		if (/^(?:-e|--escape-everything)$/.test(string)) {
			options.escapeEverything = true;
			return;
		}

		// Process string(s)
		let result;
		try {
			result = cssesc(string, options);
			log(result);
		} catch (exception) {
			log(exception.message + '\n');
			log('Error: failed to escape.');
			log('If you think this is a bug in cssesc, please report it:');
			log('https://github.com/mathiasbynens/cssesc/issues/new');
			log(
				'\nStack trace using cssesc@%s:\n',
				cssesc.version
			);
			log(exception.stack);
			return process.exit(1);
		}
	});
	// Return with exit status 0 outside of the `forEach` loop, in case
	// multiple strings were passed in.
	return process.exit(0);

};

if (stdin.isTTY) {
	// handle shell arguments
	main();
} else {
	let timeout;
	// Either the script is called from within a non-TTY context, or `stdin`
	// content is being piped in.
	if (!process.stdout.isTTY) {
		// The script was called from a non-TTY context. This is a rather uncommon
		// use case we don’t actively support. However, we don’t want the script
		// to wait forever in such cases, so…
		timeout = setTimeout(function() {
			// …if no piped data arrived after a whole minute, handle shell
			// arguments instead.
			main();
		}, 60000);
	}
	let data = '';
	stdin.on('data', function(chunk) {
		clearTimeout(timeout);
		data += chunk;
	});
	stdin.on('end', function() {
		strings.push(data.trim());
		main();
	});
	stdin.resume();
}


code:
/*! https://mths.be/cssesc v3.0.0 by @mathias */
'use strict';

var object = {};
var hasOwnProperty = object.hasOwnProperty;
var merge = function merge(options, defaults) {
	if (!options) {
		return defaults;
	}
	var result = {};
	for (var key in defaults) {
		// `if (defaults.hasOwnProperty(key) { … }` is not needed here, since
		// only recognized option names are used.
		result[key] = hasOwnProperty.call(options, key) ? options[key] : defaults[key];
	}
	return result;
};

var regexAnySingleEscape = /[ -,\.\/:-@\[-\^`\{-~]/;
var regexSingleEscape = /[ -,\.\/:-@\[\]\^`\{-~]/;
var regexAlwaysEscape = /['"\\]/;
var regexExcessiveSpaces = /(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g;

// https://mathiasbynens.be/notes/css-escapes#css
var cssesc = function cssesc(string, options) {
	options = merge(options, cssesc.options);
	if (options.quotes != 'single' && options.quotes != 'double') {
		options.quotes = 'single';
	}
	var quote = options.quotes == 'double' ? '"' : '\'';
	var isIdentifier = options.isIdentifier;

	var firstChar = string.charAt(0);
	var output = '';
	var counter = 0;
	var length = string.length;
	while (counter < length) {
		var character = string.charAt(counter++);
		var codePoint = character.charCodeAt();
		var value = void 0;
		// If it’s not a printable ASCII character…
		if (codePoint < 0x20 || codePoint > 0x7E) {
			if (codePoint >= 0xD800 && codePoint <= 0xDBFF && counter < length) {
				// It’s a high surrogate, and there is a next character.
				var extra = string.charCodeAt(counter++);
				if ((extra & 0xFC00) == 0xDC00) {
					// next character is low surrogate
					codePoint = ((codePoint & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000;
				} else {
					// It’s an unmatched surrogate; only append this code unit, in case
					// the next code unit is the high surrogate of a surrogate pair.
					counter--;
				}
			}
			value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
		} else {
			if (options.escapeEverything) {
				if (regexAnySingleEscape.test(character)) {
					value = '\\' + character;
				} else {
					value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
				}
			} else if (/[\t\n\f\r\x0B]/.test(character)) {
				value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
			} else if (character == '\\' || !isIdentifier && (character == '"' && quote == character || character == '\'' && quote == character) || isIdentifier && regexSingleEscape.test(character)) {
				value = '\\' + character;
			} else {
				value = character;
			}
		}
		output += value;
	}

	if (isIdentifier) {
		if (/^-[-\d]/.test(output)) {
			output = '\\-' + output.slice(1);
		} else if (/\d/.test(firstChar)) {
			output = '\\3' + firstChar + ' ' + output.slice(1);
		}
	}

	// Remove spaces after `\HEX` escapes that are not followed by a hex digit,
	// since they’re redundant. Note that this is only possible if the escape
	// sequence isn’t preceded by an odd number of backslashes.
	output = output.replace(regexExcessiveSpaces, function ($0, $1, $2) {
		if ($1 && $1.length % 2) {
			// It’s not safe to remove the space, so don’t.
			return $0;
		}
		// Strip the space.
		return ($1 || '') + $2;
	});

	if (!isIdentifier && options.wrap) {
		return quote + output + quote;
	}
	return output;
};

// Expose default options (so they can be overridden globally).
cssesc.options = {
	'escapeEverything': false,
	'isIdentifier': false,
	'quotes': 'single',
	'wrap': false
};

cssesc.version = '3.0.0';

module.exports = cssesc;


code:
.Dd August 9, 2013
.Dt cssesc 1
.Sh NAME
.Nm cssesc
.Nd escape text for use in CSS string literals or identifiers
.Sh SYNOPSIS
.Nm
.Op Fl i | -identifier Ar string
.br
.Op Fl s | -single-quotes Ar string
.br
.Op Fl d | -double-quotes Ar string
.br
.Op Fl w | -wrap Ar string
.br
.Op Fl e | -escape-everything Ar string
.br
.Op Fl v | -version
.br
.Op Fl h | -help
.Sh DESCRIPTION
.Nm
escapes strings for use in CSS string literals or identifiers while generating the shortest possible valid ASCII-only output.
.Sh OPTIONS
.Bl -ohang -offset
.It Sy "-s, --single-quotes"
Escape any occurences of ' in the input string as \\', so that the output can be used in a CSS string literal wrapped in single quotes.
.It Sy "-d, --double-quotes"
Escape any occurences of " in the input string as \\", so that the output can be used in a CSS string literal wrapped in double quotes.
.It Sy "-w, --wrap"
Make sure the output is a valid CSS string literal wrapped in quotes. The type of quotes can be specified using the
.Ar -s | --single-quotes
or
.Ar -d | --double-quotes
settings.
.It Sy "-e, --escape-everything"
Escape all the symbols in the output, even printable ASCII symbols.
.It Sy "-v, --version"
Print cssesc's version.
.It Sy "-h, --help"
Show the help screen.
.El
.Sh EXIT STATUS
The
.Nm cssesc
utility exits with one of the following values:
.Pp
.Bl -tag -width flag -compact
.It Li 0
.Nm
successfully escaped the given text and printed the result.
.It Li 1
.Nm
wasn't instructed to escape anything (for example, the
.Ar --help
flag was set); or, an error occurred.
.El
.Sh EXAMPLES
.Bl -ohang -offset
.It Sy "cssesc 'foo bar baz'"
Print an escaped version of the given text.
.It Sy echo\ 'foo bar baz'\ |\ cssesc
Print an escaped version of the text that gets piped in.
.El
.Sh BUGS
cssesc's bug tracker is located at <https://github.com/mathiasbynens/cssesc/issues>.
.Sh AUTHOR
Mathias Bynens <https://mathiasbynens.be/>
.Sh WWW
<https://mths.be/cssesc>


cssesc

description: A JavaScript library for escaping CSS strings and identifiers while generating the shortest possible ASCII-only output.

bin: bin/cssesc

keywords: css escape identifier string tool

license: MIT

type: git

build: grunt template && babel cssesc.js -o cssesc.js

test: mocha tests

cover: istanbul cover --report html node_modules/.bin/_mocha tests -- -u exports -R spec


code:
Copyright (c) Ben Briggs <beneb.info@gmail.com> (http://beneb.info)

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.


code:
# cssnano-preset-default

> Safe defaults for cssnano which require minimal configuration.

## Table of Contents

- [Overview](#overview)

- [Usage](#usage)

  - [Install](#install)
  - [Configuration](#configuration)

- [Plugins](#plugins)

  - [css-declaration-sorter (external)](#css-declaration-sorter-external)
  - [cssnano-utils](#cssnano-utils)
  - [postcss-calc (external)](#postcss-calc-external)
  - [postcss-colormin](#postcss-colormin)
  - [postcss-convert-values](#postcss-convert-values)
  - [postcss-discard-comments](#postcss-discard-comments)
  - [postcss-discard-duplicates](#postcss-discard-duplicates)
  - [postcss-discard-empty](#postcss-discard-empty)
  - [postcss-discard-overridden](#postcss-discard-overridden)
  - [postcss-merge-longhand](#postcss-merge-longhand)
  - [postcss-merge-rules](#postcss-merge-rules)
  - [postcss-minify-font-values](#postcss-minify-font-values)
  - [postcss-minify-gradients](#postcss-minify-gradients)
  - [postcss-minify-params](#postcss-minify-params)
  - [postcss-minify-selectors](#postcss-minify-selectors)
  - [postcss-normalize-charset](#postcss-normalize-charset)
  - [postcss-normalize-display-values](#postcss-normalize-display-values)
  - [postcss-normalize-positions](#postcss-normalize-positions)
  - [postcss-normalize-repeat-style](#postcss-normalize-repeat-style)
  - [postcss-normalize-string](#postcss-normalize-string)
  - [postcss-normalize-timing-functions](#postcss-normalize-timing-functions)
  - [postcss-normalize-unicode](#postcss-normalize-unicode)
  - [postcss-normalize-url](#postcss-normalize-url)
  - [postcss-normalize-whitespace](#postcss-normalize-whitespace)
  - [postcss-ordered-values](#postcss-ordered-values)
  - [postcss-reduce-initial](#postcss-reduce-initial)
  - [postcss-reduce-transforms](#postcss-reduce-transforms)
  - [postcss-svgo](#postcss-svgo)
  - [postcss-unique-selectors](#postcss-unique-selectors)

- [Contributors](#contributors)

- [License](#license)

## Overview

This default preset for cssnano only includes transforms that make no
assumptions about your CSS other than what is passed in. In previous
iterations of cssnano, assumptions were made about your CSS which caused
output to look different in certain use cases, but not others. These
transforms have been moved from the defaults to other presets, to make
this preset require only minimal configuration.

## Usage

### Install

Note that this preset comes bundled with cssnano _by default_, so you don't need to install it separately.

### Configuration

If you would like to use the default configuration, then you don't need to add anything to your `package.json`.

But should you wish to customise this, you can pass an array with the second parameter as the options object to use. For example, to remove all comments:

```diff
 {
   "name": "awesome-application",
+  "cssnano": {
+    "preset": [
+      "default",
+      {"discardComments": {"removeAll": true}}
+    ]
+  }
 }
```

Depending on your usage, the JSON configuration might not work for you, such as in cases where you would like to use options with customisable function parameters. For this use case, we recommend a `cssnano.config.js` at the same location as your `package.json`. You can then load a preset and export it with your custom parameters:

```js
const defaultPreset = require('cssnano-preset-default');

module.exports = defaultPreset({
  discardComments: {
    remove: (comment) => comment[0] === '@',
  },
});
```

Note that you may wish to publish your own preset to npm for reusability, should it differ a lot from this one. This is highly encouraged!

## Plugins

### [`css-declaration-sorter`](https://github.com/Siilwyn/css-declaration-sorter) (external)

> Sorts CSS declarations fast and automatically in a certain order.

This plugin is loaded with the following configuration:

```js
{
	keepOverrides: true
}
```

### [`cssnano-utils`](https://github.com/cssnano/cssnano/tree/master/packages/cssnano-utils)

> Utility methods used by cssnano

### [`postcss-calc`](https://github.com/postcss/postcss-calc) (external)

> PostCSS plugin to reduce calc()

This plugin is loaded with its default configuration.

### [`postcss-colormin`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-colormin)

> Minify colors in your CSS files with PostCSS.

This plugin is loaded with its default configuration.

### [`postcss-convert-values`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-convert-values)

> Convert values with PostCSS (e.g. ms -> s)

This plugin is loaded with the following configuration:

```js
{
  length: false;
}
```

### [`postcss-discard-comments`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-discard-comments)

> Discard comments in your CSS files with PostCSS.

This plugin is loaded with its default configuration.

### [`postcss-discard-duplicates`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-discard-duplicates)

> Discard duplicate rules in your CSS files with PostCSS.

This plugin is loaded with its default configuration.

### [`postcss-discard-empty`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-discard-empty)

> Discard empty rules and values with PostCSS.

This plugin is loaded with its default configuration.

### [`postcss-discard-overridden`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-discard-overridden)

> PostCSS plugin to discard overridden @keyframes or @counter-style.

This plugin is loaded with its default configuration.

### [`postcss-merge-longhand`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-merge-longhand)

> Merge longhand properties into shorthand with PostCSS.

This plugin is loaded with its default configuration.

### [`postcss-merge-rules`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-merge-rules)

> Merge CSS rules with PostCSS.

This plugin is loaded with its default configuration.

### [`postcss-minify-font-values`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-minify-font-values)

> Minify font declarations with PostCSS

This plugin is loaded with its default configuration.

### [`postcss-minify-gradients`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-minify-gradients)

> Minify gradient parameters with PostCSS.

This plugin is loaded with its default configuration.

### [`postcss-minify-params`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-minify-params)

> Minify at-rule params with PostCSS

This plugin is loaded with its default configuration.

### [`postcss-minify-selectors`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-minify-selectors)

> Minify selectors with PostCSS.

This plugin is loaded with its default configuration.

### [`postcss-normalize-charset`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-normalize-charset)

> Add necessary or remove extra charset with PostCSS

This plugin is loaded with the following configuration:

```js
{
  add: false;
}
```

### [`postcss-normalize-display-values`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-normalize-display-values)

> Normalize multiple value display syntaxes into single values.

This plugin is loaded with its default configuration.

### [`postcss-normalize-positions`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-normalize-positions)

> Normalize keyword values for position into length values.

This plugin is loaded with its default configuration.

### [`postcss-normalize-repeat-style`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-normalize-repeat-style)

> Convert two value syntax for repeat-style into one value.

This plugin is loaded with its default configuration.

### [`postcss-normalize-string`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-normalize-string)

> Normalize wrapping quotes for CSS string literals.

This plugin is loaded with its default configuration.

### [`postcss-normalize-timing-functions`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-normalize-timing-functions)

> Normalize CSS animation/transition timing functions.

This plugin is loaded with its default configuration.

### [`postcss-normalize-unicode`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-normalize-unicode)

> Normalize unicode-range descriptors, and can convert to wildcard ranges.

This plugin is loaded with its default configuration.

### [`postcss-normalize-url`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-normalize-url)

> Normalize URLs with PostCSS

This plugin is loaded with its default configuration.

### [`postcss-normalize-whitespace`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-normalize-whitespace)

> Trim whitespace inside and around CSS rules & declarations.

This plugin is loaded with its default configuration.

### [`postcss-ordered-values`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-ordered-values)

> Ensure values are ordered consistently in your CSS.

This plugin is loaded with its default configuration.

### [`postcss-reduce-initial`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-reduce-initial)

> Reduce initial definitions to the actual initial value, where possible.

This plugin is loaded with its default configuration.

### [`postcss-reduce-transforms`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-reduce-transforms)

> Reduce transform functions with PostCSS.

This plugin is loaded with its default configuration.

### [`postcss-svgo`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-svgo)

> Optimise inline SVG with PostCSS.

This plugin is loaded with its default configuration.

### [`postcss-unique-selectors`](https://github.com/cssnano/cssnano/tree/master/packages/postcss-unique-selectors)

> Ensure CSS selectors are unique.

This plugin is loaded with its default configuration.

## Contributors

See [CONTRIBUTORS.md](https://github.com/cssnano/cssnano/blob/master/CONTRIBUTORS.md).

## License

MIT © [Ben Briggs](http://beneb.info)


cssnano-preset-default

description: Safe defaults for cssnano which require minimal configuration.

files: LICENSE-MIT src types

repository: cssnano/cssnano


code:
'use strict';
/**
 * @author Ben Briggs
 * @license MIT
 * @module cssnano:preset:default
 * @overview
 *
 * This default preset for cssnano only includes transforms that make no
 * assumptions about your CSS other than what is passed in. In previous
 * iterations of cssnano, assumptions were made about your CSS which caused
 * output to look different in certain use cases, but not others. These
 * transforms have been moved from the defaults to other presets, to make
 * this preset require only minimal configuration.
 */

const cssDeclarationSorter = require('css-declaration-sorter');
const postcssDiscardComments = require('postcss-discard-comments');
const postcssReduceInitial = require('postcss-reduce-initial');
const postcssMinifyGradients = require('postcss-minify-gradients');
const postcssSvgo = require('postcss-svgo');
const postcssReduceTransforms = require('postcss-reduce-transforms');
const postcssConvertValues = require('postcss-convert-values');
const postcssCalc = require('postcss-calc');
const postcssColormin = require('postcss-colormin');
const postcssOrderedValues = require('postcss-ordered-values');
const postcssMinifySelectors = require('postcss-minify-selectors');
const postcssMinifyParams = require('postcss-minify-params');
const postcssNormalizeCharset = require('postcss-normalize-charset');
const postcssMinifyFontValues = require('postcss-minify-font-values');
const postcssNormalizeUrl = require('postcss-normalize-url');
const postcssMergeLonghand = require('postcss-merge-longhand');
const postcssDiscardDuplicates = require('postcss-discard-duplicates');
const postcssDiscardOverridden = require('postcss-discard-overridden');
const postcssNormalizeRepeatStyle = require('postcss-normalize-repeat-style');
const postcssMergeRules = require('postcss-merge-rules');
const postcssDiscardEmpty = require('postcss-discard-empty');
const postcssUniqueSelectors = require('postcss-unique-selectors');
const postcssNormalizeString = require('postcss-normalize-string');
const postcssNormalizePositions = require('postcss-normalize-positions');
const postcssNormalizeWhitespace = require('postcss-normalize-whitespace');
const postcssNormalizeUnicode = require('postcss-normalize-unicode');
const postcssNormalizeDisplayValues = require('postcss-normalize-display-values');
const postcssNormalizeTimingFunctions = require('postcss-normalize-timing-functions');
const { rawCache } = require('cssnano-utils');

/** @typedef {{
discardComments?: false | import('postcss-discard-comments').Options & { exclude?: true},
reduceInitial?:  false | { exclude?: true}
minifyGradients?:  false | { exclude?: true}
svgo?: false | import('postcss-svgo').Options & { exclude?: true},
reduceTransforms?:  false | { exclude?: true}
convertValues?: false | import('postcss-convert-values').Options & { exclude?: true},
calc?: false | import('postcss-calc').PostCssCalcOptions & { exclude?: true},
colormin?: false | Record<string, any> & { exclude?: true},
orderedValues?: false | { exclude?: true},
minifySelectors?: false | { exclude?: true},
minifyParams?: false | { exclude?: true},
normalizeCharset?: false | import('postcss-normalize-charset').Options & { exclude?: true},
minifyFontValues?: false | import('postcss-minify-font-values').Options & { exclude?: true},
normalizeUrl?: false | import('postcss-normalize-url').Options & { exclude?: true},
mergeLonghand?: false | { exclude?: true},
discardDuplicates?: false | { exclude?: true},
discardOverridden?: false | { exclude?: true},
normalizeRepeatStyle?: false | { exclude?: true},
mergeRules?: false | { exclude?: true},
discardEmpty?: false | { exclude?: true},
uniqueSelectors?: false | { exclude?: true},
normalizeString?: false | import('postcss-normalize-string').Options & { exclude?: true},
normalizePositions?: false | { exclude?: true},
normalizeWhitespace?: false| { exclude?: true},
normalizeUnicode?: false | { exclude?: true},
normalizeDisplayValues?: false | { exclude?: true},
normalizeTimingFunctions?: false | { exclude?: true},
rawCache?: false | { exclude?: true}}} Options */

const defaultOpts = {
  convertValues: {
    length: false,
  },
  normalizeCharset: {
    add: false,
  },
  cssDeclarationSorter: {
    keepOverrides: true,
  },
};

/**
 * @param {Options} opts
 * @return {{plugins: [import('postcss').PluginCreator<any>, boolean | Record<string, any> | undefined][]}}
 */
function defaultPreset(opts = {}) {
  const options = Object.assign({}, defaultOpts, opts);

  /** @type {[import('postcss').PluginCreator<any>, boolean | Record<string, any> | undefined][]} **/
  const plugins = [
    [postcssDiscardComments, options.discardComments],
    [postcssMinifyGradients, options.minifyGradients],
    [postcssReduceInitial, options.reduceInitial],
    [postcssSvgo, options.svgo],
    [postcssNormalizeDisplayValues, options.normalizeDisplayValues],
    [postcssReduceTransforms, options.reduceTransforms],
    [postcssColormin, options.colormin],
    [postcssNormalizeTimingFunctions, options.normalizeTimingFunctions],
    [postcssCalc, options.calc],
    [postcssConvertValues, options.convertValues],
    [postcssOrderedValues, options.orderedValues],
    [postcssMinifySelectors, options.minifySelectors],
    [postcssMinifyParams, options.minifyParams],
    [postcssNormalizeCharset, options.normalizeCharset],
    [postcssDiscardOverridden, options.discardOverridden],
    [postcssNormalizeString, options.normalizeString],
    [postcssNormalizeUnicode, options.normalizeUnicode],
    [postcssMinifyFontValues, options.minifyFontValues],
    [postcssNormalizeUrl, options.normalizeUrl],
    [postcssNormalizeRepeatStyle, options.normalizeRepeatStyle],
    [postcssNormalizePositions, options.normalizePositions],
    [postcssNormalizeWhitespace, options.normalizeWhitespace],
    [postcssMergeLonghand, options.mergeLonghand],
    [postcssDiscardDuplicates, options.discardDuplicates],
    [postcssMergeRules, options.mergeRules],
    [postcssDiscardEmpty, options.discardEmpty],
    [postcssUniqueSelectors, options.uniqueSelectors],
    [cssDeclarationSorter, options.cssDeclarationSorter],
    [rawCache, options.rawCache],
  ];

  return { plugins };
}

module.exports = defaultPreset;


code:
export = defaultPreset;
/**
 * @param {Options} opts
 * @return {{plugins: [import('postcss').PluginCreator<any>, boolean | Record<string, any> | undefined][]}}
 */
declare function defaultPreset(opts?: Options): {
    plugins: [import('postcss').PluginCreator<any>, boolean | Record<string, any> | undefined][];
};
declare namespace defaultPreset {
    export { Options };
}
type Options = {
    discardComments?: false | import('postcss-discard-comments').Options & {
        exclude?: true;
    };
    reduceInitial?: false | {
        exclude?: true;
    };
    minifyGradients?: false | {
        exclude?: true;
    };
    svgo?: false | import('postcss-svgo').Options & {
        exclude?: true;
    };
    reduceTransforms?: false | {
        exclude?: true;
    };
    convertValues?: false | import('postcss-convert-values').Options & {
        exclude?: true;
    };
    calc?: false | import('postcss-calc').PostCssCalcOptions & {
        exclude?: true;
    };
    colormin?: false | (Record<string, any> & {
        exclude?: true;
    });
    orderedValues?: false | {
        exclude?: true;
    };
    minifySelectors?: false | {
        exclude?: true;
    };
    minifyParams?: false | {
        exclude?: true;
    };
    normalizeCharset?: false | import('postcss-normalize-charset').Options & {
        exclude?: true;
    };
    minifyFontValues?: false | import('postcss-minify-font-values').Options & {
        exclude?: true;
    };
    normalizeUrl?: false | import('postcss-normalize-url').Options & {
        exclude?: true;
    };
    mergeLonghand?: false | {
        exclude?: true;
    };
    discardDuplicates?: false | {
        exclude?: true;
    };
    discardOverridden?: false | {
        exclude?: true;
    };
    normalizeRepeatStyle?: false | {
        exclude?: true;
    };
    mergeRules?: false | {
        exclude?: true;
    };
    discardEmpty?: false | {
        exclude?: true;
    };
    uniqueSelectors?: false | {
        exclude?: true;
    };
    normalizeString?: false | import('postcss-normalize-string').Options & {
        exclude?: true;
    };
    normalizePositions?: false | {
        exclude?: true;
    };
    normalizeWhitespace?: false | {
        exclude?: true;
    };
    normalizeUnicode?: false | {
        exclude?: true;
    };
    normalizeDisplayValues?: false | {
        exclude?: true;
    };
    normalizeTimingFunctions?: false | {
        exclude?: true;
    };
    rawCache?: false | {
        exclude?: true;
    };
};
import { rawCache } from "cssnano-utils";


code:
# cssnano-utils

Utility methods and plugin for cssnano projects

## List of methods and plugin(s)

| **utility methods** | **description**                                                           |
| ------------------- | ------------------------------------------------------------------------- |
| `rawCache`          | Postcss plugin to manage the raw value formatting for generated AST nodes |
| `getArguments`      | Get a list of arguments, separated by a comma.                            |
| `sameParent`        | Check that two PostCSS nodes share the same parent.                       |

## Contributors

See [CONTRIBUTORS.md](https://github.com/cssnano/cssnano/blob/master/CONTRIBUTORS.md).


cssnano-utils

files: src LICENSE types

readme:
# cssnano-utils

Utility methods and plugin for cssnano projects

## List of methods and plugin(s)

| **utility methods** | **description**                                                           |
| ------------------- | ------------------------------------------------------------------------- |
| `rawCache`          | Postcss plugin to manage the raw value formatting for generated AST nodes |
| `getArguments`      | Get a list of arguments, separated by a comma.                            |
| `sameParent`        | Check that two PostCSS nodes share the same parent.                       |

## Contributors

See [CONTRIBUTORS.md](https://github.com/cssnano/cssnano/blob/master/CONTRIBUTORS.md).


code:
'use strict';
/**
 * Extracts the arguments of a CSS function or AtRule.
 *
 * @param {import('postcss-value-parser').ParsedValue | import('postcss-value-parser').FunctionNode} node
 * @return {import('postcss-value-parser').Node[][]}
 */
module.exports = function getArguments(node) {
  /** @type {import('postcss-value-parser').Node[][]} */
  const list = [[]];
  for (const child of node.nodes) {
    if (child.type !== 'div') {
      list[list.length - 1].push(child);
    } else {
      list.push([]);
    }
  }
  return list;
};


code:
'use strict';
const rawCache = require('./rawCache.js');
const getArguments = require('./getArguments.js');
const sameParent = require('./sameParent.js');

module.exports = { rawCache, getArguments, sameParent };


code:
'use strict';

/**
 * @type {import('postcss').PluginCreator<void>}
 * @return {import('postcss').Plugin}
 */
function pluginCreator() {
  return {
    postcssPlugin: 'cssnano-util-raw-cache',
    /**
     * @param {import('postcss').Root} css
     * @param {{result: import('postcss').Result & {root: {rawCache?: any}}}} arg
     */
    OnceExit(css, { result }) {
      result.root.rawCache = {
        colon: ':',
        indent: '',
        beforeDecl: '',
        beforeRule: '',
        beforeOpen: '',
        beforeClose: '',
        beforeComment: '',
        after: '',
        emptyBody: '',
        commentLeft: '',
        commentRight: '',
      };
    },
  };
}

pluginCreator.postcss = true;

module.exports = pluginCreator;


code:
'use strict';

/**
 * @param {import('postcss').AnyNode} nodeA
 * @param {import('postcss').AnyNode} nodeB
 * @return {boolean}
 */
function checkMatch(nodeA, nodeB) {
  if (nodeA.type === 'atrule' && nodeB.type === 'atrule') {
    return (
      nodeA.params === nodeB.params &&
      nodeA.name.toLowerCase() === nodeB.name.toLowerCase()
    );
  }
  return nodeA.type === nodeB.type;
}

/** @typedef {import('postcss').AnyNode & {parent?: Child}} Child */
/**
 * @param {Child} nodeA
 * @param {Child} nodeB
 * @return {boolean}
 */
function sameParent(nodeA, nodeB) {
  if (!nodeA.parent) {
    // A is orphaned, return if B is orphaned as well
    return !nodeB.parent;
  }

  if (!nodeB.parent) {
    // B is orphaned and A is not
    return false;
  }

  // Check if parents match
  if (!checkMatch(nodeA.parent, nodeB.parent)) {
    return false;
  }

  // Check parents' parents
  return sameParent(nodeA.parent, nodeB.parent);
}

module.exports = sameParent;


code:
declare function _exports(node: import('postcss-value-parser').ParsedValue | import('postcss-value-parser').FunctionNode): import('postcss-value-parser').Node[][];
export = _exports;


code:
import rawCache = require("./rawCache.js");
import getArguments = require("./getArguments.js");
import sameParent = require("./sameParent.js");
export { rawCache, getArguments, sameParent };


code:
export = pluginCreator;
/**
 * @type {import('postcss').PluginCreator<void>}
 * @return {import('postcss').Plugin}
 */
declare function pluginCreator(): import('postcss').Plugin;
declare namespace pluginCreator {
    const postcss: true;
}


code:
export = sameParent;
/** @typedef {import('postcss').AnyNode & {parent?: Child}} Child */
/**
 * @param {Child} nodeA
 * @param {Child} nodeB
 * @return {boolean}
 */
declare function sameParent(nodeA: Child, nodeB: Child): boolean;
declare namespace sameParent {
    export { Child };
}
type Child = import('postcss').AnyNode & {
    parent?: Child;
};


code:
# cssnano

For documentation, please see the following links:

* Repository: https://github.com/cssnano/cssnano
* Website: http://cssnano.co


cssnano

description: A modular minifier, built on top of the PostCSS ecosystem.

type: opencollective

keywords: css compress minify optimise optimisation postcss postcss-plugin

files: src LICENSE-MIT types


code:
'use strict';
const path = require('path');
/** @type {any} */
const postcss = require('postcss');
const yaml = require('yaml');
const { lilconfigSync } = require('lilconfig');

const cssnano = 'cssnano';

/** @typedef {{preset?: any, plugins?: any[], configFile?: string}} Options */
/**
 * @param {string} moduleId
 * @returns {boolean}
 */
function isResolvable(moduleId) {
  try {
    require.resolve(moduleId);
    return true;
  } catch (e) {
    return false;
  }
}

/**
 * preset can be one of four possibilities:
 * preset = 'default'
 * preset = ['default', {}]
 * preset = function <- to be invoked
 * preset = {plugins: []} <- already invoked function
 *
 * @param {any} preset
 * @return {[import('postcss').PluginCreator<any>, boolean | Record<string, any> | undefined][]}}
 */
function resolvePreset(preset) {
  let fn, options;

  if (Array.isArray(preset)) {
    fn = preset[0];
    options = preset[1];
  } else {
    fn = preset;
    options = {};
  }

  // For JS setups where we invoked the preset already
  if (preset.plugins) {
    return preset.plugins;
  }

  // Provide an alias for the default preset, as it is built-in.
  if (fn === 'default') {
    return require('cssnano-preset-default')(options).plugins;
  }

  // For non-JS setups; we'll need to invoke the preset ourselves.
  if (typeof fn === 'function') {
    return fn(options).plugins;
  }

  // Try loading a preset from node_modules
  if (isResolvable(fn)) {
    return require(fn)(options).plugins;
  }

  const sugar = `cssnano-preset-${fn}`;

  // Try loading a preset from node_modules (sugar)
  if (isResolvable(sugar)) {
    return require(sugar)(options).plugins;
  }

  // If all else fails, we probably have a typo in the config somewhere
  throw new Error(
    `Cannot load preset "${fn}". Please check your configuration for errors and try again.`
  );
}

/**
 * cssnano will look for configuration firstly as options passed
 * directly to it, and failing this it will use lilconfig to
 * load an external file.

 * @param {Options} options
 */
function resolveConfig(options) {
  if (options.preset) {
    return resolvePreset(options.preset);
  }

  /** @type {string | undefined} */
  let searchPath = process.cwd();
  let configPath = undefined;

  if (options.configFile) {
    searchPath = undefined;
    configPath = path.resolve(process.cwd(), options.configFile);
  }

  const configExplorer = lilconfigSync(cssnano, {
    searchPlaces: [
      'package.json',
      '.cssnanorc',
      '.cssnanorc.json',
      '.cssnanorc.yaml',
      '.cssnanorc.yml',
      '.cssnanorc.js',
      'cssnano.config.js',
    ],
    loaders: {
      '.yaml': (filepath, content) => yaml.parse(content),
      '.yml': (filepath, content) => yaml.parse(content),
    },
  });
  const config = configPath
    ? configExplorer.load(configPath)
    : configExplorer.search(searchPath);

  if (config === null) {
    return resolvePreset('default');
  }

  return resolvePreset(config.config.preset || config.config);
}

/**
 * @type {import('postcss').PluginCreator<Options>}
 * @param {Options=} options
 * @return {import('postcss').Processor}
 */
function cssnanoPlugin(options = {}) {
  if (Array.isArray(options.plugins)) {
    if (!options.preset || !options.preset.plugins) {
      options.preset = { plugins: [] };
    }

    options.plugins.forEach((plugin) => {
      if (Array.isArray(plugin)) {
        const [pluginDef, opts = {}] = plugin;
        if (typeof pluginDef === 'string' && isResolvable(pluginDef)) {
          options.preset.plugins.push([require(pluginDef), opts]);
        } else {
          options.preset.plugins.push([pluginDef, opts]);
        }
      } else if (typeof plugin === 'string' && isResolvable(plugin)) {
        options.preset.plugins.push([require(plugin), {}]);
      } else {
        options.preset.plugins.push([plugin, {}]);
      }
    });
  }
  const plugins = [];
  const nanoPlugins = resolveConfig(options);
  for (const nanoPlugin of nanoPlugins) {
    if (Array.isArray(nanoPlugin)) {
      const [processor, opts] = nanoPlugin;
      if (
        typeof opts === 'undefined' ||
        (typeof opts === 'object' && !opts.exclude) ||
        (typeof opts === 'boolean' && opts === true)
      ) {
        plugins.push(processor(opts));
      }
    } else {
      plugins.push(nanoPlugin);
    }
  }
  return postcss(plugins);
}

cssnanoPlugin.postcss = true;
module.exports = cssnanoPlugin;


code:
export = cssnanoPlugin;
/**
 * @type {import('postcss').PluginCreator<Options>}
 * @param {Options=} options
 * @return {import('postcss').Processor}
 */
declare function cssnanoPlugin(options?: Options | undefined): import('postcss').Processor;
declare namespace cssnanoPlugin {
    export { postcss, Options };
}
type Options = {
    preset?: any;
    plugins?: any[];
    configFile?: string;
};
declare var postcss: true;


code:
## 4.2.0 (November 26, 2020)

- Trim Custom Property values when possible (#393)
- Fixed removing unit for zero-length dimentions in `min()`, `max()` and `clamp()` functions (#426)
- Fixed crash on bad value in TRBL declaration value (#412)

## 4.1.1 (November 15, 2020)

- Fixed build setup to exclude full `mdn/data` that reduced the lib size:
    * dist/csso.js: 794.5Kb -> 255.2Kb
    * dist/csso.min.js: 394.4Kb -> 194.2Kb
    * package size: 237.8 kB -> 156.1 kB
    * package unpacked size: 1.3 MB -> 586.8 kB

## 4.1.0 (October 27, 2020)

- Bumped [CSSTree](https://github.com/csstree/csstree) to `^1.0.0`
- Fixed wrongly merging of TRBL values when one of them contains `var()` (#420)
- Fixed wrongly merging of pseudo class and element with the same name, e.g. `:-ms-input-placeholder` and `::-ms-input-placeholder` (#383, #416)
- Fixed wrongly merging of `overflow` fallback (#415)

## 4.0.3 (March 24, 2020)

- Prevented percent sign removal in `flex`/`-ms-flex` (#410)
- Fixed restructuring optimisation in some cases (@charlessuh & @chsuh, #358, #411)
- Bumped dependencies (@AviVahl, #409)

## 4.0.2 (October 28, 2019)

- Fixed clean stage to avoid exceptions when source has unparsed or bad parts (#380)
- Fixed wrong percentage sign removal for zero values (#395)

## 4.0.1 (October 22, 2019)

- Bumped CSSTree to [`1.0.0-alpha.37`](https://github.com/csstree/csstree/releases/tag/v1.0.0-alpha.37) to avoid source map generation inconsistency across Node.js versions

## 4.0.0 (October 21, 2019)

- Dropped support for Node.js < 8
- Refreshed dev dependencies and scripts
- Bumped [CSSTree](https://github.com/csstree/csstree) to `1.0.0-alpha.36` (#399)
- Changed bundle files: `dist/csso.js` and `dist/csso.min.js` instead single `dist/csso-browser.js` (min version)
- Expose `compress()` as `syntax.compress()`

## 3.5.1 (June 7, 2018)

- Bumped [CSSTree](https://github.com/csstree/csstree) to `1.0.0-alpha.29` (fixes some issues)

## 3.5.0 (January 14, 2018)

- Migrated to [CSSTree](https://github.com/csstree/csstree) `1.0.0-alpha.27`

## 3.4.0 (November 3, 2017)

- Added percent sign removal for zero percentages for some properties that is safe (@RubaXa, #286)
- Removed unit removal for zero values in `-ms-flex` due it breaks flex in IE10/11 (#362)
- Improved performance of selectors comparison (@smelukov, #343)

## 3.3.1 (October 17, 2017)

- Fixed merge of `position` declarations when `sticky` fallback is using (@gruzzilkin, #356)

## 3.3.0 (October 12, 2017)

- Migrated to [CSSTree](https://github.com/csstree/csstree) `1.0.0-alpha25`
    - Changed AST format (see [CSSTree change log](https://github.com/csstree/csstree/blob/master/HISTORY.md) for details)
    - Fixed performance issue when generate CSS with source map (quadratic increase in time depending on the size of the CSS)

## 3.2.0 (September 10, 2017)

- Fixed named color compression to apply only when an identifier is guaranteed to be a color
- Added lifting of `@keyframes` to the beginning of style sheet (chunk), but after `@charset` and `@import` rules
- Added removal of `@keyframes`, `@media` and `@supports` with no prelude
- Added removal of duplicate `@keyframes` (#202)
- Added new option `forceMediaMerge` to force media rules merging. It's unsafe in general, but works fine in many cases. Use it on your own risk (#350)
- Bumped `CSSTree` to `1.0.0-alpha23`

## 3.1.1 (April 25, 2017)

- Fixed crash on a number processing when it used not in a list (#335)

## 3.1.0 (April 24, 2017)

- Implemented optimisation for `none` keyword in `border` and `outline` properties (@zoobestik, #41)
- Implemented replacing `rgba(x, x, x, 0)` to `transparent`
- Fixed plus sign omitting for numbers following identifier, hex color, number or unicode range, since it can change the meaning of CSS (e.g. `calc(1px+2px)` has been optimized to `calc(1px2px)` before, now it stays the same)
- Improved usage filtering for nested selectors (i.e. for `:nth-*()`, `:has()`, `:matches` and other pseudos)
- Implemented `blacklist` filtering in usage (#334, see [Black list filtering](https://github.com/css/csso#black-list-filtering))
- Improved white space removing, now white spaces are removing in the beginning and at the ending of sequences, and between stylesheet and block nodes
- Bumped `CSSTree` to `1.0.0-alpha19`

## 3.0.1 (March 14, 2017)

- Fixed declaration merging when declaration contains an `!important`

## 3.0.0 (March 13, 2017)

- Migrated to [CSSTree](https://github.com/csstree/csstree) as AST backend and exposed its API behind `syntax` property
- Extracted CLI into standalone package [css/csso-cli](https://github.com/css/csso-cli)

## 2.3.1 (January 6, 2017)

- Added `\0` IE hack support (#320)

## 2.3.0 (October 25, 2016)

- Added `beforeCompress` and `afterCompress` options support (#316)
- Fixed crash on empty argument in function (#317)

## 2.2.1 (July 25, 2016)

- Fixed shorthand optimisation issue when value has a color value or something unknown (#311)
- Fixed `cursor` broken fallback (#306)

## 2.2.0 (June 23, 2016)

- Implement AST cloning by adding `clone()` [function](https://github.com/css/csso#cloneast) and `clone` [option](https://github.com/css/csso#compressast-options) for `compress()` function (#296)
- Fix parse and translate attribute selector with flags but w/o operator (i.e. `[attrName i]`)
- Don't merge rules with flagged attribute selectors with others (#291)
- Take in account functions when merge TRBL-properties (#297, thanks to @ArturAralin)
- Improve partial merge (#304)
- Tweak scanner, reduce code deoptimizations and other small improvements

## 2.1.1 (May 11, 2016)

- Fix wrong declaration with `\9` hack merge (#295)

## 2.1.0 (May 8, 2016)

- New option `comments` to specify what comments to left: `exclamation`, `first-exclamation` and `none`
- Add `offset` to CSS parse error details
- Fix token `offset` computation

## 2.0.0 (April 5, 2016)

- No more `gonzales` AST format and related code
- `minify()` and `minifyBlock()` is always return an object as result now (i.e. `{ css: String, map: SourceMapGenerator or null }`)
- `parse()`
    - Returns AST in new format (so called `internal`)
    - Dynamic scanner implemented
    - New AST format + dynamic scanner = performance boost and less memory consumption
    - No more `context` argument, context should be specified via `options`
    - Supported contexts now: `stylesheet`, `atrule`, `atruleExpression`, `ruleset`, `selector`, `simpleSelector`, `block`, `declaration` and `value`
    - Drop `needPositions` option, `positions` option should be used instead
    - Drop `needInfo` option, `info` object is attaching to nodes when some information is requested by `options`
    - `options` should be an object, otherwise it treats as empty object
- `compress()`
    - No more AST converting (performance boost and less memory consumption)
    - Drop `outputAst` option
    - Returns an object as result instead of AST (i.e. `{ ast: Object }`)
- Drop methods: `justDoIt()`, `stringify()`, `cleanInfo()`

## 1.8.1 (March 30, 2016)

- Don't remove spaces after function/braces/urls since unsafe (#289)

## 1.8.0 (March 24, 2016)

- Usage data support:
    - Filter rulesets by tag names, class names and ids white lists.
    - More aggressive ruleset moving using class name scopes information.
    - New CLI option `--usage` to pass usage data file.
- Improve initial ruleset merge
    - Change order of ruleset processing, now it's left to right. Previously unmerged rulesets may prevent lookup and other rulesets merge.
    - Difference in pseudo signature just prevents ruleset merging, but don't stop lookup.
    - Simplify block comparison (performance).
- New method `csso.minifyBlock()` for css block compression (e.g. `style` attribute content).
- Ruleset merge improvement: at-rules with block (like `@media` or `@supports`) now can be skipped during ruleset merge lookup if doesn't contain something prevents it.
- FIX: Add negation (`:not()`) to pseudo signature to avoid unsafe merge (old browsers doesn't support it).
- FIX: Check nested parts of value when compute compatibility. It fixes unsafe property merging.

## 1.7.1 (March 16, 2016)

- pass block mode to tokenizer for correct parsing of declarations properties with `//` hack
- fix wrongly `@import` and `@charset` removal on double exclamation comment

## 1.7.0 (March 10, 2016)

- support for [CSS Custom Properties](https://www.w3.org/TR/css-variables/) (#279)
- rework RTBL properties merge – better merge for values with special units and don't merge values with CSS-wide keywords (#255)
- remove redundant universal selectors (#178)
- take in account `!important` when check for property overriding (#280)
- don't merge `text-align` declarations with some values (#281)
- add spaces around `/deep/` combinator on translate, since it together with universal selector can produce a comment
- better keyword and property name resolving (tolerant to hacks and so on)
- integration improvements
    - compression log function could be customized by `logger` option for `compress()` and `minify()`
    - make possible to set initial line and column for parser

## 1.6.4 (March 1, 2016)

- `npm` publish issue (#276)

## 1.6.3 (February 29, 2016)

- add `file` to generated source map since other tools can relay on it in source map transform chain

## 1.6.2 (February 29, 2016)

- tweak some parse error messages and their positions
- fix `:not()` parsing and selector groups in `:not()` is supported now (#215)
- `needPosition` parser option is deprecated, `positions` option should be used instead (`needPosition` is used still if `positions` option omitted)
- expose internal AST API as `csso.internal.*`
- `minify()` adds `sourcesContent` by default when source map is generated
- bring back support for node.js `0.10` until major release (#275)

## 1.6.1 (February 28, 2016)

- fix exception on zero length dimension compress outside declaration (#273)

## 1.6.0 (February 27, 2016)

- **source maps support**
- parser remake:
    - various parsing issues fixed
    - fix unicode sequence processing in ident (#191)
    - support for flags in attribute selector (#270)
    - position (line and column) of parse error (#109)
    - 4x performance boost, less memory consumption
- compressor refactoring
    - internal AST is using doubly linked lists (with safe transformation support during iteration) instead of arrays
    - rename `restructuring` to `restructure` option for `minify()`/`compress()` (`restructuring` is alias for `restructure` now, with lower priority)
    - unquote urls when possible (#141, #60)
- setup code coverage and a number of related fixes
- add eslint to check unused things

## 1.5.4 (January 27, 2016)

- one more fix (in `restructRuleset` this time) with merge of rulesets when a ruleset with same specificity places between them (#264)
- disable partial merge of rulesets in `@keyframes` rulesets (until sure it's correct)

## 1.5.3 (January 25, 2016)

- don't override display values with different browser support (#259)
- fix publish issue (one of modules leak in development state)

## 1.5.2 (January 24, 2016)

- don't merge rulesets if between them a ruleset with same specificity (#264)

## 1.5.1 (January 14, 2016)

- ensure `-` is not used as an identifier in attribute selectors (thanks to @mathiasbynens)
- fix broken `justDoIt()` function
- various small fixes

## 1.5.0 (January 14, 2016)

### Parser

- attach minus to number

### Compressor

- split code base into small modules and related refactoring
- introduce internal AST format for compressor (`gonzales`→`internal` and `internal`→`gonzales` convertors, walkers, translator)
- various optimizations: no snapshots, using caches and indexes
- sort selectors, merge selectors in alphabet order
- compute selector's specificity
- better ruleset restructuring, improve compression of partially equal blocks
- better ruleset merge – not only closest but also disjoined by other rulesets when safe
- join `@media` with same query
- `outputAst` – new option to specify output AST format (`gonzales` by default for backward compatibility)
- remove quotes surrounding attribute values in attribute selectors when possible (#73)
- replace `from`→`0%` and `100%`→`to` at `@keyframes` (#205)
- prevent partial merge of rulesets at `@keyframes` (#80, #197)

### API

- walker for `gonzales` AST was implemented

### CLI

- new option `--stat` (output stat in `stderr`)
- new optional parameter `level` for `--debug` option

## 1.4.4 (December 10, 2015)

- prevent removal of spaces after braces that before identifier that breaking at-rules expressions (#258)

## 1.4.3 (December 4, 2015)

- fix unicode-range parsing that cause to wrong function detection (#250)

## 1.4.2 (November 9, 2015)

- allow spaces between `progid:` and rest part of value for IE's `filter` property as `autoprefixer` generates this kind of code (#249)
- fixes for Windows:
  - correct processing new lines
  - normalize file content in test suite
- fixes to work in strict mode (#252)
- init compressor dictionaries for every css block (#248, #251)
- bump uglify-js version

## 1.4.1 (October 20, 2015)

- allow merge for `display` property (#167, #244)
- more accurate `rect` (`clip` property value) merge
- fix typo when specifying options in cli (thanks to @Taritsyn)
- fix safe unit values merge with keyword values (#244)
- fix wrong descendant combinator removal (#246)
- build browser version on `prepublish` (thanks to @silentroach)
- parser: store whitespaces as single token (performance and reduce memory consumption)
- rearrange compress tests layout

## 1.4 (October 16, 2015)

Bringing project back to life. Changed files structure, cleaned up and refactored most of sources.

### Common

- single code base (no more `src` folder)
- build browser version with `browserify` (no more `make`, and `web` folder), browser version is available at `dist/csso-browser.js`
- main file is `lib/index.js` now
- minimal `node.js` version is `0.12` now
- restrict file list to publish on npm (no more useless folders and files in package)
- add `jscs` to control code style
- automate `gh-pages` update
- util functions reworked
- translator reworked
- test suite reworked
- compressor refactored
- initial parser refactoring

### API

- new method `minify(src, options)`, options:
  - `restructuring` – if set to `false`, disable structure optimisations (`true` by default)
  - `debug` - outputs intermediate state of CSS during compression (`false` by default)
- deprecate `justDoIt()` method (use `minify` instead)
- rename `treeToString()` method to `stringify()`
- drop `printTree()` method
- AST node info
  - `column` and `offset` added
  - `ln` renamed to `line`
  - fix line counting across multiple files and input with CR LF (#147)

### CLI

- completely reworked, use [clap](https://github.com/lahmatiy/clap) to parse argv
- add support for input from stdin (#128)
- drop undocumented and obsoleted options `--rule` and `--parser` (suppose nobody use it)
- drop `-off` alias for `--restructure-off` as incorrect (only one letter options should starts with single `-`)
- new option `--debug` that reflecting to `options.debug` for `minify`

### Parsing and optimizations

- keep all exclamation comments (#194)
- add `/deep/` combinator support (#209)
- attribute selector
  - allow colon in attribute name (#237)
  - support for namespaces (#233)
- color
  - support all css/html colors
  - convert `hsla` to `rgba` and `hls` to `rgb`
  - convert `rgba` with 1 as alpha value to `rgb` (#122)
  - interpolate `rgb` and `rgba` percentage values to absolute values
  - replace percentage values in `rgba` for normalized/interpolated values
  - lowercase hex colors and color names (#169)
  - fix color minification when hex value replaced for color name (#176)
  - fit rgb values to 0..255 range (#181)
- calc
  - remove spaces for multiple operator in calc
  - don't remove units inside calc (#222)
  - fix wrong white space removal around `+` and `-` (#228)
- don't remove units in `flex` property as it could change value meaning (#200)
- don't merge `\9` hack values (#231)
- merge property values only if they have the same functions (#150, #227)
- don't merge property values with some sort of units (#140, #161)
- fix `!important` issue for `top-right-bottom-left` properties (#189)
- fix `top-right-bottom-left` properties merge (#139, #175)
- support for unicode-range (#148)
- don't crash on ruleset with no selector (#135)
- tolerant to class names that starts with digit (#99, #105)
- fix background compressing (#170)

## 1.3.12 (October 8, 2015)

- Case insensitive check for `!important` (#187)
- Fix problems with using `csso` as cli command on Windows (#83, #136, #142 and others)
- Remove byte order marker (the UTF-8 BOM) from input
- Don't strip space between funktion-funktion and funktion-vhash (#134)
- Don't merge TRBL values having \9 (hack for IE8 in bootstrap) (#159, #214, #230, #231 and others)
- Don't strip units off dimensions of non-length (#226, #229 and others)

## 1.3.7 (February 11, 2013)

- Gonzales 1.0.7.

## 1.3.6 (November 26, 2012)

- Gonzales 1.0.6.

## 1.3.5 (October 28, 2012)

- Gonzales 1.0.5.
- Protecting copyright notices in CSS: https://github.com/css/csso/issues/92
- Zero CSS throws an error: https://github.com/css/csso/issues/96
- Don't minify the second `0s` in Firefox for animations: https://github.com/css/csso/issues/100
- Japan manual
- BEM ready documentation

## 1.3.4 (October 10, 2012)

- @page inside @media Causes Error: https://github.com/css/csso/issues/90

## 1.3.3 (October 9, 2012)

- CSSO 1.3.2 compresses ".t-1" and ".t-01" as identical classes: https://github.com/css/csso/issues/88

## 1.3.2 (October 8, 2012)

- filter + important breaks CSSO v1.3.1: https://github.com/css/csso/issues/87

## 1.3.1 (October 8, 2012)

- "filter" IE property breaks CSSO v1.3.0: https://github.com/css/csso/issues/86

## 1.3.0 (October 4, 2012)

- PeCode CSS parser replaced by Gonzales CSS parser


code:
[![NPM version](https://img.shields.io/npm/v/csso.svg)](https://www.npmjs.com/package/csso)
[![Build Status](https://travis-ci.org/css/csso.svg?branch=master)](https://travis-ci.org/css/csso)
[![Coverage Status](https://coveralls.io/repos/github/css/csso/badge.svg?branch=master)](https://coveralls.io/github/css/csso?branch=master)
[![NPM Downloads](https://img.shields.io/npm/dm/csso.svg)](https://www.npmjs.com/package/csso)
[![Twitter](https://img.shields.io/badge/Twitter-@cssoptimizer-blue.svg)](https://twitter.com/cssoptimizer)

CSSO (CSS Optimizer) is a CSS minifier. It performs three sort of transformations: cleaning (removing redundant), compression (replacement for shorter form) and restructuring (merge of declarations, rulesets and so on). As a result your CSS becomes much smaller.

[![Originated by Yandex](https://cdn.rawgit.com/css/csso/8d1b89211ac425909f735e7d5df87ee16c2feec6/docs/yandex.svg)](https://www.yandex.com/)
[![Sponsored by Avito](https://cdn.rawgit.com/css/csso/8d1b89211ac425909f735e7d5df87ee16c2feec6/docs/avito.svg)](https://www.avito.ru/)

## Ready to use

- [Web interface](http://css.github.io/csso/csso.html)
- [csso-cli](https://github.com/css/csso-cli) – command line interface
- [gulp-csso](https://github.com/ben-eb/gulp-csso) – `Gulp` plugin
- [grunt-csso](https://github.com/t32k/grunt-csso) – `Grunt` plugin
- [broccoli-csso](https://github.com/sindresorhus/broccoli-csso) – `Broccoli` plugin
- [postcss-csso](https://github.com/lahmatiy/postcss-csso) – `PostCSS` plugin
- [csso-loader](https://github.com/sandark7/csso-loader) – `webpack` loader
- [csso-webpack-plugin](https://github.com/zoobestik/csso-webpack-plugin) – `webpack` plugin
- [CSSO Visual Studio Code plugin](https://marketplace.visualstudio.com/items?itemName=Aneryu.csso)

## Install

```
npm install csso
```

## API

<!-- TOC depthfrom:3 -->

- [minify(source[, options])](#minifysource-options)
- [minifyBlock(source[, options])](#minifyblocksource-options)
- [syntax.compress(ast[, options])](#syntaxcompressast-options)
- [Source maps](#source-maps)
- [Usage data](#usage-data)
    - [White list filtering](#white-list-filtering)
    - [Black list filtering](#black-list-filtering)
    - [Scopes](#scopes)

<!-- /TOC -->

Basic usage:

```js
var csso = require('csso');

var minifiedCss = csso.minify('.test { color: #ff0000; }').css;

console.log(minifiedCss);
// .test{color:red}
```

CSSO is based on [CSSTree](https://github.com/csstree/csstree) to parse CSS into AST, AST traversal and to generate AST back to CSS. All `CSSTree` API is available behind `syntax` field. You may minify CSS step by step:

```js
var csso = require('csso');
var ast = csso.syntax.parse('.test { color: #ff0000; }');
var compressedAst = csso.syntax.compress(ast).ast;
var minifiedCss = csso.syntax.generate(compressedAst);

console.log(minifiedCss);
// .test{color:red}
```

> Warning: CSSO uses early versions of CSSTree that still in active development. CSSO doesn't guarantee API behind `syntax` field or AST format will not change in future releases of CSSO, since it's subject to change in CSSTree. Be careful with CSSO updates if you use `syntax` API until this warning removal.

### minify(source[, options])

Minify `source` CSS passed as `String`.

```js
var result = csso.minify('.test { color: #ff0000; }', {
    restructure: false,   // don't change CSS structure, i.e. don't merge declarations, rulesets etc
    debug: true           // show additional debug information:
                          // true or number from 1 to 3 (greater number - more details)
});

console.log(result.css);
// > .test{color:red}
```

Returns an object with properties:

- css `String` – resulting CSS
- map `Object` – instance of [`SourceMapGenerator`](https://github.com/mozilla/source-map#sourcemapgenerator) or `null`

Options:

- sourceMap

  Type: `Boolean`
  Default: `false`

  Generate a source map when `true`.

- filename

  Type: `String`
  Default: `'<unknown>'`

  Filename of input CSS, uses for source map generation.

- debug

  Type: `Boolean`
  Default: `false`

  Output debug information to `stderr`.

- beforeCompress

  Type: `function(ast, options)` or `Array<function(ast, options)>` or `null`
  Default: `null`

  Called right after parse is run.

- afterCompress

  Type: `function(compressResult, options)` or `Array<function(compressResult, options)>` or `null`
  Default: `null`

  Called right after [`syntax.compress()`](#syntaxcompressast-options) is run.

- Other options are the same as for [`syntax.compress()`](#syntaxcompressast-options) function.

### minifyBlock(source[, options])

The same as `minify()` but for list of declarations. Usually it's a `style` attribute value.

```js
var result = csso.minifyBlock('color: rgba(255, 0, 0, 1); color: #ff0000');

console.log(result.css);
// > color:red
```

### syntax.compress(ast[, options])

Does the main task – compress an AST. This is CSSO's extension in CSSTree syntax API.

> NOTE: `syntax.compress()` performs AST compression by transforming input AST by default (since AST cloning is expensive and needed in rare cases). Use `clone` option with truthy value in case you want to keep input AST untouched.

Returns an object with properties:

- ast `Object` – resulting AST

Options:

- restructure

  Type: `Boolean`
  Default: `true`

  Disable or enable a structure optimisations.

- forceMediaMerge

  Type: `Boolean`
  Default: `false`

  Enables merging of `@media` rules with the same media query by splitted by other rules. The optimisation is unsafe in general, but should work fine in most cases. Use it on your own risk.

- clone

  Type: `Boolean`
  Default: `false`

  Transform a copy of input AST if `true`. Useful in case of AST reuse.

- comments

  Type: `String` or `Boolean`
  Default: `true`

  Specify what comments to leave:

  - `'exclamation'` or `true` – leave all exclamation comments (i.e. `/*! .. */`)
  - `'first-exclamation'` – remove every comment except first one
  - `false` – remove all comments

- usage

  Type: `Object` or `null`
  Default: `null`

  Usage data for advanced optimisations (see [Usage data](#usage-data) for details)

- logger

  Type: `Function` or `null`
  Default: `null`

  Function to track every step of transformation.

### Source maps

To get a source map set `true` for `sourceMap` option. Additianaly `filename` option can be passed to specify source file. When `sourceMap` option is `true`, `map` field of result object will contain a [`SourceMapGenerator`](https://github.com/mozilla/source-map#sourcemapgenerator) instance. This object can be mixed with another source map or translated to string.

```js
var csso = require('csso');
var css = fs.readFileSync('path/to/my.css', 'utf8');
var result = csso.minify(css, {
  filename: 'path/to/my.css', // will be added to source map as reference to source file
  sourceMap: true             // generate source map
});

console.log(result);
// { css: '...minified...', map: SourceMapGenerator {} }

console.log(result.map.toString());
// '{ .. source map content .. }'
```

Example of generating source map with respect of source map from input CSS:

```js
var require('source-map');
var csso = require('csso');
var inputFile = 'path/to/my.css';
var input = fs.readFileSync(inputFile, 'utf8');
var inputMap = input.match(/\/\*# sourceMappingURL=(\S+)\s*\*\/\s*$/);
var output = csso.minify(input, {
  filename: inputFile,
  sourceMap: true
});

// apply input source map to output
if (inputMap) {
  output.map.applySourceMap(
    new SourceMapConsumer(inputMap[1]),
    inputFile
  )
}

// result CSS with source map
console.log(
  output.css +
  '/*# sourceMappingURL=data:application/json;base64,' +
  new Buffer(output.map.toString()).toString('base64') +
  ' */'
);
```

### Usage data

`CSSO` can use data about how `CSS` is used in a markup for better compression. File with this data (`JSON`) can be set using `usage` option. Usage data may contain following sections:

- `blacklist` – a set of black lists (see [Black list filtering](#black-list-filtering))
- `tags` – white list of tags
- `ids` – white list of ids
- `classes` – white list of classes
- `scopes` – groups of classes which never used with classes from other groups on the same element

All sections are optional. Value of `tags`, `ids` and `classes` should be an array of a string, value of `scopes` should be an array of arrays of strings. Other values are ignoring.

#### White list filtering

`tags`, `ids` and `classes` are using on clean stage to filter selectors that contain something not in the lists. Selectors are filtering only by those kind of simple selector which white list is specified. For example, if only `tags` list is specified then type selectors are checking, and if all type selectors in selector present in list or selector has no any type selector it isn't filter.

> `ids` and `classes` are case sensitive, `tags` – is not.

Input CSS:

```css
* { color: green; }
ul, ol, li { color: blue; }
UL.foo, span.bar { color: red; }
```

Usage data:

```json
{
    "tags": ["ul", "LI"]
}
```

Resulting CSS:

```css
*{color:green}ul,li{color:blue}ul.foo{color:red}
```

Filtering performs for nested selectors too. `:not()` pseudos content is ignoring since the result of matching is unpredictable. Example for the same usage data as above:

```css
:nth-child(2n of ul, ol) { color: red }
:nth-child(3n + 1 of img) { color: yellow }
:not(div, ol, ul) { color: green }
:has(:matches(ul, ol), ul, ol) { color: blue }
```

Turns into:

```css
:nth-child(2n of ul){color:red}:not(div,ol,ul){color:green}:has(:matches(ul),ul){color:blue}
```

#### Black list filtering

Black list filtering performs the same as white list filtering, but filters things that mentioned in the lists. `blacklist` can contain the lists `tags`, `ids` and `classes`.

Black list has a higher priority, so when something mentioned in the white list and in the black list then white list occurrence is ignoring. The `:not()` pseudos content ignoring as well.

```css
* { color: green; }
ul, ol, li { color: blue; }
UL.foo, li.bar { color: red; }
```

Usage data:

```json
{
    "blacklist": {
        "tags": ["ul"]
    },
    "tags": ["ul", "LI"]
}
```

Resulting CSS:

```css
*{color:green}li{color:blue}li.bar{color:red}
```

#### Scopes

Scopes is designed for CSS scope isolation solutions such as [css-modules](https://github.com/css-modules/css-modules). Scopes are similar to namespaces and define lists of class names that exclusively used on some markup. This information allows the optimizer to move rules more agressive. Since it assumes selectors from different scopes don't match for the same element. This can improve rule merging.

Suppose we have a file:

```css
.module1-foo { color: red; }
.module1-bar { font-size: 1.5em; background: yellow; }

.module2-baz { color: red; }
.module2-qux { font-size: 1.5em; background: yellow; width: 50px; }
```

It can be assumed that first two rules are never used with the second two on the same markup. But we can't say that for sure without a markup review. The optimizer doesn't know it either and will perform safe transformations only. The result will be the same as input but with no spaces and some semicolons:

```css
.module1-foo{color:red}.module1-bar{font-size:1.5em;background:#ff0}.module2-baz{color:red}.module2-qux{font-size:1.5em;background:#ff0;width:50px}
```

With usage data `CSSO` can produce better output. If follow usage data is provided:

```json
{
    "scopes": [
        ["module1-foo", "module1-bar"],
        ["module2-baz", "module2-qux"]
    ]
}
```

The result will be (29 bytes extra saving):

```css
.module1-foo,.module2-baz{color:red}.module1-bar,.module2-qux{font-size:1.5em;background:#ff0}.module2-qux{width:50px}
```

If class name isn't mentioned in the `scopes` it belongs to default scope. `scopes` data doesn't affect `classes` whitelist. If class name mentioned in `scopes` but missed in `classes` (both sections are specified) it will be filtered.

Note that class name can't be set for several scopes. Also a selector can't have class names from different scopes. In both cases an exception will thrown.

Currently the optimizer doesn't care about changing order safety for out-of-bounds selectors (i.e. selectors that match to elements without class name, e.g. `.scope div` or `.scope ~ :last-child`). It assumes that scoped CSS modules doesn't relay on it's order. It may be fix in future if to be an issue.


code:
var resolveKeyword = require('css-tree').keyword;
var { hasNoChildren } = require('./utils');

module.exports = function cleanAtrule(node, item, list) {
    if (node.block) {
        // otherwise removed at-rule don't prevent @import for removal
        if (this.stylesheet !== null) {
            this.stylesheet.firstAtrulesAllowed = false;
        }

        if (hasNoChildren(node.block)) {
            list.remove(item);
            return;
        }
    }

    switch (node.name) {
        case 'charset':
            if (hasNoChildren(node.prelude)) {
                list.remove(item);
                return;
            }

            // if there is any rule before @charset -> remove it
            if (item.prev) {
                list.remove(item);
                return;
            }

            break;

        case 'import':
            if (this.stylesheet === null || !this.stylesheet.firstAtrulesAllowed) {
                list.remove(item);
                return;
            }

            // if there are some rules that not an @import or @charset before @import
            // remove it
            list.prevUntil(item.prev, function(rule) {
                if (rule.type === 'Atrule') {
                    if (rule.name === 'import' || rule.name === 'charset') {
                        return;
                    }
                }

                this.root.firstAtrulesAllowed = false;
                list.remove(item);
                return true;
            }, this);

            break;

        default:
            var name = resolveKeyword(node.name).basename;
            if (name === 'keyframes' ||
                name === 'media' ||
                name === 'supports') {

                // drop at-rule with no prelude
                if (hasNoChildren(node.prelude) || hasNoChildren(node.block)) {
                    list.remove(item);
                }
            }
    }
};


code:
module.exports = function cleanComment(data, item, list) {
    list.remove(item);
};


code:
var property = require('css-tree').property;

module.exports = function cleanDeclartion(node, item, list) {
    if (node.value.children && node.value.children.isEmpty()) {
        list.remove(item);
        return;
    }

    if (property(node.property).custom) {
        if (/\S/.test(node.value.value)) {
            node.value.value = node.value.value.trim();
        }
    }
};


code:
var { isNodeChildrenList } = require('./utils');

module.exports = function cleanRaw(node, item, list) {
    // raw in stylesheet or block children
    if (isNodeChildrenList(this.stylesheet, list) ||
        isNodeChildrenList(this.block, list)) {
        list.remove(item);
    }
};


code:
var hasOwnProperty = Object.prototype.hasOwnProperty;
var walk = require('css-tree').walk;
var { hasNoChildren } = require('./utils');

function cleanUnused(selectorList, usageData) {
    selectorList.children.each(function(selector, item, list) {
        var shouldRemove = false;

        walk(selector, function(node) {
            // ignore nodes in nested selectors
            if (this.selector === null || this.selector === selectorList) {
                switch (node.type) {
                    case 'SelectorList':
                        // TODO: remove toLowerCase when pseudo selectors will be normalized
                        // ignore selectors inside :not()
                        if (this.function === null || this.function.name.toLowerCase() !== 'not') {
                            if (cleanUnused(node, usageData)) {
                                shouldRemove = true;
                            }
                        }
                        break;

                    case 'ClassSelector':
                        if (usageData.whitelist !== null &&
                            usageData.whitelist.classes !== null &&
                            !hasOwnProperty.call(usageData.whitelist.classes, node.name)) {
                            shouldRemove = true;
                        }
                        if (usageData.blacklist !== null &&
                            usageData.blacklist.classes !== null &&
                            hasOwnProperty.call(usageData.blacklist.classes, node.name)) {
                            shouldRemove = true;
                        }
                        break;

                    case 'IdSelector':
                        if (usageData.whitelist !== null &&
                            usageData.whitelist.ids !== null &&
                            !hasOwnProperty.call(usageData.whitelist.ids, node.name)) {
                            shouldRemove = true;
                        }
                        if (usageData.blacklist !== null &&
                            usageData.blacklist.ids !== null &&
                            hasOwnProperty.call(usageData.blacklist.ids, node.name)) {
                            shouldRemove = true;
                        }
                        break;

                    case 'TypeSelector':
                        // TODO: remove toLowerCase when type selectors will be normalized
                        // ignore universal selectors
                        if (node.name.charAt(node.name.length - 1) !== '*') {
                            if (usageData.whitelist !== null &&
                                usageData.whitelist.tags !== null &&
                                !hasOwnProperty.call(usageData.whitelist.tags, node.name.toLowerCase())) {
                                shouldRemove = true;
                            }
                            if (usageData.blacklist !== null &&
                                usageData.blacklist.tags !== null &&
                                hasOwnProperty.call(usageData.blacklist.tags, node.name.toLowerCase())) {
                                shouldRemove = true;
                            }
                        }
                        break;
                }
            }
        });

        if (shouldRemove) {
            list.remove(item);
        }
    });

    return selectorList.children.isEmpty();
}

module.exports = function cleanRule(node, item, list, options) {
    if (hasNoChildren(node.prelude) || hasNoChildren(node.block)) {
        list.remove(item);
        return;
    }

    var usageData = options.usage;

    if (usageData && (usageData.whitelist !== null || usageData.blacklist !== null)) {
        cleanUnused(node.prelude, usageData);

        if (hasNoChildren(node.prelude)) {
            list.remove(item);
            return;
        }
    }
};


code:
// remove useless universal selector
module.exports = function cleanTypeSelector(node, item, list) {
    var name = item.data.name;

    // check it's a non-namespaced universal selector
    if (name !== '*') {
        return;
    }

    // remove when universal selector before other selectors
    var nextType = item.next && item.next.data.type;
    if (nextType === 'IdSelector' ||
        nextType === 'ClassSelector' ||
        nextType === 'AttributeSelector' ||
        nextType === 'PseudoClassSelector' ||
        nextType === 'PseudoElementSelector') {
        list.remove(item);
    }
};


code:
var { isNodeChildrenList } = require('./utils');

function isSafeOperator(node) {
    return node.type === 'Operator' && node.value !== '+' && node.value !== '-';
}

module.exports = function cleanWhitespace(node, item, list) {
    // remove when first or last item in sequence
    if (item.next === null || item.prev === null) {
        list.remove(item);
        return;
    }

    // white space in stylesheet or block children
    if (isNodeChildrenList(this.stylesheet, list) ||
        isNodeChildrenList(this.block, list)) {
        list.remove(item);
        return;
    }

    if (item.next.data.type === 'WhiteSpace') {
        list.remove(item);
        return;
    }

    if (isSafeOperator(item.prev.data) || isSafeOperator(item.next.data)) {
        list.remove(item);
        return;
    }
};


code:
var walk = require('css-tree').walk;
var handlers = {
    Atrule: require('./Atrule'),
    Comment: require('./Comment'),
    Declaration: require('./Declaration'),
    Raw: require('./Raw'),
    Rule: require('./Rule'),
    TypeSelector: require('./TypeSelector'),
    WhiteSpace: require('./WhiteSpace')
};

module.exports = function(ast, options) {
    walk(ast, {
        leave: function(node, item, list) {
            if (handlers.hasOwnProperty(node.type)) {
                handlers[node.type].call(this, node, item, list, options);
            }
        }
    });
};


code:
module.exports = {
    hasNoChildren: function(node) {
        return !node || !node.children || node.children.isEmpty();
    },
    isNodeChildrenList: function(node, list) {
        return node !== null && node.children === list;
    }
};


code:
var List = require('css-tree').List;
var clone = require('css-tree').clone;
var usageUtils = require('./usage');
var clean = require('./clean');
var replace = require('./replace');
var restructure = require('./restructure');
var walk = require('css-tree').walk;

function readChunk(children, specialComments) {
    var buffer = new List();
    var nonSpaceTokenInBuffer = false;
    var protectedComment;

    children.nextUntil(children.head, function(node, item, list) {
        if (node.type === 'Comment') {
            if (!specialComments || node.value.charAt(0) !== '!') {
                list.remove(item);
                return;
            }

            if (nonSpaceTokenInBuffer || protectedComment) {
                return true;
            }

            list.remove(item);
            protectedComment = node;
            return;
        }

        if (node.type !== 'WhiteSpace') {
            nonSpaceTokenInBuffer = true;
        }

        buffer.insert(list.remove(item));
    });

    return {
        comment: protectedComment,
        stylesheet: {
            type: 'StyleSheet',
            loc: null,
            children: buffer
        }
    };
}

function compressChunk(ast, firstAtrulesAllowed, num, options) {
    options.logger('Compress block #' + num, null, true);

    var seed = 1;

    if (ast.type === 'StyleSheet') {
        ast.firstAtrulesAllowed = firstAtrulesAllowed;
        ast.id = seed++;
    }

    walk(ast, {
        visit: 'Atrule',
        enter: function markScopes(node) {
            if (node.block !== null) {
                node.block.id = seed++;
            }
        }
    });
    options.logger('init', ast);

    // remove redundant
    clean(ast, options);
    options.logger('clean', ast);

    // replace nodes for shortened forms
    replace(ast, options);
    options.logger('replace', ast);

    // structure optimisations
    if (options.restructuring) {
        restructure(ast, options);
    }

    return ast;
}

function getCommentsOption(options) {
    var comments = 'comments' in options ? options.comments : 'exclamation';

    if (typeof comments === 'boolean') {
        comments = comments ? 'exclamation' : false;
    } else if (comments !== 'exclamation' && comments !== 'first-exclamation') {
        comments = false;
    }

    return comments;
}

function getRestructureOption(options) {
    if ('restructure' in options) {
        return options.restructure;
    }

    return 'restructuring' in options ? options.restructuring : true;
}

function wrapBlock(block) {
    return new List().appendData({
        type: 'Rule',
        loc: null,
        prelude: {
            type: 'SelectorList',
            loc: null,
            children: new List().appendData({
                type: 'Selector',
                loc: null,
                children: new List().appendData({
                    type: 'TypeSelector',
                    loc: null,
                    name: 'x'
                })
            })
        },
        block: block
    });
}

module.exports = function compress(ast, options) {
    ast = ast || { type: 'StyleSheet', loc: null, children: new List() };
    options = options || {};

    var compressOptions = {
        logger: typeof options.logger === 'function' ? options.logger : function() {},
        restructuring: getRestructureOption(options),
        forceMediaMerge: Boolean(options.forceMediaMerge),
        usage: options.usage ? usageUtils.buildIndex(options.usage) : false
    };
    var specialComments = getCommentsOption(options);
    var firstAtrulesAllowed = true;
    var input;
    var output = new List();
    var chunk;
    var chunkNum = 1;
    var chunkChildren;

    if (options.clone) {
        ast = clone(ast);
    }

    if (ast.type === 'StyleSheet') {
        input = ast.children;
        ast.children = output;
    } else {
        input = wrapBlock(ast);
    }

    do {
        chunk = readChunk(input, Boolean(specialComments));
        compressChunk(chunk.stylesheet, firstAtrulesAllowed, chunkNum++, compressOptions);
        chunkChildren = chunk.stylesheet.children;

        if (chunk.comment) {
            // add \n before comment if there is another content in output
            if (!output.isEmpty()) {
                output.insert(List.createItem({
                    type: 'Raw',
                    value: '\n'
                }));
            }

            output.insert(List.createItem(chunk.comment));

            // add \n after comment if chunk is not empty
            if (!chunkChildren.isEmpty()) {
                output.insert(List.createItem({
                    type: 'Raw',
                    value: '\n'
                }));
            }
        }

        if (firstAtrulesAllowed && !chunkChildren.isEmpty()) {
            var lastRule = chunkChildren.last();

            if (lastRule.type !== 'Atrule' ||
               (lastRule.name !== 'import' && lastRule.name !== 'charset')) {
                firstAtrulesAllowed = false;
            }
        }

        if (specialComments !== 'exclamation') {
            specialComments = false;
        }

        output.appendList(chunkChildren);
    } while (!input.isEmpty());

    return {
        ast: ast
    };
};


code:
var csstree = require('css-tree');
var parse = csstree.parse;
var compress = require('./compress');
var generate = csstree.generate;

function debugOutput(name, options, startTime, data) {
    if (options.debug) {
        console.error('## ' + name + ' done in %d ms\n', Date.now() - startTime);
    }

    return data;
}

function createDefaultLogger(level) {
    var lastDebug;

    return function logger(title, ast) {
        var line = title;

        if (ast) {
            line = '[' + ((Date.now() - lastDebug) / 1000).toFixed(3) + 's] ' + line;
        }

        if (level > 1 && ast) {
            var css = generate(ast);

            // when level 2, limit css to 256 symbols
            if (level === 2 && css.length > 256) {
                css = css.substr(0, 256) + '...';
            }

            line += '\n  ' + css + '\n';
        }

        console.error(line);
        lastDebug = Date.now();
    };
}

function copy(obj) {
    var result = {};

    for (var key in obj) {
        result[key] = obj[key];
    }

    return result;
}

function buildCompressOptions(options) {
    options = copy(options);

    if (typeof options.logger !== 'function' && options.debug) {
        options.logger = createDefaultLogger(options.debug);
    }

    return options;
}

function runHandler(ast, options, handlers) {
    if (!Array.isArray(handlers)) {
        handlers = [handlers];
    }

    handlers.forEach(function(fn) {
        fn(ast, options);
    });
}

function minify(context, source, options) {
    options = options || {};

    var filename = options.filename || '<unknown>';
    var result;

    // parse
    var ast = debugOutput('parsing', options, Date.now(),
        parse(source, {
            context: context,
            filename: filename,
            positions: Boolean(options.sourceMap)
        })
    );

    // before compress handlers
    if (options.beforeCompress) {
        debugOutput('beforeCompress', options, Date.now(),
            runHandler(ast, options, options.beforeCompress)
        );
    }

    // compress
    var compressResult = debugOutput('compress', options, Date.now(),
        compress(ast, buildCompressOptions(options))
    );

    // after compress handlers
    if (options.afterCompress) {
        debugOutput('afterCompress', options, Date.now(),
            runHandler(compressResult, options, options.afterCompress)
        );
    }

    // generate
    if (options.sourceMap) {
        result = debugOutput('generate(sourceMap: true)', options, Date.now(), (function() {
            var tmp = generate(compressResult.ast, { sourceMap: true });
            tmp.map._file = filename; // since other tools can relay on file in source map transform chain
            tmp.map.setSourceContent(filename, source);
            return tmp;
        }()));
    } else {
        result = debugOutput('generate', options, Date.now(), {
            css: generate(compressResult.ast),
            map: null
        });
    }

    return result;
}

function minifyStylesheet(source, options) {
    return minify('stylesheet', source, options);
}

function minifyBlock(source, options) {
    return minify('declarationList', source, options);
}

module.exports = {
    version: require('../package.json').version,

    // main methods
    minify: minifyStylesheet,
    minifyBlock: minifyBlock,

    // css syntax parser/walkers/generator/etc
    syntax: Object.assign({
        compress: compress
    }, csstree)
};