2022-01-21 08:28:41 +00:00
|
|
|
#!/usr/bin/env node
|
|
|
|
|
2022-06-08 10:36:39 +00:00
|
|
|
'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))
|
2022-01-21 08:28:41 +00:00
|
|
|
}
|
|
|
|
|
2022-06-08 10:36:39 +00:00
|
|
|
function printInfo (...args) {
|
|
|
|
console.info(picocolors.green(...args))
|
2022-01-21 08:28:41 +00:00
|
|
|
}
|
|
|
|
|
2022-06-08 10:36:39 +00:00
|
|
|
function printError (...args) {
|
|
|
|
console.error(picocolors.red(...args))
|
2022-01-21 08:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function printHelp () {
|
2022-06-08 10:36:39 +00:00
|
|
|
console.log(HELP_TEXT)
|
|
|
|
|
|
|
|
printInfo(`RTLCSS version: ${version}`)
|
|
|
|
printInfo(`Report issues to: ${bugs.url}`)
|
2022-01-21 08:28:41 +00:00
|
|
|
}
|
2022-06-08 10:36:39 +00:00
|
|
|
|
2022-01-21 08:28:41 +00:00
|
|
|
while ((arg = args.shift())) {
|
|
|
|
switch (arg) {
|
|
|
|
case '-h':
|
|
|
|
case '--help':
|
|
|
|
printHelp()
|
|
|
|
shouldBreak = true
|
|
|
|
break
|
|
|
|
case '-v':
|
|
|
|
case '--version':
|
2022-06-08 10:36:39 +00:00
|
|
|
printInfo(`rtlcss version: ${version}`)
|
2022-01-21 08:28:41 +00:00
|
|
|
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':
|
2022-06-08 10:36:39 +00:00
|
|
|
console.log = console.info = console.warn = () => {}
|
2022-01-21 08:28:41 +00:00
|
|
|
break
|
|
|
|
case '-':
|
|
|
|
case '--stdin':
|
|
|
|
input = '-'
|
|
|
|
break
|
|
|
|
default:
|
|
|
|
if (arg[0] === '-') {
|
2022-06-08 10:36:39 +00:00
|
|
|
printError(`rtlcss: unknown option. ${arg}`)
|
2022-01-21 08:28:41 +00:00
|
|
|
shouldBreak = true
|
2022-06-08 10:36:39 +00:00
|
|
|
} else if (!input) {
|
|
|
|
input = path.resolve(arg)
|
|
|
|
} else if (!output) {
|
|
|
|
output = path.resolve(arg)
|
2022-01-21 08:28:41 +00:00
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!shouldBreak) {
|
|
|
|
if (!directory && !input) {
|
|
|
|
printError('rtlcss: no input file')
|
|
|
|
console.log('')
|
|
|
|
printHelp()
|
|
|
|
shouldBreak = true
|
|
|
|
}
|
|
|
|
if (!config && input !== '-') {
|
|
|
|
try {
|
2022-06-08 10:36:39 +00:00
|
|
|
let cwd = input
|
2022-01-21 08:28:41 +00:00
|
|
|
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) {
|
2022-06-08 10:36:39 +00:00
|
|
|
const extension = path.extname(input)
|
|
|
|
output = extension ? input.replace(extension, `.rtl${extension}`) : `${input}.rtl`
|
2022-01-21 08:28:41 +00:00
|
|
|
} else {
|
|
|
|
output = input
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-08 10:36:39 +00:00
|
|
|
const processCSSFile = (error, data, outputName) => {
|
|
|
|
if (error) {
|
|
|
|
printError(`rtlcss: ${error.message}`)
|
2022-01-21 08:28:41 +00:00
|
|
|
return
|
|
|
|
}
|
2022-06-08 10:36:39 +00:00
|
|
|
|
|
|
|
let result
|
|
|
|
const opt = { map: false }
|
|
|
|
|
2022-01-21 08:28:41 +00:00
|
|
|
if (input !== '-') {
|
|
|
|
opt.from = input
|
|
|
|
opt.to = output
|
|
|
|
}
|
2022-06-08 10:36:39 +00:00
|
|
|
|
2022-01-21 08:28:41 +00:00
|
|
|
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
|
|
|
|
}
|
2022-06-08 10:36:39 +00:00
|
|
|
|
2022-01-21 08:28:41 +00:00
|
|
|
result = postcss([rtlcss.configure(config)]).process(data, opt)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (output) {
|
2022-06-08 10:36:39 +00:00
|
|
|
let savePath = outputName
|
2022-01-21 08:28:41 +00:00
|
|
|
if (directory !== true) {
|
|
|
|
savePath = output
|
|
|
|
}
|
2022-06-08 10:36:39 +00:00
|
|
|
|
2022-01-21 08:28:41 +00:00
|
|
|
printInfo('Saving:', savePath)
|
2022-06-08 10:36:39 +00:00
|
|
|
|
|
|
|
fs.writeFile(savePath, result.css, (err) => {
|
|
|
|
if (err) printError(err)
|
|
|
|
})
|
|
|
|
|
2022-01-21 08:28:41 +00:00
|
|
|
if (result.map) {
|
2022-06-08 10:36:39 +00:00
|
|
|
fs.writeFile(`${savePath}.map`, result.map, (err) => {
|
|
|
|
if (err) printError(err)
|
|
|
|
})
|
2022-01-21 08:28:41 +00:00
|
|
|
}
|
|
|
|
} else {
|
2022-06-08 10:36:39 +00:00
|
|
|
process.stdout.write(`${result.css}\n`)
|
2022-01-21 08:28:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-08 10:36:39 +00:00
|
|
|
const walk = (dir, done) => {
|
|
|
|
fs.readdir(dir, (error, list) => {
|
2022-01-21 08:28:41 +00:00
|
|
|
if (error) {
|
|
|
|
return done(error)
|
|
|
|
}
|
2022-06-08 10:36:39 +00:00
|
|
|
|
|
|
|
let i = 0;
|
|
|
|
(function next () {
|
|
|
|
let file = list[i++]
|
2022-01-21 08:28:41 +00:00
|
|
|
if (!file) {
|
|
|
|
return done(null)
|
|
|
|
}
|
2022-06-08 10:36:39 +00:00
|
|
|
|
2022-01-21 08:28:41 +00:00
|
|
|
file = dir + path.sep + file
|
2022-06-08 10:36:39 +00:00
|
|
|
fs.stat(file, (err, stat) => {
|
2022-01-21 08:28:41 +00:00
|
|
|
if (err) {
|
|
|
|
printError(err)
|
|
|
|
} else if (stat && stat.isDirectory()) {
|
2022-06-08 10:36:39 +00:00
|
|
|
walk(file, (err) => {
|
2022-01-21 08:28:41 +00:00
|
|
|
if (err) {
|
|
|
|
printError(err)
|
|
|
|
} else {
|
|
|
|
next()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} else {
|
2022-06-08 10:36:39 +00:00
|
|
|
// process only *.css files
|
|
|
|
if (file.endsWith('.css')) {
|
2022-01-21 08:28:41 +00:00
|
|
|
// compute output directory
|
2022-06-08 10:36:39 +00:00
|
|
|
const relativePath = path.relative(input, file).split(path.sep)
|
2022-01-21 08:28:41 +00:00
|
|
|
relativePath.pop()
|
|
|
|
relativePath.push(path.basename(file).replace('.css', ext || '.rtl.css'))
|
|
|
|
|
2022-06-08 10:36:39 +00:00
|
|
|
// set rtl filename
|
|
|
|
const rtlFile = path.join(output, relativePath.join(path.sep))
|
2022-01-21 08:28:41 +00:00
|
|
|
|
|
|
|
// create output directory if it does not exist
|
2022-06-08 10:36:39 +00:00
|
|
|
const dirName = path.dirname(rtlFile)
|
2022-01-21 08:28:41 +00:00
|
|
|
if (!fs.existsSync(dirName)) {
|
2022-06-08 10:36:39 +00:00
|
|
|
fs.mkdirSync(dirName, { recursive: true })
|
2022-01-21 08:28:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// read and process the file.
|
2022-06-08 10:36:39 +00:00
|
|
|
fs.readFile(file, 'utf8', (e, data) => {
|
2022-01-21 08:28:41 +00:00
|
|
|
try {
|
|
|
|
processCSSFile(e, data, rtlFile)
|
|
|
|
} catch (e) {
|
|
|
|
printError('rtlcss: error processing file', file)
|
|
|
|
printError(e)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2022-06-08 10:36:39 +00:00
|
|
|
|
2022-01-21 08:28:41 +00:00
|
|
|
next()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
if (input !== '-') {
|
|
|
|
if (directory !== true) {
|
2022-06-08 10:36:39 +00:00
|
|
|
fs.stat(input, (error, stat) => {
|
2022-01-21 08:28:41 +00:00
|
|
|
if (error) {
|
|
|
|
printError(error)
|
|
|
|
} else if (stat && stat.isDirectory()) {
|
2022-06-08 10:36:39 +00:00
|
|
|
printError('rtlcss: Input expected to be a file, use the -d option to process a directory.')
|
2022-01-21 08:28:41 +00:00
|
|
|
} else {
|
2022-06-08 10:36:39 +00:00
|
|
|
fs.readFile(input, 'utf8', (e, data) => {
|
2022-01-21 08:28:41 +00:00
|
|
|
try {
|
|
|
|
processCSSFile(e, data)
|
|
|
|
} catch (e) {
|
|
|
|
printError('rtlcss: error processing file', input)
|
|
|
|
printError(e)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
} else {
|
2022-06-08 10:36:39 +00:00
|
|
|
walk(input, (error) => {
|
2022-01-21 08:28:41 +00:00
|
|
|
if (error) {
|
2022-06-08 10:36:39 +00:00
|
|
|
printError(`rtlcss: ${error}`)
|
2022-01-21 08:28:41 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
process.stdin.resume()
|
|
|
|
process.stdin.setEncoding('utf8')
|
|
|
|
|
2022-06-08 10:36:39 +00:00
|
|
|
let buffer = ''
|
|
|
|
process.stdin.on('data', (data) => {
|
2022-01-21 08:28:41 +00:00
|
|
|
buffer += data
|
|
|
|
})
|
2022-06-08 10:36:39 +00:00
|
|
|
process.on('SIGINT', () => {
|
2022-01-21 08:28:41 +00:00
|
|
|
processCSSFile(false, buffer)
|
|
|
|
process.exit()
|
|
|
|
})
|
2022-06-08 10:36:39 +00:00
|
|
|
process.stdin.on('end', () => {
|
2022-01-21 08:28:41 +00:00
|
|
|
processCSSFile(false, buffer)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|