mirror of
https://github.com/asg017/sqlite-vec.git
synced 2026-04-25 08:46:49 +02:00
docs and fuzz
This commit is contained in:
parent
ff30ed3df3
commit
f4fe53e584
8 changed files with 1312 additions and 103 deletions
194
site/build-ref.mjs
Normal file
194
site/build-ref.mjs
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
import Database from "better-sqlite3";
|
||||
import { load } from "js-yaml";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { resolve, dirname } from "node:path";
|
||||
import { readFileSync, writeFileSync } from "node:fs";
|
||||
import * as v from "valibot";
|
||||
import { table } from "table";
|
||||
|
||||
const REF_PATH = resolve(
|
||||
dirname(fileURLToPath(import.meta.url)),
|
||||
"../reference.yaml"
|
||||
);
|
||||
const EXT_PATH = resolve(
|
||||
dirname(fileURLToPath(import.meta.url)),
|
||||
"../dist/vec0"
|
||||
);
|
||||
|
||||
const DocSchema = v.object({
|
||||
sections: v.record(
|
||||
v.string(),
|
||||
v.object({
|
||||
title: v.string(),
|
||||
desc: v.string(),
|
||||
})
|
||||
),
|
||||
functions: v.record(
|
||||
v.string(),
|
||||
v.object({
|
||||
params: v.array(v.string()),
|
||||
desc: v.string(),
|
||||
section: v.string(),
|
||||
example: v.union([v.string(), v.array(v.string())]),
|
||||
})
|
||||
),
|
||||
/*table_functions: v.record(
|
||||
v.string(),
|
||||
v.object({
|
||||
params: v.array(v.string()),
|
||||
desc: v.string(),
|
||||
example: v.union([v.string(), v.array(v.string())]),
|
||||
})
|
||||
),*/
|
||||
});
|
||||
|
||||
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) {
|
||||
s += v.toString(16).toUpperCase();
|
||||
}
|
||||
s += "'";
|
||||
return `-- ${s}`;
|
||||
}
|
||||
if (typeof value === "object" || Array.isArray(value))
|
||||
return "-- " + JSON.stringify(value, null, 2);
|
||||
}
|
||||
function formatValue(value) {
|
||||
if (typeof value === "string" || typeof value === "number") return value;
|
||||
if (value === null) return "NULL";
|
||||
if (value instanceof Uint8Array) {
|
||||
let s = "X'";
|
||||
for (const v of value) {
|
||||
s += v.toString(16);
|
||||
}
|
||||
s += "'";
|
||||
return s;
|
||||
}
|
||||
if (typeof value === "object" || Array.isArray(value))
|
||||
return JSON.stringify(value, null, 2);
|
||||
}
|
||||
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);
|
||||
stmt.raw(true);
|
||||
} 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;
|
||||
}
|
||||
|
||||
const result =
|
||||
results.length > 1 || stmt.columns().length > 1
|
||||
? `/*\n${tableize(stmt, results)}\n*/\n`
|
||||
: formatSingleValue(results[0][0]);
|
||||
md += result + "\n\n";
|
||||
}
|
||||
|
||||
md += "\n```\n\n";
|
||||
|
||||
return md;
|
||||
}
|
||||
|
||||
let md = `# API Reference
|
||||
|
||||
::: warning
|
||||
sqlite-vec is pre-v1, so expect breaking changes.
|
||||
:::
|
||||
|
||||
[[toc]]
|
||||
|
||||
`;
|
||||
const doc = v.parse(DocSchema, load(readFileSync(REF_PATH, "utf8")));
|
||||
|
||||
const db = new Database();
|
||||
db.loadExtension(EXT_PATH);
|
||||
|
||||
let lastSection = null;
|
||||
for (const [name, { params, desc, example, section }] of Object.entries(
|
||||
doc.functions
|
||||
)) {
|
||||
const headerText = `\`${name}(${(params ?? []).join(", ")})\` {#${name}}`;
|
||||
|
||||
if (lastSection != section) {
|
||||
md += `## ${doc.sections[section].title} {#${section}} \n\n`;
|
||||
md += doc.sections[section].desc;
|
||||
md += "\n\n";
|
||||
lastSection = section;
|
||||
}
|
||||
|
||||
md += "### " + headerText + "\n\n";
|
||||
|
||||
md += desc + "\n\n";
|
||||
md += renderExamples(db, name, example);
|
||||
}
|
||||
|
||||
writeFileSync("api-reference.md", md, "utf8");
|
||||
console.log("done");
|
||||
Loading…
Add table
Add a link
Reference in a new issue