-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathnode.js
More file actions
executable file
·121 lines (112 loc) · 3.78 KB
/
node.js
File metadata and controls
executable file
·121 lines (112 loc) · 3.78 KB
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
#!/usr/bin/env node
import fs from "fs";
import chalk from "chalk";
import fetch from "node-fetch";
import { program } from "commander";
import { outputOptions, versionOption } from "./options.js";
program
.version("1.0.0")
.description("Generate a single HTML file with embedded Swagger/OpenAPI spec")
.option("-o, --output <file>", "Output HTML file", "swagger-api-docs.html")
.option("--versioned", "Use versioned Swagger UI assets", false)
.argument("<url>", "Swagger UI init.js URL or base URL")
.parse(process.argv);
const options = program.opts();
const inputArg = program.args[0];
if (!inputArg) {
console.error("Usage: node node.js <swagger-ui-init.js-URL or base URL>");
process.exit(1);
}
let swaggerInitUrl = inputArg;
if (!swaggerInitUrl.endsWith('swagger-ui-init.js')) {
swaggerInitUrl = swaggerInitUrl.replace(/\/+$/, '') + '/swagger-ui-init.js';
}
// Output file handling
let outputFile = outputOptions(options.output);
function makeHtmlWithSpec(spec) {
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Swagger Docs</title>
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist/swagger-ui.css" />
</head>
<body>
<div id="swagger-ui"></div>
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js"></script>
<script src="https://unpkg.com/swagger-ui-dist/swagger-ui-standalone-preset.js"></script>
<script>
// Embed the swagger JSON directly
const swaggerSpec = ${JSON.stringify(spec, null, 2)};
window.onload = () => {
SwaggerUIBundle({
spec: swaggerSpec,
dom_id: "#swagger-ui",
presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],
layout: "StandaloneLayout"
});
};
</script>
</body>
</html>`;
}
(async () => {
try {
console.log(chalk.blue.bold("🔄 Fetching swagger-ui-init.js..."));
const res = await fetch(swaggerInitUrl);
const text = await res.text();
// Extract the swaggerDoc object using a balanced-brace parser
const swaggerDocKey = '"swaggerDoc"';
const swaggerDocIdx = text.indexOf(swaggerDocKey);
if (swaggerDocIdx === -1) {
console.error(chalk.red.bold("❌ Could not find swaggerDoc key inside swagger-ui-init.js"));
process.exit(1);
}
let start = text.indexOf('{', swaggerDocIdx);
if (start === -1) {
console.error(chalk.red.bold("❌ Could not find opening brace for swaggerDoc object"));
process.exit(1);
}
let braceCount = 0;
let end = start;
for (let i = start; i < text.length; i++) {
if (text[i] === '{') braceCount++;
if (text[i] === '}') braceCount--;
if (braceCount === 0) {
end = i + 1;
break;
}
}
if (braceCount !== 0) {
console.error(chalk.red.bold("❌ Could not find matching closing brace for swaggerDoc object"));
process.exit(1);
}
const jsonText = text.slice(start, end);
let json;
try {
json = JSON.parse(jsonText);
} catch (e) {
console.error(chalk.red.bold("❌ Failed to parse swaggerDoc JSON: " + e.message));
process.exit(1);
}
// Adjust output file if versioned option is set
outputFile = versionOption(options.versioned, outputFile, json);
// Only output a single HTML file with the spec embedded
try {
fs.writeFileSync(outputFile, makeHtmlWithSpec(json));
console.log(chalk.green.bold("✅ Export complete!"));
console.log(
chalk.yellow.bold(
`Open ${outputFile} in your browser to view docs offline. No separate swagger.json needed.`,
),
);
} catch (e) {
console.error(
chalk.red.bold(`❌ Failed to write output file: ${e.message}`),
);
process.exit(1);
}
} catch (err) {
console.error(chalk.red.bold("❌ Failed:"), chalk.red(err.message));
}
})();