object.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*!
  2. * Stylus - Object
  3. * Copyright (c) Automattic <developer.wordpress.com>
  4. * MIT Licensed
  5. */
  6. /**
  7. * Module dependencies.
  8. */
  9. var Node = require('./node')
  10. , nodes = require('./')
  11. , nativeObj = {}.constructor;
  12. /**
  13. * Initialize a new `Object`.
  14. *
  15. * @api public
  16. */
  17. var Object = module.exports = function Object(){
  18. Node.call(this);
  19. this.vals = {};
  20. };
  21. /**
  22. * Inherit from `Node.prototype`.
  23. */
  24. Object.prototype.__proto__ = Node.prototype;
  25. /**
  26. * Set `key` to `val`.
  27. *
  28. * @param {String} key
  29. * @param {Node} val
  30. * @return {Object} for chaining
  31. * @api public
  32. */
  33. Object.prototype.set = function(key, val){
  34. this.vals[key] = val;
  35. return this;
  36. };
  37. /**
  38. * Return length.
  39. *
  40. * @return {Number}
  41. * @api public
  42. */
  43. Object.prototype.__defineGetter__('length', function() {
  44. return nativeObj.keys(this.vals).length;
  45. });
  46. /**
  47. * Get `key`.
  48. *
  49. * @param {String} key
  50. * @return {Node}
  51. * @api public
  52. */
  53. Object.prototype.get = function(key){
  54. return this.vals[key] || nodes.null;
  55. };
  56. /**
  57. * Has `key`?
  58. *
  59. * @param {String} key
  60. * @return {Boolean}
  61. * @api public
  62. */
  63. Object.prototype.has = function(key){
  64. return key in this.vals;
  65. };
  66. /**
  67. * Operate on `right` with the given `op`.
  68. *
  69. * @param {String} op
  70. * @param {Node} right
  71. * @return {Node}
  72. * @api public
  73. */
  74. Object.prototype.operate = function(op, right){
  75. switch (op) {
  76. case '.':
  77. case '[]':
  78. return this.get(right.hash);
  79. case '==':
  80. var vals = this.vals
  81. , a
  82. , b;
  83. if ('object' != right.nodeName || this.length != right.length)
  84. return nodes.false;
  85. for (var key in vals) {
  86. a = vals[key];
  87. b = right.vals[key];
  88. if (a.operate(op, b).isFalse)
  89. return nodes.false;
  90. }
  91. return nodes.true;
  92. case '!=':
  93. return this.operate('==', right).negate();
  94. default:
  95. return Node.prototype.operate.call(this, op, right);
  96. }
  97. };
  98. /**
  99. * Return Boolean based on the length of this object.
  100. *
  101. * @return {Boolean}
  102. * @api public
  103. */
  104. Object.prototype.toBoolean = function(){
  105. return nodes.Boolean(this.length);
  106. };
  107. /**
  108. * Convert object to string with properties.
  109. *
  110. * @return {String}
  111. * @api private
  112. */
  113. Object.prototype.toBlock = function(){
  114. var str = '{'
  115. , key
  116. , val;
  117. for (key in this.vals) {
  118. val = this.get(key);
  119. if ('object' == val.first.nodeName) {
  120. str += key + ' ' + val.first.toBlock();
  121. } else {
  122. switch (key) {
  123. case '@charset':
  124. str += key + ' ' + val.first.toString() + ';';
  125. break;
  126. default:
  127. str += key + ':' + toString(val) + ';';
  128. }
  129. }
  130. }
  131. str += '}';
  132. return str;
  133. function toString(node) {
  134. if (node.nodes) {
  135. return node.nodes.map(toString).join(node.isList ? ',' : ' ');
  136. } else if ('literal' == node.nodeName && ',' == node.val) {
  137. return '\\,';
  138. }
  139. return node.toString();
  140. }
  141. };
  142. /**
  143. * Return a clone of this node.
  144. *
  145. * @return {Node}
  146. * @api public
  147. */
  148. Object.prototype.clone = function(parent){
  149. var clone = new Object;
  150. clone.lineno = this.lineno;
  151. clone.column = this.column;
  152. clone.filename = this.filename;
  153. for (var key in this.vals) {
  154. clone.vals[key] = this.vals[key].clone(parent, clone);
  155. }
  156. return clone;
  157. };
  158. /**
  159. * Return a JSON representation of this node.
  160. *
  161. * @return {Object}
  162. * @api public
  163. */
  164. Object.prototype.toJSON = function(){
  165. return {
  166. __type: 'Object',
  167. vals: this.vals,
  168. lineno: this.lineno,
  169. column: this.column,
  170. filename: this.filename
  171. };
  172. };
  173. /**
  174. * Return "{ <prop>: <val> }"
  175. *
  176. * @return {String}
  177. * @api public
  178. */
  179. Object.prototype.toString = function(){
  180. var obj = {};
  181. for (var prop in this.vals) {
  182. obj[prop] = this.vals[prop].toString();
  183. }
  184. return JSON.stringify(obj);
  185. };