128 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			128 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| const createCustomError = require('../utils/createCustomError');
 | |
| const generate = require('../definition-syntax/generate');
 | |
| const defaultLoc = { offset: 0, line: 1, column: 1 };
 | |
| 
 | |
| function locateMismatch(matchResult, node) {
 | |
|     const tokens = matchResult.tokens;
 | |
|     const longestMatch = matchResult.longestMatch;
 | |
|     const mismatchNode = longestMatch < tokens.length ? tokens[longestMatch].node || null : null;
 | |
|     const badNode = mismatchNode !== node ? mismatchNode : null;
 | |
|     let mismatchOffset = 0;
 | |
|     let mismatchLength = 0;
 | |
|     let entries = 0;
 | |
|     let css = '';
 | |
|     let start;
 | |
|     let end;
 | |
| 
 | |
|     for (let i = 0; i < tokens.length; i++) {
 | |
|         const token = tokens[i].value;
 | |
| 
 | |
|         if (i === longestMatch) {
 | |
|             mismatchLength = token.length;
 | |
|             mismatchOffset = css.length;
 | |
|         }
 | |
| 
 | |
|         if (badNode !== null && tokens[i].node === badNode) {
 | |
|             if (i <= longestMatch) {
 | |
|                 entries++;
 | |
|             } else {
 | |
|                 entries = 0;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         css += token;
 | |
|     }
 | |
| 
 | |
|     if (longestMatch === tokens.length || entries > 1) { // last
 | |
|         start = fromLoc(badNode || node, 'end') || buildLoc(defaultLoc, css);
 | |
|         end = buildLoc(start);
 | |
|     } else {
 | |
|         start = fromLoc(badNode, 'start') ||
 | |
|             buildLoc(fromLoc(node, 'start') || defaultLoc, css.slice(0, mismatchOffset));
 | |
|         end = fromLoc(badNode, 'end') ||
 | |
|             buildLoc(start, css.substr(mismatchOffset, mismatchLength));
 | |
|     }
 | |
| 
 | |
|     return {
 | |
|         css,
 | |
|         mismatchOffset,
 | |
|         mismatchLength,
 | |
|         start,
 | |
|         end
 | |
|     };
 | |
| }
 | |
| 
 | |
| function fromLoc(node, point) {
 | |
|     const value = node && node.loc && node.loc[point];
 | |
| 
 | |
|     if (value) {
 | |
|         return 'line' in value ? buildLoc(value) : value;
 | |
|     }
 | |
| 
 | |
|     return null;
 | |
| }
 | |
| 
 | |
| function buildLoc({ offset, line, column }, extra) {
 | |
|     const loc = {
 | |
|         offset,
 | |
|         line,
 | |
|         column
 | |
|     };
 | |
| 
 | |
|     if (extra) {
 | |
|         const lines = extra.split(/\n|\r\n?|\f/);
 | |
| 
 | |
|         loc.offset += extra.length;
 | |
|         loc.line += lines.length - 1;
 | |
|         loc.column = lines.length === 1 ? loc.column + extra.length : lines.pop().length + 1;
 | |
|     }
 | |
| 
 | |
|     return loc;
 | |
| }
 | |
| 
 | |
| const SyntaxReferenceError = function(type, referenceName) {
 | |
|     const error = createCustomError(
 | |
|         'SyntaxReferenceError',
 | |
|         type + (referenceName ? ' `' + referenceName + '`' : '')
 | |
|     );
 | |
| 
 | |
|     error.reference = referenceName;
 | |
| 
 | |
|     return error;
 | |
| };
 | |
| 
 | |
| const SyntaxMatchError = function(message, syntax, node, matchResult) {
 | |
|     const error = createCustomError('SyntaxMatchError', message);
 | |
|     const {
 | |
|         css,
 | |
|         mismatchOffset,
 | |
|         mismatchLength,
 | |
|         start,
 | |
|         end
 | |
|     } = locateMismatch(matchResult, node);
 | |
| 
 | |
|     error.rawMessage = message;
 | |
|     error.syntax = syntax ? generate(syntax) : '<generic>';
 | |
|     error.css = css;
 | |
|     error.mismatchOffset = mismatchOffset;
 | |
|     error.mismatchLength = mismatchLength;
 | |
|     error.message = message + '\n' +
 | |
|         '  syntax: ' + error.syntax + '\n' +
 | |
|         '   value: ' + (css || '<empty string>') + '\n' +
 | |
|         '  --------' + new Array(error.mismatchOffset + 1).join('-') + '^';
 | |
| 
 | |
|     Object.assign(error, start);
 | |
|     error.loc = {
 | |
|         source: (node && node.loc && node.loc.source) || '<unknown>',
 | |
|         start,
 | |
|         end
 | |
|     };
 | |
| 
 | |
|     return error;
 | |
| };
 | |
| 
 | |
| module.exports = {
 | |
|     SyntaxReferenceError,
 | |
|     SyntaxMatchError
 | |
| };
 |