pax_global_header00006660000000000000000000000064143414706410014516gustar00rootroot0000000000000052 comment=a3574b1f67e4d8c1a78b6b72b501354f545c34d2 postcss-cli-10.1.0/000077500000000000000000000000001434147064100140405ustar00rootroot00000000000000postcss-cli-10.1.0/.eslintrc.yaml000066400000000000000000000001411434147064100166210ustar00rootroot00000000000000env: node: true parserOptions: sourceType: module extends: problems rules: no-console: off postcss-cli-10.1.0/.github/000077500000000000000000000000001434147064100154005ustar00rootroot00000000000000postcss-cli-10.1.0/.github/workflows/000077500000000000000000000000001434147064100174355ustar00rootroot00000000000000postcss-cli-10.1.0/.github/workflows/ci.yml000066400000000000000000000007371434147064100205620ustar00rootroot00000000000000name: Node.js CI on: push: branches: master pull_request: jobs: test: strategy: matrix: node: [14, 16, 18] os: [ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - run: git config --global core.autocrlf input - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - run: npm install - run: npm run ci postcss-cli-10.1.0/.gitignore000066400000000000000000000013171434147064100160320ustar00rootroot00000000000000# Test artifacts .tmp # Logs logs *.log npm-debug.log* # Runtime data pids *.pid *.seed *.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # node-waf configuration .lock-wscript # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules jspm_packages # Optional npm cache directory .npm # Optional eslint cache .eslintcache # Optional REPL history .node_repl_history # Output of 'npm pack' *.tgz # Yarn Integrity file .yarn-integrity postcss-cli-10.1.0/.npmrc000066400000000000000000000000231434147064100151530ustar00rootroot00000000000000package-lock=false postcss-cli-10.1.0/.prettierignore000066400000000000000000000000061434147064100170770ustar00rootroot00000000000000.tmp/ postcss-cli-10.1.0/CHANGELOG.md000066400000000000000000000274451434147064100156650ustar00rootroot00000000000000# 10.1.0 / 2022-11-29 - Allow running `--watch` mode in non-TTY contexts, like Docker ([#448](https://github.com/postcss/postcss-cli/pull/448)) - Update dependencies # 10.0.0 / 2022-06-29 - **BREAKING:** Drop Node 12 support ([#438](https://github.com/postcss/postcss-cli/pull/438)) - Add support for ESM config files ([#437](https://github.com/postcss/postcss-cli/pull/437)) # 9.1.0 / 2021-12-10 - Don't write to files if they're unchanged ([#320](https://github.com/postcss/postcss-cli/issues/320), [#417](https://github.com/postcss/postcss-cli/pull/417)) # 9.0.2 / 2021-11-04 - Switch to picocolors ([#409](https://github.com/postcss/postcss-cli/pull/409)) - Remove test files from npm package # 9.0.1 / 2021-09-28 - Actually exit with error when attempting to stdout in watch mode - Remove `bin/` from `files` in package.json # 9.0.0 / 2021-09-24 - **BREAKING:** Require Node.js v12+ - **BREAKING:** Must specify full file path, including `.js` extension, when loading local plugins with `--use` ([#401](https://github.com/postcss/postcss-cli/pull/401)) - **BREAKING:** Officially remove support for watching postcss config (was already broken in previous releases) - Add support for `dir-dependency` messages ([#383](https://github.com/postcss/postcss-cli/pull/383), [#391](https://github.com/postcss/postcss-cli/pull/391)) - Update deps # 8.3.1 / 2020-12-12 - Ensure paths are not interpreted as numbers ([#360](https://github.com/postcss/postcss-cli/issues/360)) - Better errors for incorrect postcss version ([#361](https://github.com/postcss/postcss-cli/issues/361), [#362](https://github.com/postcss/postcss-cli/pull/362)) # 8.3.0 / 2020-11-17 - Exit on EOF/`^D` ([#358](https://github.com/postcss/postcss-cli/pull/358)) # 8.2.0 / 2020-10-29 - Allow backslashes in paths for better Windows experence ([#355](https://github.com/postcss/postcss-cli/pull/355)) # 8.1.0 / 2020-10-08 - Add support for `postcss.config.cjs` files ([#351](https://github.com/postcss/postcss-cli/pull/351)) # 8.0.0 / 2020-09-21 - **BREAKING:** Support postcss v8 ([#344](https://github.com/postcss/postcss-cli/issues/344), [#349](https://github.com/postcss/postcss-cli/pull/349)) - **BREAKING:** postcss is now a `peerDependency`, you must install it seperately ([#344](https://github.com/postcss/postcss-cli/issues/344), [#349](https://github.com/postcss/postcss-cli/pull/349)) - Upgrade dependencies ([#340](https://github.com/postcss/postcss-cli/pull/340)) # 7.1.2 / 2020-08-31 - Make `--version` machine-readable ([#334](https://github.com/postcss/postcss-cli/issues/334), [#335](https://github.com/postcss/postcss-cli/pull/335)) - Organize and clarify `--help` text ([#336](https://github.com/postcss/postcss-cli/pull/336)) - Update dependencies # 7.1.1 / 2020-04-27 - Fix bug where external source maps were not properly generated ([#324](https://github.com/postcss/postcss-cli/pull/324)) - Update dependencies # 7.1.0 / 2020-01-09 - Respect `map.annotation` option when set to a string ([#307](https://github.com/postcss/postcss-cli/pull/307)) # 7.0.0 / 2020-01-07 - **BREAKING:** Drop support for Node 6 & 8 - Update `globby`, which may be a breaking change for a small number of users using certain glob patterns, see https://github.com/mrmlnc/fast-glob#pattern-syntax for details ([#303](https://github.com/postcss/postcss-cli/pull/303)) - Update dependencies # 6.1.3 / 2019-07-08 - Fix external sorcemap filenames when the directory name contains `.css` ([#283](https://github.com/postcss/postcss-cli/issues/283), [#286](https://github.com/postcss/postcss-cli/pull/286)) # 6.1.2 / 2019-02-22 - Upgrade dependency globby to fix bug in sub-dependency ([#265](https://github.com/postcss/postcss-cli/issues/265), [#270](https://github.com/postcss/postcss-cli/pull/270)) # 6.1.1 / 2019-01-04 - Fix empty lines being printed in some cases ([#256](https://github.com/postcss/postcss-cli/issues/256), [#257](https://github.com/postcss/postcss-cli/pull/257)) # 6.1.0 / 2018-12-19 - Add `--include-dotfiles` flag to allow globs to match dotfiles. ([#254](https://github.com/postcss/postcss-cli/pull/254)) - Only log warning messages. This has always been intended behavior, but it wasn't working as expected. ([#244](https://github.com/postcss/postcss-cli/pull/244)) # 6.0.1 / 2018-10-17 - Better error handling for errors thrown by plugins ([#242](https://github.com/postcss/postcss-cli/issues/242), [#243](https://github.com/postcss/postcss-cli/pull/243)) - Update dependencies - Clarify docs ([#233](https://github.com/postcss/postcss-cli/issues/233)) # 6.0.0 / 2018-07-18 - Drop support for Node 4 - Upgrade to postcss v7 ([release notes](https://github.com/postcss/postcss/blob/master/CHANGELOG.md#70-president-amy)) - Upgrade to postcss-load-config v2 ([release notes](https://github.com/michael-ciniawsky/postcss-load-config/blob/master/CHANGELOG.md#200-2018-07-10)) # 5.0.1 / 2018-06-18 - Shallow copy options object; fixes a few edge cases - Adjust options for file watching to play better with some editors # 5.0.0 / 2018-02-06 - Now allows passing a directory as the input (all files in the directory will be processed) - The CLI is now silent by default; added `--verbose` flag for if you want noisy logs - Doesn't exit watch mode when there's an error in the plugin chain - Removed non-obvious shorthand arguments (`-x`, `-p`, `-s`, `-t`, `-e`, `-b`, & `-c`). Also removed `-v` as an alias for `--version`. - Prevent stupid option combinations like `--dir` & `-o`, and `--watch` & `--replace` - Doesn't allow `--watch` when writing to STDOUT # 4.1.1 / 2017-08-17 - Fixed bug with `--config` - Upgraded dependencies # 4.1.0 / 2017-06-10 - Can now pass a number to `--poll` to set poll interval - Updated `postcss-reporter` dependency to v4.0.0 # 4.0.0 / 2017-05-09 - **BREAKING:** Upgrade postcss to v6.x # 3.2.0 / 2017-04-21 - Added `--base` CLI option for keeping directory structure # 3.1.1 / 2017-04-04 - Fixed `files` property in `package.json`; `lib/` folder wasn't included in v3.1.0 # 3.1.0 / 2017-04-04 - Improved incremental rebuilds for better performance in watch mode. - Switched to `read-cache` for file reading for better performance. - Set a dummy filename when reading from stdin to help plugins like autoprefixer find config files. - Updated `fs-promise` dependency. # 3.0.0 / 2017-03-15 ## Changes since 3.0.0-beta ### Breaking Changes - Don't exit on `CssSyntaxError` in watch mode. v2 behaved this way, but v3.0.0-beta didn't. - Error out if `from` or `to` options are set in the config file. Use command line arguments instead. ### New Features - Add `--poll` option. v2 had this, however, this new implementation removes the capability to set the interval, which was supported in v2. ### Bugfixes - Set `from` option for correct sourcemaps - Fix `--watch`'s glob handling - Fix error handling ## Changes since v2.6.0 ### Breaking Changes - Uses https://github.com/michael-ciniawsky/postcss-load-config for config files. Dropped support for the v2 config file format. - Can't set input files in config file; pass input files on the command line instead. - `--use` accepts a list of plugins. This may cause issues if you have your list of css files at the end of your command. - Can't pass options to plugins via `--plugin.key=value` anymore, use a config file. - Changed usage of the `--map` option; use `--map` for external sourcemaps, `--no-map` to disable all maps. Inline sourcemaps are default. - Removed `--log` flag; this behavior is now default. - Removed the `--local-plugins` flag; same result can be achieved with `postcss.config.js`. - Removed the global `watchCSS` handler, plugins that import/rely on other files should use a `dependency` message instead. - Changed behavior of the `--poll` option; no longer accepts an integer `interval`. ### New Features - `--ext` (`-x`) option allows you to set the file extensions for your output files when using `--dir`. - `--env` allows you to set `NODE_ENV` in a cross-platform manner. Migration guide for upgrading from v2: https://github.com/postcss/postcss-cli/wiki/Migrating-from-v2-to-v3 # 3.0.0-beta / 2017-03-17 ## Breaking Changes - Uses https://github.com/michael-ciniawsky/postcss-load-config for config files. Dropped support for the v2 config file format. - Can't set input files in config file; pass input files on the command line instead. - `--use` accepts a list of plugins. This may cause issues if you have your list of css files at the end of your command. - Can't pass options to plugins via `--plugin.key=value` anymore, use a config file. - Changed usage of the `--map` option; use `--map` for external sourcemaps, `--no-map` to disable all maps. Inline sourcemaps are default. - Removed `--log` flag; this behavior is now default. - Removed the `--local-plugins` flag; same result can be achieved with `postcss.config.js`. - Removed the global `watchCSS` handler, plugins that import/rely on other files should use a `dependency` message instead. ## New Features - `--ext` (`-x`) option allows you to set the file extensions for your output files when using `--dir`. - `--env` allows you to set `NODE_ENV` in a cross-platform manner. Migration guide: https://github.com/postcss/postcss-cli/wiki/Migrating-from-v2-to-v3 # 2.6.0 / 2016-08-30 - Add log option - Update postcss-import to v8.1.2 from v7.1.0 - Update globby to v4.1.0 from v3.0.1 - Update postcss-url to v5.1.2 from v4.0.0 - Update jshint to v2.9.2 from v2.6.3 - Update chokidar to v1.5.1 from v1.0.3 - Update yargs to v4.7.1 from v3.32.0 - Support es6 export - Allow running without plugins - Add test for --poll - Add --poll flag # 2.5.2 / 2016-04-18 - Fix typo in help message: -use => [--use|-u] - npm install --save mkdirp - Support mkdirp to create dest path if it doesn't exists - Fix booleans in config file # 2.5.1 / 2016-02-11 - fix `input` argument # 2.5.0 / 2016-01-30 - move to postcss/postcss-cli repository - Update Readme.md # 2.4.1 / 2016-01-27 - improve warning disply format # 2.4.0 / 2016-01-15 - add support for source maps # 2.3.3 / 2015-12-28 - add usage example for `local-plugins` option in config file # 2.3.2 / 2015-10-27 - auto-configure postcss-import support - add support for watching multiple entry points # 2.3.1 / 2015-10-25 - update Travis config - upgrade postcss-import dependency - fix deprecation warnings during make test-watch # 2.3.0 / 2015-10-24 - add --local-plugins option that lets postcss-cli to look for plugins in current directory # 2.2.0 / 2015-10-09 - add support for --replace|-r - if used input files are replaced with generated output - refactor support for custom syntax options # 2.1.1 / 2015-10-08 - add globby to support wildcards in Windows - remove obsolete note on postcss-import compatibility # 2.1.0 / 2015-09-01 - add support for PostCSS 5.0 custom syntax options # 2.0.0 / 2015-08-24 - remove support for --safe option - switch to using postcss 5.x # 1.5.0 / 2015-07-20 - add watch mode (-w|--watch) in which postcss-cli observes and recompiles inputs whenever they change - update neo-async dependency to released version - update postcss-url dependency (used in tests only) # 1.4.0 / 2015-07-12 - allow specifying input file via config file - allow specifying -u|--use via config file # 1.3.1 / 2015-05-03 - update npm keyword: postcssrunner -> postcss-runner # 1.3.0 / 2015-04-28 - add support for stdin/stdout if no input/output file specified # 1.2.1 / 2015-04-20 - fix typo in readme # 1.2.0 / 2015-04-02 - display warnings and errors - stop testing on node 0.10 # 1.1.0 / 2015-03-28 - prefer postcss async API if available # 1.0.0 / 2015-03-22 - use official yargs version - add support for multiple input files # 0.3.0 / 2015-03-19 - support JS format as plugins config # 0.2.0 / 2015-03-13 - use autoprefixer instead of autoprefixer-core - change short options for --use from `p` to `u` - add -v|--version support - add --safe option to enable postcss safe mode # 0.1.0 / 2015-03-11 - initial implementaion postcss-cli-10.1.0/LICENSE000066400000000000000000000020641434147064100150470ustar00rootroot00000000000000License (MIT) Copyright (c) 2016 Michael Ciniawsky 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. postcss-cli-10.1.0/README.md000066400000000000000000000134461434147064100153270ustar00rootroot00000000000000[![npm][npm]][npm-url] [![node][node]][node-url] [![tests][tests]][tests-url] [![cover][cover]][cover-url] [![chat][chat]][chat-url]

PostCSS CLI

Install

```bash npm i -D postcss postcss-cli ```

Usage

``` Usage: postcss [input.css] [OPTIONS] [-o|--output output.css] [--watch|-w] postcss ... [OPTIONS] --dir [--watch|-w] postcss [OPTIONS] --dir [--watch|-w] postcss [OPTIONS] --dir [--watch|-w] postcss ... [OPTIONS] --replace Basic options: -o, --output Output file [string] -d, --dir Output directory [string] -r, --replace Replace (overwrite) the input file [boolean] -m, --map Create an external sourcemap --no-map Disable the default inline sourcemaps -w, --watch Watch files for changes and recompile as needed [boolean] --verbose Be verbose [boolean] --env A shortcut for setting NODE_ENV [string] Options for use without a config file: -u, --use List of postcss plugins to use [array] --parser Custom postcss parser [string] --stringifier Custom postcss stringifier [string] --syntax Custom postcss syntax [string] Options for use with --dir: --ext Override the output file extension; for use with --dir [string] --base Mirror the directory structure relative to this path in the output directory, for use with --dir [string] Advanced options: --include-dotfiles Enable glob to match files/dirs that begin with "." [boolean] --poll Use polling for file watching. Can optionally pass polling interval; default 100 ms --config Set a custom directory to look for a config file [string] Options: --version Show version number [boolean] -h, --help Show help [boolean] Examples: postcss input.css -o output.css Basic usage postcss src/**/*.css --base src --dir build Glob Pattern & output cat input.css | postcss -u autoprefixer > output.css Piping input & output If no input files are passed, it reads from stdin. If neither -o, --dir, or --replace is passed, it writes to stdout. If there are multiple input files, the --dir or --replace option must be passed. Input files may contain globs (e.g. src/**/*.css). If you pass an input directory, it will process all files in the directory and any subdirectories, respecting the glob pattern. ``` > ℹ️ More details on custom parsers, stringifiers and syntaxes, can be found [here](https://github.com/postcss/postcss#syntaxes). ### [Config](https://github.com/michael-ciniawsky/postcss-load-config) If you need to pass options to your plugins, or have a long plugin chain, you'll want to use a configuration file. **postcss.config.js** ```js module.exports = { parser: 'sugarss', plugins: [ require('postcss-import')({ ...options }), require('postcss-url')({ url: 'copy', useHash: true }), ], } ``` Note that you **can not** set the `from` or `to` options for postcss in the config file. They are set automatically based on the CLI arguments. ### Context For more advanced usage, it's recommended to use a function in `postcss.config.js`; this gives you access to the CLI context to dynamically apply options and plugins **per file** | Name | Type | Default | Description | | :-------: | :--------: | :--------------------------------: | :------------------- | | `env` | `{String}` | `'development'` | process.env.NODE_ENV | | `file` | `{Object}` | `dirname, basename, extname` | File | | `options` | `{Object}` | `map, parser, syntax, stringifier` | PostCSS Options | **postcss.config.js** ```js module.exports = (ctx) => ({ map: ctx.options.map, parser: ctx.file.extname === '.sss' ? 'sugarss' : false, plugins: { 'postcss-import': { root: ctx.file.dirname }, cssnano: ctx.env === 'production' ? {} : false, }, }) ``` > ⚠️ If you want to set options via CLI, it's mandatory to reference `ctx.options` in `postcss.config.js` ```bash postcss input.sss -p sugarss -o output.css -m ``` **postcss.config.js** ```js module.exports = (ctx) => ({ map: ctx.options.map, parser: ctx.options.parser, plugins: { 'postcss-import': { root: ctx.file.dirname }, cssnano: ctx.env === 'production' ? {} : false, }, }) ``` [npm]: https://img.shields.io/npm/v/postcss-cli.svg [npm-url]: https://npmjs.com/package/postcss-cli [node]: https://img.shields.io/node/v/postcss-cli.svg [node-url]: https://nodejs.org/ [tests]: https://img.shields.io/github/workflow/status/postcss/postcss-cli/Node.js%20CI/master [tests-url]: https://github.com/postcss/postcss-cli/actions?query=branch%3Amaster [cover]: https://img.shields.io/coveralls/postcss/postcss-cli/master.svg [cover-url]: https://coveralls.io/github/postcss/postcss-cli [chat]: https://img.shields.io/gitter/room/postcss/postcss.svg [chat-url]: https://gitter.im/postcss/postcss postcss-cli-10.1.0/index.js000077500000000000000000000221051434147064100155100ustar00rootroot00000000000000#!/usr/bin/env node import fs from 'fs-extra' import path from 'path' import prettyHrtime from 'pretty-hrtime' import stdin from 'get-stdin' import read from 'read-cache' import pc from 'picocolors' import { globby } from 'globby' import slash from 'slash' import chokidar from 'chokidar' import postcss from 'postcss' import postcssrc from 'postcss-load-config' import postcssReporter from 'postcss-reporter/lib/formatter.js' import argv from './lib/args.js' import createDependencyGraph from './lib/DependencyGraph.js' import getMapfile from './lib/getMapfile.js' const reporter = postcssReporter() const depGraph = createDependencyGraph() let input = argv._ const { dir, output } = argv if (argv.map) argv.map = { inline: false } let cliConfig async function buildCliConfig() { cliConfig = { options: { map: argv.map !== undefined ? argv.map : { inline: true }, parser: argv.parser ? await import(argv.parser) : undefined, syntax: argv.syntax ? await import(argv.syntax) : undefined, stringifier: argv.stringifier ? await import(argv.stringifier) : undefined, }, plugins: argv.use ? await Promise.all( argv.use.map(async (plugin) => { try { return (await import(plugin)).default() } catch (e) { const msg = e.message || `Cannot find module '${plugin}'` let prefix = msg.includes(plugin) ? '' : ` (${plugin})` if (e.name && e.name !== 'Error') prefix += `: ${e.name}` return error(`Plugin Error${prefix}: ${msg}'`) } }) ) : [], } } let configFile if (argv.env) process.env.NODE_ENV = argv.env if (argv.config) argv.config = path.resolve(argv.config) let { isTTY } = process.stdin if (process.env.FORCE_IS_TTY === 'true') { isTTY = true } if (argv.watch && isTTY) { process.stdin.on('end', () => process.exit(0)) process.stdin.resume() } /* istanbul ignore next */ if (parseInt(postcss().version) < 8) { error('Please install PostCSS 8 or above') } buildCliConfig() .then(() => { if (argv.watch && !(argv.output || argv.replace || argv.dir)) { error('Cannot write to stdout in watch mode') // Need to explicitly exit here, since error() doesn't exit in watch mode process.exit(1) } if (input && input.length) { return globby( input.map((i) => slash(String(i))), { dot: argv.includeDotfiles } ) } if (argv.replace || argv.dir) { error( 'Input Error: Cannot use --dir or --replace when reading from stdin' ) } if (argv.watch) { error('Input Error: Cannot run in watch mode when reading from stdin') } return ['stdin'] }) .then((i) => { if (!i || !i.length) { error('Input Error: You must pass a valid list of files to parse') } if (i.length > 1 && !argv.dir && !argv.replace) { error( 'Input Error: Must use --dir or --replace with multiple input files' ) } if (i[0] !== 'stdin') i = i.map((i) => path.resolve(i)) input = i return files(input) }) .then((results) => { if (argv.watch) { const printMessage = () => printVerbose(pc.dim('\nWaiting for file changes...')) const watcher = chokidar.watch(input.concat(dependencies(results)), { usePolling: argv.poll, interval: argv.poll && typeof argv.poll === 'number' ? argv.poll : 100, awaitWriteFinish: { stabilityThreshold: 50, pollInterval: 10, }, }) if (configFile) watcher.add(configFile) watcher.on('ready', printMessage).on('change', (file) => { let recompile = [] if (input.includes(file)) recompile.push(file) const dependants = depGraph .dependantsOf(file) .concat(getAncestorDirs(file).flatMap(depGraph.dependantsOf)) recompile = recompile.concat( dependants.filter((file) => input.includes(file)) ) if (!recompile.length) recompile = input return files([...new Set(recompile)]) .then((results) => watcher.add(dependencies(results))) .then(printMessage) .catch(error) }) } }) .catch((err) => { error(err) process.exit(1) }) function rc(ctx, path) { if (argv.use) return Promise.resolve(cliConfig) return postcssrc(ctx, path) .then((rc) => { if (rc.options.from || rc.options.to) { error( 'Config Error: Can not set from or to options in config file, use CLI arguments instead' ) } configFile = rc.file return rc }) .catch((err) => { if (!err.message.includes('No PostCSS Config found')) throw err }) } function files(files) { if (typeof files === 'string') files = [files] return Promise.all( files.map((file) => { if (file === 'stdin') { return stdin().then((content) => { if (!content) return error('Input Error: Did not receive any STDIN') return css(content, 'stdin') }) } return read(file).then((content) => css(content, file)) }) ) } function css(css, file) { const ctx = { options: cliConfig.options } if (file !== 'stdin') { ctx.file = { dirname: path.dirname(file), basename: path.basename(file), extname: path.extname(file), } if (!argv.config) argv.config = path.dirname(file) } const relativePath = file !== 'stdin' ? path.relative(path.resolve(), file) : file if (!argv.config) argv.config = process.cwd() const time = process.hrtime() printVerbose(pc.cyan(`Processing ${pc.bold(relativePath)}...`)) return rc(ctx, argv.config) .then((config) => { config = config || cliConfig const options = { ...config.options } if (file === 'stdin' && output) file = output // TODO: Unit test this options.from = file === 'stdin' ? path.join(process.cwd(), 'stdin') : file if (output || dir || argv.replace) { const base = argv.base ? file.replace(path.resolve(argv.base), '') : path.basename(file) options.to = output || (argv.replace ? file : path.join(dir, base)) if (argv.ext) { options.to = options.to.replace(path.extname(options.to), argv.ext) } options.to = path.resolve(options.to) } if (!options.to && config.options.map && !config.options.map.inline) { error( 'Output Error: Cannot output external sourcemaps when writing to STDOUT' ) } return postcss(config.plugins) .process(css, options) .then((result) => { const tasks = [] if (options.to) { tasks.push(outputFile(options.to, result.css)) if (result.map) { const mapfile = getMapfile(options) tasks.push(outputFile(mapfile, result.map.toString())) } } else process.stdout.write(result.css, 'utf8') return Promise.all(tasks).then(() => { const prettyTime = prettyHrtime(process.hrtime(time)) printVerbose( pc.green( `Finished ${pc.bold(relativePath)} in ${pc.bold(prettyTime)}` ) ) const messages = result.warnings() if (messages.length) { console.warn(reporter({ ...result, messages })) } return result }) }) }) .catch((err) => { throw err }) async function outputFile(file, string) { const fileExists = await fs.pathExists(file) const currentValue = fileExists ? await fs.readFile(file, 'utf8') : null if (currentValue === string) return return fs.outputFile(file, string) } } function dependencies(results) { if (!Array.isArray(results)) results = [results] const messages = [] results.forEach((result) => { if (result.messages <= 0) return result.messages .filter((msg) => msg.type === 'dependency' || msg.type === 'dir-dependency' ? msg : '' ) .map(depGraph.add) .forEach((dependency) => { if (dependency.type === 'dir-dependency') { messages.push( dependency.glob ? path.join(dependency.dir, dependency.glob) : dependency.dir ) } else { messages.push(dependency.file) } }) }) return messages } function printVerbose(message) { if (argv.verbose) console.warn(message) } function error(err) { // Seperate error from logging output if (argv.verbose) console.error() if (typeof err === 'string') { console.error(pc.red(err)) } else if (err.name === 'CssSyntaxError') { console.error(err.toString()) } else { console.error(err) } // Watch mode shouldn't exit on error if (argv.watch) return process.exit(1) } // Input: '/imports/components/button.css' // Output: ['/imports/components', '/imports', '/'] function getAncestorDirs(fileOrDir) { const { root } = path.parse(fileOrDir) if (fileOrDir === root) { return [] } const parentDir = path.dirname(fileOrDir) return [parentDir, ...getAncestorDirs(parentDir)] } postcss-cli-10.1.0/lib/000077500000000000000000000000001434147064100146065ustar00rootroot00000000000000postcss-cli-10.1.0/lib/DependencyGraph.js000066400000000000000000000014421434147064100202050ustar00rootroot00000000000000import path from 'path' import { DepGraph } from 'dependency-graph' export default function createDependencyGraph() { const graph = new DepGraph() return { add(message) { message.parent = path.resolve(message.parent) graph.addNode(message.parent) if (message.type === 'dir-dependency') { message.dir = path.resolve(message.dir) graph.addNode(message.dir) graph.addDependency(message.parent, message.dir) } else { message.file = path.resolve(message.file) graph.addNode(message.file) graph.addDependency(message.parent, message.file) } return message }, dependantsOf(node) { node = path.resolve(node) if (graph.hasNode(node)) return graph.dependantsOf(node) return [] }, } } postcss-cli-10.1.0/lib/DependencyGraph.test.js000066400000000000000000000012271434147064100211640ustar00rootroot00000000000000import test from 'ava' import path from 'path' import createDependencyGraph from './DependencyGraph.js' function resolveArray(arr) { return arr.map((p) => path.resolve(p)) } test('tracks dependencies', (t) => { const graph = createDependencyGraph() graph.add({ file: 'aa', parent: 'a' }) graph.add({ file: 'bb', parent: 'b' }) graph.add({ file: 'ab', parent: 'a' }) graph.add({ file: 'ab', parent: 'b' }) t.deepEqual(graph.dependantsOf('aa'), resolveArray(['a'])) t.deepEqual(graph.dependantsOf('bb'), resolveArray(['b'])) t.deepEqual(graph.dependantsOf('ab'), resolveArray(['a', 'b'])) t.deepEqual(graph.dependantsOf('nonexistent'), []) }) postcss-cli-10.1.0/lib/args.js000066400000000000000000000065771434147064100161170ustar00rootroot00000000000000import yargs from 'yargs' const { argv } = yargs(process.argv.slice(2)) .usage( `Usage: $0 [input.css] [OPTIONS] [-o|--output output.css] [--watch|-w] $0 ... [OPTIONS] --dir [--watch|-w] $0 [OPTIONS] --dir [--watch|-w] $0 [OPTIONS] --dir [--watch|-w] $0 ... [OPTIONS] --replace` ) .group( ['o', 'd', 'r', 'map', 'no-map', 'watch', 'verbose', 'env'], 'Basic options:' ) .option('o', { alias: 'output', desc: 'Output file', type: 'string', conflicts: ['dir', 'replace'], }) .option('d', { alias: 'dir', desc: 'Output directory', type: 'string', conflicts: ['output', 'replace'], }) .option('r', { alias: 'replace', desc: 'Replace (overwrite) the input file', type: 'boolean', conflicts: ['output', 'dir'], }) .alias('m', 'map') .describe('map', 'Create an external sourcemap') .describe('no-map', 'Disable the default inline sourcemaps') .option('w', { alias: 'watch', desc: 'Watch files for changes and recompile as needed', type: 'boolean', conflicts: 'replace', }) .option('verbose', { desc: 'Be verbose', type: 'boolean', }) .option('env', { desc: 'A shortcut for setting NODE_ENV', type: 'string', }) .group( ['u', 'parser', 'stringifier', 'syntax'], 'Options for use without a config file:' ) .option('u', { alias: 'use', desc: 'List of postcss plugins to use', type: 'array', }) .option('parser', { desc: 'Custom postcss parser', type: 'string', }) .option('stringifier', { desc: 'Custom postcss stringifier', type: 'string', }) .option('syntax', { desc: 'Custom postcss syntax', type: 'string', }) .group(['ext', 'base'], 'Options for use with --dir:') .option('ext', { desc: 'Override the output file extension; for use with --dir', type: 'string', implies: 'dir', }) .option('base', { desc: 'Mirror the directory structure relative to this path in the output directory, for use with --dir', type: 'string', implies: 'dir', }) .group(['include-dotfiles', 'poll', 'config'], 'Advanced options:') .option('include-dotfiles', { desc: 'Enable glob to match files/dirs that begin with "."', type: 'boolean', }) .option('poll', { desc: 'Use polling for file watching. Can optionally pass polling interval; default 100 ms', implies: 'watch', }) .option('config', { desc: 'Set a custom directory to look for a config file', type: 'string', }) .alias('h', 'help') .example('$0 input.css -o output.css', 'Basic usage') .example('$0 src/**/*.css --base src --dir build', 'Glob Pattern & output') .example( 'cat input.css | $0 -u autoprefixer > output.css', 'Piping input & output' ) .epilog( `If no input files are passed, it reads from stdin. If neither -o, --dir, or --replace is passed, it writes to stdout. If there are multiple input files, the --dir or --replace option must be passed. Input files may contain globs (e.g. src/**/*.css). If you pass an input directory, it will process all files in the directory and any subdirectories, respecting the glob pattern. For more details, please see https://github.com/postcss/postcss-cli` ) if (argv.ext && argv.ext.indexOf('.') !== 0) argv.ext = `.${argv.ext}` export default argv postcss-cli-10.1.0/lib/getMapfile.js000066400000000000000000000003571434147064100172260ustar00rootroot00000000000000import path from 'path' export default function getMapfile(options) { if (options.map && typeof options.map.annotation === 'string') { return `${path.dirname(options.to)}/${options.map.annotation}` } return `${options.to}.map` } postcss-cli-10.1.0/lib/getMapfile.test.js000066400000000000000000000012451434147064100202010ustar00rootroot00000000000000import test from 'ava' import getMapfile from './getMapfile.js' test('mapFile path is properly resolved', async (t) => { const paths = [ { input: { to: '/foo/bar.css/baz/index.css' }, want: '/foo/bar.css/baz/index.css.map', }, { input: { to: '/foo/bar.sss/baz/index.sss' }, want: '/foo/bar.sss/baz/index.sss.map', }, { input: { to: '/foo/bar.css/baz/bar.css' }, want: '/foo/bar.css/baz/bar.css.map', }, { input: { map: { annotation: 'foo.map' }, to: '/foo/bar.css/baz/bar.css' }, want: '/foo/bar.css/baz/foo.map', }, ] for (const p of paths) { t.is(getMapfile(p.input), p.want) } }) postcss-cli-10.1.0/logo.svg000066400000000000000000000016741434147064100155310ustar00rootroot00000000000000 Svg Vector Icons : http://www.onlinewebfonts.com/icon postcss-cli-10.1.0/package.json000066400000000000000000000034531434147064100163330ustar00rootroot00000000000000{ "name": "postcss-cli", "version": "10.1.0", "description": "CLI for PostCSS", "type": "module", "engines": { "node": ">=14" }, "bin": { "postcss": "./index.js" }, "scripts": { "ci": "eslint . && c8 ava -v && npm run prettier -- --list-different", "clean": "node test/helpers/clean.js", "prettier": "prettier --single-quote --no-semi \"**/*.{js,md}\"", "format": "npm run prettier -- --write && eslint . --fix", "pretest": "npm run clean && npm run format", "test": "c8 ava -v" }, "dependencies": { "chokidar": "^3.3.0", "dependency-graph": "^0.11.0", "fs-extra": "^11.0.0", "get-stdin": "^9.0.0", "globby": "^13.0.0", "picocolors": "^1.0.0", "postcss-load-config": "^4.0.0", "postcss-reporter": "^7.0.0", "pretty-hrtime": "^1.0.3", "read-cache": "^1.0.0", "slash": "^5.0.0", "yargs": "^17.0.0" }, "devDependencies": { "ava": "^3.1.0", "c8": "^7.9.0", "coveralls": "^3.0.0", "eslint": "^8.2.0", "eslint-config-problems": "7.0.1", "postcss": "^8.0.4", "postcss-import": "^15.0.0", "prettier": "~2.8.0", "sugarss": "^4.0.0", "uuid": "^9.0.0" }, "peerDependencies": { "postcss": "^8.0.0" }, "files": [ "index.js", "lib", "!**/*.test.js" ], "keywords": [ "cli", "postcss", "postcss-runner" ], "contributors": [ { "name": "Michael Ciniawky", "email": "michael.ciniawsky@gmail.com" }, { "name": "Ryan Zimmermann", "email": "opensrc@ryanzim.com" } ], "repository": { "type": "git", "url": "https://github.com/postcss/postcss-cli.git" }, "bugs": { "url": "https://github.com/postcss/postcss-cli/issues" }, "homepage": "https://github.com/postcss/postcss-cli#readme", "license": "MIT" } postcss-cli-10.1.0/renovate.json000066400000000000000000000001321434147064100165520ustar00rootroot00000000000000{ "extends": [ "config:base", ":preserveSemverRanges", ":label(deps)" ] } postcss-cli-10.1.0/test/000077500000000000000000000000001434147064100150175ustar00rootroot00000000000000postcss-cli-10.1.0/test/base.js000066400000000000000000000012121434147064100162630ustar00rootroot00000000000000import test from 'ava' import path from 'path' import cli from './helpers/cli.js' import tmp from './helpers/tmp.js' import read from './helpers/read.js' test('--base --dir works', async (t) => { const dir = tmp() const { error, stderr } = await cli([ '"test/fixtures/base/**/*.css"', '--dir', dir, '--base', 'test/fixtures/base', '--no-map', ]) t.falsy(error, stderr) t.is( await read(path.join(dir, 'level-1/level-2/a.css')), await read('test/fixtures/base/level-1/level-2/a.css') ) t.is( await read(path.join(dir, 'level-1/b.css')), await read('test/fixtures/base/level-1/b.css') ) }) postcss-cli-10.1.0/test/cli.js000066400000000000000000000006351434147064100161300ustar00rootroot00000000000000import test from 'ava' import cli from './helpers/cli.js' import tmp from './helpers/tmp.js' import read from './helpers/read.js' test('works with defaults', async (t) => { const output = tmp('output.css') const { error, stderr } = await cli([ 'test/fixtures/a.css', '-o', output, '--no-map', ]) t.falsy(error, stderr) t.is(await read(output), await read('test/fixtures/a.css')) }) postcss-cli-10.1.0/test/config.js000066400000000000000000000040611434147064100166230ustar00rootroot00000000000000import test from 'ava' import path from 'path' import ENV from './helpers/env.js' import cli from './helpers/cli.js' import read from './helpers/read.js' test('supports common config', async (t) => { const env = `module.exports = { plugins: [ require('postcss-import')() ] }` const dir = await ENV(env, ['a.css']) const { error, stderr } = await cli( ['a.css', '-o', 'output.css', '--no-map'], dir ) t.falsy(error, stderr) t.is( await read(path.join(dir, 'output.css')), await read('test/fixtures/a.css') ) }) test('supports ESM config', async (t) => { const env = `import postcssImport from 'postcss-import' export default function () { return { plugins: [ postcssImport() ] } }` const dir = await ENV(env, ['a.css'], 'mjs') const { error, stderr } = await cli( ['a.css', '-o', 'output.css', '--no-map'], dir ) t.falsy(error, stderr) t.is( await read(path.join(dir, 'output.css')), await read('test/fixtures/a.css') ) }) test("doesn't error on empty config", async (t) => { const env = `module.exports = {}` const dir = await ENV(env, ['a.css']) const { error, stderr } = await cli( ['a.css', '-o', 'output.css', '--no-map'], dir ) t.falsy(error, stderr) t.is( await read(path.join(dir, 'output.css')), await read('test/fixtures/a.css') ) }) test('errors if `to` is set', async (t) => { const env = `module.exports = { to: 'out.css' }` const dir = await ENV(env, ['a.css']) const { stderr } = await cli(['a.css', '-o', 'output.css', '--no-map'], dir) t.regex( stderr, /Config Error: Can not set from or to options in config file, use CLI arguments instead/ ) }) test('errors if `from` is set', async (t) => { const env = `module.exports = { from: 'in.css' }` const dir = await ENV(env, ['a.css']) const { stderr } = await cli(['a.css', '-o', 'output.css', '--no-map'], dir) t.regex( stderr, /Config Error: Can not set from or to options in config file, use CLI arguments instead/ ) }) postcss-cli-10.1.0/test/dir.js000066400000000000000000000010321434147064100161270ustar00rootroot00000000000000import test from 'ava' import path from 'path' import cli from './helpers/cli.js' import tmp from './helpers/tmp.js' import read from './helpers/read.js' test('--dir works', async (t) => { const dir = tmp() const { error, stderr } = await cli([ 'test/fixtures/a.css', 'test/fixtures/b.css', '--dir', dir, '--no-map', ]) t.falsy(error, stderr) t.is(await read(path.join(dir, 'a.css')), await read('test/fixtures/a.css')) t.is(await read(path.join(dir, 'b.css')), await read('test/fixtures/b.css')) }) postcss-cli-10.1.0/test/error.js000066400000000000000000000035221434147064100165100ustar00rootroot00000000000000import test from 'ava' import tmp from './helpers/tmp.js' import cli from './helpers/cli.js' test('multiple input files && --output', (t) => { return cli(['test/fixtures/*.css', '-o', tmp()]).then(({ error, code }) => { t.is(code, 1, 'expected non-zero error code') t.regex(error.toString(), /Input Error: Must use --dir or --replace/) }) }) test('multiple input files && writing to stdout', (t) => { return cli(['test/fixtures/*.css']).then(({ error, code }) => { t.is(code, 1, 'expected non-zero error code') t.regex(error.toString(), /Input Error: Must use --dir or --replace/) }) }) test('--map && writing to stdout', (t) => { return cli(['test/fixtures/a.css', '--map']).then(({ error, code }) => { t.is(code, 1, 'expected non-zero error code') t.regex( error.toString(), /Output Error: Cannot output external sourcemaps when writing to STDOUT/ ) }) }) test('plugin not found', (t) => { return cli(['test/fixtures/a.css', '-u', 'postcss-plugin', '-o', tmp()]).then( ({ error, code }) => { t.is(code, 1, 'expected non-zero error code') t.regex( error.toString(), /Plugin Error: Cannot find package 'postcss-plugin'/ ) } ) }) test('plugin throws on require', (t) => { return cli([ 'test/fixtures/a.css', '-u', './test/fixtures/_bad-plugin.js', '-o', tmp(), ]).then(({ error, code }) => { t.is(code, 1, 'expected non-zero error code') t.regex(error.toString(), /Plugin Error \(.*bad-plugin.js\): This fails/) }) }) test('CssSyntaxError', (t) => { return cli(['test/fixtures/a.css', '--parser', 'sugarss', '-o', tmp()]).then( ({ error, code }) => { t.is(code, 1, 'expected non-zero error code') t.regex( error.toString(), /CssSyntaxError: .*a.css:1:4: Unnecessary curly bracket/ ) } ) }) postcss-cli-10.1.0/test/ext.js000066400000000000000000000013501434147064100161540ustar00rootroot00000000000000import test from 'ava' import fs from 'fs-extra' import path from 'path' import cli from './helpers/cli.js' import tmp from './helpers/tmp.js' test('--ext works', async (t) => { const dir = tmp() const { error, stderr } = await cli([ 'test/fixtures/a.sss', '--parser', 'sugarss', '-d', dir, '--ext', '.css', ]) t.falsy(error, stderr) t.truthy(await fs.pathExists(path.join(dir, 'a.css'))) }) test('--ext works with no leading dot', async (t) => { const dir = tmp() const { error, stderr } = await cli([ 'test/fixtures/a.sss', '--parser', 'sugarss', '-d', dir, '--ext', 'css', ]) t.falsy(error, stderr) t.truthy(await fs.pathExists(path.join(dir, 'a.css'))) }) postcss-cli-10.1.0/test/fixtures/000077500000000000000000000000001434147064100166705ustar00rootroot00000000000000postcss-cli-10.1.0/test/fixtures/_bad-plugin.js000066400000000000000000000000361434147064100214060ustar00rootroot00000000000000throw new Error('This fails') postcss-cli-10.1.0/test/fixtures/a.css000066400000000000000000000000251434147064100176170ustar00rootroot00000000000000.a { color: red; } postcss-cli-10.1.0/test/fixtures/a.sss000066400000000000000000000000201434147064100176320ustar00rootroot00000000000000.a color: red postcss-cli-10.1.0/test/fixtures/b.css000066400000000000000000000000261434147064100176210ustar00rootroot00000000000000.b { color: blue; } postcss-cli-10.1.0/test/fixtures/b.sss000066400000000000000000000000211434147064100176340ustar00rootroot00000000000000.b color: blue postcss-cli-10.1.0/test/fixtures/base/000077500000000000000000000000001434147064100176025ustar00rootroot00000000000000postcss-cli-10.1.0/test/fixtures/base/level-1/000077500000000000000000000000001434147064100210475ustar00rootroot00000000000000postcss-cli-10.1.0/test/fixtures/base/level-1/b.css000066400000000000000000000000261434147064100220000ustar00rootroot00000000000000.b { color: blue; } postcss-cli-10.1.0/test/fixtures/base/level-1/level-2/000077500000000000000000000000001434147064100223155ustar00rootroot00000000000000postcss-cli-10.1.0/test/fixtures/base/level-1/level-2/a.css000066400000000000000000000000251434147064100232440ustar00rootroot00000000000000.a { color: red; } postcss-cli-10.1.0/test/fixtures/base/level-1/level-2/unrelated.md000066400000000000000000000000601434147064100246160ustar00rootroot00000000000000Editing this file should not trigger a rebuild. postcss-cli-10.1.0/test/fixtures/glob/000077500000000000000000000000001434147064100176135ustar00rootroot00000000000000postcss-cli-10.1.0/test/fixtures/glob/a.css000066400000000000000000000000251434147064100205420ustar00rootroot00000000000000.a { color: red; } postcss-cli-10.1.0/test/fixtures/glob/b.css000066400000000000000000000000261434147064100205440ustar00rootroot00000000000000.b { color: blue; } postcss-cli-10.1.0/test/fixtures/glob/s.css000066400000000000000000000000241434147064100205630ustar00rootroot00000000000000.a { color: red } postcss-cli-10.1.0/test/fixtures/import.css000066400000000000000000000000231434147064100207070ustar00rootroot00000000000000@import "./a.css"; postcss-cli-10.1.0/test/fixtures/import.sss000066400000000000000000000000201434147064100207240ustar00rootroot00000000000000@import 'a.sss' postcss-cli-10.1.0/test/fixtures/s.css000066400000000000000000000000241434147064100176400ustar00rootroot00000000000000.a { color: red } postcss-cli-10.1.0/test/fixtures/unchanged-input.css000066400000000000000000000000271434147064100224720ustar00rootroot00000000000000body { color: red; } postcss-cli-10.1.0/test/fixtures/unchanged-output.css000066400000000000000000000004351434147064100226760ustar00rootroot00000000000000body { color: red; } /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInVuY2hhbmdlZC1pbnB1dC5jc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEiLCJmaWxlIjoidW5jaGFuZ2VkLW91dHB1dC5jc3MiLCJzb3VyY2VzQ29udGVudCI6WyJib2R5IHtcbiAgY29sb3I6IHJlZDtcbn1cbiJdfQ== */postcss-cli-10.1.0/test/glob.js000066400000000000000000000012361434147064100163020ustar00rootroot00000000000000import test from 'ava' import path from 'path' import cli from './helpers/cli.js' import tmp from './helpers/tmp.js' import read from './helpers/read.js' test('works with glob patterns', async (t) => { const output = tmp() const { error, stderr } = await cli([ 'test/fixtures/glob/*.css', '-d', output, '--no-map', ]) t.falsy(error, stderr) t.is( await read(path.join(output, 'a.css')), await read('test/fixtures/glob/a.css') ) t.is( await read(path.join(output, 'b.css')), await read('test/fixtures/glob/b.css') ) t.is( await read(path.join(output, 's.css')), await read('test/fixtures/glob/s.css') ) }) postcss-cli-10.1.0/test/helpers/000077500000000000000000000000001434147064100164615ustar00rootroot00000000000000postcss-cli-10.1.0/test/helpers/clean.js000066400000000000000000000002521434147064100201000ustar00rootroot00000000000000import fs from 'fs-extra' Promise.all([ fs.emptyDir('./test/fixtures/.tmp/'), fs.remove('./coverage'), ]).catch((err) => { console.error(err) process.exit(1) }) postcss-cli-10.1.0/test/helpers/cli.js000066400000000000000000000006351434147064100175720ustar00rootroot00000000000000import path from 'path' import { exec } from 'child_process' export default function (args, cwd) { return new Promise((resolve) => { exec( `node ${path.resolve('index.js')} ${args.join(' ')}`, { cwd }, (error, stdout, stderr) => { resolve({ code: error && error.code ? error.code : 0, error, stdout, stderr, }) } ) }) } postcss-cli-10.1.0/test/helpers/env.js000066400000000000000000000010071434147064100176050ustar00rootroot00000000000000import fs from 'fs-extra' import path from 'path' import { globby } from 'globby' import tmp from './tmp.js' export default function (config, fixtures = '**/*', extension = 'cjs') { const dir = tmp() return Promise.all([ globby(fixtures, { cwd: 'test/fixtures' }).then((list) => { return list.map((item) => { return fs.copy(path.join('test/fixtures', item), path.join(dir, item)) }) }), fs.outputFile(path.join(dir, `postcss.config.${extension}`), config), ]).then(() => dir) } postcss-cli-10.1.0/test/helpers/read.js000066400000000000000000000003001434147064100177230ustar00rootroot00000000000000import fs from 'fs-extra' export default function (path) { return fs.readFile(path, 'utf8').then( (content) => content.replace(/\r\n/g, '\n') // normalize line endings on Windows ) } postcss-cli-10.1.0/test/helpers/tmp.js000066400000000000000000000002461434147064100176210ustar00rootroot00000000000000import path from 'path' import { v4 as uuid } from 'uuid' export default function (ext) { ext = ext || '' return path.join('test/fixtures/.tmp', uuid(), ext) } postcss-cli-10.1.0/test/map.js000066400000000000000000000021661434147064100161370ustar00rootroot00000000000000import test from 'ava' import fs from 'fs-extra' import cli from './helpers/cli.js' import tmp from './helpers/tmp.js' import read from './helpers/read.js' test('inline maps are generated by default', async (t) => { const output = tmp('output.css') const { error, stderr } = await cli([ 'test/fixtures/import.css', '-u', 'postcss-import', '-o', output, ]) t.falsy(error, stderr) t.regex(await read(output), /\/*# sourceMappingURL=/) }) test('--map generates external sourcemaps', async (t) => { const output = tmp('output.css') const { error, stderr } = await cli([ 'test/fixtures/import.css', '-u', 'postcss-import', '-o', output, '--map', ]) t.falsy(error, stderr) t.truthy(await fs.pathExists(output.replace('.css', '.css.map'))) }) test('--no-map disables internal sourcemaps', async (t) => { const output = tmp('output.css') const { error, stderr } = await cli([ 'test/fixtures/import.css', '-u', 'postcss-import', '-o', output, '--no-map', ]) t.falsy(error, stderr) t.notRegex(await read(output), /\/*# sourceMappingURL=/) }) postcss-cli-10.1.0/test/misc.js000066400000000000000000000006641434147064100163160ustar00rootroot00000000000000import test from 'ava' import cli from './helpers/cli.js' test('--help', async (t) => { const help = await cli(['--help']) t.falsy(help.error) t.truthy(help.stdout.length > 10, 'expected --help to output a help message') }) test('--version', async (t) => { const version = await cli(['--version']) t.falsy(version.error) t.truthy( version.stdout.length > 5, 'expected --version to output version info' ) }) postcss-cli-10.1.0/test/parser.js000066400000000000000000000006671434147064100166620ustar00rootroot00000000000000import test from 'ava' import cli from './helpers/cli.js' import tmp from './helpers/tmp.js' import read from './helpers/read.js' test('--parser works', async (t) => { const output = tmp('output.css') const { error, stderr } = await cli([ 'test/fixtures/a.sss', '--parser', 'sugarss', '-o', output, '--no-map', ]) t.falsy(error, stderr) t.is(await read(output), await read('test/fixtures/s.css')) }) postcss-cli-10.1.0/test/replace.js000066400000000000000000000012741434147064100167740ustar00rootroot00000000000000import test from 'ava' import fs from 'fs-extra' import path from 'path' import cli from './helpers/cli.js' import tmp from './helpers/tmp.js' import read from './helpers/read.js' test('--replace works', async (t) => { const dir = tmp() const output = path.join(dir, 'output.css') await Promise.all([ fs.copy('test/fixtures/import.css', output), fs.copy('test/fixtures/a.css', path.join(dir, 'a.css')), ]) const { error, stderr } = await cli([ output.replace(/\\/g, '/'), // gotta keep globby happy on Windows '--replace', '-u', 'postcss-import', '--no-map', ]) t.falsy(error, stderr) t.is(await read(output), await read('test/fixtures/a.css')) }) postcss-cli-10.1.0/test/stdin.js000066400000000000000000000012101434147064100164700ustar00rootroot00000000000000import test from 'ava' import fs from 'fs-extra' import path from 'path' import { exec } from 'child_process' import tmp from './helpers/tmp.js' import read from './helpers/read.js' test.cb('reads from stdin', (t) => { const output = tmp('output.css') const cp = exec( `node ${path.resolve('index.js')} -o ${output} --no-map`, (error, stdout, stderr) => { if (error) t.end(error, stderr) Promise.all([read(output), read('test/fixtures/a.css')]) .then(([a, e]) => { t.is(a, e) t.end() }) .catch(t.end) } ) fs.createReadStream('test/fixtures/a.css').pipe(cp.stdin) }) postcss-cli-10.1.0/test/stdout.js000066400000000000000000000011661434147064100167030ustar00rootroot00000000000000import test from 'ava' import fs from 'fs-extra' import path from 'path' import { exec } from 'child_process' import read from './helpers/read.js' test.cb('writes to stdout', (t) => { const cp = exec( `node ${path.resolve( 'index.js' )} --parser sugarss -u postcss-import --no-map`, (error, stdout, stderr) => { if (error) t.end(error, stderr) Promise.all([stdout.replace(/\r\n/g, '\n'), read('test/fixtures/s.css')]) .then(([a, e]) => { t.is(a, e) t.end() }) .catch(t.end) } ) fs.createReadStream('./test/fixtures/a.sss').pipe(cp.stdin) }) postcss-cli-10.1.0/test/stringifier.js000066400000000000000000000007011434147064100177000ustar00rootroot00000000000000import test from 'ava' import cli from './helpers/cli.js' import tmp from './helpers/tmp.js' import read from './helpers/read.js' test('--stringifier works', async (t) => { const output = tmp('output.sss') const { error, stderr } = await cli([ 'test/fixtures/a.css', '--stringifier', 'sugarss', '-o', output, '--no-map', ]) t.falsy(error, stderr) t.is(await read(output), await read('test/fixtures/a.sss')) }) postcss-cli-10.1.0/test/syntax.js000066400000000000000000000006671434147064100167140ustar00rootroot00000000000000import test from 'ava' import cli from './helpers/cli.js' import tmp from './helpers/tmp.js' import read from './helpers/read.js' test('--syntax works', async (t) => { const output = tmp('output.sss') const { error, stderr } = await cli([ 'test/fixtures/a.sss', '--syntax', 'sugarss', '-o', output, '--no-map', ]) t.falsy(error, stderr) t.is(await read(output), await read('test/fixtures/a.sss')) }) postcss-cli-10.1.0/test/unchanged.js000066400000000000000000000007471434147064100173210ustar00rootroot00000000000000import fs from 'fs-extra' import test from 'ava' import cli from './helpers/cli.js' test('files are not saved if the contents are the same', async (t) => { const input = 'test/fixtures/unchanged-input.css' const output = 'test/fixtures/unchanged-output.css' const intialStat = await fs.stat(output) const { error, stderr } = await cli([input, '-o', output]) t.falsy(error, stderr) const finalStat = await fs.stat(output) t.is(finalStat.mtimeMs, intialStat.mtimeMs) }) postcss-cli-10.1.0/test/use.js000066400000000000000000000006651434147064100161600ustar00rootroot00000000000000import test from 'ava' import cli from './helpers/cli.js' import tmp from './helpers/tmp.js' import read from './helpers/read.js' test('--use works', async (t) => { const output = tmp('i.css') const { error, stderr } = await cli([ 'test/fixtures/import.css', '-u', 'postcss-import', '-o', output, '--no-map', ]) t.falsy(error, stderr) t.is(await read(output), await read('test/fixtures/a.css')) }) postcss-cli-10.1.0/test/watch.js000066400000000000000000000324251434147064100164710ustar00rootroot00000000000000import test from 'ava' import fs from 'fs-extra' import path from 'path' import { exec, spawn } from 'child_process' import chokidar from 'chokidar' import ENV from './helpers/env.js' import read from './helpers/read.js' import tmp from './helpers/tmp.js' // XXX: All the tests in this file are skipped on the Windows CI; too flacky there const testCb = process.env.CI && process.platform === 'win32' ? test.cb.skip : test.cb testCb('--watch works', (t) => { let cp t.plan(2) ENV('', ['a.css']) .then((dir) => { // Init watcher: const watcher = chokidar.watch('.', { cwd: dir, ignoreInitial: true, awaitWriteFinish: true, }) // On the first output: watcher.on('add', (p) => { // Assert, then change the source file if (p === 'output.css') { isEqual(p, 'test/fixtures/a.css') .then(() => read('test/fixtures/b.css')) .then((css) => fs.writeFile(path.join(dir, 'a.css'), css)) .catch(done) } }) // When the change is picked up: watcher.on('change', (p) => { if (p === 'output.css') { isEqual(p, 'test/fixtures/b.css') .then(() => done()) .catch(done) } }) // Start postcss-cli: watcher.on('ready', () => { // Using exec() and quoting "*.css" to test watch's glob handling: cp = exec( `node ${path.resolve('index.js')} "*.css" -o output.css --no-map -w`, { cwd: dir } ) cp.on('error', t.end) cp.on('exit', (code) => { if (code) t.end(code) }) }) // Helper functions: function isEqual(p, expected) { return Promise.all([read(path.join(dir, p)), read(expected)]).then( ([a, e]) => t.is(a, e) ) } function done(err) { try { cp.kill() } catch {} t.end(err) } }) .catch(t.end) }) testCb('--watch dependencies', (t) => { let cp t.plan(2) ENV('', ['import.css', 'a.css']) .then((dir) => { // Init watcher: const watcher = chokidar.watch('.', { cwd: dir, ignoreInitial: true, awaitWriteFinish: true, }) // On the first output: watcher.on('add', (p) => { // Assert, then change the source file if (p === 'output.css') { isEqual(p, 'test/fixtures/a.css') .then(() => read('test/fixtures/b.css')) .then((css) => fs.writeFile(path.join(dir, 'a.css'), css)) .catch(done) } }) // When the change is picked up: watcher.on('change', (p) => { if (p === 'output.css') { isEqual(p, 'test/fixtures/b.css') .then(() => done()) .catch(done) } }) // Start postcss-cli: watcher.on('ready', () => { cp = exec( `node ${path.resolve( 'index.js' )} import.css -o output.css -u postcss-import -w --no-map`, { cwd: dir } ) cp.on('error', t.end) cp.on('exit', (code) => { if (code) t.end(code) }) }) // Helper functions: function isEqual(p, expected) { return Promise.all([read(path.join(dir, p)), read(expected)]).then( ([a, e]) => t.is(a, e) ) } function done(err) { try { cp.kill() } catch {} t.end(err) } }) .catch(t.end) }) // Doesn't work on CI for some reason ;(process.env.CI ? test.cb.skip : test.cb)( "--watch doesn't exit on CssSyntaxError", (t) => { t.plan(0) ENV('', ['a.css']) .then((dir) => { // Init watcher: const watcher = chokidar.watch('.', { cwd: dir, ignoreInitial: true, awaitWriteFinish: true, }) watcher.on('add', (p) => { if (p === 'output.css') { // Change to invalid CSS fs.writeFile(path.join(dir, 'a.css'), '.a { color: red').catch(done) } }) let killed = false const cp = exec( `node ${path.resolve( 'index.js' )} a.css -o output.css -u postcss-import -w --no-map`, { cwd: dir } ) cp.on('error', t.end) cp.stderr.on('data', (chunk) => { // When error message is printed, kill the process after a timeout if (~chunk.indexOf('Unclosed block')) { setTimeout(() => { killed = true cp.kill() }, 1000) } }) cp.on('exit', (code) => { if (!killed) return t.end(`Should not exit (exited with code ${code})`) done() }) function done(err) { try { cp.kill() } catch {} t.end(err) } }) .catch(t.end) } ) testCb('--watch does exit on closing stdin (Ctrl-D/EOF)', (t) => { t.plan(1) const cp = spawn(`./index.js test/fixtures/a.css -o ${tmp()} -w --no-map`, { shell: true, env: { ...process.env, FORCE_IS_TTY: true, }, }) cp.on('error', t.end) cp.on('exit', (code) => { t.is(code, 0) t.end() }) cp.stdin.end() }) testCb('--watch watches dependencies', (t) => { let cp t.plan(2) ENV('', ['s.css', 'a.css', 'b.css']).then((dir) => { fs.writeFile( path.join(dir, 'postcss.config.cjs'), ` const fs = require('fs') module.exports = { plugins: [ (root, result) => { const file = '${path.resolve(dir, 'a.css')}' result.messages.push({ plugin: 'test', type: 'dependency', file, parent: result.opts.from, }) root.nodes = [] root.append(fs.readFileSync(file, 'utf8')) return root } ] } ` ) .then(() => { // Init watcher: const watcher = chokidar.watch('.', { cwd: dir, ignoreInitial: true, awaitWriteFinish: true, }) // On the first output: watcher.on('add', (p) => { // Assert, then change the source file if (p === 'output.css') { isEqual(p, 'test/fixtures/a.css') .then(() => read('test/fixtures/b.css')) .then((css) => fs.writeFile(path.join(dir, 'a.css'), css)) .catch(done) } }) // When the change is picked up: watcher.on('change', (p) => { if (p === 'output.css') { isEqual(p, 'test/fixtures/b.css') .then(() => done()) .catch(done) } }) // Start postcss-cli: watcher.on('ready', () => { // Using exec() and quoting "*.css" to test watch's glob handling: cp = exec( `node ${path.resolve( 'index.js' )} "s.css" -o output.css --no-map -w`, { cwd: dir } ) cp.on('error', t.end) cp.on('exit', (code) => { if (code) t.end(code) }) }) // Helper functions: function isEqual(p, expected) { return Promise.all([read(path.join(dir, p)), read(expected)]).then( ([a, e]) => t.is(a, e) ) } function done(err) { try { cp.kill() } catch {} t.end(err) } }) .catch(t.end) }) }) testCb('--watch watches directory dependencies', (t) => { let cp t.plan(2) ENV('', ['s.css', 'base/level-1/b.css', 'base/level-1/level-2/a.css']).then( (dir) => { fs.writeFile( path.join(dir, 'postcss.config.cjs'), ` const fs = require('fs') module.exports = { plugins: [ (root, result) => { result.messages.push({ plugin: 'test', type: 'dir-dependency', dir: '${path.resolve(dir, 'base')}', parent: result.opts.from, }) root.nodes = [] root.append(fs.readFileSync('${path.resolve( dir, 'base/level-1/level-2/a.css' )}', 'utf8')) return root } ] } ` ) .then(() => { // Init watcher: const watcher = chokidar.watch('.', { cwd: dir, ignoreInitial: true, awaitWriteFinish: true, }) // On the first output: watcher.on('add', (p) => { // Assert, then change the source file if (p === 'output.css') { isEqual(p, 'test/fixtures/base/level-1/level-2/a.css') .then(() => read('test/fixtures/base/level-1/b.css')) .then((css) => fs.writeFile( path.join(dir, 'base/level-1/level-2/a.css'), css ) ) .catch(done) } }) // When the change is picked up: watcher.on('change', (p) => { if (p === 'output.css') { isEqual(p, 'test/fixtures/base/level-1/b.css') .then(() => done()) .catch(done) } }) // Start postcss-cli: watcher.on('ready', () => { // Using exec() and quoting "*.css" to test watch's glob handling: cp = exec( `node ${path.resolve( 'index.js' )} "s.css" -o output.css --no-map -w`, { cwd: dir } ) cp.on('error', t.end) cp.on('exit', (code) => { if (code) t.end(code) }) }) // Helper functions: function isEqual(p, expected) { return Promise.all([read(path.join(dir, p)), read(expected)]).then( ([a, e]) => t.is(a, e) ) } function done(err) { try { cp.kill() } catch {} t.end(err) } }) .catch(t.end) } ) }) testCb( '--watch applies glob on dir-dependency (and excludes non matching files)', (t) => { let cp let modifying = null // one of "unrelated.md", "a.css" t.plan(1) ENV('', [ 's.css', 'base/level-1/b.css', 'base/level-1/level-2/a.css', 'base/level-1/level-2/unrelated.md', ]).then((dir) => { fs.writeFile( path.join(dir, 'postcss.config.cjs'), ` const fs = require('fs') module.exports = { plugins: [ (root, result) => { result.messages.push({ plugin: 'test', type: 'dir-dependency', dir: '${path.resolve(dir, 'base')}', glob: '**/*.css', parent: result.opts.from, }) root.nodes = [] root.append(fs.readFileSync('${path.resolve( dir, 'base/level-1/level-2/a.css' )}', 'utf8')) return root } ] } ` ) .then(() => { // Init watcher: const watcher = chokidar.watch('.', { cwd: dir, ignoreInitial: true, awaitWriteFinish: true, }) // On the first output: watcher.on('add', (p) => { if (p === 'output.css') { // Modify unwatched file, shouldn't trigger output modifyUnwatched() } }) // When the change is picked up: watcher.on('change', (p) => { if (p === 'output.css') { // Assert that change to output.css happened only after modifying the watched a.css t.is( modifying, 'a.css', `Unexpected change to ${p} after modifying ${modifying}` ) done() } else if (p === 'base/level-1/level-2/unrelated.md') { // Modify watched file next, should trigger output setTimeout(modifyWatched, 250) } }) // Start postcss-cli: watcher.on('ready', () => { cp = exec( `node ${path.resolve( 'index.js' )} "s.css" -o output.css --no-map -w`, { cwd: dir } ) cp.on('error', t.end) cp.on('exit', (code) => { if (code) t.end(code) }) }) function modifyUnwatched() { modifying = 'unrelated.md' fs.writeFile( path.join(dir, 'base/level-1/level-2/unrelated.md'), 'Some modification' ).catch(done) } function modifyWatched() { modifying = 'a.css' fs.writeFile( path.join(dir, 'base/level-1/level-2/a.css'), 'a { color: hotpink }' ).catch(done) } function done(err) { try { cp.kill() } catch {} t.end(err) } }) .catch(t.end) }) } )