#!/usr/bin/env node 'use strict' const path = require('path') const fs = require('fs') const picocolors = require('picocolors') const postcss = require('postcss') const rtlcss = require('../lib/rtlcss.js') const configLoader = require('../lib/config-loader.js') const { version, bugs } = require('../package.json') const HELP_TEXT = `Usage: rtlcss [option option=parameter ...] [source] [destination] Option Description -------------- ---------------------------------------------- -h,--help Print help (this message) and exit. -v,--version Print version number and exit. -c,--config Path to configuration settings file. - ,--stdin Read from stdin stream. -d,--directory Process all *.css files from input directory (recursive). -e,--ext Used with -d option to set the output files extension. Default: ".rtl.css". -s,--silent Silent mode, no warnings or errors are printed. *If no destination is specified, output will be written to the same input folder as {source}.rtl.{ext} ` let input, output, directory, ext, config, currentErrorcode, arg const args = process.argv.slice(2) let shouldBreak = false process.on('exit', () => { process.reallyExit(currentErrorcode) }) function printWarning (...args) { console.warn(picocolors.yellow(...args)) } function printInfo (...args) { console.info(picocolors.green(...args)) } function printError (...args) { console.error(picocolors.red(...args)) } function printHelp () { console.log(HELP_TEXT) printInfo(`RTLCSS version: ${version}`) printInfo(`Report issues to: ${bugs.url}`) } while ((arg = args.shift())) { switch (arg) { case '-h': case '--help': printHelp() shouldBreak = true break case '-v': case '--version': printInfo(`rtlcss version: ${version}`) shouldBreak = true break case '-c': case '--config': arg = args.shift() try { config = configLoader.load(path.resolve(arg)) } catch (e) { printError('rtlcss: invalid config file. ', e) shouldBreak = true currentErrorcode = 1 } break case '-d': case '--directory': directory = true break case '-e': case '--ext': ext = args.shift() break case '-s': case '--silent': console.log = console.info = console.warn = () => {} break case '-': case '--stdin': input = '-' break default: if (arg[0] === '-') { printError(`rtlcss: unknown option. ${arg}`) shouldBreak = true } else if (!input) { input = path.resolve(arg) } else if (!output) { output = path.resolve(arg) } break } } if (!shouldBreak) { if (!directory && !input) { printError('rtlcss: no input file') console.log('') printHelp() shouldBreak = true } if (!config && input !== '-') { try { let cwd = input if (directory !== true) { cwd = path.dirname(input) } config = configLoader.load(null, cwd) } catch (e) { printError('rtlcss: invalid config file. ', e) currentErrorcode = 1 shouldBreak = true } } } if (!shouldBreak) { if (!output && input !== '-') { if (directory !== true) { const extension = path.extname(input) output = extension ? input.replace(extension, `.rtl${extension}`) : `${input}.rtl` } else { output = input } } const processCSSFile = (error, data, outputName) => { if (error) { printError(`rtlcss: ${error.message}`) return } let result const opt = { map: false } if (input !== '-') { opt.from = input opt.to = output } if (!config) { printWarning('rtlcss: Warning! No config present, using defaults.') result = postcss([rtlcss]).process(data, opt) } else { if ('map' in config === true && input !== '-') { opt.map = config.map } result = postcss([rtlcss.configure(config)]).process(data, opt) } if (output) { let savePath = outputName if (directory !== true) { savePath = output } printInfo('Saving:', savePath) fs.writeFile(savePath, result.css, (err) => { if (err) printError(err) }) if (result.map) { fs.writeFile(`${savePath}.map`, result.map, (err) => { if (err) printError(err) }) } } else { process.stdout.write(`${result.css}\n`) } } const walk = (dir, done) => { fs.readdir(dir, (error, list) => { if (error) { return done(error) } let i = 0; (function next () { let file = list[i++] if (!file) { return done(null) } file = dir + path.sep + file fs.stat(file, (err, stat) => { if (err) { printError(err) } else if (stat && stat.isDirectory()) { walk(file, (err) => { if (err) { printError(err) } else { next() } }) } else { // process only *.css files if (file.endsWith('.css')) { // compute output directory const relativePath = path.relative(input, file).split(path.sep) relativePath.pop() relativePath.push(path.basename(file).replace('.css', ext || '.rtl.css')) // set rtl filename const rtlFile = path.join(output, relativePath.join(path.sep)) // create output directory if it does not exist const dirName = path.dirname(rtlFile) if (!fs.existsSync(dirName)) { fs.mkdirSync(dirName, { recursive: true }) } // read and process the file. fs.readFile(file, 'utf8', (e, data) => { try { processCSSFile(e, data, rtlFile) } catch (e) { printError('rtlcss: error processing file', file) printError(e) } }) } next() } }) })() }) } if (input !== '-') { if (directory !== true) { fs.stat(input, (error, stat) => { if (error) { printError(error) } else if (stat && stat.isDirectory()) { printError('rtlcss: Input expected to be a file, use the -d option to process a directory.') } else { fs.readFile(input, 'utf8', (e, data) => { try { processCSSFile(e, data) } catch (e) { printError('rtlcss: error processing file', input) printError(e) } }) } }) } else { walk(input, (error) => { if (error) { printError(`rtlcss: ${error}`) } }) } } else { process.stdin.resume() process.stdin.setEncoding('utf8') let buffer = '' process.stdin.on('data', (data) => { buffer += data }) process.on('SIGINT', () => { processCSSFile(false, buffer) process.exit() }) process.stdin.on('end', () => { processCSSFile(false, buffer) }) } }