Files
bDS/src/renderer/python/pythonSyntaxCheck.ts
2026-02-23 21:38:12 +01:00

74 lines
2.4 KiB
TypeScript

import type { PyodideInterface } from 'pyodide';
import type { PythonSyntaxError } from './runtimeProtocol';
const SYNTAX_CHECK_SCRIPT = [
'import ast',
'import json',
'',
'__bds_syntax_errors = []',
'try:',
' ast.parse(__bds_syntax_source)',
'except SyntaxError as exc:',
' line = exc.lineno or 1',
' column = exc.offset or 1',
' end_line = getattr(exc, "end_lineno", None) or line',
' end_column = getattr(exc, "end_offset", None) or (column + 1)',
' __bds_syntax_errors.append({',
' "line": line,',
' "column": column,',
' "endLine": end_line,',
' "endColumn": end_column,',
' "message": exc.msg or "invalid syntax",',
' })',
'__bds_syntax_result_json = json.dumps({"errors": __bds_syntax_errors})',
'__bds_syntax_result_json',
].join('\n');
function toResultString(result: unknown): string {
if (typeof result === 'string') {
return result;
}
if (result === null || result === undefined) {
return '';
}
return String(result);
}
function parseSyntaxErrors(rawJsonResult: unknown): PythonSyntaxError[] {
const rawText = toResultString(rawJsonResult).trim();
if (rawText.length === 0) {
throw new Error('Python syntax check returned no JSON result');
}
const parsed = JSON.parse(rawText) as { errors?: unknown };
if (!Array.isArray(parsed.errors)) {
return [];
}
return parsed.errors
.filter((item): item is PythonSyntaxError => {
return item
&& typeof item === 'object'
&& Number.isFinite((item as { line?: number }).line)
&& Number.isFinite((item as { column?: number }).column)
&& Number.isFinite((item as { endLine?: number }).endLine)
&& Number.isFinite((item as { endColumn?: number }).endColumn)
&& typeof (item as { message?: unknown }).message === 'string';
})
.map((item) => ({
line: Math.max(1, Math.floor(item.line)),
column: Math.max(1, Math.floor(item.column)),
endLine: Math.max(1, Math.floor(item.endLine)),
endColumn: Math.max(1, Math.floor(item.endColumn)),
message: item.message,
}));
}
export async function runPythonSyntaxCheck(runtime: PyodideInterface, sourceCode: string): Promise<PythonSyntaxError[]> {
runtime.globals.set('__bds_syntax_source', sourceCode);
const rawJsonResult = await runtime.runPythonAsync(SYNTAX_CHECK_SCRIPT);
return parseSyntaxErrors(rawJsonResult);
}