error.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. const createCustomError = require('../utils/createCustomError');
  2. const generate = require('../definition-syntax/generate');
  3. const defaultLoc = { offset: 0, line: 1, column: 1 };
  4. function locateMismatch(matchResult, node) {
  5. const tokens = matchResult.tokens;
  6. const longestMatch = matchResult.longestMatch;
  7. const mismatchNode = longestMatch < tokens.length ? tokens[longestMatch].node || null : null;
  8. const badNode = mismatchNode !== node ? mismatchNode : null;
  9. let mismatchOffset = 0;
  10. let mismatchLength = 0;
  11. let entries = 0;
  12. let css = '';
  13. let start;
  14. let end;
  15. for (let i = 0; i < tokens.length; i++) {
  16. const token = tokens[i].value;
  17. if (i === longestMatch) {
  18. mismatchLength = token.length;
  19. mismatchOffset = css.length;
  20. }
  21. if (badNode !== null && tokens[i].node === badNode) {
  22. if (i <= longestMatch) {
  23. entries++;
  24. } else {
  25. entries = 0;
  26. }
  27. }
  28. css += token;
  29. }
  30. if (longestMatch === tokens.length || entries > 1) { // last
  31. start = fromLoc(badNode || node, 'end') || buildLoc(defaultLoc, css);
  32. end = buildLoc(start);
  33. } else {
  34. start = fromLoc(badNode, 'start') ||
  35. buildLoc(fromLoc(node, 'start') || defaultLoc, css.slice(0, mismatchOffset));
  36. end = fromLoc(badNode, 'end') ||
  37. buildLoc(start, css.substr(mismatchOffset, mismatchLength));
  38. }
  39. return {
  40. css,
  41. mismatchOffset,
  42. mismatchLength,
  43. start,
  44. end
  45. };
  46. }
  47. function fromLoc(node, point) {
  48. const value = node && node.loc && node.loc[point];
  49. if (value) {
  50. return 'line' in value ? buildLoc(value) : value;
  51. }
  52. return null;
  53. }
  54. function buildLoc({ offset, line, column }, extra) {
  55. const loc = {
  56. offset,
  57. line,
  58. column
  59. };
  60. if (extra) {
  61. const lines = extra.split(/\n|\r\n?|\f/);
  62. loc.offset += extra.length;
  63. loc.line += lines.length - 1;
  64. loc.column = lines.length === 1 ? loc.column + extra.length : lines.pop().length + 1;
  65. }
  66. return loc;
  67. }
  68. const SyntaxReferenceError = function(type, referenceName) {
  69. const error = createCustomError(
  70. 'SyntaxReferenceError',
  71. type + (referenceName ? ' `' + referenceName + '`' : '')
  72. );
  73. error.reference = referenceName;
  74. return error;
  75. };
  76. const SyntaxMatchError = function(message, syntax, node, matchResult) {
  77. const error = createCustomError('SyntaxMatchError', message);
  78. const {
  79. css,
  80. mismatchOffset,
  81. mismatchLength,
  82. start,
  83. end
  84. } = locateMismatch(matchResult, node);
  85. error.rawMessage = message;
  86. error.syntax = syntax ? generate(syntax) : '<generic>';
  87. error.css = css;
  88. error.mismatchOffset = mismatchOffset;
  89. error.mismatchLength = mismatchLength;
  90. error.message = message + '\n' +
  91. ' syntax: ' + error.syntax + '\n' +
  92. ' value: ' + (css || '<empty string>') + '\n' +
  93. ' --------' + new Array(error.mismatchOffset + 1).join('-') + '^';
  94. Object.assign(error, start);
  95. error.loc = {
  96. source: (node && node.loc && node.loc.source) || '<unknown>',
  97. start,
  98. end
  99. };
  100. return error;
  101. };
  102. module.exports = {
  103. SyntaxReferenceError,
  104. SyntaxMatchError
  105. };