Files
directus/packages/utils/shared/apply-options-data.ts
2025-08-05 14:52:35 -04:00

67 lines
2.0 KiB
TypeScript

import type { JsonValue } from '@directus/types';
import type { ResolveFn, Scope } from 'micromustache';
import { get, renderFn } from 'micromustache';
import { parseJSON } from './parse-json.js';
type Mustache<T> = T extends string
? JsonValue
: T extends Array<infer U>
? Array<Mustache<U>>
: T extends Record<any, any>
? { [K in keyof T]: Mustache<T[K]> }
: T;
export function applyOptionsData(
options: Record<string, any>,
data: Record<string, any>,
skipUndefinedKeys: string[] = [],
): Record<string, any> {
return Object.fromEntries(
Object.entries(options).map(([key, value]) => [key, renderMustache(value, data, skipUndefinedKeys.includes(key))]),
);
}
function resolveFn(skipUndefined: boolean): (path: string, scope: Scope) => any {
return (path, scope) => {
const value = get(scope, path);
if (value !== undefined || !skipUndefined) {
return typeof value === 'object' ? JSON.stringify(value) : value;
} else {
return `{{ ${path} }}`;
}
};
}
function renderMustache<T extends JsonValue>(item: T, scope: Scope, skipUndefined: boolean): Mustache<T> {
if (typeof item === 'string') {
const raw = item.match(/^\{\{\s*([^}\s]+)\s*\}\}$/);
if (raw !== null) {
const value = get(scope, raw[1]!);
if (value !== undefined) {
return value;
}
}
return renderFn(item, resolveFn(skipUndefined) as ResolveFn, scope, { explicit: true }) as Mustache<T>;
} else if (Array.isArray(item)) {
return item.map((element) => renderMustache(element, scope, skipUndefined)) as Mustache<T>;
} else if (typeof item === 'object' && item !== null) {
return Object.fromEntries(
Object.entries(item).map(([key, value]) => [key, renderMustache(value, scope, skipUndefined)]),
) as Mustache<T>;
} else {
return item as Mustache<T>;
}
}
export function optionToObject<T>(option: T): Exclude<T, string> {
return typeof option === 'string' ? parseJSON(option) : (option as Exclude<T, string>);
}
export function optionToString(option: unknown): string {
return typeof option === 'object' ? JSON.stringify(option) : String(option);
}