|
@@ -1,9 +1,10 @@
|
|
import * as acorn from 'acorn';
|
|
import * as acorn from 'acorn';
|
|
import acornImportMeta from 'acorn-import-meta';
|
|
import acornImportMeta from 'acorn-import-meta';
|
|
import * as ESTree from 'estree';
|
|
import * as ESTree from 'estree';
|
|
-
|
|
|
|
import chalk, { Chalk } from 'chalk';
|
|
import chalk, { Chalk } from 'chalk';
|
|
|
|
|
|
|
|
+import { IASTParserFacadeInputData } from './interfaces/IASTParserFacadeInputData';
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Facade over AST parser `acorn`
|
|
* Facade over AST parser `acorn`
|
|
*/
|
|
*/
|
|
@@ -27,23 +28,23 @@ export class ASTParserFacade {
|
|
];
|
|
];
|
|
|
|
|
|
/**
|
|
/**
|
|
- * @param {string} input
|
|
|
|
|
|
+ * @param {string} inputData
|
|
* @param {Options} config
|
|
* @param {Options} config
|
|
* @returns {Program}
|
|
* @returns {Program}
|
|
*/
|
|
*/
|
|
- public static parse (input: string, config: acorn.Options): ESTree.Program | never {
|
|
|
|
|
|
+ public static parse (inputData: IASTParserFacadeInputData, config: acorn.Options): ESTree.Program | never {
|
|
const sourceTypeLength: number = ASTParserFacade.sourceTypes.length;
|
|
const sourceTypeLength: number = ASTParserFacade.sourceTypes.length;
|
|
|
|
|
|
for (let i: number = 0; i < sourceTypeLength; i++) {
|
|
for (let i: number = 0; i < sourceTypeLength; i++) {
|
|
try {
|
|
try {
|
|
- return ASTParserFacade.parseType(input, config, ASTParserFacade.sourceTypes[i]);
|
|
|
|
|
|
+ return ASTParserFacade.parseType(inputData, config, ASTParserFacade.sourceTypes[i]);
|
|
} catch (error) {
|
|
} catch (error) {
|
|
if (i < sourceTypeLength - 1) {
|
|
if (i < sourceTypeLength - 1) {
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
throw new Error(ASTParserFacade.processParsingError(
|
|
throw new Error(ASTParserFacade.processParsingError(
|
|
- input,
|
|
|
|
|
|
+ inputData,
|
|
error.message,
|
|
error.message,
|
|
error.loc
|
|
error.loc
|
|
));
|
|
));
|
|
@@ -54,16 +55,17 @@ export class ASTParserFacade {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * @param {string} input
|
|
|
|
|
|
+ * @param {IASTParserFacadeInputData} inputData
|
|
* @param {acorn.Options} inputConfig
|
|
* @param {acorn.Options} inputConfig
|
|
* @param {acorn.Options["sourceType"]} sourceType
|
|
* @param {acorn.Options["sourceType"]} sourceType
|
|
* @returns {Program}
|
|
* @returns {Program}
|
|
*/
|
|
*/
|
|
private static parseType (
|
|
private static parseType (
|
|
- input: string,
|
|
|
|
|
|
+ inputData: IASTParserFacadeInputData,
|
|
inputConfig: acorn.Options,
|
|
inputConfig: acorn.Options,
|
|
sourceType: acorn.Options['sourceType']
|
|
sourceType: acorn.Options['sourceType']
|
|
): ESTree.Program {
|
|
): ESTree.Program {
|
|
|
|
+ const { sourceCode } = inputData;
|
|
const comments: ESTree.Comment[] = [];
|
|
const comments: ESTree.Comment[] = [];
|
|
const config: acorn.Options = {
|
|
const config: acorn.Options = {
|
|
...inputConfig,
|
|
...inputConfig,
|
|
@@ -74,7 +76,7 @@ export class ASTParserFacade {
|
|
const program: ESTree.Program = (
|
|
const program: ESTree.Program = (
|
|
<any>acorn
|
|
<any>acorn
|
|
.Parser.extend(acornImportMeta)
|
|
.Parser.extend(acornImportMeta)
|
|
- .parse(input, config)
|
|
|
|
|
|
+ .parse(sourceCode, config)
|
|
);
|
|
);
|
|
|
|
|
|
if (comments.length) {
|
|
if (comments.length) {
|
|
@@ -85,16 +87,22 @@ export class ASTParserFacade {
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * @param {string} sourceCode
|
|
|
|
|
|
+ * @param {IASTParserFacadeInputData} inputData
|
|
* @param {string} errorMessage
|
|
* @param {string} errorMessage
|
|
- * @param {Position} position
|
|
|
|
|
|
+ * @param {Position | null} position
|
|
* @returns {never}
|
|
* @returns {never}
|
|
*/
|
|
*/
|
|
- private static processParsingError (sourceCode: string, errorMessage: string, position: ESTree.Position | null): never {
|
|
|
|
|
|
+ private static processParsingError (
|
|
|
|
+ inputData: IASTParserFacadeInputData,
|
|
|
|
+ errorMessage: string,
|
|
|
|
+ position: ESTree.Position | null
|
|
|
|
+ ): never {
|
|
if (!position || !position.line || !position.column) {
|
|
if (!position || !position.line || !position.column) {
|
|
throw new Error(errorMessage);
|
|
throw new Error(errorMessage);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ const { sourceCode, inputFilePath } = inputData;
|
|
|
|
+
|
|
const sourceCodeLines: string[] = sourceCode.split(/\r?\n/);
|
|
const sourceCodeLines: string[] = sourceCode.split(/\r?\n/);
|
|
const errorLine: string | undefined = sourceCodeLines[position.line - 1];
|
|
const errorLine: string | undefined = sourceCodeLines[position.line - 1];
|
|
|
|
|
|
@@ -102,6 +110,10 @@ export class ASTParserFacade {
|
|
throw new Error(errorMessage);
|
|
throw new Error(errorMessage);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ const formattedInputFilePath: string = inputFilePath
|
|
|
|
+ ? `${inputFilePath}, `
|
|
|
|
+ : '';
|
|
|
|
+
|
|
const startErrorIndex: number = Math.max(0, position.column - ASTParserFacade.nearestSymbolsCount);
|
|
const startErrorIndex: number = Math.max(0, position.column - ASTParserFacade.nearestSymbolsCount);
|
|
const endErrorIndex: number = Math.min(errorLine.length, position.column + ASTParserFacade.nearestSymbolsCount);
|
|
const endErrorIndex: number = Math.min(errorLine.length, position.column + ASTParserFacade.nearestSymbolsCount);
|
|
|
|
|
|
@@ -110,6 +122,8 @@ export class ASTParserFacade {
|
|
errorLine.substring(startErrorIndex, endErrorIndex).replace(/^\s+/, '')
|
|
errorLine.substring(startErrorIndex, endErrorIndex).replace(/^\s+/, '')
|
|
}...`;
|
|
}...`;
|
|
|
|
|
|
- throw new Error(`Line ${position.line}: ${errorMessage}\n${formattedPointer} ${formattedCodeSlice}`);
|
|
|
|
|
|
+ throw new Error(
|
|
|
|
+ `ERROR in ${formattedInputFilePath}line ${position.line}: ${errorMessage}\n${formattedPointer} ${formattedCodeSlice}`
|
|
|
|
+ );
|
|
}
|
|
}
|
|
}
|
|
}
|