initial commit to support yaml format

This commit is contained in:
Amar Zavery 2017-06-26 10:38:47 -07:00
Родитель f7cf17e7c9
Коммит ec0d891aec
4 изменённых файлов: 87 добавлений и 21 удалений

Просмотреть файл

@ -24,6 +24,12 @@ exports.builder = {
'need to be transformed. If operationIds are not provided then the entire spec will be processed. ' +
'Example: "StorageAccounts_Create, StorageAccounts_List, Usages_List".',
string: true
},
y: {
alias: 'inYaml',
describe: 'A boolean flag when provided will indicate the tool to ' +
'generate wireformat in a yaml doc. Default is a markdown doc.',
boolean: true
}
};
@ -33,12 +39,13 @@ exports.handler = function (argv) {
let operationIds = argv.operationIds;
let outDir = argv.outDir;
let vOptions = {};
let emitYaml = argv.inYaml;
vOptions.consoleLogLevel = argv.logLevel;
vOptions.logFilepath = argv.f;
if (specPath.match(/.*composite.*/ig) !== null) {
return validate.generateWireFormatInCompositeSpec(specPath, vOptions);
return validate.generateWireFormatInCompositeSpec(specPath, outDir, emitYaml, vOptions);
} else {
return validate.generateWireFormat(specPath, outDir, operationIds, vOptions);
return validate.generateWireFormat(specPath, outDir, emitYaml, operationIds, vOptions);
}
}

Просмотреть файл

