cli.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. #!/usr/bin/env node
  2. function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
  3. var fs = _interopDefault(require('fs'));
  4. var postcss = _interopDefault(require('postcss'));
  5. const selectorRegExp = /:blank([^\w-]|$)/gi;
  6. var plugin = postcss.plugin('css-blank-pseudo', opts => {
  7. const replaceWith = String(Object(opts).replaceWith || '[blank]');
  8. const preserve = Boolean('preserve' in Object(opts) ? opts.preserve : true);
  9. return root => {
  10. root.walkRules(selectorRegExp, rule => {
  11. const selector = rule.selector.replace(selectorRegExp, ($0, $1) => {
  12. return `${replaceWith}${$1}`;
  13. });
  14. const clone = rule.clone({
  15. selector
  16. });
  17. if (preserve) {
  18. rule.before(clone);
  19. } else {
  20. rule.replaceWith(clone);
  21. }
  22. });
  23. };
  24. });
  25. if (process.argv.length < 3) {
  26. console.log(['CSS Blank Pseudo\n', ' Transforms CSS with :blank {}\n', 'Usage:\n', ' css-blank-pseudo source.css transformed.css', ' css-blank-pseudo --in=source.css --out=transformed.css --opts={}', ' echo "@media (prefers-color-scheme: dark) {}" | css-blank-pseudo\n'].join('\n'));
  27. process.exit(0);
  28. } // get process and plugin options from the command line
  29. const fileRegExp = /^[\w\/.]+$/;
  30. const argRegExp = /^--(\w+)=("|')?(.+)\2$/;
  31. const relaxedJsonPropRegExp = /(['"])?([a-z0-9A-Z_]+)(['"])?:/g;
  32. const relaxedJsonValueRegExp = /("[a-z0-9A-Z_]+":\s*)'?([A-z0-9]+)'?([,}])/g;
  33. const argo = process.argv.slice(2).reduce((object, arg) => {
  34. const argMatch = arg.match(argRegExp);
  35. const fileMatch = arg.match(fileRegExp);
  36. if (argMatch) {
  37. object[argMatch[1]] = argMatch[3];
  38. } else if (fileMatch) {
  39. if (object.from === '<stdin>') {
  40. object.from = arg;
  41. } else if (object.to === '<stdout>') {
  42. object.to = arg;
  43. }
  44. }
  45. return object;
  46. }, {
  47. from: '<stdin>',
  48. to: '<stdout>',
  49. opts: 'null'
  50. }); // get css from command line arguments or stdin
  51. (argo.from === '<stdin>' ? getStdin() : readFile(argo.from)).then(css => {
  52. const pluginOpts = JSON.parse(argo.opts.replace(relaxedJsonPropRegExp, '"$2": ').replace(relaxedJsonValueRegExp, '$1"$2"$3'));
  53. const processOptions = Object.assign({
  54. from: argo.from,
  55. to: argo.to || argo.from
  56. }, argo.map ? {
  57. map: JSON.parse(argo.map)
  58. } : {});
  59. const result = plugin.process(css, processOptions, pluginOpts);
  60. if (argo.to === '<stdout>') {
  61. return result.css;
  62. } else {
  63. return writeFile(argo.to, result.css).then(() => `CSS was written to "${argo.to}"`);
  64. }
  65. }).then(result => {
  66. console.log(result);
  67. process.exit(0);
  68. }, error => {
  69. console.error(error);
  70. process.exit(1);
  71. });
  72. function readFile(pathname) {
  73. return new Promise((resolve, reject) => {
  74. fs.readFile(pathname, 'utf8', (error, data) => {
  75. if (error) {
  76. reject(error);
  77. } else {
  78. resolve(data);
  79. }
  80. });
  81. });
  82. }
  83. function writeFile(pathname, data) {
  84. return new Promise((resolve, reject) => {
  85. fs.writeFile(pathname, data, (error, content) => {
  86. if (error) {
  87. reject(error);
  88. } else {
  89. resolve(content);
  90. }
  91. });
  92. });
  93. }
  94. function getStdin() {
  95. return new Promise(resolve => {
  96. let data = '';
  97. if (process.stdin.isTTY) {
  98. resolve(data);
  99. } else {
  100. process.stdin.setEncoding('utf8');
  101. process.stdin.on('readable', () => {
  102. let chunk;
  103. while (chunk = process.stdin.read()) {
  104. data += chunk;
  105. }
  106. });
  107. process.stdin.on('end', () => {
  108. resolve(data);
  109. });
  110. }
  111. });
  112. }