code:
'use strict';
const parser = require('postcss-selector-parser');
const canUnquote = require('./lib/canUnquote.js');

const pseudoElements = new Set([
  '::before',
  '::after',
  '::first-letter',
  '::first-line',
]);

/**
 * @param {parser.Attribute} selector
 * @return {void}
 */
function attribute(selector) {
  if (selector.value) {
    if (selector.raws.value) {
      // Join selectors that are split over new lines
      selector.raws.value = selector.raws.value.replace(/\\\n/g, '').trim();
    }
    if (canUnquote(selector.value)) {
      selector.quoteMark = null;
    }

    if (selector.operator) {
      selector.operator = /** @type {parser.AttributeOperator} */ (
        selector.operator.trim()
      );
    }
  }

  selector.rawSpaceBefore = '';
  selector.rawSpaceAfter = '';
  selector.spaces.attribute = { before: '', after: '' };
  selector.spaces.operator = { before: '', after: '' };
  selector.spaces.value = {
    before: '',
    after: selector.insensitive ? ' ' : '',
  };

  if (selector.raws.spaces) {
    selector.raws.spaces.attribute = {
      before: '',
      after: '',
    };

    selector.raws.spaces.operator = {
      before: '',
      after: '',
    };

    selector.raws.spaces.value = {
      before: '',
      after: selector.insensitive ? ' ' : '',
    };

    if (selector.insensitive) {
      selector.raws.spaces.insensitive = {
        before: '',
        after: '',
      };
    }
  }

  selector.attribute = selector.attribute.trim();
}

/**
 * @param {parser.Combinator} selector
 * @return {void}
 */
function combinator(selector) {
  const value = selector.value.trim();
  selector.spaces.before = '';
  selector.spaces.after = '';
  selector.rawSpaceBefore = '';
  selector.rawSpaceAfter = '';
  selector.value = value.length ? value : ' ';
}

const pseudoReplacements = new Map([
  [':nth-child', ':first-child'],
  [':nth-of-type', ':first-of-type'],
  [':nth-last-child', ':last-child'],
  [':nth-last-of-type', ':last-of-type'],
]);

/**
 * @param {parser.Pseudo} selector
 * @return {void}
 */
function pseudo(selector) {
  const value = selector.value.toLowerCase();

  if (selector.nodes.length === 1 && pseudoReplacements.has(value)) {
    const first = selector.at(0);
    const one = first.at(0);

    if (first.length === 1) {
      if (one.value === '1') {
        selector.replaceWith(
          parser.pseudo({
            value: /** @type {string} */ (pseudoReplacements.get(value)),
          })
        );
      }

      if (one.value && one.value.toLowerCase() === 'even') {
        one.value = '2n';
      }
    }

    if (first.length === 3) {
      const two = first.at(1);
      const three = first.at(2);

      if (
        one.value &&
        one.value.toLowerCase() === '2n' &&
        two.value === '+' &&
        three.value === '1'
      ) {
        one.value = 'odd';

        two.remove();
        three.remove();
      }
    }

    return;
  }

  selector.walk((child) => {
    if (child.type === 'selector' && child.parent) {
      const uniques = new Set();
      child.parent.each((sibling) => {
        const siblingStr = String(sibling);

        if (!uniques.has(siblingStr)) {
          uniques.add(siblingStr);
        } else {
          sibling.remove();
        }
      });
    }
  });

  if (pseudoElements.has(value)) {
    selector.value = selector.value.slice(1);
  }
}

const tagReplacements = new Map([
  ['from', '0%'],
  ['100%', 'to'],
]);

/**
 * @param {parser.Tag} selector
 * @return {void}
 */
function tag(selector) {
  const value = selector.value.toLowerCase();

  if (tagReplacements.has(value)) {
    selector.value = /** @type {string} */ (tagReplacements.get(value));
  }
}

/**
 * @param {parser.Universal} selector
 * @return {void}
 */
function universal(selector) {
  const next = selector.next();

  if (next && next.type !== 'combinator') {
    selector.remove();
  }
}

const reducers = new Map(
  /** @type {[string, ((selector: parser.Node) => void)][]}*/ ([
    ['attribute', attribute],
    ['combinator', combinator],
    ['pseudo', pseudo],
    ['tag', tag],
    ['universal', universal],
  ])
);

/**
 * @type {import('postcss').PluginCreator<void>}
 * @return {import('postcss').Plugin}
 */
function pluginCreator() {
  return {
    postcssPlugin: 'postcss-minify-selectors',

    OnceExit(css) {
      const cache = new Map();
      const processor = parser((selectors) => {
        const uniqueSelectors = new Set();

        selectors.walk((sel) => {
          // Trim whitespace around the value
          sel.spaces.before = sel.spaces.after = '';
          const reducer = reducers.get(sel.type);
          if (reducer !== undefined) {
            reducer(sel);
            return;
          }

          const toString = String(sel);

          if (
            sel.type === 'selector' &&
            sel.parent &&
            sel.parent.type !== 'pseudo'
          ) {
            if (!uniqueSelectors.has(toString)) {
              uniqueSelectors.add(toString);
            } else {
              sel.remove();
            }
          }
        });
        selectors.nodes.sort();
      });

      css.walkRules((rule) => {
        const selector =
          rule.raws.selector && rule.raws.selector.value === rule.selector
            ? rule.raws.selector.raw
            : rule.selector;

        // If the selector ends with a ':' it is likely a part of a custom mixin,
        // so just pass through.
        if (selector[selector.length - 1] === ':') {
          return;
        }

        if (cache.has(selector)) {
          rule.selector = cache.get(selector);

          return;
        }

        const optimizedSelector = processor.processSync(selector);

        rule.selector = optimizedSelector;
        cache.set(selector, optimizedSelector);
      });
    },
  };
}

pluginCreator.postcss = true;
module.exports = pluginCreator;


code:
'use strict';
/**
 * Can unquote attribute detection from mothereff.in
 * Copyright Mathias Bynens <https://mathiasbynens.be/>
 * https://github.com/mathiasbynens/mothereff.in
 */
const escapes = /\\([0-9A-Fa-f]{1,6})[ \t\n\f\r]?/g;
const range =
  // eslint-disable-next-line no-control-regex
  /[\u0000-\u002c\u002e\u002f\u003A-\u0040\u005B-\u005E\u0060\u007B-\u009f]/;

/**
 * @param {string} value
 * @return {boolean}
 */
module.exports = function canUnquote(value) {
  if (value === '-' || value === '') {
    return false;
  }

  value = value.replace(escapes, 'a').replace(/\\./g, 'a');

  return !(range.test(value) || /^(?:-?\d|--)/.test(value));
};

license: mit


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:
declare function _exports(value: string): boolean;
export = _exports;


code:
# CSS Modules: Extract Imports

