-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
148 lines (120 loc) · 5.5 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
import fetch from "node-fetch";
import fs from "fs";
import { JSDOM } from "jsdom";
import "./extensions/string.extensions.js";
// https://gunici-prp.epias.com.tr/gunici-service/technical/tr/index.html
// https://seffaflik.epias.com.tr/transparency/technical/tr/index.html
// https://gunici-prp.epias.com.tr/gunici-trading-service/technical/tr/index.html
const OBJECT_BLUEPRINT = "class";
// const TARGET_URL = "https://gunici-prp.epias.com.tr/gunici-trading-service/technical/tr/index.html";
const OUTPUT_DIRECTORY_PATH = "outputs";
// const OUTPUT_FILE_PATH = `${OUTPUT_DIRECTORY_PATH}/output_${new URL(TARGET_URL).hostname}_${new Date().getTime()}.cs`;
const DEFAULT_NAME_CASE_METHOD = "toCamelCase";
const INCLUDE_DESCRIPTIONS = true;
let output = "";
const app = async () => {
const docUrls = [
"https://gunici-prp.epias.com.tr/gunici-service/technical/tr/index.html",
"https://seffaflik.epias.com.tr/transparency/technical/tr/index.html",
"https://gunici-prp.epias.com.tr/gunici-trading-service/technical/tr/index.html",
];
if (!fs.existsSync(OUTPUT_DIRECTORY_PATH)) fs.mkdirSync(OUTPUT_DIRECTORY_PATH);
for (const docUrl of docUrls) {
await convertDocDefinitions(docUrl);
}
};
const convertDocDefinitions = async (targetUrl: string) => {
const outputFilePath = `${OUTPUT_DIRECTORY_PATH}/output_${new URL(targetUrl).hostname}_${new Date().getTime()}.cs`;
const response = await fetch(targetUrl);
console.log(`FETCHED: ${targetUrl}`);
const htmlString = await response.text();
const dom = new JSDOM(htmlString);
const document = dom.window.document;
const sect1s = document.querySelectorAll("div.sect1");
const definitionsSect = [...sect1s.values()].find((sect) => sect.querySelector("#_definitions"));
const definitions = definitionsSect.querySelectorAll(".sectionbody .sect2");
for (const definition of definitions) {
const properties = [];
const table = definition.querySelector("table");
if (table === null) continue;
Array.from(table.tBodies[0].rows).forEach((row) => {
const name = row.cells[0].querySelector("strong").textContent.trim()[DEFAULT_NAME_CASE_METHOD]();
const isOptional = row.cells[0].querySelector("em").textContent.trim() === "opsiyonel";
if (row.cells.length === 3) {
const description = row.cells[1].textContent.trim().replace("\n", " ");
const type = typeConverter(row.cells[2].textContent.trim(), name);
properties.push({ name, isOptional, description, type });
} else {
const type = typeConverter(row.cells[1].textContent.trim(), name);
properties.push({ name, isOptional, type });
}
});
const className = definition.querySelector("h3").textContent.split(" ").at(-1).trim();
const classCode = `public ${OBJECT_BLUEPRINT} ${className} {\n${properties
.map((prop) => {
let propDef = ` public ${prop.type}${prop.isOptional && prop.type !== "string" ? "?" : ""} ${
prop.name
} { get; set; }`;
if (INCLUDE_DESCRIPTIONS && prop.description && prop.description.length > 0)
return propDef + ` // ${prop.description}`;
return propDef;
})
.join("\n")}\n}\n\n`;
output += classCode;
}
console.log("Writing...");
fs.writeFileSync(outputFilePath, output);
console.log("DONE");
};
const typeConverter = (type: string, propName: string) => {
const arrayTypeRegex = /<(.+)> array/;
const arrayTypeMatch = type.match(arrayTypeRegex);
if (arrayTypeMatch && arrayTypeMatch.length > 0) {
let typeString = arrayTypeMatch[1].trim();
if (typeString.includes("enum (")) return `${createAndGetEnum(typeString, propName)}[]`;
return `${getKnownType(typeString)}[]`;
}
const mapTypeRegex = /<(.+)> map/;
const mapTypeMatch = type.match(mapTypeRegex);
if (mapTypeMatch && mapTypeMatch.length > 0) {
let typeString = mapTypeMatch[1].trim();
let [type1, type2] = typeString.split(",").map((s) => s.trim());
if (type2.includes("enum (")) type2 = createAndGetEnum(typeString, propName);
return `Dictionary<${getKnownType(type1)}, ${getKnownType(type2)}>`;
}
if (type.includes("enum (")) return createAndGetEnum(type, propName);
return getKnownType(type);
};
const getKnownType = (type: string) => {
switch (type) {
case "string (date-time)":
case "string(date-time)":
return "DateTime";
case "integer (int64)":
case "integer(int64)":
return "long";
case "integer (int32)":
case "integer(int32)":
return "int";
case "number (double)":
case "number(double)":
case "number":
return "decimal";
case "boolean":
return "bool";
default:
return type.replace(/\s/g, "");
}
};
const createAndGetEnum = (enumString: string, propName: string) => {
const enumTypeRegex = /\((.+)\)/;
const enumTypeMatch = enumString.match(enumTypeRegex);
if (enumTypeMatch && enumTypeMatch.length > 0) {
const enums = enumTypeMatch[1].split(",").map((s) => s.trim());
const enumName = propName.capitalizeFirstLetter();
const classCode = `public enum ${enumName} {\n${enums.map((e) => `${e},`).join("\n")}\n}\n\n`;
output += classCode;
return enumName;
}
};
app();