-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbuild-openapi.js
More file actions
102 lines (92 loc) · 3.46 KB
/
build-openapi.js
File metadata and controls
102 lines (92 loc) · 3.46 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
'use strict';
// scripts/build-openapi.js
const fs = require('fs');
const yaml = require('js-yaml');
const path = require('path');
/**
* Takes the openapi.yaml file and populates any missing fields using the
* components within the openAPI folder, as defined by the user. This
* way we can build elements dynamically, and ensure that the documentation
* is up to date as we develop.
*/
function buildOpenAPI() {
console.log('Building OpenAPI specification...');
// Create the `dist` folder (for distribution) if the
// `dist` folder does not exist.
if (!fs.existsSync('dist')) {
fs.mkdirSync('dist');
}
// Load the main openapi.yaml file, with its placeholders.
const mainSpec = yaml.load(fs.readFileSync('openapi-template.yaml', 'utf8'));
// We've split out the files for paths, and components:
const toBuild = {paths: './paths',
parameters: './components/parameters',
schemas: './components/schemas',
responses: './components/responses',
};
/**
* For each YAML element, parse through the associated directory and add
* each individual element. This allows us to split up our files efficiently.
* This is a recursive function, it goes into each subdirectory.
* @param {string} dir
* @return {array}
*/
function findYamlElements(dir) {
// self note: you can `push()` to a const array.
const yamlElements = [];
const items = fs.readdirSync(dir);
items.forEach((item) => {
const fullPath = path.join(dir, item);
if (fs.statSync(fullPath).isDirectory()) {
yamlElements.push(findYamlElements(fullPath));
} else if (item.endsWith('.yaml') || item.endsWith('.yml')) {
yamlElements.push(fullPath);
}
});
return yamlElements;
}
// Load in all the different section's files:
// This will give us `useFiles` which tells us which files are associated
// with each section.
Object.keys(toBuild).forEach((key) => {
console.log(`Loading paths for the ${key} section...`);
const outputs = findYamlElements(toBuild[key]).flat();
outputs.forEach((file) => {
console.log(`Loading paths from ${file}...`);
try {
const pathSpec = yaml.load(fs.readFileSync(file, 'utf8'));
if (pathSpec && typeof pathSpec === 'object') {
if (key === 'paths') {
Object.assign(mainSpec[key], pathSpec);
console.log(`Added ${Object.keys(pathSpec).length} paths from ${file}`);
} else {
Object.assign(mainSpec.components[key], pathSpec);
console.log(`Added ${Object.keys(pathSpec).length} components from ${file}`);
}
}
} catch (error) {
console.error(`❌ Error loading ${file}:`, error.message);
}
});
});
// Write combined spec
const outputFile = '../openapi.yaml';
fs.writeFileSync(outputFile, yaml.dump(mainSpec, {
indent: 2,
lineWidth: 120,
noRefs: false,
}));
console.log(`🎉 OpenAPI spec built successfully!`);
console.log(`📄 Total paths: ${Object.keys(mainSpec.paths).length}`);
console.log(`📄 Total schemas: ${Object.keys(mainSpec.components.schemas).length}`);
console.log(`📄 Total parameters: ${Object.keys(mainSpec.components.parameters).length}`);
console.log(`📄 Total responses: ${Object.keys(mainSpec.components.responses).length}`);
console.log(`📁 Output: ${outputFile}`);
}
// Handle errors gracefully
try {
buildOpenAPI();
} catch (error) {
console.error('❌ Build failed:', error.message);
process.exit(1);
};