397
packages/logic/computeResultTranscript.ts
Normal file
397
packages/logic/computeResultTranscript.ts
Normal file
@ -0,0 +1,397 @@
|
||||
import {
|
||||
Answer,
|
||||
ContinueChatResponse,
|
||||
Edge,
|
||||
Group,
|
||||
InputBlock,
|
||||
TypebotInSession,
|
||||
Variable,
|
||||
} from '@typebot.io/schemas'
|
||||
import { SetVariableHistoryItem } from '@typebot.io/schemas/features/result'
|
||||
import { isBubbleBlock, isInputBlock } from '@typebot.io/schemas/helpers'
|
||||
import { BubbleBlockType } from '@typebot.io/schemas/features/blocks/bubbles/constants'
|
||||
import { convertRichTextToMarkdown } from '@typebot.io/lib/markdown/convertRichTextToMarkdown'
|
||||
import { LogicBlockType } from '@typebot.io/schemas/features/blocks/logic/constants'
|
||||
import { createId } from '@typebot.io/lib/createId'
|
||||
import { executeCondition } from './executeCondition'
|
||||
import {
|
||||
parseBubbleBlock,
|
||||
BubbleBlockWithDefinedContent,
|
||||
} from '../bot-engine/parseBubbleBlock'
|
||||
import { defaultChoiceInputOptions } from '@typebot.io/schemas/features/blocks/inputs/choice/constants'
|
||||
import { defaultPictureChoiceOptions } from '@typebot.io/schemas/features/blocks/inputs/pictureChoice/constants'
|
||||
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
|
||||
import { parseVariables } from '@typebot.io/variables/parseVariables'
|
||||
|
||||
type TranscriptMessage =
|
||||
| {
|
||||
role: 'bot' | 'user'
|
||||
} & (
|
||||
| { type: 'text'; text: string }
|
||||
| { type: 'image'; image: string }
|
||||
| { type: 'video'; video: string }
|
||||
| { type: 'audio'; audio: string }
|
||||
)
|
||||
|
||||
export const parseTranscriptMessageText = (
|
||||
message: TranscriptMessage
|
||||
): string => {
|
||||
switch (message.type) {
|
||||
case 'text':
|
||||
return message.text
|
||||
case 'image':
|
||||
return message.image
|
||||
case 'video':
|
||||
return message.video
|
||||
case 'audio':
|
||||
return message.audio
|
||||
}
|
||||
}
|
||||
|
||||
export const computeResultTranscript = ({
|
||||
typebot,
|
||||
answers,
|
||||
setVariableHistory,
|
||||
visitedEdges,
|
||||
stopAtBlockId,
|
||||
}: {
|
||||
typebot: TypebotInSession
|
||||
answers: Pick<Answer, 'blockId' | 'content'>[]
|
||||
setVariableHistory: Pick<
|
||||
SetVariableHistoryItem,
|
||||
'blockId' | 'variableId' | 'value'
|
||||
>[]
|
||||
visitedEdges: string[]
|
||||
stopAtBlockId?: string
|
||||
}): TranscriptMessage[] => {
|
||||
const firstEdgeId = getFirstEdgeId(typebot)
|
||||
if (!firstEdgeId) return []
|
||||
const firstEdge = typebot.edges.find((edge) => edge.id === firstEdgeId)
|
||||
if (!firstEdge) return []
|
||||
const firstGroup = getNextGroup(typebot, firstEdgeId)
|
||||
if (!firstGroup) return []
|
||||
return executeGroup({
|
||||
typebotsQueue: [{ typebot }],
|
||||
nextGroup: firstGroup,
|
||||
currentTranscript: [],
|
||||
answers,
|
||||
setVariableHistory,
|
||||
visitedEdges,
|
||||
stopAtBlockId,
|
||||
})
|
||||
}
|
||||
|
||||
const getFirstEdgeId = (typebot: TypebotInSession) => {
|
||||
if (typebot.version === '6') return typebot.events?.[0].outgoingEdgeId
|
||||
return typebot.groups.at(0)?.blocks.at(0)?.outgoingEdgeId
|
||||
}
|
||||
|
||||
const getNextGroup = (
|
||||
typebot: TypebotInSession,
|
||||
edgeId: string
|
||||
): { group: Group; blockIndex?: number } | undefined => {
|
||||
const edge = typebot.edges.find((edge) => edge.id === edgeId)
|
||||
if (!edge) return
|
||||
const group = typebot.groups.find((group) => group.id === edge.to.groupId)
|
||||
if (!group) return
|
||||
const blockIndex = edge.to.blockId
|
||||
? group.blocks.findIndex((block) => block.id === edge.to.blockId)
|
||||
: undefined
|
||||
return { group, blockIndex }
|
||||
}
|
||||
|
||||
const executeGroup = ({
|
||||
currentTranscript,
|
||||
typebotsQueue,
|
||||
answers,
|
||||
nextGroup,
|
||||
setVariableHistory,
|
||||
visitedEdges,
|
||||
stopAtBlockId,
|
||||
}: {
|
||||
currentTranscript: TranscriptMessage[]
|
||||
nextGroup:
|
||||
| {
|
||||
group: Group
|
||||
blockIndex?: number | undefined
|
||||
}
|
||||
| undefined
|
||||
typebotsQueue: {
|
||||
typebot: TypebotInSession
|
||||
resumeEdgeId?: string
|
||||
}[]
|
||||
answers: Pick<Answer, 'blockId' | 'content'>[]
|
||||
setVariableHistory: Pick<
|
||||
SetVariableHistoryItem,
|
||||
'blockId' | 'variableId' | 'value'
|
||||
>[]
|
||||
visitedEdges: string[]
|
||||
stopAtBlockId?: string
|
||||
}): TranscriptMessage[] => {
|
||||
if (!nextGroup) return currentTranscript
|
||||
for (const block of nextGroup?.group.blocks.slice(
|
||||
nextGroup.blockIndex ?? 0
|
||||
)) {
|
||||
if (stopAtBlockId && block.id === stopAtBlockId) return currentTranscript
|
||||
if (setVariableHistory.at(0)?.blockId === block.id)
|
||||
typebotsQueue[0].typebot.variables = applySetVariable(
|
||||
setVariableHistory.shift(),
|
||||
typebotsQueue[0].typebot
|
||||
)
|
||||
let nextEdgeId = block.outgoingEdgeId
|
||||
if (isBubbleBlock(block)) {
|
||||
if (!block.content) continue
|
||||
const parsedBubbleBlock = parseBubbleBlock(
|
||||
block as BubbleBlockWithDefinedContent,
|
||||
{
|
||||
version: 2,
|
||||
variables: typebotsQueue[0].typebot.variables,
|
||||
typebotVersion: typebotsQueue[0].typebot.version,
|
||||
}
|
||||
)
|
||||
const newMessage =
|
||||
convertChatMessageToTranscriptMessage(parsedBubbleBlock)
|
||||
if (newMessage) currentTranscript.push(newMessage)
|
||||
} else if (isInputBlock(block)) {
|
||||
const answer = answers.shift()
|
||||
if (!answer) break
|
||||
if (block.options?.variableId) {
|
||||
const variable = typebotsQueue[0].typebot.variables.find(
|
||||
(variable) => variable.id === block.options?.variableId
|
||||
)
|
||||
if (variable) {
|
||||
typebotsQueue[0].typebot.variables =
|
||||
typebotsQueue[0].typebot.variables.map((v) =>
|
||||
v.id === variable.id ? { ...v, value: answer.content } : v
|
||||
)
|
||||
}
|
||||
}
|
||||
currentTranscript.push({
|
||||
role: 'user',
|
||||
type: 'text',
|
||||
text: answer.content,
|
||||
})
|
||||
const outgoingEdge = getOutgoingEdgeId({
|
||||
block,
|
||||
answer: answer.content,
|
||||
variables: typebotsQueue[0].typebot.variables,
|
||||
})
|
||||
if (outgoingEdge.isOffDefaultPath) visitedEdges.shift()
|
||||
nextEdgeId = outgoingEdge.edgeId
|
||||
} else if (block.type === LogicBlockType.CONDITION) {
|
||||
const passedCondition = block.items.find(
|
||||
(item) =>
|
||||
item.content &&
|
||||
executeCondition({
|
||||
variables: typebotsQueue[0].typebot.variables,
|
||||
condition: item.content,
|
||||
})
|
||||
)
|
||||
if (passedCondition) {
|
||||
visitedEdges.shift()
|
||||
nextEdgeId = passedCondition.outgoingEdgeId
|
||||
}
|
||||
} else if (block.type === LogicBlockType.AB_TEST) {
|
||||
nextEdgeId = visitedEdges.shift() ?? nextEdgeId
|
||||
} else if (block.type === LogicBlockType.JUMP) {
|
||||
if (!block.options?.groupId) continue
|
||||
const groupToJumpTo = typebotsQueue[0].typebot.groups.find(
|
||||
(group) => group.id === block.options?.groupId
|
||||
)
|
||||
const blockToJumpTo =
|
||||
groupToJumpTo?.blocks.find((b) => b.id === block.options?.blockId) ??
|
||||
groupToJumpTo?.blocks[0]
|
||||
|
||||
if (!blockToJumpTo) continue
|
||||
|
||||
const portalEdge = {
|
||||
id: createId(),
|
||||
from: { blockId: '', groupId: '' },
|
||||
to: { groupId: block.options.groupId, blockId: blockToJumpTo.id },
|
||||
}
|
||||
typebotsQueue[0].typebot.edges.push(portalEdge)
|
||||
visitedEdges.shift()
|
||||
nextEdgeId = portalEdge.id
|
||||
} else if (block.type === LogicBlockType.TYPEBOT_LINK) {
|
||||
const isLinkingSameTypebot =
|
||||
block.options &&
|
||||
(block.options.typebotId === 'current' ||
|
||||
block.options.typebotId === typebotsQueue[0].typebot.id)
|
||||
if (!isLinkingSameTypebot) continue
|
||||
let resumeEdge: Edge | undefined
|
||||
if (!block.outgoingEdgeId) {
|
||||
const currentBlockIndex = nextGroup.group.blocks.findIndex(
|
||||
(b) => b.id === block.id
|
||||
)
|
||||
const nextBlockInGroup =
|
||||
currentBlockIndex === -1
|
||||
? undefined
|
||||
: nextGroup.group.blocks.at(currentBlockIndex + 1)
|
||||
if (nextBlockInGroup)
|
||||
resumeEdge = {
|
||||
id: createId(),
|
||||
from: {
|
||||
blockId: '',
|
||||
},
|
||||
to: {
|
||||
groupId: nextGroup.group.id,
|
||||
blockId: nextBlockInGroup.id,
|
||||
},
|
||||
}
|
||||
}
|
||||
return executeGroup({
|
||||
typebotsQueue: [
|
||||
{
|
||||
typebot: typebotsQueue[0].typebot,
|
||||
resumeEdgeId: resumeEdge ? resumeEdge.id : block.outgoingEdgeId,
|
||||
},
|
||||
{
|
||||
typebot: resumeEdge
|
||||
? {
|
||||
...typebotsQueue[0].typebot,
|
||||
edges: typebotsQueue[0].typebot.edges.concat([resumeEdge]),
|
||||
}
|
||||
: typebotsQueue[0].typebot,
|
||||
},
|
||||
],
|
||||
answers,
|
||||
setVariableHistory,
|
||||
currentTranscript,
|
||||
nextGroup,
|
||||
visitedEdges,
|
||||
stopAtBlockId,
|
||||
})
|
||||
}
|
||||
if (nextEdgeId) {
|
||||
const nextGroup = getNextGroup(typebotsQueue[0].typebot, nextEdgeId)
|
||||
if (nextGroup) {
|
||||
return executeGroup({
|
||||
typebotsQueue,
|
||||
answers,
|
||||
setVariableHistory,
|
||||
currentTranscript,
|
||||
nextGroup,
|
||||
visitedEdges,
|
||||
stopAtBlockId,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typebotsQueue.length > 1 && typebotsQueue[0].resumeEdgeId) {
|
||||
return executeGroup({
|
||||
typebotsQueue: typebotsQueue.slice(1),
|
||||
answers,
|
||||
setVariableHistory,
|
||||
currentTranscript,
|
||||
nextGroup: getNextGroup(
|
||||
typebotsQueue[1].typebot,
|
||||
typebotsQueue[0].resumeEdgeId
|
||||
),
|
||||
visitedEdges: visitedEdges.slice(1),
|
||||
stopAtBlockId,
|
||||
})
|
||||
}
|
||||
return currentTranscript
|
||||
}
|
||||
|
||||
const applySetVariable = (
|
||||
setVariable:
|
||||
| Pick<SetVariableHistoryItem, 'blockId' | 'variableId' | 'value'>
|
||||
| undefined,
|
||||
typebot: TypebotInSession
|
||||
): Variable[] => {
|
||||
if (!setVariable) return typebot.variables
|
||||
const variable = typebot.variables.find(
|
||||
(variable) => variable.id === setVariable.variableId
|
||||
)
|
||||
if (!variable) return typebot.variables
|
||||
return typebot.variables.map((v) =>
|
||||
v.id === variable.id ? { ...v, value: setVariable.value } : v
|
||||
)
|
||||
}
|
||||
|
||||
const convertChatMessageToTranscriptMessage = (
|
||||
chatMessage: ContinueChatResponse['messages'][0]
|
||||
): TranscriptMessage | null => {
|
||||
switch (chatMessage.type) {
|
||||
case BubbleBlockType.TEXT: {
|
||||
if (!chatMessage.content.richText) return null
|
||||
return {
|
||||
role: 'bot',
|
||||
type: 'text',
|
||||
text: convertRichTextToMarkdown(chatMessage.content.richText),
|
||||
}
|
||||
}
|
||||
case BubbleBlockType.IMAGE: {
|
||||
if (!chatMessage.content.url) return null
|
||||
return {
|
||||
role: 'bot',
|
||||
type: 'image',
|
||||
image: chatMessage.content.url,
|
||||
}
|
||||
}
|
||||
case BubbleBlockType.VIDEO: {
|
||||
if (!chatMessage.content.url) return null
|
||||
return {
|
||||
role: 'bot',
|
||||
type: 'video',
|
||||
video: chatMessage.content.url,
|
||||
}
|
||||
}
|
||||
case BubbleBlockType.AUDIO: {
|
||||
if (!chatMessage.content.url) return null
|
||||
return {
|
||||
role: 'bot',
|
||||
type: 'audio',
|
||||
audio: chatMessage.content.url,
|
||||
}
|
||||
}
|
||||
case 'custom-embed':
|
||||
case BubbleBlockType.EMBED: {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getOutgoingEdgeId = ({
|
||||
block,
|
||||
answer,
|
||||
variables,
|
||||
}: {
|
||||
block: InputBlock
|
||||
answer: string | undefined
|
||||
variables: Variable[]
|
||||
}): { edgeId: string | undefined; isOffDefaultPath: boolean } => {
|
||||
if (
|
||||
block.type === InputBlockType.CHOICE &&
|
||||
!(
|
||||
block.options?.isMultipleChoice ??
|
||||
defaultChoiceInputOptions.isMultipleChoice
|
||||
) &&
|
||||
answer
|
||||
) {
|
||||
const matchedItem = block.items.find(
|
||||
(item) =>
|
||||
parseVariables(variables)(item.content).normalize() ===
|
||||
answer.normalize()
|
||||
)
|
||||
if (matchedItem?.outgoingEdgeId)
|
||||
return { edgeId: matchedItem.outgoingEdgeId, isOffDefaultPath: true }
|
||||
}
|
||||
if (
|
||||
block.type === InputBlockType.PICTURE_CHOICE &&
|
||||
!(
|
||||
block.options?.isMultipleChoice ??
|
||||
defaultPictureChoiceOptions.isMultipleChoice
|
||||
) &&
|
||||
answer
|
||||
) {
|
||||
const matchedItem = block.items.find(
|
||||
(item) =>
|
||||
parseVariables(variables)(item.title).normalize() === answer.normalize()
|
||||
)
|
||||
if (matchedItem?.outgoingEdgeId)
|
||||
return { edgeId: matchedItem.outgoingEdgeId, isOffDefaultPath: true }
|
||||
}
|
||||
return { edgeId: block.outgoingEdgeId, isOffDefaultPath: false }
|
||||
}
|
204
packages/logic/executeCondition.ts
Normal file
204
packages/logic/executeCondition.ts
Normal file
@ -0,0 +1,204 @@
|
||||
import { isNotDefined, isDefined } from '@typebot.io/lib'
|
||||
import { Comparison, Condition, Variable } from '@typebot.io/schemas'
|
||||
import { findUniqueVariableValue } from '@typebot.io/variables/findUniqueVariableValue'
|
||||
import { parseVariables } from '@typebot.io/variables/parseVariables'
|
||||
import {
|
||||
LogicalOperator,
|
||||
ComparisonOperators,
|
||||
defaultConditionItemContent,
|
||||
} from '@typebot.io/schemas/features/blocks/logic/condition/constants'
|
||||
|
||||
type Props = {
|
||||
condition: Condition
|
||||
variables: Variable[]
|
||||
}
|
||||
|
||||
export const executeCondition = ({ condition, variables }: Props): boolean => {
|
||||
if (!condition.comparisons) return false
|
||||
return (condition.logicalOperator ??
|
||||
defaultConditionItemContent.logicalOperator) === LogicalOperator.AND
|
||||
? condition.comparisons.every(executeComparison(variables))
|
||||
: condition.comparisons.some(executeComparison(variables))
|
||||
}
|
||||
|
||||
const executeComparison =
|
||||
(variables: Variable[]) =>
|
||||
(comparison: Comparison): boolean => {
|
||||
if (!comparison?.variableId) return false
|
||||
const inputValue =
|
||||
variables.find((v) => v.id === comparison.variableId)?.value ?? null
|
||||
const value =
|
||||
comparison.value === 'undefined' || comparison.value === 'null'
|
||||
? null
|
||||
: findUniqueVariableValue(variables)(comparison.value) ??
|
||||
parseVariables(variables)(comparison.value)
|
||||
if (isNotDefined(comparison.comparisonOperator)) return false
|
||||
switch (comparison.comparisonOperator) {
|
||||
case ComparisonOperators.CONTAINS: {
|
||||
if (Array.isArray(inputValue)) {
|
||||
const equal = (a: string | null, b: string | null) => {
|
||||
if (typeof a === 'string' && typeof b === 'string')
|
||||
return a.normalize() === b.normalize()
|
||||
return a !== b
|
||||
}
|
||||
return compare(equal, inputValue, value, 'some')
|
||||
}
|
||||
const contains = (a: string | null, b: string | null) => {
|
||||
if (b === '' || !b || !a) return false
|
||||
return a
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.normalize()
|
||||
.includes(b.toLowerCase().trim().normalize())
|
||||
}
|
||||
return compare(contains, inputValue, value, 'some')
|
||||
}
|
||||
case ComparisonOperators.NOT_CONTAINS: {
|
||||
if (Array.isArray(inputValue)) {
|
||||
const notEqual = (a: string | null, b: string | null) => {
|
||||
if (typeof a === 'string' && typeof b === 'string')
|
||||
return a.normalize() !== b.normalize()
|
||||
return a !== b
|
||||
}
|
||||
return compare(notEqual, inputValue, value)
|
||||
}
|
||||
const notContains = (a: string | null, b: string | null) => {
|
||||
if (b === '' || !b || !a) return true
|
||||
return !a
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.normalize()
|
||||
.includes(b.toLowerCase().trim().normalize())
|
||||
}
|
||||
return compare(notContains, inputValue, value)
|
||||
}
|
||||
case ComparisonOperators.EQUAL: {
|
||||
return compare(
|
||||
(a, b) => {
|
||||
if (typeof a === 'string' && typeof b === 'string')
|
||||
return a.normalize() === b.normalize()
|
||||
return a === b
|
||||
},
|
||||
inputValue,
|
||||
value
|
||||
)
|
||||
}
|
||||
case ComparisonOperators.NOT_EQUAL: {
|
||||
return compare(
|
||||
(a, b) => {
|
||||
if (typeof a === 'string' && typeof b === 'string')
|
||||
return a.normalize() !== b.normalize()
|
||||
return a !== b
|
||||
},
|
||||
inputValue,
|
||||
value
|
||||
)
|
||||
}
|
||||
case ComparisonOperators.GREATER: {
|
||||
if (isNotDefined(inputValue) || isNotDefined(value)) return false
|
||||
if (typeof inputValue === 'string') {
|
||||
if (typeof value === 'string')
|
||||
return parseDateOrNumber(inputValue) > parseDateOrNumber(value)
|
||||
return Number(inputValue) > value.length
|
||||
}
|
||||
if (typeof value === 'string') return inputValue.length > Number(value)
|
||||
return inputValue.length > value.length
|
||||
}
|
||||
case ComparisonOperators.LESS: {
|
||||
if (isNotDefined(inputValue) || isNotDefined(value)) return false
|
||||
if (typeof inputValue === 'string') {
|
||||
if (typeof value === 'string')
|
||||
return parseDateOrNumber(inputValue) < parseDateOrNumber(value)
|
||||
return Number(inputValue) < value.length
|
||||
}
|
||||
if (typeof value === 'string') return inputValue.length < Number(value)
|
||||
return inputValue.length < value.length
|
||||
}
|
||||
case ComparisonOperators.IS_SET: {
|
||||
return isDefined(inputValue) && inputValue.length > 0
|
||||
}
|
||||
case ComparisonOperators.IS_EMPTY: {
|
||||
return isNotDefined(inputValue) || inputValue.length === 0
|
||||
}
|
||||
case ComparisonOperators.STARTS_WITH: {
|
||||
const startsWith = (a: string | null, b: string | null) => {
|
||||
if (b === '' || !b || !a) return false
|
||||
return a
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.normalize()
|
||||
.startsWith(b.toLowerCase().trim().normalize())
|
||||
}
|
||||
return compare(startsWith, inputValue, value)
|
||||
}
|
||||
case ComparisonOperators.ENDS_WITH: {
|
||||
const endsWith = (a: string | null, b: string | null) => {
|
||||
if (b === '' || !b || !a) return false
|
||||
return a
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.normalize()
|
||||
.endsWith(b.toLowerCase().trim().normalize())
|
||||
}
|
||||
return compare(endsWith, inputValue, value)
|
||||
}
|
||||
case ComparisonOperators.MATCHES_REGEX: {
|
||||
const matchesRegex = (a: string | null, b: string | null) => {
|
||||
if (b === '' || !b || !a) return false
|
||||
const regex = preprocessRegex(b)
|
||||
if (!regex) return false
|
||||
return new RegExp(regex.pattern, regex.flags).test(a)
|
||||
}
|
||||
return compare(matchesRegex, inputValue, value, 'some')
|
||||
}
|
||||
case ComparisonOperators.NOT_MATCH_REGEX: {
|
||||
const matchesRegex = (a: string | null, b: string | null) => {
|
||||
if (b === '' || !b || !a) return false
|
||||
const regex = preprocessRegex(b)
|
||||
if (!regex) return true
|
||||
return !new RegExp(regex.pattern, regex.flags).test(a)
|
||||
}
|
||||
return compare(matchesRegex, inputValue, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const compare = (
|
||||
compareStrings: (a: string | null, b: string | null) => boolean,
|
||||
a: Exclude<Variable['value'], undefined>,
|
||||
b: Exclude<Variable['value'], undefined>,
|
||||
type: 'every' | 'some' = 'every'
|
||||
): boolean => {
|
||||
if (!a || typeof a === 'string') {
|
||||
if (!b || typeof b === 'string') return compareStrings(a, b)
|
||||
return type === 'every'
|
||||
? b.every((b) => compareStrings(a, b))
|
||||
: b.some((b) => compareStrings(a, b))
|
||||
}
|
||||
if (!b || typeof b === 'string') {
|
||||
return type === 'every'
|
||||
? a.every((a) => compareStrings(a, b))
|
||||
: a.some((a) => compareStrings(a, b))
|
||||
}
|
||||
if (type === 'every')
|
||||
return a.every((a) => b.every((b) => compareStrings(a, b)))
|
||||
return a.some((a) => b.some((b) => compareStrings(a, b)))
|
||||
}
|
||||
|
||||
const parseDateOrNumber = (value: string): number => {
|
||||
const parsed = Number(value)
|
||||
if (isNaN(parsed)) {
|
||||
const time = Date.parse(value)
|
||||
return time
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
const preprocessRegex = (regex: string) => {
|
||||
const regexWithFlags = regex.match(/\/(.+)\/([gimuy]*)$/)
|
||||
|
||||
if (regexWithFlags)
|
||||
return { pattern: regexWithFlags[1], flags: regexWithFlags[2] }
|
||||
|
||||
return { pattern: regex }
|
||||
}
|
18
packages/logic/package.json
Normal file
18
packages/logic/package.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "@typebot.io/logic",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"scripts": {},
|
||||
"keywords": [],
|
||||
"author": "Baptiste Arnaud",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@typebot.io/schemas": "workspace:*",
|
||||
"@typebot.io/lib": "workspace:*",
|
||||
"@typebot.io/variables": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typebot.io/tsconfig": "workspace:*",
|
||||
"@udecode/plate-common": "30.4.5"
|
||||
}
|
||||
}
|
12
packages/logic/tsconfig.json
Normal file
12
packages/logic/tsconfig.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "@typebot.io/tsconfig/base.json",
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"../variables/parseVariables.ts",
|
||||
"../bot-engine/parseBubbleBlock.ts"
|
||||
],
|
||||
"exclude": ["node_modules"],
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2021", "DOM"]
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user