mixin-definition.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. var tslib_1 = require("tslib");
  4. var selector_1 = tslib_1.__importDefault(require("./selector"));
  5. var element_1 = tslib_1.__importDefault(require("./element"));
  6. var ruleset_1 = tslib_1.__importDefault(require("./ruleset"));
  7. var declaration_1 = tslib_1.__importDefault(require("./declaration"));
  8. var detached_ruleset_1 = tslib_1.__importDefault(require("./detached-ruleset"));
  9. var expression_1 = tslib_1.__importDefault(require("./expression"));
  10. var contexts_1 = tslib_1.__importDefault(require("../contexts"));
  11. var utils = tslib_1.__importStar(require("../utils"));
  12. var Definition = function (name, params, rules, condition, variadic, frames, visibilityInfo) {
  13. this.name = name || 'anonymous mixin';
  14. this.selectors = [new selector_1.default([new element_1.default(null, name, false, this._index, this._fileInfo)])];
  15. this.params = params;
  16. this.condition = condition;
  17. this.variadic = variadic;
  18. this.arity = params.length;
  19. this.rules = rules;
  20. this._lookups = {};
  21. var optionalParameters = [];
  22. this.required = params.reduce(function (count, p) {
  23. if (!p.name || (p.name && !p.value)) {
  24. return count + 1;
  25. }
  26. else {
  27. optionalParameters.push(p.name);
  28. return count;
  29. }
  30. }, 0);
  31. this.optionalParameters = optionalParameters;
  32. this.frames = frames;
  33. this.copyVisibilityInfo(visibilityInfo);
  34. this.allowRoot = true;
  35. };
  36. Definition.prototype = Object.assign(new ruleset_1.default(), {
  37. type: 'MixinDefinition',
  38. evalFirst: true,
  39. accept: function (visitor) {
  40. if (this.params && this.params.length) {
  41. this.params = visitor.visitArray(this.params);
  42. }
  43. this.rules = visitor.visitArray(this.rules);
  44. if (this.condition) {
  45. this.condition = visitor.visit(this.condition);
  46. }
  47. },
  48. evalParams: function (context, mixinEnv, args, evaldArguments) {
  49. /* jshint boss:true */
  50. var frame = new ruleset_1.default(null, null);
  51. var varargs;
  52. var arg;
  53. var params = utils.copyArray(this.params);
  54. var i;
  55. var j;
  56. var val;
  57. var name;
  58. var isNamedFound;
  59. var argIndex;
  60. var argsLength = 0;
  61. if (mixinEnv.frames && mixinEnv.frames[0] && mixinEnv.frames[0].functionRegistry) {
  62. frame.functionRegistry = mixinEnv.frames[0].functionRegistry.inherit();
  63. }
  64. mixinEnv = new contexts_1.default.Eval(mixinEnv, [frame].concat(mixinEnv.frames));
  65. if (args) {
  66. args = utils.copyArray(args);
  67. argsLength = args.length;
  68. for (i = 0; i < argsLength; i++) {
  69. arg = args[i];
  70. if (name = (arg && arg.name)) {
  71. isNamedFound = false;
  72. for (j = 0; j < params.length; j++) {
  73. if (!evaldArguments[j] && name === params[j].name) {
  74. evaldArguments[j] = arg.value.eval(context);
  75. frame.prependRule(new declaration_1.default(name, arg.value.eval(context)));
  76. isNamedFound = true;
  77. break;
  78. }
  79. }
  80. if (isNamedFound) {
  81. args.splice(i, 1);
  82. i--;
  83. continue;
  84. }
  85. else {
  86. throw { type: 'Runtime', message: "Named argument for " + this.name + " " + args[i].name + " not found" };
  87. }
  88. }
  89. }
  90. }
  91. argIndex = 0;
  92. for (i = 0; i < params.length; i++) {
  93. if (evaldArguments[i]) {
  94. continue;
  95. }
  96. arg = args && args[argIndex];
  97. if (name = params[i].name) {
  98. if (params[i].variadic) {
  99. varargs = [];
  100. for (j = argIndex; j < argsLength; j++) {
  101. varargs.push(args[j].value.eval(context));
  102. }
  103. frame.prependRule(new declaration_1.default(name, new expression_1.default(varargs).eval(context)));
  104. }
  105. else {
  106. val = arg && arg.value;
  107. if (val) {
  108. // This was a mixin call, pass in a detached ruleset of it's eval'd rules
  109. if (Array.isArray(val)) {
  110. val = new detached_ruleset_1.default(new ruleset_1.default('', val));
  111. }
  112. else {
  113. val = val.eval(context);
  114. }
  115. }
  116. else if (params[i].value) {
  117. val = params[i].value.eval(mixinEnv);
  118. frame.resetCache();
  119. }
  120. else {
  121. throw { type: 'Runtime', message: "wrong number of arguments for " + this.name + " (" + argsLength + " for " + this.arity + ")" };
  122. }
  123. frame.prependRule(new declaration_1.default(name, val));
  124. evaldArguments[i] = val;
  125. }
  126. }
  127. if (params[i].variadic && args) {
  128. for (j = argIndex; j < argsLength; j++) {
  129. evaldArguments[j] = args[j].value.eval(context);
  130. }
  131. }
  132. argIndex++;
  133. }
  134. return frame;
  135. },
  136. makeImportant: function () {
  137. var rules = !this.rules ? this.rules : this.rules.map(function (r) {
  138. if (r.makeImportant) {
  139. return r.makeImportant(true);
  140. }
  141. else {
  142. return r;
  143. }
  144. });
  145. var result = new Definition(this.name, this.params, rules, this.condition, this.variadic, this.frames);
  146. return result;
  147. },
  148. eval: function (context) {
  149. return new Definition(this.name, this.params, this.rules, this.condition, this.variadic, this.frames || utils.copyArray(context.frames));
  150. },
  151. evalCall: function (context, args, important) {
  152. var _arguments = [];
  153. var mixinFrames = this.frames ? this.frames.concat(context.frames) : context.frames;
  154. var frame = this.evalParams(context, new contexts_1.default.Eval(context, mixinFrames), args, _arguments);
  155. var rules;
  156. var ruleset;
  157. frame.prependRule(new declaration_1.default('@arguments', new expression_1.default(_arguments).eval(context)));
  158. rules = utils.copyArray(this.rules);
  159. ruleset = new ruleset_1.default(null, rules);
  160. ruleset.originalRuleset = this;
  161. ruleset = ruleset.eval(new contexts_1.default.Eval(context, [this, frame].concat(mixinFrames)));
  162. if (important) {
  163. ruleset = ruleset.makeImportant();
  164. }
  165. return ruleset;
  166. },
  167. matchCondition: function (args, context) {
  168. if (this.condition && !this.condition.eval(new contexts_1.default.Eval(context, [this.evalParams(context, /* the parameter variables */ new contexts_1.default.Eval(context, this.frames ? this.frames.concat(context.frames) : context.frames), args, [])]
  169. .concat(this.frames || []) // the parent namespace/mixin frames
  170. .concat(context.frames)))) { // the current environment frames
  171. return false;
  172. }
  173. return true;
  174. },
  175. matchArgs: function (args, context) {
  176. var allArgsCnt = (args && args.length) || 0;
  177. var len;
  178. var optionalParameters = this.optionalParameters;
  179. var requiredArgsCnt = !args ? 0 : args.reduce(function (count, p) {
  180. if (optionalParameters.indexOf(p.name) < 0) {
  181. return count + 1;
  182. }
  183. else {
  184. return count;
  185. }
  186. }, 0);
  187. if (!this.variadic) {
  188. if (requiredArgsCnt < this.required) {
  189. return false;
  190. }
  191. if (allArgsCnt > this.params.length) {
  192. return false;
  193. }
  194. }
  195. else {
  196. if (requiredArgsCnt < (this.required - 1)) {
  197. return false;
  198. }
  199. }
  200. // check patterns
  201. len = Math.min(requiredArgsCnt, this.arity);
  202. for (var i = 0; i < len; i++) {
  203. if (!this.params[i].name && !this.params[i].variadic) {
  204. if (args[i].value.eval(context).toCSS() != this.params[i].value.eval(context).toCSS()) {
  205. return false;
  206. }
  207. }
  208. }
  209. return true;
  210. }
  211. });
  212. exports.default = Definition;
  213. //# sourceMappingURL=mixin-definition.js.map