FeatureRange.cjs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. 'use strict';
  2. const types = require('../../tokenizer/types.cjs');
  3. const SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
  4. const LESSTHANSIGN = 0x003C; // U+003C LESS-THAN SIGN (<)
  5. const EQUALSSIGN = 0x003D; // U+003D EQUALS SIGN (=)
  6. const GREATERTHANSIGN = 0x003E; // U+003E GREATER-THAN SIGN (>)
  7. const name = 'FeatureRange';
  8. const structure = {
  9. kind: String,
  10. left: ['Identifier', 'Number', 'Dimension', 'Ratio', 'Function'],
  11. leftComparison: String,
  12. middle: ['Identifier', 'Number', 'Dimension', 'Ratio', 'Function'],
  13. rightComparison: [String, null],
  14. right: ['Identifier', 'Number', 'Dimension', 'Ratio', 'Function', null]
  15. };
  16. function readTerm() {
  17. this.skipSC();
  18. switch (this.tokenType) {
  19. case types.Number:
  20. if (this.isDelim(SOLIDUS, this.lookupOffsetNonSC(1))) {
  21. return this.Ratio();
  22. } else {
  23. return this.Number();
  24. }
  25. case types.Dimension:
  26. return this.Dimension();
  27. case types.Ident:
  28. return this.Identifier();
  29. case types.Function:
  30. return this.parseWithFallback(
  31. () => {
  32. const res = this.Function(this.readSequence, this.scope.Value);
  33. this.skipSC();
  34. if (this.isDelim(SOLIDUS)) {
  35. this.error();
  36. }
  37. return res;
  38. },
  39. () => {
  40. return this.Ratio();
  41. }
  42. );
  43. default:
  44. this.error('Number, dimension, ratio or identifier is expected');
  45. }
  46. }
  47. function readComparison(expectColon) {
  48. this.skipSC();
  49. if (this.isDelim(LESSTHANSIGN) ||
  50. this.isDelim(GREATERTHANSIGN)) {
  51. const value = this.source[this.tokenStart];
  52. this.next();
  53. if (this.isDelim(EQUALSSIGN)) {
  54. this.next();
  55. return value + '=';
  56. }
  57. return value;
  58. }
  59. if (this.isDelim(EQUALSSIGN)) {
  60. return '=';
  61. }
  62. this.error(`Expected ${expectColon ? '":", ' : ''}"<", ">", "=" or ")"`);
  63. }
  64. function parse(kind = 'unknown') {
  65. const start = this.tokenStart;
  66. this.skipSC();
  67. this.eat(types.LeftParenthesis);
  68. const left = readTerm.call(this);
  69. const leftComparison = readComparison.call(this, left.type === 'Identifier');
  70. const middle = readTerm.call(this);
  71. let rightComparison = null;
  72. let right = null;
  73. if (this.lookupNonWSType(0) !== types.RightParenthesis) {
  74. rightComparison = readComparison.call(this);
  75. right = readTerm.call(this);
  76. }
  77. this.skipSC();
  78. this.eat(types.RightParenthesis);
  79. return {
  80. type: 'FeatureRange',
  81. loc: this.getLocation(start, this.tokenStart),
  82. kind,
  83. left,
  84. leftComparison,
  85. middle,
  86. rightComparison,
  87. right
  88. };
  89. }
  90. function generate(node) {
  91. this.token(types.LeftParenthesis, '(');
  92. this.node(node.left);
  93. this.tokenize(node.leftComparison);
  94. this.node(node.middle);
  95. if (node.right) {
  96. this.tokenize(node.rightComparison);
  97. this.node(node.right);
  98. }
  99. this.token(types.RightParenthesis, ')');
  100. }
  101. exports.generate = generate;
  102. exports.name = name;
  103. exports.parse = parse;
  104. exports.structure = structure;