sqlite-vec/site/build-ref.mjs

202 lines
4.4 KiB
JavaScript
Raw Normal View History

2024-07-16 22:28:15 -07:00
import Database from "better-sqlite3";
import { load } from "js-yaml";
import { fileURLToPath } from "node:url";
2024-07-31 12:55:03 -07:00
import { dirname, resolve } from "node:path";
2024-07-16 22:28:15 -07:00
import { readFileSync, writeFileSync } from "node:fs";
import * as v from "valibot";
import { table } from "table";
2024-07-22 21:24:44 -07:00
const HEADER = `---
outline: 2
---
# API Reference
A complete reference to all the SQL scalar functions, table functions, and virtual tables inside \`sqlite-vec\`.
::: warning
sqlite-vec is pre-v1, so expect breaking changes.
:::
[[toc]]
`;
2024-07-16 22:28:15 -07:00
const REF_PATH = resolve(
dirname(fileURLToPath(import.meta.url)),
2024-07-31 12:55:03 -07:00
"../reference.yaml",
2024-07-16 22:28:15 -07:00
);
const EXT_PATH = resolve(
dirname(fileURLToPath(import.meta.url)),
2024-07-31 12:55:03 -07:00
"../dist/vec0",
2024-07-16 22:28:15 -07:00
);
2024-07-22 21:24:44 -07:00
const DocSchema = v.objectWithRest(
{
sections: v.record(
v.string(),
v.object({
title: v.string(),
desc: v.string(),
2024-07-31 12:55:03 -07:00
}),
2024-07-22 21:24:44 -07:00
),
},
v.record(
2024-07-16 22:28:15 -07:00
v.string(),
v.object({
params: v.array(v.string()),
desc: v.string(),
example: v.union([v.string(), v.array(v.string())]),
2024-07-31 12:55:03 -07:00
}),
),
2024-07-22 21:24:44 -07:00
);
2024-07-16 22:28:15 -07:00
const tableConfig = {
border: {
topBody: ``,
topJoin: ``,
topLeft: ``,
topRight: ``,
bottomBody: ``,
bottomJoin: ``,
bottomLeft: ``,
bottomRight: ``,
bodyLeft: ``,
bodyRight: ``,
bodyJoin: ``,
joinBody: ``,
joinLeft: ``,
joinRight: ``,
joinJoin: ``,
},
};
function formatSingleValue(value) {
if (typeof value === "string") {
const s = `'${value.replace(/'/g, "''")}'`;
if (s.split("\n").length > 1) {
return `/*\n${s}\n*/`;
}
return `-- ${s}`;
}
if (typeof value === "number") return `-- ${value.toString()}`;
if (value === null) return "-- NULL";
if (value instanceof Uint8Array) {
let s = "X'";
for (const v of value) {
2024-07-22 21:24:44 -07:00
s += v.toString(16).toUpperCase().padStart(2, "0");
2024-07-16 22:28:15 -07:00
}
s += "'";
return `-- ${s}`;
}
2024-07-31 12:55:03 -07:00
if (typeof value === "object" || Array.isArray(value)) {
2024-07-16 22:28:15 -07:00
return "-- " + JSON.stringify(value, null, 2);
2024-07-31 12:55:03 -07:00
}
2024-07-16 22:28:15 -07:00
}
function formatValue(value) {
2024-07-22 21:24:44 -07:00
if (typeof value === "string") return `'${value}'`;
if (typeof value === "number") return value;
2024-07-16 22:28:15 -07:00
if (value === null) return "NULL";
if (value instanceof Uint8Array) {
let s = "X'";
for (const v of value) {
2024-07-22 21:24:44 -07:00
s += v.toString(16).toUpperCase().padStart(2, "0");
2024-07-16 22:28:15 -07:00
}
s += "'";
return s;
}
2024-07-31 12:55:03 -07:00
if (typeof value === "object" || Array.isArray(value)) {
2024-07-16 22:28:15 -07:00
return JSON.stringify(value, null, 2);
2024-07-31 12:55:03 -07:00
}
2024-07-16 22:28:15 -07:00
}
function tableize(stmt, results) {
const columnNames = stmt.columns().map((c) => c.name);
const rows = results.map((row) =>
row.map((value) => {
return formatValue(value);
})
);
return table([columnNames, ...rows], tableConfig);
}
function renderExamples(db, name, example) {
let md = "```sql\n";
const examples = Array.isArray(example) ? example : [example];
for (const example of examples) {
const sql = example
/* Strip any '```sql' markdown at the beginning */
.replace(/^\w*```sql/, "")
/* Strip any '```' markdown at the end */
.replace(/```\w*$/m, "")
.trim();
let stmt, results, error;
results = null;
try {
stmt = db.prepare(sql);
2024-07-22 21:24:44 -07:00
try {
stmt.raw(true);
} catch (err) {
1;
}
2024-07-16 22:28:15 -07:00
} catch (error) {
console.error(`Error preparing statement for ${name}:`);
console.error(error);
throw Error();
}
try {
results = stmt.all();
} catch (e) {
error = e.message;
}
md += sql + "\n";
if (!results) {
md += `-- ❌ ${error}\n\n`;
continue;
}
2024-07-31 12:55:03 -07:00
const result = results.length > 1 || stmt.columns().length > 1
? `/*\n${tableize(stmt, results)}\n*/\n`
: formatSingleValue(results[0][0]);
2024-07-16 22:28:15 -07:00
md += result + "\n\n";
}
md += "\n```\n\n";
return md;
}
2024-07-22 21:24:44 -07:00
let md = HEADER;
2024-07-16 22:28:15 -07:00
const doc = v.parse(DocSchema, load(readFileSync(REF_PATH, "utf8")));
const db = new Database();
db.loadExtension(EXT_PATH);
2024-07-22 21:24:44 -07:00
for (const section in doc.sections) {
md += `## ${doc.sections[section].title} {#${section}} \n\n`;
md += doc.sections[section].desc;
md += "\n\n";
2024-07-16 22:28:15 -07:00
2024-07-31 12:55:03 -07:00
for (
const [name, { params, desc, example }] of Object.entries(
doc[section],
)
) {
2024-07-22 21:24:44 -07:00
const headerText = `\`${name}(${(params ?? []).join(", ")})\` {#${name}}`;
2024-07-16 22:28:15 -07:00
2024-07-22 21:24:44 -07:00
md += "### " + headerText + "\n\n";
md += desc + "\n\n";
md += renderExamples(db, name, example);
}
2024-07-16 22:28:15 -07:00
}
writeFileSync("api-reference.md", md, "utf8");
console.log("done");