import { getBuiltInParserHandler } from '../../builtInParsers/builtInParserHandlers.js'; import { createRPCClient } from '../../httpApi/clients/createRPCClient.js'; import { SpecifyError, specifyErrors } from '../../errors/index.js'; import { ParserToolbox } from '../ParserToolbox.js'; import { ParserFunction } from '../definitions/ParserFunction.js'; import { chainParserFunctions } from '../chainParserFunctions.js'; import { ParsersEngineDataBox } from '../definitions/parsersEngineDataBox.js'; import { handleSerializedParsersEngineResult } from './handleSerializedParsersEngineResult.js'; import { serializeParsersEngineDataBox } from '../utils/serializeParsersEngineDataBox.js'; import { BuiltInParserRuleSignature } from '../../builtInParsers/internals/BuiltInParserRuleSignature.js'; import { BuiltInParserName, getBuiltInParserDefinition, } from '../../builtInParsers/builtInParsers.js'; /** * Build a ParserFunction, executed locally, wrapped into a ParsersPipeline from a given Parser rule * @param rule * @param context */ export function makeLocalBuiltInParsersPipelineFromRule( rule: BuiltInParserRuleSignature, context: { isRemote: boolean; personalAccessToken?: string; }, ) { const fns = rule.parsers.map((parser, i, xs) => { const parserFunction = getBuiltInParserHandler(parser.name as BuiltInParserName); const parserDefinition = getBuiltInParserDefinition(parser.name as BuiltInParserName); const shouldExecuteRemotely = parser.options?.shouldExecuteRemotely ?? false; const isLastParser = i === xs.length - 1; return (previousDataBox: ParsersEngineDataBox, toolbox: ParserToolbox) => { if (!(parserDefinition.inTypes as Array).includes(previousDataBox.type)) { throw new SpecifyError({ errorKey: specifyErrors.PARSERS_ENGINE_RULE_EXECUTION_FAILED.errorKey, publicMessage: `Invalid input type "${previousDataBox.type}" for parser "${parser.name}".`, }); } // We send to remote if not already remote and the parser is marked to be executed remotely if (context.isRemote === false && shouldExecuteRemotely === true) { return createRPCClient(context.personalAccessToken) .executeParsersEngine({ body: { rules: [ { name: rule.name ? `RPC from ${rule.name} - ${parser.name}` : `RPC from ${parser.name}`, parsers: [parser], }, ], dataBox: serializeParsersEngineDataBox(previousDataBox), returnedKeys: { // We request the next dataBox only if it's not the last parser of the rule next: !isLastParser, }, }, }) .then(results => { let result = results[0]; if (!result) { throw new SpecifyError({ errorKey: specifyErrors.PARSERS_ENGINE_RPC_EXECUTION_FAILED.errorKey, publicMessage: `RPC result not found for parser "${parser.name}${ rule.name ? ` on rule "${rule.name}"` : '' }.`, }); } return handleSerializedParsersEngineResult(result, toolbox, parserDefinition.outType); }); } // @ts-expect-error - forcing arguments with narrower types return parserFunction(previousDataBox, toolbox, parser.options, parser.output, { isRemote: context.isRemote, }); }; }); return chainParserFunctions( // @ts-expect-error ...fns, ) as ParserFunction; }