Ratio.js 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. var isDigit = require('../../tokenizer').isDigit;
  2. var TYPE = require('../../tokenizer').TYPE;
  3. var NUMBER = TYPE.Number;
  4. var DELIM = TYPE.Delim;
  5. var SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
  6. var FULLSTOP = 0x002E; // U+002E FULL STOP (.)
  7. // Terms of <ratio> should be a positive numbers (not zero or negative)
  8. // (see https://drafts.csswg.org/mediaqueries-3/#values)
  9. // However, -o-min-device-pixel-ratio takes fractional values as a ratio's term
  10. // and this is using by various sites. Therefore we relax checking on parse
  11. // to test a term is unsigned number without an exponent part.
  12. // Additional checking may be applied on lexer validation.
  13. function consumeNumber() {
  14. this.scanner.skipWS();
  15. var value = this.consume(NUMBER);
  16. for (var i = 0; i < value.length; i++) {
  17. var code = value.charCodeAt(i);
  18. if (!isDigit(code) && code !== FULLSTOP) {
  19. this.error('Unsigned number is expected', this.scanner.tokenStart - value.length + i);
  20. }
  21. }
  22. if (Number(value) === 0) {
  23. this.error('Zero number is not allowed', this.scanner.tokenStart - value.length);
  24. }
  25. return value;
  26. }
  27. // <positive-integer> S* '/' S* <positive-integer>
  28. module.exports = {
  29. name: 'Ratio',
  30. structure: {
  31. left: String,
  32. right: String
  33. },
  34. parse: function() {
  35. var start = this.scanner.tokenStart;
  36. var left = consumeNumber.call(this);
  37. var right;
  38. this.scanner.skipWS();
  39. if (!this.scanner.isDelim(SOLIDUS)) {
  40. this.error('Solidus is expected');
  41. }
  42. this.eat(DELIM);
  43. right = consumeNumber.call(this);
  44. return {
  45. type: 'Ratio',
  46. loc: this.getLocation(start, this.scanner.tokenStart),
  47. left: left,
  48. right: right
  49. };
  50. },
  51. generate: function(node) {
  52. this.chunk(node.left);
  53. this.chunk('/');
  54. this.chunk(node.right);
  55. }
  56. };