diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..fe10be7 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,34 @@ +name: "CodeQL" + +on: + push: + branches: + - master + - "!dependabot/**" + pull_request: + # The branches below must be a subset of the branches above + branches: + - master + schedule: + - cron: "0 2 * * 5" + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: "javascript" + + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml new file mode 100644 index 0000000..c13795c --- /dev/null +++ b/.github/workflows/node.js.yml @@ -0,0 +1,25 @@ +# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: x86 Linux build + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + node-version: [10.x, 12.x, 14.x, 15.x] + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + - run: npm ci + - run: npm test diff --git a/.jshintrc b/.jshintrc index 5d47cc8..a546a1f 100644 --- a/.jshintrc +++ b/.jshintrc @@ -2,6 +2,7 @@ "camelcase": true, "curly": false, "eqeqeq": false, + "esversion": 6, "immed": true, "indent": 2, "noarg": true, diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 27ae770..0000000 --- a/.travis.yml +++ /dev/null @@ -1,9 +0,0 @@ -language: node_js -cache: npm -node_js: - - 6 - - 8 - - 10 - - 12 -matrix: - fast_finish: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 61636b2..854e45e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,7 +37,7 @@ At the end make sure code styling validation passes: npm run check ``` -Finally push to your fork and [submit a pull request](https://github.com/jakubpawlowicz/clean-css-cli/compare/). +Finally push to your fork and [submit a pull request](https://github.com/clean-css/clean-css-cli/compare/). At this point you're waiting for a PR review which should not thake more than a day. diff --git a/History.md b/History.md index 67c01b6..5cbdfa9 100644 --- a/History.md +++ b/History.md @@ -1,135 +1,240 @@ -[4.3.0 / 2019-04-06](https://github.com/jakubpawlowicz/clean-css-cli/compare/4.2...v4.3.0) +[5.6.3 / 2023-11-30](https://github.com/clean-css/clean-css-cli/compare/v5.6.2...v5.6.3) +================== + +* Bumps clean-css dependency to 5.3.3 + +[5.6.2 / 2023-01-19](https://github.com/clean-css/clean-css-cli/compare/v5.6.1...v5.6.2) +================== + +* Bumps clean-css dependency to 5.3.2 + +[5.6.1 / 2022-07-13](https://github.com/clean-css/clean-css-cli/compare/v5.6.0...v5.6.1) +================== + +* Bumps clean-css dependency to 5.3.1. + +[5.6.0 / 2022-03-31](https://github.com/clean-css/clean-css-cli/compare/v5.5.2...v5.6.0) +================== + +* Bumps clean-css dependency to 5.3.0. + +[5.5.2 / 2022-01-28](https://github.com/clean-css/clean-css-cli/compare/v5.5.1...v5.5.2) +================== + +* Bumps clean-css dependency to 5.2.4. + +[5.5.1 / 2022-01-26](https://github.com/clean-css/clean-css-cli/compare/v5.5.0...v5.5.1) +================== + +* Bumps clean-css dependency to 5.2.3. + +[5.5.0 / 2021-12-08](https://github.com/clean-css/clean-css-cli/compare/5.4...v5.5.0) +================== + +* Adds a new `--watch` switch, which makes CLI re-run optimizations when watched file(s) change. + +[5.4.2 / 2021-10-21](https://github.com/clean-css/clean-css-cli/compare/v5.4.1...v5.4.2) +================== + +* Bumps clean-css dependency to 5.2.2. + +[5.4.1 / 2021-09-30](https://github.com/clean-css/clean-css-cli/compare/v5.4.0...v5.4.1) +================== + +* Bumps clean-css dependency to 5.2.1. + +[5.4.0 / 2021-09-30](https://github.com/clean-css/clean-css-cli/compare/5.3...v5.4.0) +================== + +* Bumps clean-css dependency to 5.2.0. + +[5.3.3 / 2021-08-05](https://github.com/clean-css/clean-css-cli/compare/v5.3.2...v5.3.3) +================== + +* Bumps clean-css dependency to 5.1.5. + +[5.3.2 / 2021-07-29](https://github.com/clean-css/clean-css-cli/compare/v5.3.1...v5.3.2) +================== + +* Bumps clean-css dependency to 5.1.4. + +[5.3.1 / 2021-07-29](https://github.com/clean-css/clean-css-cli/compare/v5.3.0...v5.3.1) +================== + +* Bumps clean-css dependency to 5.1.3. + +[5.3.0 / 2021-04-28](https://github.com/clean-css/clean-css-cli/compare/5.2...v5.3.0) +================== + +* Fixed issue [#61](https://github.com/clean-css/clean-css-cli/issues/61) - source maps, rebasing, and batch processing. +* Fixed issue [#65](https://github.com/clean-css/clean-css-cli/issues/65) - batch processing with output path. + +[5.2.2 / 2021-03-19](https://github.com/clean-css/clean-css-cli/compare/v5.2.1...v5.2.2) +================== + +* Bumps clean-css dependency to 5.1.2. + +[5.2.1 / 2021-03-03](https://github.com/clean-css/clean-css-cli/compare/v5.2.0...v5.2.1) +================== + +* Bumps clean-css dependency to 5.1.1. + +[5.2.0 / 2021-02-18](https://github.com/clean-css/clean-css-cli/compare/5.1...v5.2.0) +================== + +* Bumps clean-css dependency to 5.1.0. + +[5.1.0 / 2021-02-12](https://github.com/clean-css/clean-css-cli/compare/5.0...v5.1.0) +================== + +* Fixed issue [#51](https://github.com/clean-css/clean-css-cli/issues/51) - excluding files via glob negated pattern. + +[5.0.1 / 2021-02-11](https://github.com/clean-css/clean-css-cli/compare/v5.0.0...v5.0.1) +================== + +* Fixed issue [#54](https://github.com/clean-css/clean-css-cli/issues/54) - rebasing is still on if output option is used. + +[5.0.0 / 2021-02-10](https://github.com/clean-css/clean-css-cli/compare/4.3...v5.0.0) +================== + +* Adds `--batch-suffix` option to specify what gets appended to output filename in batch mode. +* Bumps clean-css dependency to 5.0. +* Bumps commander dependency to 7.0. +* Fixed issue [#18](https://github.com/clean-css/clean-css-cli/issues/18) - allows batch processing of input files. +* Fixed issue [#36](https://github.com/clean-css/clean-css-cli/issues/36) - automatically creates missing output directories. + +[4.3.0 / 2019-04-06](https://github.com/clean-css/clean-css-cli/compare/4.2...v4.3.0) ================== * Bumps clean-css dependency to 4.2.1. -* Fixed issue [#21](https://github.com/jakubpawlowicz/clean-css-cli/issues/21) - sanity check for printing out help. -* Fixed issue [#27](https://github.com/jakubpawlowicz/clean-css-cli/issues/27) - way to provide input source map. +* Fixed issue [#21](https://github.com/clean-css/clean-css-cli/issues/21) - sanity check for printing out help. +* Fixed issue [#27](https://github.com/clean-css/clean-css-cli/issues/27) - way to provide input source map. -[4.2.0 / 2018-08-02](https://github.com/jakubpawlowicz/clean-css-cli/compare/4.1...v4.2.0) +[4.2.0 / 2018-08-02](https://github.com/clean-css/clean-css-cli/compare/4.1...v4.2.0) ================== * Bumps clean-css dependency to 4.2.0. -[4.1.11 / 2018-03-02](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.1.10...v4.1.11) +[4.1.11 / 2018-03-02](https://github.com/clean-css/clean-css-cli/compare/v4.1.10...v4.1.11) ================== -* Fixed issue [#17](https://github.com/jakubpawlowicz/clean-css-cli/issues/17) - empty `--inline` switch. +* Fixed issue [#17](https://github.com/clean-css/clean-css-cli/issues/17) - empty `--inline` switch. -[4.1.10 / 2017-09-19](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.1.9...v4.1.10) +[4.1.10 / 2017-09-19](https://github.com/clean-css/clean-css-cli/compare/v4.1.9...v4.1.10) ================== * Bumps clean-css dependency to 4.1.9. -[4.1.9 / 2017-09-03](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.1.8...v4.1.9) +[4.1.9 / 2017-09-03](https://github.com/clean-css/clean-css-cli/compare/v4.1.8...v4.1.9) ================== * Bumps clean-css dependency to 4.1.8. -[4.1.8 / 2017-09-03](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.1.7...v4.1.8) +[4.1.8 / 2017-09-03](https://github.com/clean-css/clean-css-cli/compare/v4.1.7...v4.1.8) ================== * Bumps clean-css dependency to 4.1.7. -[4.1.7 / 2017-09-03](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.1.6...v4.1.7) +[4.1.7 / 2017-09-03](https://github.com/clean-css/clean-css-cli/compare/v4.1.6...v4.1.7) ================== * Bumps clean-css dependency to 4.1.6. -[4.1.6 / 2017-06-29](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.1.5...v4.1.6) +[4.1.6 / 2017-06-29](https://github.com/clean-css/clean-css-cli/compare/v4.1.5...v4.1.6) ================== * Bumps clean-css dependency to 4.1.5. -[4.1.5 / 2017-06-14](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.1.4...v4.1.5) +[4.1.5 / 2017-06-14](https://github.com/clean-css/clean-css-cli/compare/v4.1.4...v4.1.5) ================== * Bumps clean-css dependency to 4.1.4. -[4.1.4 / 2017-06-09](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.1.3...v4.1.4) +[4.1.4 / 2017-06-09](https://github.com/clean-css/clean-css-cli/compare/v4.1.3...v4.1.4) ================== -* Fixed issue [#10](https://github.com/jakubpawlowicz/clean-css-cli/issues/10) - IE/Edge source maps. +* Fixed issue [#10](https://github.com/clean-css/clean-css-cli/issues/10) - IE/Edge source maps. -[4.1.3 / 2017-05-18](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.1.2...v4.1.3) +[4.1.3 / 2017-05-18](https://github.com/clean-css/clean-css-cli/compare/v4.1.2...v4.1.3) ================== * Bumps clean-css dependency to 4.1.3. -[4.1.2 / 2017-05-10](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.1.1...v4.1.2) +[4.1.2 / 2017-05-10](https://github.com/clean-css/clean-css-cli/compare/v4.1.1...v4.1.2) ================== * Bumps clean-css dependency to 4.1.2. -[4.1.1 / 2017-05-10](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.1.0...v4.1.1) +[4.1.1 / 2017-05-10](https://github.com/clean-css/clean-css-cli/compare/v4.1.0...v4.1.1) ================== * Bumps clean-css dependency to 4.1.1. -[4.1.0 / 2017-05-08](https://github.com/jakubpawlowicz/clean-css-cli/compare/4.0...v4.1.0) +[4.1.0 / 2017-05-08](https://github.com/clean-css/clean-css-cli/compare/4.0...v4.1.0) ================== * Bumps clean-css dependency to 4.1.x. -* Fixed issue [#1](https://github.com/jakubpawlowicz/clean-css-cli/issues/1) - option to remove inlined files. -* Fixed issue [#2](https://github.com/jakubpawlowicz/clean-css-cli/issues/2) - glob matching source paths. -* Fixed issue [#5](https://github.com/jakubpawlowicz/clean-css-cli/issues/5) - non-boolean compatibility options. -* Fixed issue [#7](https://github.com/jakubpawlowicz/clean-css-cli/issues/7) - using CLI as a module. +* Fixed issue [#1](https://github.com/clean-css/clean-css-cli/issues/1) - option to remove inlined files. +* Fixed issue [#2](https://github.com/clean-css/clean-css-cli/issues/2) - glob matching source paths. +* Fixed issue [#5](https://github.com/clean-css/clean-css-cli/issues/5) - non-boolean compatibility options. +* Fixed issue [#7](https://github.com/clean-css/clean-css-cli/issues/7) - using CLI as a module. -[4.0.12 / 2017-04-12](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.0.11...v4.0.12) +[4.0.12 / 2017-04-12](https://github.com/clean-css/clean-css-cli/compare/v4.0.11...v4.0.12) ================== * Bumps clean-css dependency to 4.0.12. -[4.0.11 / 2017-04-11](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.0.10...v4.0.11) +[4.0.11 / 2017-04-11](https://github.com/clean-css/clean-css-cli/compare/v4.0.10...v4.0.11) ================== * Bumps clean-css dependency to 4.0.11. -[4.0.10 / 2017-03-22](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.0.9...v4.0.10) +[4.0.10 / 2017-03-22](https://github.com/clean-css/clean-css-cli/compare/v4.0.9...v4.0.10) ================== * Bumps clean-css dependency to 4.0.10. -[4.0.9 / 2017-03-15](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.0.8...v4.0.9) +[4.0.9 / 2017-03-15](https://github.com/clean-css/clean-css-cli/compare/v4.0.8...v4.0.9) ================== * Bumps clean-css dependency to 4.0.9. -[4.0.8 / 2017-02-22](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.0.7...v4.0.8) +[4.0.8 / 2017-02-22](https://github.com/clean-css/clean-css-cli/compare/v4.0.7...v4.0.8) ================== * Bumps clean-css dependency to 4.0.8. -[4.0.7 / 2017-02-14](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.0.6...v4.0.7) +[4.0.7 / 2017-02-14](https://github.com/clean-css/clean-css-cli/compare/v4.0.6...v4.0.7) ================== * Bumps clean-css dependency to 4.0.7. -[4.0.6 / 2017-02-10](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.0.5...v4.0.6) +[4.0.6 / 2017-02-10](https://github.com/clean-css/clean-css-cli/compare/v4.0.5...v4.0.6) ================== * Bumps clean-css dependency to 4.0.6. -[4.0.5 / 2017-02-07](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.0.4...v4.0.5) +[4.0.5 / 2017-02-07](https://github.com/clean-css/clean-css-cli/compare/v4.0.4...v4.0.5) ================== * Bumps clean-css dependency to 4.0.5. -[4.0.4 / 2017-02-07](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.0.3...v4.0.4) +[4.0.4 / 2017-02-07](https://github.com/clean-css/clean-css-cli/compare/v4.0.3...v4.0.4) ================== * Bumps clean-css dependency to 4.0.4. -[4.0.3 / 2017-02-07](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.0.2...v4.0.3) +[4.0.3 / 2017-02-07](https://github.com/clean-css/clean-css-cli/compare/v4.0.2...v4.0.3) ================== * Bumps clean-css dependency to 4.0.3. -[4.0.2 / 2017-02-07](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.0.1...v4.0.2) +[4.0.2 / 2017-02-07](https://github.com/clean-css/clean-css-cli/compare/v4.0.1...v4.0.2) ================== * Bumps clean-css dependency to 4.0.2. -[4.0.1 / 2017-02-07](https://github.com/jakubpawlowicz/clean-css-cli/compare/v4.0.0...v4.0.1) +[4.0.1 / 2017-02-07](https://github.com/clean-css/clean-css-cli/compare/v4.0.0...v4.0.1) ================== * Bumps clean-css dependency to 4.0.1. @@ -138,4 +243,4 @@ ================== * Initial release of separate clean-css-cli. -* See [clean-css release notes](https://github.com/jakubpawlowicz/clean-css/blob/master/History.md#400--2017-01-23) for a full list of changes. +* See [clean-css release notes](https://github.com/clean-css/clean-css/blob/master/History.md#400--2017-01-23) for a full list of changes. diff --git a/README.md b/README.md index 9decfe8..49a7a9f 100644 --- a/README.md +++ b/README.md @@ -6,24 +6,28 @@ [![NPM version](https://img.shields.io/npm/v/clean-css-cli.svg?style=flat)](https://www.npmjs.com/package/clean-css-cli) -[![Linux Build Status](https://img.shields.io/travis/jakubpawlowicz/clean-css-cli/master.svg?style=flat&label=Linux%20build)](https://travis-ci.org/jakubpawlowicz/clean-css) -[![Dependency Status](https://img.shields.io/david/jakubpawlowicz/clean-css-cli.svg?style=flat)](https://david-dm.org/jakubpawlowicz/clean-css-cli) +![x86 Linux build](https://github.com/clean-css/clean-css-cli/workflows/x86%20Linux%20build/badge.svg) +[![Dependency Status](https://img.shields.io/david/clean-css/clean-css-cli.svg?style=flat)](https://david-dm.org/clean-css/clean-css-cli) [![NPM Downloads](https://img.shields.io/npm/dm/clean-css-cli.svg)](https://www.npmjs.com/package/clean-css-cli) -[![Twitter](https://img.shields.io/badge/Twitter-@cleancss-blue.svg)](https://twitter.com/cleancss) clean-css-cli is a command-line interface to [clean-css](https://github.com/jakubpawlowicz/clean-css) - fast and efficient CSS optimizer for [Node.js](http://nodejs.org/). Previously a part of clean-css it's a separate package since clean-css 4.0. +__IMPORTANT: clean-css-cli is now in a [maintenance mode](https://github.com/clean-css/clean-css-cli/discussions/76). PRs are still welcome, and I will try do an occasional bugfix relase.__ + **Table of Contents** - [Node.js version support](#nodejs-version-support) - [Install](#install) - [Use](#use) - * [Important: 4.0 breaking changes](#important-40-breaking-changes) - * [What's new in version 4.1](#whats-new-in-version-41) - * [What's new in version 4.2](#whats-new-in-version-42) + * [What's new in version 5.5](#whats-new-in-version-55) + * [What's new in version 5.1](#whats-new-in-version-51) + * [What's new in version 5.0](#whats-new-in-version-50) * [What's new in version 4.3](#whats-new-in-version-43) + * [What's new in version 4.2](#whats-new-in-version-42) + * [What's new in version 4.1](#whats-new-in-version-41) + * [What's new in version 4.0](#whats-new-in-version-40) * [CLI options](#cli-options) * [Compatibility modes](#compatibility-modes) * [Formatting options](#formatting-options) @@ -35,6 +39,7 @@ Previously a part of clean-css it's a separate package since clean-css 4.0. * [As a module](#as-a-module) - [FAQ](#faq) * [How to optimize multiple files?](#how-to-optimize-multiple-files) + * [How to process multiple files without concatenating them into one output file?](#how-to-process-multiple-files-without-concatenating-them-into-one-output-file) * [How to specify a custom rounding precision?](#how-to-specify-a-custom-rounding-precision) * [How to rebase relative image URLs?](#how-to-rebase-relative-image-urls) * [How to apply level 1 & 2 optimizations at the same time?](#how-to-apply-level-1--2-optimizations-at-the-same-time) @@ -44,7 +49,7 @@ Previously a part of clean-css it's a separate package since clean-css 4.0. # Node.js version support -clean-css-cli requires Node.js 4.0+ (tested on Linux, OS X, and Windows) +clean-css-cli requires Node.js 10.0+ (tested on Linux) # Install @@ -59,23 +64,41 @@ Note: Global install via -g option is recommended unless you want to execute the cleancss -o one.min.css one.css ``` -## Important: 4.0 breaking changes +## What's new in version 5.5 -clean-css-cli 4.0 introduces some breaking changes: +clean-css-cli 5.5 introduces the following changes / features: -* API and CLI interfaces are split, so CLI has been moved to this repository while API stays at [clean-css](https://github.com/jakubpawlowicz/clean-css); -* `--root` and `--relativeTo` options are replaced by a single option taken from `--output` path - this means that rebasing URLs and import inlining is much simpler but may not be (YMMV) as powerful as in 3.x; -* `--rounding-precision` is disabled by default; -* `--rounding-precision` applies to **all** units now, not only `px` as in 3.x; -* `--skip-import` and `--skip-import-from` are merged into `--inline` option which defaults to `local`. Remote `@import` rules are **NOT** inlined by default anymore; -* renames `--timeout` option to `--inline-timeout`; -* remote resources without a protocol, e.g. `//fonts.googleapis.com/css?family=Domine:700`, are not inlined anymore; -* changes default Internet Explorer compatibility from 9+ to 10+, to revert the old default use `--compatibility ie9` option; -* moves `--rounding-precision`, `--s0`, and `--s1` options to level 1 optimization options, see examples; -* moves `--skip-media-merging`, `--skip-restructuring`, `--semantic-merging`, and `--skip-shorthand-compacting` to level 2 optimizations options, see examples below; -* level 1 optimizations are the new default, up to 3.x it was level 2; -* `--keep-breaks` option is replaced with `--format keep-breaks` to ease transition; -* `--skip-aggressive-merging` option is removed as aggressive merging is replaced by smarter override merging. +* adds a new `--watch` switch, which makes `cleancss` re-run optimizations when watched file(s) change. + +## What's new in version 5.1 + +clean-css-cli 5.1 introduces the following changes / features: + +* accept `!path/to/file` as a way of telling `cleancss` to ignore such file, also accepts any available glob patterns. + +## What's new in version 5.0 + +clean-css-cli 5.0 introduces the following changes / features: + +* adds `--batch` option (off by default) which processes input files one by one without joining them together; +* adds `--batch-suffix` option to specify what gets appended to output filename in batch mode; +* automatically creates missing output directories; +* clean-css 5.0 with loads of bugfixes; +* drops official support for Node.js 4, 6, and 8; +* `--skip-rebase` option has been removed as rebasing URLs is disabled by default now +* `--with-rebase` option is added if you really want URLs rebasing + +## What's new in version 4.3 + +clean-css-cli 4.3 introduces the following changes / features: + +* `--input-source-map` option which accepts a path to input source map file. + +## What's new in version 4.2 + +clean-css-cli 4.2 introduces the following changes / features: + +* [clean-css 4.2](https://github.com/jakubpawlowicz/clean-css#whats-new-in-version-42) as a dependency; ## What's new in version 4.1 @@ -88,35 +111,42 @@ clean-css-cli 4.1 introduces the following changes / features: * extracts CLI into an importable module, so it can be reused and enhanced if needed; * adds `beforeMinify` callback as a second argument to CLI module, see [example use case](#as-a-module). -## What's new in version 4.2 - -clean-css-cli 4.2 introduces the following changes / features: +## What's new in version 4.0 -* [clean-css 4.2](https://github.com/jakubpawlowicz/clean-css#whats-new-in-version-42) as a dependency; - -## What's new in version 4.3 - -clean-css-cli 4.3 introduces the following changes / features: +clean-css-cli 4.0 introduces some breaking changes: -* `--input-source-map` option which accepts a path to input source map file. +* API and CLI interfaces are split, so CLI has been moved to this repository while API stays at [clean-css](https://github.com/jakubpawlowicz/clean-css); +* `--root` and `--relativeTo` options are replaced by a single option taken from `--output` path - this means that rebasing URLs and import inlining is much simpler but may not be (YMMV) as powerful as in 3.x; +* `--rounding-precision` is disabled by default; +* `--rounding-precision` applies to **all** units now, not only `px` as in 3.x; +* `--skip-import` and `--skip-import-from` are merged into `--inline` option which defaults to `local`. Remote `@import` rules are **NOT** inlined by default anymore; +* renames `--timeout` option to `--inline-timeout`; +* remote resources without a protocol, e.g. `//fonts.googleapis.com/css?family=Domine:700`, are not inlined anymore; +* changes default Internet Explorer compatibility from 9+ to 10+, to revert the old default use `--compatibility ie9` option; +* moves `--rounding-precision`, `--s0`, and `--s1` options to level 1 optimization options, see examples; +* moves `--skip-media-merging`, `--skip-restructuring`, `--semantic-merging`, and `--skip-shorthand-compacting` to level 2 optimizations options, see examples below; +* level 1 optimizations are the new default, up to 3.x it was level 2; +* `--keep-breaks` option is replaced with `--format keep-breaks` to ease transition; +* `--skip-aggressive-merging` option is removed as aggressive merging is replaced by smarter override merging. ## CLI options ```shell --h, --help output usage information --v, --version output the version number +-b, --batch If enabled, optimizes input files one by one instead of joining them together -c, --compatibility [ie7|ie8] Force compatibility mode (see Readme for advanced examples) -d, --debug Shows debug information (minification time & compression efficiency) -f, --format Controls output formatting, see examples below +-h, --help output usage information -o, --output [output-file] Use [output-file] as output instead of STDOUT --O [optimizations] Turn on level optimizations; optionally accepts a list of fine-grained options, defaults to `1`, see examples below +-O [optimizations] Turn on level optimizations; optionally accepts a list of fine-grained options, defaults to `1`, IMPORTANT: the prefix is O (a capital o letter), NOT a 0 (zero, a number) +-v, --version output the version number --inline [rules] Enables inlining for listed sources (defaults to `local`) --inline-timeout [seconds] Per connection timeout when fetching remote stylesheets (defaults to 5 seconds) +--input-source-map [file] Specifies the path of the input source map file --remove-inlined-files Remove files inlined in or via `@import` statements ---skip-rebase Disable URLs rebasing --source-map Enables building input's source map --source-map-inline-sources Enables inlining sources inside source maps ---input-source-map [file] Specifies the path of the input source map file +--with-rebase Enables URLs rebasing ``` ## Compatibility modes @@ -217,16 +247,18 @@ cleancss --inline 'local,remote,!fonts.googleapis.com' one.css ## Optimization levels -The `--level` option can be either `0`, `1` (default), or `2`, e.g. +The `-O` option can be either `0`, `1` (default), or `2`, e.g. ```shell -cleancss --level 2 one.css +cleancss -O2 one.css ``` or a fine-grained configuration given via a string. Please note that level 1 optimization options are generally safe while level 2 optimizations should be safe for most users. +Important: The `-O` option is using the capital letter O (as in "Oscar"), not the number zero. + ### Level 0 optimizations Level 0 optimizations simply means "no optimizations". Use it when you'd like to inline imports and / or rebase URLs but skip everything else, e.g. @@ -314,12 +346,20 @@ clean-css-cli can also be used as a module in a way of enhancing its functionali var cleanCssCli = require('clean-css-cli'); -return cleanCssCli(process, function beforeMinify(cleanCss) { - cleanCss.options.level['1'].transform = function (propertyName, propertyValue) { - if (propertyName == 'background-image' && propertyValue.indexOf('../valid/path/to') == -1) { - return propertyValue.replace('url(', 'url(../valid/path/to/'); +var customPlugin = { + level1: { + value: function (propertyName, propertyValue, options) { + if (propertyName == 'background-image' && propertyValue.indexOf('../valid/path/to') == -1) { + return propertyValue.replace('url(', 'url(../valid/path/to/'); + } else { + return propertyValue; + } } } +} + +return cleanCssCli(process, function (cleanCss) { + cleanCss.options.plugins.level1Value.push(customPlugin.level1.value); }); ``` @@ -341,6 +381,36 @@ Since version 4.1.0 it can also be done using glob pattern matching, e.g. cleancss -o merged.min.css *.css ``` +## How to process multiple files without concatenating them into one output file? + +Since clean-css-cli 5.0 you can optimize files one by one, without joining them into one output file, e.g. + +```shell +cleancss --batch styles/*.css +``` + +By default it will pick up every single file from `styles` directory, optimize it, add a `-min` suffix to filename (before extension), and write it to disk. + +You can use `--batch-suffix` option to customize the `-min` suffix, e.g. + +```shell +cleancss --batch --batch-suffix '.min' styles/*.css # output will have `.min` suffix before `.css`, e.g. styles.min.css +``` + +or + +```shell +cleancss --batch --batch-suffix '' styles/*.css # output files will OVERRIDE input files +``` + +Remember you can use [glob matching](https://www.npmjs.com/package/glob#glob-primer) to match exactly the files you want. + +Since clean-css-cli 5.1 you can also use a negated pattern to exclude some files from being matched, e.g. + +```shell +cleancss --batch styles/*.css !styles/*.min.css +``` + ## How to specify a custom rounding precision? The level 1 `roundingPrecision` optimization option accept a string with per-unit rounding precision settings, e.g. @@ -353,7 +423,7 @@ which sets all units rounding precision to 3 digits except `px` unit precision o ## How to rebase relative image URLs? -clean-css-cli will handle it automatically for you when full paths to input files are passed in and `--output` option is used, e.g +clean-css-cli will rebase paths it automatically for you when full paths to input files are passed, and `--with-rebase` & `--output` options are used, e.g ```css /*! one.css */ @@ -363,7 +433,7 @@ a { ``` ```shell -cleancss -o build/one.min.css one.css +cleancss --with-rebase -o build/one.min.css one.css ``` ```css @@ -383,14 +453,14 @@ will apply level 1 optimizations, except url normalization, and default level 2 # Contributing -See [CONTRIBUTING.md](https://github.com/jakubpawlowicz/clean-css-cli/blob/master/CONTRIBUTING.md). +See [CONTRIBUTING.md](https://github.com/clean-css/clean-css-cli/blob/master/CONTRIBUTING.md). ## How to get started? First clone the sources: ```shell -git clone git@github.com:jakubpawlowicz/clean-css-cli.git +git clone git@github.com:clean-css/clean-css-cli.git ``` then install dependencies: @@ -409,4 +479,4 @@ npm test # to run all tests # License -clean-css-cli is released under the [MIT License](https://github.com/jakubpawlowicz/clean-css-cli/blob/master/LICENSE). +clean-css-cli is released under the [MIT License](https://github.com/clean-css/clean-css-cli/blob/master/LICENSE). diff --git a/index.js b/index.js index ff8c0bc..bfd06df 100644 --- a/index.js +++ b/index.js @@ -2,7 +2,7 @@ var fs = require('fs'); var path = require('path'); var CleanCSS = require('clean-css'); -var commands = require('commander'); +var program = require('commander'); var glob = require('glob'); var COMPATIBILITY_PATTERN = /([\w\.]+)=(\w+)/g; @@ -12,8 +12,7 @@ function cli(process, beforeMinifyCallback) { var packageConfig = fs.readFileSync(path.join(__dirname, 'package.json')); var buildVersion = JSON.parse(packageConfig).version; var fromStdin; - var debugMode; - var removeInlinedFiles; + var inputOptions; var options; var stdin; var data; @@ -21,163 +20,144 @@ function cli(process, beforeMinifyCallback) { beforeMinifyCallback = beforeMinifyCallback || Function.prototype; // Specify commander options to parse command line params correctly - commands - .version(buildVersion, '-v, --version') + program .usage('[options] ') + .option('-b, --batch', 'If enabled, optimizes input files one by one instead of joining them together') .option('-c, --compatibility [ie7|ie8]', 'Force compatibility mode (see Readme for advanced examples)') .option('-d, --debug', 'Shows debug information (minification time & compression efficiency)') .option('-f, --format ', 'Controls output formatting, see examples below') + .option('-h, --help', 'display this help') .option('-o, --output [output-file]', 'Use [output-file] as output instead of STDOUT') - .option('-O [optimizations]', 'Turn on level optimizations; optionally accepts a list of fine-grained options, defaults to `1`, see examples below', function (val) { return Math.abs(parseInt(val)); }) + .option('-O [optimizations]', 'Turn on level optimizations; optionally accepts a list of fine-grained options, defaults to `1`, see examples below, IMPORTANT: the prefix is O (a capital o letter), NOT a 0 (zero, a number)', function (val) { return Math.abs(parseInt(val)); }) + .version(buildVersion, '-v, --version') + .option('--batch-suffix ', 'A suffix (without extension) appended to input file name when processing in batch mode (`-min` is the default)', '-min') .option('--inline [rules]', 'Enables inlining for listed sources (defaults to `local`)') .option('--inline-timeout [seconds]', 'Per connection timeout when fetching remote stylesheets (defaults to 5 seconds)', parseFloat) + .option('--input-source-map [file]', 'Specifies the path of the input source map file') .option('--remove-inlined-files', 'Remove files inlined in or via `@import` statements') - .option('--skip-rebase', 'Disable URLs rebasing') .option('--source-map', 'Enables building input\'s source map') .option('--source-map-inline-sources', 'Enables inlining sources inside source maps') - .option('--input-source-map [file]', 'Specifies the path of the input source map file'); - - commands.on('--help', function () { - console.log(' Examples:\n'); - console.log(' %> cleancss one.css'); - console.log(' %> cleancss -o one-min.css one.css'); - console.log(' %> cleancss -o merged-and-minified.css one.css two.css three.css'); - console.log(' %> cleancss one.css two.css three.css | gzip -9 -c > merged-minified-and-gzipped.css.gz'); + .option('--with-rebase', 'Enable URLs rebasing') + .option('--watch', 'Runs CLI in watch mode'); + + program.on('--help', function () { + console.log(''); + console.log('Examples:\n'); + console.log(' %> cleancss one.css'); + console.log(' %> cleancss -o one-min.css one.css'); + console.log(' %> cleancss -o merged-and-minified.css one.css two.css three.css'); + console.log(' %> cleancss one.css two.css three.css | gzip -9 -c > merged-minified-and-gzipped.css.gz'); console.log(''); - console.log(' Formatting options:'); - console.log(' %> cleancss --format beautify one.css'); - console.log(' %> cleancss --format keep-breaks one.css'); - console.log(' %> cleancss --format \'indentBy:1;indentWith:tab\' one.css'); - console.log(' %> cleancss --format \'breaks:afterBlockBegins=on;spaces:aroundSelectorRelation=on\' one.css'); - console.log(' %> # `breaks` controls where to insert breaks'); - console.log(' %> # `afterAtRule` controls if a line break comes after an at-rule; e.g. `@charset`; defaults to `off` (alias to `false`)'); - console.log(' %> # `afterBlockBegins` controls if a line break comes after a block begins; e.g. `@media`; defaults to `off`'); - console.log(' %> # `afterBlockEnds` controls if a line break comes after a block ends, defaults to `off`'); - console.log(' %> # `afterComment` controls if a line break comes after a comment; defaults to `off`'); - console.log(' %> # `afterProperty` controls if a line break comes after a property; defaults to `off`'); - console.log(' %> # `afterRuleBegins` controls if a line break comes after a rule begins; defaults to `off`'); - console.log(' %> # `afterRuleEnds` controls if a line break comes after a rule ends; defaults to `off`'); - console.log(' %> # `beforeBlockEnds` controls if a line break comes before a block ends; defaults to `off`'); - console.log(' %> # `betweenSelectors` controls if a line break comes between selectors; defaults to `off`'); - console.log(' %> # `indentBy` controls number of characters to indent with; defaults to `0`'); - console.log(' %> # `indentWith` controls a character to indent with, can be `space` or `tab`; defaults to `space`'); - console.log(' %> # `spaces` controls where to insert spaces'); - console.log(' %> # `aroundSelectorRelation` controls if spaces come around selector relations; e.g. `div > a`; defaults to `off`'); - console.log(' %> # `beforeBlockBegins` controls if a space comes before a block begins; e.g. `.block {`; defaults to `off`'); - console.log(' %> # `beforeValue` controls if a space comes before a value; e.g. `width: 1rem`; defaults to `off`'); - console.log(' %> # `wrapAt` controls maximum line length; defaults to `off`'); + console.log('Formatting options:'); + console.log(' %> cleancss --format beautify one.css'); + console.log(' %> cleancss --format keep-breaks one.css'); + console.log(' %> cleancss --format \'indentBy:1;indentWith:tab\' one.css'); + console.log(' %> cleancss --format \'breaks:afterBlockBegins=on;spaces:aroundSelectorRelation=on\' one.css'); + console.log(' %> cleancss --format \'breaks:afterBlockBegins=2;spaces:aroundSelectorRelation=on\' one.css'); console.log(''); - console.log(' Level 0 optimizations:'); - console.log(' %> cleancss -O0 one.css'); + console.log('Level 0 optimizations:'); + console.log(' %> cleancss -O0 one.css'); console.log(''); - console.log(' Level 1 optimizations:'); - console.log(' %> cleancss -O1 one.css'); - console.log(' %> cleancss -O1 removeQuotes:off;roundingPrecision:4;specialComments:1 one.css'); - console.log(' %> cleancss -O1 all:off;specialComments:1 one.css'); - console.log(' %> # `cleanupCharsets` controls `@charset` moving to the front of a stylesheet; defaults to `on`'); - console.log(' %> # `normalizeUrls` controls URL normalzation; default to `on`'); - console.log(' %> # `optimizeBackground` controls `background` property optimizatons; defaults to `on`'); - console.log(' %> # `optimizeBorderRadius` controls `border-radius` property optimizatons; defaults to `on`'); - console.log(' %> # `optimizeFilter` controls `filter` property optimizatons; defaults to `on`'); - console.log(' %> # `optimizeFontWeight` controls `font-weight` property optimizatons; defaults to `on`'); - console.log(' %> # `optimizeOutline` controls `outline` property optimizatons; defaults to `on`'); - console.log(' %> # `removeEmpty` controls removing empty rules and nested blocks; defaults to `on` (since 4.1.0)'); - console.log(' %> # `removeNegativePaddings` controls removing negative paddings; defaults to `on`'); - console.log(' %> # `removeQuotes` controls removing quotes when unnecessary; defaults to `on`'); - console.log(' %> # `removeWhitespace` controls removing unused whitespace; defaults to `on`'); - console.log(' %> # `replaceMultipleZeros` contols removing redundant zeros; defaults to `on`'); - console.log(' %> # `replaceTimeUnits` controls replacing time units with shorter values; defaults to `on'); - console.log(' %> # `replaceZeroUnits` controls replacing zero values with units; defaults to `on`'); - console.log(' %> # `roundingPrecision` rounds pixel values to `N` decimal places; `off` disables rounding; defaults to `off`'); - console.log(' %> # `selectorsSortingMethod` denotes selector sorting method; can be `natural` or `standard`; defaults to `standard`'); - console.log(' %> # `specialComments` denotes a number of /*! ... */ comments preserved; defaults to `all`'); - console.log(' %> # `tidyAtRules` controls at-rules (e.g. `@charset`, `@import`) optimizing; defaults to `on`'); - console.log(' %> # `tidyBlockScopes` controls block scopes (e.g. `@media`) optimizing; defaults to `on`'); - console.log(' %> # `tidySelectors` controls selectors optimizing; defaults to `on`'); + console.log('Level 1 optimizations:'); + console.log(' %> cleancss -O1 one.css'); + console.log(' %> cleancss -O1 removeQuotes:off;roundingPrecision:4;specialComments:1 one.css'); + console.log(' %> cleancss -O1 all:off;specialComments:1 one.css'); console.log(''); - console.log(' Level 2 optimizations:'); - console.log(' %> cleancss -O2 one.css'); - console.log(' %> cleancss -O2 mergeMedia:off;restructureRules:off;mergeSemantically:on;mergeIntoShorthands:off one.css'); - console.log(' %> cleancss -O2 all:off;removeDuplicateRules:on one.css'); - console.log(' %> # `mergeAdjacentRules` controls adjacent rules merging; defaults to `on`'); - console.log(' %> # `mergeIntoShorthands` controls merging properties into shorthands; defaults to `on`'); - console.log(' %> # `mergeMedia` controls `@media` merging; defaults to `on`'); - console.log(' %> # `mergeNonAdjacentRules` controls non-adjacent rule merging; defaults to `on`'); - console.log(' %> # `mergeSemantically` controls semantic merging; defaults to `off`'); - console.log(' %> # `overrideProperties` controls property overriding based on understandability; defaults to `on`'); - console.log(' %> # `reduceNonAdjacentRules` controls non-adjacent rule reducing; defaults to `on`'); - console.log(' %> # `removeDuplicateFontRules` controls duplicate `@font-face` removing; defaults to `on`'); - console.log(' %> # `removeDuplicateMediaBlocks` controls duplicate `@media` removing; defaults to `on`'); - console.log(' %> # `removeDuplicateRules` controls duplicate rules removing; defaults to `on`'); - console.log(' %> # `removeEmpty` controls removing empty rules and nested blocks; defaults to `on` (since 4.1.0)'); - console.log(' %> # `removeUnusedAtRules` controls unused at rule removing; defaults to `off` (since 4.1.0)'); - console.log(' %> # `restructureRules` controls rule restructuring; defaults to `off`'); - console.log(' %> # `skipProperties` controls which properties won\'t be optimized, defaults to empty list which means all will be optimized (since 4.1.0)'); + console.log('Level 2 optimizations:'); + console.log(' %> cleancss -O2 one.css'); + console.log(' %> cleancss -O2 mergeMedia:off;restructureRules:off;mergeSemantically:on;mergeIntoShorthands:off one.css'); + console.log(' %> cleancss -O2 all:off;removeDuplicateRules:on one.css'); process.exit(); }); - commands.parse(process.argv); - - if (commands.rawArgs.indexOf('-O0') > -1) { - commands.O0 = true; - } - - if (commands.rawArgs.indexOf('-O1') > -1) { - commands.O1 = findArgumentTo('-O1', commands.rawArgs, commands.args); - } - - if (commands.rawArgs.indexOf('-O2') > -1) { - commands.O2 = findArgumentTo('-O2', commands.rawArgs, commands.args); - } + program.parse(process.argv); + inputOptions = program.opts(); // If no sensible data passed in just print help and exit - if (commands.args.length === 0) { + if (program.args.length === 0) { fromStdin = !process.env.__DIRECT__ && !process.stdin.isTTY; if (!fromStdin) { - commands.outputHelp(); + program.outputHelp(); return 0; } } - // Now coerce commands into CleanCSS configuration... - debugMode = commands.debug; - removeInlinedFiles = commands.removeInlinedFiles; - + // Now coerce arguments into CleanCSS configuration... options = { - compatibility: commands.compatibility, - format: commands.format, - inline: typeof commands.inline == 'string' ? commands.inline : 'local', - inlineTimeout: commands.inlineTimeout * 1000, - level: commands.O0 || commands.O1 || commands.O2 ? - { '0': commands.O0, '1': commands.O1, '2': commands.O2 } : - undefined, - output: commands.output, - rebase: commands.skipRebase ? false : true, - rebaseTo: ('output' in commands) && commands.output.length > 0 ? path.dirname(path.resolve(commands.output)) : process.cwd(), - sourceMap: commands.sourceMap, - sourceMapInlineSources: commands.sourceMapInlineSources + batch: inputOptions.batch, + compatibility: inputOptions.compatibility, + format: inputOptions.format, + inline: typeof inputOptions.inline == 'string' ? inputOptions.inline : 'local', + inlineTimeout: inputOptions.inlineTimeout * 1000, + level: { 1: true }, + output: inputOptions.output, + rebase: inputOptions.withRebase ? true : false, + rebaseTo: undefined, + sourceMap: inputOptions.sourceMap, + sourceMapInlineSources: inputOptions.sourceMapInlineSources }; - if (commands.inputSourceMap && !options.sourceMap) { + if (program.rawArgs.indexOf('-O0') > -1) { + options.level[0] = true; + options.level[1] = false; + } + + if (program.rawArgs.indexOf('-O1') > -1) { + options.level[1] = findArgumentTo('-O1', program.rawArgs, program.args); + } + + if (program.rawArgs.indexOf('-O2') > -1) { + options.level[2] = findArgumentTo('-O2', program.rawArgs, program.args); + } + + if (inputOptions.inputSourceMap && !options.sourceMap) { options.sourceMap = true; } - if (options.sourceMap && !options.output) { + if (options.sourceMap && !options.output && !options.batch) { outputFeedback(['Source maps will not be built because you have not specified an output file.'], true); options.sourceMap = false; } + if (options.output && options.batch) { + fs.mkdirSync(options.output, {recursive: true}); + } + + if (inputOptions.withRebase && ('output' in inputOptions) && inputOptions.output.length > 0) { + if (isDirectory(path.resolve(inputOptions.output))) { + options.rebaseTo = path.resolve(inputOptions.output); + } else { + options.rebaseTo = path.dirname(path.resolve(inputOptions.output)); + } + } else { + if (inputOptions.withRebase) { + options.rebaseTo = process.cwd(); + } + } + var configurations = { + batchSuffix: inputOptions.batchSuffix, beforeMinifyCallback: beforeMinifyCallback, - debugMode: debugMode, - removeInlinedFiles: removeInlinedFiles, - inputSourceMap: commands.inputSourceMap + debugMode: inputOptions.debug, + removeInlinedFiles: inputOptions.removeInlinedFiles, + inputSourceMap: inputOptions.inputSourceMap }; // ... and do the magic! - if (commands.args.length > 0) { - minify(process, options, configurations, expandGlobs(commands.args)); + if (program.args.length > 0) { + var expandedGlobs = expandGlobs(program.args); + if (inputOptions.watch) { + var inputPaths = expandedGlobs.map(function (path) { return path.expanded; }); + + minify(process, options, configurations, expandedGlobs); + require('chokidar').watch(inputPaths).on('change', function (pathToChangedFile) { + console.log(`File '${pathToChangedFile}' has changed. Rerunning all optimizations...`); + minify(process, options, configurations, expandedGlobs); + }); + } else { + minify(process, options, configurations, expandedGlobs); + } } else { stdin = process.openStdin(); stdin.setEncoding('utf-8'); @@ -191,6 +171,18 @@ function cli(process, beforeMinifyCallback) { } } +function isDirectory(path) { + try { + return fs.statSync(path).isDirectory(); + } catch (e) { + if (e.code == 'ENOENT') { + return false; + } else { + throw e; + } + } +} + function findArgumentTo(option, rawArgs, args) { var value = true; var optionAt = rawArgs.indexOf(option); @@ -220,52 +212,103 @@ function findArgumentTo(option, rawArgs, args) { } function expandGlobs(paths) { - return paths.reduce(function (accumulator, path) { - return accumulator.concat(glob.sync(path, { nodir: true, nonull: true})); + var globPatterns = paths.filter(function (path) { return path[0] != '!'; }); + var ignoredGlobPatterns = paths + .filter(function (path) { return path[0] == '!'; }) + .map(function (path) { return path.substring(1); }); + + return globPatterns.reduce(function (accumulator, path) { + var expandedWithSource = + glob.sync(path, { ignore: ignoredGlobPatterns, nodir: true, nonull: true }) + .map(function (expandedPath) { return { expanded: expandedPath, source: path }; }); + + return accumulator.concat(expandedWithSource); }, []); } function minify(process, options, configurations, data) { var cleanCss = new CleanCSS(options); + var input = typeof(data) == 'string' ? + data : + data.map(function (o) { return o.expanded; }); applyNonBooleanCompatibilityFlags(cleanCss, options.compatibility); configurations.beforeMinifyCallback(cleanCss); - cleanCss.minify(data, getSourceMapContent(configurations.inputSourceMap), function (errors, minified) { - var mapFilename; - - if (configurations.debugMode) { - console.error('Original: %d bytes', minified.stats.originalSize); - console.error('Minified: %d bytes', minified.stats.minifiedSize); - console.error('Efficiency: %d%', ~~(minified.stats.efficiency * 10000) / 100.0); - console.error('Time spent: %dms', minified.stats.timeSpent); - - if (minified.inlinedStylesheets.length > 0) { - console.error('Inlined stylesheets:'); - minified.inlinedStylesheets.forEach(function (uri) { - console.error('- %s', uri); - }); + cleanCss.minify(input, getSourceMapContent(configurations.inputSourceMap), function (errors, minified) { + var inputPath; + var outputPath; + + if (options.batch && !('styles' in minified)) { + for (inputPath in minified) { + outputPath = options.batch && options.output ? + toBatchOutputPath(inputPath, configurations.batchSuffix, options.output, data) : + toSimpleOutputPath(inputPath, configurations.batchSuffix); + + processMinified(process, configurations, minified[inputPath], inputPath, outputPath); } + } else { + processMinified(process, configurations, minified, null, options.output); } + }); +} - outputFeedback(minified.errors, true); - outputFeedback(minified.warnings); +function toSimpleOutputPath(inputPath, batchSuffix) { + var extensionName = path.extname(inputPath); - if (minified.errors.length > 0) { - process.exit(1); - } + return inputPath.replace(new RegExp(extensionName + '$'), batchSuffix + extensionName); +} + +function toBatchOutputPath(inputPath, batchSuffix, output, expandedWithSource) { + var extensionName = path.extname(inputPath); + var inputSource = expandedWithSource.find(function (ic) { return ic.expanded == inputPath; }).source; + var inputSourceRoot = inputSource.indexOf('*') > -1 ? + inputSource.substring(0, inputSource.indexOf('*')) : + path.dirname(inputSource); + + return path.join(output, inputPath.replace(inputSourceRoot, '').replace(new RegExp(extensionName + '$'), batchSuffix + extensionName)); +} + +function processMinified(process, configurations, minified, inputPath, outputPath) { + var mapOutputPath; - if (configurations.removeInlinedFiles) { - minified.inlinedStylesheets.forEach(fs.unlinkSync); + if (configurations.debugMode) { + if (inputPath) { + console.error('File: %s', inputPath); } - if (minified.sourceMap) { - mapFilename = path.basename(options.output) + '.map'; - output(process, options, minified.styles + lineBreak + '/*# sourceMappingURL=' + mapFilename + ' */'); - outputMap(options, minified.sourceMap, mapFilename); - } else { - output(process, options, minified.styles); + console.error('Original: %d bytes', minified.stats.originalSize); + console.error('Minified: %d bytes', minified.stats.minifiedSize); + console.error('Efficiency: %d%', ~~(minified.stats.efficiency * 10000) / 100.0); + console.error('Time spent: %dms', minified.stats.timeSpent); + + if (minified.inlinedStylesheets.length > 0) { + console.error('Inlined stylesheets:'); + minified.inlinedStylesheets.forEach(function (uri) { + console.error('- %s', uri); + }); } - }); + + console.error(''); + } + + outputFeedback(minified.errors, true); + outputFeedback(minified.warnings); + + if (minified.errors.length > 0) { + process.exit(1); + } + + if (configurations.removeInlinedFiles) { + minified.inlinedStylesheets.forEach(fs.unlinkSync); + } + + if (minified.sourceMap) { + mapOutputPath = outputPath + '.map'; + output(process, outputPath, minified.styles + lineBreak + '/*# sourceMappingURL=' + path.basename(mapOutputPath) + ' */'); + outputMap(mapOutputPath, minified.sourceMap); + } else { + output(process, outputPath, minified.styles); + } } function applyNonBooleanCompatibilityFlags(cleanCss, compatibility) { @@ -318,17 +361,17 @@ function getSourceMapContent(sourceMapPath) { return content; } -function output(process, options, minified) { - if (options.output) { - fs.writeFileSync(options.output, minified, 'utf8'); +function output(process, outputPath, minified) { + if (outputPath) { + fs.mkdirSync(path.dirname(outputPath), {recursive: true}); + fs.writeFileSync(outputPath, minified, 'utf8'); } else { process.stdout.write(minified); } } -function outputMap(options, sourceMap, mapFilename) { - var mapPath = path.join(path.dirname(options.output), mapFilename); - fs.writeFileSync(mapPath, sourceMap.toString(), 'utf-8'); +function outputMap(mapOutputPath, sourceMap) { + fs.writeFileSync(mapOutputPath, sourceMap.toString(), 'utf-8'); } module.exports = cli; diff --git a/package-lock.json b/package-lock.json index 727be62..f06ecb2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,28 @@ { "name": "clean-css-cli", - "version": "4.3.0", + "version": "5.6.3", "lockfileVersion": 1, "requires": true, "dependencies": { + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -18,10 +32,33 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, "clean-css": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", - "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz", + "integrity": "sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==", "requires": { "source-map": "~0.6.0" }, @@ -44,9 +81,9 @@ } }, "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.0.0.tgz", + "integrity": "sha512-ovx/7NkTrnPuIV8sqk/GjUIIM1+iUQeqA3ye2VNpq9sVoiZsooObWlQy+OPWGI17GDaEoybuAGJm6U8yC077BA==" }, "concat-map": { "version": "0.0.1", @@ -63,9 +100,9 @@ } }, "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, "date-now": { @@ -74,35 +111,32 @@ "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", "dev": true }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, "diff": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/diff/-/diff-1.0.8.tgz", - "integrity": "sha1-NDJ2MI7Jkbe8giZ+1VvBQR+XFmY=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, "dom-serializer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", - "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", "dev": true, "requires": { - "domelementtype": "^1.3.0", - "entities": "^1.1.1" + "domelementtype": "^2.0.1", + "entities": "^2.0.0" }, "dependencies": { + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "dev": true + }, "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true } } @@ -139,9 +173,9 @@ "dev": true }, "eventemitter3": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", - "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true }, "exit": { @@ -156,24 +190,35 @@ "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=", "dev": true }, - "follow-redirects": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz", - "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==", - "dev": true, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "requires": { - "debug": "^3.2.6" + "to-regex-range": "^5.0.1" } }, + "follow-redirects": { + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", + "dev": true + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -183,6 +228,14 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, "htmlparser2": { "version": "3.8.3", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", @@ -197,12 +250,12 @@ } }, "http-proxy": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", - "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, "requires": { - "eventemitter3": "^3.0.0", + "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", "requires-port": "^1.0.0" } @@ -221,6 +274,32 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", @@ -228,40 +307,49 @@ "dev": true }, "jshint": { - "version": "2.10.2", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.10.2.tgz", - "integrity": "sha512-e7KZgCSXMJxznE/4WULzybCMNXNAd/bf5TSrvVEq78Q/K8ZwFpmBqQeDtNiHc3l49nV4E/+YeHU/JZjSUIrLAA==", + "version": "2.13.4", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.13.4.tgz", + "integrity": "sha512-HO3bosL84b2qWqI0q+kpT/OpRJwo0R4ivgmxaO848+bo10rc50SkPnrtwSFXttW0ym4np8jbJvLwk5NziB7jIw==", "dev": true, "requires": { "cli": "~1.0.0", "console-browserify": "1.1.x", "exit": "0.1.x", "htmlparser2": "3.8.x", - "lodash": "~4.17.11", + "lodash": "~4.17.21", "minimatch": "~3.0.2", - "shelljs": "0.3.x", "strip-json-comments": "1.0.x" + }, + "dependencies": { + "minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "requires": { "brace-expansion": "^1.1.7" } }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "once": { "version": "1.4.0", @@ -276,6 +364,11 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" + }, "readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", @@ -288,18 +381,20 @@ "string_decoder": "~0.10.x" } }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, - "shelljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", - "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", - "dev": true - }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -318,13 +413,21 @@ "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", "dev": true }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, "vows": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/vows/-/vows-0.8.2.tgz", - "integrity": "sha1-aR95qybM3oC6cm3en+yOc9a88us=", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/vows/-/vows-0.8.3.tgz", + "integrity": "sha512-PVIxa/ovXhrw5gA3mz6M+ZF3PHlqX4tutR2p/y9NWPAaFVKcWBE8b2ktfr0opQM/qFmcOVWKjSCJVjnYOvjXhw==", "dev": true, "requires": { - "diff": "~1.0.8", + "diff": "^4.0.1", "eyes": "~0.1.6", "glob": "^7.1.2" } diff --git a/package.json b/package.json index 6b0b58b..43f5572 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "clean-css-cli", - "version": "4.3.0", + "version": "5.6.3", "description": "A command-line interface to clean-css CSS optimization library", "scripts": { "check": "jshint ./bin/cleancss .", @@ -9,7 +9,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/jakubpawlowicz/clean-css-cli.git" + "url": "git+https://github.com/clean-css/clean-css-cli.git" }, "keywords": [ "css", @@ -19,31 +19,33 @@ "bin": { "cleancss": "./bin/cleancss" }, - "author": "Jakub Pawlowicz (http://twitter.com/jakubpawlowicz)", + "author": "Jakub Pawlowicz ", "license": "MIT", "bugs": { - "url": "https://github.com/jakubpawlowicz/clean-css-cli/issues" + "url": "https://github.com/clean-css/clean-css-cli/issues" }, "main": "index.js", "files": [ "bin", "History.md", "index.js", - "LICENSE" + "LICENSE", + "README.md" ], - "homepage": "https://github.com/jakubpawlowicz/clean-css-cli#readme", + "homepage": "https://github.com/clean-css/clean-css-cli#readme", "dependencies": { - "clean-css": "^4.2.1", - "commander": "2.x", - "glob": "7.x" + "chokidar": "^3.5.2", + "clean-css": "^5.3.3", + "commander": "7.x", + "glob": "^7.1.6" }, "devDependencies": { "http-proxy": "1.x", - "jshint": "2.x", + "jshint": "^2.13.0", "source-map": "0.5.x", - "vows": "0.8.x" + "vows": "^0.8.3" }, "engines": { - "node": ">= 4.0" + "node": ">= 10.12.0" } } diff --git a/test/binary-test.js b/test/binary-test.js index bdcf10e..d9848e2 100644 --- a/test/binary-test.js +++ b/test/binary-test.js @@ -1,5 +1,6 @@ var assert = require('assert'); var exec = require('child_process').exec; +var execSync = require('child_process').execSync; var fs = require('fs'); var http = require('http'); var path = require('path'); @@ -12,6 +13,9 @@ var vows = require('vows'); function binaryContext(options, context) { context.topic = function () { + (context.setup || Function.prototype)(); + delete context.setup; + // We add __DIRECT__=1 to force binary into 'non-piped' mode exec('__DIRECT__=1 ./bin/cleancss ' + options, this.callback); }; @@ -152,6 +156,13 @@ vows.describe('cleancss') } }) }) + .addBatch({ + 'level 0 optimizations': pipedContext('a{color:#ff0000;margin:0 0 0 0}', '-O0', { + 'should skip all optimizations': function (error, stdout) { + assert.equal(stdout, 'a{color:#ff0000;margin:0 0 0 0}'); + } + }) + }) .addBatch({ 'enable restructuring optimizations': pipedContext('div{margin-top:0}.one{margin:0}.two{display:block;margin-top:0}', '-O2 restructureRules:on', { 'should do basic optimizations only': function (error, stdout) { @@ -196,6 +207,15 @@ vows.describe('cleancss') teardown: function () { deleteFile('./reset1-min.css'); } + }), + 'to file when target path does not exist': binaryContext('-o ./test/fixtures-temp/reset-min.css ./test/fixtures/reset.css', { + 'should create a directory and optimized file': function () { + assert.isTrue(fs.existsSync('test/fixtures-temp')); + assert.isTrue(fs.existsSync('test/fixtures-temp/reset-min.css')); + }, + teardown: function () { + exec('rm -rf test/fixtures-temp'); + } }) }) .addBatch({ @@ -236,10 +256,10 @@ vows.describe('cleancss') 'relative image paths': { 'no output': binaryContext('./test/fixtures/partials-relative/base.css', { 'should leave paths': function (error, stdout) { - assert.equal(stdout, 'a{background:url(test/fixtures/partials/extra/down.gif) 0 0 no-repeat}'); + assert.equal(stdout, 'a{background:url(../partials/extra/down.gif) 0 0 no-repeat}'); } }), - 'output': binaryContext('-o ./base1-min.css ./test/fixtures/partials-relative/base.css', { + 'output': binaryContext('--with-rebase -o ./base1-min.css ./test/fixtures/partials-relative/base.css', { 'should rewrite path relative to current path': function () { var minimized = fs.readFileSync('./base1-min.css', 'utf-8'); assert.equal(minimized, 'a{background:url(test/fixtures/partials/extra/down.gif) 0 0 no-repeat}'); @@ -269,14 +289,14 @@ vows.describe('cleancss') }) .addBatch({ 'complex import and url rebasing': { - 'absolute': binaryContext('./test/fixtures/rebasing/assets/ui.css', { + 'absolute': binaryContext('--with-rebase ./test/fixtures/rebasing/assets/ui.css', { 'should rebase urls correctly': function (error, stdout) { assert.include(stdout, 'url(test/fixtures/rebasing/components/bootstrap/images/glyphs.gif)'); assert.include(stdout, 'url(test/fixtures/rebasing/components/jquery-ui/images/prev.gif)'); assert.include(stdout, 'url(test/fixtures/rebasing/components/jquery-ui/images/next.gif)'); } }), - 'relative': binaryContext('-o test/ui.bundled.css ./test/fixtures/rebasing/assets/ui.css', { + 'relative': binaryContext('--with-rebase -o test/ui.bundled.css ./test/fixtures/rebasing/assets/ui.css', { 'should rebase urls correctly': function () { var minimized = fs.readFileSync('test/ui.bundled.css', 'utf-8'); assert.include(minimized, 'url(fixtures/rebasing/components/bootstrap/images/glyphs.gif)'); @@ -291,14 +311,28 @@ vows.describe('cleancss') }) .addBatch({ 'complex import and skipped url rebasing': { - 'absolute': binaryContext('--skip-rebase ./test/fixtures/rebasing/assets/ui.css', { - 'should rebase urls correctly': function (error, stdout) { + 'absolute': binaryContext('./test/fixtures/rebasing/assets/ui.css', { + 'should not rebase urls': function (error, stdout) { assert.isNull(error); assert.include(stdout, 'url(../images/glyphs.gif)'); assert.include(stdout, 'url(../images/prev.gif)'); assert.include(stdout, 'url(../images/next.gif)'); } }) + }, + 'complex import, skipped url rebasing, and output file': { + 'absolute': binaryContext('-o ./test/ui-no-rebase.min.css ./test/fixtures/rebasing/assets/ui.css', { + 'should not rebase urls': function () { + var minimized = fs.readFileSync('./test/ui-no-rebase.min.css', 'utf-8'); + + assert.include(minimized, 'url(../images/glyphs.gif)'); + assert.include(minimized, 'url(../images/prev.gif)'); + assert.include(minimized, 'url(../images/next.gif)'); + }, + teardown: function () { + deleteFile('test/ui-no-rebase.min.css'); + } + }) } }) .addBatch({ @@ -416,7 +450,7 @@ vows.describe('cleancss') }), 'custom': pipedContext('div{width:0.00051px}', '-O1 roundingPrecision:4', { 'should keep 4 decimal places': function (error, stdout) { - assert.equal(stdout, 'div{width:.0005px}'); + assert.equal(stdout, 'div{width:0.0005px}'); } }), 'zero': pipedContext('div{width:1.5051px}', '-O1 roundingPrecision:0', { @@ -536,7 +570,27 @@ vows.describe('cleancss') } }) .addBatch({ - 'source maps - output file with existing map': binaryContext('--source-map -o ./styles.min.css ./test/fixtures/source-maps/styles.css', { + 'source maps - output file with existing map and no rebasing': binaryContext('--source-map -o ./styles.min.css ./test/fixtures/source-maps/styles.css', { + 'includes right content in map file': function () { + var sourceMap = new SourceMapConsumer(fs.readFileSync('./styles.min.css.map', 'utf-8')); + assert.deepEqual( + sourceMap.originalPositionFor({ line: 1, column: 1 }), + { + source: 'test/fixtures/source-maps/styles.css', + line: 1, + column: 0, + name: null + } + ); + }, + 'teardown': function () { + deleteFile('styles.min.css'); + deleteFile('styles.min.css.map'); + } + }) + }) + .addBatch({ + 'source maps - output file with existing map': binaryContext('--source-map --with-rebase -o ./styles.min.css ./test/fixtures/source-maps/styles.css', { 'includes right content in map file': function () { var sourceMap = new SourceMapConsumer(fs.readFileSync('./styles.min.css.map', 'utf-8')); assert.deepEqual( @@ -556,7 +610,7 @@ vows.describe('cleancss') }) }) .addBatch({ - 'source maps - output file for existing map in different folder': binaryContext('--source-map -o ./styles-relative.min.css ./test/fixtures/source-maps/relative.css', { + 'source maps - output file for existing map in different folder': binaryContext('--source-map --with-rebase -o ./styles-relative.min.css ./test/fixtures/source-maps/relative.css', { 'includes right content in map file': function () { var sourceMap = new SourceMapConsumer(fs.readFileSync('./styles-relative.min.css.map', 'utf-8')); assert.deepEqual( @@ -654,15 +708,15 @@ vows.describe('cleancss') 'topic': function() { var self = this; - exec('cp test/fixtures/reset.css test/fixtures/reset-removing.css', function () { - exec('__DIRECT__=1 ./bin/cleancss test/fixtures/reset-removing.css', self.callback); + exec('cp test/fixtures/reset.css test/fixtures/reset-removing-1.css', function () { + exec('__DIRECT__=1 ./bin/cleancss test/fixtures/reset-removing-1.css', self.callback); }); }, 'keeps the file': function () { - assert.isTrue(fs.existsSync('test/fixtures/reset-removing.css')); + assert.isTrue(fs.existsSync('test/fixtures/reset-removing-1.css')); }, 'teardown': function () { - deleteFile('test/fixtures/reset-removing.css'); + deleteFile('test/fixtures/reset-removing-1.css'); } } }) @@ -671,12 +725,12 @@ vows.describe('cleancss') 'topic': function() { var self = this; - exec('cp test/fixtures/reset.css test/fixtures/reset-removing.css', function () { - exec('__DIRECT__=1 ./bin/cleancss --remove-inlined-files test/fixtures/reset-removing.css', self.callback); + exec('cp test/fixtures/reset.css test/fixtures/reset-removing-2.css', function () { + exec('__DIRECT__=1 ./bin/cleancss --remove-inlined-files test/fixtures/reset-removing-2.css', self.callback); }); }, 'removes the file': function () { - assert.isFalse(fs.existsSync('test/fixtures/reset-removing.css')); + assert.isFalse(fs.existsSync('test/fixtures/reset-removing-2.css')); } } }) @@ -685,12 +739,12 @@ vows.describe('cleancss') 'topic': function() { var self = this; - exec('cp test/fixtures/reset.css test/fixtures/reset-removing.css', function () { - exec('echo "@import \'test/fixtures/reset-removing.css\';" | ./bin/cleancss --remove-inlined-files', self.callback); + exec('cp test/fixtures/reset.css test/fixtures/reset-removing-3.css', function () { + exec('echo "@import \'test/fixtures/reset-removing-3.css\';" | ./bin/cleancss --remove-inlined-files', self.callback); }); }, 'removes the file': function () { - assert.isFalse(fs.existsSync('test/fixtures/reset-removing.css')); + assert.isFalse(fs.existsSync('test/fixtures/reset-removing-3.css')); } } }) @@ -719,7 +773,7 @@ vows.describe('cleancss') }) .addBatch({ 'content of input-source-map': pipedContext(fs.readFileSync('./test/fixtures/source-maps/map/styles.css'), '-o ./test/styles.min.css --input-source-map ./test/fixtures/source-maps/map/input.map', { - 'includes the right content of the source map': function() { + 'processes content normally': function() { assert.isTrue(fs.existsSync('test/styles.min.css.map')); var sourceMap = new SourceMapConsumer(fs.readFileSync('./test/styles.min.css.map', 'utf-8')); @@ -739,4 +793,187 @@ vows.describe('cleancss') } }) }) + .addBatch({ + 'batch processing in piped mode': pipedContext(fs.readFileSync('./test/fixtures/partials/one.css'), '-b', { + 'includes the right content of the source map': function (error, stdout) { + assert.equal(stdout, '.one{color:red}'); + } + }), + 'batch processing with explicitely given paths': binaryContext('-b ./test/fixtures-batch-1/partials/one.css ./test/fixtures-batch-1/partials/five.css', { + 'setup': function () { + execSync('cp -fr test/fixtures test/fixtures-batch-1'); + }, + 'creates two separate minified files': function () { + assert.isTrue(fs.existsSync('test/fixtures-batch-1/partials/one-min.css')); + assert.isFalse(fs.existsSync('test/fixtures-batch-1/partials/two-min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-1/partials/five-min.css')); + }, + 'teardown': function () { + execSync('rm -fr test/fixtures-batch-1'); + } + }) + }) + .addBatch({ + 'batch processing with wildard paths': binaryContext('-b ./test/fixtures-batch-2/partials/\\*\\*/*.css', { + 'setup': function () { + execSync('cp -fr test/fixtures test/fixtures-batch-2'); + }, + 'creates two separate minified files': function () { + assert.isTrue(fs.existsSync('test/fixtures-batch-2/partials/extra/four-min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-2/partials/extra/three-min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-2/partials/one-min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-2/partials/two-min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-2/partials/quoted-svg-min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-2/partials/five-min.css')); + }, + 'teardown': function () { + execSync('rm -fr test/fixtures-batch-2'); + } + }) + }) + .addBatch({ + 'batch processing with custom suffix': binaryContext('--batch --batch-suffix \'.min\' ./test/fixtures-batch-3/partials/one.css ./test/fixtures-batch-3/partials/five.css', { + 'setup': function () { + execSync('cp -fr test/fixtures test/fixtures-batch-3'); + }, + 'creates two separate minified files': function () { + assert.isFalse(fs.existsSync('test/fixtures-batch-3/partials/one-min.css')); + assert.isFalse(fs.existsSync('test/fixtures-batch-3/partials/two-min.css')); + assert.isFalse(fs.existsSync('test/fixtures-batch-3/partials/five-min.css')); + + assert.isTrue(fs.existsSync('test/fixtures-batch-3/partials/one.min.css')); + assert.isFalse(fs.existsSync('test/fixtures-batch-3/partials/two.min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-3/partials/five.min.css')); + }, + 'teardown': function () { + execSync('rm -fr test/fixtures-batch-3'); + } + }) + }) + .addBatch({ + 'batch processing with output given': binaryContext('-b -o ./test/fixtures-batch-4-output ./test/fixtures-batch-4/partials/one.css ./test/fixtures-batch-4/partials/five.css', { + 'setup': function () { + execSync('cp -fr test/fixtures test/fixtures-batch-4'); + }, + 'does not produce any errors': function (error) { + assert.equal(error, ''); + }, + 'creates two separate minified files': function () { + assert.isFalse(fs.existsSync('test/fixtures-batch-4/partials/one-min.css')); + assert.isFalse(fs.existsSync('test/fixtures-batch-4/partials/two-min.css')); + assert.isFalse(fs.existsSync('test/fixtures-batch-4/partials/five-min.css')); + + assert.isTrue(fs.existsSync('test/fixtures-batch-4-output/one-min.css')); + assert.isFalse(fs.existsSync('test/fixtures-batch-4-output/two-min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-4-output/five-min.css')); + }, + 'teardown': function () { + execSync('rm -fr test/fixtures-batch-4'); + execSync('rm -fr test/fixtures-batch-4-output'); + } + }) + }) + .addBatch({ + 'batch processing with wildcard and exclude paths': binaryContext('-b ./test/fixtures-batch-5/partials/\\*\\*/*.css !./test/fixtures-batch-5/partials/one* !./test/fixtures-batch-5/partials/fiv?.css', { + 'setup': function () { + execSync('cp -fr test/fixtures test/fixtures-batch-5'); + }, + 'creates two separate minified files': function () { + assert.isTrue(fs.existsSync('test/fixtures-batch-5/partials/extra/four-min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-5/partials/extra/three-min.css')); + assert.isFalse(fs.existsSync('test/fixtures-batch-5/partials/one-min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-5/partials/two-min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-5/partials/quoted-svg-min.css')); + assert.isFalse(fs.existsSync('test/fixtures-batch-5/partials/five-min.css')); + }, + 'teardown': function () { + execSync('rm -fr test/fixtures-batch-5'); + } + }) + }) + .addBatch({ + 'batch processing with output as a path': binaryContext('-b ./test/fixtures-batch-6/partials/\\*\\*/*.css -o test/fixtures-batch-6-output', { + 'setup': function () { + execSync('cp -fr test/fixtures test/fixtures-batch-6'); + }, + 'creates two separate minified files': function () { + assert.isTrue(fs.existsSync('test/fixtures-batch-6-output/extra/four-min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-6-output/extra/three-min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-6-output/one-min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-6-output/two-min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-6-output/quoted-svg-min.css')); + assert.isTrue(fs.existsSync('test/fixtures-batch-6-output/five-min.css')); + }, + 'teardown': function () { + execSync('rm -fr test/fixtures-batch-6'); + execSync('rm -fr test/fixtures-batch-6-output'); + } + }) + }) + .addBatch({ + 'batch processing with source maps': binaryContext('-b ./test/fixtures-batch-7/partials/\\*\\*/*.css --source-map', { + 'setup': function () { + execSync('cp -fr test/fixtures test/fixtures-batch-7'); + execSync('rm -fr test/fixtures-batch-7/partials/extra/four.css'); + execSync('touch test/fixtures-batch-7/partials/extra/four.css'); + }, + 'does not raise an error': function (error, stdout, stderr) { + assert.equal(stderr, ''); + }, + 'creates source map files': function () { + assert.isTrue(fs.existsSync('test/fixtures-batch-7/partials/extra/three-min.css.map')); + assert.isTrue(fs.existsSync('test/fixtures-batch-7/partials/one-min.css.map')); + assert.isTrue(fs.existsSync('test/fixtures-batch-7/partials/two-min.css.map')); + assert.isTrue(fs.existsSync('test/fixtures-batch-7/partials/quoted-svg-min.css.map')); + assert.isTrue(fs.existsSync('test/fixtures-batch-7/partials/five-min.css.map')); + }, + 'teardown': function () { + execSync('rm -fr test/fixtures-batch-7'); + } + }) + }) + .addBatch({ + 'batch processing with source maps and output as a path': binaryContext('-b ./test/fixtures-batch-8/partials/\\*\\*/*.css --source-map -o test/fixtures-batch-8-output', { + 'setup': function () { + execSync('cp -fr test/fixtures test/fixtures-batch-8'); + execSync('rm -fr test/fixtures-batch-8/partials/extra/four.css'); + execSync('touch test/fixtures-batch-8/partials/extra/four.css'); + }, + 'does not raise an error': function (error, stdout, stderr) { + assert.equal(stderr, ''); + }, + 'creates source map files': function () { + assert.isTrue(fs.existsSync('test/fixtures-batch-8-output/extra/three-min.css.map')); + assert.isTrue(fs.existsSync('test/fixtures-batch-8-output/one-min.css.map')); + assert.isTrue(fs.existsSync('test/fixtures-batch-8-output/two-min.css.map')); + assert.isTrue(fs.existsSync('test/fixtures-batch-8-output/quoted-svg-min.css.map')); + assert.isTrue(fs.existsSync('test/fixtures-batch-8-output/five-min.css.map')); + }, + 'teardown': function () { + execSync('rm -fr test/fixtures-batch-8'); + execSync('rm -fr test/fixtures-batch-8-output'); + } + }) + }) + .addBatch({ + 'batch processing with source maps, rebase and output as a path': binaryContext('-b ./test/fixtures-batch-9/partials-relative/\\*\\*/included.css --source-map --with-rebase -o test/fixtures-batch-9-output', { + 'setup': function () { + execSync('cp -fr test/fixtures test/fixtures-batch-9'); + }, + 'does not raise an error': function (error, stdout, stderr) { + assert.equal(stderr, ''); + }, + 'rebases output correctly': function () { + var minimized = fs.readFileSync('./test/fixtures-batch-9-output/extra/included-min.css', 'utf-8'); + assert.equal(minimized, 'a{background:url(../fixtures-batch-9/partials/extra/down.gif) 0 0 no-repeat}\n/*# sourceMappingURL=included-min.css.map */'); + }, + 'creates source map files': function () { + assert.isTrue(fs.existsSync('test/fixtures-batch-9-output/extra/included-min.css.map')); + }, + 'teardown': function () { + execSync('rm -fr test/fixtures-batch-9'); + execSync('rm -fr test/fixtures-batch-9-output'); + } + }) + }) .export(module); diff --git a/test/custom-cli/custom-cleancss b/test/custom-cli/custom-cleancss index 106a455..3de31ef 100755 --- a/test/custom-cli/custom-cleancss +++ b/test/custom-cli/custom-cleancss @@ -1,10 +1,19 @@ #!/usr/bin/env node var cleanCssCli = require('../../index'); -return cleanCssCli(process, function (cleanCss) { - cleanCss.options.level['1'].transform = function (propertyName, propertyValue) { - if (propertyName == 'background-image' && propertyValue.indexOf('../valid/path/to') == -1) { - return propertyValue.replace('url(', 'url(../valid/path/to/'); + +var customPlugin = { + level1: { + value: function (propertyName, propertyValue, options) { + if (propertyName == 'background-image' && propertyValue.indexOf('../valid/path/to') == -1) { + return propertyValue.replace('url(', 'url(../valid/path/to/'); + } else { + return propertyValue; + } } } +} + +return cleanCssCli(process, function (cleanCss) { + cleanCss.options.plugins.level1Value.push(customPlugin.level1.value); }); diff --git a/test/fixtures/unsupported/selectors-ie7.css b/test/fixtures/unsupported/selectors-ie7.css index 3f2fc3e..d43708e 100644 --- a/test/fixtures/unsupported/selectors-ie7.css +++ b/test/fixtures/unsupported/selectors-ie7.css @@ -2,15 +2,15 @@ p:focus{top:0} p:before{top:0} p:after{top:0} p:root{top:0} -p:nth-of-type(1){top:0} -p:nth-last-of-type(1){top:0} +p:first-of-type{top:0} +p:last-of-type{top:0} p:first-of-type{top:0} p:last-of-type{top:0} p:only-of-type{top:0} p:only-child{top:0} p:last-child{top:0} -p:nth-child(1){top:0} -p:nth-last-child(1){top:0} +p:first-child{top:0} +p:last-child{top:0} p:empty{top:0} p:target{top:0} p:checked{top:0} diff --git a/test/fixtures/unsupported/selectors-ie8.css b/test/fixtures/unsupported/selectors-ie8.css index 2d01251..fb8a104 100644 --- a/test/fixtures/unsupported/selectors-ie8.css +++ b/test/fixtures/unsupported/selectors-ie8.css @@ -1,13 +1,13 @@ p:root{top:0} -p:nth-of-type(1){top:0} -p:nth-last-of-type(1){top:0} +p:first-of-type{top:0} +p:last-of-type{top:0} p:first-of-type{top:0} p:last-of-type{top:0} p:only-of-type{top:0} p:only-child{top:0} p:last-child{top:0} -p:nth-child(1){top:0} -p:nth-last-child(1){top:0} +p:first-child{top:0} +p:last-child{top:0} p:empty{top:0} p:target{top:0} p:checked{top:0}