feat: hooked the APIs of the app into the pyoide core.
This commit is contained in:
128
src/renderer/python/generatePythonApiModuleV1.ts
Normal file
128
src/renderer/python/generatePythonApiModuleV1.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { BDS_PYTHON_API_CONTRACT_V1 } from './pythonApiContractV1';
|
||||
|
||||
function toSnakeCase(value: string): string {
|
||||
return value
|
||||
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
||||
.replace(/[^a-zA-Z0-9]+/g, '_')
|
||||
.replace(/^_+|_+$/g, '')
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
function quotePython(value: string): string {
|
||||
return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
||||
}
|
||||
|
||||
function buildPythonMethod(method: {
|
||||
method: string;
|
||||
description: string;
|
||||
params: Array<{ name: string; required: boolean }>;
|
||||
}): string {
|
||||
const [namespace, member] = method.method.split('.');
|
||||
if (!namespace || !member) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const pythonMethodName = toSnakeCase(member);
|
||||
const pythonParams = method.params.map((param) => ({
|
||||
sourceName: param.name,
|
||||
pythonName: toSnakeCase(param.name),
|
||||
required: param.required,
|
||||
}));
|
||||
|
||||
const signature = pythonParams.length > 0
|
||||
? `, ${pythonParams.map((param) => (param.required ? param.pythonName : `${param.pythonName}=None`)).join(', ')}`
|
||||
: '';
|
||||
|
||||
const argsDict = method.params.length > 0
|
||||
? `{ ${method.params.map((param, index) => `"${param.name}": ${pythonParams[index]?.pythonName}`).join(', ')} }`
|
||||
: '{}';
|
||||
|
||||
return [
|
||||
` async def ${pythonMethodName}(self${signature}):`,
|
||||
` \"\"\"${quotePython(method.description)}\"\"\"`,
|
||||
` return await self._transport.call("${method.method}", ${argsDict})`,
|
||||
'',
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function buildPythonNamespaceClass(
|
||||
namespace: string,
|
||||
methods: Array<{ method: string; description: string; params: Array<{ name: string; required: boolean }> }>
|
||||
): string {
|
||||
const className = `${namespace[0].toUpperCase()}${namespace.slice(1)}Api`;
|
||||
const methodBlocks = methods.map((method) => buildPythonMethod(method)).join('');
|
||||
|
||||
return [
|
||||
`class ${className}:`,
|
||||
' def __init__(self, transport):',
|
||||
' self._transport = transport',
|
||||
'',
|
||||
methodBlocks.trimEnd(),
|
||||
'',
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
export function generatePythonApiModuleV1(): string {
|
||||
const namespaceMap = new Map<string, Array<{ method: string; description: string; params: Array<{ name: string; required: boolean }> }>>();
|
||||
|
||||
for (const method of BDS_PYTHON_API_CONTRACT_V1.methods) {
|
||||
const [namespace] = method.method.split('.');
|
||||
if (!namespace) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const entries = namespaceMap.get(namespace) ?? [];
|
||||
entries.push({
|
||||
method: method.method,
|
||||
description: method.description,
|
||||
params: method.params.map((param) => ({
|
||||
name: param.name,
|
||||
required: param.required,
|
||||
})),
|
||||
});
|
||||
namespaceMap.set(namespace, entries);
|
||||
}
|
||||
|
||||
const namespaceBlocks = Array.from(namespaceMap.entries())
|
||||
.sort(([left], [right]) => left.localeCompare(right))
|
||||
.map(([namespace, methods]) => buildPythonNamespaceClass(namespace, methods))
|
||||
.join('\n');
|
||||
|
||||
const namespaceAssignments = Array.from(namespaceMap.keys())
|
||||
.sort((left, right) => left.localeCompare(right))
|
||||
.map((namespace) => ` self.${toSnakeCase(namespace)} = ${namespace[0].toUpperCase()}${namespace.slice(1)}Api(transport)`)
|
||||
.join('\n');
|
||||
|
||||
return [
|
||||
'# Auto-generated by generatePythonApiModuleV1.ts',
|
||||
`# Contract version: ${BDS_PYTHON_API_CONTRACT_V1.version}`,
|
||||
'',
|
||||
'import json',
|
||||
'',
|
||||
'class BdsApiError(Exception):',
|
||||
' pass',
|
||||
'',
|
||||
namespaceBlocks.trimEnd(),
|
||||
'',
|
||||
'class BdsApi:',
|
||||
' def __init__(self, transport):',
|
||||
' self._transport = transport',
|
||||
namespaceAssignments,
|
||||
'',
|
||||
'class _Transport:',
|
||||
' def __init__(self, call_impl):',
|
||||
' self._call_impl = call_impl',
|
||||
'',
|
||||
' async def call(self, method, args):',
|
||||
' raw_result = await self._call_impl(method, json.dumps(args))',
|
||||
' if raw_result is None or raw_result == "":',
|
||||
' return None',
|
||||
' return json.loads(raw_result)',
|
||||
'',
|
||||
'def install_bds_api(call_impl):',
|
||||
' _transport = _Transport(call_impl)',
|
||||
' bds = BdsApi(_transport)',
|
||||
' return bds',
|
||||
'',
|
||||
].join('\n');
|
||||
}
|
||||
Reference in New Issue
Block a user