├── .github └── workflows │ └── check.yaml ├── .gitignore ├── .jshintrc ├── History.md ├── Makefile ├── Readme.md ├── bin └── postcss ├── index.js ├── lib ├── argv.js └── run.js ├── package.json └── test ├── argv.js ├── cmd.js ├── fixtures ├── config-all.js ├── config-all.json ├── config.js ├── config.json ├── dummy-plugin.js ├── image.png ├── in-force-error.css ├── in-warning.css ├── in.css └── invalid.css └── ref ├── config-all.css ├── config.css ├── js-config-all.css ├── js-config.css ├── opts.css ├── replace.css ├── safe.css ├── source-maps-file.css ├── source-maps-file.css.map └── source-maps.css /.github/workflows/check.yaml: -------------------------------------------------------------------------------- 1 | name: check 2 | on: [push] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | - uses: actions/setup-node@v2 9 | with: 10 | node-version: 'lts/*' 11 | - run: yarn install 12 | - run: make check 13 | env: 14 | NO_COLOR: 1 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | test/_build 3 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "undef": true, 4 | "unused": true, 5 | "laxbreak": true, 6 | "laxcomma": true, 7 | "proto": true, 8 | "esversion": 11 9 | } 10 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 4.0.3 / 2024-12-25 3 | ================== 4 | 5 | * fix badges in Readme 6 | 7 | 4.0.2 / 2024-12-25 8 | ================== 9 | 10 | * replace tape with node:test 11 | * replace jshint with @pirxpilot/jshint 12 | 13 | 4.0.1 / 2024-02-06 14 | ================== 15 | 16 | * soft dependency update 17 | 18 | 4.0.0 / 2022-05-16 19 | ================== 20 | 21 | * use async/await instead of callbacks 22 | 23 | 3.2.0 / 2022-05-15 24 | ================== 25 | 26 | * support postcss@8 27 | * move postcss to peer dependencies 28 | 29 | 3.1.0 / 2020-06-04 30 | ================== 31 | 32 | * export runner and argument parser 33 | * fix make check and lint target 34 | * fix typo in Readme 35 | * move command line tests to tape 36 | * update tape to ~5 37 | 38 | 3.0.1 / 2020-04-22 39 | ================== 40 | 41 | * upgrade async to ~3 42 | * upgrade yargs-parser 43 | * replace mocha/should with tape 44 | 45 | 3.0.0 / 2018-12-27 46 | ================== 47 | 48 | * rewrite in ES6 49 | * replace yargs with yargs-parser 50 | * replace neo-async with async 51 | * work with postcss ~5, ~6, and ~7 52 | 53 | 1.0.4 / 2017-02-19 54 | ================== 55 | 56 | * transfer repo to pirxpilot 57 | 58 | 1.0.3 / 2016-12-07 59 | ================== 60 | 61 | * replace `.npmignore` with package.files 62 | 63 | 1.0.2 / 2016-12-07 64 | ================== 65 | 66 | * upgrade neoasync to ~2 67 | * remove unused dev dependency on postcss-import 68 | 69 | 1.0.1 / 2016-02-03 70 | ================== 71 | 72 | * minor code clean-up - simplify `processCss` extract `dumpWarnings` and `dumpErrors` 73 | 74 | 1.0.0 / 2016-01-30 75 | ================== 76 | 77 | * initial implementaion - simplfied version of postcss-cli 78 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | check: lint test 2 | 3 | lint: 4 | ./node_modules/.bin/jshint *.js lib test bin/postcss 5 | 6 | test: 7 | node --test test/*.js 8 | 9 | clean: 10 | rm -rf test/_build 11 | 12 | .PHONY: check clean lint test 13 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | [![NPM version][npm-image]][npm-url] 2 | [![Build Status][build-image]][build-url] 3 | [![Dependency Status][deps-image]][deps-url] 4 | 5 | # postcss-cli-simple 6 | 7 | Simple CLI for [postcss]. To be used in Makefiles. If you are looking for more options check out [postcss-cli]. 8 | More on the [history of this project][history]. 9 | 10 | ## Installation 11 | 12 | npm install postcss-cli-simple 13 | 14 | ## Usage 15 | 16 | postcss [options] -o output-file input-file 17 | 18 | In Makefile you can use it with [pattern rules]: 19 | 20 | ````Make 21 | deploy/%.css: %.css 22 | ./node_modules/.bin/postcss \ 23 | --use postcss-url --postcss-url.url=rebase \ 24 | --use autoprefixer --autoprefixer.browsers "> 5%" \ 25 | --use cssnano --no-cssnano.discardUnused 26 | --output $@ $< 27 | ```` 28 | 29 | #### `--output|-o` 30 | 31 | Output file name. 32 | 33 | #### `--use|-u` 34 | 35 | Plugin to be used. Multiple plugins can be specified. At least one plugin needs to be specified either with `--use` option or in the config file. 36 | 37 | Plugin options can be specified using [yargs dot notation]. For example, to pass `browsers` option to `autoprefixer` one can use `--autoprefixer.browsers "> 5%"`. To set plugin option to `false` use [yargs boolean negation]. For example, to switch off `discardUnused` in `cssnano` try: `--no-cssnano.discardUnused`. 38 | 39 | #### `--map|-m` 40 | 41 | Activate source map generation. By default inline maps are generated. To generate source maps 42 | in a separate _.map_ file use `--map file` or `--no-map.inline`. 43 | 44 | You can use [advances source map options][source-map-options] - some examples: 45 | 46 | - `--no-map` - do not generated source maps - even if previous maps exist 47 | - `--map.annotation ` - specify alternaive path to be used in source map annotation appended to CSS 48 | - `--no-map.annotation` - supress adding annotation to CSS 49 | - `--no-map.sourcesContent` - remove origin CSS from maps 50 | 51 | #### `--config|-c` 52 | 53 | JSON file with plugin configuration. Plugin names should be the keys. 54 | 55 | ````json 56 | { 57 | "autoprefixer": { 58 | "browsers": "> 5%" 59 | }, 60 | "postcss-cachify": { 61 | "baseUrl": "/res" 62 | } 63 | } 64 | ```` 65 | 66 | JavaScript configuration can be used if functions are allowed as plugins parameters. Although you might be better off writing your own plugin. 67 | 68 | ````js 69 | module.exports = { 70 | "postcss-url": { 71 | url: function(url) { return "http://example.com/" + url; } 72 | }, 73 | autoprefixer: { 74 | browsers: "> 5%" 75 | } 76 | }; 77 | ```` 78 | 79 | Alternatively configuration options can be passed as `--plugin.option` parameters. 80 | 81 | Note that command-line options can also be specified in the config file: 82 | 83 | ````json 84 | { 85 | "use": ["autoprefixer", "postcss-cachify"], 86 | "output": "bundle.css", 87 | "autoprefixer": { 88 | "browsers": "> 5%" 89 | }, 90 | "postcss-cachify": { 91 | "baseUrl": "/res" 92 | } 93 | } 94 | ```` 95 | 96 | #### `--syntax|-s` 97 | 98 | Optional module to use as a [custom PostCSS syntax](https://github.com/postcss/postcss#syntaxes). 99 | 100 | #### `--parser|-p` 101 | 102 | Optional module to use as a [custom PostCSS input parser](https://github.com/postcss/postcss#syntaxes). 103 | 104 | #### `--stringifier|-t` 105 | 106 | Optional module to use as a [custom PostCSS output stringifier](https://github.com/postcss/postcss#syntaxes). 107 | 108 | #### `--help|-h` 109 | 110 | Show help 111 | 112 | ### Examples 113 | 114 | Use autoprefixer as a postcss plugin pass parameters from a json file 115 | 116 | postcss --use autoprefixer -c options.json -o screen.css screen.css 117 | 118 | Use more than one plugin and pass config parameters 119 | 120 | postcss --use autoprefixer --autoprefixer.browsers "> 5%" \ 121 | --use postcss-cachify --postcss-cachify.baseUrl /res \ 122 | -o screen.css screen.css 123 | 124 | 125 | ## License 126 | 127 | MIT 128 | 129 | [postcss]: https://npmjs.org/package/postcss 130 | [postcss-cli]: https://npmjs.org/package/postcss-cli 131 | [history]: https://github.com/postcss/postcss/issues/154#issuecomment-177278640 132 | [source-map-options]: https://github.com/postcss/postcss/blob/master/docs/source-maps.md 133 | [pattern rules]: https://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html 134 | [yargs dot notation]: https://www.npmjs.com/package/yargs#dot-notation 135 | [yargs boolean negation]: https://www.npmjs.com/package/yargs#negate-fields 136 | 137 | 138 | [npm-image]: https://img.shields.io/npm/v/postcss-cli-simple 139 | [npm-url]: https://npmjs.org/package/postcss-cli-simple 140 | 141 | [build-image]: https://img.shields.io/github/actions/workflow/status/pirxpilot/postcss-cli/check.yaml?branch=main 142 | [build-url]: https://github.com/pirxpilot/postcss-cli/actions/workflows/check.yaml 143 | 144 | [deps-image]: https://img.shields.io/librariesio/release/npm/postcss-cli-simple 145 | [deps-url]: https://libraries.io/npm/postcss-cli-simple 146 | -------------------------------------------------------------------------------- /bin/postcss: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { argv, run } = require('..'); 4 | const args = argv(); 5 | 6 | if (typeof args === 'number') { 7 | process.exit(args); 8 | } else { 9 | run(args).then(exitCode => process.exit(exitCode)); 10 | } 11 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | argv: require('./lib/argv'), 3 | run: require('./lib/run') 4 | }; 5 | -------------------------------------------------------------------------------- /lib/argv.js: -------------------------------------------------------------------------------- 1 | const yargsParser = require('yargs-parser'); 2 | 3 | module.exports = parse; 4 | 5 | const parserConfig = { 6 | alias: { 7 | config: 'c', 8 | use: 'u', 9 | output: 'o', 10 | map: 'm', 11 | syntax: 's', 12 | parser: 'p', 13 | stringifier: 't', 14 | version: 'v', 15 | help: 'h', 16 | }, 17 | array: [ 'use' ], 18 | 19 | config: 'config', 20 | 21 | nargs: { 22 | config: 1, 23 | use: 1, 24 | output: 1, 25 | syntax: 1, 26 | parser: 1, 27 | stringifier: 1, 28 | }, 29 | 30 | boolean: ['version', 'help'], 31 | 32 | coerce: { 33 | map: v => v === 'file' ? { inline: false } : v 34 | } 35 | }; 36 | 37 | function version() { 38 | const { version } = require('postcss/package.json'); 39 | return `postcss version: ${ version }`; 40 | } 41 | 42 | function usage() { 43 | return ` 44 | Usage: 45 | node_modules/.bin/postcss -use plugin [--config|-c config.json] [--output|-o output.css] input.css 46 | 47 | Options: 48 | -c, --config JSON file with plugin configuration 49 | -u, --use postcss plugin name (can be used multiple times) 50 | -o, --output Output file 51 | -m, --map Source map 52 | -s, --syntax Alternative input syntax parser 53 | -p, --parser Alternative CSS parser 54 | -t, --stringifier Alternative output stringifier 55 | -v, --version Show version number 56 | -h, --help Show help 57 | 58 | Examples: 59 | 60 | # use autoprefixer as a postcss plugin: 61 | postcss --use autoprefixer -c options.json -o screen.css screen.css 62 | 63 | # pass plugin parameters in plugin.option notation 64 | postcss --use autoprefixer --autoprefixer.browsers "> 5%" -o screen.css screen.css 65 | `; 66 | } 67 | 68 | function parse(args = process.argv.slice(2)) { 69 | let argv = yargsParser(args, parserConfig); 70 | 71 | if (argv.version) { 72 | console.log(version()); 73 | return 0; 74 | } 75 | 76 | if (argv.help) { 77 | console.log(usage()); 78 | return 0; 79 | } 80 | 81 | if (!argv.use) { 82 | console.log(usage()); 83 | console.error('Please specify at least one plugin name.'); 84 | return 1; 85 | } 86 | 87 | if (argv._.length !== 1) { 88 | console.log(usage()); 89 | console.error('Please specify a single input file.'); 90 | return 1; 91 | } 92 | 93 | return argv; 94 | } 95 | 96 | -------------------------------------------------------------------------------- /lib/run.js: -------------------------------------------------------------------------------- 1 | const { readFile, writeFile } = require('fs').promises; 2 | const postcss = require('postcss'); 3 | 4 | module.exports = run; 5 | 6 | async function run(argv) { 7 | 8 | // load and configure plugin array 9 | const plugins = argv.use.map(name => { 10 | let plugin = require(name); 11 | if (name in argv) { 12 | plugin = plugin(argv[name]); 13 | } else if (plugin.postcss) { 14 | plugin = plugin(); 15 | } 16 | return plugin; 17 | }); 18 | 19 | const commonOptions = [ 20 | 'syntax', 21 | 'parser', 22 | 'stringifier' 23 | ].reduce((cso, opt) => { 24 | if (argv[opt]) { 25 | cso[opt] = require(argv[opt]); 26 | } 27 | return cso; 28 | }, Object.create(null)); 29 | 30 | if ('map' in argv) { 31 | commonOptions.map = argv.map; 32 | } 33 | 34 | const processor = postcss(plugins); 35 | const from = argv._[0]; 36 | const to = argv.output; 37 | 38 | try { 39 | // this is where magic happens 40 | const css = await readFile(from); 41 | const result = await processor.process(css, { from, to, ...commonOptions }); 42 | result.warnings().forEach(w => console.warn(w.toString())); 43 | await writeResult(to, result); 44 | return 0; 45 | } catch (err) { 46 | dumpErrors(err); 47 | return 1; 48 | } 49 | } 50 | 51 | function writeResult(name, { css, map }) { 52 | const tasks = [writeFile(name, css)]; 53 | if (map) { 54 | tasks.push(writeFile(`${name}.map`, map.toString())); 55 | } 56 | return Promise.all(tasks); 57 | } 58 | 59 | function dumpErrors(err) { 60 | if (err.message && typeof err.showSourceCode === 'function') { 61 | console.error(err.message, err.showSourceCode()); 62 | } else { 63 | console.error(err); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "postcss-cli-simple", 3 | "version": "4.0.3", 4 | "description": "simple CLI for postcss", 5 | "main": "index.js", 6 | "bin": { 7 | "postcss": "bin/postcss" 8 | }, 9 | "scripts": { 10 | "test": "make check" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/pirxpilot/postcss-cli.git" 15 | }, 16 | "keywords": [ 17 | "postcss", 18 | "postcss-runner", 19 | "cli" 20 | ], 21 | "author": "Damian Krzeminski ", 22 | "license": "MIT", 23 | "dependencies": { 24 | "yargs-parser": "~18 || ~19 || ~20 || ~21" 25 | }, 26 | "peerDependencies": { 27 | "postcss": "~5 || ~6 || ~7 || ~8" 28 | }, 29 | "devDependencies": { 30 | "@pirxpilot/jshint": "~3", 31 | "postcss": "~8", 32 | "postcss-url": "~10" 33 | }, 34 | "files": [ 35 | "index.js", 36 | "bin", 37 | "lib" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /test/argv.js: -------------------------------------------------------------------------------- 1 | const test = require('node:test'); 2 | 3 | const argv = require('../lib/argv'); 4 | 5 | // trim and split as a bad approximation of converting commang line into array of strings 6 | function _(strings) { 7 | return strings[0].trim().split(/\s+/); 8 | } 9 | 10 | test('single plugin', function(t) { 11 | t.plan(5); 12 | 13 | const opts = argv(_`--use autoprefixer -o out.css in.css`); 14 | t.assert.deepEqual(opts.use, [ 'autoprefixer' ]); 15 | t.assert.equal(opts.output, 'out.css'); 16 | t.assert.deepEqual(opts._, [ 'in.css' ]); 17 | 18 | t.assert.equal(opts.version, undefined, 'should not have version'); 19 | t.assert.equal(opts.help, undefined, 'should not have tape'); 20 | }); 21 | 22 | test('syntax', function(t) { 23 | t.plan(1); 24 | 25 | const opts = argv(_` 26 | --use autoprefixer 27 | -s mysyntax 28 | --output out.css 29 | in.css 30 | `); 31 | 32 | t.assert.equal(opts.syntax, 'mysyntax'); 33 | }); 34 | 35 | test('parser', function(t) { 36 | t.plan(1); 37 | 38 | const opts = argv(_` 39 | --use autoprefixer 40 | -p myparser 41 | --output out.css 42 | in.css 43 | `); 44 | 45 | t.assert.equal(opts.parser, 'myparser'); 46 | }); 47 | 48 | test('stringifier', function(t) { 49 | t.plan(1); 50 | 51 | const opts = argv(_` 52 | --use autoprefixer 53 | --stringifier mystringifier 54 | --output out.css 55 | in.css 56 | `); 57 | 58 | t.assert.equal(opts.stringifier, 'mystringifier'); 59 | }); 60 | 61 | test('config .json', function(t) { 62 | t.plan(3); 63 | 64 | const opts = argv(_`--config test/fixtures/config-all.json in.css`); 65 | 66 | t.assert.deepEqual(opts.use, [ 'postcss-url' ]); 67 | t.assert.equal(opts.output, 'test/build/config-all.css'); 68 | t.assert.deepEqual(opts['postcss-url'], { url: 'inline' }); 69 | }); 70 | 71 | test('config .js', function(t) { 72 | t.plan(4); 73 | 74 | const opts = argv(_` 75 | --use postcss-url 76 | --output out.css 77 | --config test/fixtures/config.js 78 | in.css 79 | `); 80 | 81 | t.assert.deepEqual(opts.use, [ 'postcss-url' ]); 82 | t.assert.equal(opts.output, 'out.css'); 83 | 84 | t.assert.ok(opts['postcss-url'], 'opts should have `postcss-url` property'); 85 | t.assert.equal(typeof opts['postcss-url'].url, 'function'); 86 | }); 87 | 88 | test('multiple plugins with options', function(t) { 89 | t.plan(6); 90 | 91 | const opts = argv(_` 92 | --use postcss-url --postcss-url.url=rebase --postcss-url.assetPath /temp/example 93 | --use autoprefixer --autoprefixer.browsers >5% 94 | --use cssnano --no-cssnano.discardUnused 95 | --output out.css in.css 96 | `); 97 | 98 | t.assert.deepEqual(opts.use, [ 'postcss-url', 'autoprefixer', 'cssnano' ]); 99 | t.assert.deepEqual(opts.output, 'out.css'); 100 | t.assert.deepEqual(opts._, [ 'in.css' ]); 101 | 102 | t.assert.deepEqual(opts['postcss-url'], { url: 'rebase', assetPath: '/temp/example' }); 103 | t.assert.deepEqual(opts.autoprefixer, { browsers: '>5%' }); 104 | t.assert.deepEqual(opts.cssnano, { discardUnused: false }); 105 | }); 106 | -------------------------------------------------------------------------------- /test/cmd.js: -------------------------------------------------------------------------------- 1 | const test = require('node:test'); 2 | const assert = require('node:assert/strict'); 3 | 4 | const { promisify } = require('node:util'); 5 | const { exec: execCB } = require('node:child_process'); 6 | const { mkdir, rm, readFile } = require('node:fs/promises'); 7 | const { resolve } = require('node:path'); 8 | 9 | const exec = promisify(execCB); 10 | 11 | function c(strs) { 12 | return strs 13 | .map(s => s 14 | .replace('postcss', resolve(__dirname, '../bin/postcss')) 15 | .replace(/fixtures|ref|_build/g, p => resolve(__dirname, p)) 16 | ) 17 | .join(''); 18 | } 19 | 20 | function read(path) { 21 | return readFile(path, 'utf-8'); 22 | } 23 | 24 | test('cmd', async function (t) { 25 | 26 | t.before(function () { 27 | return mkdir(c`_build`, { recursive: true }); 28 | }); 29 | 30 | t.after(function () { 31 | return rm(c`_build`, { recursive: true }); 32 | }); 33 | 34 | await t.test('help', async function () { 35 | const { stdout, stderr } = await exec(c`postcss --help`); 36 | assert.equal(stderr, ''); 37 | assert.ok(stdout.includes('Usage:'), 'help needs to include Usage'); 38 | assert.ok(stdout.includes('Options:'), 'help needs to include Options'); 39 | assert.ok(stdout.includes('Examples:'), 'help needs to include Examples'); 40 | }); 41 | 42 | await t.test('version', async function () { 43 | const { stdout, stderr } = await exec(c`postcss --version`); 44 | assert.equal(stderr, ''); 45 | assert.match(stdout, /postcss version: \d+\.\d+\.\d+/, 'version of postcss is displayed'); 46 | }); 47 | 48 | await t.test('warning', async function () { 49 | const cmd = c` 50 | NODE_PATH=fixtures postcss --use dummy-plugin -o _build/warning.css fixtures/in-warning.css 51 | `; 52 | const { stdout, stderr } = await exec(cmd); 53 | assert.equal(stderr, c`dummy-plugin: fixtures/in-warning.css:1:1: Dummy warning\n`, 'should display warning'); 54 | assert.equal(stdout, '', 'should be empty'); 55 | }); 56 | 57 | await t.test('error', async function () { 58 | const cmd = c` 59 | NO_COLOR=1 \ 60 | NODE_PATH=fixtures \ 61 | postcss \ 62 | --use dummy-plugin \ 63 | --dummy-plugin.fail=true \ 64 | -o _build/invalid.css fixtures/in-force-error.css 65 | `; 66 | const { code, stderr, stdout } = await exec(cmd).catch(e => e); 67 | assert.equal(code, 1); 68 | assert.equal(stdout, '', 'should be empty'); 69 | assert.equal(stderr, c`dummy-plugin: fixtures/in-force-error.css:1:1: Dummy error > 1 | a { 70 | | ^ 71 | 2 | background: url(image.png); 72 | 3 | display: flex; 73 | ` 74 | , 'should display error'); 75 | }); 76 | 77 | await t.test('source-maps-file', async function () { 78 | const cmd = c` 79 | postcss -u postcss-url --postcss-url.url=rebase --map file -o _build/source-maps-file.css fixtures/in.css 80 | `; 81 | const expected = await read(c`ref/source-maps-file.css`); 82 | const expectedMap = await read(c`ref/source-maps-file.css.map`); 83 | const { stdout, stderr } = await exec(cmd); 84 | assert.equal(stderr, '', 'should be empty'); 85 | assert.equal(stdout, '', 'should be empty'); 86 | 87 | const output = await read(c`_build/source-maps-file.css`); 88 | assert.equal(output, expected, 'css is compiled'); 89 | 90 | const outputMap = await read(c`_build/source-maps-file.css.map`); 91 | assert.equal(outputMap, expectedMap, 'source map is emitted to a file'); 92 | 93 | }); 94 | 95 | await cliTest('opts', c`postcss --use -u postcss-url --postcss-url.url=rebase`); 96 | 97 | await cliTest('source-maps', c`postcss -u postcss-url --postcss-url.url=rebase --map`); 98 | 99 | await cliTest('config', c`postcss -u postcss-url -c fixtures/config.json`); 100 | 101 | await cliTest('config-all', c`postcss -c fixtures/config-all.json`); 102 | 103 | await cliTest('js-config', c`postcss -u postcss-url -c fixtures/config.js`); 104 | 105 | await cliTest('js-config-all', c`postcss -c fixtures/config-all.js`); 106 | 107 | async function cliTest(name, cmd, 108 | inpath = c`fixtures/in.css`, 109 | outpath = c`_build/` + `${name}.css`, 110 | refpath = outpath.replace('_build', 'ref') 111 | ) { 112 | await t.test(name, async function () { 113 | const expected = await read(refpath); 114 | const { stdout, stderr } = await exec(`${cmd} -o ${outpath} ${inpath}`); 115 | assert.equal(stderr, '', 'stderr should be empty'); 116 | assert.equal(stdout, '', 'stdout should be empty'); 117 | const output = await read(outpath); 118 | assert.equal(output, expected, 'css should be compiled'); 119 | }); 120 | } 121 | }); 122 | 123 | -------------------------------------------------------------------------------- /test/fixtures/config-all.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | use: "postcss-url", 3 | output: "test/build/js-config-all.css", 4 | "postcss-url": { 5 | url: function(opts) { return "http://example.com/" + opts.url; } 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /test/fixtures/config-all.json: -------------------------------------------------------------------------------- 1 | { 2 | "use": "postcss-url", 3 | "output": "test/build/config-all.css", 4 | "postcss-url": { 5 | "url": "inline" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "postcss-url": { 3 | url: ({ url }) => `http://example.com/${url}` 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /test/fixtures/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "postcss-url": { 3 | "url": "inline" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/fixtures/dummy-plugin.js: -------------------------------------------------------------------------------- 1 | module.exports = function() { 2 | return { 3 | postcssPlugin: 'dummy-plugin', 4 | Rule: function (rule, { result }) { 5 | if (rule.selector === 'a') { 6 | throw rule.error('Dummy error'); 7 | } 8 | if (rule.selector === 'figure') { 9 | result.warn('Dummy warning', { node: rule }); 10 | } 11 | } 12 | }; 13 | }; 14 | 15 | module.exports.postcss = true; 16 | -------------------------------------------------------------------------------- /test/fixtures/image.png: -------------------------------------------------------------------------------- 1 | not really an image 2 | -------------------------------------------------------------------------------- /test/fixtures/in-force-error.css: -------------------------------------------------------------------------------- 1 | a { 2 | background: url(image.png); 3 | display: flex; 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/in-warning.css: -------------------------------------------------------------------------------- 1 | figure { 2 | display: none; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/in.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: url(image.png); 3 | display: flex; 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/invalid.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: white; 3 | display: flex 4 | -------------------------------------------------------------------------------- /test/ref/config-all.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: url(data:image/png;base64,bm90IHJlYWxseSBhbiBpbWFnZQo=); 3 | display: flex; 4 | } 5 | -------------------------------------------------------------------------------- /test/ref/config.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: url(data:image/png;base64,bm90IHJlYWxseSBhbiBpbWFnZQo=); 3 | display: flex; 4 | } 5 | -------------------------------------------------------------------------------- /test/ref/js-config-all.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: url(http://example.com/image.png); 3 | display: flex; 4 | } 5 | -------------------------------------------------------------------------------- /test/ref/js-config.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: url(http://example.com/image.png); 3 | display: flex; 4 | } 5 | -------------------------------------------------------------------------------- /test/ref/opts.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: url(../fixtures/image.png); 3 | display: flex; 4 | } 5 | -------------------------------------------------------------------------------- /test/ref/replace.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: url(data:image/png;base64,bm90IHJlYWxseSBhbiBpbWFnZQo=); 3 | display: flex; 4 | } 5 | -------------------------------------------------------------------------------- /test/ref/safe.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: white; 3 | display: flex 4 | } -------------------------------------------------------------------------------- /test/ref/source-maps-file.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: url(../fixtures/image.png); 3 | display: flex; 4 | } 5 | 6 | /*# sourceMappingURL=source-maps-file.css.map */ -------------------------------------------------------------------------------- /test/ref/source-maps-file.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["../fixtures/in.css"],"names":[],"mappings":"AAAA;EACE,sCAA0B;EAC1B,aAAa;AACf","file":"source-maps-file.css","sourcesContent":["body {\n background: url(image.png);\n display: flex;\n}\n"]} -------------------------------------------------------------------------------- /test/ref/source-maps.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: url(../fixtures/image.png); 3 | display: flex; 4 | } 5 | 6 | /*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL2ZpeHR1cmVzL2luLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLHNDQUEwQjtFQUMxQixhQUFhO0FBQ2YiLCJmaWxlIjoic291cmNlLW1hcHMuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiYm9keSB7XG4gIGJhY2tncm91bmQ6IHVybChpbWFnZS5wbmcpO1xuICBkaXNwbGF5OiBmbGV4O1xufVxuIl19 */ --------------------------------------------------------------------------------