taler-docs

Documentation for GNU Taler components, APIs and protocols
Log | Files | Refs | README | LICENSE

commit 26c11ba83ceea113b2dd598d2c077cbfe2ef6bd8
parent 4acae6513ed81664d904f035999041a846e02761
Author: Nullptrderef <nullptrderef@proton.me>
Date:   Sun, 26 May 2024 00:19:18 +0200

feat: wip type gen

Diffstat:
Acontrib/extract-types.mjs | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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); + }) + ); +})();