🐛 New sendMessage version for the new parser
Make sure old client still communicate with old parser
This commit is contained in:
186
packages/bot-engine/parseBubbleBlock.ts
Normal file
186
packages/bot-engine/parseBubbleBlock.ts
Normal file
@@ -0,0 +1,186 @@
|
||||
import { parseVideoUrl } from '@typebot.io/lib/parseVideoUrl'
|
||||
import {
|
||||
BubbleBlock,
|
||||
Variable,
|
||||
ChatReply,
|
||||
BubbleBlockType,
|
||||
} from '@typebot.io/schemas'
|
||||
import { deepParseVariables } from './variables/deepParseVariables'
|
||||
import { isEmpty, isNotEmpty } from '@typebot.io/lib/utils'
|
||||
import { getVariablesToParseInfoInText } from './variables/parseVariables'
|
||||
import { TDescendant, createPlateEditor } from '@udecode/plate-common'
|
||||
import {
|
||||
createDeserializeMdPlugin,
|
||||
deserializeMd,
|
||||
} from '@udecode/plate-serializer-md'
|
||||
|
||||
type Params = {
|
||||
version: 1 | 2
|
||||
variables: Variable[]
|
||||
}
|
||||
|
||||
export const parseBubbleBlock = (
|
||||
block: BubbleBlock,
|
||||
{ version, variables }: Params
|
||||
): ChatReply['messages'][0] => {
|
||||
switch (block.type) {
|
||||
case BubbleBlockType.TEXT: {
|
||||
if (version === 1)
|
||||
return deepParseVariables(
|
||||
variables,
|
||||
{},
|
||||
{ takeLatestIfList: true }
|
||||
)(block)
|
||||
return {
|
||||
...block,
|
||||
content: {
|
||||
...block.content,
|
||||
richText: parseVariablesInRichText(block.content.richText, {
|
||||
variables,
|
||||
takeLatestIfList: true,
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
case BubbleBlockType.EMBED: {
|
||||
const message = deepParseVariables(variables)(block)
|
||||
return {
|
||||
...message,
|
||||
content: {
|
||||
...message.content,
|
||||
height:
|
||||
typeof message.content.height === 'string'
|
||||
? parseFloat(message.content.height)
|
||||
: message.content.height,
|
||||
},
|
||||
}
|
||||
}
|
||||
case BubbleBlockType.VIDEO: {
|
||||
const parsedContent = deepParseVariables(variables)(block.content)
|
||||
return {
|
||||
...block,
|
||||
content: parsedContent.url ? parseVideoUrl(parsedContent.url) : {},
|
||||
}
|
||||
}
|
||||
default:
|
||||
return deepParseVariables(variables)(block)
|
||||
}
|
||||
}
|
||||
|
||||
const parseVariablesInRichText = (
|
||||
elements: TDescendant[],
|
||||
{
|
||||
variables,
|
||||
takeLatestIfList,
|
||||
}: { variables: Variable[]; takeLatestIfList?: boolean }
|
||||
): TDescendant[] => {
|
||||
const parsedElements: TDescendant[] = []
|
||||
for (const element of elements) {
|
||||
if ('text' in element) {
|
||||
const text = element.text as string
|
||||
if (isEmpty(text)) {
|
||||
parsedElements.push(element)
|
||||
continue
|
||||
}
|
||||
const variablesInText = getVariablesToParseInfoInText(text, {
|
||||
variables,
|
||||
takeLatestIfList,
|
||||
})
|
||||
if (variablesInText.length === 0) {
|
||||
parsedElements.push(element)
|
||||
continue
|
||||
}
|
||||
let lastTextEndIndex = 0
|
||||
let index = -1
|
||||
for (const variableInText of variablesInText) {
|
||||
index += 1
|
||||
const textBeforeVariable = text.substring(
|
||||
lastTextEndIndex,
|
||||
variableInText.startIndex
|
||||
)
|
||||
const textAfterVariable =
|
||||
index === variablesInText.length - 1
|
||||
? text.substring(variableInText.endIndex)
|
||||
: undefined
|
||||
lastTextEndIndex = variableInText.endIndex
|
||||
const isStandaloneElement =
|
||||
isEmpty(textBeforeVariable) && isEmpty(textAfterVariable)
|
||||
const variableElements = convertMarkdownToRichText(
|
||||
isStandaloneElement
|
||||
? variableInText.value
|
||||
: variableInText.value.replace(/[\n]+/g, ' ')
|
||||
)
|
||||
const variableElementsWithStyling = applyElementStyleToDescendants(
|
||||
variableElements,
|
||||
{
|
||||
bold: element.bold,
|
||||
italic: element.italic,
|
||||
underline: element.underline,
|
||||
}
|
||||
)
|
||||
|
||||
if (isStandaloneElement) {
|
||||
parsedElements.push(...variableElementsWithStyling)
|
||||
continue
|
||||
}
|
||||
const children: TDescendant[] = []
|
||||
if (isNotEmpty(textBeforeVariable))
|
||||
children.push({
|
||||
...element,
|
||||
text: textBeforeVariable,
|
||||
})
|
||||
children.push({
|
||||
type: 'inline-variable',
|
||||
children: variableElementsWithStyling,
|
||||
})
|
||||
if (isNotEmpty(textAfterVariable))
|
||||
children.push({
|
||||
...element,
|
||||
text: textAfterVariable,
|
||||
})
|
||||
parsedElements.push(...children)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
const type =
|
||||
element.children.length === 1 &&
|
||||
'text' in element.children[0] &&
|
||||
(element.children[0].text as string).startsWith('{{') &&
|
||||
(element.children[0].text as string).endsWith('}}')
|
||||
? 'variable'
|
||||
: element.type
|
||||
|
||||
parsedElements.push({
|
||||
...element,
|
||||
type,
|
||||
children: parseVariablesInRichText(element.children as TDescendant[], {
|
||||
variables,
|
||||
takeLatestIfList,
|
||||
}),
|
||||
})
|
||||
}
|
||||
return parsedElements
|
||||
}
|
||||
|
||||
const applyElementStyleToDescendants = (
|
||||
variableElements: TDescendant[],
|
||||
styles: { bold: unknown; italic: unknown; underline: unknown }
|
||||
): TDescendant[] =>
|
||||
variableElements.map((variableElement) => {
|
||||
if ('text' in variableElement) return { ...styles, ...variableElement }
|
||||
return {
|
||||
...variableElement,
|
||||
children: applyElementStyleToDescendants(
|
||||
variableElement.children,
|
||||
styles
|
||||
),
|
||||
}
|
||||
})
|
||||
|
||||
const convertMarkdownToRichText = (text: string): TDescendant[] => {
|
||||
const plugins = [createDeserializeMdPlugin()]
|
||||
return deserializeMd(createPlateEditor({ plugins }) as unknown as any, text)
|
||||
}
|
||||
Reference in New Issue
Block a user