Skip to content

Commit

Permalink
fn support
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderkirtzel committed Feb 27, 2025
1 parent d0a520e commit f1d39bd
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 53 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

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

23 changes: 23 additions & 0 deletions website/docs/destinations/event_mapping.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,15 @@ import {
DataSet,
DataComplete,
DataLoop,
DataCondition,
DataConsent,
DataFn,
} from '@site/src/components/templates/mappings/eventConfig';
import { DestinationPush } from '@site/src/components/templates/destination';
import Link from '@docusaurus/Link';
import { getEvent } from '@elbwalker/utils';

export const event = getEvent('order complete');

<DestinationContextProvider
destination={destination}
Expand Down Expand Up @@ -132,17 +139,33 @@ used for creating an array of dynamic length.
Is a function to check if the mapping should be used. It returns a boolean, if
it's `true` the mapping will be used.

<DataCondition />

### consent

Some values may require an explicit consent state. It can be used to redact
value and protect a users privacy by hiding information.

<DataConsent />

### fn

A function that returns the value. It receives the current event context, the
mapping configuration and the options about the current instance with additional
properties.

<DestinationPush event={{ data: event.data }}>
{`{
data: {
fn: (event) => {
console.log("🚀 ~ event:", event)
return Date.now() + event.data.id;
},
value: "fallback"
}
}`}
</DestinationPush>

### validate

A final check to validate the value. After `key`, `loop`, `map` or `set`
Expand Down
16 changes: 10 additions & 6 deletions website/src/components/molecules/codeBox.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isString, tryCatch } from '@elbwalker/utils';
import { isString } from '@elbwalker/utils';
import { Highlight, themes as prismThemes } from 'prism-react-renderer';
import Editor from 'react-simple-code-editor';

Expand All @@ -11,24 +11,29 @@ export const formatValue = (value: unknown, options: FormatValueProps = {}) => {
const { intent = 2, quotes = false } = options;

let str = isString(value)
? `"${value}"`
: JSON.stringify(value, null, intent);
? quotes
? `"${value}"`
: value
: JSON.stringify(value, null, 2);

if (intent === 0)
str = str
.replace(/([:,])\s*(?=\S)/g, '$1 ')
.replace(/{\s*/, '{ ')
.replace(/\s*}/, ' }');

if (!quotes) str = str.replace(/"([^"]+)":/g, '$1:'); // Remove quotes from keys
str = str.replace(/"([^"]+)":/g, '$1:'); // Remove quotes from keys

return str;
};

export const parseInput = (code: unknown): unknown => {
return Function('"use strict"; return (' + code + ')')();
};

