summaryrefslogtreecommitdiff
path: root/extract-tsdefs/extract.ts
diff options
context:
space:
mode:
Diffstat (limited to 'extract-tsdefs/extract.ts')
-rw-r--r--extract-tsdefs/extract.ts171
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();
};