css.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*!
  2. * Stylus - CSS to Stylus conversion
  3. * Copyright (c) Automattic <developer.wordpress.com>
  4. * MIT Licensed
  5. */
  6. /**
  7. * Convert the given `css` to Stylus source.
  8. *
  9. * @param {String} css
  10. * @return {String}
  11. * @api public
  12. */
  13. module.exports = function(css){
  14. return new Converter(css).stylus();
  15. };
  16. /**
  17. * Initialize a new `Converter` with the given `css`.
  18. *
  19. * @param {String} css
  20. * @api private
  21. */
  22. function Converter(css) {
  23. var { parse } = require('css');
  24. this.css = css;
  25. this.root = parse(css, { position: false });
  26. this.indents = 0;
  27. }
  28. /**
  29. * Convert to Stylus.
  30. *
  31. * @return {String}
  32. * @api private
  33. */
  34. Converter.prototype.stylus = function(){
  35. return this.visitRules(this.root.stylesheet.rules);
  36. };
  37. /**
  38. * Return indent string.
  39. *
  40. * @return {String}
  41. * @api private
  42. */
  43. Converter.prototype.__defineGetter__('indent', function(){
  44. return Array(this.indents + 1).join(' ');
  45. });
  46. /**
  47. * Visit `node`.
  48. *
  49. * @param {*} node
  50. * @return {String}
  51. * @api private
  52. */
  53. Converter.prototype.visit = function(node){
  54. switch (node.type) {
  55. case 'rule':
  56. case 'comment':
  57. case 'charset':
  58. case 'namespace':
  59. case 'media':
  60. case 'import':
  61. case 'document':
  62. case 'keyframes':
  63. case 'page':
  64. case 'host':
  65. case 'supports':
  66. var name = node.type[0].toUpperCase() + node.type.slice(1);
  67. return this['visit' + name](node);
  68. case 'font-face':
  69. return this.visitFontFace(node);
  70. }
  71. };
  72. /**
  73. * Visit the rules on `node`.
  74. *
  75. * @param {Array} node
  76. * @return {String}
  77. * @api private
  78. */
  79. Converter.prototype.visitRules = function(node){
  80. var buf = '';
  81. for (var i = 0, len = node.length; i < len; ++i) {
  82. buf += this.visit(node[i]);
  83. }
  84. return buf;
  85. };
  86. /**
  87. * Visit FontFace `node`.
  88. *
  89. * @param {FontFace} node
  90. * @return {String}
  91. * @api private
  92. */
  93. Converter.prototype.visitFontFace = function(node){
  94. var buf = this.indent + '@font-face';
  95. buf += '\n';
  96. ++this.indents;
  97. for (var i = 0, len = node.declarations.length; i < len; ++i) {
  98. buf += this.visitDeclaration(node.declarations[i]);
  99. }
  100. --this.indents;
  101. return buf;
  102. };
  103. /**
  104. * Visit Media `node`.
  105. *
  106. * @param {Media} node
  107. * @return {String}
  108. * @api private
  109. */
  110. Converter.prototype.visitMedia = function(node){
  111. var buf = this.indent + '@media ' + node.media;
  112. buf += '\n';
  113. ++this.indents;
  114. buf += this.visitRules(node.rules);
  115. --this.indents;
  116. return buf;
  117. };
  118. /**
  119. * Visit Declaration `node`.
  120. *
  121. * @param {Declaration} node
  122. * @return {String}
  123. * @api private
  124. */
  125. Converter.prototype.visitDeclaration = function(node){
  126. if ('comment' == node.type) {
  127. return this.visitComment(node);
  128. } else {
  129. var buf = this.indent + node.property + ': ' + node.value + '\n';
  130. return buf;
  131. }
  132. };
  133. /**
  134. * Visit Rule `node`.`
  135. *
  136. * @param {Rule} node
  137. * @return {String}
  138. * @api private
  139. */
  140. Converter.prototype.visitRule = function(node){
  141. var buf = this.indent + node.selectors.join(',\n' + this.indent) + '\n';
  142. ++this.indents;
  143. for (var i = 0, len = node.declarations.length; i < len; ++i) {
  144. buf += this.visitDeclaration(node.declarations[i]);
  145. }
  146. --this.indents;
  147. return buf + '\n';
  148. };
  149. /**
  150. * Visit Comment `node`.`
  151. *
  152. * @param {Comment} node
  153. * @return {String}
  154. * @api private
  155. */
  156. Converter.prototype.visitComment = function(node){
  157. var buf = this.indent + '/*' + node.comment + '*/';
  158. return buf + '\n';
  159. };
  160. /**
  161. * Visit Charset `node`.`
  162. *
  163. * @param {Charset} node
  164. * @return {String}
  165. * @api private
  166. */
  167. Converter.prototype.visitCharset = function(node){
  168. var buf = this.indent + '@charset ' + node.charset;
  169. return buf + '\n';
  170. };
  171. /**
  172. * Visit Namespace `node`.`
  173. *
  174. * @param {Namespace} node
  175. * @return {String}
  176. * @api private
  177. */
  178. Converter.prototype.visitNamespace = function(node){
  179. var buf = this.indent + '@namespace ' + node.namespace;
  180. return buf + '\n';
  181. };
  182. /**
  183. * Visit Import `node`.`
  184. *
  185. * @param {Import} node
  186. * @return {String}
  187. * @api private
  188. */
  189. Converter.prototype.visitImport = function(node){
  190. var buf = this.indent + '@import ' + node.import;
  191. return buf + '\n';
  192. };
  193. /**
  194. * Visit Document `node`.`
  195. *
  196. * @param {Document} node
  197. * @return {String}
  198. * @api private
  199. */
  200. Converter.prototype.visitDocument = function(node){
  201. var buf = this.indent + '@' + node.vendor + 'document ' + node.document;
  202. buf += '\n';
  203. ++this.indents;
  204. buf += this.visitRules(node.rules);
  205. --this.indents;
  206. return buf;
  207. };
  208. /**
  209. * Visit Keyframes `node`.`
  210. *
  211. * @param {Keyframes} node
  212. * @return {String}
  213. * @api private
  214. */
  215. Converter.prototype.visitKeyframes = function(node){
  216. var buf = this.indent + '@keyframes ' + node.name;
  217. buf += '\n';
  218. ++this.indents;
  219. for (var i = 0, len = node.keyframes.length; i < len; ++i) {
  220. buf += this.visitKeyframe(node.keyframes[i]);
  221. }
  222. --this.indents;
  223. return buf;
  224. };
  225. /**
  226. * Visit Keyframe `node`.`
  227. *
  228. * @param {Keyframe} node
  229. * @return {String}
  230. * @api private
  231. */
  232. Converter.prototype.visitKeyframe = function(node){
  233. var buf = this.indent + node.values.join(', ');
  234. buf += '\n';
  235. ++this.indents;
  236. for (var i = 0, len = node.declarations.length; i < len; ++i) {
  237. buf += this.visitDeclaration(node.declarations[i]);
  238. }
  239. --this.indents;
  240. return buf;
  241. };
  242. /**
  243. * Visit Page `node`.`
  244. *
  245. * @param {Page} node
  246. * @return {String}
  247. * @api private
  248. */
  249. Converter.prototype.visitPage = function(node){
  250. var buf = this.indent + '@page' + (node.selectors.length ? ' ' + node.selectors.join(', ') : '');
  251. buf += '\n';
  252. ++this.indents;
  253. for (var i = 0, len = node.declarations.length; i < len; ++i) {
  254. buf += this.visitDeclaration(node.declarations[i]);
  255. }
  256. --this.indents;
  257. return buf;
  258. };
  259. /**
  260. * Visit Supports `node`.`
  261. *
  262. * @param {Supports} node
  263. * @return {String}
  264. * @api private
  265. */
  266. Converter.prototype.visitSupports = function(node){
  267. var buf = this.indent + '@supports ' + node.supports;
  268. buf += '\n';
  269. ++this.indents;
  270. buf += this.visitRules(node.rules);
  271. --this.indents;
  272. return buf;
  273. };
  274. /**
  275. * Visit Host `node`.`
  276. *
  277. * @param {Host} node
  278. * @return {String}
  279. * @api private
  280. */
  281. Converter.prototype.visitHost = function(node){
  282. var buf = this.indent + '@host';
  283. buf += '\n';
  284. ++this.indents;
  285. buf += this.visitRules(node.rules);
  286. --this.indents;
  287. return buf;
  288. };