Skip to content

Commit 27a6758

Browse files
committed
new gen script
1 parent 9dbafb8 commit 27a6758

1 file changed

Lines changed: 97 additions & 2 deletions

File tree

packages/core/src/generate.ts

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import path from "path";
2+
import { mergeDeep } from "remeda";
23
import { z } from "zod";
34

45
import { Provider, Model } from "./schema.js";
@@ -8,15 +9,23 @@ const ExtendsModel = Model.sourceType()
89
.extend({
910
extends: z
1011
.object({
11-
from: z.string(),
12+
from: z
13+
.string()
14+
.regex(/^[^/]+\/[^/]+$/, "Must be in provider/model format"),
1215
omit: z.array(z.string()).optional(),
1316
})
1417
.strict(),
1518
})
1619
.strict();
1720

1821
export async function generate(directory: string) {
19-
const result = {} as Record<string, Provider>;
22+
const result: Record<string, Provider> = {};
23+
const extendsModels: Array<{
24+
providerID: string;
25+
modelID: string;
26+
modelPath: string;
27+
model: z.infer<typeof ExtendsModel>;
28+
}> = [];
2029
for await (const providerPath of new Bun.Glob("*/provider.toml").scan({
2130
cwd: directory,
2231
absolute: true,
@@ -48,6 +57,20 @@ export async function generate(directory: string) {
4857
},
4958
}).then((mod) => mod.default);
5059
toml.id = modelID;
60+
if (toml.extends !== undefined) {
61+
const model = ExtendsModel.safeParse(toml);
62+
if (!model.success) {
63+
model.error.cause = { modelPath, toml };
64+
throw model.error;
65+
}
66+
extendsModels.push({
67+
providerID,
68+
modelID,
69+
modelPath,
70+
model: model.data,
71+
});
72+
continue;
73+
}
5174
const model = Model.safeParse(toml);
5275
if (!model.success) {
5376
model.error.cause = { modelPath, toml };
@@ -58,5 +81,77 @@ export async function generate(directory: string) {
5881
result[providerID] = provider.data;
5982
}
6083

84+
for (const pendingModel of extendsModels) {
85+
const [providerID, modelID] = pendingModel.model.extends.from.split("/");
86+
const baseModel = result[providerID]?.models[modelID];
87+
if (baseModel === undefined) {
88+
throw new Error(`Unable to resolve extends.from: ${pendingModel.model.extends.from}`, {
89+
cause: { modelPath: pendingModel.modelPath, toml: pendingModel.model },
90+
});
91+
}
92+
93+
const { extends: extendsConfig, ...overrides } = pendingModel.model;
94+
const merged: Record<string, unknown> = structuredClone(
95+
mergeDeep(baseModel, overrides),
96+
);
97+
98+
for (const omit of extendsConfig.omit ?? []) {
99+
const parts = omit.split(".");
100+
const parents: Array<{
101+
value: Record<string, unknown>;
102+
key: string;
103+
}> = [];
104+
let current = merged;
105+
106+
for (const part of parts.slice(0, -1)) {
107+
const next = current[part];
108+
if (
109+
next === undefined ||
110+
next === null ||
111+
typeof next !== "object" ||
112+
Array.isArray(next)
113+
) {
114+
throw new Error(`Unable to omit missing path: ${omit}`, {
115+
cause: { modelPath: pendingModel.modelPath, toml: pendingModel.model },
116+
});
117+
}
118+
parents.push({ value: current, key: part });
119+
current = next as Record<string, unknown>;
120+
}
121+
122+
const lastPart = parts.at(-1);
123+
if (lastPart === undefined || !(lastPart in current)) {
124+
throw new Error(`Unable to omit missing path: ${omit}`, {
125+
cause: { modelPath: pendingModel.modelPath, toml: pendingModel.model },
126+
});
127+
}
128+
129+
delete current[lastPart];
130+
131+
for (let index = parents.length - 1; index >= 0; index--) {
132+
const parent = parents[index];
133+
const value = parent?.value[parent.key];
134+
if (
135+
value === null ||
136+
value === undefined ||
137+
typeof value !== "object" ||
138+
Array.isArray(value) ||
139+
Object.keys(value).length > 0
140+
) {
141+
break;
142+
}
143+
delete parent.value[parent.key];
144+
}
145+
}
146+
147+
const model = Model.safeParse(merged);
148+
if (!model.success) {
149+
model.error.cause = { modelPath: pendingModel.modelPath, toml: merged };
150+
throw model.error;
151+
}
152+
153+
result[pendingModel.providerID]!.models[pendingModel.modelID] = model.data;
154+
}
155+
61156
return result;
62157
}

0 commit comments

Comments
 (0)