index.js 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. /* eslint-disable import/no-extraneous-dependencies */
  2. const Input = require('postcss/lib/input');
  3. const LessParser = require('./LessParser');
  4. const LessStringifier = require('./LessStringifier');
  5. module.exports = {
  6. parse(less, options) {
  7. const input = new Input(less, options);
  8. const parser = new LessParser(input);
  9. parser.parse();
  10. // To handle double-slash comments (`//`) we end up creating a new tokenizer
  11. // in certain cases (see `lib/nodes/inline-comment.js`). However, this means
  12. // that any following node in the AST will have incorrect start/end positions
  13. // on the `source` property. To fix that, we'll walk the AST and compute
  14. // updated positions for all nodes.
  15. parser.root.walk((node) => {
  16. const offset = input.css.lastIndexOf(node.source.input.css);
  17. if (offset === 0) {
  18. // Short circuit - this node was processed with the original tokenizer
  19. // and should therefore have correct position information.
  20. return;
  21. }
  22. // This ensures that the chunk of source we're processing corresponds
  23. // strictly to a terminal substring of the input CSS. This should always
  24. // be the case, but if it ever isn't, we prefer to fail instead of
  25. // producing potentially invalid output.
  26. // istanbul ignore next
  27. if (offset + node.source.input.css.length !== input.css.length) {
  28. throw new Error('Invalid state detected in postcss-less');
  29. }
  30. const newStartOffset = offset + node.source.start.offset;
  31. const newStartPosition = input.fromOffset(offset + node.source.start.offset);
  32. // eslint-disable-next-line no-param-reassign
  33. node.source.start = {
  34. offset: newStartOffset,
  35. line: newStartPosition.line,
  36. column: newStartPosition.col
  37. };
  38. // Not all nodes have an `end` property.
  39. if (node.source.end) {
  40. const newEndOffset = offset + node.source.end.offset;
  41. const newEndPosition = input.fromOffset(offset + node.source.end.offset);
  42. // eslint-disable-next-line no-param-reassign
  43. node.source.end = {
  44. offset: newEndOffset,
  45. line: newEndPosition.line,
  46. column: newEndPosition.col
  47. };
  48. }
  49. });
  50. return parser.root;
  51. },
  52. stringify(node, builder) {
  53. const stringifier = new LessStringifier(builder);
  54. stringifier.stringify(node);
  55. },
  56. nodeToString(node) {
  57. let result = '';
  58. module.exports.stringify(node, (bit) => {
  59. result += bit;
  60. });
  61. return result;
  62. }
  63. };