commit 26c11ba83ceea113b2dd598d2c077cbfe2ef6bd8
parent 4acae6513ed81664d904f035999041a846e02761
Author: Nullptrderef <nullptrderef@proton.me>
Date: Sun, 26 May 2024 00:19:18 +0200
feat: wip type gen
Diffstat:
1 file changed, 128 insertions(+), 0 deletions(-)
diff --git a/contrib/extract-types.mjs b/contrib/extract-types.mjs
@@ -0,0 +1,128 @@
+import fsSync, { promises as fs } from "fs";
+import * as path from "path";
+
+/**
+ * @param {string} file
+ */
+const runFileJob = async (file) => {
+ let workingFile = file;
+ const tsDefs = file.match(/[\t ]*\.\. ts\:def\:\: [a-zA-Z][a-zA-Z0-9_]*/g);
+ /** @type string[] */
+ const defines = [];
+ /** @type string[] */
+ const imports = [];
+ let dtsOutput = "";
+ if (tsDefs)
+ for (const def of tsDefs) {
+ if (!def) {
+ console.warn("No matches in ", file);
+ break;
+ }
+ workingFile = workingFile.substring(workingFile.indexOf(def));
+ let [defMatch, indentation, defName] = def.match(
+ /([\t ])*\.\. ts\:def\:\: ([a-zA-Z][a-zA-Z0-9_]*) *\n?/
+ );
+
+ // Extract the ts def
+ indentation = indentation ?? "";
+ workingFile = workingFile.substring(defMatch.length);
+ const workingFileLines = workingFile.split("\n");
+ let tsMatch = "";
+ while (workingFileLines[0]?.trim() === "") workingFileLines.shift();
+ while (
+ workingFileLines[0]?.trim() === "" ||
+ (workingFileLines[0] &&
+ new RegExp("^" + "[ \\t]".repeat(indentation.length + 2)).test(
+ workingFileLines[0]
+ ))
+ ) {
+ if (workingFileLines[0].length > indentation.length + 2)
+ workingFileLines[0] = workingFileLines[0].substring(
+ indentation.length + 2
+ );
+ tsMatch += workingFileLines.shift() + "\n";
+ }
+ workingFile = workingFileLines.join("\n");
+
+ // Convert comments to JSDocs
+ tsMatch = tsMatch
+ .replace(/([ \t]*\/\/.*\n?)+/g, (match) => {
+ match = match
+ .split("\n")
+ .map((v) => v.replace(/[ \t]+\/\/ ?/, "").trim())
+ .join("\n")
+ .trim();
+ if (match.includes("\n"))
+ match = `/**
+${match
+ .split("\n")
+ .map((v) => (v.trimStart().startsWith("//") ? v.replace("//", "") : v))
+ .map((v) => " *" + (v.startsWith(" ") ? "" : " ") + v)
+ .join("\n")
+ .replace(/\*\//g, "*/")}
+ */
+`;
+ else
+ match = `/**
+ * ${(match.trimStart().startsWith("//") ? match.replace("//", "") : match)
+ .trim()
+ .replace(/\*\//g, "*/")}
+ */
+`;
+ return match;
+ })
+ .trim();
+
+ defines.push(defName);
+ dtsOutput += tsMatch + "\n";
+ }
+
+ // Now, find the unknown imports
+
+ return {
+ defines,
+ dtsOutput,
+ };
+};
+
+(async () => {
+ const genDocsForDirs = ["core/"].map((v) => path.resolve(v));
+ const genDocsForFiles = (
+ await Promise.all(
+ genDocsForDirs.map(async (dir) =>
+ (await fs.readdir(dir)).map((file) => path.join(dir, file))
+ )
+ )
+ ).flat();
+ const output = path.resolve(
+ process.env.TYPE_OUTPUPT ?? process.env.TMP ?? process.env.TEMP ?? "/tmp",
+ "net.taler.docs.ts-extracted"
+ );
+ const tsDocOutput = path.join(output, "dts");
+ const zodOutput = path.join(output, "zod");
+
+ if (fsSync.existsSync(tsDocOutput))
+ await fs.rm(tsDocOutput, { recursive: true });
+ await fs.mkdir(tsDocOutput, {
+ recursive: true,
+ });
+ if (fsSync.existsSync(zodOutput)) await fs.rm(zodOutput, { recursive: true });
+ await fs.mkdir(zodOutput, {
+ recursive: true,
+ });
+ const jobResults = await Promise.all(
+ genDocsForFiles.map(async (filepath) => ({
+ source: filepath,
+ output: path.join(
+ tsDocOutput,
+ path.basename(filepath).replace(".rst", ".ts")
+ ),
+ result: await runFileJob(await fs.readFile(filepath, "utf-8")),
+ }))
+ );
+ await Promise.all(
+ jobResults.map(async ({ output, result }) => {
+ await fs.writeFile(output, result.dtsOutput);
+ })
+ );
+})();