2
0
Files
bot/apps/viewer/src/features/blocks/logic/setVariable/executeSetVariable.ts
2023-05-11 17:17:24 -04:00

103 lines
3.4 KiB
TypeScript

import { SessionState, SetVariableBlock, Variable } from '@typebot.io/schemas'
import { byId } from '@typebot.io/lib'
import { ExecuteLogicResponse } from '@/features/chat/types'
import { updateVariables } from '@/features/variables/updateVariables'
import { parseVariables } from '@/features/variables/parseVariables'
import { parseGuessedValueType } from '@/features/variables/parseGuessedValueType'
import { parseScriptToExecuteClientSideAction } from '../script/executeScript'
export const executeSetVariable = async (
state: SessionState,
block: SetVariableBlock,
lastBubbleBlockId?: string
): Promise<ExecuteLogicResponse> => {
const { variables } = state.typebot
if (!block.options?.variableId)
return {
outgoingEdgeId: block.outgoingEdgeId,
}
if (block.options.isExecutedOnClient && block.options.expressionToEvaluate) {
const scriptToExecute = parseScriptToExecuteClientSideAction(
state.typebot.variables,
block.options.expressionToEvaluate
)
return {
outgoingEdgeId: block.outgoingEdgeId,
clientSideActions: [
{
setVariable: {
scriptToExecute,
},
lastBubbleBlockId,
},
],
}
}
const expressionToEvaluate = getExpressionToEvaluate(state.result.id)(
block.options
)
const evaluatedExpression = expressionToEvaluate
? evaluateSetVariableExpression(variables)(expressionToEvaluate)
: undefined
const existingVariable = variables.find(byId(block.options.variableId))
if (!existingVariable) return { outgoingEdgeId: block.outgoingEdgeId }
const newVariable = {
...existingVariable,
value: evaluatedExpression,
}
const newSessionState = await updateVariables(state)([newVariable])
return {
outgoingEdgeId: block.outgoingEdgeId,
newSessionState,
}
}
const evaluateSetVariableExpression =
(variables: Variable[]) =>
(str: string): unknown => {
const isSingleVariable =
str.startsWith('{{') && str.endsWith('}}') && str.split('{{').length === 2
if (isSingleVariable) return parseVariables(variables)(str)
const evaluating = parseVariables(variables, { fieldToParse: 'id' })(
str.includes('return ') ? str : `return ${str}`
)
try {
const func = Function(...variables.map((v) => v.id), evaluating)
return func(...variables.map((v) => parseGuessedValueType(v.value)))
} catch (err) {
return parseVariables(variables)(str)
}
}
const getExpressionToEvaluate =
(resultId: string | undefined) =>
(options: SetVariableBlock['options']): string | null => {
switch (options.type) {
case 'Today':
return 'new Date().toISOString()'
case 'Tomorrow': {
return 'new Date(Date.now() + 86400000).toISOString()'
}
case 'Yesterday': {
return 'new Date(Date.now() - 86400000).toISOString()'
}
case 'Random ID': {
return 'Math.random().toString(36).substring(2, 15)'
}
case 'User ID': {
return resultId ?? 'Math.random().toString(36).substring(2, 15)'
}
case 'Map item with same index': {
return `const itemIndex = ${options.mapListItemParams?.baseListVariableId}.indexOf(${options.mapListItemParams?.baseItemVariableId})
return ${options.mapListItemParams?.targetListVariableId}.at(itemIndex)`
}
case 'Empty': {
return null
}
case 'Custom':
case undefined: {
return options.expressionToEvaluate ?? null
}
}
}