interface CodeBoxProps {
value: string;
label?: string;
format?: FormatValueProps;
onChange?: (code: string) => void;
disabled?: boolean;
language?: string;
Expand All @@ -39,7 +44,6 @@ interface CodeBoxProps {
const CodeBox: React.FC<CodeBoxProps> = ({
value = '',
label,
format,
onChange,
disabled = false,
language = 'javascript',
Expand Down
26 changes: 12 additions & 14 deletions website/src/components/organisms/mapping.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import type { Mapping as WalkerOSMapping, WalkerOS } from '@elbwalker/types';
import { useEffect, useState, useRef, useCallback, memo } from 'react';
import { debounce, isObject } from '@elbwalker/utils';
import CodeBox, { formatValue } from '../molecules/codeBox';
import { useEffect, useState, useRef, memo } from 'react';
import { debounce } from '@elbwalker/utils';
import CodeBox, { formatValue, parseInput } from '../molecules/codeBox';

interface MappingProps {
left: unknown;
middle?: unknown;
left: string;
middle?: string;
right?: string;
options?: WalkerOS.AnyObject;
mapping?: WalkerOSMapping.Config;
Expand All @@ -24,8 +24,8 @@ interface MappingProps {

const Mapping: React.FC<MappingProps> = memo(
({
left: initLeft = {},
middle: initMiddle = {},
left: initLeft = '{}',
middle: initMiddle = '{}',
right: initRight = '',
options,
fn,
Expand All @@ -35,20 +35,18 @@ const Mapping: React.FC<MappingProps> = memo(
labelRight = 'Result',
showMiddle = true,
}) => {
const [left, setLeft] = useState(formatValue(initLeft));
const [middle, setMiddle] = useState(formatValue(initMiddle));
const [left, setLeft] = useState(initLeft);
const [middle, setMiddle] = useState(initMiddle);
const [right, setRight] = useState<string[]>([initRight]);

const log = useRef((...args: unknown[]) => {
const params = args.map((arg) => formatValue(arg)).join(', ');
const params = args
.map((arg) => formatValue(arg, { quotes: true }))
.join(', ');

setRight([fnName ? `${fnName}(${params})` : params]);
}).current;

const parseInput = useCallback((code: string): unknown => {
return Function('"use strict"; return (' + code + ')')();
}, []);

const updateRight = useRef(
debounce(
(leftStr: string, middleStr: string, options: WalkerOS.AnyObject) => {
Expand Down
34 changes: 22 additions & 12 deletions website/src/components/templates/destination.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type { Destination, Mapping, WalkerOS } from '@elbwalker/types';
import React, {
createContext,
useCallback,
useContext,
useMemo,
useState,
} from 'react';
import type { Destination, Mapping, WalkerOS } from '@elbwalker/types';
import { createEvent } from '@elbwalker/utils';
import { createEvent, isString } from '@elbwalker/utils';
import MappingConfig from '../organisms/mapping';

import { formatValue, parseInput } from '../molecules/codeBox';
interface DestinationContextValue {
customConfig: WalkerOS.AnyObject;
setConfig: (config: WalkerOS.AnyObject) => void;
Expand Down Expand Up @@ -61,6 +61,7 @@ export const DestinationInit: React.FC<DestinationInitProps> = ({
custom = {},
}) => {
const { destination, setConfig, fnName } = useDestinationContext();
const left = formatValue(custom);

const mappingFn = (
left: never,
Expand Down Expand Up @@ -88,7 +89,7 @@ export const DestinationInit: React.FC<DestinationInitProps> = ({
return (
<MappingConfig
fnName={fnName}
left={custom}
left={left}
fn={mappingFn}
labelLeft="Custom Config"
showMiddle={false}
Expand All @@ -100,13 +101,16 @@ export const DestinationInit: React.FC<DestinationInitProps> = ({
interface DestinationPushProps {
event: WalkerOS.PartialEvent;
mapping?: Mapping.EventConfig | string;
children?: React.ReactNode;
}

export const DestinationPush: React.FC<DestinationPushProps> = ({
event,
mapping = {},
children,
}) => {
const { customConfig, destination, fnName } = useDestinationContext();
const middleValue = children ?? mapping;

const mappingFn = useCallback(
(
Expand All @@ -118,10 +122,12 @@ export const DestinationPush: React.FC<DestinationPushProps> = ({
try {
const event = createEvent(left);
const [entity, action] = event.event.split(' ');
const finalMapping = { [entity]: { [action]: middle } };
const finalMapping = {
[entity]: { [action]: middle },
};

destinationPush(
{ hooks: {} } as never, // Fake instance
{ hooks: {}, consent: event.consent } as never, // Fake instance
{
...destination,
config: {
Expand All @@ -142,8 +148,8 @@ export const DestinationPush: React.FC<DestinationPushProps> = ({
return (
<MappingConfig
fnName={fnName}
left={event}
middle={mapping}
left={formatValue(event)}
middle={formatValue(middleValue)}
fn={mappingFn}
options={customConfig}
/>
Expand All @@ -161,17 +167,19 @@ import {
tryCatch,
useHooks,
} from '@elbwalker/utils';
import { EventMapping } from '@elbwalker/types/src/mapping';

function resolveMappingData(
event: WalkerOS.Event,
data?: Mapping.Data,
options?: Mapping.Options,
): Destination.Data {
if (!data) return;

// @TODO update
return Array.isArray(data)
? data.map((item) => getMappingValue(event, item))
: getMappingValue(event, data);
? data.map((item) => getMappingValue(event, item, options))
: getMappingValue(event, data, options);
}

export function destinationPush(
Expand All @@ -182,7 +190,7 @@ export function destinationPush(
const { config } = destination;
const { eventMapping, mappingKey } = getMappingEvent(event, config.mapping);

let data = resolveMappingData(event, config.data);
let data = resolveMappingData(event, config.data, { instance });

if (eventMapping) {
// Check if event should be processed or ignored
Expand All @@ -193,7 +201,9 @@ export function destinationPush(

// Transform event to a custom data
if (eventMapping.data) {
const dataEvent = resolveMappingData(event, eventMapping.data);
const dataEvent = resolveMappingData(event, eventMapping.data, {
instance,
});
data =
isObject(data) && isObject(dataEvent) // Only merge objects
? assign(data, dataEvent)
Expand Down
Loading

0 comments on commit f1d39bd

Please sign in to comment.