@ -7,9 +7,10 @@ const url = require('url'),
class HttpTemplate {
constructor(request, responses) {
constructor(request, responses, emitYaml) {
this.request = request;
this.responses = responses;
this.emitYaml = emitYaml || false;
}
getHost() {
@ -22,15 +23,16 @@ class HttpTemplate {
getRequestHeaders() {
let result = ``;
let padding = this.emitYaml ? ` ` : ``;
if (this.request.body) {
result += `Content-Length: ${JSON.stringify(this.request.body).length}\n`;
result += `${padding}Content-Length: ${JSON.stringify(this.request.body).length}\n`;
}
if (this.request.headers) {
let headers = Object.keys(this.request.headers);
for (let i = 0; i < headers.length; i++) {
let headerName = headers[i];
result += `${headerName}: ${this.request.headers[headerName]}`;
result += `${padding}${headerName}: ${this.request.headers[headerName]}`;
if (i !== headers.length - 1) {
result += `\n`;
}
@ -41,15 +43,16 @@ class HttpTemplate {
getCurlRequestHeaders() {
let result = ``;
let padding = this.emitYaml ? ` ` : ``;
if (this.request.body) {
result += ` \n-H 'Content-Length: ${JSON.stringify(this.request.body).length}' \\`;
result += `\n${padding}-H 'Content-Length: ${JSON.stringify(this.request.body).length}' \\`;
}
if (this.request.headers) {
let headers = Object.keys(this.request.headers);
for (let i = 0; i < headers.length; i++) {
let headerName = headers[i];
result += `\n-H '${headerName}: ${this.request.headers[headerName]}' \\`;
result += `\n${padding}-H '${headerName}: ${this.request.headers[headerName]}' \\`;
}
}
return result;
@ -63,18 +66,23 @@ class HttpTemplate {
return body;
}
//The format for request body in Curl has been inspired from the following links:
// - https://stackoverflow.com/questions/34847981/curl-with-multiline-of-json
// - https://ok-b.org/t/34847981/curl-with-multiline-of-json
getCurlRequestBody() {
let body = ``;
let padding = this.emitYaml ? ` ` : ``;
if (this.request && this.request.body !== null && this.request.body !== undefined) {
body = `\n-d ${JSON.stringify(this.request.body, null, 2).split('\n').join(' \\\n')}`;
body = `\n${padding}-d @- << EOF\n${padding}${JSON.stringify(this.request.body, null, 2).split(`\n`).join(`\n${padding}`)}\n${padding}EOF`;
}
return body;
}
getResponseHeaders(response) {
let result = ``;
let padding = this.emitYaml ? ` ` : ``;
if (response.body) {
result += `Content-Length: ${JSON.stringify(response.body).length}\n`;
result += `${padding}Content-Length: ${JSON.stringify(response.body).length}\n`;
}
let gotContentType = false;
if (response.headers) {
@ -82,14 +90,14 @@ class HttpTemplate {
for (let i = 0; i < headers.length; i++) {
let headerName = headers[i];
if (headerName.match(/^Content-Type$/ig) !== null) gotContentType = true;
result += `${headerName}: ${response.headers[headerName]}`;
result += `${padding}${headerName}: ${response.headers[headerName]}`;
if (i !== headers.length - 1) {
result += `\n`;
}
}
}
if (!gotContentType) {
result += `Content-Type: application/json; charset=utf-8`
result += `${padding}Content-Type: application/json; charset=utf-8`
}
return result;
}
@ -103,7 +111,8 @@ class HttpTemplate {
}
populateRequest() {
let requestTemplate =
let requestTemplate = ``;
let requestTemplateMD =
`## Request
\`\`\`http
@ -117,13 +126,30 @@ ${this.getRequestBody()}
\`\`\`\
`;
let requestTemplateYAML =
`#Request
request: |
${this.request.method} ${this.request.url} HTTP/1.1
Authorization: Bearer <token>
${this.getRequestHeaders()}
host: ${this.getHost()}
Connection: close
${this.getRequestBody()}
`;
requestTemplate = this.emitYaml ? requestTemplateYAML : requestTemplateMD;
return requestTemplate;
}
populateResponse(response, responseType) {
if (!responseType) responseType = 'Response';
let responseGuid = uuid.v4();
let responseTemplate = `
let responseTemplate = ``;
let responseTemplateMD = `
## ${responseType}
#### StatusCode: ${response.statusCode}
@ -145,17 +171,48 @@ Connection: close
${this.getResponseBody(response)}
\`\`\`
`;
let responseTemplateYAML = `
#${responseType}
response:
#${response.statusCode}
${response.statusCode}: |
HTTP 1.1 ${response.statusCode}
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
x-ms-ratelimit-remaining-subscription-writes: 1199
x-ms-request-id: ${responseGuid}
x-ms-correlation-request-id: ${responseGuid}
x-ms-routing-request-id: WESTUS2:${new Date().toISOString().replace(/(\W)/ig, '')}:${responseGuid}
Strict-Transport-Security: max-age=31536000; includeSubDomains
${this.getResponseHeaders(response)}
Date: ${new Date().toUTCString()}
Connection: close
${this.getResponseBody(response)}
`;
responseTemplate = this.emitYaml ? responseTemplateYAML : responseTemplateMD;
return responseTemplate;
}
populateCurl() {
let template =
let template = ``;
let templateMD =
`\n## Curl
\`\`\`bash
curl -X ${this.request.method} '${this.request.url}' \\\n-H 'authorization: bearer <token>' \\${this.getCurlRequestHeaders()}${this.getCurlRequestBody()}
\`\`\`
`;
let templateYAML =
`\n#Curl
curl: |
curl -X ${this.request.method} '${this.request.url}' \\\n -H 'authorization: bearer <token>' \\${this.getCurlRequestHeaders()}${this.getCurlRequestBody()}
`;
template = this.emitYaml ? templateYAML : templateMD;
return template;
}

Просмотреть файл

@ -164,11 +164,11 @@ exports.resolveCompositeSpec = function resolveCompositeSpec(specPath, outputDir
};
exports.generateWireFormat = function generateWireFormat(specPath, outDir, operationIds, options) {
exports.generateWireFormat = function generateWireFormat(specPath, outDir, emitYaml, operationIds, options) {
if (!options) options = {};
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel;
log.filepath = options.logFilepath || log.filepath;
let wfGenerator = new WireFormatGenerator(specPath, null, outDir);
let wfGenerator = new WireFormatGenerator(specPath, null, outDir, emitYaml);
return wfGenerator.initialize().then(function () {
log.info(`Generating wire format request and responses for swagger spec: "${specPath}":\n`);
wfGenerator.processOperations(operationIds);
@ -179,7 +179,7 @@ exports.generateWireFormat = function generateWireFormat(specPath, outDir, opera
});
};
exports.generateWireFormatInCompositeSpec = function generateWireFormatInCompositeSpec(compositeSpecPath, outDir, options) {
exports.generateWireFormatInCompositeSpec = function generateWireFormatInCompositeSpec(compositeSpecPath, outDir, emitYaml, options) {
if (!options) options = {};
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel;
log.filepath = options.logFilepath || log.filepath;
@ -187,7 +187,7 @@ exports.generateWireFormatInCompositeSpec = function generateWireFormatInComposi
options.consoleLogLevel = log.consoleLogLevel;
options.logFilepath = log.filepath;
let promiseFactories = docs.map(function (doc) {
return function () { return exports.generateWireFormat(doc, outDir, null, options); }
return function () { return exports.generateWireFormat(doc, outDir, emitYaml, null, options); }
});
return utils.executePromisesSequentially(promiseFactories);
}).catch(function (err) {

Просмотреть файл

@ -19,7 +19,7 @@ const ErrorCodes = Constants.ErrorCodes;
class WireFormatGenerator {
constructor(specPath, specInJson, wireFormatDir) {
constructor(specPath, specInJson, wireFormatDir, emitYaml) {
if (specPath === null || specPath === undefined || typeof specPath.valueOf() !== 'string' || !specPath.trim().length) {
throw new Error('specPath is a required parameter of type string and it cannot be an empty string.')
}
@ -37,6 +37,7 @@ class WireFormatGenerator {
if (!fs.existsSync(this.wireFormatDir)) {
fs.mkdirSync(this.wireFormatDir);
}
this.emitYaml = emitYaml || false;
this.specInJson = specInJson;
this.specResolver = null;
this.swaggerApi = null;
@ -248,9 +249,10 @@ class WireFormatGenerator {
let sampleRequest = self.processRequest(operation, xmsExample.parameters);
let sampleResponses = self.processXmsExampleResponses(operation, xmsExample.responses);
let exampleFileName = path.basename(xmsExamples[scenario].filePath);
let wireformatFileName = `${exampleFileName.substring(0, exampleFileName.indexOf(path.extname(exampleFileName)))}.md`;
let wireformatFileName = `${exampleFileName.substring(0, exampleFileName.indexOf(path.extname(exampleFileName)))}.`;
wireformatFileName += self.emitYaml ? 'yml' : 'md';
let fileName = path.join(self.wireFormatDir, wireformatFileName);
let httpTempl = new HttpTemplate(sampleRequest, sampleResponses);
let httpTempl = new HttpTemplate(sampleRequest, sampleResponses, self.emitYaml);
let sampleData = httpTempl.populate();
fs.writeFileSync(fileName, sampleData, { encoding: 'utf8' });
}