fix: catch all error in text macro replace

This commit is contained in:
Innei
2022-04-22 14:07:34 +08:00
parent 60290d48bd
commit a571facd2b

View File

@@ -1,13 +1,17 @@
import dayjs from 'dayjs'
import { marked } from 'marked'
import { BadRequestException, Injectable } from '@nestjs/common'
import { BadRequestException, Injectable, Logger } from '@nestjs/common'
import { deepCloneWithFunction } from '~/utils'
import { safeEval } from '~/utils/safe-eval.util'
@Injectable()
export class TextMacroService {
private readonly logger: Logger
constructor() {
this.logger = new Logger(TextMacroService.name)
}
static readonly Reg = {
'#': /^#(.*?)$/g,
$: /^\$(.*?)$/g,
@@ -66,59 +70,64 @@ export class TextMacroService {
text: string,
model: T,
): Promise<string> {
const matchedReg = /\[\[\s(.*?)\s\]\]/g
if (text.search(matchedReg) != -1) {
text = text.replace(matchedReg, (match, condition) => {
const ast = marked.lexer(text)
try {
const matchedReg = /\[\[\s(.*?)\s\]\]/g
if (text.search(matchedReg) != -1) {
text = text.replace(matchedReg, (match, condition) => {
const ast = marked.lexer(text)
// FIXME: shallow find, if same text both in code block and paragraph, the macro in paragraph also will not replace
const isInCodeBlock = ast.some((i) => {
if (i.type === 'code' || i.type === 'codespan') {
return i.raw.includes(condition)
}
})
// FIXME: shallow find, if same text both in code block and paragraph, the macro in paragraph also will not replace
const isInCodeBlock = ast.some((i) => {
if (i.type === 'code' || i.type === 'codespan') {
return i.raw.includes(condition)
}
})
if (isInCodeBlock) {
return match
}
condition = condition?.trim()
if (condition.search(TextMacroService.Reg['?']) != -1) {
return this.ifConditionGrammar(condition, model)
}
if (condition.search(TextMacroService.Reg['$']) != -1) {
const variable = condition
.replace(TextMacroService.Reg['$'], '$1')
.replace(/\s/g, '')
return model[variable]
}
// eslint-disable-next-line no-useless-escape
if (condition.search(TextMacroService.Reg['#']) != -1) {
// eslint-disable-next-line no-useless-escape
const functions = condition.replace(TextMacroService.Reg['#'], '$1')
const variables = Object.keys(model).reduce(
(acc, key) => ({ [`$${key}`]: model[key], ...acc }),
{},
)
try {
return safeEval(
`return ${functions}`,
{
dayjs: deepCloneWithFunction(dayjs),
fromNow: (time: Date | string) => dayjs(time).fromNow(),
...variables,
},
{ timeout: 1000 },
)
} catch {
if (isInCodeBlock) {
return match
}
}
})
condition = condition?.trim()
if (condition.search(TextMacroService.Reg['?']) != -1) {
return this.ifConditionGrammar(condition, model)
}
if (condition.search(TextMacroService.Reg['$']) != -1) {
const variable = condition
.replace(TextMacroService.Reg['$'], '$1')
.replace(/\s/g, '')
return model[variable]
}
// eslint-disable-next-line no-useless-escape
if (condition.search(TextMacroService.Reg['#']) != -1) {
// eslint-disable-next-line no-useless-escape
const functions = condition.replace(TextMacroService.Reg['#'], '$1')
const variables = Object.keys(model).reduce(
(acc, key) => ({ [`$${key}`]: model[key], ...acc }),
{},
)
try {
return safeEval(
`return ${functions}`,
{
dayjs: deepCloneWithFunction(dayjs),
fromNow: (time: Date | string) => dayjs(time).fromNow(),
...variables,
},
{ timeout: 1000 },
)
} catch {
return match
}
}
})
}
return text
} catch (err) {
this.logger.log(err.message)
return text
}
return text
}
}