Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: postcss/postcss-cli
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 35545bdb384d0e75ffa4385de960968f4a6cd28d
Choose a base ref
...
head repository: postcss/postcss-cli
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: e5419b5dd587f81a78acbc0f68b33efe150d9ef3
Choose a head ref
Loading
2 changes: 2 additions & 0 deletions .eslintrc.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
env:
node: true
parserOptions:
sourceType: module
extends: problems
rules:
no-console: off
22 changes: 22 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: 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
14 changes: 0 additions & 14 deletions .travis.yml

This file was deleted.

27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
# 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))
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[![npm][npm]][npm-url]
[![node][node]][node-url]
[![Greenkeeper badge](https://badges.greenkeeper.io/postcss/postcss-cli.svg)](https://greenkeeper.io/)
[![tests][tests]][tests-url]
[![cover][cover]][cover-url]
[![chat][chat]][chat-url]
@@ -98,7 +97,7 @@ Note that you **can not** set the `from` or `to` options for postcss in the conf

### Context

For more advanced usage it's recommend to to use a function in `postcss.config.js`, this gives you access to the CLI context to dynamically apply options and plugins **per file**
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 |
| :-------: | :--------: | :--------------------------------: | :------------------- |
@@ -142,8 +141,8 @@ module.exports = (ctx) => ({
[npm-url]: https://npmjs.com/package/postcss-cli
[node]: https://img.shields.io/node/v/postcss-cli.svg
[node-url]: https://nodejs.org/
[tests]: http://img.shields.io/travis/postcss/postcss-cli/master.svg
[tests-url]: https://travis-ci.org/postcss/postcss-cli
[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
3 changes: 0 additions & 3 deletions bin/postcss

This file was deleted.

150 changes: 99 additions & 51 deletions index.js
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,49 +1,59 @@
'use strict'

const fs = require('fs-extra')
const path = require('path')

const prettyHrtime = require('pretty-hrtime')
const stdin = require('get-stdin')
const read = require('read-cache')
const chalk = require('chalk')
const globber = require('globby')
const slash = require('slash')
const chokidar = require('chokidar')

const postcss = require('postcss')
const postcssrc = require('postcss-load-config')
const reporter = require('postcss-reporter/lib/formatter')()

const argv = require('./lib/args')
const createDependencyGraph = require('./lib/DependencyGraph')
const getMapfile = require('./lib/getMapfile')
#!/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 }

const cliConfig = {
options: {
map: argv.map !== undefined ? argv.map : { inline: true },
parser: argv.parser ? require(argv.parser) : undefined,
syntax: argv.syntax ? require(argv.syntax) : undefined,
stringifier: argv.stringifier ? require(argv.stringifier) : undefined,
},
plugins: argv.use
? argv.use.map((plugin) => {
try {
return require(plugin)()
} 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 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
@@ -61,14 +71,16 @@ if (parseInt(postcss().version) < 8) {
error('Please install PostCSS 8 or above')
}

Promise.resolve()
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 globber(
return globby(
input.map((i) => slash(String(i))),
{ dot: argv.includeDotfiles }
)
@@ -106,7 +118,7 @@ Promise.resolve()
.then((results) => {
if (argv.watch) {
const printMessage = () =>
printVerbose(chalk.dim('\nWaiting for file changes...'))
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,
@@ -123,13 +135,17 @@ Promise.resolve()

if (input.includes(file)) recompile.push(file)

const dependants = depGraph
.dependantsOf(file)
.concat(getAncestorDirs(file).flatMap(depGraph.dependantsOf))

recompile = recompile.concat(
depGraph.dependantsOf(file).filter((file) => input.includes(file))
dependants.filter((file) => input.includes(file))
)

if (!recompile.length) recompile = input

return files(recompile)
return files([...new Set(recompile)])
.then((results) => watcher.add(dependencies(results)))
.then(printMessage)
.catch(error)
@@ -197,7 +213,7 @@ function css(css, file) {

const time = process.hrtime()

printVerbose(chalk`{cyan Processing {bold ${relativePath}}...}`)
printVerbose(pc.cyan(`Processing ${pc.bold(relativePath)}...`))

return rc(ctx, argv.config)
.then((config) => {
@@ -234,18 +250,20 @@ function css(css, file) {
const tasks = []

if (options.to) {
tasks.push(fs.outputFile(options.to, result.css))
tasks.push(outputFile(options.to, result.css))

if (result.map) {
const mapfile = getMapfile(options)
tasks.push(fs.outputFile(mapfile, result.map.toString()))
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(
chalk`{green Finished {bold ${relativePath}} in {bold ${prettyTime}}}`
pc.green(
`Finished ${pc.bold(relativePath)} in ${pc.bold(prettyTime)}`
)
)

const messages = result.warnings()
@@ -260,6 +278,13 @@ function css(css, file) {
.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) {
@@ -271,9 +296,21 @@ function dependencies(results) {
if (result.messages <= 0) return

result.messages
.filter((msg) => (msg.type === 'dependency' ? msg : ''))
.filter((msg) =>
msg.type === 'dependency' || msg.type === 'dir-dependency' ? msg : ''
)
.map(depGraph.add)
.forEach((dependency) => messages.push(dependency.file))
.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
@@ -288,7 +325,7 @@ function error(err) {
if (argv.verbose) console.error()

if (typeof err === 'string') {
console.error(chalk.red(err))
console.error(pc.red(err))
} else if (err.name === 'CssSyntaxError') {
console.error(err.toString())
} else {
@@ -298,3 +335,14 @@ function error(err) {
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)]
}
22 changes: 14 additions & 8 deletions lib/DependencyGraph.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
'use strict'
const path = require('path')
const { DepGraph } = require('dependency-graph')
import path from 'path'
import { DepGraph } from 'dependency-graph'

module.exports = function () {
export default function createDependencyGraph() {
const graph = new DepGraph()
return {
add(message) {
message.parent = path.resolve(message.parent)
message.file = path.resolve(message.file)

graph.addNode(message.parent)
graph.addNode(message.file)
graph.addDependency(message.parent, message.file)

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) {
7 changes: 3 additions & 4 deletions lib/DependencyGraph.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict'
const test = require('ava')
const path = require('path')
const createDependencyGraph = require('./DependencyGraph.js')
import test from 'ava'
import path from 'path'
import createDependencyGraph from './DependencyGraph.js'

function resolveArray(arr) {
return arr.map((p) => path.resolve(p))
Loading