/** * Configuration for how to combine one document-root `x-*` extension's value * across inputs (proposal 48, generalising issue #60). * * A node mirrors one point in the extension value's own JSON shape: `kind` * says what shape is expected there, `strategy` says how to combine it. Left * unconfigured (the extension key absent from {@link ExtensionMergeStrategies}, * or a field absent from an `object`/`merge` node's `fields`), a value is * taken wholesale from whichever input declared it first -- today's behaviour, * unchanged. * * `kind` is declarative-only for `'first'`/`'last'`/`'error'`: those three * operate on a value of any shape, so a `scalar` node with strategy `'error'` * still fails on disagreement even if the actual value turns out to be an * object. Checking `kind` there and silently falling back on a mismatch would * mean the one strategy whose entire purpose is "tell me about disagreement" * could disagree and say nothing -- the worst version of the type-mismatch * fallback below. `kind` only gates behaviour for the strategies that inspect * internal structure (`concat`, `concat-unique`, `union-by-key`, `merge`), * where there is no sensible operation to fall back to except `'first'`. */ export type ExtensionMergeNode = /** A leaf value: string, number, boolean, or null. */ { kind: 'scalar'; strategy: 'first' | 'last' | 'error'; } /** A JSON array, combined wholesale -- one input's whole array wins. */ | { kind: 'array'; strategy: 'first' | 'last' | 'error'; } /** * A JSON array, combined element-by-element: every input's array * concatenated in input order (`'concat'`), optionally deduplicated by deep * equality (`'concat-unique'`). `sortBy` (optional) sorts the result * afterwards by a named field, for arrays of objects; omitted, the result * keeps concatenation order. * * If any input's value at this key is not an array, the whole node falls * back to `'first'` (see the module-level type-mismatch note). */ | { kind: 'array'; strategy: 'concat' | 'concat-unique'; sortBy?: string; } /** * A JSON array of objects, where elements sharing the same value at `key` * across (and within) inputs are the *same* logical entry and are combined * using `item`. `item` is required: defaulting it to wholesale `'first'` * would make this strategy behave exactly like `'concat-unique'` on the * outer array minus true duplicates, silently defeating the reason to pick * this strategy over that one. * * Elements whose key value appears only once across every input's array * pass through unchanged (via `item` applied to a single-element group). * Output order is first-seen order across all inputs, flattened -- there is * no `sortBy` here, because preserving first-seen order is this strategy's * point, not an accident of it. * * If any input's value is not an array, or any element is not an object * carrying a string/number/boolean value at `key`, the whole node falls * back to `'first'`. */ | { kind: 'array'; strategy: 'union-by-key'; key: string; item: ExtensionMergeNode; } /** A JSON object, combined wholesale -- one input's whole object wins. */ | { kind: 'object'; strategy: 'first' | 'last' | 'error'; } /** * A JSON object, combined field by field. A field not listed in `fields` * defaults to `'first'`, applied to that field's value wholesale regardless * of its own shape -- an unconfigured field is never guessed at. * * If any input's value at this key is not a plain object, the whole node * falls back to `'first'`. */ | { kind: 'object'; strategy: 'merge'; fields?: { [fieldName: string]: ExtensionMergeNode; }; }; /** Keyed by extension name, e.g. `x-tagGroups`. */ export type ExtensionMergeStrategies = { [extensionKey: string]: ExtensionMergeNode; }; export type ExtensionMergeSuccess = { ok: true; value: unknown; }; /** * `path` names where in the extension's value the disagreement was found * (e.g. `x-tagGroups[name=Admin].tags`), for a caller to build a message that * points at more than just the extension key. */ export type ExtensionMergeFailure = { ok: false; path: string; message: string; }; export type ExtensionMergeNodeResult = ExtensionMergeSuccess | ExtensionMergeFailure; /** * Combines the values found for one extension key (or one nested field/array * element inside it) across whichever inputs declared it. * * `values` must already have `undefined` entries filtered out -- each element * is one input's (or one grouped array element's) actual declared value. * `'last'` means last *present* in `values`, not "declared by the last input * overall": if only inputs 1 and 3 declare a field, `'last'` returns input * 3's value, and the same rule applies one level down -- inside a `merge` * node, a field declared only by the first of several occurrences returns * that occurrence's value for `'last'` too, because it is the only one * present at that field. * * `node === undefined` (the key, or this field, is not configured) always * returns `values[0]` unprocessed -- today's first-wins behaviour, and the * same rule an unlisted `fields` entry in a `merge` node uses, so leaving * something unconfigured is indistinguishable from how this library already * behaved before this mechanism existed. */ export declare function mergeExtensionNode(node: ExtensionMergeNode | undefined, values: unknown[], path: string): ExtensionMergeNodeResult; //# sourceMappingURL=extension-merge-strategies.d.ts.map