Last active
August 31, 2016 19:59
-
-
Save iamdustan/2e36a440b5702e14376bfba56d303427 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
/** | |
* This script will generate a JavaScript program to interact with the IBM | |
* Watson API. Try it out yourself! | |
* | |
* ``` | |
* $ git clone https://gist.github.com/2e36a440b5702e14376bfba56d303427.git watson | |
* $ cd watson | |
* $ chmod +x watson.sh | |
* $ ./watson.sh > output.js | |
* ``` | |
*/ | |
'use strict'; | |
const Https = require('https'); | |
const j = require('jscodeshift'); | |
Https.request({hostname: 'watson-api-explorer.mybluemix.net', path: '/listings/text-to-speech-v1.json'}, | |
res => { | |
res.setEncoding('utf8'); | |
let body = ''; | |
res.on('data', (chunk) => body += chunk); | |
res.on('end', () => performMagic(JSON.parse(body))); | |
}) | |
.end(); | |
/** | |
* Quick and dirty Object.entries polyfill | |
*/ | |
const entries = (obj) => { | |
const result = []; | |
for (const key in obj) { | |
result.push([key, obj[key]]); | |
} | |
return result; | |
} | |
/** | |
* This is where the aptly named magic begins. This loops through each path in | |
* the Swagger definition and generates our new program from it and outputs it | |
* to stdout. | |
*/ | |
const performMagic = (json) => { | |
const e = entries(json.paths); | |
const code = e | |
.filter((_, i) => i === e.length - 1) | |
.map(([path, methods]) => { | |
const code = []; | |
for (const method in methods) { | |
code.push(toFn(path, method, methods[method])); | |
} | |
return code; | |
}) | |
.reduce((result, current) => result.concat(current), []); | |
const program = j.program(code); | |
program.comments = [j.commentBlock('* @flow ')]; | |
process.stdout.write(j(program).toSource()); | |
}; | |
const capitalize = str => str[0].toUpperCase() + str.slice(1).toLowerCase(); | |
/** | |
* A simplistic transform of method + path to generate the function name. | |
* @example: | |
* genFnName('get', '/v1/synthesize') => 'getV1Synthesize'; | |
* genFnName('delete', '/v1/synthesize') => 'deleteV1Synthesize'; | |
*/ | |
const genFnName = (method, path) => | |
path.split(/\/|_/g).filter(Boolean).reduce((str, part) => | |
str + capitalize(part), | |
method.toLowerCase() | |
) | |
.replace(/{(\w+)}/g, (match, word) => capitalize(word)) | |
/** | |
* Generate the type annotation reference for the arguments | |
**/ | |
const genTypeAnnotation = (param) => { | |
if (param.type === 'string') { | |
if (param.enum) { | |
return j.unionTypeAnnotation(param.enum.map(e => j.stringLiteralTypeAnnotation(e, e))); | |
} | |
return j.stringTypeAnnotation(); | |
} | |
if (param.schema && param.schema.$ref) { | |
return j.genericTypeAnnotation(j.identifier(param.schema.$ref.replace('#/definitions/', '')), null); | |
} | |
// TODO: an exercise to the reader to handle all the types you may have | |
return j.anyTypeAnnotation(); | |
}; | |
/** | |
* Generate the function arguments | |
**/ | |
const genArgs = (params) => !params ? [] : params.map(param => Object.assign( | |
j.identifier(param.name + ':'), // hack around recast printer | |
{typeAnnotation: genTypeAnnotation(param)} | |
)); | |
/** | |
* Format description assuming single indentation and comment block like what | |
* you see in this file. This does not respect word boundaries. | |
*/ | |
const formatDescription = (str) => | |
str.match(/.{1,76}/g).reduce((str, part) => str + '\n * ' + part, '*') + '\n *' | |
/** | |
* Generate a JS AST from a Swagger entry. | |
*/ | |
const toFn = (path, method, obj) => { | |
return Object.assign( | |
j.exportDeclaration(false, j.functionDeclaration( | |
j.identifier(genFnName(method, path)), | |
genArgs(obj.parameters), | |
j.blockStatement([]) | |
)), | |
{comments: [j.commentBlock(formatDescription(obj.description))]} | |
); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment