forked from APIs-guru/aws2openapi
-
Notifications
You must be signed in to change notification settings - Fork 0
/
aws2openapi.js
154 lines (133 loc) · 5.44 KB
/
aws2openapi.js
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
149
150
151
152
153
154
'use strict';
const fs = require('fs');
const path = require('path');
const oasv = require('oas-validator');
const rr = require('recursive-readdir');
const yaml = require('js-yaml');
const aws2oa = require('./index.js');
const helpers = require('./helpers.js');
var preferred = require('./preferred.json');
function doit(input, regionConfig) {
var outputDir = (process.argv.length>3 ? process.argv[3] : './aws/');
if (!outputDir.endsWith('/')) outputDir += '/';
var outputYaml = (process.argv.length>4 ? (process.argv[4] == '-y') : false);
console.log(input);
var aws = require(path.resolve(input));
var options = {
regionConfig: regionConfig
};
try {
options.paginators = require(path.resolve(input.replace('.normal.','.paginators.')));
console.log(' Has paginators');
}
catch (ex) {}
try {
options.examples = require(path.resolve(input.replace('.normal.','.examples.')));
console.log(' Has examples version '+options.examples.version);
}
catch (ex) {}
// https://docs.aws.amazon.com/aws-sdk-php/v2/guide/feature-waiters.html
try {
options.waiters = require(path.resolve(input.replace('.normal.','.waiters2.')));
console.log(' Has waiters version '+options.waiters.version);
}
catch (ex) {}
var components = input.split('\\').join('/').split('/');
var filename = components[components.length-1];
options.filename = filename;
options.preferred = preferred;
filename = filename.replace('.normal.json','');
let prefix = helpers.extractServiceName(filename);
options.serviceName = prefix;
var result = aws2oa.convert(aws,options,function(err,openapi){
if ((err) && (Object.keys(err).length>0)) {
console.log(JSON.stringify(err));
}
if (openapi) {
oasv.validate(openapi, { laxurls: true, validateSchema: 'never', text: '{}' })
.then(options => {
})
.catch(ex => {
if (ex.options && ex.options.context) {
const errorLocation = ex.options.context.pop();
console.error('@',errorLocation);
}
console.error(aws.metadata.uid, ex.message);
process.exitCode = 1;
});
var version = filename.replace(prefix+'-','');
openapi.info["x-serviceName"] = prefix;
try {
fs.mkdirSync(outputDir+prefix);
}
catch (e) {}
try {
fs.mkdirSync(outputDir+prefix+'/'+version);
}
catch (e) {}
var origin = openapi.info['x-origin'];
var lastOrigin = origin[origin.length-1];
lastOrigin.url = lastOrigin.url.replace('{filename}',prefix+'/'+version+'/openapi.'+(outputYaml ? 'yaml' : 'json'));
if (outputYaml) {
fs.writeFileSync(outputDir+prefix+'/'+version+'/openapi.yaml',yaml.dump(openapi,{lineWidth: -1}),'utf8');
}
else {
fs.writeFileSync(outputDir+prefix+'/'+version+'/openapi.json',JSON.stringify(openapi,null,2),'utf8');
}
}
});
if (!result) {
console.log('Failed conversion: %s',input);
process.exitCode = 1;
}
}
function getRegionConfig(awsRoot) {
const regionConfig = require(path.join(awsRoot, 'lib', 'region_config_data.json'));
// We make a few amends to the official AWS endpoint config data. It describes the URLs
// that the SDK sends requests to, but that's only a subset of all valid URLs, so we add a
// couple of extra options that might be also relevant.
// All based on https://docs.aws.amazon.com/general/latest/gr/rande.html
// See buildServers below to understand how this is all used.
// EC2/autoscaling/ELB/EMR all allow both region-less and regioned URLs:
regionConfig.patterns['regionOrGeneral'] = {
"endpoint": "{service}.{region}.amazonaws.com",
"generalEndpoint": "{service}.amazonaws.com"
};
regionConfig.rules['us-east-1/ec2'] = 'regionOrGeneral';
regionConfig.rules['us-east-1/autoscaling'] = 'regionOrGeneral';
regionConfig.rules['us-east-1/elasticloadbalancing'] = 'regionOrGeneral';
regionConfig.rules['us-west-2/elasticmapreduce'] = 'regionOrGeneral';
regionConfig.rules['*/rds'] = 'regionOrGeneral';
// S3 allows both - and .: s3.us-east-1.amazonaws.com or s3-us-east-1.amazonaws.com
regionConfig.patterns['s3signature'].endpoint = "{service}{dash-or-dot}{region}.amazonaws.com";
// S3 also has a general endpoint, resolving to us-east-1
regionConfig.rules['us-east-1/s3'].endpoint = "{service}{dash-or-dot}{region}.amazonaws.com";
regionConfig.rules['us-east-1/s3'].generalEndpoint = "{service}.amazonaws.com";
// Chime/health/support have special non-standard endpoints
regionConfig.rules['*/chime'] = { endpoint: "service.chime.aws.amazon.com" };
regionConfig.rules['*/health'] = { endpoint: "https://health.us-east-1.amazonaws.com" };
regionConfig.rules['*/support'] = { endpoint: "https://support.us-east-1.amazonaws.com" };
return regionConfig;
}
let inputspec = process.argv[2];
if (inputspec) {
inputspec = path.resolve(inputspec);
let awsRoot = path.dirname(inputspec); // We require the given AWS spec to always be one dir down from the SDK root
const stats = fs.statSync(inputspec);
if (stats.isFile()) {
awsRoot = path.resolve(awsRoot, '..');
const regionConfig = getRegionConfig(awsRoot);
doit(inputspec, regionConfig);
}
else {
const regionConfig = getRegionConfig(awsRoot);
rr(inputspec, function(err, files) {
for (var f in files) {
const filename = files[f];
if (filename.indexOf('normal')>=0) {
doit(filename, regionConfig);
}
}
});
}
}