Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LessParser.js 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /* eslint no-param-reassign: off */
  2. const Comment = require('postcss/lib/comment');
  3. const Parser = require('postcss/lib/parser');
  4. const { isInlineComment } = require('./nodes/inline-comment');
  5. const { interpolation } = require('./nodes/interpolation');
  6. const { isMixinToken } = require('./nodes/mixin');
  7. const importNode = require('./nodes/import');
  8. const variableNode = require('./nodes/variable');
  9. const importantPattern = /(!\s*important)$/i;
  10. module.exports = class LessParser extends Parser {
  11. constructor(...args) {
  12. super(...args);
  13. this.lastNode = null;
  14. }
  15. atrule(token) {
  16. if (interpolation.bind(this)(token)) {
  17. return;
  18. }
  19. super.atrule(token);
  20. importNode(this.lastNode);
  21. variableNode(this.lastNode);
  22. }
  23. decl(...args) {
  24. super.decl(...args);
  25. // #123: add `extend` decorator to nodes
  26. const extendPattern = /extend\(.+\)/i;
  27. if (extendPattern.test(this.lastNode.value)) {
  28. this.lastNode.extend = true;
  29. }
  30. }
  31. each(tokens) {
  32. // prepend a space so the `name` will be parsed correctly
  33. tokens[0][1] = ` ${tokens[0][1]}`;
  34. const firstParenIndex = tokens.findIndex((t) => t[0] === '(');
  35. const lastParen = tokens.reverse().find((t) => t[0] === ')');
  36. const lastParenIndex = tokens.reverse().indexOf(lastParen);
  37. const paramTokens = tokens.splice(firstParenIndex, lastParenIndex);
  38. const params = paramTokens.map((t) => t[1]).join('');
  39. for (const token of tokens.reverse()) {
  40. this.tokenizer.back(token);
  41. }
  42. this.atrule(this.tokenizer.nextToken());
  43. this.lastNode.function = true;
  44. this.lastNode.params = params;
  45. }
  46. init(node, line, column) {
  47. super.init(node, line, column);
  48. this.lastNode = node;
  49. }
  50. inlineComment(token) {
  51. const node = new Comment();
  52. const text = token[1].slice(2);
  53. this.init(node, token[2], token[3]);
  54. node.source.end = { line: token[4], column: token[5] };
  55. node.inline = true;
  56. node.raws.begin = '//';
  57. if (/^\s*$/.test(text)) {
  58. node.text = '';
  59. node.raws.left = text;
  60. node.raws.right = '';
  61. } else {
  62. const match = text.match(/^(\s*)([^]*[^\s])(\s*)$/);
  63. [, node.raws.left, node.text, node.raws.right] = match;
  64. }
  65. }
  66. mixin(tokens) {
  67. const [first] = tokens;
  68. const identifier = first[1].slice(0, 1);
  69. const bracketsIndex = tokens.findIndex((t) => t[0] === 'brackets');
  70. const firstParenIndex = tokens.findIndex((t) => t[0] === '(');
  71. let important = '';
  72. // fix for #86. if rulesets are mixin params, they need to be converted to a brackets token
  73. if ((bracketsIndex < 0 || bracketsIndex > 3) && firstParenIndex > 0) {
  74. const lastParenIndex = tokens.reduce((last, t, i) => (t[0] === ')' ? i : last));
  75. const contents = tokens.slice(firstParenIndex, lastParenIndex + firstParenIndex);
  76. const brackets = contents.map((t) => t[1]).join('');
  77. const [paren] = tokens.slice(firstParenIndex);
  78. const start = [paren[2], paren[3]];
  79. const [last] = tokens.slice(lastParenIndex, lastParenIndex + 1);
  80. const end = [last[2], last[3]];
  81. const newToken = ['brackets', brackets].concat(start, end);
  82. const tokensBefore = tokens.slice(0, firstParenIndex);
  83. const tokensAfter = tokens.slice(lastParenIndex + 1);
  84. tokens = tokensBefore;
  85. tokens.push(newToken);
  86. tokens = tokens.concat(tokensAfter);
  87. }
  88. const importantTokens = [];
  89. for (const token of tokens) {
  90. if (token[1] === '!' || importantTokens.length) {
  91. importantTokens.push(token);
  92. }
  93. if (token[1] === 'important') {
  94. break;
  95. }
  96. }
  97. if (importantTokens.length) {
  98. const [bangToken] = importantTokens;
  99. const bangIndex = tokens.indexOf(bangToken);
  100. const last = importantTokens[importantTokens.length - 1];
  101. const start = [bangToken[2], bangToken[3]];
  102. const end = [last[4], last[5]];
  103. const combined = importantTokens.map((t) => t[1]).join('');
  104. const newToken = ['word', combined].concat(start, end);
  105. tokens.splice(bangIndex, importantTokens.length, newToken);
  106. }
  107. const importantIndex = tokens.findIndex((t) => importantPattern.test(t[1]));
  108. if (importantIndex > 0) {
  109. [, important] = tokens[importantIndex];
  110. tokens.splice(importantIndex, 1);
  111. }
  112. for (const token of tokens.reverse()) {
  113. this.tokenizer.back(token);
  114. }
  115. this.atrule(this.tokenizer.nextToken());
  116. this.lastNode.mixin = true;
  117. this.lastNode.raws.identifier = identifier;
  118. if (important) {
  119. this.lastNode.important = true;
  120. this.lastNode.raws.important = important;
  121. }
  122. }
  123. other(token) {
  124. if (!isInlineComment.bind(this)(token)) {
  125. super.other(token);
  126. }
  127. }
  128. rule(tokens) {
  129. const last = tokens[tokens.length - 1];
  130. const prev = tokens[tokens.length - 2];
  131. if (prev[0] === 'at-word' && last[0] === '{') {
  132. this.tokenizer.back(last);
  133. if (interpolation.bind(this)(prev)) {
  134. const newToken = this.tokenizer.nextToken();
  135. tokens = tokens.slice(0, tokens.length - 2).concat([newToken]);
  136. for (const tokn of tokens.reverse()) {
  137. this.tokenizer.back(tokn);
  138. }
  139. return;
  140. }
  141. }
  142. super.rule(tokens);
  143. // #123: add `extend` decorator to nodes
  144. const extendPattern = /:extend\(.+\)/i;
  145. if (extendPattern.test(this.lastNode.selector)) {
  146. this.lastNode.extend = true;
  147. }
  148. }
  149. unknownWord(tokens) {
  150. // NOTE: keep commented for examining unknown structures
  151. // console.log('unknown', tokens);
  152. const [first] = tokens;
  153. // #121 support `each` - http://lesscss.org/functions/#list-functions-each
  154. if (tokens[0][1] === 'each' && tokens[1][0] === '(') {
  155. this.each(tokens);
  156. return;
  157. }
  158. // TODO: move this into a util function/file
  159. if (isMixinToken(first)) {
  160. this.mixin(tokens);
  161. return;
  162. }
  163. super.unknownWord(tokens);
  164. }
  165. };