diff options
Diffstat (limited to 'extract-tsdefs/extract.ts')
-rw-r--r-- | extract-tsdefs/extract.ts | 171 |
1 files changed, 146 insertions, 25 deletions
diff --git a/extract-tsdefs/extract.ts b/extract-tsdefs/extract.ts index 5012df93..b4721892 100644 --- a/extract-tsdefs/extract.ts +++ b/extract-tsdefs/extract.ts @@ -1,9 +1,26 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ + import * as ts from "typescript"; import * as fs from "fs/promises"; import * as path from "path"; import * as prettier from "prettier"; const currentDir = "."; +const excludedNames = new Set(["TalerErrorCode", "WalletBackupContentV1"]); const configFile = ts.findConfigFile( currentDir, @@ -37,27 +54,26 @@ const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); const fileSymbol = program.getTypeChecker().getSymbolAtLocation(sourceFile); -//console.log(sourceFile.referencedFiles); - -// for (const f of program.getSourceFiles()) { -// console.log(f.fileName); -// } - const expo = fileSymbol?.exports; if (!expo) { throw Error(); } -interface GatherState { +interface PerOpGatherState { opName: string; nameSet: Set<string>; - decls: ts.Declaration[]; - texts: string[]; + group: string; } -const builtin = new Set<string>("Array"); +interface GatherState { + declTexts: Map<string, string>; +} -function gatherDecls(node: ts.Node, gatherState: GatherState): void { +function gatherDecls( + node: ts.Node, + gatherState: GatherState, + perOpState: PerOpGatherState +): void { switch (node.kind) { case ts.SyntaxKind.TypeReference: { console.log(`typeref ${node.getText()}`); @@ -72,10 +88,13 @@ function gatherDecls(node: ts.Node, gatherState: GatherState): void { break; } const name = symbol.name; - if (gatherState.nameSet.has(name)) { + if (perOpState.nameSet.has(name)) { + break; + } + perOpState.nameSet.add(name); + if (excludedNames.has(name)) { break; } - gatherState.nameSet.add(name); const decls = symbol.getDeclarations(); decls?.forEach((decl) => { console.log(`decl kind ${ts.SyntaxKind[node.kind]}`); @@ -87,14 +106,30 @@ function gatherDecls(node: ts.Node, gatherState: GatherState): void { console.log(`decl source ${decl.getSourceFile().fileName}`); console.log(`mod name ${decl.getSourceFile().moduleName}`); switch (decl.kind) { + case ts.SyntaxKind.EnumMember: { + const parentType = checker.getTypeAtLocation(decl.parent); + const declText = printer.printNode( + ts.EmitHint.Unspecified, + decl, + decl.getSourceFile()! + ); + gatherState.declTexts.set( + name, + `// Enum value:\n// ${ + parentType.symbol.name || parentType.aliasSymbol?.name + }.${declText}` + ); + break; + } case ts.SyntaxKind.InterfaceDeclaration: + case ts.SyntaxKind.EnumDeclaration: case ts.SyntaxKind.TypeAliasDeclaration: { const declText = printer.printNode( ts.EmitHint.Unspecified, decl, decl.getSourceFile()! ); - gatherState.texts.push(declText); + gatherState.declTexts.set(name, declText); console.log(declText); break; } @@ -102,13 +137,13 @@ function gatherDecls(node: ts.Node, gatherState: GatherState): void { console.log(`unknown decl kind ${ts.SyntaxKind[decl.kind]}`); break; } - gatherDecls(decl, gatherState); + gatherDecls(decl, gatherState, perOpState); }); break; } default: node.forEachChild((child) => { - gatherDecls(child, gatherState); + gatherDecls(child, gatherState, perOpState); }); //console.log(`// unknown node kind ${ts.SyntaxKind[node.kind]}`); return; @@ -117,8 +152,12 @@ function gatherDecls(node: ts.Node, gatherState: GatherState): void { const main = async () => { const f = await fs.open("out.md", "w"); + const gatherState: GatherState = { + declTexts: new Map<string, string>(), + }; + const perOpStates: PerOpGatherState[] = []; - const gathers: GatherState[] = []; + let currentGroup: string = "Unknown Group"; expo.forEach((v, k) => { if (!v.name.endsWith("Op")) { @@ -126,29 +165,96 @@ const main = async () => { } const decls = v.getDeclarations(); decls?.forEach((decl) => { - const gatherState: GatherState = { + const commentRanges = ts.getLeadingCommentRanges( + sourceFile.getFullText(), + decl.getFullStart() + ); + + console.log(commentRanges); + commentRanges?.forEach((r) => { + const text = sourceFile.getFullText().slice(r.pos, r.end); + console.log("comment text:", text); + const groupPrefix = "group:"; + const loc = text.indexOf(groupPrefix); + if (loc >= 0) { + const groupName = text.slice(loc + groupPrefix.length); + console.log("got new group", groupName); + currentGroup = groupName; + } + }); + + const perOpState: PerOpGatherState = { opName: v.name, - decls: [], - texts: [], nameSet: new Set<string>(), + group: currentGroup, }; const declText = printer.printNode( ts.EmitHint.Unspecified, decl, decl.getSourceFile()! ); - gatherState.texts.push(declText); - gatherDecls(decl, gatherState); - gathers.push(gatherState); + perOpState.nameSet.add(v.name); + gatherState.declTexts.set(v.name, declText); + gatherDecls(decl, gatherState, perOpState); + perOpStates.push(perOpState); }); }); + const allNames: Set<string> = new Set(); + + for (const g of perOpStates) { + for (const k of g.nameSet.values()) { + allNames.add(k); + } + } + + const commonNames: Set<string> = new Set(); + + for (const name of allNames) { + let count = 0; + for (const g of perOpStates) { + for (const k of g.nameSet.values()) { + if (name === k) { + count++; + } + } + } + if (count > 1) { + console.log(`common name: ${name}`); + commonNames.add(name); + } + } + + const groups = new Set<string>(); + for (const g of perOpStates) { + groups.add(g.group); + } + await f.write(`# Wallet API Documentation\n`); + await f.write(`## Overview\n`); + for (const g of groups.values()) { + await f.write(`### ${g}\n`); + for (const op of perOpStates) { + if (op.group !== g) { + continue; + } + await f.write(`* [${op.opName}](#${op.opName.toLowerCase()})\n`); + } + } + await f.write(`## Operation Reference\n`); - for (const g of gathers) { + for (const g of perOpStates) { + await f.write(`(${g.opName.toLowerCase()})=\n`); await f.write(`### ${g.opName}\n`); - for (const text of g.texts) { + for (const name of g.nameSet.values()) { + if (commonNames.has(name)) { + continue; + } + const text = gatherState.declTexts.get(name); + if (!text) { + continue; + } await f.write("```typescript\n"); const formatted = prettier.format(text, { semi: true, @@ -160,6 +266,21 @@ const main = async () => { await f.write("\n"); } + await f.write(`## Common Declarations\n`); + for (const name of commonNames.values()) { + const text = gatherState.declTexts.get(name); + if (!text) { + continue; + } + await f.write("```typescript\n"); + const formatted = prettier.format(text, { + semi: true, + parser: "typescript", + }); + await f.write(`${formatted}`); + await f.write("```\n"); + } + await f.close(); }; |