Files
documentation/node_modules/rtlcss/bin/rtlcss.js
2024-03-22 03:47:51 +05:30

291 lines
7.3 KiB
JavaScript
Executable File

#!/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}
`
const ErrorCodes = Object.freeze({
Ok: 0,
ArgumentError: 1,
ProcessingError: 2
})
let input, output, directory, ext, config
let currentErrorcode = ErrorCodes.Ok
const args = process.argv.slice(2)
process.on('exit', () => { process.reallyExit(currentErrorcode) })
function printWarning (...args) {
args.forEach(a => console.warn(picocolors.yellow(a)))
}
function printInfo (...args) {
args.forEach(a => console.info(picocolors.green(a)))
}
function printError (...args) {
args.forEach(a => console.error(picocolors.red(a)))
}
function printHelp () {
console.log(HELP_TEXT)
printInfo(`RTLCSS version: ${version}`)
printInfo(`Report issues to: ${bugs.url}`)
}
function 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) {
const savePath = directory !== true ? output : outputName
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`)
}
}
function 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 = path.join(dir, 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 (path.extname(file) === '.css') {
// TODO: this could probably be simplified
// 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) {
currentErrorcode = ErrorCodes.ProcessingError
printError(`rtlcss: error processing file ${file}`)
printError(e)
}
})
}
next()
}
})
})()
})
}
function main () {
let arg
while ((arg = args.shift())) {
switch (arg) {
case '-h':
case '--help':
printHelp()
return
case '-v':
case '--version':
printInfo(`rtlcss version: ${version}`)
return
case '-c':
case '--config':
arg = args.shift()
try {
config = configLoader.load(path.resolve(arg))
} catch (e) {
printError(`rtlcss: invalid config file. ${e}`)
currentErrorcode = ErrorCodes.ArgumentError
return
}
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}`)
currentErrorcode = ErrorCodes.ArgumentError
return
}
if (!input) {
input = path.resolve(arg)
} else if (!output) {
output = path.resolve(arg)
}
break
}
}
if (!directory && !input) {
printError('rtlcss: no input file\n')
printHelp()
currentErrorcode = ErrorCodes.ArgumentError
return
}
if (!config && input !== '-') {
try {
const cwd = directory !== true ? path.dirname(input) : input
config = configLoader.load(null, cwd)
} catch (error) {
printError(`rtlcss: invalid config file. ${error}`)
currentErrorcode = ErrorCodes.ArgumentError
}
}
if (!output && input !== '-') {
if (directory !== true) {
const extension = path.extname(input)
output = extension ? input.replace(extension, `.rtl${extension}`) : `${input}.rtl`
} else {
output = input
}
}
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', (err, data) => {
try {
processCSSFile(err, data)
} catch (err) {
currentErrorcode = ErrorCodes.ProcessingError
printError(`rtlcss: error processing file ${input}`)
printError(err)
}
})
}
})
} 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)
})
}
}
main()