Skip to content

Commit 26e4007

Browse files
committed
Few CLI tweaks
1 parent 9fa57ab commit 26e4007

File tree

9 files changed

+152
-63
lines changed

9 files changed

+152
-63
lines changed

__tests__/cli.test.js

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import path from 'path'
33
import cli from '../src/cli/main'
44
import * as constants from '../src/constants'
55
import * as utils from '../src/cli/utils'
6+
import runInTempDirectory from '../jest/runInTempDirectory'
67

78
describe('cli', () => {
89
const inputCssPath = path.resolve(__dirname, 'fixtures/tailwind-input.css')
@@ -13,37 +14,30 @@ describe('cli', () => {
1314
beforeEach(() => {
1415
console.log = jest.fn()
1516
process.stdout.write = jest.fn()
16-
utils.writeFile = jest.fn()
1717
})
1818

1919
describe('init', () => {
2020
it('creates a Tailwind config file', () => {
21-
return cli(['init']).then(() => {
22-
expect(utils.writeFile.mock.calls[0][0]).toEqual(constants.defaultConfigFile)
21+
return runInTempDirectory(() => {
22+
return cli(['init']).then(() => {
23+
expect(utils.readFile(constants.defaultConfigFile)).toEqual(simpleConfigFixture)
24+
})
2325
})
2426
})
2527

26-
it('creates a Tailwind config file in a custom location', () => {
27-
return cli(['init', 'custom.js']).then(() => {
28-
expect(utils.writeFile.mock.calls[0][0]).toEqual('custom.js')
29-
})
30-
})
31-
32-
it('creates a Tailwind config file without comments', () => {
33-
return cli(['init', '--no-comments']).then(() => {
34-
expect(utils.writeFile.mock.calls[0][1]).not.toContain('/**')
35-
})
36-
})
37-
38-
it('creates a simple Tailwind config file', () => {
39-
return cli(['init']).then(() => {
40-
expect(utils.writeFile.mock.calls[0][1]).toEqual(simpleConfigFixture)
28+
it('creates a full Tailwind config file', () => {
29+
return runInTempDirectory(() => {
30+
return cli(['init', '--full']).then(() => {
31+
expect(utils.readFile(constants.defaultConfigFile)).toEqual(defaultConfigFixture)
32+
})
4133
})
4234
})
4335

44-
it('creates a full Tailwind config file', () => {
45-
return cli(['init', '--full']).then(() => {
46-
expect(utils.writeFile.mock.calls[0][1]).toEqual(defaultConfigFixture)
36+
it('creates a Tailwind config file in a custom location', () => {
37+
return runInTempDirectory(() => {
38+
return cli(['init', 'custom.js']).then(() => {
39+
expect(utils.exists('custom.js')).toEqual(true)
40+
})
4741
})
4842
})
4943
})
@@ -62,9 +56,10 @@ describe('cli', () => {
6256
})
6357

6458
it('creates compiled CSS file', () => {
65-
return cli(['build', inputCssPath, '--output', 'output.css']).then(() => {
66-
expect(utils.writeFile.mock.calls[0][0]).toEqual('output.css')
67-
expect(utils.writeFile.mock.calls[0][1]).toContain('.example')
59+
return runInTempDirectory(() => {
60+
return cli(['build', inputCssPath, '--output', 'output.css']).then(() => {
61+
expect(utils.readFile('output.css')).toContain('.example')
62+
})
6863
})
6964
})
7065

__tests__/cli.utils.test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,18 @@ describe('cli utils', () => {
5656
expect(result).toEqual({ test: ['c', 'd', 'h'] })
5757
})
5858
})
59+
60+
describe('getSimplePath', () => {
61+
it('strips leading ./', () => {
62+
const result = utils.getSimplePath('./test')
63+
64+
expect(result).toEqual('test')
65+
})
66+
67+
it('returns unchanged path if it does not begin with ./', () => {
68+
const result = utils.getSimplePath('../test')
69+
70+
expect(result).toEqual('../test')
71+
})
72+
})
5973
})

__tests__/customConfig.test.js

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,9 @@
11
import fs from 'fs'
22
import path from 'path'
3-
import rimraf from 'rimraf'
43
import postcss from 'postcss'
54
import tailwind from '../src/index'
65
import { defaultConfigFile } from '../src/constants'
7-
8-
function inTempDirectory(callback) {
9-
return new Promise(resolve => {
10-
rimraf.sync('./__tmp')
11-
fs.mkdirSync(path.resolve('./__tmp'))
12-
process.chdir(path.resolve('./__tmp'))
13-
callback().then(() => {
14-
process.chdir(path.resolve('../'))
15-
rimraf('./__tmp', resolve)
16-
})
17-
})
18-
}
6+
import inTempDirectory from '../jest/runInTempDirectory'
197

208
test('it uses the values from the custom config file', () => {
219
return postcss([tailwind(path.resolve(`${__dirname}/fixtures/custom-config.js`))])

jest/runInTempDirectory.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import fs from 'fs'
2+
import path from 'path'
3+
4+
import rimraf from 'rimraf'
5+
6+
const tmpPath = path.resolve(__dirname, '../__tmp')
7+
8+
export default function(callback) {
9+
return new Promise(resolve => {
10+
const currentPath = process.cwd()
11+
12+
rimraf.sync(tmpPath)
13+
fs.mkdirSync(tmpPath)
14+
process.chdir(tmpPath)
15+
16+
callback().then(() => {
17+
process.chdir(currentPath)
18+
rimraf(tmpPath, resolve)
19+
})
20+
})
21+
}

src/cli/colors.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import chalk from 'chalk'
2+
3+
/**
4+
* Applies colors to emphasize
5+
*
6+
* @param {...string} msgs
7+
*/
8+
export function bold(...msgs) {
9+
return chalk.bold(...msgs)
10+
}
11+
12+
/**
13+
* Applies colors to inform
14+
*
15+
* @param {...string} msgs
16+
*/
17+
export function info(...msgs) {
18+
return chalk.bold.cyan(...msgs)
19+
}
20+
21+
/**
22+
* Applies colors to signify error
23+
*
24+
* @param {...string} msgs
25+
*/
26+
export function error(...msgs) {
27+
return chalk.bold.red(...msgs)
28+
}
29+
30+
/**
31+
* Applies colors to represent a command
32+
*
33+
* @param {...string} msgs
34+
*/
35+
export function command(...msgs) {
36+
return chalk.bold.magenta(...msgs)
37+
}
38+
39+
/**
40+
* Applies colors to represent a file
41+
*
42+
* @param {...string} msgs
43+
*/
44+
export function file(...msgs) {
45+
return chalk.bold.magenta(...msgs)
46+
}

src/cli/commands/build.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import autoprefixer from 'autoprefixer'
22
import bytes from 'bytes'
3-
import chalk from 'chalk'
43
import prettyHrtime from 'pretty-hrtime'
54

65
import tailwind from '../..'
76

87
import commands from '.'
98
import compile from '../compile'
9+
import * as colors from '../colors'
1010
import * as emoji from '../emoji'
1111
import * as utils from '../utils'
1212

@@ -75,19 +75,22 @@ function buildToStdout(compileOptions) {
7575
* @return {Promise}
7676
*/
7777
function buildToFile(compileOptions, startTime) {
78+
const inputFileSimplePath = utils.getSimplePath(compileOptions.inputFile)
79+
const outputFileSimplePath = utils.getSimplePath(compileOptions.outputFile)
80+
7881
utils.header()
7982
utils.log()
80-
utils.log(emoji.go, 'Building...', chalk.bold.cyan(compileOptions.inputFile))
83+
utils.log(emoji.go, 'Building...', colors.file(inputFileSimplePath))
8184

8285
return compile(compileOptions).then(result => {
8386
utils.writeFile(compileOptions.outputFile, result.css)
8487

8588
const prettyTime = prettyHrtime(process.hrtime(startTime))
8689

8790
utils.log()
88-
utils.log(emoji.yes, 'Finished in', chalk.bold.magenta(prettyTime))
89-
utils.log(emoji.pack, 'Size:', chalk.bold.magenta(bytes(result.css.length)))
90-
utils.log(emoji.disk, 'Saved to', chalk.bold.cyan(compileOptions.outputFile))
91+
utils.log(emoji.yes, 'Finished in', colors.info(prettyTime))
92+
utils.log(emoji.pack, 'Size:', colors.info(bytes(result.css.length)))
93+
utils.log(emoji.disk, 'Saved to', colors.file(outputFileSimplePath))
9194
utils.footer()
9295
})
9396
}
@@ -106,13 +109,15 @@ export function run(cliParams, cliOptions) {
106109
const configFile = cliOptions.config && cliOptions.config[0]
107110
const outputFile = cliOptions.output && cliOptions.output[0]
108111
const autoprefix = !cliOptions.noAutoprefixer
112+
const inputFileSimplePath = utils.getSimplePath(inputFile)
113+
const configFileSimplePath = utils.getSimplePath(configFile)
109114

110115
!inputFile && stopWithHelp('CSS file is required.')
111-
!utils.exists(inputFile) && stop(chalk.bold.magenta(inputFile), 'does not exist.')
116+
!utils.exists(inputFile) && stop(colors.file(inputFileSimplePath), 'does not exist.')
112117

113118
configFile &&
114119
!utils.exists(configFile) &&
115-
stop(chalk.bold.magenta(configFile), 'does not exist.')
120+
stop(colors.file(configFileSimplePath), 'does not exist.')
116121

117122
const compileOptions = {
118123
inputFile,

src/cli/commands/help.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import chalk from 'chalk'
21
import { forEach, map, padEnd } from 'lodash'
32

43
import commands from '.'
54
import * as constants from '../../constants'
5+
import * as colors from '../colors'
66
import * as utils from '../utils'
77

88
export const usage = 'help [command]'
@@ -18,11 +18,11 @@ export function forApp() {
1818

1919
utils.log()
2020
utils.log('Usage:')
21-
utils.log(' ', chalk.bold(constants.cli + ' <command> [options]'))
21+
utils.log(' ', colors.bold(constants.cli + ' <command> [options]'))
2222
utils.log()
2323
utils.log('Commands:')
2424
forEach(commands, command => {
25-
utils.log(' ', chalk.bold(padEnd(command.usage, pad)), command.description)
25+
utils.log(' ', colors.bold(padEnd(command.usage, pad)), command.description)
2626
})
2727
}
2828

@@ -34,18 +34,18 @@ export function forApp() {
3434
export function forCommand(command) {
3535
utils.log()
3636
utils.log('Usage:')
37-
utils.log(' ', chalk.bold(constants.cli, command.usage))
37+
utils.log(' ', colors.bold(constants.cli, command.usage))
3838
utils.log()
3939
utils.log('Description:')
40-
utils.log(' ', chalk.bold(command.description))
40+
utils.log(' ', colors.bold(command.description))
4141

4242
if (command.options) {
4343
const pad = Math.max(...map(command.options, 'usage.length')) + PADDING_SIZE
4444

4545
utils.log()
4646
utils.log('Options:')
4747
forEach(command.options, option => {
48-
utils.log(' ', chalk.bold(padEnd(option.usage, pad)), option.description)
48+
utils.log(' ', colors.bold(padEnd(option.usage, pad)), option.description)
4949
})
5050
}
5151
}
@@ -56,7 +56,7 @@ export function forCommand(command) {
5656
* @param {string} commandName
5757
*/
5858
export function invalidCommand(commandName) {
59-
utils.error('Invalid command:', chalk.bold.magenta(commandName))
59+
utils.error('Invalid command:', colors.command(commandName))
6060
forApp()
6161
utils.die()
6262
}

src/cli/commands/init.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import chalk from 'chalk'
2-
31
import * as constants from '../../constants'
2+
import * as colors from '../colors'
43
import * as emoji from '../emoji'
54
import * as utils from '../utils'
65

76
export const usage = 'init [file]'
87
export const description =
9-
'Creates Tailwind config file. Default: ' + chalk.bold.magenta(constants.defaultConfigFile)
8+
'Creates Tailwind config file. Default: ' +
9+
colors.file(utils.getSimplePath(constants.defaultConfigFile))
1010

1111
export const options = [
1212
{
@@ -32,16 +32,16 @@ export function run(cliParams, cliOptions) {
3232

3333
const full = cliOptions.full
3434
const file = cliParams[0] || constants.defaultConfigFile
35+
const simplePath = utils.getSimplePath(file)
3536

36-
utils.exists(file) && utils.die(chalk.bold.magenta(file), 'already exists.')
37+
utils.exists(file) && utils.die(colors.file(simplePath), 'already exists.')
3738

3839
const stubFile = full ? constants.defaultConfigStubFile : constants.simpleConfigStubFile
39-
const stub = utils.readFile(stubFile)
4040

41-
utils.writeFile(file, stub)
41+
utils.copyFile(stubFile, file)
4242

4343
utils.log()
44-
utils.log(emoji.yes, 'Created Tailwind config file:', chalk.bold.magenta(file))
44+
utils.log(emoji.yes, 'Created Tailwind config file:', colors.file(simplePath))
4545

4646
utils.footer()
4747

src/cli/utils.js

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import chalk from 'chalk'
2-
import { ensureFileSync, existsSync, outputFileSync, readFileSync } from 'fs-extra'
3-
import { findKey, mapValues, trimStart } from 'lodash'
1+
import { copyFileSync, ensureFileSync, existsSync, outputFileSync, readFileSync } from 'fs-extra'
2+
import { findKey, mapValues, startsWith, trimStart } from 'lodash'
43

4+
import * as colors from './colors'
55
import * as emoji from './emoji'
66
import packageJson from '../../package.json'
77

@@ -58,7 +58,7 @@ export function log(...msgs) {
5858
*/
5959
export function header() {
6060
log()
61-
log(chalk.bold(packageJson.name), chalk.bold.cyan(packageJson.version))
61+
log(colors.bold(packageJson.name), colors.info(packageJson.version))
6262
}
6363

6464
/**
@@ -75,7 +75,7 @@ export function footer() {
7575
*/
7676
export function error(...msgs) {
7777
log()
78-
console.error(' ', emoji.no, chalk.bold.red(msgs.join(' ')))
78+
console.error(' ', emoji.no, colors.error(msgs.join(' ')))
7979
}
8080

8181
/**
@@ -99,6 +99,16 @@ export function exists(path) {
9999
return existsSync(path)
100100
}
101101

102+
/**
103+
* Copies file source to destination.
104+
*
105+
* @param {string} source
106+
* @param {string} destination
107+
*/
108+
export function copyFile(source, destination) {
109+
copyFileSync(source, destination)
110+
}
111+
102112
/**
103113
* Gets file content.
104114
*
@@ -121,3 +131,13 @@ export function writeFile(path, content) {
121131

122132
return outputFileSync(path, content)
123133
}
134+
135+
/**
136+
* Strips leading ./ from path
137+
*
138+
* @param {string} path
139+
* @return {string}
140+
*/
141+
export function getSimplePath(path) {
142+
return startsWith(path, './') ? path.slice(2) : path
143+
}

0 commit comments

Comments
 (0)