From 80bb68e0aa489f2e3bbb70c7fd2fa8104fc52dce Mon Sep 17 00:00:00 2001 From: Innei Date: Sat, 30 Apr 2022 21:51:23 +0800 Subject: [PATCH] feat: add styling and typography method for macors --- src/common/guard/roles.guard.ts | 3 +- src/modules/markdown/markdown.controller.ts | 6 +- src/modules/markdown/markdown.service.ts | 10 +- src/processors/helper/helper.macro.service.ts | 108 +++++++++++++----- 4 files changed, 93 insertions(+), 34 deletions(-) diff --git a/src/common/guard/roles.guard.ts b/src/common/guard/roles.guard.ts index 118eec63..dafb7456 100644 --- a/src/common/guard/roles.guard.ts +++ b/src/common/guard/roles.guard.ts @@ -6,8 +6,7 @@ * @FilePath: /server/apps/server/src/auth/roles.guard.ts * Mark: Coding with Love */ -import { CanActivate, ExecutionContext } from '@nestjs/common' -import { Injectable } from '@nestjs/common' +import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common' import { AuthGuard } from '@nestjs/passport' import { isTest } from '~/global/env.global' diff --git a/src/modules/markdown/markdown.controller.ts b/src/modules/markdown/markdown.controller.ts index b6d9a4e8..ff89f518 100644 --- a/src/modules/markdown/markdown.controller.ts +++ b/src/modules/markdown/markdown.controller.ts @@ -178,7 +178,7 @@ export class MarkdownController { const { id } = params const now = performance.now() const [ - { html: markdown, document, type }, + { html: markdownMacros, document, type }, { url: { webUrl }, }, @@ -212,9 +212,7 @@ export class MarkdownController { })() const url = new URL(relativePath!, webUrl) - const markdownMacros = this.service.renderMarkdownContent( - await this.macroService.replaceTextMacro(markdown, document), - ) + const structure = await this.service.getRenderedMarkdownHtmlStructure( markdownMacros, document.title, diff --git a/src/modules/markdown/markdown.service.ts b/src/modules/markdown/markdown.service.ts index cb3ae0ef..bb3f5f95 100644 --- a/src/modules/markdown/markdown.service.ts +++ b/src/modules/markdown/markdown.service.ts @@ -15,6 +15,7 @@ import { ReturnModelType } from '@typegoose/typegoose' import { DatabaseService } from '~/processors/database/database.service' import { AssetService } from '~/processors/helper/helper.asset.service' +import { TextMacroService } from '~/processors/helper/helper.macro.service' import { InjectModel } from '~/transformers/model.transformer' import { CategoryModel } from '../category/category.model' @@ -39,6 +40,8 @@ export class MarkdownService { private readonly pageModel: ReturnModelType, private readonly databaseService: DatabaseService, + + private readonly macroService: TextMacroService, ) {} async insertPostsToDb(data: DatatypeDto[]) { @@ -223,7 +226,12 @@ ${text.trim()} } return { - html: doc.document.text, + html: this.renderMarkdownContent( + await this.macroService.replaceTextMacro( + doc.document.text, + doc.document, + ), + ), ...doc, document: doc.document, } diff --git a/src/processors/helper/helper.macro.service.ts b/src/processors/helper/helper.macro.service.ts index c4b8320e..c89621a9 100644 --- a/src/processors/helper/helper.macro.service.ts +++ b/src/processors/helper/helper.macro.service.ts @@ -1,24 +1,29 @@ import dayjs from 'dayjs' +import { FastifyRequest } from 'fastify' import { marked } from 'marked' -import { BadRequestException, Injectable, Logger } from '@nestjs/common' +import { + BadRequestException, + Inject, + Injectable, + Logger, + Scope, +} from '@nestjs/common' +import { REQUEST } from '@nestjs/core' +import { UserModel } from '~/modules/user/user.model' 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, - '?': /^\?\??(.*?)\??\?$/g, - } +const logger = new Logger('TextMacroService') +const RegMap = { + '#': /^#(.*?)$/g, + $: /^\$(.*?)$/g, + '?': /^\?\??(.*?)\??\?$/g, +} as const - private ifConditionGrammar(text: string, model: T) { +class HelperStatic { + public ifConditionGrammar(text: string, model: T) { const conditionSplitter = text.split('|') conditionSplitter.forEach((item: string, index: string | number) => { conditionSplitter[index] = item.replace(/"/g, '') @@ -66,9 +71,42 @@ export class TextMacroService { return output } + private generateFunctionContext = (variables: object) => { + return { + // time utils + dayjs: deepCloneWithFunction(dayjs), + fromNow: (time: Date | string) => dayjs(time).fromNow(), + + // typography + center: (text: string) => { + return `

${text}

` + }, + right: (text: string) => { + return `

${text}

` + }, + + // styling + opacity: (text: string, opacity = 0.8) => { + return `${text}` + }, + blur: (text: string, blur = 1) => { + return `${text}` + }, + color: (text: string, color = '') => { + return `${text}` + }, + size: (text: string, size = '1em') => { + return `${text}` + }, + + ...variables, + } + } public async replaceTextMacro( text: string, model: T, + + extraContext: Record = {}, ): Promise { try { const matchedReg = /\[\[\s(.*?)\s\]\]/g @@ -88,19 +126,19 @@ export class TextMacroService { } condition = condition?.trim() - if (condition.search(TextMacroService.Reg['?']) != -1) { - return this.ifConditionGrammar(condition, model) + if (condition.search(RegMap['?']) != -1) { + return helper.ifConditionGrammar(condition, model) } - if (condition.search(TextMacroService.Reg['$']) != -1) { + if (condition.search(RegMap['$']) != -1) { const variable = condition - .replace(TextMacroService.Reg['$'], '$1') + .replace(RegMap['$'], '$1') .replace(/\s/g, '') - return model[variable] + return model[variable] ?? extraContext[variable] } // eslint-disable-next-line no-useless-escape - if (condition.search(TextMacroService.Reg['#']) != -1) { + if (condition.search(RegMap['#']) != -1) { // eslint-disable-next-line no-useless-escape - const functions = condition.replace(TextMacroService.Reg['#'], '$1') + const functions = condition.replace(RegMap['#'], '$1') const variables = Object.keys(model).reduce( (acc, key) => ({ [`$${key}`]: model[key], ...acc }), @@ -110,12 +148,7 @@ export class TextMacroService { try { return safeEval( `return ${functions}`, - { - dayjs: deepCloneWithFunction(dayjs), - fromNow: (time: Date | string) => dayjs(time).fromNow(), - - ...variables, - }, + this.generateFunctionContext({ ...variables, ...extraContext }), { timeout: 1000 }, ) } catch { @@ -126,8 +159,29 @@ export class TextMacroService { } return text } catch (err) { - this.logger.log(err.message) + logger.log(err.message) return text } } } + +const helper = new HelperStatic() +@Injectable({ scope: Scope.REQUEST }) +export class TextMacroService { + constructor( + @Inject(REQUEST) + private readonly request: FastifyRequest & { + isMaster: boolean + user: UserModel + }, + ) {} + + public replaceTextMacro(text: string, model: object) { + const isMaster = this.request.isMaster + return helper.replaceTextMacro(text, model, { + hideForGuest(text: string) { + return isMaster ? text : '' + }, + }) + } +}