1import type {
2 ModelCapabilities,
3 ProviderOptionDescriptor,
4 ProviderOptionSelection,
5} from "@t3tools/contracts";
6import {
7 buildProviderOptionSelectionsFromDescriptors,
8 getProviderOptionDescriptors,
9} from "@t3tools/shared/model";
10
11export function resolveProviderOptionDescriptors(input: {
12 readonly capabilities: ModelCapabilities | null | undefined;
13 readonly selections: ReadonlyArray<ProviderOptionSelection> | null | undefined;
14}): ReadonlyArray<ProviderOptionDescriptor> {
15 if (!input.capabilities) {
16 return [];
17 }
18 return getProviderOptionDescriptors({
19 caps: input.capabilities,
20 selections: input.selections,
21 });
22}
23
24/**
25 * Applies one option change (by descriptor id) and returns the full selection
26 * list to store on the model selection, or null when the change doesn't match
27 * an advertised descriptor / choice.
28 */
29export function applyProviderOptionSelection(
30 descriptors: ReadonlyArray<ProviderOptionDescriptor>,
31 change: ProviderOptionSelection,
32): ReadonlyArray<ProviderOptionSelection> | null {
33 const descriptor = descriptors.find((candidate) => candidate.id === change.id);
34 if (!descriptor) {
35 return null;
36 }
37 if (
38 (descriptor.type === "boolean" && typeof change.value !== "boolean") ||
39 (descriptor.type === "select" &&
40 (typeof change.value !== "string" ||
41 !descriptor.options.some((option) => option.id === change.value)))
42 ) {
43 return null;
44 }
45
46 const nextDescriptors = descriptors.map((candidate) =>
47 candidate.id === descriptor.id
48 ? {
49 ...candidate,
50 currentValue: change.value,
51 }
52 : candidate,
53 ) as ReadonlyArray<ProviderOptionDescriptor>;
54
55 return buildProviderOptionSelectionsFromDescriptors(nextDescriptors) ?? [];
56}