MISC: Show user-friendly error message when there is syntax error in scripts (#1963)

This commit is contained in:
catloversg
2025-02-16 16:27:26 +07:00
committed by GitHub
parent 0a4598a9a0
commit 23bc4e8804
3 changed files with 56 additions and 24 deletions
+2 -2
View File
@@ -146,7 +146,7 @@ function parseOnlyRamCalculate(
const scriptFileType = getFileType(script.filename); const scriptFileType = getFileType(script.filename);
let moduleAST; let moduleAST;
try { try {
moduleAST = parseAST(script.code, scriptFileType); moduleAST = parseAST(script.filename, script.server, script.code, scriptFileType);
} catch (error) { } catch (error) {
return { return {
errorCode: RamCalculationErrorCode.ImportError, errorCode: RamCalculationErrorCode.ImportError,
@@ -552,7 +552,7 @@ export function calculateRamUsage(
): RamCalculation { ): RamCalculation {
try { try {
const fileType = getFileType(scriptName); const fileType = getFileType(scriptName);
const ast = typeof input === "string" ? parseAST(input, fileType) : input; const ast = typeof input === "string" ? parseAST(scriptName, server, input, fileType) : input;
return parseOnlyRamCalculate(ast, scriptName, server, getFileTypeFeature(fileType), otherScripts); return parseOnlyRamCalculate(ast, scriptName, server, getFileTypeFeature(fileType), otherScripts);
} catch (error) { } catch (error) {
return { return {
+1 -1
View File
@@ -276,7 +276,7 @@ function Root(props: IProps): React.ReactElement {
} }
let ast; let ast;
try { try {
ast = parseAST(newCode, getFileType(currentScript.path)); ast = parseAST(currentScript.path, currentScript.hostname, newCode, getFileType(currentScript.path));
makeModelsForImports(ast, server); makeModelsForImports(ast, server);
} catch (error) { } catch (error) {
showRAMError({ showRAMError({
+33 -1
View File
@@ -63,9 +63,10 @@ export function getFileTypeFeature(fileType: FileType): FileTypeFeature {
return result; return result;
} }
export function parseAST(code: string, fileType: FileType): AST { export function parseAST(scriptName: string, hostname: string, code: string, fileType: FileType): AST {
const fileTypeFeature = getFileTypeFeature(fileType); const fileTypeFeature = getFileTypeFeature(fileType);
let ast: AST; let ast: AST;
try {
/** /**
* acorn is much faster than babel-parser, especially when parsing many big JS files, so we use it to parse the AST of * acorn is much faster than babel-parser, especially when parsing many big JS files, so we use it to parse the AST of
* JS code. babel-parser is only useful when we have to parse JSX and TypeScript. * JS code. babel-parser is only useful when we have to parse JSX and TypeScript.
@@ -90,6 +91,37 @@ export function parseAST(code: string, fileType: FileType): AST {
plugins: [["estree", { classFeatures: true }], ...plugins], plugins: [["estree", { classFeatures: true }], ...plugins],
}).program; }).program;
} }
} catch (error) {
/**
* The message of syntax errors may be cryptic for players without programming experience. For example, some players
* asked us what "Unexpected token" means. Therefore, we will catch the error here and provide a user-friendly error
* message.
*/
if (error instanceof SyntaxError) {
let errorLocation = "unknown";
/**
* Some browsers (e.g., Firefox, Chrome) add the "loc" property to the error object. This property provides the
* line and column numbers of the error.
*/
if (
"loc" in error &&
error.loc &&
typeof error.loc === "object" &&
"line" in error.loc &&
"column" in error.loc
) {
errorLocation = `Line ${error.loc.line}, Column: ${error.loc.column}`;
}
throw new Error(
`Syntax error in ${scriptName}, server: ${hostname}. Error location: ${errorLocation}. Error message: ${error.message}.`,
{
cause: error,
},
);
} else {
throw error;
}
}
return ast; return ast;
} }