[![Build Status](https://travis-ci.org/css-modules/postcss-modules-extract-imports.svg?branch=master)](https://travis-ci.org/css-modules/postcss-modules-extract-imports)

Transforms:

```css
:local(.continueButton) {
  composes: button from "library/button.css";
  color: green;
}
```

into:

```css
:import("library/button.css") {
  button: __tmp_487387465fczSDGHSABb;
}
:local(.continueButton) {
  composes: __tmp_487387465fczSDGHSABb;
  color: green;
}
```

## Specification

- Only a certain whitelist of properties are inspected. Currently, that whitelist is `['composes']` alone.
- An extend-import has the following format:

```
composes: className [... className] from "path/to/file.css",  className [... className], className [... className] from global;
```

## Options

- `failOnWrongOrder` `bool` generates exception for unpredictable imports order.

```css
.aa {
  composes: b from "./b.css";
  composes: c from "./c.css";
}

.bb {
  /* "b.css" should be before "c.css" in this case */
  composes: c from "./c.css";
  composes: b from "./b.css";
}
```

## Building

```
npm install
npm test
```

[![Build Status](https://travis-ci.org/css-modules/postcss-modules-extract-imports.svg?branch=master)](https://travis-ci.org/css-modules/postcss-modules-extract-imports)

- Lines: [![Coverage Status](https://coveralls.io/repos/css-modules/postcss-modules-extract-imports/badge.svg?branch=master)](https://coveralls.io/r/css-modules/postcss-modules-extract-imports?branch=master)
- Statements: [![codecov.io](http://codecov.io/github/css-modules/postcss-modules-extract-imports/coverage.svg?branch=master)](http://codecov.io/github/css-modules/postcss-modules-extract-imports?branch=master)

## License

ISC

## With thanks

- Mark Dalgleish
- Tobias Koppers
- Guy Bedford

---

Glen Maddern, 2015.


postcss-modules-extract-imports

description: A CSS Modules transform to extract local aliases for inline imports

prettier: prettier -l --ignore-path .gitignore . "!test/test-cases"

eslint: eslint --ignore-path .gitignore .

lint: yarn eslint && yarn prettier

test:only: jest

test:watch: jest --watch

pretest: yarn lint

test: yarn test:coverage

prepublishOnly: yarn test

type: git

keywords: css-modules postcss plugin

author: Glen Maddern

license: ISC


code:
const topologicalSort = require("./topologicalSort");

const matchImports = /^(.+?)\s+from\s+(?:"([^"]+)"|'([^']+)'|(global))$/;
const icssImport = /^:import\((?:"([^"]+)"|'([^']+)')\)/;

const VISITED_MARKER = 1;

/**
 * :import('G') {}
 *
 * Rule
 *   composes: ... from 'A'
 *   composes: ... from 'B'

 * Rule
 *   composes: ... from 'A'
 *   composes: ... from 'A'
 *   composes: ... from 'C'
 *
 * Results in:
 *
 * graph: {
 *   G: [],
 *   A: [],
 *   B: ['A'],
 *   C: ['A'],
 * }
 */
function addImportToGraph(importId, parentId, graph, visited) {
  const siblingsId = parentId + "_" + "siblings";
  const visitedId = parentId + "_" + importId;

  if (visited[visitedId] !== VISITED_MARKER) {
    if (!Array.isArray(visited[siblingsId])) {
      visited[siblingsId] = [];
    }

    const siblings = visited[siblingsId];

    if (Array.isArray(graph[importId])) {
      graph[importId] = graph[importId].concat(siblings);
    } else {
      graph[importId] = siblings.slice();
    }

    visited[visitedId] = VISITED_MARKER;

    siblings.push(importId);
  }
}

module.exports = (options = {}) => {
  let importIndex = 0;
  const createImportedName =
    typeof options.createImportedName !== "function"
      ? (importName /*, path*/) =>
          `i__imported_${importName.replace(/\W/g, "_")}_${importIndex++}`
      : options.createImportedName;
  const failOnWrongOrder = options.failOnWrongOrder;

  return {
    postcssPlugin: "postcss-modules-extract-imports",
    prepare() {
      const graph = {};
      const visited = {};
      const existingImports = {};
      const importDecls = {};
      const imports = {};

      return {
        Once(root, postcss) {
          // Check the existing imports order and save refs
          root.walkRules((rule) => {
            const matches = icssImport.exec(rule.selector);

            if (matches) {
              const [, /*match*/ doubleQuotePath, singleQuotePath] = matches;
              const importPath = doubleQuotePath || singleQuotePath;

              addImportToGraph(importPath, "root", graph, visited);

              existingImports[importPath] = rule;
            }
          });

          root.walkDecls(/^composes$/, (declaration) => {
            const multiple = declaration.value.split(",");
            const values = [];

            multiple.forEach((value) => {
              const matches = value.trim().match(matchImports);

              if (!matches) {
                values.push(value);

                return;
              }

              let tmpSymbols;
              let [
                ,
                /*match*/ symbols,
                doubleQuotePath,
                singleQuotePath,
                global,
              ] = matches;

              if (global) {
                // Composing globals simply means changing these classes to wrap them in global(name)
                tmpSymbols = symbols.split(/\s+/).map((s) => `global(${s})`);
              } else {
                const importPath = doubleQuotePath || singleQuotePath;

                let parent = declaration.parent;
                let parentIndexes = "";

                while (parent.type !== "root") {
                  parentIndexes =
                    parent.parent.index(parent) + "_" + parentIndexes;
                  parent = parent.parent;
                }

                const { selector } = declaration.parent;
                const parentRule = `_${parentIndexes}${selector}`;

                addImportToGraph(importPath, parentRule, graph, visited);

                importDecls[importPath] = declaration;
                imports[importPath] = imports[importPath] || {};

                tmpSymbols = symbols.split(/\s+/).map((s) => {
                  if (!imports[importPath][s]) {
                    imports[importPath][s] = createImportedName(s, importPath);
                  }

                  return imports[importPath][s];
                });
              }

              values.push(tmpSymbols.join(" "));
            });

            declaration.value = values.join(", ");
          });

          const importsOrder = topologicalSort(graph, failOnWrongOrder);

          if (importsOrder instanceof Error) {
            const importPath = importsOrder.nodes.find((importPath) =>
              // eslint-disable-next-line no-prototype-builtins
              importDecls.hasOwnProperty(importPath)
            );
            const decl = importDecls[importPath];

            throw decl.error(
              "Failed to resolve order of composed modules " +
                importsOrder.nodes
                  .map((importPath) => "`" + importPath + "`")
                  .join(", ") +
                ".",
              {
                plugin: "postcss-modules-extract-imports",
                word: "composes",
              }
            );
          }

          let lastImportRule;

          importsOrder.forEach((path) => {
            const importedSymbols = imports[path];
            let rule = existingImports[path];

            if (!rule && importedSymbols) {
              rule = postcss.rule({
                selector: `:import("${path}")`,
                raws: { after: "\n" },
              });

              if (lastImportRule) {
                root.insertAfter(lastImportRule, rule);
              } else {
                root.prepend(rule);
              }
            }

            lastImportRule = rule;

            if (!importedSymbols) {
              return;
            }

            Object.keys(importedSymbols).forEach((importedSymbol) => {
              rule.append(
                postcss.decl({
                  value: importedSymbol,
                  prop: importedSymbols[importedSymbol],
                  raws: { before: "\n  " },
                })
              );
            });
          });
        },
      };
    },
  };
};

module.exports.postcss = true;


code:
const PERMANENT_MARKER = 2;
const TEMPORARY_MARKER = 1;

function createError(node, graph) {
  const er = new Error("Nondeterministic import's order");

  const related = graph[node];
  const relatedNode = related.find(
    (relatedNode) => graph[relatedNode].indexOf(node) > -1
  );

  er.nodes = [node, relatedNode];

  return er;
}

function walkGraph(node, graph, state, result, strict) {
  if (state[node] === PERMANENT_MARKER) {
    return;
  }

  if (state[node] === TEMPORARY_MARKER) {
    if (strict) {
      return createError(node, graph);
    }

    return;
  }

  state[node] = TEMPORARY_MARKER;

  const children = graph[node];
  const length = children.length;

  for (let i = 0; i < length; ++i) {
    const error = walkGraph(children[i], graph, state, result, strict);

    if (error instanceof Error) {
      return error;
    }
  }

  state[node] = PERMANENT_MARKER;

  result.push(node);
}

function topologicalSort(graph, strict) {
  const result = [];
  const state = {};

  const nodes = Object.keys(graph);
  const length = nodes.length;

  for (let i = 0; i < length; ++i) {
    const er = walkGraph(nodes[i], graph, state, result, strict);

    if (er instanceof Error) {
      return er;
    }
  }

  return result;
}

module.exports = topologicalSort;


code:
[![Build Status][ci-img]][ci] [![codecov][codecov-img]][codecov] [![npm][npm-img]][npm]

# CSS Modules: Local by Default

Transformation examples:

<!-- prettier-ignore-start -->
```css
.foo { ... } /* => */ :local(.foo) { ... }

.foo .bar { ... } /* => */ :local(.foo) :local(.bar) { ... }

/* Shorthand global selector */

:global .foo .bar { ... } /* => */ .foo .bar { ... }

.foo :global .bar { ... } /* => */ :local(.foo) .bar { ... }

/* Targeted global selector */

:global(.foo) .bar { ... } /* => */ .foo :local(.bar) { ... }

.foo:global(.bar) { ... } /* => */ :local(.foo).bar { ... }

.foo :global(.bar) .baz { ... } /* => */ :local(.foo) .bar :local(.baz) { ... }

.foo:global(.bar) .baz { ... } /* => */ :local(.foo).bar :local(.baz) { ... }
```
<!-- prettier-ignore-end -->

## Building

```bash
$ npm install
$ npm test
```

- Build: [![Build Status][ci-img]][ci]
- Lines: [![coveralls][coveralls-img]][coveralls]
- Statements: [![codecov][codecov-img]][codecov]

## Development

```bash
$ yarn test:watch
```

## License

MIT

## With thanks

- [Tobias Koppers](https://github.com/sokra)
- [Glen Maddern](https://github.com/geelen)

---

Mark Dalgleish, 2015.

[ci-img]: https://img.shields.io/travis/css-modules/postcss-modules-local-by-default/master.svg?style=flat-square
[ci]: https://travis-ci.org/css-modules/postcss-modules-local-by-default
[npm-img]: https://img.shields.io/npm/v/postcss-modules-local-by-default.svg?style=flat-square
[npm]: https://www.npmjs.com/package/postcss-modules-local-by-default
[coveralls-img]: https://img.shields.io/coveralls/css-modules/postcss-modules-local-by-default/master.svg?style=flat-square
[coveralls]: https://coveralls.io/r/css-modules/postcss-modules-local-by-default?branch=master
[codecov-img]: https://img.shields.io/codecov/c/github/css-modules/postcss-modules-local-by-default/master.svg?style=flat-square
[codecov]: https://codecov.io/github/css-modules/postcss-modules-local-by-default?branch=master


postcss-modules-local-by-default

description: A CSS Modules transform to make local scope the default

author: Mark Dalgleish

license: MIT

keywords: css-modules postcss css postcss-plugin

prettier: prettier -l --ignore-path .gitignore .

prepublishOnly: yarn lint && yarn test


code:
"use strict";

const selectorParser = require("postcss-selector-parser");
const valueParser = require("postcss-value-parser");
const { extractICSS } = require("icss-utils");

const isSpacing = (node) => node.type === "combinator" && node.value === " ";

function normalizeNodeArray(nodes) {
  const array = [];

  nodes.forEach((x) => {
    if (Array.isArray(x)) {
      normalizeNodeArray(x).forEach((item) => {
        array.push(item);
      });
    } else if (x) {
      array.push(x);
    }
  });

  if (array.length > 0 && isSpacing(array[array.length - 1])) {
    array.pop();
  }
  return array;
}

function localizeNode(rule, mode, localAliasMap) {
  const transform = (node, context) => {
    if (context.ignoreNextSpacing && !isSpacing(node)) {
      throw new Error("Missing whitespace after " + context.ignoreNextSpacing);
    }

    if (context.enforceNoSpacing && isSpacing(node)) {
      throw new Error("Missing whitespace before " + context.enforceNoSpacing);
    }

    let newNodes;

    switch (node.type) {
      case "root": {
        let resultingGlobal;

        context.hasPureGlobals = false;

        newNodes = node.nodes.map((n) => {
          const nContext = {
            global: context.global,
            lastWasSpacing: true,
            hasLocals: false,
            explicit: false,
          };

          n = transform(n, nContext);

          if (typeof resultingGlobal === "undefined") {
            resultingGlobal = nContext.global;
          } else if (resultingGlobal !== nContext.global) {
            throw new Error(
              'Inconsistent rule global/local result in rule "' +
                node +
                '" (multiple selectors must result in the same mode for the rule)'
            );
          }

          if (!nContext.hasLocals) {
            context.hasPureGlobals = true;
          }

          return n;
        });

        context.global = resultingGlobal;

        node.nodes = normalizeNodeArray(newNodes);
        break;
      }
      case "selector": {
        newNodes = node.map((childNode) => transform(childNode, context));

        node = node.clone();
        node.nodes = normalizeNodeArray(newNodes);
        break;
      }
      case "combinator": {
        if (isSpacing(node)) {
          if (context.ignoreNextSpacing) {
            context.ignoreNextSpacing = false;
            context.lastWasSpacing = false;
            context.enforceNoSpacing = false;
            return null;
          }
          context.lastWasSpacing = true;
          return node;
        }
        break;
      }
      case "pseudo": {
        let childContext;
        const isNested = !!node.length;
        const isScoped = node.value === ":local" || node.value === ":global";
        const isImportExport =
          node.value === ":import" || node.value === ":export";

        if (isImportExport) {
          context.hasLocals = true;
          // :local(.foo)
        } else if (isNested) {
          if (isScoped) {
            if (node.nodes.length === 0) {
              throw new Error(`${node.value}() can't be empty`);
            }

            if (context.inside) {
              throw new Error(
                `A ${node.value} is not allowed inside of a ${context.inside}(...)`
              );
            }

            childContext = {
              global: node.value === ":global",
              inside: node.value,
              hasLocals: false,
              explicit: true,
            };

            newNodes = node
              .map((childNode) => transform(childNode, childContext))
              .reduce((acc, next) => acc.concat(next.nodes), []);

            if (newNodes.length) {
              const { before, after } = node.spaces;

              const first = newNodes[0];
              const last = newNodes[newNodes.length - 1];

              first.spaces = { before, after: first.spaces.after };
              last.spaces = { before: last.spaces.before, after };
            }

            node = newNodes;

            break;
          } else {
            childContext = {
              global: context.global,
              inside: context.inside,
              lastWasSpacing: true,
              hasLocals: false,
              explicit: context.explicit,
            };
            newNodes = node.map((childNode) => {
              const newContext = {
                ...childContext,
                enforceNoSpacing: false,
              };

              const result = transform(childNode, newContext);

              childContext.global = newContext.global;
              childContext.hasLocals = newContext.hasLocals;

              return result;
            });

            node = node.clone();
            node.nodes = normalizeNodeArray(newNodes);

            if (childContext.hasLocals) {
              context.hasLocals = true;
            }
          }
          break;

          //:local .foo .bar
        } else if (isScoped) {
          if (context.inside) {
            throw new Error(
              `A ${node.value} is not allowed inside of a ${context.inside}(...)`
            );
          }

          const addBackSpacing = !!node.spaces.before;

          context.ignoreNextSpacing = context.lastWasSpacing
            ? node.value
            : false;

          context.enforceNoSpacing = context.lastWasSpacing
            ? false
            : node.value;

          context.global = node.value === ":global";
          context.explicit = true;

          // because this node has spacing that is lost when we remove it
          // we make up for it by adding an extra combinator in since adding
          // spacing on the parent selector doesn't work
          return addBackSpacing
            ? selectorParser.combinator({ value: " " })
            : null;
        }
        break;
      }
      case "id":
      case "class": {
        if (!node.value) {
          throw new Error("Invalid class or id selector syntax");
        }

        if (context.global) {
          break;
        }

        const isImportedValue = localAliasMap.has(node.value);
        const isImportedWithExplicitScope = isImportedValue && context.explicit;

        if (!isImportedValue || isImportedWithExplicitScope) {
          const innerNode = node.clone();
          innerNode.spaces = { before: "", after: "" };

          node = selectorParser.pseudo({
            value: ":local",
            nodes: [innerNode],
            spaces: node.spaces,
          });

          context.hasLocals = true;
        }

        break;
      }
      case "nesting": {
        if (node.value === "&") {
          context.hasLocals = true;
        }
      }
    }

    context.lastWasSpacing = false;
    context.ignoreNextSpacing = false;
    context.enforceNoSpacing = false;

    return node;
  };

  const rootContext = {
    global: mode === "global",
    hasPureGlobals: false,
  };

  rootContext.selector = selectorParser((root) => {
    transform(root, rootContext);
  }).processSync(rule, { updateSelector: false, lossless: true });

  return rootContext;
}

function localizeDeclNode(node, context) {
  switch (node.type) {
    case "word":
      if (context.localizeNextItem) {
        if (!context.localAliasMap.has(node.value)) {
          node.value = ":local(" + node.value + ")";
          context.localizeNextItem = false;
        }
      }
      break;

    case "function":
      if (
        context.options &&
        context.options.rewriteUrl &&
        node.value.toLowerCase() === "url"
      ) {
        node.nodes.map((nestedNode) => {
          if (nestedNode.type !== "string" && nestedNode.type !== "word") {
            return;
          }

          let newUrl = context.options.rewriteUrl(
            context.global,
            nestedNode.value
          );

          switch (nestedNode.type) {
            case "string":
              if (nestedNode.quote === "'") {
                newUrl = newUrl.replace(/(\\)/g, "\\$1").replace(/'/g, "\\'");
              }

              if (nestedNode.quote === '"') {
                newUrl = newUrl.replace(/(\\)/g, "\\$1").replace(/"/g, '\\"');
              }

              break;
            case "word":
              newUrl = newUrl.replace(/("|'|\)|\\)/g, "\\$1");
              break;
          }

          nestedNode.value = newUrl;
        });
      }
      break;
  }
  return node;
}

// `none` is special value, other is global values
const specialKeywords = [
  "none",
  "inherit",
  "initial",
  "revert",
  "revert-layer",
  "unset",
];

function localizeDeclarationValues(localize, declaration, context) {
  const valueNodes = valueParser(declaration.value);

  valueNodes.walk((node, index, nodes) => {
    if (
      node.type === "function" &&
      (node.value.toLowerCase() === "var" || node.value.toLowerCase() === "env")
    ) {
      return false;
    }

    if (
      node.type === "word" &&
      specialKeywords.includes(node.value.toLowerCase())
    ) {
      return;
    }

    const subContext = {
      options: context.options,
      global: context.global,
      localizeNextItem: localize && !context.global,
      localAliasMap: context.localAliasMap,
    };
    nodes[index] = localizeDeclNode(node, subContext);
  });

  declaration.value = valueNodes.toString();
}

function localizeDeclaration(declaration, context) {
  const isAnimation = /animation$/i.test(declaration.prop);

  if (isAnimation) {
    // letter
    // An uppercase letter or a lowercase letter.
    //
    // ident-start code point
    // A letter, a non-ASCII code point, or U+005F LOW LINE (_).
    //
    // ident code point
    // An ident-start code point, a digit, or U+002D HYPHEN-MINUS (-).

    // We don't validate `hex digits`, because we don't need it, it is work of linters.
    const validIdent =
      /^-?([a-z\u0080-\uFFFF_]|(\\[^\r\n\f])|-(?![0-9]))((\\[^\r\n\f])|[a-z\u0080-\uFFFF_0-9-])*$/i;

    /*
    The spec defines some keywords that you can use to describe properties such as the timing
    function. These are still valid animation names, so as long as there is a property that accepts
    a keyword, it is given priority. Only when all the properties that can take a keyword are
    exhausted can the animation name be set to the keyword. I.e.

    animation: infinite infinite;

    The animation will repeat an infinite number of times from the first argument, and will have an
    animation name of infinite from the second.
    */
    const animationKeywords = {
      // animation-direction
      $normal: 1,
      $reverse: 1,
      $alternate: 1,
      "$alternate-reverse": 1,
      // animation-fill-mode
      $forwards: 1,
      $backwards: 1,
      $both: 1,
      // animation-iteration-count
      $infinite: 1,
      // animation-play-state
      $paused: 1,
      $running: 1,
      // animation-timing-function
      $ease: 1,
      "$ease-in": 1,
      "$ease-out": 1,
      "$ease-in-out": 1,
      $linear: 1,
      "$step-end": 1,
      "$step-start": 1,
      // Special
      $none: Infinity, // No matter how many times you write none, it will never be an animation name
      // Global values
      $initial: Infinity,
      $inherit: Infinity,
      $unset: Infinity,
      $revert: Infinity,
      "$revert-layer": Infinity,
    };
    let parsedAnimationKeywords = {};
    const valueNodes = valueParser(declaration.value).walk((node) => {
      // If div-token appeared (represents as comma ','), a possibility of an animation-keywords should be reflesh.
      if (node.type === "div") {
        parsedAnimationKeywords = {};

        return;
      }
      // Do not handle nested functions
      else if (node.type === "function") {
        return false;
      }
      // Ignore all except word
      else if (node.type !== "word") {
        return;
      }

      const value = node.type === "word" ? node.value.toLowerCase() : null;

      let shouldParseAnimationName = false;

      if (value && validIdent.test(value)) {
        if ("$" + value in animationKeywords) {
          parsedAnimationKeywords["$" + value] =
            "$" + value in parsedAnimationKeywords
              ? parsedAnimationKeywords["$" + value] + 1
              : 0;

          shouldParseAnimationName =
            parsedAnimationKeywords["$" + value] >=
            animationKeywords["$" + value];
        } else {
          shouldParseAnimationName = true;
        }
      }

      const subContext = {
        options: context.options,
        global: context.global,
        localizeNextItem: shouldParseAnimationName && !context.global,
        localAliasMap: context.localAliasMap,
      };

      return localizeDeclNode(node, subContext);
    });

    declaration.value = valueNodes.toString();

    return;
  }

  const isAnimationName = /animation(-name)?$/i.test(declaration.prop);

  if (isAnimationName) {
    return localizeDeclarationValues(true, declaration, context);
  }

  const hasUrl = /url\(/i.test(declaration.value);

  if (hasUrl) {
    return localizeDeclarationValues(false, declaration, context);
  }
}

module.exports = (options = {}) => {
  if (
    options &&
    options.mode &&
    options.mode !== "global" &&
    options.mode !== "local" &&
    options.mode !== "pure"
  ) {
    throw new Error(
      'options.mode must be either "global", "local" or "pure" (default "local")'
    );
  }

  const pureMode = options && options.mode === "pure";
  const globalMode = options && options.mode === "global";

  return {
    postcssPlugin: "postcss-modules-local-by-default",
    prepare() {
      const localAliasMap = new Map();

      return {
        Once(root) {
          const { icssImports } = extractICSS(root, false);

          Object.keys(icssImports).forEach((key) => {
            Object.keys(icssImports[key]).forEach((prop) => {
              localAliasMap.set(prop, icssImports[key][prop]);
            });
          });

          root.walkAtRules((atRule) => {
            if (/keyframes$/i.test(atRule.name)) {
              const globalMatch = /^\s*:global\s*\((.+)\)\s*$/.exec(
                atRule.params
              );
              const localMatch = /^\s*:local\s*\((.+)\)\s*$/.exec(
                atRule.params
              );

              let globalKeyframes = globalMode;

              if (globalMatch) {
                if (pureMode) {
                  throw atRule.error(
                    "@keyframes :global(...) is not allowed in pure mode"
                  );
                }
                atRule.params = globalMatch[1];
                globalKeyframes = true;
              } else if (localMatch) {
                atRule.params = localMatch[0];
                globalKeyframes = false;
              } else if (
                atRule.params &&
                !globalMode &&
                !localAliasMap.has(atRule.params)
              ) {
                atRule.params = ":local(" + atRule.params + ")";
              }

              atRule.walkDecls((declaration) => {
                localizeDeclaration(declaration, {
                  localAliasMap,
                  options: options,
                  global: globalKeyframes,
                });
              });
            } else if (/scope$/i.test(atRule.name)) {
              if (atRule.params) {
                atRule.params = atRule.params
                  .split("to")
                  .map((item) => {
                    const selector = item.trim().slice(1, -1).trim();
                    const context = localizeNode(
                      selector,
                      options.mode,
                      localAliasMap
                    );

                    context.options = options;
                    context.localAliasMap = localAliasMap;

                    if (pureMode && context.hasPureGlobals) {
                      throw atRule.error(
                        'Selector in at-rule"' +
                          selector +
                          '" is not pure ' +
                          "(pure selectors must contain at least one local class or id)"
                      );
                    }

                    return `(${context.selector})`;
                  })
                  .join(" to ");
              }

              atRule.nodes.forEach((declaration) => {
                if (declaration.type === "decl") {
                  localizeDeclaration(declaration, {
                    localAliasMap,
                    options: options,
                    global: globalMode,
                  });
                }
              });
            } else if (atRule.nodes) {
              atRule.nodes.forEach((declaration) => {
                if (declaration.type === "decl") {
                  localizeDeclaration(declaration, {
                    localAliasMap,
                    options: options,
                    global: globalMode,
                  });
                }
              });
            }
          });

          root.walkRules((rule) => {
            if (
              rule.parent &&
              rule.parent.type === "atrule" &&
              /keyframes$/i.test(rule.parent.name)
            ) {
              // ignore keyframe rules
              return;
            }

            const context = localizeNode(rule, options.mode, localAliasMap);

            context.options = options;
            context.localAliasMap = localAliasMap;

            if (pureMode && context.hasPureGlobals) {
              throw rule.error(
                'Selector "' +
                  rule.selector +
                  '" is not pure ' +
                  "(pure selectors must contain at least one local class or id)"
              );
            }

            rule.selector = context.selector;

            // Less-syntax mixins parse as rules with no nodes
            if (rule.nodes) {
              rule.nodes.forEach((declaration) =>
                localizeDeclaration(declaration, context)
              );
            }
          });
        },
      };
    },
  };
};
module.exports.postcss = true;


code:
# CSS Modules: Scope Locals & Extend

[![Build Status](https://travis-ci.org/css-modules/postcss-modules-scope.svg?branch=master)](https://travis-ci.org/css-modules/postcss-modules-scope)

Transforms:

```css
:local(.continueButton) {
  color: green;
}
```

into:

```css
:export {
  continueButton: __buttons_continueButton_djd347adcxz9;
}
.__buttons_continueButton_djd347adcxz9 {
  color: green;
}
```

so it doesn't pollute CSS global scope and can be simply used in JS like so:

```js
import styles from "./buttons.css";
elem.innerHTML = `<button class="${styles.continueButton}">Continue</button>`;
```

## Composition

Since we're exporting class names, there's no reason to export only one. This can give us some really useful reuse of styles:

```css
.globalButtonStyle {
  background: white;
  border: 1px solid;
  border-radius: 0.25rem;
}
.globalButtonStyle:hover {
  box-shadow: 0 0 4px -2px;
}
:local(.continueButton) {
  compose-with: globalButtonStyle;
  color: green;
}
```

becomes:

```
.globalButtonStyle {
  background: white;
  border: 1px solid;
  border-radius: 0.25rem;
}
.globalButtonStyle:hover {
  box-shadow: 0 0 4px -2px;
}
:local(.continueButton) {
  compose-with: globalButtonStyle;
  color: green;
}
```

**Note:** you can also use `composes` as a shorthand for `compose-with`

## Local-by-default & reuse across files

You're looking for [CSS Modules](https://github.com/css-modules/css-modules). It uses this plugin as well as a few others, and it's amazing.

## Building

```
npm install
npm test
```

- Status: [![Build Status](https://travis-ci.org/css-modules/postcss-modules-scope.svg?branch=master)](https://travis-ci.org/css-modules/postcss-modules-scope)
- Lines: [![Coverage Status](https://coveralls.io/repos/css-modules/postcss-modules-scope/badge.svg?branch=master)](https://coveralls.io/r/css-modules/postcss-modules-scope?branch=master)
- Statements: [![codecov.io](http://codecov.io/github/css-modules/postcss-modules-scope/coverage.svg?branch=master)](http://codecov.io/github/css-modules/postcss-modules-scope?branch=master)

## Development

- `npm test:watch` will watch `src` and `test` for changes and run the tests

## License

ISC

## With thanks

- Mark Dalgleish
- Tobias Koppers
- Guy Bedford

---

Glen Maddern, 2015.


postcss-modules-scope

description: A CSS Modules transform to extract export statements from local-scope classes


code:
"use strict";

const selectorParser = require("postcss-selector-parser");

const hasOwnProperty = Object.prototype.hasOwnProperty;

function isNestedRule(rule) {
  if (!rule.parent || rule.parent.type === "root") {
    return false;
  }

  if (rule.parent.type === "rule") {
    return true;
  }

  return isNestedRule(rule.parent);
}

function getSingleLocalNamesForComposes(root, rule) {
  if (isNestedRule(rule)) {
    throw new Error(`composition is not allowed in nested rule \n\n${rule}`);
  }

  return root.nodes.map((node) => {
    if (node.type !== "selector" || node.nodes.length !== 1) {
      throw new Error(
        `composition is only allowed when selector is single :local class name not in "${root}"`
      );
    }

    node = node.nodes[0];

    if (
      node.type !== "pseudo" ||
      node.value !== ":local" ||
      node.nodes.length !== 1
    ) {
      throw new Error(
        'composition is only allowed when selector is single :local class name not in "' +
          root +
          '", "' +
          node +
          '" is weird'
      );
    }

    node = node.first;

    if (node.type !== "selector" || node.length !== 1) {
      throw new Error(
        'composition is only allowed when selector is single :local class name not in "' +
          root +
          '", "' +
          node +
          '" is weird'
      );
    }

    node = node.first;

    if (node.type !== "class") {
      // 'id' is not possible, because you can't compose ids
      throw new Error(
        'composition is only allowed when selector is single :local class name not in "' +
          root +
          '", "' +
          node +
          '" is weird'
      );
    }

    return node.value;
  });
}

const whitespace = "[\\x20\\t\\r\\n\\f]";
const unescapeRegExp = new RegExp(
  "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)",
  "ig"
);

function unescape(str) {
  return str.replace(unescapeRegExp, (_, escaped, escapedWhitespace) => {
    const high = "0x" + escaped - 0x10000;

    // NaN means non-codepoint
    // Workaround erroneous numeric interpretation of +"0x"
    return high !== high || escapedWhitespace
      ? escaped
      : high < 0
      ? // BMP codepoint
        String.fromCharCode(high + 0x10000)
      : // Supplemental Plane codepoint (surrogate pair)
        String.fromCharCode((high >> 10) | 0xd800, (high & 0x3ff) | 0xdc00);
  });
}

const plugin = (options = {}) => {
  const generateScopedName =
    (options && options.generateScopedName) || plugin.generateScopedName;
  const generateExportEntry =
    (options && options.generateExportEntry) || plugin.generateExportEntry;
  const exportGlobals = options && options.exportGlobals;

  return {
    postcssPlugin: "postcss-modules-scope",
    Once(root, { rule }) {
      const exports = Object.create(null);

      function exportScopedName(name, rawName, node) {
        const scopedName = generateScopedName(
          rawName ? rawName : name,
          root.source.input.from,
          root.source.input.css,
          node
        );
        const exportEntry = generateExportEntry(
          rawName ? rawName : name,
          scopedName,
          root.source.input.from,
          root.source.input.css,
          node
        );
        const { key, value } = exportEntry;

        exports[key] = exports[key] || [];

        if (exports[key].indexOf(value) < 0) {
          exports[key].push(value);
        }

        return scopedName;
      }

      function localizeNode(node) {
        switch (node.type) {
          case "selector":
            node.nodes = node.map((item) => localizeNode(item));
            return node;
          case "class":
            return selectorParser.className({
              value: exportScopedName(
                node.value,
                node.raws && node.raws.value ? node.raws.value : null,
                node
              ),
            });
          case "id": {
            return selectorParser.id({
              value: exportScopedName(
                node.value,
                node.raws && node.raws.value ? node.raws.value : null,
                node
              ),
            });
          }
          case "attribute": {
            if (node.attribute === "class" && node.operator === "=") {
              return selectorParser.attribute({
                attribute: node.attribute,
                operator: node.operator,
                quoteMark: "'",
                value: exportScopedName(node.value, null, null),
              });
            }
          }
        }

        throw new Error(
          `${node.type} ("${node}") is not allowed in a :local block`
        );
      }

      function traverseNode(node) {
        switch (node.type) {
          case "pseudo":
            if (node.value === ":local") {
              if (node.nodes.length !== 1) {
                throw new Error('Unexpected comma (",") in :local block');
              }

              const selector = localizeNode(node.first);
              // move the spaces that were around the pseudo selector to the first
              // non-container node
              selector.first.spaces = node.spaces;

              const nextNode = node.next();

              if (
                nextNode &&
                nextNode.type === "combinator" &&
                nextNode.value === " " &&
                /\\[A-F0-9]{1,6}$/.test(selector.last.value)
              ) {
                selector.last.spaces.after = " ";
              }

              node.replaceWith(selector);

              return;
            }
          /* falls through */
          case "root":
          case "selector": {
            node.each((item) => traverseNode(item));
            break;
          }
          case "id":
          case "class":
            if (exportGlobals) {
              exports[node.value] = [node.value];
            }
            break;
        }
        return node;
      }

      // Find any :import and remember imported names
      const importedNames = {};

      root.walkRules(/^:import\(.+\)$/, (rule) => {
        rule.walkDecls((decl) => {
          importedNames[decl.prop] = true;
        });
      });

      // Find any :local selectors
      root.walkRules((rule) => {
        let parsedSelector = selectorParser().astSync(rule);

        rule.selector = traverseNode(parsedSelector.clone()).toString();

        rule.walkDecls(/^(composes|compose-with)$/i, (decl) => {
          const localNames = getSingleLocalNamesForComposes(
            parsedSelector,
            decl.parent
          );
          const multiple = decl.value.split(",");

          multiple.forEach((value) => {
            const classes = value.trim().split(/\s+/);

            classes.forEach((className) => {
              const global = /^global\(([^)]+)\)$/.exec(className);

              if (global) {
                localNames.forEach((exportedName) => {
                  exports[exportedName].push(global[1]);
                });
              } else if (hasOwnProperty.call(importedNames, className)) {
                localNames.forEach((exportedName) => {
                  exports[exportedName].push(className);
                });
              } else if (hasOwnProperty.call(exports, className)) {
                localNames.forEach((exportedName) => {
                  exports[className].forEach((item) => {
                    exports[exportedName].push(item);
                  });
                });
              } else {
                throw decl.error(
                  `referenced class name "${className}" in ${decl.prop} not found`
                );
              }
            });
          });

          decl.remove();
        });

        // Find any :local values
        rule.walkDecls((decl) => {
          if (!/:local\s*\((.+?)\)/.test(decl.value)) {
            return;
          }

          let tokens = decl.value.split(/(,|'[^']*'|"[^"]*")/);

          tokens = tokens.map((token, idx) => {
            if (idx === 0 || tokens[idx - 1] === ",") {
              let result = token;

              const localMatch = /:local\s*\((.+?)\)/.exec(token);

              if (localMatch) {
                const input = localMatch.input;
                const matchPattern = localMatch[0];
                const matchVal = localMatch[1];
                const newVal = exportScopedName(matchVal);

                result = input.replace(matchPattern, newVal);
              } else {
                return token;
              }

              return result;
            } else {
              return token;
            }
          });

          decl.value = tokens.join("");
        });
      });

      // Find any :local keyframes
      root.walkAtRules(/keyframes$/i, (atRule) => {
        const localMatch = /^\s*:local\s*\((.+?)\)\s*$/.exec(atRule.params);

        if (!localMatch) {
          return;
        }

        atRule.params = exportScopedName(localMatch[1]);
      });

      root.walkAtRules(/scope$/i, (atRule) => {
        if (atRule.params) {
          atRule.params = atRule.params
            .split("to")
            .map((item) => {
              const selector = item.trim().slice(1, -1).trim();

              const localMatch = /^\s*:local\s*\((.+?)\)\s*$/.exec(selector);

              if (!localMatch) {
                return `(${selector})`;
              }

              let parsedSelector = selectorParser().astSync(selector);

              return `(${traverseNode(parsedSelector).toString()})`;
            })
            .join(" to ");
        }
      });

      // If we found any :locals, insert an :export rule
      const exportedNames = Object.keys(exports);

      if (exportedNames.length > 0) {
        const exportRule = rule({ selector: ":export" });

        exportedNames.forEach((exportedName) =>
          exportRule.append({
            prop: exportedName,
            value: exports[exportedName].join(" "),
            raws: { before: "\n  " },
          })
        );

        root.append(exportRule);
      }
    },
  };
};

plugin.postcss = true;

plugin.generateScopedName = function (name, path) {
  const sanitisedPath = path
    .replace(/\.[^./\\]+$/, "")
    .replace(/[\W_]+/g, "_")
    .replace(/^_|_$/g, "");

  return `_${sanitisedPath}__${name}`.trim();
};

plugin.generateExportEntry = function (name, scopedName) {
  return {
    key: unescape(name),
    value: unescape(scopedName),
  };
};

module.exports = plugin;


code:
# Change Log

All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).

## [4.0.0](https://github.com/postcss-modules-local-by-default/compare/v4.0.0-rc.5...v4.0.0) - 2020-13-08

### Fixes

- compatibility with other plugins

## [4.0.0-rc.5](https://github.com/postcss-modules-local-by-default/compare/v4.0.0-rc.4...v4.0.0-rc.5) - 2020-11-08

### Fixes

- compatibility with other plugins

## [4.0.0-rc.4](https://github.com/postcss-modules-local-by-default/compare/v4.0.0-rc.3...v4.0.0-rc.4) - 2020-10-08

### Fixes

- perf
- compatibility with empty custom properties
- works with `options.createImportedName`

## [4.0.0-rc.3](https://github.com/postcss-modules-local-by-default/compare/v4.0.0-rc.2...v4.0.0-rc.3) - 2020-10-08

### BREAKING CHANGE

- minimum supported `postcss` version is `^8.1.0`

### Fixes

- minimum supported `Node.js` version is `^10 || ^12 || >= 14`
- compatibility with PostCSS 8

## [4.0.0-rc.2](https://github.com/postcss-modules-local-by-default/compare/v4.0.0-rc.1...v4.0.0-rc.2) - 2020-09-22

### Fixes

- avoid using `postcss` directly to create decls and rules

## [4.0.0-rc.1](https://github.com/postcss-modules-local-by-default/compare/v4.0.0-rc.0...v4.0.0-rc.1) - 2020-09-22

### BREAKING CHANGE

- update `icss-utils` for PostCSS 8 compatibility

## [4.0.0-rc.0](https://github.com/postcss-modules-local-by-default/compare/v3.0.0...v4.0.0-rc.1) - 2020-09-18

### BREAKING CHANGE

- minimum supported `Node.js` version is `>= 10.13.0 || >= 12.13.0 || >= 14`
- minimum supported `postcss` version is `^8.0.3`
- `postcss` was moved to `peerDependencies`, you need to install `postcss` in your project before use the plugin


code:
# CSS Modules: Values

Pass arbitrary values between your module files

### Usage

```css
/* colors.css */
@value primary: #BF4040;
@value secondary: #1F4F7F;

.text-primary {
  color: primary;
}

.text-secondary {
  color: secondary;
}
```

```css
/* breakpoints.css */
@value small: (max-width: 599px);
@value medium: (min-width: 600px) and (max-width: 959px);
@value large: (min-width: 960px);
```

```css
/* my-component.css */
/* alias paths for other values or composition */
@value colors: "./colors.css";
/* import multiple from a single file */
@value primary, secondary from colors;
/* make local aliases to imported values */
@value small as bp-small, large as bp-large from "./breakpoints.css";
/* value as selector name */
@value selectorValue: secondary-color;

.selectorValue {
  color: secondary;
}

.header {
  composes: text-primary from colors;
  box-shadow: 0 0 10px secondary;
}

@media bp-small {
  .header {
    box-shadow: 0 0 4px secondary;
  }
}
@media bp-large {
  .header {
    box-shadow: 0 0 20px secondary;
  }
}
```

**If you are using Sass** along with this PostCSS plugin, do not use the colon `:` in your `@value` definitions. It will cause Sass to crash.

Note also you can _import_ multiple values at once but can only _define_ one value per line.

```css
@value a: b, c: d; /* defines a as "b, c: d" */
```

## License

ISC

## With thanks

- Mark Dalgleish
- Tobias Koppers
- Josh Johnston

---

Glen Maddern, 2015.


postcss-modules-values

description: PostCSS plugin for CSS Modules to pass arbitrary values between your module files

keywords: css modules postcss


code:
"use strict";

const ICSSUtils = require("icss-utils");

const matchImports = /^(.+?|\([\s\S]+?\))\s+from\s+("[^"]*"|'[^']*'|[\w-]+)$/;
const matchValueDefinition = /(?:\s+|^)([\w-]+):?(.*?)$/;
const matchImport = /^([\w-]+)(?:\s+as\s+([\w-]+))?/;

module.exports = (options) => {
  let importIndex = 0;
  const createImportedName =
    (options && options.createImportedName) ||
    ((importName /*, path*/) =>
      `i__const_${importName.replace(/\W/g, "_")}_${importIndex++}`);

  return {
    postcssPlugin: "postcss-modules-values",
    prepare(result) {
      const importAliases = [];
      const definitions = {};

      return {
        Once(root, postcss) {
          root.walkAtRules(/value/i, (atRule) => {
            const matches = atRule.params.match(matchImports);

            if (matches) {
              let [, /*match*/ aliases, path] = matches;

              // We can use constants for path names
              if (definitions[path]) {
                path = definitions[path];
              }

              const imports = aliases
                .replace(/^\(\s*([\s\S]+)\s*\)$/, "$1")
                .split(/\s*,\s*/)
                .map((alias) => {
                  const tokens = matchImport.exec(alias);

                  if (tokens) {
                    const [, /*match*/ theirName, myName = theirName] = tokens;
                    const importedName = createImportedName(myName);
                    definitions[myName] = importedName;
                    return { theirName, importedName };
                  } else {
                    throw new Error(`@import statement "${alias}" is invalid!`);
                  }
                });

              importAliases.push({ path, imports });

              atRule.remove();

              return;
            }

            if (atRule.params.indexOf("@value") !== -1) {
              result.warn("Invalid value definition: " + atRule.params);
            }

            let [, key, value] = `${atRule.params}${atRule.raws.between}`.match(
              matchValueDefinition
            );

            const normalizedValue = value.replace(/\/\*((?!\*\/).*?)\*\//g, "");

            if (normalizedValue.length === 0) {
              result.warn("Invalid value definition: " + atRule.params);
              atRule.remove();

              return;
            }

            let isOnlySpace = /^\s+$/.test(normalizedValue);

            if (!isOnlySpace) {
              value = value.trim();
            }

            // Add to the definitions, knowing that values can refer to each other
            definitions[key] = ICSSUtils.replaceValueSymbols(
              value,
              definitions
            );

            atRule.remove();
          });

          /* If we have no definitions, don't continue */
          if (!Object.keys(definitions).length) {
            return;
          }

          /* Perform replacements */
          ICSSUtils.replaceSymbols(root, definitions);

          /* We want to export anything defined by now, but don't add it to the CSS yet or it well get picked up by the replacement stuff */
          const exportDeclarations = Object.keys(definitions).map((key) =>
            postcss.decl({
              value: definitions[key],
              prop: key,
              raws: { before: "\n  " },
            })
          );

          /* Add export rules if any */
          if (exportDeclarations.length > 0) {
            const exportRule = postcss.rule({
              selector: ":export",
              raws: { after: "\n" },
            });

            exportRule.append(exportDeclarations);

            root.prepend(exportRule);
          }

          /* Add import rules */
          importAliases.reverse().forEach(({ path, imports }) => {
            const importRule = postcss.rule({
              selector: `:import(${path})`,
              raws: { after: "\n" },
            });

            imports.forEach(({ theirName, importedName }) => {
              importRule.append({
                value: theirName,
                prop: importedName,
                raws: { before: "\n  " },
              });
            });

            root.prepend(importRule);
          });
        },
      };
    },
  };
};

module.exports.postcss = true;


code:
# postcss-normalize-charset

Add necessary or remove extra charset with PostCSS

```css
a{
  content: "©";
}
```

```css
@charset "utf-8";
a{
  content: "©";
}
```

## API

### normalizeCharset([options])

#### options

##### add

Type: `boolean`
Default: `true`

Pass `false` to stop the module from adding a `@charset` declaration if it was
missing from the file (and the file contained non-ascii characters).

## Usage

See the [PostCSS documentation](https://github.com/postcss/postcss#usage) for
examples for your environment.

## Contributors

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

## License

MIT © [Bogdan Chadkin](mailto:trysound@yandex.ru)


postcss-normalize-charset

keywords: postcss css postcss-plugin charset

author: Bogdan Chadkin <trysound@yandex.ru>

files: src LICENSE types

repository: cssnano/cssnano

readme:
# postcss-normalize-charset

Add necessary or remove extra charset with PostCSS

```css
a{
  content: "©";
}
```

```css
@charset "utf-8";
a{
  content: "©";
}
```

## API

### normalizeCharset([options])

#### options

##### add

Type: `boolean`
Default: `true`

Pass `false` to stop the module from adding a `@charset` declaration if it was
missing from the file (and the file contained non-ascii characters).

## Usage

See the [PostCSS documentation](https://github.com/postcss/postcss#usage) for
examples for your environment.

## Contributors

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

## License

MIT © [Bogdan Chadkin](mailto:trysound@yandex.ru)


code:
'use strict';
const charset = 'charset';
// eslint-disable-next-line no-control-regex
const nonAscii = /[^\x00-\x7F]/;

/**
 * @typedef {{add?: boolean}} Options
 */
/**
 * @type {import('postcss').PluginCreator<Options>}
 * @param {Options} opts
 * @return {import('postcss').Plugin}
 */
function pluginCreator(opts = {}) {
  return {
    postcssPlugin: 'postcss-normalize-' + charset,

    OnceExit(css, { AtRule }) {
      /** @type {import('postcss').AtRule | undefined} */
      let charsetRule;
      /** @type {import('postcss').Node | undefined} */
      let nonAsciiNode;

      css.walk((node) => {
        if (node.type === 'atrule' && node.name === charset) {
          if (!charsetRule) {
            charsetRule = node;
          }
          node.remove();
        } else if (
          !nonAsciiNode &&
          node.parent === css &&
          nonAscii.test(node.toString())
        ) {
          nonAsciiNode = node;
        }
      });

      if (nonAsciiNode) {
        if (!charsetRule && opts.add !== false) {
          charsetRule = new AtRule({
            name: charset,
            params: '"utf-8"',
          });
        }
        if (charsetRule) {
          charsetRule.source = nonAsciiNode.source;
          css.prepend(charsetRule);
        }
      }
    },
  };
}

pluginCreator.postcss = true;
module.exports = pluginCreator;


code:
export = pluginCreator;
/**
 * @typedef {{add?: boolean}} Options
 */
/**
 * @type {import('postcss').PluginCreator<Options>}
 * @param {Options} opts
 * @return {import('postcss').Plugin}
 */
declare function pluginCreator(opts?: Options): import('postcss').Plugin;
declare namespace pluginCreator {
    export { postcss, Options };
}
type Options = {
    add?: boolean;
};
declare var postcss: true;


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:
# [postcss][postcss]-normalize-display-values

> Normalize display property values with PostCSS.

## Install

With [npm](https://npmjs.org/package/postcss-normalize-display-values) do:

```
npm install postcss-normalize-display-values --save
```

## Example

### Input

```css
div {
    display: inline flow-root
}
```

### Output

```css
div {
    display: inline-block
}
```

## Usage

See the [PostCSS documentation](https://github.com/postcss/postcss#usage) for
examples for your environment.

## Contributors

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

## License

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

[postcss]: https://github.com/postcss/postcss


postcss-normalize-display-values

description: Normalize multiple value display syntaxes into single values.

files: LICENSE-MIT src types

readme:
# [postcss][postcss]-normalize-display-values

> Normalize display property values with PostCSS.

## Install

With [npm](https://npmjs.org/package/postcss-normalize-display-values) do:

```
npm install postcss-normalize-display-values --save
```

## Example

### Input

```css
div {
    display: inline flow-root
}
```

### Output

```css
div {
    display: inline-block
}
```

## Usage

See the [PostCSS documentation](https://github.com/postcss/postcss#usage) for
examples for your environment.

## Contributors

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

## License

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

[postcss]: https://github.com/postcss/postcss


code:
'use strict';
const valueParser = require('postcss-value-parser');
const mappings = require('./lib/map.js');

/**
 * @param {string} value
 * @return {string}
 */
function transform(value) {
  const { nodes } = valueParser(value);

  if (nodes.length === 1) {
    return value;
  }

  const values = nodes
    .filter((list, index) => index % 2 === 0)
    .filter((node) => node.type === 'word')
    .map((n) => n.value.toLowerCase());

  if (values.length === 0) {
    return value;
  }

  const match = mappings.get(values.toString());

  if (!match) {
    return value;
  }

  return match;
}

/**
 * @type {import('postcss').PluginCreator<void>}
 * @return {import('postcss').Plugin}
 */
function pluginCreator() {
  return {
    postcssPlugin: 'postcss-normalize-display-values',

    prepare() {
      const cache = new Map();
      return {
        OnceExit(css) {
          css.walkDecls(/^display$/i, (decl) => {
            const value = decl.value;

            if (!value) {
              return;
            }

            if (cache.has(value)) {
              decl.value = cache.get(value);

              return;
            }

            const result = transform(value);

            decl.value = result;
            cache.set(value, result);
          });
        },
      };
    },
  };
}

pluginCreator.postcss = true;
module.exports = pluginCreator;


code:
'use strict';
const block = 'block';
const flex = 'flex';
const flow = 'flow';
const flowRoot = 'flow-root';
const grid = 'grid';
const inline = 'inline';
const inlineBlock = 'inline-block';
const inlineFlex = 'inline-flex';
const inlineGrid = 'inline-grid';
const inlineTable = 'inline-table';
const listItem = 'list-item';
const ruby = 'ruby';
const rubyBase = 'ruby-base';
const rubyText = 'ruby-text';
const runIn = 'run-in';
const table = 'table';
const tableCell = 'table-cell';
const tableCaption = 'table-caption';

/**
 * Specification: https://drafts.csswg.org/css-display/#the-display-properties
 */

module.exports = new Map([
  [[block, flow].toString(), block],
  [[block, flowRoot].toString(), flowRoot],
  [[inline, flow].toString(), inline],
  [[inline, flowRoot].toString(), inlineBlock],
  [[runIn, flow].toString(), runIn],
  [[listItem, block, flow].toString(), listItem],
  [[inline, flow, listItem].toString(), inline + ' ' + listItem],
  [[block, flex].toString(), flex],
  [[inline, flex].toString(), inlineFlex],
  [[block, grid].toString(), grid],
  [[inline, grid].toString(), inlineGrid],
  [[inline, ruby].toString(), ruby],
  // `block ruby` is same
  [[block, table].toString(), table],
  [[inline, table].toString(), inlineTable],
  [[tableCell, flow].toString(), tableCell],
  [[tableCaption, flow].toString(), tableCaption],
  [[rubyBase, flow].toString(), rubyBase],
  [[rubyText, flow].toString(), rubyText],
]);


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:
declare const _exports: {
    clear(): void;
    delete(key: string): boolean;
    forEach(callbackfn: (value: string, key: string, map: Map<string, string>) => void, thisArg?: any): void;
    get(key: string): string | undefined;
    has(key: string): boolean;
    set(key: string, value: string): Map<string, string>;
    readonly size: number;
    entries(): IterableIterator<[string, string]>;
    keys(): IterableIterator<string>;
    values(): IterableIterator<string>;
    [Symbol.iterator](): IterableIterator<[string, string]>;
    readonly [Symbol.toStringTag]: string;
};
export = _exports;


code:
# [postcss][postcss]-normalize-positions

> Normalize positions with PostCSS.

## Install

With [npm](https://npmjs.org/package/postcss-normalize-positions) do:

```
npm install postcss-normalize-positions --save
```

## Example

### Input

```css
div {
    background-position: bottom left;
}
```

### Output

```css
div {
    background-position:0 100%;
}
```

## Usage

See the [PostCSS documentation](https://github.com/postcss/postcss#usage) for
examples for your environment.

## Contributors

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

## License

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

[postcss]: https://github.com/postcss/postcss


postcss-normalize-positions

description: Normalize keyword values for position into length values.

files: src LICENSE-MIT types

keywords: css postcss postcss-plugin


code:
'use strict';
const valueParser = require('postcss-value-parser');

const directionKeywords = new Set(['top', 'right', 'bottom', 'left', 'center']);

const center = '50%';
const horizontal = new Map([
  ['right', '100%'],
  ['left', '0'],
]);
const verticalValue = new Map([
  ['bottom', '100%'],
  ['top', '0'],
]);
const mathFunctions = new Set(['calc', 'min', 'max', 'clamp']);
const variableFunctions = new Set(['var', 'env', 'constant']);
/**
 * @param {valueParser.Node} node
 * @return {boolean}
 */
function isCommaNode(node) {
  return node.type === 'div' && node.value === ',';
}

/**
 * @param {valueParser.Node} node
 * @return {boolean}
 */
function isVariableFunctionNode(node) {
  if (node.type !== 'function') {
    return false;
  }

  return variableFunctions.has(node.value.toLowerCase());
}

/**
 * @param {valueParser.Node} node
 * @return {boolean}
 */
function isMathFunctionNode(node) {
  if (node.type !== 'function') {
    return false;
  }
  return mathFunctions.has(node.value.toLowerCase());
}

/**
 * @param {valueParser.Node} node
 * @return {boolean}
 */
function isNumberNode(node) {
  if (node.type !== 'word') {
    return false;
  }

  const value = parseFloat(node.value);

  return !isNaN(value);
}

/**
 * @param {valueParser.Node} node
 * @return {boolean}
 */
function isDimensionNode(node) {
  if (node.type !== 'word') {
    return false;
  }

  const parsed = valueParser.unit(node.value);

  if (!parsed) {
    return false;
  }

  return parsed.unit !== '';
}

/**
 * @param {string} value
 * @return {string}
 */
function transform(value) {
  const parsed = valueParser(value);
  /** @type {({start: number, end: number} | {start: null, end: null})[]} */
  const ranges = [];
  let rangeIndex = 0;
  let shouldContinue = true;

  parsed.nodes.forEach((node, index) => {
    // After comma (`,`) follows next background
    if (isCommaNode(node)) {
      rangeIndex += 1;
      shouldContinue = true;

      return;
    }

    if (!shouldContinue) {
      return;
    }

    // After separator (`/`) follows `background-size` values
    // Avoid them
    if (node.type === 'div' && node.value === '/') {
      shouldContinue = false;

      return;
    }

    if (!ranges[rangeIndex]) {
      ranges[rangeIndex] = {
        start: null,
        end: null,
      };
    }

    // Do not try to be processed `var and `env` function inside background
    if (isVariableFunctionNode(node)) {
      shouldContinue = false;
      ranges[rangeIndex].start = null;
      ranges[rangeIndex].end = null;

      return;
    }

    const isPositionKeyword =
      (node.type === 'word' &&
        directionKeywords.has(node.value.toLowerCase())) ||
      isDimensionNode(node) ||
      isNumberNode(node) ||
      isMathFunctionNode(node);

    if (ranges[rangeIndex].start === null && isPositionKeyword) {
      ranges[rangeIndex].start = index;
      ranges[rangeIndex].end = index;

      return;
    }

    if (ranges[rangeIndex].start !== null) {
      if (node.type === 'space') {
        return;
      } else if (isPositionKeyword) {
        ranges[rangeIndex].end = index;

        return;
      }

      return;
    }
  });

  ranges.forEach((range) => {
    if (range.start === null) {
      return;
    }

    const nodes = parsed.nodes.slice(range.start, range.end + 1);

    if (nodes.length > 3) {
      return;
    }

    const firstNode = nodes[0].value.toLowerCase();
    const secondNode =
      nodes[2] && nodes[2].value ? nodes[2].value.toLowerCase() : null;

    if (nodes.length === 1 || secondNode === 'center') {
      if (secondNode) {
        nodes[2].value = nodes[1].value = '';
      }

      const map = new Map([...horizontal, ['center', center]]);

      if (map.has(firstNode)) {
        nodes[0].value = /** @type {string}*/ (map.get(firstNode));
      }

      return;
    }

    if (secondNode !== null) {
      if (firstNode === 'center' && directionKeywords.has(secondNode)) {
        nodes[0].value = nodes[1].value = '';

        if (horizontal.has(secondNode)) {
          nodes[2].value = /** @type {string} */ (horizontal.get(secondNode));
        }
        return;
      }

      if (horizontal.has(firstNode) && verticalValue.has(secondNode)) {
        nodes[0].value = /** @type {string} */ (horizontal.get(firstNode));
        nodes[2].value = /** @type {string} */ (verticalValue.get(secondNode));

        return;
      } else if (verticalValue.has(firstNode) && horizontal.has(secondNode)) {
        nodes[0].value = /** @type {string} */ (horizontal.get(secondNode));
        nodes[2].value = /** @type {string} */ (verticalValue.get(firstNode));

        return;
      }
    }
  });

  return parsed.toString();
}

/**
 * @type {import('postcss').PluginCreator<void>}
 * @return {import('postcss').Plugin}
 */
function pluginCreator() {
  return {
    postcssPlugin: 'postcss-normalize-positions',

    OnceExit(css) {
      const cache = new Map();

      css.walkDecls(
        /^(background(-position)?|(-\w+-)?perspective-origin)$/i,
        (decl) => {
          const value = decl.value;

          if (!value) {
            return;
          }

          if (cache.has(value)) {
            decl.value = cache.get(value);

            return;
          }

          const result = transform(value);

          decl.value = result;
          cache.set(value, result);
        }
      );
    },
  };
}

pluginCreator.postcss = true;
module.exports = pluginCreator;


code:
# [postcss][postcss]-normalize-repeat-style

> Normalize repeat styles with PostCSS.

## Install

With [npm](https://npmjs.org/package/postcss-normalize-repeat-style) do:

```
npm install postcss-normalize-repeat-style --save
```

## Example

### Input

```css
h1 {
    background: url(image.jpg) repeat no-repeat
}
```

### Output

```css
h1 {
    background: url(image.jpg) repeat-x
}
```

## Usage

See the [PostCSS documentation](https://github.com/postcss/postcss#usage) for
examples for your environment.

## Contributors

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

## License

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

[postcss]: https://github.com/postcss/postcss


postcss-normalize-repeat-style

description: Convert two value syntax for repeat-style into one value.


code:
'use strict';
const valueParser = require('postcss-value-parser');
const mappings = require('./lib/map');

/**
 * @param {unknown} item
 * @param {number} index
 * @return {boolean}
 */
function evenValues(item, index) {
  return index % 2 === 0;
}

const repeatKeywords = new Set(mappings.values());

/**
 * @param {valueParser.Node} node
 * @return {boolean}
 */
function isCommaNode(node) {
  return node.type === 'div' && node.value === ',';
}

const variableFunctions = new Set(['var', 'env', 'constant']);
/**
 * @param {valueParser.Node} node
 * @return {boolean}
 */
function isVariableFunctionNode(node) {
  if (node.type !== 'function') {
    return false;
  }

  return variableFunctions.has(node.value.toLowerCase());
}

/**
 * @param {string} value
 * @return {string}
 */
function transform(value) {
  const parsed = valueParser(value);

  if (parsed.nodes.length === 1) {
    return value;
  }
  /** @type {{start: number?, end: number?}[]} */
  const ranges = [];
  let rangeIndex = 0;
  let shouldContinue = true;

  parsed.nodes.forEach((node, index) => {
    // After comma (`,`) follows next background
    if (isCommaNode(node)) {
      rangeIndex += 1;
      shouldContinue = true;

      return;
    }

    if (!shouldContinue) {
      return;
    }

    // After separator (`/`) follows `background-size` values
    // Avoid them
    if (node.type === 'div' && node.value === '/') {
      shouldContinue = false;

      return;
    }

    if (!ranges[rangeIndex]) {
      ranges[rangeIndex] = {
        start: null,
        end: null,
      };
    }

    // Do not try to be processed `var and `env` function inside background
    if (isVariableFunctionNode(node)) {
      shouldContinue = false;
      ranges[rangeIndex].start = null;
      ranges[rangeIndex].end = null;

      return;
    }

    const isRepeatKeyword =
      node.type === 'word' && repeatKeywords.has(node.value.toLowerCase());

    if (ranges[rangeIndex].start === null && isRepeatKeyword) {
      ranges[rangeIndex].start = index;
      ranges[rangeIndex].end = index;

      return;
    }

    if (ranges[rangeIndex].start !== null) {
      if (node.type === 'space') {
        return;
      } else if (isRepeatKeyword) {
        ranges[rangeIndex].end = index;

        return;
      }

      return;
    }
  });

  ranges.forEach((range) => {
    if (range.start === null) {
      return;
    }

    const nodes = parsed.nodes.slice(
      range.start,
      /** @type {number} */ (range.end) + 1
    );

    if (nodes.length !== 3) {
      return;
    }
    const key = nodes
      .filter(evenValues)
      .map((n) => n.value.toLowerCase())
      .toString();

    const match = mappings.get(key);

    if (match) {
      nodes[0].value = match;
      nodes[1].value = nodes[2].value = '';
    }
  });

  return parsed.toString();
}

/**
 * @type {import('postcss').PluginCreator<void>}
 * @return {import('postcss').Plugin}
 */
function pluginCreator() {
  return {
    postcssPlugin: 'postcss-normalize-repeat-style',
    prepare() {
      const cache = new Map();
      return {
        OnceExit(css) {
          css.walkDecls(
            /^(background(-repeat)?|(-\w+-)?mask-repeat)$/i,
            (decl) => {
              const value = decl.value;

              if (!value) {
                return;
              }

              if (cache.has(value)) {
                decl.value = cache.get(value);

                return;
              }

              const result = transform(value);

              decl.value = result;
              cache.set(value, result);
            }
          );
        },
      };
    },
  };
}

pluginCreator.postcss = true;
module.exports = pluginCreator;


code:
'use strict';
module.exports = new Map([
  [['repeat', 'no-repeat'].toString(), 'repeat-x'],
  [['no-repeat', 'repeat'].toString(), 'repeat-y'],
  [['repeat', 'repeat'].toString(), 'repeat'],
  [['space', 'space'].toString(), 'space'],
  [['round', 'round'].toString(), 'round'],
  [['no-repeat', 'no-repeat'].toString(), 'no-repeat'],
]);


code:
# [postcss][postcss]-normalize-string

> Normalize strings with PostCSS.

## Install

With [npm](https://npmjs.org/package/postcss-normalize-string) do:

```
npm install postcss-normalize-string --save
```

## Example

### Input

```css
p:after{ content: '\\'string\\' is intact' }
```

### Output

```css
p:after{ content:"'string' is intact" }
```

## Usage

See the [PostCSS documentation](https://github.com/postcss/postcss#usage) for
examples for your environment.

## API

### normalize([options])

#### options

##### preferredQuote

Type: `string`
Default: `double`

Sets what type of quote to prefer. Possible values are `single` and `double`.

```js
var css = 'p:after{content:""}';
console.log(postcss(normalize({preferredQuote: 'single'})).process(css).css);
//=> p:after{content:''}
```

## Contributors

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

## License

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

[postcss]: https://github.com/postcss/postcss


code:
'use strict';
const valueParser = require('postcss-value-parser');

/*
 * Constants (parser usage)
 */

const SINGLE_QUOTE = "'".charCodeAt(0);
const DOUBLE_QUOTE = '"'.charCodeAt(0);
const BACKSLASH = '\\'.charCodeAt(0);
const NEWLINE = '\n'.charCodeAt(0);
const SPACE = ' '.charCodeAt(0);
const FEED = '\f'.charCodeAt(0);
const TAB = '\t'.charCodeAt(0);
const CR = '\r'.charCodeAt(0);

const WORD_END = /[ \n\t\r\f'"\\]/g;

/*
 * Constants (node type strings)
 */

const C_STRING = 'string';
const C_ESCAPED_SINGLE_QUOTE = 'escapedSingleQuote';
const C_ESCAPED_DOUBLE_QUOTE = 'escapedDoubleQuote';
const C_SINGLE_QUOTE = 'singleQuote';
const C_DOUBLE_QUOTE = 'doubleQuote';
const C_NEWLINE = 'newline';
const C_SINGLE = 'single';

/*
 * Literals
 */

const L_SINGLE_QUOTE = `'`;
const L_DOUBLE_QUOTE = `"`;
const L_NEWLINE = `\\\n`;

/*
 * Parser nodes
 */

const T_ESCAPED_SINGLE_QUOTE = { type: C_ESCAPED_SINGLE_QUOTE, value: `\\'` };
const T_ESCAPED_DOUBLE_QUOTE = { type: C_ESCAPED_DOUBLE_QUOTE, value: `\\"` };
const T_SINGLE_QUOTE = { type: C_SINGLE_QUOTE, value: L_SINGLE_QUOTE };
const T_DOUBLE_QUOTE = { type: C_DOUBLE_QUOTE, value: L_DOUBLE_QUOTE };
const T_NEWLINE = { type: C_NEWLINE, value: L_NEWLINE };

/** @typedef {T_ESCAPED_SINGLE_QUOTE | T_ESCAPED_DOUBLE_QUOTE | T_SINGLE_QUOTE | T_NEWLINE} StringAstNode */
/**
 * @typedef {{nodes: StringAstNode[],
 *            types: {escapedSingleQuote: number, escapedDoubleQuote: number, singleQuote: number, doubleQuote: number},
 *            quotes: boolean}} StringAst
 */

/**
 * @param {StringAst} ast
 * @return {string}
 */
function stringify(ast) {
  return ast.nodes.reduce((str, { value }) => {
    // Collapse multiple line strings automatically
    if (value === L_NEWLINE) {
      return str;
    }

    return str + value;
  }, '');
}

/**
 * @param {string} str
 * @return {StringAst}
 */
function parse(str) {
  let code, next, value;
  let pos = 0;
  let len = str.length;

  /** @type StringAst */
  const ast = {
    nodes: [],
    types: {
      escapedSingleQuote: 0,
      escapedDoubleQuote: 0,
      singleQuote: 0,
      doubleQuote: 0,
    },
    quotes: false,
  };

  while (pos < len) {
    code = str.charCodeAt(pos);

    switch (code) {
      case SPACE:
      case TAB:
      case CR:
      case FEED:
        next = pos;

        do {
          next += 1;
          code = str.charCodeAt(next);
        } while (
          code === SPACE ||
          code === NEWLINE ||
          code === TAB ||
          code === CR ||
          code === FEED
        );

        ast.nodes.push({
          type: 'space',
          value: str.slice(pos, next),
        });
        pos = next - 1;
        break;
      case SINGLE_QUOTE:
        ast.nodes.push(T_SINGLE_QUOTE);
        ast.types[C_SINGLE_QUOTE]++;
        ast.quotes = true;
        break;
      case DOUBLE_QUOTE:
        ast.nodes.push(T_DOUBLE_QUOTE);
        ast.types[C_DOUBLE_QUOTE]++;
        ast.quotes = true;
        break;
      case BACKSLASH:
        next = pos + 1;

        if (str.charCodeAt(next) === SINGLE_QUOTE) {
          ast.nodes.push(T_ESCAPED_SINGLE_QUOTE);
          ast.types[C_ESCAPED_SINGLE_QUOTE]++;
          ast.quotes = true;
          pos = next;
          break;
        } else if (str.charCodeAt(next) === DOUBLE_QUOTE) {
          ast.nodes.push(T_ESCAPED_DOUBLE_QUOTE);
          ast.types[C_ESCAPED_DOUBLE_QUOTE]++;
          ast.quotes = true;
          pos = next;
          break;
        } else if (str.charCodeAt(next) === NEWLINE) {
          ast.nodes.push(T_NEWLINE);
          pos = next;
          break;
        }
      /*
       * We need to fall through here to handle the token as
       * a whole word. The missing 'break' is intentional.
       */
      default:
        WORD_END.lastIndex = pos + 1;
        WORD_END.test(str);

        if (WORD_END.lastIndex === 0) {
          next = len - 1;
        } else {
          next = WORD_END.lastIndex - 2;
        }

        value = str.slice(pos, next + 1);

        ast.nodes.push({
          type: C_STRING,
          value,
        });

        pos = next;
    }
    pos++;
  }

  return ast;
}

/**
 * @param {valueParser.StringNode} node
 * @param {StringAst} ast
 * @return {void}
 */
function changeWrappingQuotes(node, ast) {
  const { types } = ast;

  if (types[C_SINGLE_QUOTE] || types[C_DOUBLE_QUOTE]) {
    return;
  }

  if (
    node.quote === L_SINGLE_QUOTE &&
    types[C_ESCAPED_SINGLE_QUOTE] > 0 &&
    !types[C_ESCAPED_DOUBLE_QUOTE]
  ) {
    node.quote = L_DOUBLE_QUOTE;
  }

  if (
    node.quote === L_DOUBLE_QUOTE &&
    types[C_ESCAPED_DOUBLE_QUOTE] > 0 &&
    !types[C_ESCAPED_SINGLE_QUOTE]
  ) {
    node.quote = L_SINGLE_QUOTE;
  }

  ast.nodes = changeChildQuotes(ast.nodes, node.quote);
}
/**
 * @param {StringAstNode[]} childNodes
 * @param {string} parentQuote
 * @return {StringAstNode[]}
 */
function changeChildQuotes(childNodes, parentQuote) {
  const updatedChildren = [];
  for (const child of childNodes) {
    if (
      child.type === C_ESCAPED_DOUBLE_QUOTE &&
      parentQuote === L_SINGLE_QUOTE
    ) {
      updatedChildren.push(T_DOUBLE_QUOTE);
    } else if (
      child.type === C_ESCAPED_SINGLE_QUOTE &&
      parentQuote === L_DOUBLE_QUOTE
    ) {
      updatedChildren.push(T_SINGLE_QUOTE);
    } else {
      updatedChildren.push(child);
    }
  }
  return updatedChildren;
}

/**
 * @param {string} value
 * @param {'single' | 'double'} preferredQuote
 * @return {string}
 */
function normalize(value, preferredQuote) {
  if (!value || !value.length) {
    return value;
  }

  return valueParser(value)
    .walk((child) => {
      if (child.type !== C_STRING) {
        return;
      }

      const ast = parse(child.value);

      if (ast.quotes) {
        changeWrappingQuotes(child, ast);
      } else if (preferredQuote === C_SINGLE) {
        child.quote = L_SINGLE_QUOTE;
      } else {
        child.quote = L_DOUBLE_QUOTE;
      }

      child.value = stringify(ast);
    })
    .toString();
}

/**
 * @param {string} original
 * @param {Map<string, string>} cache
 * @param {'single' | 'double'} preferredQuote
 * @return {string}
 */
function minify(original, cache, preferredQuote) {
  const key = original + '|' + preferredQuote;
  if (cache.has(key)) {
    return /** @type {string} */ (cache.get(key));
  }
  const newValue = normalize(original, preferredQuote);
  cache.set(key, newValue);
  return newValue;
}

/** @typedef {{preferredQuote?: 'double' | 'single'}} Options */
/**
 * @type {import('postcss').PluginCreator<Options>}
 * @param {Options} opts
 * @return {import('postcss').Plugin}
 */
function pluginCreator(opts) {
  const { preferredQuote } = Object.assign(
    {},
    {
      preferredQuote: 'double',
    },
    opts
  );

  return {
    postcssPlugin: 'postcss-normalize-string',

    OnceExit(css) {
      const cache = new Map();

      css.walk((node) => {
        switch (node.type) {
          case 'rule':
            node.selector = minify(node.selector, cache, preferredQuote);
            break;
          case 'decl':
            node.value = minify(node.value, cache, preferredQuote);
            break;
          case 'atrule':
            node.params = minify(node.params, cache, preferredQuote);
            break;
        }
      });
    },
  };
}

pluginCreator.postcss = true;
module.exports = pluginCreator;


code:
export = pluginCreator;
/** @typedef {{preferredQuote?: 'double' | 'single'}} Options */
/**
 * @type {import('postcss').PluginCreator<Options>}
 * @param {Options} opts
 * @return {import('postcss').Plugin}
 */
declare function pluginCreator(opts: Options): import('postcss').Plugin;
declare namespace pluginCreator {
    export { postcss, StringAstNode, StringAst, Options };
}
type Options = {
    preferredQuote?: 'double' | 'single';
};
declare var postcss: true;
type StringAstNode = {
    type: string;
    value: string;
} | {
    type: string;
    value: string;
} | {
    type: string;
    value: string;
} | {
    type: string;
    value: string;
};
type StringAst = {
    nodes: StringAstNode[];
    types: {
        escapedSingleQuote: number;
        escapedDoubleQuote: number;
        singleQuote: number;
        doubleQuote: number;
    };
    quotes: boolean;
};


code:
# [postcss][postcss]-normalize-timing-functions

> Normalize timing functions with PostCSS.

## Install

With [npm](https://npmjs.org/package/postcss-normalize-timing-functions) do:

```
npm install postcss-normalize-timing-functions --save
```

## Example

### Input

```css
div {
    animate: fade 3s cubic-bezier(0.42, 0, 1, 1)
}
```

### Output

```css
div {
    animate: fade 3s ease-in
}
```

## Usage

See the [PostCSS documentation](https://github.com/postcss/postcss#usage) for
examples for your environment.

## Contributors

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

## License

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

[postcss]: https://github.com/postcss/postcss


postcss-normalize-timing-functions

description: Normalize CSS animation/transition timing functions.

readme:
# [postcss][postcss]-normalize-timing-functions

> Normalize timing functions with PostCSS.

## Install

With [npm](https://npmjs.org/package/postcss-normalize-timing-functions) do:

```
npm install postcss-normalize-timing-functions --save
```

## Example

### Input

```css
div {
    animate: fade 3s cubic-bezier(0.42, 0, 1, 1)
}
```

### Output

```css
div {
    animate: fade 3s ease-in
}
```

## Usage

See the [PostCSS documentation](https://github.com/postcss/postcss#usage) for
examples for your environment.

## Contributors

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

## License

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

[postcss]: https://github.com/postcss/postcss


code:
'use strict';
const valueParser = require('postcss-value-parser');

/** @type {(node: valueParser.Node) => number} */
const getValue = (node) => parseFloat(node.value);

/* Works because toString() normalizes the formatting,
   so comparing the string forms behaves the same as number equality*/
const conversions = new Map([
  [[0.25, 0.1, 0.25, 1].toString(), 'ease'],
  [[0, 0, 1, 1].toString(), 'linear'],
  [[0.42, 0, 1, 1].toString(), 'ease-in'],
  [[0, 0, 0.58, 1].toString(), 'ease-out'],
  [[0.42, 0, 0.58, 1].toString(), 'ease-in-out'],
]);
/**
 * @param {valueParser.Node} node
 * @return {void | false}
 */
function reduce(node) {
  if (node.type !== 'function') {
    return false;
  }

  if (!node.value) {
    return;
  }

  const lowerCasedValue = node.value.toLowerCase();

  if (lowerCasedValue === 'steps') {
    // Don't bother checking the step-end case as it has the same length
    // as steps(1)
    if (
      node.nodes[0].type === 'word' &&
      getValue(node.nodes[0]) === 1 &&
      node.nodes[2] &&
      node.nodes[2].type === 'word' &&
      (node.nodes[2].value.toLowerCase() === 'start' ||
        node.nodes[2].value.toLowerCase() === 'jump-start')
    ) {
      /** @type string */ (node.type) = 'word';
      node.value = 'step-start';

      delete (/** @type Partial<valueParser.FunctionNode> */ (node).nodes);

      return;
    }

    if (
      node.nodes[0].type === 'word' &&
      getValue(node.nodes[0]) === 1 &&
      node.nodes[2] &&
      node.nodes[2].type === 'word' &&
      (node.nodes[2].value.toLowerCase() === 'end' ||
        node.nodes[2].value.toLowerCase() === 'jump-end')
    ) {
      /** @type string */ (node.type) = 'word';
      node.value = 'step-end';

      delete (/** @type Partial<valueParser.FunctionNode> */ (node).nodes);

      return;
    }

    // The end case is actually the browser default, so it isn't required.
    if (
      node.nodes[2] &&
      node.nodes[2].type === 'word' &&
      (node.nodes[2].value.toLowerCase() === 'end' ||
        node.nodes[2].value.toLowerCase() === 'jump-end')
    ) {
      node.nodes = [node.nodes[0]];

      return;
    }

    return false;
  }

  if (lowerCasedValue === 'cubic-bezier') {
    const values = node.nodes
      .filter((list, index) => {
        return index % 2 === 0;
      })
      .map(getValue);

    if (values.length !== 4) {
      return;
    }

    const match = conversions.get(values.toString());

    if (match) {
      /** @type string */ (node.type) = 'word';
      node.value = match;

      delete (/** @type Partial<valueParser.FunctionNode> */ (node).nodes);

      return;
    }
  }
}

/**
 * @param {string} value
 * @return {string}
 */
function transform(value) {
  return valueParser(value).walk(reduce).toString();
}

/**
 * @type {import('postcss').PluginCreator<void>}
 * @return {import('postcss').Plugin}
 */
function pluginCreator() {
  return {
    postcssPlugin: 'postcss-normalize-timing-functions',

    OnceExit(css) {
      const cache = new Map();

      css.walkDecls(
        /^(-\w+-)?(animation|transition)(-timing-function)?$/i,
        (decl) => {
          const value = decl.value;

          if (cache.has(value)) {
            decl.value = cache.get(value);

            return;
          }

          const result = transform(value);

          decl.value = result;
          cache.set(value, result);
        }
      );
    },
  };
}

pluginCreator.postcss = true;
module.exports = pluginCreator;


code:
# [postcss][postcss]-normalize-unicode

> Normalize unicode with PostCSS.

## Install

With [npm](https://npmjs.org/package/postcss-normalize-unicode) do:

```
npm install postcss-normalize-unicode --save
```

## Example

### Input

```css
@font-face{
    font-family: test;
    unicode-range: u+2b00-2bff
}
```

### Output

```css
@font-face{
    font-family: test;
    unicode-range: u+2b??
}
```

## Usage

See the [PostCSS documentation](https://github.com/postcss/postcss#usage) for
examples for your environment.

## Contributors

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

## License

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

[postcss]: https://github.com/postcss/postcss


postcss-normalize-unicode

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


code:
'use strict';
const browserslist = require('browserslist');
const valueParser = require('postcss-value-parser');

const regexLowerCaseUPrefix = /^u(?=\+)/;

/**
 * @param {string} range
 * @return {string}
 */
function unicode(range) {
  const values = range.slice(2).split('-');

  if (values.length < 2) {
    return range;
  }

  const left = values[0].split('');
  const right = values[1].split('');

  if (left.length !== right.length) {
    return range;
  }

  const merged = mergeRangeBounds(left, right);

  if (merged) {
    return merged;
  }

  return range;
}
/**
 * @param {string[]} left
 * @param {string[]} right
 * @return {false|string}
 */
function mergeRangeBounds(left, right) {
  let questionCounter = 0;
  let group = 'u+';
  for (const [index, value] of left.entries()) {
    if (value === right[index] && questionCounter === 0) {
      group = group + value;
    } else if (value === '0' && right[index] === 'f') {
      questionCounter++;
      group = group + '?';
    } else {
      return false;
    }
  }
  // The maximum number of wildcard characters (?) for ranges is 5.
  if (questionCounter < 6) {
    return group;
  } else {
    return false;
  }
}

/**
 * IE and Edge before 16 version ignore the unicode-range if the 'U' is lowercase
 *
 * https://caniuse.com/#search=unicode-range
 *
 * @param {string} browser
 * @return {boolean}
 */
function hasLowerCaseUPrefixBug(browser) {
  return browserslist('ie <=11, edge <= 15').includes(browser);
}

/**
 * @param {string} value
 * @return {string}
 */
function transform(value, isLegacy = false) {
  return valueParser(value)
    .walk((child) => {
      if (child.type === 'unicode-range') {
        const transformed = unicode(child.value.toLowerCase());

        child.value = isLegacy
          ? transformed.replace(regexLowerCaseUPrefix, 'U')
          : transformed;
      }

      return false;
    })
    .toString();
}

/**
 * @type {import('postcss').PluginCreator<void>}
 * @return {import('postcss').Plugin}
 */
function pluginCreator() {
  return {
    postcssPlugin: 'postcss-normalize-unicode',
    /** @param {import('postcss').Result & {opts: browserslist.Options}} result*/
    prepare(result) {
      const cache = new Map();
      const resultOpts = result.opts || {};
      const browsers = browserslist(null, {
        stats: resultOpts.stats,
        path: __dirname,
        env: resultOpts.env,
      });
      const isLegacy = browsers.some(hasLowerCaseUPrefixBug);

      return {
        OnceExit(css) {
          css.walkDecls(/^unicode-range$/i, (decl) => {
            const value = decl.value;

            if (cache.has(value)) {
              decl.value = cache.get(value);

              return;
            }

            const newValue = transform(value, isLegacy);

            decl.value = newValue;
            cache.set(value, newValue);
          });
        },
      };
    },
  };
}

pluginCreator.postcss = true;
module.exports = pluginCreator;


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:
# [postcss][postcss]-normalize-url

> [Normalize URLs](https://github.com/sindresorhus/normalize-url) with PostCSS.

## Install

With [npm](https://npmjs.org/package/postcss-normalize-url) do:

```
npm install postcss-normalize-url --save
```

## Example

### Input

```css
h1 {
    background: url("http://site.com:80/image.jpg")
}
```

### Output

```css
h1 {
    background: url(http://site.com/image.jpg)
}
```

Note that this module will also try to normalize relative URLs, and is capable
of stripping unnecessary quotes. For more examples, see the [tests](test.js).

## Usage

See the [PostCSS documentation](https://github.com/postcss/postcss#usage) for
examples for your environment.

## API

### normalize([options])

Please see the [normalize-url documentation][docs]. By default,
`normalizeProtocol`, `stripHash` & `stripWWW` are set to `false`.

## Contributors

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

## License

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

[docs]: https://github.com/sindresorhus/normalize-url#options
[postcss]: https://github.com/postcss/postcss