rtlcss.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #!/usr/bin/env node
  2. var path = require('path')
  3. var fs = require('fs')
  4. var sys = require('util')
  5. var chalk = require('chalk')
  6. var mkdirp = require('mkdirp')
  7. var postcss = require('postcss')
  8. var rtlcss = require('../lib/rtlcss')
  9. var configLoader = require('../lib/config-loader')
  10. var input, output, directory, ext, config, currentErrorcode, arg
  11. var args = process.argv.slice(2)
  12. var shouldBreak = false
  13. process.on('exit', function () { process.reallyExit(currentErrorcode) })
  14. function printWarning () {
  15. console.warn(chalk.yellow.apply(this, printWarning.arguments))
  16. }
  17. function printInfo () {
  18. console.info(chalk.green.apply(this, printInfo.arguments))
  19. }
  20. function printError () {
  21. console.error(chalk.red.apply(this, printError.arguments))
  22. }
  23. function printHelp () {
  24. console.log('Usage: rtlcss [option option=parameter ...] [source] [destination]')
  25. console.log('')
  26. /*eslint-disable*/
  27. var options = [
  28. 'Option ' , 'Description ',
  29. '--------------', '----------------------------------------------',
  30. '-h,--help' , 'Print help (this message) and exit.',
  31. '-v,--version' , 'Print version number and exit.',
  32. '-c,--config' , 'Path to configuration settings file.',
  33. '- ,--stdin' , 'Read from stdin stream.',
  34. '-d,--dirctory' , 'Process all *.css files from input directory (recursive).',
  35. '-e,--ext' , 'Used with -d option to set the output files extension.\n\t\t Default: ".rtl.css".',
  36. '-s,--silent' , 'Silent mode, no warnings or errors are printed.'
  37. ]
  38. /*eslint-enable */
  39. for (var x = 0; x < options.length; x++) {
  40. console.log(options[x++], '\t', options[x])
  41. }
  42. console.log('')
  43. console.log('*If no destination is specified, output will be written to the same input folder as {source}.rtl.{ext}')
  44. console.log('')
  45. printInfo('RTLCSS version: ' + require('../package.json').version)
  46. printInfo('Report issues to: https://github.com/MohammadYounes/rtlcss/issues')
  47. }
  48. while ((arg = args.shift())) {
  49. switch (arg) {
  50. case '-h':
  51. case '--help':
  52. printHelp()
  53. shouldBreak = true
  54. break
  55. case '-v':
  56. case '--version':
  57. printInfo('rtlcss version: ' + require('../package.json').version)
  58. shouldBreak = true
  59. break
  60. case '-c':
  61. case '--config':
  62. arg = args.shift()
  63. try {
  64. config = configLoader.load(path.resolve(arg))
  65. } catch (e) {
  66. printError('rtlcss: invalid config file. ', e)
  67. shouldBreak = true
  68. currentErrorcode = 1
  69. }
  70. break
  71. case '-d':
  72. case '--directory':
  73. directory = true
  74. break
  75. case '-e':
  76. case '--ext':
  77. ext = args.shift()
  78. break
  79. case '-s':
  80. case '--silent':
  81. console.log = console.info = console.warn = function () {}
  82. break
  83. case '-':
  84. case '--stdin':
  85. input = '-'
  86. break
  87. default:
  88. if (arg[0] === '-') {
  89. printError('rtlcss: unknown option. ' + arg)
  90. shouldBreak = true
  91. } else {
  92. if (!input) {
  93. input = path.resolve(arg)
  94. } else if (!output) {
  95. output = path.resolve(arg)
  96. }
  97. }
  98. break
  99. }
  100. }
  101. if (!shouldBreak) {
  102. if (!directory && !input) {
  103. printError('rtlcss: no input file')
  104. console.log('')
  105. printHelp()
  106. shouldBreak = true
  107. }
  108. if (!config && input !== '-') {
  109. try {
  110. var cwd = input
  111. if (directory !== true) {
  112. cwd = path.dirname(input)
  113. }
  114. config = configLoader.load(null, cwd)
  115. } catch (e) {
  116. printError('rtlcss: invalid config file. ', e)
  117. currentErrorcode = 1
  118. shouldBreak = true
  119. }
  120. }
  121. }
  122. if (!shouldBreak) {
  123. if (!output && input !== '-') {
  124. if (directory !== true) {
  125. output = path.extname(input) ? input.replace(/\.[^.]*$/, function (ext) { return '.rtl' + ext }) : input + '.rtl'
  126. } else {
  127. output = input
  128. }
  129. }
  130. var processCSSFile = function (e, data, outputName) {
  131. if (e) {
  132. printError('rtlcss: ' + e.message)
  133. return
  134. }
  135. var result
  136. var opt = { map: false }
  137. if (input !== '-') {
  138. opt.from = input
  139. opt.to = output
  140. }
  141. if (!config) {
  142. printWarning('rtlcss: Warning! No config present, using defaults.')
  143. result = postcss([rtlcss]).process(data, opt)
  144. } else {
  145. if ('map' in config === true && input !== '-') {
  146. opt.map = config.map
  147. }
  148. result = postcss([rtlcss.configure(config)]).process(data, opt)
  149. }
  150. if (output) {
  151. var savePath = outputName
  152. if (directory !== true) {
  153. savePath = output
  154. }
  155. printInfo('Saving:', savePath)
  156. fs.writeFile(savePath, result.css, 'utf8', function (err) { err && printError(err) })
  157. if (result.map) {
  158. fs.writeFile(savePath + '.map', result.map, 'utf8', function (err) { err && printError(err) })
  159. }
  160. } else {
  161. sys.print(result.css)
  162. }
  163. }
  164. var walk = function (dir, done) {
  165. fs.readdir(dir, function (error, list) {
  166. if (error) {
  167. return done(error)
  168. }
  169. var i = 0
  170. ;(function next () {
  171. var file = list[i++]
  172. if (!file) {
  173. return done(null)
  174. }
  175. file = dir + path.sep + file
  176. fs.stat(file, function (err, stat) {
  177. if (err) {
  178. printError(err)
  179. } else if (stat && stat.isDirectory()) {
  180. walk(file, function (err) {
  181. if (err) {
  182. printError(err)
  183. } else {
  184. next()
  185. }
  186. })
  187. } else {
  188. // process only *.css
  189. if (/\.(css)$/.test(file)) {
  190. // compute output directory
  191. var relativePath = path.relative(input, file).split(path.sep)
  192. relativePath.pop()
  193. relativePath.push(path.basename(file).replace('.css', ext || '.rtl.css'))
  194. // set rtl file name
  195. var rtlFile = path.join(output, relativePath.join(path.sep))
  196. // create output directory if it does not exist
  197. var dirName = path.dirname(rtlFile)
  198. if (!fs.existsSync(dirName)) {
  199. mkdirp.sync(dirName)
  200. }
  201. // read and process the file.
  202. fs.readFile(file, 'utf8', function (e, data) {
  203. try {
  204. processCSSFile(e, data, rtlFile)
  205. } catch (e) {
  206. printError('rtlcss: error processing file', file)
  207. printError(e)
  208. }
  209. })
  210. }
  211. next()
  212. }
  213. })
  214. })()
  215. })
  216. }
  217. if (input !== '-') {
  218. if (directory !== true) {
  219. fs.stat(input, function (error, stat) {
  220. if (error) {
  221. printError(error)
  222. } else if (stat && stat.isDirectory()) {
  223. printError('rtlcss: Input expected to be a file, use -d option to process a directory.')
  224. } else {
  225. fs.readFile(input, 'utf8', function (e, data) {
  226. try {
  227. processCSSFile(e, data)
  228. } catch (e) {
  229. printError('rtlcss: error processing file', input)
  230. printError(e)
  231. }
  232. })
  233. }
  234. })
  235. } else {
  236. walk(input, function (error) {
  237. if (error) {
  238. printError('rtlcss: ' + error)
  239. }
  240. })
  241. }
  242. } else {
  243. process.stdin.resume()
  244. process.stdin.setEncoding('utf8')
  245. var buffer = ''
  246. process.stdin.on('data', function (data) {
  247. buffer += data
  248. })
  249. process.on('SIGINT', function () {
  250. processCSSFile(false, buffer)
  251. process.exit()
  252. })
  253. process.stdin.on('end', function () {
  254. processCSSFile(false, buffer)
  255. })
  256. }
  257. }