mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-02 02:34:42 +08:00
66 lines
3.4 KiB
JavaScript
66 lines
3.4 KiB
JavaScript
import { readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
import { dirname, join, relative, resolve } from "node:path";
|
|
import { execFileSync } from "node:child_process";
|
|
import { fileURLToPath } from "node:url";
|
|
import { parse } from "yaml";
|
|
|
|
// Input: an Apache doris-website checkout containing the versioned SQL manuals.
|
|
const docsRoot = process.argv[2];
|
|
if (!docsRoot) throw new Error("Usage: node scripts/generate-doris-functions.mjs /path/to/doris-website");
|
|
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
const revision = execFileSync("git", ["-C", docsRoot, "rev-parse", "HEAD"], { encoding: "utf8" }).trim();
|
|
|
|
function files(root) {
|
|
return readdirSync(root, { withFileTypes: true }).flatMap((entry) => {
|
|
const path = join(root, entry.name);
|
|
return entry.isDirectory() ? files(path) : path.endsWith(".md") ? [path] : [];
|
|
});
|
|
}
|
|
|
|
function definitions(version) {
|
|
const root = join(docsRoot, `versioned_docs/version-${version}/sql-manual/sql-functions`);
|
|
return files(root).flatMap((path) => {
|
|
const text = readFileSync(path, "utf8");
|
|
const frontmatter = /^---\s*\n([\s\S]*?)\n---/.exec(text)?.[1];
|
|
const metadata = frontmatter ? parse(frontmatter) : {};
|
|
const name = String(metadata?.title ?? "")
|
|
.trim()
|
|
.toUpperCase();
|
|
if (!/^[A-Z][A-Z0-9_]*$/.test(name) || metadata?.draft || name === "OVERVIEW" || relative(root, path).startsWith("combinators/")) return [];
|
|
const syntax = /##+\s+Syntax\s*\n([\s\S]*?)(?=\n##|$)/i.exec(text)?.[1] ?? "";
|
|
const code = [...syntax.matchAll(/```[^\n]*\n([\s\S]*?)```|`([^`\n]+)`/g)].map((match) => match[1] ?? match[2]);
|
|
const signatures = [
|
|
...new Set(
|
|
code.flatMap((block) => {
|
|
const matches = [...block.matchAll(new RegExp(`\\b${name}\\s*\\(`, "gi"))];
|
|
return matches.flatMap((match) => {
|
|
const start = match.index;
|
|
let depth = 1;
|
|
let end = start + match[0].length;
|
|
while (end < block.length && depth > 0) {
|
|
if (block[end] === "(") depth++;
|
|
if (block[end] === ")") depth--;
|
|
end++;
|
|
}
|
|
return depth === 0 ? [block.slice(start, end).replace(/\s+/g, " ")] : [];
|
|
});
|
|
}),
|
|
),
|
|
];
|
|
const category = relative(root, dirname(path)).replaceAll("\\", "/");
|
|
const document = relative(root, path).replaceAll("\\", "/").replace(/\.md$/, "");
|
|
return [{ name, category, signatures, docs: `https://doris.apache.org/docs/${version}/sql-manual/sql-functions/${document}/` }];
|
|
});
|
|
}
|
|
|
|
const older = new Map(definitions("2.1").map((definition) => [definition.name, definition]));
|
|
const current = new Map(definitions("3.x").map((definition) => [definition.name, definition]));
|
|
const entries = [...current.values()].map((definition) => ({ ...definition, documentedIn: older.has(definition.name) ? ["2.1", "3.x"] : ["3.x"] }));
|
|
for (const definition of older.values()) {
|
|
if (!current.has(definition.name)) entries.push({ ...definition, documentedIn: ["2.1"] });
|
|
}
|
|
entries.sort((left, right) => left.name.localeCompare(right.name, "en"));
|
|
const output = { source: "https://github.com/apache/doris-website", revision, license: "Apache-2.0", functions: entries };
|
|
writeFileSync(join(repoRoot, "apps/desktop/src/lib/sql/doris/functions.generated.json"), JSON.stringify(output, null, 2) + "\n");
|
|
console.log(`Generated ${entries.length} Doris functions from ${revision}`);
|