Block.js 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import {
  2. WhiteSpace,
  3. Comment,
  4. Semicolon,
  5. AtKeyword,
  6. LeftCurlyBracket,
  7. RightCurlyBracket
  8. } from '../../tokenizer/index.js';
  9. const AMPERSAND = 0x0026; // U+0026 AMPERSAND (&)
  10. function consumeRaw() {
  11. return this.Raw(null, true);
  12. }
  13. function consumeRule() {
  14. return this.parseWithFallback(this.Rule, consumeRaw);
  15. }
  16. function consumeRawDeclaration() {
  17. return this.Raw(this.consumeUntilSemicolonIncluded, true);
  18. }
  19. function consumeDeclaration() {
  20. if (this.tokenType === Semicolon) {
  21. return consumeRawDeclaration.call(this, this.tokenIndex);
  22. }
  23. const node = this.parseWithFallback(this.Declaration, consumeRawDeclaration);
  24. if (this.tokenType === Semicolon) {
  25. this.next();
  26. }
  27. return node;
  28. }
  29. export const name = 'Block';
  30. export const walkContext = 'block';
  31. export const structure = {
  32. children: [[
  33. 'Atrule',
  34. 'Rule',
  35. 'Declaration'
  36. ]]
  37. };
  38. export function parse(isStyleBlock) {
  39. const consumer = isStyleBlock ? consumeDeclaration : consumeRule;
  40. const start = this.tokenStart;
  41. let children = this.createList();
  42. this.eat(LeftCurlyBracket);
  43. scan:
  44. while (!this.eof) {
  45. switch (this.tokenType) {
  46. case RightCurlyBracket:
  47. break scan;
  48. case WhiteSpace:
  49. case Comment:
  50. this.next();
  51. break;
  52. case AtKeyword:
  53. children.push(this.parseWithFallback(this.Atrule.bind(this, isStyleBlock), consumeRaw));
  54. break;
  55. default:
  56. if (isStyleBlock && this.isDelim(AMPERSAND)) {
  57. children.push(consumeRule.call(this));
  58. } else {
  59. children.push(consumer.call(this));
  60. }
  61. }
  62. }
  63. if (!this.eof) {
  64. this.eat(RightCurlyBracket);
  65. }
  66. return {
  67. type: 'Block',
  68. loc: this.getLocation(start, this.tokenStart),
  69. children
  70. };
  71. }
  72. export function generate(node) {
  73. this.token(LeftCurlyBracket, '{');
  74. this.children(node, prev => {
  75. if (prev.type === 'Declaration') {
  76. this.token(Semicolon, ';');
  77. }
  78. });
  79. this.token(RightCurlyBracket, '}');
  80. }