Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | 2x 2x 291x 291x 291x 2x 84x 6x 78x 2x 76x 76x 139x 139x 133x 76x 76x 80x 80x 80x 152x 72x 80x 133x 133x 35x 98x 98x 80x 76x 2x 41x 36x 34x 5x 29x 29x 29x 8x 29x 54x 29x 29x | import type { VariableSchema, VariableValue } from "@featurevisor/types";
import { mutate } from "./mutator";
const MUTATION_OP_SUFFIX = /:((?:append|prepend|after|before|remove))$/;
/**
* Get the root variable name from an override key (e.g. "tags:append" -> "tags", "payload.rows:append" -> "payload").
*/
function rootVariableFromOverrideKey(overrideKey: string): string {
const withoutSuffix = overrideKey.replace(MUTATION_OP_SUFFIX, "").trim();
const firstSegment = withoutSuffix.includes(".") ? withoutSuffix.split(".")[0] : withoutSuffix;
return firstSegment.replace(/\s*\[.*\]\s*$/, "").trim();
}
/**
* Resolve variable values from schema defaults and overrides.
* Override keys may be variable keys or dot-notation paths (e.g. "foo", "foo.a.b", "tags:append", "items[id=2]:after").
* Uses the mutator so nested paths and mutation notations are supported.
* Returns only variables that were desired to be overridden (i.e. appear in overrides).
*/
export function resolveMutationsForMultipleVariables(
variablesSchema: Record<string, VariableSchema> | undefined,
overrides: Record<string, VariableValue> | undefined,
): Record<string, VariableValue> | undefined {
if (!overrides || Object.keys(overrides).length === 0) {
return undefined;
}
if (!variablesSchema || Object.keys(variablesSchema).length === 0) {
return undefined;
}
const variableKeysToOutput = new Set<string>();
for (const overrideKey of Object.keys(overrides)) {
const variableKey = rootVariableFromOverrideKey(overrideKey);
if (variableKey && variablesSchema[variableKey]) {
variableKeysToOutput.add(variableKey);
}
}
const result: Record<string, VariableValue> = {};
for (const variableKey of variableKeysToOutput) {
const schema = variablesSchema[variableKey];
let value: VariableValue =
schema.defaultValue !== undefined && schema.defaultValue !== null
? (JSON.parse(JSON.stringify(schema.defaultValue)) as VariableValue)
: undefined;
const keysForThisVariable = Object.keys(overrides)
.filter(
(k) =>
rootVariableFromOverrideKey(k) === variableKey &&
(k === variableKey ||
k.startsWith(variableKey + ".") ||
k.startsWith(variableKey + "[") ||
k.startsWith(variableKey + ":")),
)
.sort((a, b) => a.length - b.length);
for (const overrideKey of keysForThisVariable) {
const overrideValue = overrides[overrideKey];
if (overrideKey === variableKey) {
value =
overrideValue !== undefined && overrideValue !== null
? (JSON.parse(JSON.stringify(overrideValue)) as VariableValue)
: overrideValue;
} else {
const notation = overrideKey.startsWith(variableKey + "[")
? overrideKey.slice(variableKey.length)
: overrideKey.startsWith(variableKey + ":")
? overrideKey.slice(variableKey.length)
: overrideKey.slice(variableKey.length + 1);
value = mutate(schema, value, notation, overrideValue);
}
}
result[variableKey] = value;
}
return Object.keys(result).length > 0 ? result : undefined;
}
/**
* Resolve a single variable's override value (e.g. from variableOverrides).
* If the value is a plain object with path-like keys, it is merged with the variable's default;
* otherwise the value is returned as-is (full replacement).
*/
export function resolveMutationsForSingleVariable(
variablesSchema: Record<string, VariableSchema> | undefined,
variableKey: string,
overrideValue: VariableValue,
baseValue?: VariableValue,
): VariableValue {
if (!variablesSchema || !variablesSchema[variableKey]) return overrideValue;
if (overrideValue === null || overrideValue === undefined) return overrideValue;
if (typeof overrideValue !== "object" || Array.isArray(overrideValue)) {
return overrideValue;
}
const pathMap = overrideValue as Record<string, VariableValue>;
const flat: Record<string, VariableValue> = {};
if (typeof baseValue !== "undefined") {
flat[variableKey] = JSON.parse(JSON.stringify(baseValue)) as VariableValue;
}
for (const [k, v] of Object.entries(pathMap)) {
flat[k === variableKey ? variableKey : variableKey + "." + k] = v;
}
const resolved = resolveMutationsForMultipleVariables(variablesSchema, flat);
return resolved && variableKey in resolved ? resolved[variableKey] : overrideValue;
}
|