Skip to content

Commit

Permalink
refactor(api-service): variable extraction (#7369)
Browse files Browse the repository at this point in the history
  • Loading branch information
djabarovgeorge authored Dec 24, 2024
1 parent 55f7de6 commit f0d20c3
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { Injectable } from '@nestjs/common';
import { PreviewPayload, TipTapNode } from '@novu/shared';
import { z } from 'zod';
import { processNodeAttrs } from '@novu/application-generic';
import { HydrateEmailSchemaCommand } from './hydrate-email-schema.command';
import { PlaceholderAggregation } from '../../../workflows-v2/usecases';

Expand Down Expand Up @@ -87,6 +88,8 @@ export class HydrateEmailSchemaUseCase {
placeholderAggregation: PlaceholderAggregation
) {
content.forEach((node, index) => {
processNodeAttrs(node);

if (this.isVariableNode(node)) {
this.variableLogic(masterPayload, node, content, index, placeholderAggregation);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { emailControlZodSchema } from '../../../workflows-v2/shared/schemas/emai
export class RenderEmailOutputCommand extends RenderCommand {}

@Injectable()
// todo rename to EmailOutputRenderer
export class RenderEmailOutputUsecase {
constructor(private expandEmailEditorSchemaUseCase: ExpandEmailEditorSchemaUsecase) {}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { JSONContent } from '@maily-to/render';
import _ from 'lodash';
import { processNodeAttrs, MailyContentTypeEnum } from '@novu/application-generic';

/**
* Processes raw Maily JSON editor state by converting variables to Liquid.js output syntax
Expand Down Expand Up @@ -100,16 +101,12 @@ function processForLoopNode(node: JSONContent): JSONContent {
function processNode(node: JSONContent): JSONContent {
if (!node) return node;

const processedNode: JSONContent = { ...node };

if (processedNode.attrs) {
processedNode.attrs = processAttributes(processedNode.attrs);
}
const processedNode = processNodeAttrs(node);

switch (processedNode.type) {
case 'variable':
case MailyContentTypeEnum.VARIABLE:
return processVariableNode(processedNode);
case 'for':
case MailyContentTypeEnum.FOR:
return processForLoopNode(processedNode);
default:
if (Array.isArray(processedNode.content)) {
Expand All @@ -120,44 +117,6 @@ function processNode(node: JSONContent): JSONContent {
}
}

const LIQUID_WRAPPED_KEYS = ['showIfKey'] as const;
type LiquidWrappedKey = (typeof LIQUID_WRAPPED_KEYS)[number];

/**
* Processes node attributes by converting specific keys to Liquid.js syntax
* * Please update LIQUID_WRAPPED_KEYS if you want to wrap more attributes
* @example
* // Input
* {
* showIfKey: "user.isActive",
* title: "Hello",
* color: "blue"
* }
* // Output
* {
* showIfKey: "{{user.isActive}}",
* title: "Hello",
* color: "blue"
* }
*/
export function processAttributes(attrs: Record<string, unknown>): Record<string, unknown> {
return Object.entries(attrs).reduce(
(acc, [key, value]) => ({
...acc,
[key]: shouldWrapInLiquid(key) && isString(value) ? wrapInLiquidOutput(value) : value,
}),
{} as Record<string, unknown>
);
}

function shouldWrapInLiquid(key: string): key is LiquidWrappedKey {
return LIQUID_WRAPPED_KEYS.includes(key as LiquidWrappedKey);
}

function isString(value: unknown): value is string {
return typeof value === 'string';
}

function wrapInLiquidOutput(value: string): string {
return `{{${value}}}`;
}
3 changes: 2 additions & 1 deletion libs/application-generic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@
"rrule": "^2.7.2",
"rxjs": "7.8.1",
"sanitize-html": "^2.4.0",
"shortid": "^2.2.16"
"shortid": "^2.2.16",
"@maily-to/render": "^0.0.17"
},
"optionalDependencies": {
"@novu/ee-shared-services": "workspace:*",
Expand Down
1 change: 1 addition & 0 deletions libs/application-generic/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ export * from './tracing';
export * from './usecases';
export * from './utils';
export * from './utils/inject-auth-providers';
export * from './utils/process-node-attrs';
48 changes: 48 additions & 0 deletions libs/application-generic/src/utils/process-node-attrs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { JSONContent } from '@maily-to/render';

export enum MailyContentTypeEnum {
VARIABLE = 'variable',
FOR = 'for',
BUTTON = 'button',
IMAGE = 'image',
}

export const variableAttributeConfig = (type: MailyContentTypeEnum) => {
//todo add variable type
if (type === MailyContentTypeEnum.BUTTON) {
return [
{ attr: 'text', flag: 'isTextVariable' },
{ attr: 'url', flag: 'isUrlVariable' },
{ attr: 'showIfKey', flag: 'showIfKey' },
];
}

if (type === MailyContentTypeEnum.IMAGE) {
return [
{ attr: 'src', flag: 'isSrcVariable' },
{ attr: 'externalLink', flag: 'isExternalLinkVariable' },
{ attr: 'showIfKey', flag: 'showIfKey' },
];
}

return [{ attr: 'showIfKey', flag: 'showIfKey' }];
};

export function processNodeAttrs(node: JSONContent): JSONContent {
if (!node.attrs) return node;

const typeConfig = variableAttributeConfig(node.type as MailyContentTypeEnum);

for (const { attr, flag } of typeConfig) {
if (node.attrs[flag] && node.attrs[attr]) {
// eslint-disable-next-line no-param-reassign
node.attrs[attr] = wrapInLiquidOutput(node.attrs[attr] as string);
}
}

return node;
}

export function wrapInLiquidOutput(value: string): string {
return `{{${value}}}`;
}
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f0d20c3

Please sign in to comment.