mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
commit
b8e7c12cfd
@ -3,6 +3,7 @@ import path from 'path'
|
||||
import cli from '../src/cli/main'
|
||||
import * as constants from '../src/constants'
|
||||
import * as utils from '../src/cli/utils'
|
||||
import runInTempDirectory from '../jest/runInTempDirectory'
|
||||
|
||||
describe('cli', () => {
|
||||
const inputCssPath = path.resolve(__dirname, 'fixtures/tailwind-input.css')
|
||||
@ -13,37 +14,30 @@ describe('cli', () => {
|
||||
beforeEach(() => {
|
||||
console.log = jest.fn()
|
||||
process.stdout.write = jest.fn()
|
||||
utils.writeFile = jest.fn()
|
||||
})
|
||||
|
||||
describe('init', () => {
|
||||
it('creates a Tailwind config file', () => {
|
||||
return cli(['init']).then(() => {
|
||||
expect(utils.writeFile.mock.calls[0][0]).toEqual(constants.defaultConfigFile)
|
||||
})
|
||||
})
|
||||
|
||||
it('creates a Tailwind config file in a custom location', () => {
|
||||
return cli(['init', 'custom.js']).then(() => {
|
||||
expect(utils.writeFile.mock.calls[0][0]).toEqual('custom.js')
|
||||
})
|
||||
})
|
||||
|
||||
it('creates a Tailwind config file without comments', () => {
|
||||
return cli(['init', '--no-comments']).then(() => {
|
||||
expect(utils.writeFile.mock.calls[0][1]).not.toContain('/**')
|
||||
})
|
||||
})
|
||||
|
||||
it('creates a simple Tailwind config file', () => {
|
||||
return cli(['init']).then(() => {
|
||||
expect(utils.writeFile.mock.calls[0][1]).toEqual(simpleConfigFixture)
|
||||
return runInTempDirectory(() => {
|
||||
return cli(['init']).then(() => {
|
||||
expect(utils.readFile(constants.defaultConfigFile)).toEqual(simpleConfigFixture)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('creates a full Tailwind config file', () => {
|
||||
return cli(['init', '--full']).then(() => {
|
||||
expect(utils.writeFile.mock.calls[0][1]).toEqual(defaultConfigFixture)
|
||||
return runInTempDirectory(() => {
|
||||
return cli(['init', '--full']).then(() => {
|
||||
expect(utils.readFile(constants.defaultConfigFile)).toEqual(defaultConfigFixture)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('creates a Tailwind config file in a custom location', () => {
|
||||
return runInTempDirectory(() => {
|
||||
return cli(['init', 'custom.js']).then(() => {
|
||||
expect(utils.exists('custom.js')).toEqual(true)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -62,9 +56,10 @@ describe('cli', () => {
|
||||
})
|
||||
|
||||
it('creates compiled CSS file', () => {
|
||||
return cli(['build', inputCssPath, '--output', 'output.css']).then(() => {
|
||||
expect(utils.writeFile.mock.calls[0][0]).toEqual('output.css')
|
||||
expect(utils.writeFile.mock.calls[0][1]).toContain('.example')
|
||||
return runInTempDirectory(() => {
|
||||
return cli(['build', inputCssPath, '--output', 'output.css']).then(() => {
|
||||
expect(utils.readFile('output.css')).toContain('.example')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@ -56,4 +56,18 @@ describe('cli utils', () => {
|
||||
expect(result).toEqual({ test: ['c', 'd', 'h'] })
|
||||
})
|
||||
})
|
||||
|
||||
describe('getSimplePath', () => {
|
||||
it('strips leading ./', () => {
|
||||
const result = utils.getSimplePath('./test')
|
||||
|
||||
expect(result).toEqual('test')
|
||||
})
|
||||
|
||||
it('returns unchanged path if it does not begin with ./', () => {
|
||||
const result = utils.getSimplePath('../test')
|
||||
|
||||
expect(result).toEqual('../test')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,21 +1,9 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import rimraf from 'rimraf'
|
||||
import postcss from 'postcss'
|
||||
import tailwind from '../src/index'
|
||||
import { defaultConfigFile } from '../src/constants'
|
||||
|
||||
function inTempDirectory(callback) {
|
||||
return new Promise(resolve => {
|
||||
rimraf.sync('./__tmp')
|
||||
fs.mkdirSync(path.resolve('./__tmp'))
|
||||
process.chdir(path.resolve('./__tmp'))
|
||||
callback().then(() => {
|
||||
process.chdir(path.resolve('../'))
|
||||
rimraf('./__tmp', resolve)
|
||||
})
|
||||
})
|
||||
}
|
||||
import inTempDirectory from '../jest/runInTempDirectory'
|
||||
|
||||
test('it uses the values from the custom config file', () => {
|
||||
return postcss([tailwind(path.resolve(`${__dirname}/fixtures/custom-config.js`))])
|
||||
|
||||
21
jest/runInTempDirectory.js
Normal file
21
jest/runInTempDirectory.js
Normal file
@ -0,0 +1,21 @@
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
import rimraf from 'rimraf'
|
||||
|
||||
const tmpPath = path.resolve(__dirname, '../__tmp')
|
||||
|
||||
export default function(callback) {
|
||||
return new Promise(resolve => {
|
||||
const currentPath = process.cwd()
|
||||
|
||||
rimraf.sync(tmpPath)
|
||||
fs.mkdirSync(tmpPath)
|
||||
process.chdir(tmpPath)
|
||||
|
||||
callback().then(() => {
|
||||
process.chdir(currentPath)
|
||||
rimraf(tmpPath, resolve)
|
||||
})
|
||||
})
|
||||
}
|
||||
46
src/cli/colors.js
Normal file
46
src/cli/colors.js
Normal file
@ -0,0 +1,46 @@
|
||||
import chalk from 'chalk'
|
||||
|
||||
/**
|
||||
* Applies colors to emphasize
|
||||
*
|
||||
* @param {...string} msgs
|
||||
*/
|
||||
export function bold(...msgs) {
|
||||
return chalk.bold(...msgs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies colors to inform
|
||||
*
|
||||
* @param {...string} msgs
|
||||
*/
|
||||
export function info(...msgs) {
|
||||
return chalk.bold.cyan(...msgs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies colors to signify error
|
||||
*
|
||||
* @param {...string} msgs
|
||||
*/
|
||||
export function error(...msgs) {
|
||||
return chalk.bold.red(...msgs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies colors to represent a command
|
||||
*
|
||||
* @param {...string} msgs
|
||||
*/
|
||||
export function command(...msgs) {
|
||||
return chalk.bold.magenta(...msgs)
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies colors to represent a file
|
||||
*
|
||||
* @param {...string} msgs
|
||||
*/
|
||||
export function file(...msgs) {
|
||||
return chalk.bold.magenta(...msgs)
|
||||
}
|
||||
@ -1,12 +1,12 @@
|
||||
import autoprefixer from 'autoprefixer'
|
||||
import bytes from 'bytes'
|
||||
import chalk from 'chalk'
|
||||
import prettyHrtime from 'pretty-hrtime'
|
||||
|
||||
import tailwind from '../..'
|
||||
|
||||
import commands from '.'
|
||||
import compile from '../compile'
|
||||
import * as colors from '../colors'
|
||||
import * as emoji from '../emoji'
|
||||
import * as utils from '../utils'
|
||||
|
||||
@ -75,9 +75,12 @@ function buildToStdout(compileOptions) {
|
||||
* @return {Promise}
|
||||
*/
|
||||
function buildToFile(compileOptions, startTime) {
|
||||
const inputFileSimplePath = utils.getSimplePath(compileOptions.inputFile)
|
||||
const outputFileSimplePath = utils.getSimplePath(compileOptions.outputFile)
|
||||
|
||||
utils.header()
|
||||
utils.log()
|
||||
utils.log(emoji.go, 'Building...', chalk.bold.cyan(compileOptions.inputFile))
|
||||
utils.log(emoji.go, 'Building...', colors.file(inputFileSimplePath))
|
||||
|
||||
return compile(compileOptions).then(result => {
|
||||
utils.writeFile(compileOptions.outputFile, result.css)
|
||||
@ -85,9 +88,9 @@ function buildToFile(compileOptions, startTime) {
|
||||
const prettyTime = prettyHrtime(process.hrtime(startTime))
|
||||
|
||||
utils.log()
|
||||
utils.log(emoji.yes, 'Finished in', chalk.bold.magenta(prettyTime))
|
||||
utils.log(emoji.pack, 'Size:', chalk.bold.magenta(bytes(result.css.length)))
|
||||
utils.log(emoji.disk, 'Saved to', chalk.bold.cyan(compileOptions.outputFile))
|
||||
utils.log(emoji.yes, 'Finished in', colors.info(prettyTime))
|
||||
utils.log(emoji.pack, 'Size:', colors.info(bytes(result.css.length)))
|
||||
utils.log(emoji.disk, 'Saved to', colors.file(outputFileSimplePath))
|
||||
utils.footer()
|
||||
})
|
||||
}
|
||||
@ -106,13 +109,15 @@ export function run(cliParams, cliOptions) {
|
||||
const configFile = cliOptions.config && cliOptions.config[0]
|
||||
const outputFile = cliOptions.output && cliOptions.output[0]
|
||||
const autoprefix = !cliOptions.noAutoprefixer
|
||||
const inputFileSimplePath = utils.getSimplePath(inputFile)
|
||||
const configFileSimplePath = utils.getSimplePath(configFile)
|
||||
|
||||
!inputFile && stopWithHelp('CSS file is required.')
|
||||
!utils.exists(inputFile) && stop(chalk.bold.magenta(inputFile), 'does not exist.')
|
||||
!utils.exists(inputFile) && stop(colors.file(inputFileSimplePath), 'does not exist.')
|
||||
|
||||
configFile &&
|
||||
!utils.exists(configFile) &&
|
||||
stop(chalk.bold.magenta(configFile), 'does not exist.')
|
||||
stop(colors.file(configFileSimplePath), 'does not exist.')
|
||||
|
||||
const compileOptions = {
|
||||
inputFile,
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import chalk from 'chalk'
|
||||
import { forEach, map, padEnd } from 'lodash'
|
||||
|
||||
import commands from '.'
|
||||
import * as constants from '../../constants'
|
||||
import * as colors from '../colors'
|
||||
import * as utils from '../utils'
|
||||
|
||||
export const usage = 'help [command]'
|
||||
@ -18,11 +18,11 @@ export function forApp() {
|
||||
|
||||
utils.log()
|
||||
utils.log('Usage:')
|
||||
utils.log(' ', chalk.bold(constants.cli + ' <command> [options]'))
|
||||
utils.log(' ', colors.bold(constants.cli + ' <command> [options]'))
|
||||
utils.log()
|
||||
utils.log('Commands:')
|
||||
forEach(commands, command => {
|
||||
utils.log(' ', chalk.bold(padEnd(command.usage, pad)), command.description)
|
||||
utils.log(' ', colors.bold(padEnd(command.usage, pad)), command.description)
|
||||
})
|
||||
}
|
||||
|
||||
@ -34,10 +34,10 @@ export function forApp() {
|
||||
export function forCommand(command) {
|
||||
utils.log()
|
||||
utils.log('Usage:')
|
||||
utils.log(' ', chalk.bold(constants.cli, command.usage))
|
||||
utils.log(' ', colors.bold(constants.cli, command.usage))
|
||||
utils.log()
|
||||
utils.log('Description:')
|
||||
utils.log(' ', chalk.bold(command.description))
|
||||
utils.log(' ', colors.bold(command.description))
|
||||
|
||||
if (command.options) {
|
||||
const pad = Math.max(...map(command.options, 'usage.length')) + PADDING_SIZE
|
||||
@ -45,7 +45,7 @@ export function forCommand(command) {
|
||||
utils.log()
|
||||
utils.log('Options:')
|
||||
forEach(command.options, option => {
|
||||
utils.log(' ', chalk.bold(padEnd(option.usage, pad)), option.description)
|
||||
utils.log(' ', colors.bold(padEnd(option.usage, pad)), option.description)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -56,7 +56,7 @@ export function forCommand(command) {
|
||||
* @param {string} commandName
|
||||
*/
|
||||
export function invalidCommand(commandName) {
|
||||
utils.error('Invalid command:', chalk.bold.magenta(commandName))
|
||||
utils.error('Invalid command:', colors.command(commandName))
|
||||
forApp()
|
||||
utils.die()
|
||||
}
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import chalk from 'chalk'
|
||||
|
||||
import * as constants from '../../constants'
|
||||
import * as colors from '../colors'
|
||||
import * as emoji from '../emoji'
|
||||
import * as utils from '../utils'
|
||||
|
||||
export const usage = 'init [file]'
|
||||
export const description =
|
||||
'Creates Tailwind config file. Default: ' + chalk.bold.magenta(constants.defaultConfigFile)
|
||||
'Creates Tailwind config file. Default: ' +
|
||||
colors.file(utils.getSimplePath(constants.defaultConfigFile))
|
||||
|
||||
export const options = [
|
||||
{
|
||||
@ -32,16 +32,16 @@ export function run(cliParams, cliOptions) {
|
||||
|
||||
const full = cliOptions.full
|
||||
const file = cliParams[0] || constants.defaultConfigFile
|
||||
const simplePath = utils.getSimplePath(file)
|
||||
|
||||
utils.exists(file) && utils.die(chalk.bold.magenta(file), 'already exists.')
|
||||
utils.exists(file) && utils.die(colors.file(simplePath), 'already exists.')
|
||||
|
||||
const stubFile = full ? constants.defaultConfigStubFile : constants.simpleConfigStubFile
|
||||
const stub = utils.readFile(stubFile)
|
||||
|
||||
utils.writeFile(file, stub)
|
||||
utils.copyFile(stubFile, file)
|
||||
|
||||
utils.log()
|
||||
utils.log(emoji.yes, 'Created Tailwind config file:', chalk.bold.magenta(file))
|
||||
utils.log(emoji.yes, 'Created Tailwind config file:', colors.file(simplePath))
|
||||
|
||||
utils.footer()
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import chalk from 'chalk'
|
||||
import { ensureFileSync, existsSync, outputFileSync, readFileSync } from 'fs-extra'
|
||||
import { findKey, mapValues, trimStart } from 'lodash'
|
||||
import { copyFileSync, ensureFileSync, existsSync, outputFileSync, readFileSync } from 'fs-extra'
|
||||
import { findKey, mapValues, startsWith, trimStart } from 'lodash'
|
||||
|
||||
import * as colors from './colors'
|
||||
import * as emoji from './emoji'
|
||||
import packageJson from '../../package.json'
|
||||
|
||||
@ -58,7 +58,7 @@ export function log(...msgs) {
|
||||
*/
|
||||
export function header() {
|
||||
log()
|
||||
log(chalk.bold(packageJson.name), chalk.bold.cyan(packageJson.version))
|
||||
log(colors.bold(packageJson.name), colors.info(packageJson.version))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,7 +75,7 @@ export function footer() {
|
||||
*/
|
||||
export function error(...msgs) {
|
||||
log()
|
||||
console.error(' ', emoji.no, chalk.bold.red(msgs.join(' ')))
|
||||
console.error(' ', emoji.no, colors.error(msgs.join(' ')))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,6 +99,16 @@ export function exists(path) {
|
||||
return existsSync(path)
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies file source to destination.
|
||||
*
|
||||
* @param {string} source
|
||||
* @param {string} destination
|
||||
*/
|
||||
export function copyFile(source, destination) {
|
||||
copyFileSync(source, destination)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets file content.
|
||||
*
|
||||
@ -121,3 +131,13 @@ export function writeFile(path, content) {
|
||||
|
||||
return outputFileSync(path, content)
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips leading ./ from path
|
||||
*
|
||||
* @param {string} path
|
||||
* @return {string}
|
||||
*/
|
||||
export function getSimplePath(path) {
|
||||
return startsWith(path, './') ? path.slice(2) : path
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user