This commit is contained in:
Sergey Shandar 2018-05-29 15:38:27 -07:00
Родитель 68a1e601d8
Коммит a75a0a4d6b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 1C1B75FAA0B9B3C8
42 изменённых файлов: 3075 добавлений и 2876 удалений

19
cli.ts
Просмотреть файл

@ -1,15 +1,12 @@
#!/usr/bin/env node
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
import yargs = require('yargs')
import os = require('os')
import log = require('./lib/util/logging')
var yargs = require('yargs'),
os = require('os'),
log = require('./lib/util/logging');
var defaultLogDir = log.directory;
var logFilepath = log.filepath;
var packageVersion = require('./package.json').version;
let defaultLogDir = log.directory
let logFilepath = log.filepath
let packageVersion = require('./package.json').version
yargs
.version(packageVersion)
@ -29,8 +26,8 @@ yargs
})
.global(['h', 'l', 'f'])
.help()
.argv;
.argv
if (yargs.argv._.length === 0 && yargs.argv.h === false) {
yargs.coerce('help', function (arg: any) { return true; }).argv;
yargs.coerce('help', function (arg: any) { return true; }).argv
}

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

@ -1,24 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
import validate = require('./lib/validate');
var utils = require('./lib/util/utils');
import validate = require('./lib/validate')
import utils = require('./lib/util/utils')
// Easy to use methods from validate.js
exports.getDocumentsFromCompositeSwagger = validate.getDocumentsFromCompositeSwagger;
exports.validateSpec = validate.validateSpec;
exports.validateCompositeSpec = validate.validateCompositeSpec;
exports.validateExamples = validate.validateExamples;
exports.validateExamplesInCompositeSpec = validate.validateExamplesInCompositeSpec;
exports.log = require('./lib/util/logging');
exports.executePromisesSequentially = utils.executePromisesSequentially;
exports.resolveSpec = validate.resolveSpec;
exports.resolveCompositeSpec = validate.resolveCompositeSpec;
export let getDocumentsFromCompositeSwagger = validate.getDocumentsFromCompositeSwagger;
export let validateSpec = validate.validateSpec;
export let validateCompositeSpec = validate.validateCompositeSpec;
export let validateExamples = validate.validateExamples;
export let validateExamplesInCompositeSpec = validate.validateExamplesInCompositeSpec;
export let log = require('./lib/util/logging');
export let executePromisesSequentially = utils.executePromisesSequentially;
export let resolveSpec = validate.resolveSpec;
export let resolveCompositeSpec = validate.resolveCompositeSpec;
// Classes
exports.Validator = require('./lib/validators/specValidator');
exports.LiveValidator = require('./lib/validators/liveValidator');
exports.SpecResolver = require('./lib/validators/specResolver');
export let Validator = require('./lib/validators/specValidator');
export let LiveValidator = require('./lib/validators/liveValidator');
export let SpecResolver = require('./lib/validators/specResolver');
// Constants
exports.Constants = require('./lib/util/constants');
export let Constants = require('./lib/util/constants');

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

@ -2,22 +2,21 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
const vscodeJsonRpc = require("vscode-jsonrpc");
const linq = require('linq');
const jsonPath = require('jsonpath');
const yaml = require("js-yaml");
const utils = require("../util/utils");
import log = require('../util/logging');
const SpecValidator = require('../validators/specValidator');
const extensionBase = require('@microsoft.azure/autorest-extension-base');
const openAPIDocUrl = "https://github.com/Azure/oav";
exports = module.exports;
import vscodeJsonRpc = require("vscode-jsonrpc")
import linq = require('linq')
import jsonPath = require('jsonpath')
import yaml = require("js-yaml")
import utils = require("../util/utils")
import log = require('../util/logging')
import SpecValidator = require('../validators/specValidator')
import extensionBase = require('@microsoft.azure/autorest-extension-base')
const extension = new extensionBase.AutoRestExtension();
const modelValidatorPluginName = "model-validator";
const modelValidationCategory = "ExampleModelViolation";
const openAPIDocUrl = "https://github.com/Azure/oav"
const extension = new extensionBase.AutoRestExtension()
const modelValidatorPluginName = "model-validator"
const modelValidationCategory = "ExampleModelViolation"
class FormattedOutput{
constructor(
@ -35,117 +34,174 @@ class FormattedOutput{
*/
function analyzeSwagger(swaggerFileName: any, autoRestApi: any) {
return autoRestApi.ReadFile(swaggerFileName).then((swaggerFile: any) => {
const swagger = yaml.safeLoad(swaggerFile);
return exports.openApiValidationExample(swagger, swaggerFileName).then(function (exampleValidationResults: any) {
const swagger = yaml.safeLoad(swaggerFile)
return openApiValidationExample(swagger, swaggerFileName).then(function (exampleValidationResults: any) {
for (const result of exampleValidationResults) {
autoRestApi.Message({ Channel: result.channel, Text: result.text, Details: result.details, Key: result.code, Source: result.source });
autoRestApi.Message({
Channel: result.channel,
Text: result.text,
Details: result.details,
Key: result.code,
Source: result.source
})
}
// console.error(JSON.stringify(exampleValidationResults, null, 2));
});
});
// console.error(JSON.stringify(exampleValidationResults, null, 2))
})
})
}
extension.Add(modelValidatorPluginName, (autoRestApi: any) => {
return autoRestApi.ListInputs().then((swaggerFileNames: any) => {
const promises = [];
const promises = []
for (const swaggerFileName of swaggerFileNames) {
promises.push(
analyzeSwagger(swaggerFileName, autoRestApi)
);
)
}
return Promise.all(promises).then(_ => true);
});
});
return Promise.all(promises).then(_ => true)
})
})
exports.openApiValidationExample = function openApiValidationExample(swagger: any, swaggerFileName: any, options: any) {
var formattedResult: any[] = [];
if (!options) options = {};
options.consoleLogLevel = "off";
log.consoleLogLevel = options.consoleLogLevel;
let specVal = new SpecValidator(swaggerFileName, swagger, options);
//console.error(JSON.stringify(swagger, null, 2));
export function openApiValidationExample(swagger: any, swaggerFileName: any, options?: any) {
var formattedResult: any[] = []
if (!options) options = {}
options.consoleLogLevel = "off"
log.consoleLogLevel = options.consoleLogLevel
let specVal = new SpecValidator(swaggerFileName, swagger, options)
//console.error(JSON.stringify(swagger, null, 2))
return specVal.initialize().then(function () {
specVal.validateOperations();
specVal.validateOperations()
Promise.resolve(specVal.specValidationResult).then((specValidationResult) => {
for (let op of utils.getKeys(specValidationResult.operations)) {
const xmsExamplesNode = specValidationResult.operations[op]["x-ms-examples"];
for (let scenario of utils.getKeys(xmsExamplesNode.scenarios)) {
// invalid? meaning that there's an issue found in the validation
var scenarioItem = xmsExamplesNode.scenarios[scenario];
var scenarioItem = xmsExamplesNode.scenarios[scenario]
if (scenarioItem.isValid === false) {
// get path to x-ms-examples in swagger
const xmsexPath = linq.from(jsonPath.nodes(swagger, `$.paths[*][?(@.operationId==='${op}')]["x-ms-examples"]`))
const xmsexPath = linq
.from(jsonPath.nodes(swagger, `$.paths[*][?(@.operationId==='${op}')]["x-ms-examples"]`))
.select((x: any) => x.path)
.firstOrDefault();
if (!xmsexPath) {
throw new Error("Model Validator: Path to x-ms-examples not found.");
throw new Error("Model Validator: Path to x-ms-examples not found.")
}
//console.error(JSON.stringify(scenarioItem, null, 2));
var result = new FormattedOutput("verbose", scenarioItem, scenario, [modelValidationCategory], "Model validator found issue (see details).", [{ document: swaggerFileName, Position: { path: xmsexPath } }]);
formattedResult.push(result);
var result = new FormattedOutput(
"verbose",
scenarioItem,
scenario,
[modelValidationCategory],
"Model validator found issue (see details).",
[{ document: swaggerFileName, Position: { path: xmsexPath } }])
formattedResult.push(result)
// request
const request = scenarioItem.request;
const request = scenarioItem.request
if (request.isValid === false) {
const error = request.error;
const innerErrors = error.innerErrors;
const error = request.error
const innerErrors = error.innerErrors
if (!innerErrors || !innerErrors.length) {
throw new Error("Model Validator: Unexpected format.");
throw new Error("Model Validator: Unexpected format.")
}
for (const innerError of innerErrors) {
const path = convertIndicesFromStringToNumbers(innerError.path);
//console.error(JSON.stringify(error, null, 2));
let resultDetails = { type: "Error", code: error.code, message: error.message, id: error.id, validationCategory: modelValidationCategory, innerErrors: innerError };
result = new FormattedOutput("error", resultDetails, [error.code, error.id, modelValidationCategory],
innerError.message + ". \nScenario: " + scenario + ". \nDetails: " + JSON.stringify(innerError.errors, null, 2) + "\nMore info: " + openAPIDocUrl + "#" + error.id.toLowerCase() + "-" + error.code.toLowerCase() + "\n",
[{ document: swaggerFileName, Position: { path: path } }]);
formattedResult.push(result);
const path = convertIndicesFromStringToNumbers(innerError.path)
//console.error(JSON.stringify(error, null, 2))
let resultDetails = {
type: "Error",
code: error.code,
message: error.message,
id: error.id,
validationCategory: modelValidationCategory,
innerErrors: innerError
}
result = new FormattedOutput(
"error",
resultDetails,
[error.code, error.id, modelValidationCategory],
innerError.message
+ ". \nScenario: "
+ scenario
+ ". \nDetails: "
+ JSON.stringify(innerError.errors, null, 2)
+ "\nMore info: "
+ openAPIDocUrl
+ "#"
+ error.id.toLowerCase()
+ "-"
+ error.code.toLowerCase()
+ "\n",
[{ document: swaggerFileName, Position: { path: path } }])
formattedResult.push(result)
}
}
// responses
for (let responseCode of utils.getKeys(scenarioItem.responses)) {
const response = scenarioItem.responses[responseCode];
const response = scenarioItem.responses[responseCode]
if (response.isValid === false) {
const error = response.error;
const innerErrors = error.innerErrors;
const error = response.error
const innerErrors = error.innerErrors
if (!innerErrors || !innerErrors.length) {
throw new Error("Model Validator: Unexpected format.");
throw new Error("Model Validator: Unexpected format.")
}
for (const innerError of innerErrors) {
//console.error(JSON.stringify(error, null, 2));
let resultDetails = { type: "Error", code: error.code, message: error.message, id: error.id, validationCategory: modelValidationCategory, innerErrors: innerError };
result = new FormattedOutput("error", resultDetails, [error.code, error.id, modelValidationCategory],
innerError.message + ". \nScenario: " + scenario + ". \nDetails: " + JSON.stringify(innerError.errors, null, 2) + "\nMore info: " + openAPIDocUrl + "#" + error.id.toLowerCase() + "-" + error.code.toLowerCase() + "\n",
[{ document: swaggerFileName, Position: { path: xmsexPath.slice(0, xmsexPath.length - 1).concat(["responses", responseCode]) } }
]);
formattedResult.push(result);
let resultDetails = {
type: "Error",
code: error.code,
message: error.message,
id: error.id,
validationCategory: modelValidationCategory,
innerErrors: innerError
}
result = new FormattedOutput(
"error",
resultDetails,
[error.code, error.id, modelValidationCategory],
innerError.message
+ ". \nScenario: "
+ scenario
+ ". \nDetails: "
+ JSON.stringify(innerError.errors, null, 2)
+ "\nMore info: "
+ openAPIDocUrl
+ "#"
+ error.id.toLowerCase()
+ "-"
+ error.code.toLowerCase() + "\n",
[{
document: swaggerFileName,
Position: {
path: xmsexPath.slice(0, xmsexPath.length - 1).concat(["responses", responseCode])
}
}])
formattedResult.push(result)
}
}
}
}
}
}
});
return formattedResult;
})
return formattedResult
}).catch(function (err: any) {
console.error(err);
return Promise.reject(err);
});
};
console.error(err)
return Promise.reject(err)
})
}
/**
* Path comes with indices as strings in "inner errors", so converting those to actual numbers for path to work.
*/
function convertIndicesFromStringToNumbers(path: any) {
const result = path.slice();
const result = path.slice()
for (let i = 1; i < result.length; ++i) {
const num = parseInt(result[i]);
const num = parseInt(result[i])
if (!isNaN(num) && result[i - 1] === "parameters") {
result[i] = num;
result[i] = num
}
}
return result;
return result
}
extension.Run();
extension.Run()

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

@ -1,15 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
var util = require('util'),
log = require('../util/logging'),
validate = require('../validate');
import util = require('util')
import log = require('../util/logging')
import validate = require('../validate')
exports.command = 'extract-xmsexamples <spec-path> <recordings>';
export let command = 'extract-xmsexamples <spec-path> <recordings>'
exports.describe = 'Extracts the x-ms-examples for a given swagger from the .NET session recordings and saves them in a file.';
export let describe =
'Extracts the x-ms-examples for a given swagger from the .NET session recordings and saves them in a file.'
exports.builder = {
export let builder = {
d: {
alias: 'outDir',
describe: 'The output directory where the x-ms-examples files need to be stored. If not provided ' +
@ -22,19 +23,17 @@ exports.builder = {
boolean: true,
default: true
}
};
}
exports.handler = function (argv: any) {
log.debug(argv);
let specPath = argv.specPath;
let recordings = argv.recordings;
let vOptions: any = {};
vOptions.consoleLogLevel = argv.logLevel;
vOptions.logFilepath = argv.f;
vOptions.output = argv.outDir;
vOptions.matchApiVersion = argv.matchApiVersion;
export let handler = function (argv: any) {
log.debug(argv)
let specPath = argv.specPath
let recordings = argv.recordings
let vOptions: any = {}
vOptions.consoleLogLevel = argv.logLevel
vOptions.logFilepath = argv.f
vOptions.output = argv.outDir
vOptions.matchApiVersion = argv.matchApiVersion
return validate.extractXMsExamples(specPath, recordings, vOptions);
};
exports = module.exports;
return validate.extractXMsExamples(specPath, recordings, vOptions)
}

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

@ -1,15 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
var util = require('util'),
log = require('../util/logging'),
validate = require('../validate');
import util = require('util')
import log = require('../util/logging')
import validate = require('../validate')
exports.command = 'generate-uml <spec-path>';
export let command = 'generate-uml <spec-path>'
exports.describe = 'Generates a class diagram of the model definitions in the given swagger spec.';
export let describe = 'Generates a class diagram of the model definitions in the given swagger spec.'
exports.builder = {
export let builder = {
d: {
alias: 'outputDir',
describe: 'Output directory where the class diagram will be stored.',
@ -42,22 +42,20 @@ exports.builder = {
default: "TB",
choices: ["TB", "LR", "RL"]
}
};
}
exports.handler = function (argv: any) {
log.debug(argv);
let specPath = argv.specPath;
let vOptions: any = {};
vOptions.consoleLogLevel = argv.logLevel;
vOptions.logFilepath = argv.f;
vOptions.shouldDisableProperties = argv.p;
vOptions.shouldDisableAllof = argv.a;
vOptions.shouldDisableRefs = argv.r;
vOptions.direction = argv.i;
export let handler = function (argv: any) {
log.debug(argv)
let specPath = argv.specPath
let vOptions: any = {}
vOptions.consoleLogLevel = argv.logLevel
vOptions.logFilepath = argv.f
vOptions.shouldDisableProperties = argv.p
vOptions.shouldDisableAllof = argv.a
vOptions.shouldDisableRefs = argv.r
vOptions.direction = argv.i
function execGenerateUml() {
return validate.generateUml(specPath, argv.d, vOptions);
return validate.generateUml(specPath, argv.d, vOptions)
}
return execGenerateUml().catch((err: any) => { process.exitCode = 1; });
};
exports = module.exports;
return execGenerateUml().catch((err: any) => { process.exitCode = 1; })
}

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

@ -1,16 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
'use strict';
var util = require('util'),
log = require('../util/logging'),
validate = require('../validate');
import util = require('util')
import log = require('../util/logging')
import validate = require('../validate')
exports.command = 'generate-wireformat <spec-path>';
export let command = 'generate-wireformat <spec-path>'
exports.describe = 'Transforms the x-ms-examples for a given operation into raw request/response format and saves them in a markdown file.';
export let describe =
'Transforms the x-ms-examples for a given operation into raw request/response format and saves them in a markdown file.'
exports.builder = {
export let builder = {
d: {
alias: 'outDir',
describe: 'The output directory where the raw request/response markdown files need to be stored. If not provided and if the spec-path is a ' +
@ -31,26 +31,24 @@ exports.builder = {
'generate wireformat in a yaml doc. Default is a markdown doc.',
boolean: true
}
};
}
exports.handler = function (argv: any) {
log.debug(argv);
let specPath = argv.specPath;
let operationIds = argv.operationIds;
let outDir = argv.outDir;
let vOptions: any = {};
let emitYaml = argv.inYaml;
vOptions.consoleLogLevel = argv.logLevel;
vOptions.logFilepath = argv.f;
export let handler = function (argv: any) {
log.debug(argv)
let specPath = argv.specPath
let operationIds = argv.operationIds
let outDir = argv.outDir
let vOptions: any = {}
let emitYaml = argv.inYaml
vOptions.consoleLogLevel = argv.logLevel
vOptions.logFilepath = argv.f
function execWireFormat() {
if (specPath.match(/.*composite.*/ig) !== null) {
return validate.generateWireFormatInCompositeSpec(specPath, outDir, emitYaml, vOptions);
return validate.generateWireFormatInCompositeSpec(specPath, outDir, emitYaml, vOptions)
} else {
return validate.generateWireFormat(specPath, outDir, emitYaml, operationIds, vOptions);
return validate.generateWireFormat(specPath, outDir, emitYaml, operationIds, vOptions)
}
}
return execWireFormat().catch((err: any) => { process.exitCode = 1; });
};
exports = module.exports;
return execWireFormat().catch((err: any) => { process.exitCode = 1 })
}

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

@ -1,15 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
var util = require('util'),
log = require('../util/logging'),
validate = require('../validate');
import util = require('util')
import log = require('../util/logging')
import validate = require('../validate')
exports.command = 'resolve-spec <spec-path>';
export let command = 'resolve-spec <spec-path>'
exports.describe = 'Resolves the swagger spec based on the selected options like allOfs, relativePaths, examples etc.';
export let describe =
'Resolves the swagger spec based on the selected options like allOfs, relativePaths, examples etc.'
exports.builder = {
export let builder = {
a: {
alias: 'additionalPropertiesFalse',
describe: 'Should additionalProperties be set to false?',
@ -64,31 +65,29 @@ exports.builder = {
string: true,
default: './'
}
};
}
exports.handler = function (argv: any) {
log.debug(argv);
let specPath = argv.specPath;
let vOptions: any = {};
vOptions.consoleLogLevel = argv.logLevel;
vOptions.logFilepath = argv.f;
vOptions.shouldResolveRelativePaths = argv.r;
vOptions.shouldResolveXmsExamples = argv.e;
vOptions.shouldResolveAllOf = argv.o;
vOptions.shouldSetAdditionalPropertiesFalse = argv.a;
vOptions.shouldResolveParameterizedHost = argv.t;
vOptions.shouldResolvePureObjects = argv.p;
vOptions.shouldResolveDiscriminator = argv.c;
vOptions.shouldResolveNullableTypes = argv.n;
export let handler = function (argv: any) {
log.debug(argv)
let specPath = argv.specPath
let vOptions: any = {}
vOptions.consoleLogLevel = argv.logLevel
vOptions.logFilepath = argv.f
vOptions.shouldResolveRelativePaths = argv.r
vOptions.shouldResolveXmsExamples = argv.e
vOptions.shouldResolveAllOf = argv.o
vOptions.shouldSetAdditionalPropertiesFalse = argv.a
vOptions.shouldResolveParameterizedHost = argv.t
vOptions.shouldResolvePureObjects = argv.p
vOptions.shouldResolveDiscriminator = argv.c
vOptions.shouldResolveNullableTypes = argv.n
function execResolve() {
if (specPath.match(/.*composite.*/ig) !== null) {
return validate.resolveCompositeSpec(specPath, argv.d, vOptions);
return validate.resolveCompositeSpec(specPath, argv.d, vOptions)
} else {
return validate.resolveSpec(specPath, argv.d, vOptions);
return validate.resolveSpec(specPath, argv.d, vOptions)
}
}
return execResolve().catch((err: any) => { process.exitCode = 1; });
};
exports = module.exports;
return execResolve().catch((err: any) => { process.exitCode = 1 })
}

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

@ -1,15 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
var util = require('util'),
log = require('../util/logging'),
validate = require('../validate');
import util = require('util')
import log = require('../util/logging')
import validate = require('../validate')
exports.command = 'validate-example <spec-path>';
export let command = 'validate-example <spec-path>'
exports.describe = 'Performs validation of x-ms-examples and examples present in the spec.';
export let describe = 'Performs validation of x-ms-examples and examples present in the spec.'
exports.builder = {
export let builder = {
o: {
alias: 'operationIds',
describe: 'A comma separated string of operationIds for which the examples ' +
@ -17,20 +17,18 @@ exports.builder = {
'Example: "StorageAccounts_Create, StorageAccounts_List, Usages_List".',
string: true
}
};
}
exports.handler = function (argv: any) {
log.debug(argv);
let specPath = argv.specPath;
let operationIds = argv.operationIds;
let vOptions: any = {};
vOptions.consoleLogLevel = argv.logLevel;
vOptions.logFilepath = argv.f;
export let handler = function (argv: any) {
log.debug(argv)
let specPath = argv.specPath
let operationIds = argv.operationIds
let vOptions: any = {}
vOptions.consoleLogLevel = argv.logLevel
vOptions.logFilepath = argv.f
if (specPath.match(/.*composite.*/ig) !== null) {
return validate.validateExamplesInCompositeSpec(specPath, vOptions);
return validate.validateExamplesInCompositeSpec(specPath, vOptions)
} else {
return validate.validateExamples(specPath, operationIds, vOptions);
return validate.validateExamples(specPath, operationIds, vOptions)
}
};
exports = module.exports;
}

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

@ -1,26 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
var util = require('util'),
log = require('../util/logging'),
validate = require('../validate');
import util = require('util')
import log = require('../util/logging')
import validate = require('../validate')
exports.command = 'validate-spec <spec-path>';
export let command = 'validate-spec <spec-path>'
exports.describe = 'Performs semantic validation of the spec.';
export let describe = 'Performs semantic validation of the spec.'
exports.handler = function (argv: any) {
log.debug(argv);
let specPath = argv.specPath;
let vOptions: any = {};
vOptions.consoleLogLevel = argv.logLevel;
vOptions.logFilepath = argv.f;
export let handler = function (argv: any) {
log.debug(argv)
let specPath = argv.specPath
let vOptions: any = {}
vOptions.consoleLogLevel = argv.logLevel
vOptions.logFilepath = argv.f
if (specPath.match(/.*composite.*/ig) !== null) {
return validate.validateCompositeSpec(specPath, vOptions);
return validate.validateCompositeSpec(specPath, vOptions)
} else {
return validate.validateSpec(specPath, vOptions);
return validate.validateSpec(specPath, vOptions)
}
};
exports = module.exports;
}

2
lib/json-refs.d.ts поставляемый
Просмотреть файл

@ -1,3 +1,3 @@
declare module "json-refs" {
function findRefs(_0: any, _1: any): any;
function findRefs(_0: any, _1?: any): any
}

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

@ -1,14 +1,4 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for
* license information.
*
* Code generated by Microsoft (R) AutoRest Code Generator.
* Changes may cause incorrect behavior and will be lost if the code is
* regenerated.
*/
import LiveValidationError = require('./liveValidationError');
import LiveValidationError = require('./liveValidationError')
/**
* @class

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

@ -108,4 +108,4 @@ class ErrorWrapper extends ErrorResponse {
}
}
module.exports = ErrorWrapper;
export = ErrorWrapper;

292
lib/models/index.d.ts поставляемый
Просмотреть файл

@ -1,270 +1,22 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for
* license information.
*
* Code generated by Microsoft (R) AutoRest Code Generator.
* Changes may cause incorrect behavior and will be lost if the code is
* regenerated.
*/
import * as moment from "moment";
/**
* @class
* Initializes a new instance of the LiveRequest class.
* @constructor
* Properties of the request.
*
* @member {object} headers Headers of the request.
*
* @member {string} method Http verb of the request. Possible values include:
* 'GET', 'PUT', 'PATCH', 'POST', 'DELETE', 'HEAD', 'OPTIONS', 'TRACE'
*
* @member {string} url Url of the request.
*
* @member {object} [body] Parsed body of the request as a JSON.
*
*/
export interface LiveRequest {
headers: { [propertyName: string]: string };
method: string;
url: string;
body?: any;
}
/**
* @class
* Initializes a new instance of the LiveResponse class.
* @constructor
* Properties of the response.
*
* @member {string} statusCode The Response status code.
*
* @member {object} headers Headers of the response.
*
* @member {object} [body] Body of the response.
*
* @member {string} [encoding] The encoding of the response body when the body
* is a buffer.
*
*/
export interface LiveResponse {
statusCode: string;
headers: { [propertyName: string]: string };
body?: any;
encoding?: string;
}
/**
* @class
* Initializes a new instance of the RequestResponse class.
* @constructor
* Describes the live request and response to be validated.
*
* @member {object} liveRequest Schema for the live request to be validated
*
* @member {object} [liveRequest.headers] Headers of the request.
*
* @member {string} [liveRequest.method] Http verb of the request. Possible
* values include: 'GET', 'PUT', 'PATCH', 'POST', 'DELETE', 'HEAD', 'OPTIONS',
* 'TRACE'
*
* @member {string} [liveRequest.url] Url of the request.
*
* @member {object} [liveRequest.body] Parsed body of the request as a JSON.
*
* @member {object} liveResponse Schema for the live response to be validated
*
* @member {string} [liveResponse.statusCode] The Response status code.
*
* @member {object} [liveResponse.headers] Headers of the response.
*
* @member {object} [liveResponse.body] Body of the response.
*
* @member {string} [liveResponse.encoding] The encoding of the response body
* when the body is a buffer.
*
*/
export interface RequestResponse {
liveRequest: LiveRequest;
liveResponse: LiveResponse;
}
/**
* @class
* Initializes a new instance of the OperationInfo class.
* @constructor
* Describes the operation against which the live request and response
* validation happened.
*
* @member {string} operationId The id of the operation against which
* validation happened. This will help find the problematic information in the
* spec and will be useful in preparing report.
*
* @member {string} apiVersion Describes the api-version of the openapi
* specification. This will help find the openapi spec corresponding to that
* api-version and will be useful in preparing report.
*
*/
export interface OperationInfo {
operationId: string;
apiVersion: string;
}
/**
* @class
* Initializes a new instance of the LiveValidationError class.
* @constructor
* Describes the error occurred while performing validation on live
* request/response.
*
* @member {string} [code] The unique error code describing an error.
*
* @member {string} [message] The error message providing meaningful
* information.
*
*/
export interface LiveValidationError {
code?: string;
message?: string;
}
/**
* @class
* Initializes a new instance of the ErrorResponse class.
* @constructor
* Describes the error response for negative scenarios.
*
* @member {string} [description] Description of the model property or the
* parameter in the swagger spec that causes validation failure.
*
* @member {array} [params] The parameters used when validation failed
* (z-schema construct).
*
* @member {array} [path] The path to the location in the document or the model
* where the error/warning occurred.
*
*/
export interface ErrorResponse extends LiveValidationError {
description?: string;
params?: string[];
path?: string[];
}
/**
* @class
* Initializes a new instance of the ErrorWrapper class.
* @constructor
* Wrapper object
*
* @member {array} [errors] An array of inner errors.
*
*/
export interface ErrorWrapper extends ErrorResponse {
errors?: ErrorResponse[];
}
/**
* @class
* Initializes a new instance of the RequestValidationResult class.
* @constructor
* Describes the validation result of the live request.
*
* @member {boolean} [successfulRequest] Describes the status of live request
* validation.
*
* @member {array} [operationInfo] The corresponding operation(s) in openapi
* spec that was used for validating the request.
*
* @member {array} [errors] Provides more information about live response
* validation.
*
*/
export interface RequestValidationResult {
readonly successfulRequest?: boolean;
readonly operationInfo?: OperationInfo[];
readonly errors?: ErrorWrapper[];
}
/**
* @class
* Initializes a new instance of the ResponseValidationResult class.
* @constructor
* Describes the validation result of the live response.
*
* @member {boolean} [successfulResponse] Describes the status of live response
* validation.
*
* @member {array} [operationInfo] The corresponding operation(s) in openapi
* spec that was used for validating the response.
*
* @member {array} [errors] Provides more information about live response
* validation.
*
*/
export interface ResponseValidationResult {
readonly successfulResponse?: boolean;
readonly operationInfo?: OperationInfo[];
readonly errors?: ErrorWrapper[];
}
/**
* @class
* Initializes a new instance of the ValidationResult class.
* @constructor
* Describes the validation result of the live request, response validation.
*
* @member {object} [requestValidationResult] Describes the validation result
* of the live request.
*
* @member {boolean} [requestValidationResult.successfulRequest] Describes the
* status of live request validation.
*
* @member {array} [requestValidationResult.operationInfo] The corresponding
* operation(s) in openapi spec that was used for validating the request.
*
* @member {array} [requestValidationResult.errors] Provides more information
* about live response validation.
*
* @member {object} [responseValidationResult] Describes the validation result
* of the live response.
*
* @member {boolean} [responseValidationResult.successfulResponse] Describes
* the status of live response validation.
*
* @member {array} [responseValidationResult.operationInfo] The corresponding
* operation(s) in openapi spec that was used for validating the response.
*
* @member {array} [responseValidationResult.errors] Provides more information
* about live response validation.
*
* @member {array} [errors] Provides more information about validation for
* scenarios where no potential operation was found or multiple operations were
* found or the input was invalid.
*
*/
export interface ValidationResult {
readonly requestValidationResult?: RequestValidationResult;
readonly responseValidationResult?: ResponseValidationResult;
readonly errors?: ErrorWrapper[];
}
/**
* @class
* Initializes a new instance of the PotentialOperationsResult class.
*
* @constructor
* Provides information about the issue that occured while performing
* live request and response validation.
*
* @member {Array<Operation>} List of potential operations found.
*
* @member {LiveValidationError} Reason when potential operations were empty.
*
*/
export interface PotentialOperationsResult {
operations: Array<any>;
reason: LiveValidationError;
}
import liveRequest = require('./liveRequest');
import liveResponse = require('./liveResponse');
import requestResponse = require('./requestResponse');
import operationInfo = require('./operationInfo');
import liveValidationError = require('./liveValidationError');
import errorResponse = require('./errorResponse');
import errorWrapper = require('./errorWrapper');
import requestValidationResult = require('./requestValidationResult');
import responseValidationResult = require('./responseValidationResult');
import validationResult = require('./validationResult');
import potentialOperationsResult = require('./potentialOperationsResult');
export declare const LiveRequest: typeof liveRequest;
export declare const LiveResponse: typeof liveResponse;
export declare const RequestResponse: typeof requestResponse;
export declare const OperationInfo: typeof operationInfo;
export declare const LiveValidationError: typeof liveValidationError;
export declare const ErrorResponse: typeof errorResponse;
export declare const ErrorWrapper: typeof errorWrapper;
export declare const RequestValidationResult: typeof requestValidationResult;
export declare const ResponseValidationResult: typeof responseValidationResult;
export declare const ValidationResult: typeof validationResult;
export declare const PotentialOperationsResult: typeof potentialOperationsResult;

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

@ -21,9 +21,9 @@ class PotentialOperationsResult {
operations: any[]
reason: any
constructor(operations: any[], reason: any) {
this.operations = operations || [];
this.operations = operations || []
if (reason) {
this.reason = reason;
this.reason = reason
}
}
}

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

@ -84,7 +84,7 @@ class ResponseValidationResult {
}
}
}
};
}
}
}

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

@ -24,7 +24,7 @@ class ResponseWrapper {
public statusCode: number|string,
public body: any,
public headers: any,
public encoding: string) {
public encoding?: string) {
}
}
export = ResponseWrapper

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

@ -97,7 +97,7 @@ class ValidationResult {
}
}
}
};
}
}
}

3
lib/sway.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,3 @@
declare module "sway" {
function create(options: any): any
}

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

@ -1,9 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
const url = require('url'),
uuid = require('uuid');
import utils = require('../util/utils');
import url = require('url')
import uuid = require('uuid')
import utils = require('../util/utils')
class HttpTemplate {
@ -11,57 +11,58 @@ class HttpTemplate {
}
getHost() {
let result = 'management.azure.com';
let result: string|undefined = 'management.azure.com'
if (this.request.url) {
result = url.parse(this.request.url).host;
result = url.parse(this.request.url).host
}
return result;
return result
}
getCurlRequestHeaders(padding?: any) {
let result = ``;
if (!padding) padding = ``;
let result = ``
if (!padding) padding = ``
if (this.request.body) {
result += `\n${padding}-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 = utils.getKeys(this.request.headers);
let headers = utils.getKeys(this.request.headers)
for (let i = 0; i < headers.length; i++) {
let headerName = headers[i];
result += `\n${padding}-H '${headerName}: ${this.request.headers[headerName]}' \\`;
let headerName = headers[i]
result += `\n${padding}-H '${headerName}: ${this.request.headers[headerName]}' \\`
}
}
return result;
return result
}
getRequestBody() {
let body = ``;
let body = ``
if (this.request && this.request.body !== null && this.request.body !== undefined) {
body = JSON.stringify(this.request.body);
body = JSON.stringify(this.request.body)
}
return body;
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(padding?: any) {
let body = ``;
if (!padding) padding = ``;
let body = ``
if (!padding) padding = ``
if (this.request && this.request.body !== null && this.request.body !== undefined) {
body = `\n${padding}-d @- << EOF\n${padding}${JSON.stringify(this.request.body, null, 2).split(`\n`).join(`\n${padding}`)}\n${padding}EOF`;
body =
`\n${padding}-d @- << EOF\n${padding}${JSON.stringify(this.request.body, null, 2).split(`\n`).join(`\n${padding}`)}\n${padding}EOF`
}
return body;
return body
}
getResponseBody(response: any) {
let body = ``;
let body = ``
if (response && response.body !== null && response.body !== undefined) {
body = JSON.stringify(response.body);
body = JSON.stringify(response.body)
}
return body;
return body
}
}
export = HttpTemplate;
export = HttpTemplate

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

@ -1,57 +1,57 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
const url = require('url')
import url = require('url')
import HttpTemplate = require('./httpTemplate')
const uuid = require('uuid')
import uuid = require('uuid')
import utils = require('../util/utils')
class MarkdownHttpTemplate extends HttpTemplate {
constructor(request: any, responses: any) {
super(request, responses);
super(request, responses)
}
getRequestHeaders() {
let result = ``;
let result = ``
if (this.request.body) {
result += `Content-Length: ${JSON.stringify(this.request.body).length}\n`;
result += `Content-Length: ${JSON.stringify(this.request.body).length}\n`
}
if (this.request.headers) {
let headers = utils.getKeys(this.request.headers);
let headers = utils.getKeys(this.request.headers)
for (let i = 0; i < headers.length; i++) {
let headerName = headers[i];
result += `${headerName}: ${this.request.headers[headerName]}`;
let headerName = headers[i]
result += `${headerName}: ${this.request.headers[headerName]}`
if (i !== headers.length - 1) {
result += `\n`;
result += `\n`
}
}
}
return result;
return result
}
getResponseHeaders(response: any) {
let result = ``;
let result = ``
if (response.body) {
result += `Content-Length: ${JSON.stringify(response.body).length}\n`;
result += `Content-Length: ${JSON.stringify(response.body).length}\n`
}
let gotContentType = false;
let gotContentType = false
if (response.headers) {
let headers = utils.getKeys(response.headers);
let headers = utils.getKeys(response.headers)
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]}`;
let headerName = headers[i]
if (headerName.match(/^Content-Type$/ig) !== null) gotContentType = true
result += `${headerName}: ${response.headers[headerName]}`
if (i !== headers.length - 1) {
result += `\n`;
result += `\n`
}
}
}
if (!gotContentType) {
result += `Content-Type: application/json; charset=utf-8`;
result += `Content-Type: application/json; charset=utf-8`
}
return result;
return result
}
populateRequest() {
@ -68,13 +68,13 @@ Connection: close
${this.getRequestBody()}
\`\`\`\
`;
return requestTemplate;
`
return requestTemplate
}
populateResponse(response: any, responseType: any) {
if (!responseType) responseType = 'Response';
let responseGuid = uuid.v4();
if (!responseType) responseType = 'Response'
let responseGuid = uuid.v4()
let responseTemplate = `
## ${responseType}
@ -96,8 +96,8 @@ Connection: close
${this.getResponseBody(response)}
\`\`\`
`;
return responseTemplate;
`
return responseTemplate
}
populateCurl() {
@ -107,28 +107,30 @@ ${this.getResponseBody(response)}
\`\`\`bash
curl -X ${this.request.method} '${this.request.url}' \\\n-H 'authorization: bearer <token>' \\${this.getCurlRequestHeaders()}${this.getCurlRequestBody()}
\`\`\`
`;
return template;
`
return template
}
populate() {
let template = ``;
template += this.populateRequest();
template += this.populateCurl();
let template = ``
template += this.populateRequest()
template += this.populateCurl()
if (this.responses) {
if (this.responses.longrunning) {
if (this.responses.longrunning.initialResponse) {
template += this.populateResponse(this.responses.longrunning.initialResponse, 'Initial Response');
template += this.populateResponse(this.responses.longrunning.initialResponse, 'Initial Response')
}
if (this.responses.longrunning.finalResponse) {
template += this.populateResponse(this.responses.longrunning.finalResponse, 'Final Response after polling is complete and successful');
template += this.populateResponse(
this.responses.longrunning.finalResponse,
'Final Response after polling is complete and successful')
}
} else {
template += this.populateResponse(this.responses.standard.finalResponse, 'Response');
template += this.populateResponse(this.responses.standard.finalResponse, 'Response')
}
}
return template;
return template
}
}
module.exports = MarkdownHttpTemplate;
export = MarkdownHttpTemplate

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

@ -1,58 +1,57 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
'use strict';
import url = require('url')
import utils = require('../util/utils')
import HttpTemplate = require('./httpTemplate')
import uuid = require('uuid');
import uuid = require('uuid')
class YamlHttpTemplate extends HttpTemplate {
constructor(request: any, responses: any) {
super(request, responses);
super(request, responses)
}
getRequestHeaders() {
let result = ``;
let result = ``
if (this.request.body) {
result += ` Content-Length: ${JSON.stringify(this.request.body).length}\n`;
result += ` Content-Length: ${JSON.stringify(this.request.body).length}\n`
}
if (this.request.headers) {
let headers = utils.getKeys(this.request.headers);
let headers = utils.getKeys(this.request.headers)
for (let i = 0; i < headers.length; i++) {
let headerName = headers[i];
result += ` ${headerName}: ${this.request.headers[headerName]}`;
let headerName = headers[i]
result += ` ${headerName}: ${this.request.headers[headerName]}`
if (i !== headers.length - 1) {
result += `\n`;
result += `\n`
}
}
}
return result;
return result
}
getResponseHeaders(response: any) {
let result = ``;
let result = ``
if (response.body) {
result += ` Content-Length: ${JSON.stringify(response.body).length}\n`;
result += ` Content-Length: ${JSON.stringify(response.body).length}\n`
}
let gotContentType = false;
let gotContentType = false
if (response.headers) {
let headers = utils.getKeys(response.headers);
let headers = utils.getKeys(response.headers)
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]}`;
let headerName = headers[i]
if (headerName.match(/^Content-Type$/ig) !== null) gotContentType = true
result += ` ${headerName}: ${response.headers[headerName]}`
if (i !== headers.length - 1) {
result += `\n`;
result += `\n`
}
}
}
if (!gotContentType) {
result += ` Content-Type: application/json; charset=utf-8`;
result += ` Content-Type: application/json; charset=utf-8`
}
return result;
return result
}
populateRequest() {
@ -66,13 +65,13 @@ ${this.getRequestHeaders()}
Connection: close
${this.getRequestBody()}
`;
return requestTemplate;
`
return requestTemplate
}
populateResponse(response: any, responseType: any) {
if (!responseType) responseType = 'Response';
let responseGuid = uuid.v4();
if (!responseType) responseType = 'Response'
let responseGuid = uuid.v4()
let responseTemplate = `
#${responseType}
response:
@ -92,38 +91,40 @@ ${this.getResponseHeaders(response)}
Connection: close
${this.getResponseBody(response)}
`;
return responseTemplate;
`
return responseTemplate
}
populateCurl() {
let padding = ` `;
let padding = ` `
let template =
`\n#Curl
curl: |
curl -X ${this.request.method} '${this.request.url}' \\\n -H 'authorization: bearer <token>' \\${this.getCurlRequestHeaders(padding)}${this.getCurlRequestBody(padding)}
`;
return template;
`
return template
}
populate() {
let template = ``;
template += this.populateRequest();
template += this.populateCurl();
let template = ``
template += this.populateRequest()
template += this.populateCurl()
if (this.responses) {
if (this.responses.longrunning) {
if (this.responses.longrunning.initialResponse) {
template += this.populateResponse(this.responses.longrunning.initialResponse, 'Initial Response');
template += this.populateResponse(this.responses.longrunning.initialResponse, 'Initial Response')
}
if (this.responses.longrunning.finalResponse) {
template += this.populateResponse(this.responses.longrunning.finalResponse, 'Final Response after polling is complete and successful');
template += this.populateResponse(
this.responses.longrunning.finalResponse,
'Final Response after polling is complete and successful')
}
} else {
template += this.populateResponse(this.responses.standard.finalResponse, 'Response');
template += this.populateResponse(this.responses.standard.finalResponse, 'Response')
}
}
return template;
return template
}
}
module.exports = YamlHttpTemplate;
export = YamlHttpTemplate

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

@ -1,13 +1,14 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
var util = require('util'),
JsonRefs = require('json-refs'),
yuml2svg = require('yuml2svg'),
utils = require('./util/utils'),
Constants = require('./util/constants'),
log = require('./util/logging'),
ErrorCodes = Constants.ErrorCodes;
import util = require('util')
import JsonRefs = require('json-refs')
import yuml2svg = require('yuml2svg')
import utils = require('./util/utils')
import Constants = require('./util/constants')
import log = require('./util/logging')
let ErrorCodes = Constants.ErrorCodes;
/**
* @class
@ -33,118 +34,117 @@ class UmlGenerator {
*/
constructor(specInJson: any, options: any) {
if (specInJson === null || specInJson === undefined || typeof specInJson !== 'object') {
throw new Error('specInJson is a required property of type object');
throw new Error('specInJson is a required property of type object')
}
this.specInJson = specInJson;
this.graphDefinition = '';
if (!options) options = {};
this.options = options;
this.bg = '{bg:cornsilk}';
this.specInJson = specInJson
this.graphDefinition = ''
if (!options) options = {}
this.options = options
this.bg = '{bg:cornsilk}'
}
generateGraphDefinition() {
this.generateModelPropertiesGraph();
this.generateModelPropertiesGraph()
if (!this.options.shouldDisableAllof) {
this.generateAllOfGraph();
this.generateAllOfGraph()
}
}
generateAllOfGraph() {
let spec = this.specInJson;
let definitions = spec.definitions;
let spec = this.specInJson
let definitions = spec.definitions
for (let modelName of utils.getKeys(definitions)) {
let model = definitions[modelName];
this.generateAllOfForModel(modelName, model);
let model = definitions[modelName]
this.generateAllOfForModel(modelName, model)
}
}
generateAllOfForModel(modelName: any, model: any) {
if (model.allOf) {
model.allOf.map((item: any) => {
let referencedModel = item;
let ref = item['$ref'];
let segments = ref.split('/');
let parent = segments[segments.length - 1];
this.graphDefinition += `\n[${parent}${this.bg}]^-.-allOf[${modelName}${this.bg}]`;
});
let referencedModel = item
let ref = item['$ref']
let segments = ref.split('/')
let parent = segments[segments.length - 1]
this.graphDefinition += `\n[${parent}${this.bg}]^-.-allOf[${modelName}${this.bg}]`
})
}
}
generateModelPropertiesGraph() {
let spec = this.specInJson;
let definitions = spec.definitions;
let references: any[] = [];
let spec = this.specInJson
let definitions = spec.definitions
let references: any[] = []
for (let modelName of utils.getKeys(definitions)) {
let model = definitions[modelName];
let modelProperties = model.properties;
let props = '';
let model = definitions[modelName]
let modelProperties = model.properties
let props = ''
if (modelProperties) {
for (let propertyName of utils.getKeys(modelProperties)) {
let property = modelProperties[propertyName];
let propertyType = this.getPropertyType(modelName, property, references);
let discriminator = '';
let property = modelProperties[propertyName]
let propertyType = this.getPropertyType(modelName, property, references)
let discriminator = ''
if (model.discriminator && model.discriminator === propertyName) {
discriminator = '(discriminator)';
discriminator = '(discriminator)'
}
props += `-${propertyName}${discriminator}:${propertyType};`;
props += `-${propertyName}${discriminator}:${propertyType};`
}
}
if (!this.options.shouldDisableProperties) {
this.graphDefinition += props.length ? `[${modelName}|${props}${this.bg}]\n` : `[${modelName}${this.bg}]\n`;
this.graphDefinition += props.length ? `[${modelName}|${props}${this.bg}]\n` : `[${modelName}${this.bg}]\n`
}
}
if (references.length && !this.options.shouldDisableRefs) {
this.graphDefinition += references.join('\n');
this.graphDefinition += references.join('\n')
}
}
getPropertyType(modelName: any, property: any, references: any) {
if (property.type && property.type.match(/^(string|number|boolean)$/i) !== null) {
return property.type;
return property.type
}
if (property.type === 'array') {
let result = 'Array<';
let result = 'Array<'
if (property.items) {
result += this.getPropertyType(modelName, property.items, references);
result += this.getPropertyType(modelName, property.items, references)
}
result += '>';
return result;
result += '>'
return result
}
if (property['$ref']) {
let segments = property['$ref'].split('/');
let referencedModel = segments[segments.length - 1];
references.push(`[${modelName}${this.bg}]->[${referencedModel}${this.bg}]`);
return referencedModel;
let segments = property['$ref'].split('/')
let referencedModel = segments[segments.length - 1]
references.push(`[${modelName}${this.bg}]->[${referencedModel}${this.bg}]`)
return referencedModel
}
if (property.additionalProperties && typeof property.additionalProperties === 'object') {
let result = 'Dictionary<';
result += this.getPropertyType(modelName, property.additionalProperties, references);
result += '>';
return result;
let result = 'Dictionary<'
result += this.getPropertyType(modelName, property.additionalProperties, references)
result += '>'
return result
}
if (property.type === 'object') {
return 'Object';
return 'Object'
}
return '';
return ''
}
generateDiagramFromGraph() {
this.generateGraphDefinition();
let svg = '';
this.generateGraphDefinition()
let svg = ''
try {
log.info(this.graphDefinition);
svg = yuml2svg(this.graphDefinition, false, { dir: this.options.direction, type: 'class' });
//console.log(svg);
log.info(this.graphDefinition)
svg = yuml2svg(this.graphDefinition, false, { dir: this.options.direction, type: 'class' })
//console.log(svg)
} catch (err) {
return Promise.reject(err);
return Promise.reject(err)
}
return Promise.resolve(svg);
return Promise.resolve(svg)
}
}
module.exports = UmlGenerator;
export = UmlGenerator

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

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
var Constants = {
let Constants = {
constraints: ['minLength', 'maxLength', 'minimum', 'maximum', 'enum', 'maxItems', 'minItems', 'uniqueItems', 'multipleOf', 'pattern'],
xmsExamples: 'x-ms-examples',
exampleInSpec: 'example-in-spec',
@ -55,6 +55,6 @@ var Constants = {
knownTitleToResourceProviders: {
'ResourceManagementClient': 'Microsoft.Resources'
}
};
}
export = Constants;
export = Constants

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

@ -1,13 +1,14 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
var winston = require('winston'),
path = require('path'),
fs = require('fs'),
os = require('os'),
logDir = path.resolve(os.homedir(), 'oav_output');
import winston = require('winston')
import path = require('path')
import fs = require('fs')
import os = require('os')
var currentLogFile: any;
let logDir = path.resolve(os.homedir(), 'oav_output')
let currentLogFile: any
/*
* Provides current time in custom format that will be used in naming log files. Example:'20140820_151113'
@ -17,23 +18,23 @@ function getTimeStamp() {
// We pad each value so that sorted directory listings show the files in chronological order
function pad(number: any) {
if (number < 10) {
return '0' + number;
return '0' + number
}
return number;
return number
}
var now = new Date();
const now = new Date()
return pad(now.getFullYear()) +
pad(now.getMonth() + 1) +
pad(now.getDate()) +
"_" +
pad(now.getHours()) +
pad(now.getMinutes()) +
pad(now.getSeconds());
pad(now.getSeconds())
}
var customLogLevels = {
let customLogLevels = {
off: 0,
json: 1,
error: 2,
@ -42,9 +43,15 @@ var customLogLevels = {
verbose: 5,
debug: 6,
silly: 7
};
}
var logger = new (winston.Logger)({
type ILogger = winston.LoggerInstance & {
consoleLogLevel: any
filepath: any
directory: any
}
let logger = new (winston.Logger)({
transports: [
new (winston.transports.Console)({
level: 'warn',
@ -54,7 +61,7 @@ var logger = new (winston.Logger)({
})
],
levels: customLogLevels
});
})
Object.defineProperties(logger, {
'consoleLogLevel': {
@ -62,49 +69,50 @@ Object.defineProperties(logger, {
get: function () { return this.transports.console.level; },
set: function (level) {
if (!level) {
level = 'warn';
level = 'warn'
}
let validLevels = Object.keys(customLogLevels);
let validLevels = Object.keys(customLogLevels)
if (!validLevels.some(function (item) { return item === level; })) {
throw new Error(`The logging level provided is "${level}". Valid values are: "${validLevels}".`);
throw new Error(`The logging level provided is "${level}". Valid values are: "${validLevels}".`)
}
this.transports.console.level = level;
return;
this.transports.console.level = level
return
}
},
'directory': {
enumerable: true,
get: function () {
return logDir;
return logDir
},
set: function (logDirectory) {
if (!logDirectory || logDirectory && typeof logDirectory.valueOf() !== 'string') {
throw new Error('logDirectory cannot be null or undefined and must be of type "string".');
throw new Error('logDirectory cannot be null or undefined and must be of type "string".')
}
if (!fs.existsSync(logDirectory)) {
fs.mkdirSync(logDirectory);
fs.mkdirSync(logDirectory)
}
logDir = logDirectory;
return;
logDir = logDirectory
return
}
},
'filepath': {
enumerable: true,
get: function () {
if (!currentLogFile) {
let filename = `validate_log_${getTimeStamp()}.log`;
currentLogFile = path.join(this.directory, filename);
let filename = `validate_log_${getTimeStamp()}.log`
currentLogFile = path.join(this.directory, filename)
}
return currentLogFile;
return currentLogFile
},
set: function (logFilePath) {
if (!logFilePath || logFilePath && typeof logFilePath.valueOf() !== 'string') {
throw new Error('filepath cannot be null or undefined and must be of type string. It must be an absolute file path.');
throw new Error(
'filepath cannot be null or undefined and must be of type string. It must be an absolute file path.')
}
currentLogFile = logFilePath;
this.directory = path.dirname(logFilePath);
currentLogFile = logFilePath
this.directory = path.dirname(logFilePath)
if (!this.transports.file) {
this.add(winston.transports.File, {
level: 'silly',
@ -113,11 +121,11 @@ Object.defineProperties(logger, {
prettyPrint: true,
json: false,
filename: logFilePath
});
})
}
return;
return
}
}
});
export = logger;
export = (logger as any) as ILogger

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

@ -1,28 +1,29 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
var fs = require('fs'),
execSync = require('child_process').execSync,
util = require('util'),
path = require('path'),
jsonPointer = require('json-pointer'),
YAML = require('js-yaml'),
log = require('./logging'),
request = require('request'),
lodash = require('lodash'),
http = require('http');
import fs = require('fs')
import { execSync } from 'child_process'
import util = require('util')
import path = require('path')
import jsonPointer from 'json-pointer'
import YAML = require('js-yaml')
import log = require('./logging')
import request = require('request')
import lodash from 'lodash'
import http = require('http')
/*
* Caches the json docs that were successfully parsed by parseJson(). This avoids, fetching them again.
* key: docPath
* value: parsed doc in JSON format
*/
export let docCache: any = {};
export let docCache: any = {}
export function clearCache() {
docCache = {};
return;
};
docCache = {}
return
}
/*
* Removes byte order marker. This catches EF BB BF (the UTF-8 BOM)
* because the buffer-to-string conversion in `fs.readFile()`
@ -30,13 +31,13 @@ export function clearCache() {
*/
export function stripBOM(content: any) {
if (Buffer.isBuffer(content)) {
content = content.toString();
content = content.toString()
}
if (content.charCodeAt(0) === 0xFEFF || content.charCodeAt(0) === 0xFFFE) {
content = content.slice(1);
content = content.slice(1)
}
return content;
};
return content
}
/*
* Provides a parsed JSON from the given file path or a url.
@ -48,36 +49,39 @@ export function stripBOM(content: any) {
*/
export function parseJson(specPath: string) {
if (!specPath || (specPath && typeof specPath.valueOf() !== 'string')) {
let err = new Error('A (github) url or a local file path to the swagger spec is required and must be of type string.');
return Promise.reject(err);
let err = new Error(
'A (github) url or a local file path to the swagger spec is required and must be of type string.')
return Promise.reject(err)
}
if (docCache[specPath]) {
return Promise.resolve(docCache[specPath]);
return Promise.resolve(docCache[specPath])
}
//url
if (specPath.match(/^http.*/ig) !== null) {
//If the spec path is a url starting with https://github then let us auto convert it to an https://raw.githubusercontent url.
if (specPath.startsWith('https://github')) {
specPath = specPath.replace(/^https:\/\/(github.com)(.*)blob\/(.*)/ig, 'https://raw.githubusercontent.com$2$3');
specPath = specPath.replace(
/^https:\/\/(github.com)(.*)blob\/(.*)/ig, 'https://raw.githubusercontent.com$2$3')
}
let res = makeRequest({ url: specPath, errorOnNon200Response: true });
docCache[specPath] = res;
return res;
let res = makeRequest({ url: specPath, errorOnNon200Response: true })
docCache[specPath] = res
return res
} else {
//local filepath
try {
let fileContent = stripBOM(fs.readFileSync(specPath, 'utf8'));
let result = parseContent(specPath, fileContent);
docCache[specPath] = result;
return Promise.resolve(result);
let fileContent = stripBOM(fs.readFileSync(specPath, 'utf8'))
let result = parseContent(specPath, fileContent)
docCache[specPath] = result
return Promise.resolve(result)
} catch (err) {
let msg = `Unable to read the content or execute "JSON.parse()" on the content of file "${specPath}". The error is:\n${err}`;
let e = new Error(msg);
log.error(e);
return Promise.reject(e);
let msg =
`Unable to read the content or execute "JSON.parse()" on the content of file "${specPath}". The error is:\n${err}`
let e: any = new Error(msg)
log.error(e)
return Promise.reject(e)
}
}
};
}
/*
* Provides a parsed JSON from the given content.
@ -89,18 +93,19 @@ export function parseJson(specPath: string) {
* @returns {object} jsonDoc - Parsed document in JSON format.
*/
export function parseContent(filePath: string, fileContent: string) {
let result = null;
let result = null
if (/.*\.json$/ig.test(filePath)) {
result = JSON.parse(fileContent);
result = JSON.parse(fileContent)
} else if (/.*\.ya?ml$/ig.test(filePath)) {
result = YAML.safeLoad(fileContent);
result = YAML.safeLoad(fileContent)
} else {
let msg = `We currently support "*.json" and "*.yaml | *.yml" file formats for validating swaggers.\n` +
`The current file extension in "${filePath}" is not supported.`;
throw new Error(msg);
let msg =
`We currently support "*.json" and "*.yaml | *.yml" file formats for validating swaggers.\n` +
`The current file extension in "${filePath}" is not supported.`
throw new Error(msg)
}
return result;
};
return result
}
/*
* A utility function to help us acheive stuff in the same way as async/await but with yield statement and generator functions.
@ -109,16 +114,16 @@ export function parseContent(filePath: string, fileContent: string) {
*/
export function run(genfun: any) {
// instantiate the generator object
var gen = genfun();
let gen = genfun()
// This is the async loop pattern
function next(err?: any, answer?: any) {
var res;
let res
if (err) {
// if err, throw it into the wormhole
return gen.throw(err);
return gen.throw(err)
} else {
// if good value, send it
res = gen.next(answer);
res = gen.next(answer)
}
if (!res.done) {
// if we are not at the end
@ -128,12 +133,12 @@ export function run(genfun: any) {
// and passing it a callback
// that receives err, answer
// for which we'll just use `next()`
res.value(next);
res.value(next)
}
}
// Kick off the async loop
next();
};
next()
}
/*
* Makes a generic request. It is a wrapper on top of request.js library that provides a promise instead of a callback.
@ -148,28 +153,29 @@ export function makeRequest(options: any) {
var promise = new Promise(function (resolve, reject) {
request(options, function (err: any, response: any, responseBody: any) {
if (err) {
reject(err);
reject(err)
}
if (options.errorOnNon200Response && response.statusCode !== 200) {
var msg = `StatusCode: "${response.statusCode}", ResponseBody: "${responseBody}."`;
reject(new Error(msg));
var msg = `StatusCode: "${response.statusCode}", ResponseBody: "${responseBody}."`
reject(new Error(msg))
}
let res = responseBody;
let res = responseBody
try {
if (typeof responseBody.valueOf() === 'string') {
res = parseContent(options.url, responseBody);
res = parseContent(options.url, responseBody)
}
} catch (error) {
let msg = `An error occurred while parsing the file ${options.url}. The error is:\n ${util.inspect(error, { depth: null })}.`;
let e = new Error(msg);
reject(e);
let msg =
`An error occurred while parsing the file ${options.url}. The error is:\n ${util.inspect(error, { depth: null })}.`
let e = new Error(msg)
reject(e)
}
resolve(res);
});
});
return promise;
};
resolve(res)
})
})
return promise
}
/*
* Executes an array of promises sequentially. Inspiration of this method is here:
@ -180,11 +186,11 @@ export function makeRequest(options: any) {
* @return A chain of resolved or rejected promises
*/
export function executePromisesSequentially(promiseFactories: any[]) {
let result = Promise.resolve();
let result = Promise.resolve()
promiseFactories.forEach(function (promiseFactory) {
result = result.then(promiseFactory);
});
return result;
result = result.then(promiseFactory)
})
return result
};
/*
@ -198,17 +204,17 @@ export function executePromisesSequentially(promiseFactories: any[]) {
* @return {string} result A random string
*/
export function generateRandomId(prefix: string, existingIds: any) {
let randomStr;
let randomStr
while (true) {
randomStr = Math.random().toString(36).substr(2, 12);
randomStr = Math.random().toString(36).substr(2, 12)
if (prefix && typeof prefix.valueOf() === 'string') {
randomStr = prefix + randomStr;
randomStr = prefix + randomStr
}
if (!existingIds || !(randomStr in existingIds)) {
break;
break
}
}
return randomStr;
return randomStr
};
/*
@ -232,31 +238,31 @@ export function generateRandomId(prefix: string, existingIds: any) {
*/
export function parseReferenceInSwagger(reference: string) {
if (!reference || (reference && reference.trim().length === 0)) {
throw new Error('reference cannot be null or undefined and it must be a non-empty string.');
throw new Error('reference cannot be null or undefined and it must be a non-empty string.')
}
let result: any = {};
let result: any = {}
if (reference.includes('#')) {
//local reference in the doc
if (reference.startsWith('#/')) {
result.localReference = {};
result.localReference.value = reference;
result.localReference.accessorProperty = reference.slice(2).replace('/', '.');
result.localReference = {}
result.localReference.value = reference
result.localReference.accessorProperty = reference.slice(2).replace('/', '.')
} else {
//filePath+localReference
let segments = reference.split('#');
result.filePath = segments[0];
result.localReference = {};
result.localReference.value = '#' + segments[1];
result.localReference.accessorProperty = segments[1].slice(1).replace('/', '.');
let segments = reference.split('#')
result.filePath = segments[0]
result.localReference = {}
result.localReference.value = '#' + segments[1]
result.localReference.accessorProperty = segments[1].slice(1).replace('/', '.')
}
} else {
//we are assuming that the string is a relative filePath
result.filePath = reference;
result.filePath = reference
}
return result;
};
return result
}
/*
* Same as path.join(), however, it converts backward slashes to forward slashes.
@ -272,11 +278,11 @@ export function parseReferenceInSwagger(reference: string) {
* @return {string} resolved path
*/
export function joinPath(...args: string[]) {
let finalPath = path.join(...args);
finalPath = finalPath.replace(/\\/gi, '/');
finalPath = finalPath.replace(/^(http|https):\/(.*)/gi, '$1://$2');
return finalPath;
};
let finalPath = path.join(...args)
finalPath = finalPath.replace(/\\/gi, '/')
finalPath = finalPath.replace(/^(http|https):\/(.*)/gi, '$1://$2')
return finalPath
}
/*
* Provides a parsed JSON from the given file path or a url. Same as parseJson(). However,
@ -288,9 +294,9 @@ export function joinPath(...args: string[]) {
* @returns {object} jsonDoc - Parsed document in JSON format.
*/
export function parseJsonWithPathFragments(...args: string[]) {
let specPath = joinPath(...args);
return parseJson(specPath);
};
let specPath = joinPath(...args)
return parseJson(specPath)
}
/*
* Merges source object into the target object
@ -304,18 +310,18 @@ export function mergeObjects(source: any, target: any) {
Object.keys(source).forEach(function (key) {
if (Array.isArray(source[key])) {
if (target[key] && !Array.isArray(target[key])) {
throw new Error(`Cannot merge ${key} from source object into target object because the same property in target object is not (of the same type) an Array.`);
throw new Error(`Cannot merge ${key} from source object into target object because the same property in target object is not (of the same type) an Array.`)
}
if (!target[key]) {
target[key] = [];
target[key] = []
}
target[key] = mergeArrays(source[key], target[key]);
target[key] = mergeArrays(source[key], target[key])
} else {
target[key] = lodash.cloneDeep(source[key]);
target[key] = lodash.cloneDeep(source[key])
}
});
return target;
};
return target
}
/*
* Merges source array into the target array
@ -327,12 +333,12 @@ export function mergeObjects(source: any, target: any) {
*/
export function mergeArrays(source: any[], target: any[]) {
if (!Array.isArray(target) || (!Array.isArray(source))) {
return target;
return target
}
source.forEach((item) => {
target.push(lodash.cloneDeep(item));
});
return target;
target.push(lodash.cloneDeep(item))
})
return target
};
/*
@ -345,15 +351,15 @@ export function mergeArrays(source: any[], target: any[]) {
* @returns {any} result - Returns the value that the ptr points to, in the doc.
*/
export function getObject(doc: any, ptr: string) {
let result;
let result
try {
result = jsonPointer.get(doc, ptr);
result = jsonPointer.get(doc, ptr)
} catch (err) {
log.error(err);
throw err;
log.error(err)
throw err
}
return result;
};
return result
}
/*
* Sets the given value at the location provided by the ptr in the given doc.
@ -365,14 +371,14 @@ export function getObject(doc: any, ptr: string) {
* location provided by the ptr in the doc.
*/
export function setObject(doc: any, ptr: string, value: any) {
let result;
let result
try {
result = jsonPointer.set(doc, ptr, value);
result = jsonPointer.set(doc, ptr, value)
} catch (err) {
log.error(err);
log.error(err)
}
return result;
};
return result
}
/*
* Removes the location pointed by the json pointer in the given doc.
@ -381,14 +387,14 @@ export function setObject(doc: any, ptr: string, value: any) {
* @param {string} ptr The json reference pointer.
*/
export function removeObject(doc: any, ptr: string) {
let result;
let result
try {
result = jsonPointer.remove(doc, ptr);
result = jsonPointer.remove(doc, ptr)
} catch (err) {
log.error(err);
log.error(err)
}
return result;
};
return result
}
/**
/*
@ -400,22 +406,22 @@ export function removeObject(doc: any, ptr: string) {
*
* @returns {string} result - provider namespace from the given path.
*/
export function getProvider(path: string) {
export function getProvider(path?: string|null) {
if (path === null || path === undefined || typeof path.valueOf() !== 'string' || !path.trim().length) {
throw new Error('path is a required parameter of type string and it cannot be an empty string.');
throw new Error('path is a required parameter of type string and it cannot be an empty string.')
}
let providerRegEx = new RegExp('/providers/(\:?[^{/]+)', 'gi');
let result;
let pathMatch;
let providerRegEx = new RegExp('/providers/(\:?[^{/]+)', 'gi')
let result
let pathMatch
// Loop over the paths to find the last matched provider namespace
while ((pathMatch = providerRegEx.exec(path)) !== null) {
result = pathMatch[1];
result = pathMatch[1]
}
return result;
};
return result
}
/**
/*
@ -430,45 +436,52 @@ export function getProvider(path: string) {
*/
export function gitClone(directory: string, url: string, branch: string) {
if (url === null || url === undefined || typeof url.valueOf() !== 'string' || !url.trim().length) {
throw new Error('url is a required parameter of type string and it cannot be an empty string.');
throw new Error('url is a required parameter of type string and it cannot be an empty string.')
}
if (directory === null || directory === undefined || typeof directory.valueOf() !== 'string' || !directory.trim().length) {
throw new Error('directory is a required parameter of type string and it cannot be an empty string.');
if (directory === null
|| directory === undefined
|| typeof directory.valueOf() !== 'string'
|| !directory.trim().length) {
throw new Error('directory is a required parameter of type string and it cannot be an empty string.')
}
// If the directory exists then we assume that the repo to be cloned is already present.
if (fs.existsSync(directory)) {
if (fs.lstatSync(directory).isDirectory()) {
try {
removeDirSync(directory);
removeDirSync(directory)
} catch (err) {
throw new Error(`An error occurred while deleting directory ${directory}: ${util.inspect(err, { depth: null })}.`);
throw new Error(
`An error occurred while deleting directory ${directory}: ${util.inspect(err, { depth: null })}.`)
}
} else {
try {
fs.unlinkSync(directory);
fs.unlinkSync(directory)
} catch (err) {
throw new Error(`An error occurred while deleting file ${directory}: ${util.inspect(err, { depth: null })}.`);
throw new Error(
`An error occurred while deleting file ${directory}: ${util.inspect(err, { depth: null })}.`)
}
}
}
try {
fs.mkdirSync(directory);
fs.mkdirSync(directory)
} catch (err) {
throw new Error(`An error occurred while creating directory ${directory}: ${util.inspect(err, { depth: null })}.`);
throw new Error(
`An error occurred while creating directory ${directory}: ${util.inspect(err, { depth: null })}.`)
}
try {
let isBranchDefined = branch !== null && branch !== undefined && typeof branch.valueOf() === 'string';
let cmd = isBranchDefined ? `git clone --depth=1 --branch ${branch} ${url} ${directory}` : `git clone --depth=1 ${url} ${directory}`;
let result = execSync(cmd, { encoding: 'utf8' });
let isBranchDefined = branch !== null && branch !== undefined && typeof branch.valueOf() === 'string'
let cmd = isBranchDefined
? `git clone --depth=1 --branch ${branch} ${url} ${directory}`
: `git clone --depth=1 ${url} ${directory}`
let result = execSync(cmd, { encoding: 'utf8' })
} catch (err) {
throw new Error(`An error occurred while cloning git repository: ${util.inspect(err, { depth: null })}.`);
throw new Error(`An error occurred while cloning git repository: ${util.inspect(err, { depth: null })}.`)
}
};
}
/*
* Removes given directory recursively.
@ -477,13 +490,13 @@ export function gitClone(directory: string, url: string, branch: string) {
export function removeDirSync(dir: string) {
if (fs.existsSync(dir)) {
fs.readdirSync(dir).forEach(function (file: any) {
var current = dir + '/' + file;
if (fs.statSync(current).isDirectory()) removeDirSync(current);
else fs.unlinkSync(current);
});
fs.rmdirSync(dir);
var current = dir + '/' + file
if (fs.statSync(current).isDirectory()) removeDirSync(current)
else fs.unlinkSync(current)
})
fs.rmdirSync(dir)
}
};
}
/*
* Finds the first content-type that contains "/json". Only supported Content-Types are
@ -493,44 +506,52 @@ export function removeDirSync(dir: string) {
* @returns {string} firstMatchedJson content-type that contains "/json".
*/
export function getJsonContentType(consumesOrProduces: any[]) {
let firstMatchedJson = null;
let firstMatchedJson = null
if (consumesOrProduces) {
firstMatchedJson = consumesOrProduces.find((contentType) => {
return (contentType.match(/.*\/json.*/ig) !== null);
});
return (contentType.match(/.*\/json.*/ig) !== null)
})
}
return firstMatchedJson;
};
return firstMatchedJson
}
/**
* Determines whether the given string is url encoded
* @param {string} str - The input string to be verified.
* @returns {boolean} result - true if str is url encoded; false otherwise.
*/
export function isUrlEncoded(str: string) {
str = str || '';
return str !== decodeURIComponent(str);
};
export function isUrlEncoded(str: string): boolean {
str = str || ''
return str !== decodeURIComponent(str)
}
/**
* Determines whether the given model is a pure (free-form) object candidate (i.e. equivalent of the C# Object type).
* @param {object} model - The model to be verified
* @returns {boolean} result - true if model is a pure object; false otherwise.
*/
export function isPureObject(model: any) {
export function isPureObject(model: any): boolean {
if (!model) {
throw new Error(`model cannot be null or undefined and must be of type "object"`);
throw new Error(`model cannot be null or undefined and must be of type "object"`)
}
if (model.type && typeof model.type.valueOf() === 'string' && model.type === 'object' && model.properties && getKeys(model.properties).length === 0) {
return true;
if (model.type
&& typeof model.type.valueOf() === 'string'
&& model.type === 'object'
&& model.properties
&& getKeys(model.properties).length === 0) {
return true
} else if (!model.type && model.properties && getKeys(model.properties).length === 0) {
return true;
} else if (model.type && typeof model.type.valueOf() === 'string' && model.type === 'object' && !model.properties && !model.additionalProperties) {
return true;
return true
} else if (model.type
&& typeof model.type.valueOf() === 'string'
&& model.type === 'object'
&& !model.properties
&& !model.additionalProperties) {
return true
} else {
return false;
return false
}
};
}
/**
* Relaxes/Transforms the given entities type from a specific JSON schema primitive type (http://json-schema.org/latest/json-schema-core.html#rfc.section.4.2)
@ -543,32 +564,35 @@ export function isPureObject(model: any) {
*/
export function relaxEntityType(entity: any, isRequired?: boolean) {
if (isPureObject(entity) && entity.type) {
delete entity.type;
delete entity.type
}
if (entity.additionalProperties && isPureObject(entity.additionalProperties) && entity.additionalProperties.type) {
delete entity.additionalProperties.type;
if (entity.additionalProperties
&& isPureObject(entity.additionalProperties)
&& entity.additionalProperties.type) {
delete entity.additionalProperties.type
}
return entity;
};
return entity
}
/**
* Relaxes/Transforms model definition like entities recursively
*/
export function relaxModelLikeEntities(model: any) {
model = relaxEntityType(model);
model = relaxEntityType(model)
if (model.properties) {
let modelProperties = model.properties;
let modelProperties = model.properties
for (let propName of getKeys(modelProperties)) {
if (modelProperties[propName].properties) {
modelProperties[propName] = relaxModelLikeEntities(modelProperties[propName]);
modelProperties[propName] = relaxModelLikeEntities(modelProperties[propName])
} else {
modelProperties[propName] = relaxEntityType(modelProperties[propName], isPropertyRequired(propName, model));
modelProperties[propName] = relaxEntityType(
modelProperties[propName], isPropertyRequired(propName, model))
}
}
}
return model;
};
return model
}
/**
* Relaxes the entity to be a oneOf: [the current type OR null type] if the condition is satisfied
@ -585,9 +609,9 @@ export function allowNullType(entity: any, isPropRequired?: boolean) {
if (entity.items) {
// if items object contains inline properties
if (entity.items.properties) {
entity.items = allowNullableTypes(entity.items);
entity.items = allowNullableTypes(entity.items)
} else {
entity.items = allowNullType(entity.items);
entity.items = allowNullType(entity.items)
}
}
}
@ -595,33 +619,33 @@ export function allowNullType(entity: any, isPropRequired?: boolean) {
// takes care of string 'false' and 'true'
if (typeof entity['x-nullable'] === 'string') {
if (entity['x-nullable'].toLowerCase() === 'false') {
entity['x-nullable'] = false;
entity['x-nullable'] = false
} else if (entity['x-nullable'].toLowerCase() === 'true') {
entity['x-nullable'] = true;
entity['x-nullable'] = true
}
}
if (shouldAcceptNullValue(entity['x-nullable'], isPropRequired)) {
let savedEntity = entity;
let savedEntity = entity
// handling nullable parameters
if (savedEntity.in) {
entity.oneOf = [{ "type": entity.type }, { "type": "null" }];
delete entity.type;
entity.oneOf = [{ "type": entity.type }, { "type": "null" }]
delete entity.type
} else {
entity = {};
entity.oneOf = [savedEntity, { "type": "null" }];
entity = {}
entity.oneOf = [savedEntity, { "type": "null" }]
}
}
}
// if there's a $ref
if (entity && entity["$ref"] && shouldAcceptNullValue(entity['x-nullable'], isPropRequired)) {
let savedEntity = entity;
entity = {};
entity.oneOf = [savedEntity, { "type": "null" }];
let savedEntity = entity
entity = {}
entity.oneOf = [savedEntity, { "type": "null" }]
}
return entity;
};
return entity
}
/** logic table to determine when to use oneOf to accept null values
* required \ x-nullable | True | False | Undefined
@ -630,9 +654,9 @@ export function allowNullType(entity: any, isPropRequired?: boolean) {
* No | convert to oneOf[] | | convert to oneOf[]
*/
export function shouldAcceptNullValue(xnullable: any, isPropRequired: any) {
let isPropNullable = xnullable && typeof xnullable === 'boolean';
return (isPropNullable === undefined && !isPropRequired) || isPropNullable;
};
let isPropNullable = xnullable && typeof xnullable === 'boolean'
return (isPropNullable === undefined && !isPropRequired) || isPropNullable
}
/**
* Relaxes/Transforms model definition to allow null values
*/
@ -640,20 +664,21 @@ export function allowNullableTypes(model: any) {
// process additionalProperties if present
if (model && typeof model.additionalProperties === 'object') {
if (model.additionalProperties.properties || model.additionalProperties.additionalProperties) {
model.additionalProperties = allowNullableTypes(model.additionalProperties);
model.additionalProperties = allowNullableTypes(model.additionalProperties)
} else {
// there shouldn't be more properties nesting at this point
model.additionalProperties = allowNullType(model.additionalProperties);
model.additionalProperties = allowNullType(model.additionalProperties)
}
}
if (model && model.properties) {
let modelProperties = model.properties;
let modelProperties = model.properties
for (let propName of getKeys(modelProperties)) {
// process properties if present
if (modelProperties[propName].properties || modelProperties[propName].additionalProperties) {
modelProperties[propName] = allowNullableTypes(modelProperties[propName]);
modelProperties[propName] = allowNullableTypes(modelProperties[propName])
}
modelProperties[propName] = allowNullType(modelProperties[propName], isPropertyRequired(propName, model));
modelProperties[propName] = allowNullType(
modelProperties[propName], isPropertyRequired(propName, model))
}
}
@ -662,51 +687,51 @@ export function allowNullableTypes(model: any) {
if (model.items) {
// if items object contains additional properties
if (model.items.additionalProperties && typeof model.items.additionalProperties === 'object') {
if (model.items.additionalProperties.properties || model.items.additionalProperties.additionalProperties) {
model.items.additionalProperties = allowNullableTypes(model.items.additionalProperties);
if (model.items.additionalProperties.properties
|| model.items.additionalProperties.additionalProperties) {
model.items.additionalProperties = allowNullableTypes(model.items.additionalProperties)
} else {
// there shouldn't be more properties nesting at this point
model.items.additionalProperties = allowNullType(model.items.additionalProperties);
model.items.additionalProperties = allowNullType(model.items.additionalProperties)
}
}
// if items object contains inline properties
if (model.items.properties) {
model.items = allowNullableTypes(model.items);
model.items = allowNullableTypes(model.items)
}
else {
model.items = allowNullType(model.items);
model.items = allowNullType(model.items)
}
}
}
// if we have a top level "object" with x-nullable set, we need to relax the model at that level
else if (model.type == "object" && model['x-nullable']) {
model = allowNullType(model);
model = allowNullType(model)
}
}
// if model is a parameter (contains "in" property") we want to relax the parameter
if (model && model.in && model['x-nullable']) {
model = allowNullType(model, model["required"]);
model = allowNullType(model, model["required"])
}
return model;
};
return model
}
/**
* Relaxes/Transforms parameter definition to allow null values for non-path parameters
*/
export function allowNullableParams(parameter: any) {
if (parameter["in"] && parameter["in"] === "body" && parameter["schema"]) {
parameter["schema"] = allowNullableTypes(parameter["schema"]);
parameter["schema"] = allowNullableTypes(parameter["schema"])
}
else {
if (parameter["in"] && parameter["in"] !== "path") {
parameter = allowNullType(parameter, parameter["required"]);
parameter = allowNullType(parameter, parameter["required"])
}
}
return parameter;
};
return parameter
}
/**
* Sanitizes the file name by replacing special characters with
@ -715,9 +740,8 @@ export function allowNullableParams(parameter: any) {
* @returns {string} result - The sanitized string.
*/
export function sanitizeFileName(str: string) {
let result = str ? str.replace(/[{}\[\]'";\(\)#@~`!%&\^\$\+=,\/\\?<>\|\*:]/ig, '').replace(/(\s+)/ig, '_') : str;
return result;
};
return str ? str.replace(/[{}\[\]'";\(\)#@~`!%&\^\$\+=,\/\\?<>\|\*:]/ig, '').replace(/(\s+)/ig, '_') : str
}
/**
* Gets the values of an object or returns an empty Array if the object is not defined.
@ -726,10 +750,10 @@ export function sanitizeFileName(str: string) {
*/
export function getValues(obj: any): any[] {
if (obj === undefined || obj === null) {
return [];
return []
}
return Object.values(obj);
};
return Object.values(obj)
}
/**
* Gets the keys of an object or returns an empty Array if the object is not defined.
@ -738,23 +762,24 @@ export function getValues(obj: any): any[] {
*/
export function getKeys(obj: any): string[] {
if (obj === undefined || obj === null) {
return [];
return []
}
return Object.keys(obj);
};
return Object.keys(obj)
}
/**
* Checks if the property is required in the model.
*/
function isPropertyRequired(propName: any, model: any) {
return model.required ? model.required.some((p: any) => { return p == propName; }) : false;
return model.required ? model.required.some((p: any) => { return p == propName; }) : false
}
/**
* Contains the reverse mapping of http.STATUS_CODES
*/
export const statusCodeStringToStatusCode = lodash.invert(lodash.mapValues(http.STATUS_CODES, (value: any) => { return value.replace(/ |-/g, "").toLowerCase(); }));
export const statusCodeStringToStatusCode = lodash.invert(
lodash.mapValues(http.STATUS_CODES, (value: any) => { return value.replace(/ |-/g, "").toLowerCase(); }))
/**
* Models an ARM cloud error schema.
@ -764,7 +789,7 @@ export const CloudErrorSchema = {
schema: {
"$ref": "#/definitions/CloudErrorWrapper"
}
};
}
/**
* Models an ARM cloud error wrapper.
@ -777,7 +802,7 @@ export const CloudErrorWrapper = {
}
},
additionalProperties: false
};
}
/**
* Models a Cloud Error
@ -787,7 +812,8 @@ export const CloudError = {
properties: {
code: {
type: "string",
description: "An identifier for the error. Codes are invariant and are intended to be consumed programmatically."
description:
"An identifier for the error. Codes are invariant and are intended to be consumed programmatically."
},
message: {
type: "string",
@ -813,4 +839,4 @@ export const CloudError = {
},
required: ["code", "message"],
additionalProperties: false
};
}

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

@ -1,9 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
var pointer = require('json-pointer');
exports = module.exports;
import pointer = require('json-pointer')
class foo{
constructor(
@ -20,78 +15,85 @@ class foo{
}
}
exports.serialize = function seralize() {
let result: any = {};
for (let prop in this) {
if (this[prop] !== null && this[prop] !== undefined) {
if (prop === 'jsonpath')
result['json-path'] = this[prop];
class ValidateResponse {
seralize() {
let result: any = {}
for (let prop in this) {
if (this[prop] !== null && this[prop] !== undefined) {
if (prop === 'jsonpath')
result['json-path'] = this[prop]
}
}
return result
}
return result;
};
exports.constructErrors = function constructErrors(validationError: any, specPath: any, providerNamespace: any) {
if (!validationError) {
throw new Error('validationError cannot be null or undefined.');
constructErrors(validationError: any, specPath: any, providerNamespace: any) {
const self = this
if (!validationError) {
throw new Error('validationError cannot be null or undefined.')
}
let result: any = []
validationError.innerErrors.forEach(function (error: any) {
let e: any = {
validationCategory: 'SwaggerViolation',
providerNamespace: providerNamespace,
type: 'error',
inner: error.inner
}
if (error.code && (self.mapper as any)[error.code]) {
e.code = error.code
e.id = (self.mapper as any)[error.code]
e.message = error.message
} else {
e.code = 'SWAGGER_SCHEMA_VALIDATION_ERROR'
e.message = validationError.message
e.id = (self.mapper as any)[e.code]
e.inner = error
}
if (error.path && error.path.length) {
let paths = [specPath + '#'].concat(error.path)
let jsonpath = pointer.compile(paths)
e.jsonref = jsonpath
e['json-path'] = pointer.unescape(jsonpath)
}
result.push(e)
})
return result
}
let result: any = [];
validationError.innerErrors.forEach(function (error: any) {
let e: any = {
validationCategory: 'SwaggerViolation',
providerNamespace: providerNamespace,
type: 'error',
inner: error.inner
};
if (error.code && exports.mapper[error.code]) {
e.code = error.code;
e.id = exports.mapper[error.code];
e.message = error.message;
} else {
e.code = 'SWAGGER_SCHEMA_VALIDATION_ERROR';
e.message = validationError.message;
e.id = exports.mapper[e.code];
e.inner = error;
}
if (error.path && error.path.length) {
let paths = [specPath + '#'].concat(error.path);
let jsonpath = pointer.compile(paths);
e.jsonref = jsonpath;
e['json-path'] = pointer.unescape(jsonpath);
}
result.push(e);
});
return result;
};
exports.sanitizeWarnings = function sanitizeWarnings(warnings: any) {
if (!warnings) {
throw new Error('validationError cannot be null or undefined.');
sanitizeWarnings(warnings: any) {
if (!warnings) {
throw new Error('validationError cannot be null or undefined.')
}
let result: any = []
warnings.forEach(function (warning: any) {
if (warning.code
&& warning.code !== 'EXTRA_REFERENCE_PROPERTIES'
&& warning.code !== 'UNUSED_DEFINITION') {
result.push(warning)
}
})
return result
}
let result: any = [];
warnings.forEach(function (warning: any) {
if (warning.code && warning.code !== 'EXTRA_REFERENCE_PROPERTIES' && warning.code !== 'UNUSED_DEFINITION') {
result.push(warning);
}
});
return result;
};
exports.mapper = {
'SWAGGER_SCHEMA_VALIDATION_ERROR': 'M6000',
'INVALID_PARAMETER_COMBINATION': 'M6001',
'MULTIPLE_BODY_PARAMETERS': 'M6002',
'DUPLICATE_PARAMETER': 'M6003',
'DUPLICATE_OPERATIONID': 'M6004',
'MISSING_PATH_PARAMETER_DEFINITION': 'M6005',
'EMPTY_PATH_PARAMETER_DECLARATION': 'M6006',
'EQUIVALENT_PATH': 'M6008',
'UNRESOLVABLE_REFERENCE': 'M6010',
'INVALID_TYPE': 'M6011',
'CIRCULAR_INHERITANCE': 'M6012',
'OBJECT_MISSING_REQUIRED_PROPERTY': 'M6013',
'OBJECT_MISSING_REQUIRED_PROPERTY_DEFINITION': 'M6014',
'ENUM_MISMATCH': 'M6015',
'ENUM_CASE_MISMATCH': 'M6016'
mapper = {
'SWAGGER_SCHEMA_VALIDATION_ERROR': 'M6000',
'INVALID_PARAMETER_COMBINATION': 'M6001',
'MULTIPLE_BODY_PARAMETERS': 'M6002',
'DUPLICATE_PARAMETER': 'M6003',
'DUPLICATE_OPERATIONID': 'M6004',
'MISSING_PATH_PARAMETER_DEFINITION': 'M6005',
'EMPTY_PATH_PARAMETER_DECLARATION': 'M6006',
'EQUIVALENT_PATH': 'M6008',
'UNRESOLVABLE_REFERENCE': 'M6010',
'INVALID_TYPE': 'M6011',
'CIRCULAR_INHERITANCE': 'M6012',
'OBJECT_MISSING_REQUIRED_PROPERTY': 'M6013',
'OBJECT_MISSING_REQUIRED_PROPERTY_DEFINITION': 'M6014',
'ENUM_MISMATCH': 'M6015',
'ENUM_CASE_MISMATCH': 'M6016'
}
}
};
export = new ValidateResponse() as any

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

@ -1,21 +1,18 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
'use strict';
var fs = require('fs'),
path = require('path'),
msrest = require('ms-rest'),
msrestazure = require('ms-rest-azure'),
ResourceManagementClient = require('azure-arm-resource').ResourceManagementClient,
log = require('./util/logging'),
utils = require('./util/utils'),
path = require('path'),
SpecValidator = require('./validators/specValidator'),
WireFormatGenerator = require('./wireFormatGenerator'),
XMsExampleExtractor = require('./xMsExampleExtractor'),
SpecResolver = require('./validators/specResolver'),
UmlGenerator = require('./umlGenerator');
import fs = require('fs')
import path = require('path')
import msrest = require('ms-rest')
import msrestazure = require('ms-rest-azure')
import { ResourceManagementClient } from 'azure-arm-resource'
import log = require('./util/logging')
import utils = require('./util/utils')
import SpecValidator = require('./validators/specValidator')
import WireFormatGenerator = require('./wireFormatGenerator')
import XMsExampleExtractor = require('./xMsExampleExtractor')
import SpecResolver = require('./validators/specResolver')
import UmlGenerator = require('./umlGenerator')
export let finalValidationResult: any = { validityStatus: true };
@ -24,251 +21,255 @@ export function getDocumentsFromCompositeSwagger(compositeSpecPath: any) {
let finalDocs: any = [];
return utils.parseJson(compositeSpecPath).then(function (result: any) {
compositeSwagger = result;
if (!(compositeSwagger.documents && Array.isArray(compositeSwagger.documents) && compositeSwagger.documents.length > 0)) {
throw new Error(`CompositeSwagger - ${compositeSpecPath} must contain a documents property and it must be of type array and it must be a non empty array.`);
if (!(compositeSwagger.documents
&& Array.isArray(compositeSwagger.documents)
&& compositeSwagger.documents.length > 0)) {
throw new Error(
`CompositeSwagger - ${compositeSpecPath} must contain a documents property and it must be of type array and it must be a non empty array.`)
}
let docs = compositeSwagger.documents;
let basePath = path.dirname(compositeSpecPath);
let docs = compositeSwagger.documents
let basePath = path.dirname(compositeSpecPath)
for (let i = 0; i < docs.length; i++) {
if (docs[i].startsWith('.')) {
docs[i] = docs[i].substring(1);
docs[i] = docs[i].substring(1)
}
let individualPath = '';
let individualPath = ''
if (docs[i].startsWith('http')) {
individualPath = docs[i];
individualPath = docs[i]
} else {
individualPath = basePath + docs[i];
individualPath = basePath + docs[i]
}
finalDocs.push(individualPath);
finalDocs.push(individualPath)
}
return finalDocs;
return finalDocs
}).catch(function (err: any) {
log.error(err);
return Promise.reject(err);
});
};
log.error(err)
return Promise.reject(err)
})
}
export function validateSpec(specPath: any, options: any) {
if (!options) options = {};
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel;
log.filepath = options.logFilepath || log.filepath;
export function validateSpec(specPath: any, options: any, _?: any) {
if (!options) options = {}
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel
log.filepath = options.logFilepath || log.filepath
// As a part of resolving discriminators we replace all the parent references
// with a oneof array containing references to the parent and its children.
// This breaks the swagger specification 2.0 schema since oneOf is not supported.
// Hence we disable it since it is not required for semantic check.
options.shouldResolveDiscriminator = false;
options.shouldResolveDiscriminator = false
// parameters in 'x-ms-parameterized-host' extension need not be resolved for semantic
// validation as that would not match the path parameters defined in the path template
// and cause the semantic validation to fail.
options.shouldResolveParameterizedHost = false;
options.shouldResolveParameterizedHost = false
// We shoudln't be resolving nullable types for semantic validaiton as we'll replace nodes
// with oneof arrays which are not semantically valid in swagger 2.0 schema.
options.shouldResolveNullableTypes = false;
let validator = new SpecValidator(specPath, null, options);
finalValidationResult[specPath] = validator.specValidationResult;
options.shouldResolveNullableTypes = false
let validator = new SpecValidator(specPath, null, options)
finalValidationResult[specPath] = validator.specValidationResult
return validator.initialize().then(function () {
log.info(`Semantically validating ${specPath}:\n`);
log.info(`Semantically validating ${specPath}:\n`)
return validator.validateSpec().then(function (result: any) {
updateEndResultOfSingleValidation(validator);
logDetailedInfo(validator);
return Promise.resolve(validator.specValidationResult);
});
updateEndResultOfSingleValidation(validator)
logDetailedInfo(validator)
return Promise.resolve(validator.specValidationResult)
})
}).catch(function (err: any) {
log.error(err);
return Promise.reject(err);
});
};
log.error(err)
return Promise.reject(err)
})
}
export function validateCompositeSpec(compositeSpecPath: any, options: any) {
if (!options) options = {};
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel;
log.filepath = options.logFilepath || log.filepath;
if (!options) options = {}
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel
log.filepath = options.logFilepath || log.filepath
return getDocumentsFromCompositeSwagger(compositeSpecPath).then(function (docs: any) {
options.consoleLogLevel = log.consoleLogLevel;
options.logFilepath = log.filepath;
options.consoleLogLevel = log.consoleLogLevel
options.logFilepath = log.filepath
let promiseFactories = docs.map(function (doc: any) {
return function () { return validateSpec(doc, options); };
});
return utils.executePromisesSequentially(promiseFactories);
return function () { return validateSpec(doc, options) }
})
return utils.executePromisesSequentially(promiseFactories)
}).catch(function (err: any) {
log.error(err);
return Promise.reject(err);
});
};
log.error(err)
return Promise.reject(err)
})
}
export function validateExamples(specPath: any, operationIds: any, options?: any) {
if (!options) options = {};
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel;
log.filepath = options.logFilepath || log.filepath;
let validator = new SpecValidator(specPath, null, options);
finalValidationResult[specPath] = validator.specValidationResult;
if (!options) options = {}
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel
log.filepath = options.logFilepath || log.filepath
let validator = new SpecValidator(specPath, null, options)
finalValidationResult[specPath] = validator.specValidationResult
return validator.initialize().then(function () {
log.info(`Validating "examples" and "x-ms-examples" in ${specPath}:\n`);
validator.validateOperations(operationIds);
updateEndResultOfSingleValidation(validator);
logDetailedInfo(validator);
return Promise.resolve(validator.specValidationResult);
log.info(`Validating "examples" and "x-ms-examples" in ${specPath}:\n`)
validator.validateOperations(operationIds)
updateEndResultOfSingleValidation(validator)
logDetailedInfo(validator)
return Promise.resolve(validator.specValidationResult)
}).catch(function (err: any) {
log.error(err);
return Promise.reject(err);
});
};
log.error(err)
return Promise.reject(err)
})
}
export function validateExamplesInCompositeSpec(compositeSpecPath: any, options: any) {
if (!options) options = {};
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel;
log.filepath = options.logFilepath || log.filepath;
if (!options) options = {}
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel
log.filepath = options.logFilepath || log.filepath
return getDocumentsFromCompositeSwagger(compositeSpecPath).then(function (docs: any) {
options.consoleLogLevel = log.consoleLogLevel;
options.logFilepath = log.filepath;
options.consoleLogLevel = log.consoleLogLevel
options.logFilepath = log.filepath
let promiseFactories = docs.map(function (doc: any) {
return function () { return validateExamples(doc, options); };
});
return utils.executePromisesSequentially(promiseFactories);
return function () { return validateExamples(doc, options) }
})
return utils.executePromisesSequentially(promiseFactories)
}).catch(function (err: any) {
log.error(err);
return Promise.reject(err);
});
};
log.error(err)
return Promise.reject(err)
})
}
export function resolveSpec(specPath: any, outputDir: any, options: any) {
if (!options) options = {};
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel;
log.filepath = options.logFilepath || log.filepath;
let specFileName = path.basename(specPath);
let resolver: any;
if (!options) options = {}
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel
log.filepath = options.logFilepath || log.filepath
let specFileName = path.basename(specPath)
let resolver: any
return utils.parseJson(specPath).then((result: any) => {
resolver = new SpecResolver(specPath, result, options);
return resolver.resolve();
resolver = new SpecResolver(specPath, result, options)
return resolver.resolve()
}).then(() => {
let resolvedSwagger = JSON.stringify(resolver.specInJson, null, 2);
let resolvedSwagger = JSON.stringify(resolver.specInJson, null, 2)
if (outputDir !== './' && !fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir);
fs.mkdirSync(outputDir)
}
let outputFilepath = `${path.join(outputDir, specFileName)}`;
fs.writeFileSync(`${path.join(outputDir, specFileName)}`, resolvedSwagger, { encoding: 'utf8' });
console.log(`Saved the resolved spec at "${outputFilepath}".`);
return Promise.resolve();
let outputFilepath = `${path.join(outputDir, specFileName)}`
fs.writeFileSync(`${path.join(outputDir, specFileName)}`, resolvedSwagger, { encoding: 'utf8' })
console.log(`Saved the resolved spec at "${outputFilepath}".`)
return Promise.resolve()
}).catch((err: any) => {
log.error(err);
return Promise.reject(err);
});
};
log.error(err)
return Promise.reject(err)
})
}
export function resolveCompositeSpec(specPath: any, outputDir: any, options: any) {
if (!options) options = {};
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel;
log.filepath = options.logFilepath || log.filepath;
if (!options) options = {}
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel
log.filepath = options.logFilepath || log.filepath
return getDocumentsFromCompositeSwagger(specPath).then(function (docs: any) {
options.consoleLogLevel = log.consoleLogLevel;
options.logFilepath = log.filepath;
options.consoleLogLevel = log.consoleLogLevel
options.logFilepath = log.filepath
let promiseFactories = docs.map(function (doc: any) {
return function () { return resolveSpec(doc, outputDir, options); };
});
return utils.executePromisesSequentially(promiseFactories);
return function () { return resolveSpec(doc, outputDir, options) }
})
return utils.executePromisesSequentially(promiseFactories)
}).catch(function (err: any) {
log.error(err);
return Promise.reject(err);
});
};
log.error(err)
return Promise.reject(err)
})
}
export function generateWireFormat(specPath: any, outDir: any, emitYaml: any, operationIds: any, options: any) {
if (!options) options = {};
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel;
log.filepath = options.logFilepath || log.filepath;
let wfGenerator = new WireFormatGenerator(specPath, null, outDir, emitYaml);
export function generateWireFormat(
specPath: any, outDir: any, emitYaml: any, operationIds: any, options: any) {
if (!options) options = {}
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel
log.filepath = options.logFilepath || log.filepath
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);
return Promise.resolve();
log.info(`Generating wire format request and responses for swagger spec: "${specPath}":\n`)
wfGenerator.processOperations(operationIds)
return Promise.resolve()
}).catch(function (err: any) {
log.error(err);
return Promise.reject(err);
});
};
log.error(err)
return Promise.reject(err)
})
}
export function generateWireFormatInCompositeSpec(compositeSpecPath: any, outDir: any, emitYaml: any, options: any) {
if (!options) options = {};
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel;
log.filepath = options.logFilepath || log.filepath;
export function generateWireFormatInCompositeSpec(
compositeSpecPath: any, outDir: any, emitYaml: any, options: any) {
if (!options) options = {}
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel
log.filepath = options.logFilepath || log.filepath
return getDocumentsFromCompositeSwagger(compositeSpecPath).then(function (docs: any) {
options.consoleLogLevel = log.consoleLogLevel;
options.logFilepath = log.filepath;
options.consoleLogLevel = log.consoleLogLevel
options.logFilepath = log.filepath
let promiseFactories = docs.map(function (doc: any) {
return function () { return generateWireFormat(doc, outDir, emitYaml, null, options); };
});
return utils.executePromisesSequentially(promiseFactories);
return function () { return generateWireFormat(doc, outDir, emitYaml, null, options) }
})
return utils.executePromisesSequentially(promiseFactories)
}).catch(function (err: any) {
log.error(err);
return Promise.reject(err);
});
};
log.error(err)
return Promise.reject(err)
})
}
export function generateUml(specPath: any, outputDir: any, options?: any) {
if (!options) options = {};
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel;
log.filepath = options.logFilepath || log.filepath;
let specFileName = path.basename(specPath);
let resolver: any;
let resolverOptions: any = {};
resolverOptions.shouldResolveRelativePaths = true;
resolverOptions.shouldResolveXmsExamples = false;
resolverOptions.shouldResolveAllOf = false;
resolverOptions.shouldSetAdditionalPropertiesFalse = false;
resolverOptions.shouldResolvePureObjects = false;
resolverOptions.shouldResolveDiscriminator = false;
resolverOptions.shouldResolveParameterizedHost = false;
resolverOptions.shouldResolveNullableTypes = false;
if (!options) options = {}
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel
log.filepath = options.logFilepath || log.filepath
let specFileName = path.basename(specPath)
let resolver: any
let resolverOptions: any = {}
resolverOptions.shouldResolveRelativePaths = true
resolverOptions.shouldResolveXmsExamples = false
resolverOptions.shouldResolveAllOf = false
resolverOptions.shouldSetAdditionalPropertiesFalse = false
resolverOptions.shouldResolvePureObjects = false
resolverOptions.shouldResolveDiscriminator = false
resolverOptions.shouldResolveParameterizedHost = false
resolverOptions.shouldResolveNullableTypes = false
return utils.parseJson(specPath).then((result: any) => {
resolver = new SpecResolver(specPath, result, resolverOptions);
return resolver.resolve();
resolver = new SpecResolver(specPath, result, resolverOptions)
return resolver.resolve()
}).then(() => {
let umlGenerator = new UmlGenerator(resolver.specInJson, options);
return umlGenerator.generateDiagramFromGraph();
let umlGenerator = new UmlGenerator(resolver.specInJson, options)
return umlGenerator.generateDiagramFromGraph()
}).then((svgGraph: any) => {
if (outputDir !== './' && !fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir);
fs.mkdirSync(outputDir)
}
let svgFile = specFileName.replace(path.extname(specFileName), '.svg');
let outputFilepath = `${path.join(outputDir, svgFile)}`;
fs.writeFileSync(`${path.join(outputDir, svgFile)}`, svgGraph, { encoding: 'utf8' });
console.log(`Saved the uml at "${outputFilepath}". Please open the file in a browser.`);
return Promise.resolve();
let svgFile = specFileName.replace(path.extname(specFileName), '.svg')
let outputFilepath = `${path.join(outputDir, svgFile)}`
fs.writeFileSync(`${path.join(outputDir, svgFile)}`, svgGraph, { encoding: 'utf8' })
console.log(`Saved the uml at "${outputFilepath}". Please open the file in a browser.`)
return Promise.resolve()
}).catch((err: any) => {
log.error(err);
return Promise.reject(err);
});
};
log.error(err)
return Promise.reject(err)
})
}
export function updateEndResultOfSingleValidation(validator: any) {
if (validator.specValidationResult.validityStatus) {
if (!(log.consoleLogLevel === 'json' || log.consoleLogLevel === 'off')) {
log.info('No Errors were found.');
log.info('No Errors were found.')
}
}
if (!validator.specValidationResult.validityStatus) {
process.exitCode = 1;
finalValidationResult.validityStatus = validator.specValidationResult.validityStatus;
process.exitCode = 1
finalValidationResult.validityStatus = validator.specValidationResult.validityStatus
}
return;
};
return
}
export function logDetailedInfo(validator: any) {
if (log.consoleLogLevel === 'json') {
console.dir(validator.specValidationResult, { depth: null, colors: true });
console.dir(validator.specValidationResult, { depth: null, colors: true })
}
log.silly('############################');
log.silly(validator.specValidationResult);
log.silly('----------------------------');
};
log.silly('############################')
log.silly(validator.specValidationResult)
log.silly('----------------------------')
}
export function extractXMsExamples(specPath: any, recordings: any, options: any) {
if (!options) options = {};
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel;
log.filepath = options.logFilepath || log.filepath;
let xMsExampleExtractor = new XMsExampleExtractor(specPath, recordings, options);
return xMsExampleExtractor.extract();
};
if (!options) options = {}
log.consoleLogLevel = options.consoleLogLevel || log.consoleLogLevel
log.filepath = options.logFilepath || log.filepath
let xMsExampleExtractor = new XMsExampleExtractor(specPath, recordings, options)
return xMsExampleExtractor.extract()
}

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

@ -2,19 +2,19 @@
// Licensed under the MIT License. See License.txt in the project root for license information.
import util = require('util')
const
path = require('path'),
os = require('os'),
url = require('url'),
_ = require('lodash'),
glob = require('glob'),
msRest = require('ms-rest'),
SpecValidator = require('./specValidator'),
Constants = require('../util/constants'),
log = require('../util/logging'),
utils = require('../util/utils'),
models = require('../models'),
http = require('http');
import path = require('path')
import os = require('os')
import url = require('url')
import _ = require('lodash')
import glob = require('glob')
import msRest = require('ms-rest')
import SpecValidator = require('./specValidator')
import Constants = require('../util/constants')
import log = require('../util/logging')
import utils = require('../util/utils')
import models = require('../models')
import http = require('http')
import PotentialOperationsResult = require('../models/potentialOperationsResult')
/**
* @class
@ -46,71 +46,80 @@ class LiveValidator {
*
* @returns {object} CacheBuilder Returns the configured CacheBuilder object.
*/
constructor(public options: any) {
constructor(public options?: any) {
if (this.options === null || this.options === undefined) {
this.options = {};
this.options = {}
}
if (typeof this.options !== 'object') {
throw new Error('options must be of type "object".');
throw new Error('options must be of type "object".')
}
if (this.options.swaggerPaths === null || this.options.swaggerPaths === undefined) {
this.options.swaggerPaths = [];
this.options.swaggerPaths = []
}
if (!Array.isArray(this.options.swaggerPaths)) {
throw new Error(`options.swaggerPaths must be of type "array" instead of type "${typeof this.options.swaggerPaths}".`);
throw new Error(
`options.swaggerPaths must be of type "array" instead of type "${typeof this.options.swaggerPaths}".`)
}
if (this.options.git === null || this.options.git === undefined) {
this.options.git = {
"url": "https://github.com/Azure/azure-rest-api-specs.git",
"shouldClone": false
};
}
}
if (typeof this.options.git !== 'object') {
throw new Error('options.git must be of type "object".');
throw new Error('options.git must be of type "object".')
}
if (this.options.git.url === null || this.options.git.url === undefined) {
this.options.git.url = "https://github.com/Azure/azure-rest-api-specs.git";
this.options.git.url = "https://github.com/Azure/azure-rest-api-specs.git"
}
if (typeof this.options.git.url.valueOf() !== 'string') {
throw new Error('options.git.url must be of type "string".');
throw new Error('options.git.url must be of type "string".')
}
if (this.options.git.shouldClone === null || this.options.git.shouldClone === undefined) {
this.options.git.shouldClone = false;
this.options.git.shouldClone = false
}
if (typeof this.options.git.shouldClone !== 'boolean') {
throw new Error('options.git.shouldClone must be of type "boolean".');
throw new Error('options.git.shouldClone must be of type "boolean".')
}
if (this.options.directory === null || this.options.directory === undefined) {
this.options.directory = path.resolve(os.homedir(), 'repo');
this.options.directory = path.resolve(os.homedir(), 'repo')
}
if (typeof this.options.directory.valueOf() !== 'string') {
throw new Error('options.directory must be of type "string".');
throw new Error('options.directory must be of type "string".')
}
this.cache = {};
this.cache = {}
}
/**
* Initializes the Live Validator.
*/
initialize() {
let self = this;
let self = this
// Clone github repository if required
if (self.options.git.shouldClone) {
utils.gitClone(self.options.directory, self.options.git.url, self.options.git.branch);
utils.gitClone(self.options.directory, self.options.git.url, self.options.git.branch)
}
// Construct array of swagger paths to be used for building a cache
let swaggerPaths;
let swaggerPaths
if (self.options.swaggerPaths.length !== 0) {
swaggerPaths = self.options.swaggerPaths;
log.debug(`Using user provided swagger paths. Total paths: ${swaggerPaths.length}`);
swaggerPaths = self.options.swaggerPaths
log.debug(`Using user provided swagger paths. Total paths: ${swaggerPaths.length}`)
} else {
let allJsonsPattern = '/specification/**/*.json';
let jsonsPattern = path.join(self.options.directory, self.options.swaggerPathsPattern || allJsonsPattern);
swaggerPaths = glob.sync(jsonsPattern, { ignore: ['**/examples/**/*', '**/quickstart-templates/**/*', '**/schema/**/*', '**/live/**/*', '**/wire-format/**/*'] });
log.debug(`Using swaggers found from directory "${self.options.directory}" and pattern "${jsonsPattern}". Total paths: ${swaggerPaths.length}`);
let allJsonsPattern = '/specification/**/*.json'
let jsonsPattern = path.join(
self.options.directory, self.options.swaggerPathsPattern || allJsonsPattern)
swaggerPaths = glob.sync(
jsonsPattern,
{
ignore: [
'**/examples/**/*', '**/quickstart-templates/**/*', '**/schema/**/*', '**/live/**/*', '**/wire-format/**/*'
]
})
log.debug(
`Using swaggers found from directory "${self.options.directory}" and pattern "${jsonsPattern}". Total paths: ${swaggerPaths.length}`)
}
// console.log(swaggerPaths);
// Create array of promise factories that builds up cache
@ -141,7 +150,7 @@ class LiveValidator {
// }
let promiseFactories = swaggerPaths.map((swaggerPath: any) => {
return () => {
log.info(`Building cache from: "${swaggerPath}"`);
log.info(`Building cache from: "${swaggerPath}"`)
let validator = new SpecValidator(
swaggerPath,
@ -149,59 +158,61 @@ class LiveValidator {
{
shouldModelImplicitDefaultResponse: this.options.shouldModelImplicitDefaultResponse,
isPathCaseSensitive: this.options.isPathCaseSensitive
});
})
return validator.initialize().then((api: any) => {
let operations = api.getOperations();
let apiVersion = api.info.version.toLowerCase();
let operations = api.getOperations()
let apiVersion = api.info.version.toLowerCase()
operations.forEach((operation: any) => {
let httpMethod = operation.method.toLowerCase();
let provider = utils.getProvider(operation.pathObject.path);
log.debug(`${apiVersion}, ${operation.operationId}, ${operation.pathObject.path}, ${httpMethod}`);
let httpMethod = operation.method.toLowerCase()
let provider = utils.getProvider(operation.pathObject.path)
log.debug(`${apiVersion}, ${operation.operationId}, ${operation.pathObject.path}, ${httpMethod}`)
if (!provider) {
let title = api.info.title;
let title = api.info.title
// Whitelist lookups: Look up knownTitleToResourceProviders
// Putting the provider namespace onto operation for future use
if (title && Constants.knownTitleToResourceProviders[title]) {
operation.provider = Constants.knownTitleToResourceProviders[title];
if (title && (Constants.knownTitleToResourceProviders as any)[title]) {
operation.provider = (Constants.knownTitleToResourceProviders as any)[title]
}
// Put the operation into 'Microsoft.Unknown' RPs
provider = Constants.unknownResourceProvider;
apiVersion = Constants.unknownApiVersion;
log.debug(`Unable to find provider for path : "${operation.pathObject.path}". Bucketizing into provider: "${provider}"`);
provider = Constants.unknownResourceProvider
apiVersion = Constants.unknownApiVersion
log.debug(
`Unable to find provider for path : "${operation.pathObject.path}". Bucketizing into provider: "${provider}"`)
}
provider = provider.toLowerCase();
provider = provider.toLowerCase()
// Get all api-version for given provider or initialize it
let apiVersions = self.cache[provider] || {};
let apiVersions = self.cache[provider] || {}
// Get methods for given apiVersion or initialize it
let allMethods = apiVersions[apiVersion] || {};
let allMethods = apiVersions[apiVersion] || {}
// Get specific http methods array for given verb or initialize it
let operationsForHttpMethod = allMethods[httpMethod] || [];
let operationsForHttpMethod = allMethods[httpMethod] || []
// Builds the cache
operationsForHttpMethod.push(operation);
allMethods[httpMethod] = operationsForHttpMethod;
apiVersions[apiVersion] = allMethods;
self.cache[provider] = apiVersions;
});
operationsForHttpMethod.push(operation)
allMethods[httpMethod] = operationsForHttpMethod
apiVersions[apiVersion] = allMethods
self.cache[provider] = apiVersions
})
return Promise.resolve(self.cache);
return Promise.resolve(self.cache)
}).catch(function (err: any) {
// Do Not reject promise in case, we cannot initialize one of the swagger
log.debug(`Unable to initialize "${swaggerPath}" file from SpecValidator. Error: ${err}`);
log.warn(`Unable to initialize "${swaggerPath}" file from SpecValidator. We are ignoring this swagger file and continuing to build cache for other valid specs.`);
});
};
});
log.debug(`Unable to initialize "${swaggerPath}" file from SpecValidator. Error: ${err}`)
log.warn(
`Unable to initialize "${swaggerPath}" file from SpecValidator. We are ignoring this swagger file and continuing to build cache for other valid specs.`)
})
}
})
return utils.executePromisesSequentially(promiseFactories).then(() => {
log.info("Cache initialization complete.");
});
log.info("Cache initialization complete.")
})
}
/**
@ -213,98 +224,109 @@ class LiveValidator {
*
* @returns {PotentialOperationsResult} Potential operation result object.
*/
getPotentialOperations(requestUrl: string, requestMethod: string) {
getPotentialOperations(requestUrl: string, requestMethod: string): PotentialOperationsResult {
if (_.isEmpty(this.cache)) {
let msg = `Please call "liveValidator.initialize()" before calling this method, so that cache is populated.`;
throw new Error(msg);
let msg =
`Please call "liveValidator.initialize()" before calling this method, so that cache is populated.`
throw new Error(msg)
}
if (requestUrl === null || requestUrl === undefined || typeof requestUrl.valueOf() !== 'string' ||
!requestUrl.trim().length) {
throw new Error('requestUrl is a required parameter of type "string" and it cannot be an empty string.');
if (requestUrl === null
|| requestUrl === undefined
|| typeof requestUrl.valueOf() !== 'string'
|| !requestUrl.trim().length) {
throw new Error(
'requestUrl is a required parameter of type "string" and it cannot be an empty string.')
}
if (requestMethod === null || requestMethod === undefined || typeof requestMethod.valueOf() !== 'string' ||
!requestMethod.trim().length) {
throw new Error('requestMethod is a required parameter of type "string" and it cannot be an empty string.');
if (requestMethod === null
|| requestMethod === undefined
|| typeof requestMethod.valueOf() !== 'string'
|| !requestMethod.trim().length) {
throw new Error(
'requestMethod is a required parameter of type "string" and it cannot be an empty string.')
}
let self = this;
let potentialOperations: any[] = [];
let parsedUrl = url.parse(requestUrl, true);
let path = parsedUrl.pathname;
requestMethod = requestMethod.toLowerCase();
let result;
let msg;
let code;
let liveValidationError;
let self = this
let potentialOperations: any[] = []
let parsedUrl = url.parse(requestUrl, true)
let path = parsedUrl.pathname
requestMethod = requestMethod.toLowerCase()
let result
let msg
let code
let liveValidationError
if (path === null || path === undefined) {
msg = `Could not find path from requestUrl: "${requestUrl}".`;
liveValidationError = new models.LiveValidationError(Constants.ErrorCodes.PathNotFoundInRequestUrl.name, msg);
result = new models.PotentialOperationsResult(potentialOperations, liveValidationError);
return result;
msg = `Could not find path from requestUrl: "${requestUrl}".`
liveValidationError = new models.LiveValidationError(
Constants.ErrorCodes.PathNotFoundInRequestUrl.name, msg)
result = new models.PotentialOperationsResult(potentialOperations, liveValidationError)
return result
}
// Lower all the keys of query parameters before searching for `api-version`
var queryObject = _.transform(parsedUrl.query, function (result: any, value: any, key: any) {
result[key.toLowerCase()] = value;
});
let apiVersion = queryObject['api-version'];
let provider = utils.getProvider(path);
result[key.toLowerCase()] = value
})
let apiVersion: any = queryObject['api-version']
let provider = utils.getProvider(path)
// Provider would be provider found from the path or Microsoft.Unknown
provider = provider || Constants.unknownResourceProvider;
provider = provider || Constants.unknownResourceProvider
if (provider === Constants.unknownResourceProvider) {
apiVersion = Constants.unknownApiVersion;
apiVersion = Constants.unknownApiVersion
}
provider = provider.toLowerCase();
provider = provider.toLowerCase()
// Search using provider
let allApiVersions = self.cache[provider];
let allApiVersions = self.cache[provider]
if (allApiVersions) {
// Search using api-version found in the requestUrl
if (apiVersion) {
let allMethods = allApiVersions[apiVersion];
let allMethods = allApiVersions[apiVersion]
if (allMethods) {
let operationsForHttpMethod = allMethods[requestMethod];
let operationsForHttpMethod = allMethods[requestMethod]
// Search using requestMethod provided by user
if (operationsForHttpMethod) {
// Find the best match using regex on path
potentialOperations = self.getPotentialOperationsHelper(path, requestMethod, operationsForHttpMethod);
potentialOperations = self.getPotentialOperationsHelper(
path, requestMethod, operationsForHttpMethod)
// If potentialOperations were to be [] then we need reason
msg = `Could not find best match operation for verb "${requestMethod}" for api-version "${apiVersion}" and provider "${provider}" in the cache.`;
code = Constants.ErrorCodes.OperationNotFoundInCache;
msg =
`Could not find best match operation for verb "${requestMethod}" for api-version "${apiVersion}" and provider "${provider}" in the cache.`
code = Constants.ErrorCodes.OperationNotFoundInCache
} else {
msg = `Could not find any methods with verb "${requestMethod}" for api-version "${apiVersion}" and provider "${provider}" in the cache.`;
code = Constants.ErrorCodes.OperationNotFoundInCacheWithVerb;
log.debug(msg);
msg =
`Could not find any methods with verb "${requestMethod}" for api-version "${apiVersion}" and provider "${provider}" in the cache.`
code = Constants.ErrorCodes.OperationNotFoundInCacheWithVerb
log.debug(msg)
}
} else {
msg = `Could not find exact api-version "${apiVersion}" for provider "${provider}" in the cache.`;
code = Constants.ErrorCodes.OperationNotFoundInCacheWithApi;
log.debug(`${msg} We'll search in the resource provider "Microsoft.Unknown".`);
potentialOperations = self.getPotentialOperationsHelper(path, requestMethod, []);
msg = `Could not find exact api-version "${apiVersion}" for provider "${provider}" in the cache.`
code = Constants.ErrorCodes.OperationNotFoundInCacheWithApi
log.debug(`${msg} We'll search in the resource provider "Microsoft.Unknown".`)
potentialOperations = self.getPotentialOperationsHelper(path, requestMethod, [])
}
} else {
msg = `Could not find api-version in requestUrl "${requestUrl}".`;
code = Constants.ErrorCodes.OperationNotFoundInCacheWithApi;
log.debug(msg);
msg = `Could not find api-version in requestUrl "${requestUrl}".`
code = Constants.ErrorCodes.OperationNotFoundInCacheWithApi
log.debug(msg)
}
} else {
// provider does not exist in cache
msg = `Could not find provider "${provider}" in the cache.`;
code = Constants.ErrorCodes.OperationNotFoundInCacheWithProvider;
log.debug(`${msg} We'll search in the resource provider "Microsoft.Unknown".`);
potentialOperations = self.getPotentialOperationsHelper(path, requestMethod, []);
msg = `Could not find provider "${provider}" in the cache.`
code = Constants.ErrorCodes.OperationNotFoundInCacheWithProvider
log.debug(`${msg} We'll search in the resource provider "Microsoft.Unknown".`)
potentialOperations = self.getPotentialOperationsHelper(path, requestMethod, [])
}
// Provide reason when we do not find any potential operaion in cache
if (potentialOperations.length === 0) {
liveValidationError = new models.LiveValidationError(code.name, msg);
liveValidationError = new models.LiveValidationError(code.name, msg)
}
result = new models.PotentialOperationsResult(potentialOperations, liveValidationError);
return result;
result = new models.PotentialOperationsResult(potentialOperations, liveValidationError)
return result
}
/**
@ -319,46 +341,52 @@ class LiveValidator {
* @returns {Array<Operation>} List of potential operations matching the requestPath.
*/
getPotentialOperationsHelper(requestPath: string, requestMethod: string, operations: any[]) {
if (requestPath === null || requestPath === undefined || typeof requestPath.valueOf() !== 'string' ||
!requestPath.trim().length) {
throw new Error('requestPath is a required parameter of type "string" and it cannot be an empty string.');
if (requestPath === null
|| requestPath === undefined
|| typeof requestPath.valueOf() !== 'string'
|| !requestPath.trim().length) {
throw new Error(
'requestPath is a required parameter of type "string" and it cannot be an empty string.')
}
if (requestMethod === null || requestMethod === undefined || typeof requestMethod.valueOf() !== 'string' ||
!requestMethod.trim().length) {
throw new Error('requestMethod is a required parameter of type "string" and it cannot be an empty string.');
if (requestMethod === null
|| requestMethod === undefined
|| typeof requestMethod.valueOf() !== 'string'
|| !requestMethod.trim().length) {
throw new Error(
'requestMethod is a required parameter of type "string" and it cannot be an empty string.')
}
if (operations === null || operations === undefined || !Array.isArray(operations)) {
throw new Error('operations is a required parameter of type "array".');
throw new Error('operations is a required parameter of type "array".')
}
let self = this;
let potentialOperations = [];
let self = this
let potentialOperations = []
potentialOperations = operations.filter((operation) => {
let pathMatch = operation.pathObject.regexp.exec(requestPath);
return pathMatch === null ? false : true;
});
let pathMatch = operation.pathObject.regexp.exec(requestPath)
return pathMatch === null ? false : true
})
// If we do not find any match then we'll look into Microsoft.Unknown -> unknown-api-version
// for given requestMethod as the fall back option
if (!potentialOperations.length) {
if (self.cache[Constants.unknownResourceProvider] &&
self.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]) {
operations = self.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion][requestMethod];
operations = self.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion][requestMethod]
potentialOperations = operations.filter((operation) => {
let pathTemplate = operation.pathObject.path;
let pathTemplate = operation.pathObject.path
if (pathTemplate && pathTemplate.includes("?")) {
pathTemplate = pathTemplate.slice(0, pathTemplate.indexOf("?"));
operation.pathObject.path = pathTemplate;
pathTemplate = pathTemplate.slice(0, pathTemplate.indexOf("?"))
operation.pathObject.path = pathTemplate
}
let pathMatch = operation.pathObject.regexp.exec(requestPath);
return pathMatch === null ? false : true;
});
let pathMatch = operation.pathObject.regexp.exec(requestPath)
return pathMatch === null ? false : true
})
}
}
return potentialOperations;
return potentialOperations
}
/**
@ -370,7 +398,7 @@ class LiveValidator {
* @returns {object} validationResult - Validation result for given input
*/
validateLiveRequestResponse(requestResponseObj: any) {
let self = this;
let self = this
let validationResult = {
requestValidationResult: {
successfulRequest: false,
@ -385,106 +413,114 @@ class LiveValidator {
errors: [] as any[]
};
if (!requestResponseObj || (requestResponseObj && typeof requestResponseObj !== 'object')) {
let msg = 'requestResponseObj cannot be null or undefined and must be of type "object".';
let e = new models.LiveValidationError(Constants.ErrorCodes.IncorrectInput.name, msg);
validationResult.errors.push(e);
return validationResult;
let msg = 'requestResponseObj cannot be null or undefined and must be of type "object".'
let e = new models.LiveValidationError(Constants.ErrorCodes.IncorrectInput.name, msg)
validationResult.errors.push(e)
return validationResult
}
try {
// We are using this to validate the payload as per the definitions in swagger.
// We do not need the serialized output from ms-rest.
let mapper = new models.RequestResponse().mapper();
msRest.models = models;
msRest.serialize(mapper, requestResponseObj, 'requestResponseObj');
(msRest as any).models = models;
(msRest as any).serialize(mapper, requestResponseObj, 'requestResponseObj');
} catch (err) {
let msg = `Found errors "${err.message}" in the provided input:\n` +
`${util.inspect(requestResponseObj, { depth: null })}.`;
let e = new models.LiveValidationError(Constants.ErrorCodes.IncorrectInput.name, msg);
validationResult.errors.push(e);
return validationResult;
let msg =
`Found errors "${err.message}" in the provided input:\n` +
`${util.inspect(requestResponseObj, { depth: null })}.`
let e = new models.LiveValidationError(Constants.ErrorCodes.IncorrectInput.name, msg)
validationResult.errors.push(e)
return validationResult
}
let request = requestResponseObj.liveRequest;
let response = requestResponseObj.liveResponse;
let request = requestResponseObj.liveRequest
let response = requestResponseObj.liveResponse
// If status code is passed as a status code string (e.g. "OK") tranform it to the status code number (e.g. '200').
if (response && !http.STATUS_CODES[response.statusCode] && utils.statusCodeStringToStatusCode[response.statusCode.toLowerCase()]) {
response.statusCode = utils.statusCodeStringToStatusCode[response.statusCode.toLowerCase()];
if (response
&& !http.STATUS_CODES[response.statusCode]
&& utils.statusCodeStringToStatusCode[response.statusCode.toLowerCase()]) {
response.statusCode = utils.statusCodeStringToStatusCode[response.statusCode.toLowerCase()]
}
if (!request.query) {
request.query = url.parse(request.url, true).query;
request.query = url.parse(request.url, true).query
}
let currentApiVersion = request.query['api-version'] || Constants.unknownApiVersion;
let potentialOperationsResult;
let potentialOperations = [];
let currentApiVersion = request.query['api-version'] || Constants.unknownApiVersion
let potentialOperationsResult
let potentialOperations = []
try {
potentialOperationsResult = self.getPotentialOperations(request.url, request.method);
potentialOperations = potentialOperationsResult.operations;
potentialOperationsResult = self.getPotentialOperations(request.url, request.method)
potentialOperations = potentialOperationsResult.operations
} catch (err) {
let msg = `An error occured while trying to search for potential operations:\n` +
`${util.inspect(err, { depth: null })}`;
let e = new models.LiveValidationError(Constants.ErrorCodes.PotentialOperationSearchError.name, msg);
validationResult.errors.push(e);
return validationResult;
let msg =
`An error occured while trying to search for potential operations:\n` +
`${util.inspect(err, { depth: null })}`
let e = new models.LiveValidationError(
Constants.ErrorCodes.PotentialOperationSearchError.name, msg)
validationResult.errors.push(e)
return validationResult
}
// Found empty potentialOperations
if (potentialOperations.length === 0) {
validationResult.errors.push(potentialOperationsResult.reason);
return validationResult;
validationResult.errors.push(potentialOperationsResult.reason)
return validationResult
}
// Found exactly 1 potentialOperations
else if (potentialOperations.length === 1) {
let operation = potentialOperations[0];
let operation = potentialOperations[0]
let basicOperationInfo = {
operationId: operation.operationId,
apiVersion: currentApiVersion
};
validationResult.requestValidationResult.operationInfo = [basicOperationInfo];
validationResult.responseValidationResult.operationInfo = [basicOperationInfo];
let reqResult;
try {
reqResult = operation.validateRequest(request);
validationResult.requestValidationResult.errors = reqResult.errors || [];
log.debug('Request Validation Result');
log.debug(reqResult);
} catch (reqValidationError) {
let msg = `An error occurred while validating the live request for operation "${operation.operationId}". ` +
`The error is:\n ${util.inspect(reqValidationError, { depth: null })}`;
let err = new models.LiveValidationError(Constants.ErrorCodes.RequestValidationError.name, msg);
validationResult.requestValidationResult.errors = [err];
}
let resResult;
validationResult.requestValidationResult.operationInfo = [basicOperationInfo]
validationResult.responseValidationResult.operationInfo = [basicOperationInfo]
let reqResult
try {
resResult = operation.validateResponse(response);
validationResult.responseValidationResult.errors = resResult.errors || [];
log.debug('Response Validation Result');
log.debug(resResult);
reqResult = operation.validateRequest(request)
validationResult.requestValidationResult.errors = reqResult.errors || []
log.debug('Request Validation Result')
log.debug(reqResult)
} catch (reqValidationError) {
let msg =
`An error occurred while validating the live request for operation "${operation.operationId}". ` +
`The error is:\n ${util.inspect(reqValidationError, { depth: null })}`
let err = new models.LiveValidationError(Constants.ErrorCodes.RequestValidationError.name, msg)
validationResult.requestValidationResult.errors = [err]
}
let resResult
try {
resResult = operation.validateResponse(response)
validationResult.responseValidationResult.errors = resResult.errors || []
log.debug('Response Validation Result')
log.debug(resResult)
} catch (resValidationError) {
let msg = `An error occurred while validating the live response for operation "${operation.operationId}". ` +
`The error is:\n ${util.inspect(resValidationError, { depth: null })}`;
let err = new models.LiveValidationError(Constants.ErrorCodes.ResponseValidationError.name, msg);
validationResult.responseValidationResult.errors = [err];
let msg =
`An error occurred while validating the live response for operation "${operation.operationId}". ` +
`The error is:\n ${util.inspect(resValidationError, { depth: null })}`
let err = new models.LiveValidationError(Constants.ErrorCodes.ResponseValidationError.name, msg)
validationResult.responseValidationResult.errors = [err]
}
if (reqResult && reqResult.errors && Array.isArray(reqResult.errors) && !reqResult.errors.length) {
validationResult.requestValidationResult.successfulRequest = true;
validationResult.requestValidationResult.successfulRequest = true
}
if (resResult && resResult.errors && Array.isArray(resResult.errors) && !resResult.errors.length) {
validationResult.responseValidationResult.successfulResponse = true;
validationResult.responseValidationResult.successfulResponse = true
}
}
// Found more than 1 potentialOperations
else {
let operationIds = potentialOperations.map((op: any) => { return op.operationId; }).join();
let msg = `Found multiple matching operations with operationIds "${operationIds}" ` +
let operationIds = potentialOperations.map((op: any) => { return op.operationId; }).join()
let msg =
`Found multiple matching operations with operationIds "${operationIds}" ` +
`for request url "${request.url}" with HTTP Method "${request.method}".`;
log.debug(msg);
let err = new models.LiveValidationError(Constants.ErrorCodes.MultipleOperationsFound.name, msg);
validationResult.errors = [err];
log.debug(msg)
let err = new models.LiveValidationError(Constants.ErrorCodes.MultipleOperationsFound.name, msg)
validationResult.errors = [err]
}
return validationResult;
return validationResult
}
}
module.exports = LiveValidator;
export = LiveValidator

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -1,23 +1,23 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
'use strict';
import JsonRefs = require('json-refs')
import fs = require('fs')
import path = require('path')
import utils = require('./util/utils')
import Sway = require('sway')
import msRest = require('ms-rest')
import JsonRefs = require('json-refs');
const fs = require('fs');
const path = require('path');
const utils = require('./util/utils');
const Sway = require('sway');
const msRest = require('ms-rest');
const HttpRequest = msRest.WebResource;
const log = require('./util/logging');
const SpecResolver = require('./validators/specResolver');
const ResponseWrapper = require('./models/responseWrapper');
const MarkdownHttpTemplate = require('./templates/markdownHttpTemplate');
const YamlHttpTemplate = require('./templates/yamlHttpTemplate');
const Constants = require('./util/constants');
const ErrorCodes = Constants.ErrorCodes;
let HttpRequest = msRest.WebResource
import log = require('./util/logging')
import SpecResolver = require('./validators/specResolver')
import ResponseWrapper = require('./models/responseWrapper')
import MarkdownHttpTemplate = require('./templates/markdownHttpTemplate')
import YamlHttpTemplate = require('./templates/yamlHttpTemplate')
import Constants = require('./util/constants')
const ErrorCodes = Constants.ErrorCodes
class WireFormatGenerator {
specPath: any
@ -30,66 +30,71 @@ class WireFormatGenerator {
options: any
specValidationResult: any
constructor(specPath: any, specInJson: any, wireFormatDir: any, emitYaml: any) {
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.');
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.')
}
//If the spec path is a url starting with https://github then let us auto convert it to an https://raw.githubusercontent url.
if (specPath.startsWith('https://github')) {
specPath = specPath.replace(/^https:\/\/(github.com)(.*)blob\/(.*)/ig, 'https://raw.githubusercontent.com$2$3');
specPath = specPath.replace(
/^https:\/\/(github.com)(.*)blob\/(.*)/ig, 'https://raw.githubusercontent.com$2$3')
}
this.specPath = specPath;
this.specDir = path.dirname(this.specPath);
let wfDir = path.join(this.specDir, 'wire-format');
this.specPath = specPath
this.specDir = path.dirname(this.specPath)
let wfDir = path.join(this.specDir, 'wire-format')
if (specPath.startsWith('https://')) {
wfDir = process.cwd() + '/wire-format';
wfDir = process.cwd() + '/wire-format'
}
this.wireFormatDir = wireFormatDir || wfDir;
this.wireFormatDir = wireFormatDir || wfDir
if (!fs.existsSync(this.wireFormatDir)) {
fs.mkdirSync(this.wireFormatDir);
fs.mkdirSync(this.wireFormatDir)
}
this.emitYaml = emitYaml || false;
this.specInJson = specInJson;
this.specResolver = null;
this.swaggerApi = null;
this.emitYaml = emitYaml || false
this.specInJson = specInJson
this.specResolver = null
this.swaggerApi = null
this.options = {
shouldResolveRelativePaths: true
};
}
}
initialize() {
let self = this;
let self = this
if (self.options.shouldResolveRelativePaths) {
utils.clearCache();
utils.clearCache()
}
return utils.parseJson(self.specPath).then((result: any) => {
self.specInJson = result;
self.specInJson = result
let options = {
shouldResolveRelativePaths: true,
shouldResolveXmsExamples: false,
shouldResolveAllOf: false,
shouldSetAdditionalPropertiesFalse: false,
shouldResolvePureObjects: false
};
self.specResolver = new SpecResolver(self.specPath, self.specInJson, options);
return self.specResolver.resolve();
}
self.specResolver = new SpecResolver(self.specPath, self.specInJson, options)
return self.specResolver.resolve()
}).then(() => {
return self.resolveExamples();
return self.resolveExamples()
}).then(() => {
let options: any = {};
options.definition = self.specInJson;
options.jsonRefs = {};
options.jsonRefs.relativeBase = self.specDir;
return Sway.create(options);
let options: any = {}
options.definition = self.specInJson
options.jsonRefs = {}
options.jsonRefs.relativeBase = self.specDir
return Sway.create(options)
}).then((api: any) => {
self.swaggerApi = api;
return Promise.resolve(api);
self.swaggerApi = api
return Promise.resolve(api)
}).catch((err: any) => {
let e = self.constructErrorObject(ErrorCodes.ResolveSpecError, err.message, [err]);
let e = self.constructErrorObject(ErrorCodes.ResolveSpecError, err.message, [err])
//self.specValidationResult.resolveSpec = e;
log.error(`${ErrorCodes.ResolveSpecError.name}: ${err.message}.`);
log.error(err.stack);
return Promise.reject(e);
});
log.error(`${ErrorCodes.ResolveSpecError.name}: ${err.message}.`)
log.error(err.stack)
return Promise.reject(e)
})
}
/*
@ -99,11 +104,11 @@ class WireFormatGenerator {
*/
updateValidityStatus(value: boolean) {
if (!Boolean(value)) {
this.specValidationResult.validityStatus = false;
this.specValidationResult.validityStatus = false
} else {
this.specValidationResult.validityStatus = true;
this.specValidationResult.validityStatus = true
}
return;
return
}
/*
@ -119,85 +124,87 @@ class WireFormatGenerator {
*
* @return {object} err Return the constructed Error object.
*/
constructErrorObject(code: string, message: string, innerErrors: any[], skipValidityStatusUpdate?: boolean) {
constructErrorObject(code: any, message: string, innerErrors: any[], skipValidityStatusUpdate?: boolean) {
let err = {
code: code,
message: message,
innerErrors: undefined as any
};
}
if (innerErrors) {
err.innerErrors = innerErrors;
err.innerErrors = innerErrors
}
//if (!skipValidityStatusUpdate) {
//this.updateValidityStatus();
//}
return err;
return err
}
resolveExamples() {
let self = this;
let self = this
let options = {
relativeBase: self.specDir,
filter: ['relative', 'remote']
};
}
let allRefsRemoteRelative = JsonRefs.findRefs(self.specInJson, options);
let allRefsRemoteRelative = JsonRefs.findRefs(self.specInJson, options)
let promiseFactories = utils.getKeys(allRefsRemoteRelative).map(function (refName: any) {
let refDetails = allRefsRemoteRelative[refName];
return function () { return self.resolveRelativeReference(refName, refDetails, self.specInJson, self.specPath); };
});
let refDetails = allRefsRemoteRelative[refName]
return function () {
return self.resolveRelativeReference(refName, refDetails, self.specInJson, self.specPath)
}
})
if (promiseFactories.length) {
return utils.executePromisesSequentially(promiseFactories);
return utils.executePromisesSequentially(promiseFactories)
} else {
return Promise.resolve(self.specInJson);
return Promise.resolve(self.specInJson)
}
}
resolveRelativeReference(refName: any, refDetails: any, doc: any, docPath: any) {
if (!refName || (refName && typeof refName.valueOf() !== 'string')) {
throw new Error('refName cannot be null or undefined and must be of type "string".');
throw new Error('refName cannot be null or undefined and must be of type "string".')
}
if (!refDetails || (refDetails && !(refDetails instanceof Object))) {
throw new Error('refDetails cannot be null or undefined and must be of type "object".');
throw new Error('refDetails cannot be null or undefined and must be of type "object".')
}
if (!doc || (doc && !(doc instanceof Object))) {
throw new Error('doc cannot be null or undefined and must be of type "object".');
throw new Error('doc cannot be null or undefined and must be of type "object".')
}
if (!docPath || (docPath && typeof docPath.valueOf() !== 'string')) {
throw new Error('docPath cannot be null or undefined and must be of type "string".');
throw new Error('docPath cannot be null or undefined and must be of type "string".')
}
let self = this;
let node = refDetails.def;
let slicedRefName = refName.slice(1);
let reference = node['$ref'];
let parsedReference = utils.parseReferenceInSwagger(reference);
let docDir = path.dirname(docPath);
let self = this
let node = refDetails.def
let slicedRefName = refName.slice(1)
let reference = node['$ref']
let parsedReference = utils.parseReferenceInSwagger(reference)
let docDir = path.dirname(docPath)
if (parsedReference.filePath) {
//assuming that everything in the spec is relative to it, let us join the spec directory
//and the file path in reference.
docPath = utils.joinPath(docDir, parsedReference.filePath);
docPath = utils.joinPath(docDir, parsedReference.filePath)
}
return utils.parseJson(docPath).then((result: any) => {
if (!parsedReference.localReference) {
//Since there is no local reference we will replace the key in the object with the parsed
//json (relative) file it is refering to.
let regex = /.*x-ms-examples.*/ig;
let regex = /.*x-ms-examples.*/ig
if (slicedRefName.match(regex) !== null) {
let exampleObj = {
filePath: docPath,
value: result
};
utils.setObject(doc, slicedRefName, exampleObj);
}
utils.setObject(doc, slicedRefName, exampleObj)
}
}
return Promise.resolve(doc);
});
return Promise.resolve(doc)
})
}
/*
@ -207,27 +214,30 @@ class WireFormatGenerator {
* which the wire format needs to be generated. If not specified then the entire spec is processed.
*/
processOperations(operationIds: string) {
let self = this;
let self = this
if (!self.swaggerApi) {
throw new Error(`Please call "specValidator.initialize()" before calling this method, so that swaggerApi is populated.`);
throw new Error(
`Please call "specValidator.initialize()" before calling this method, so that swaggerApi is populated.`)
}
if (operationIds !== null && operationIds !== undefined && typeof operationIds.valueOf() !== 'string') {
throw new Error(`operationIds parameter must be of type 'string'.`);
if (operationIds !== null
&& operationIds !== undefined
&& typeof operationIds.valueOf() !== 'string') {
throw new Error(`operationIds parameter must be of type 'string'.`)
}
let operations = self.swaggerApi.getOperations();
let operations = self.swaggerApi.getOperations()
if (operationIds) {
let operationIdsObj: any = {};
operationIds.trim().split(',').map(function (item) { operationIdsObj[item.trim()] = 1; });
let operationIdsObj: any = {}
operationIds.trim().split(',').map(function (item) { operationIdsObj[item.trim()] = 1; })
let operationsToValidate = operations.filter(function (item: any) {
return Boolean(operationIdsObj[item.operationId]);
});
if (operationsToValidate.length) operations = operationsToValidate;
return Boolean(operationIdsObj[item.operationId])
})
if (operationsToValidate.length) operations = operationsToValidate
}
for (let i = 0; i < operations.length; i++) {
let operation = operations[i];
self.processOperation(operation);
let operation = operations[i]
self.processOperation(operation)
}
}
@ -237,10 +247,10 @@ class WireFormatGenerator {
* @param {object} operation - The operation object.
*/
processOperation(operation: any) {
let self = this;
self.processXmsExamples(operation);
//self.processExample(operation);
return;
let self = this
self.processXmsExamples(operation)
//self.processExample(operation)
return
}
/*
@ -249,28 +259,33 @@ class WireFormatGenerator {
* @param {object} operation - The operation object.
*/
processXmsExamples(operation: any) {
let self = this;
let self = this
if (operation === null || operation === undefined || typeof operation !== 'object') {
throw new Error('operation cannot be null or undefined and must be of type \'object\'.');
throw new Error('operation cannot be null or undefined and must be of type \'object\'.')
}
let xmsExamples = operation[Constants.xmsExamples];
let xmsExamples = operation[Constants.xmsExamples]
if (xmsExamples) {
for (let scenario of utils.getKeys(xmsExamples)) {
//If we do not see the value property then we assume that the swagger spec had x-ms-examples references resolved.
//Then we do not need to access the value property. At the same time the file name for wire-format will be the sanitized scenario name.
let xmsExample = xmsExamples[scenario].value || xmsExamples[scenario];
let sampleRequest = self.processRequest(operation, xmsExample.parameters);
let sampleResponses = self.processXmsExampleResponses(operation, xmsExample.responses);
let exampleFileName = xmsExamples[scenario].filePath ? path.basename(xmsExamples[scenario].filePath) : `${utils.sanitizeFileName(scenario)}.json`;
let wireformatFileName = `${exampleFileName.substring(0, exampleFileName.indexOf(path.extname(exampleFileName)))}.`;
wireformatFileName += self.emitYaml ? 'yml' : 'md';
let fileName = path.join(self.wireFormatDir, wireformatFileName);
let httpTempl = self.emitYaml ? new YamlHttpTemplate(sampleRequest, sampleResponses) : new MarkdownHttpTemplate(sampleRequest, sampleResponses);
let sampleData = httpTempl.populate();
fs.writeFileSync(fileName, sampleData, { encoding: 'utf8' });
let xmsExample = xmsExamples[scenario].value || xmsExamples[scenario]
let sampleRequest = self.processRequest(operation, xmsExample.parameters)
let sampleResponses = self.processXmsExampleResponses(operation, xmsExample.responses)
let exampleFileName = xmsExamples[scenario].filePath
? path.basename(xmsExamples[scenario].filePath)
: `${utils.sanitizeFileName(scenario)}.json`
let wireformatFileName =
`${exampleFileName.substring(0, exampleFileName.indexOf(path.extname(exampleFileName)))}.`
wireformatFileName += self.emitYaml ? 'yml' : 'md'
let fileName = path.join(self.wireFormatDir, wireformatFileName)
let httpTempl = self.emitYaml
? new YamlHttpTemplate(sampleRequest, sampleResponses)
: new MarkdownHttpTemplate(sampleRequest, sampleResponses)
let sampleData = httpTempl.populate()
fs.writeFileSync(fileName, sampleData, { encoding: 'utf8' })
}
}
return;
return
}
/*
@ -283,65 +298,69 @@ class WireFormatGenerator {
* @return {object} result - The validation result.
*/
processRequest(operation: any, exampleParameterValues: any) {
let self = this;
let self = this
if (operation === null || operation === undefined || typeof operation !== 'object') {
throw new Error('operation cannot be null or undefined and must be of type \'object\'.');
throw new Error('operation cannot be null or undefined and must be of type \'object\'.')
}
if (exampleParameterValues === null || exampleParameterValues === undefined || typeof exampleParameterValues !== 'object') {
throw new Error(`In operation "${operation.operationId}", exampleParameterValues cannot be null or undefined and ` +
`must be of type "object" (A dictionary of key-value pairs of parameter-names and their values).`);
if (exampleParameterValues === null
|| exampleParameterValues === undefined
|| typeof exampleParameterValues !== 'object') {
throw new Error(
`In operation "${operation.operationId}", exampleParameterValues cannot be null or undefined and ` +
`must be of type "object" (A dictionary of key-value pairs of parameter-names and their values).`)
}
let parameters = operation.getParameters();
let options: any = {};
let parameters = operation.getParameters()
let options: any = {}
options.method = operation.method;
let pathTemplate = operation.pathObject.path;
options.method = operation.method
let pathTemplate = operation.pathObject.path
if (pathTemplate && pathTemplate.includes("?")) {
pathTemplate = pathTemplate.slice(0, pathTemplate.indexOf("?"));
operation.pathObject.path = pathTemplate;
pathTemplate = pathTemplate.slice(0, pathTemplate.indexOf("?"))
operation.pathObject.path = pathTemplate
}
options.pathTemplate = pathTemplate;
options.pathTemplate = pathTemplate
for (let i = 0; i < parameters.length; i++) {
let parameter = parameters[i];
let location = parameter.in;
let parameter = parameters[i]
let location = parameter.in
if (location === 'path' || location === 'query') {
let paramType = location + 'Parameters';
if (!options[paramType]) options[paramType] = {};
if (parameter[Constants.xmsSkipUrlEncoding] || utils.isUrlEncoded(exampleParameterValues[parameter.name])) {
let paramType = location + 'Parameters'
if (!options[paramType]) options[paramType] = {}
if (parameter[Constants.xmsSkipUrlEncoding]
|| utils.isUrlEncoded(exampleParameterValues[parameter.name])) {
options[paramType][parameter.name] = {
value: exampleParameterValues[parameter.name],
skipUrlEncoding: true
};
}
} else {
options[paramType][parameter.name] = exampleParameterValues[parameter.name];
options[paramType][parameter.name] = exampleParameterValues[parameter.name]
}
} else if (location === 'body') {
options.body = exampleParameterValues[parameter.name];
options.disableJsonStringifyOnBody = true;
options.body = exampleParameterValues[parameter.name]
options.disableJsonStringifyOnBody = true
} else if (location === 'header') {
if (!options.headers) options.headers = {};
options.headers[parameter.name] = exampleParameterValues[parameter.name];
if (!options.headers) options.headers = {}
options.headers[parameter.name] = exampleParameterValues[parameter.name]
}
}
if (options.headers) {
if (options.headers['content-type']) {
let val = delete options.headers['content-type'];
options.headers['Content-Type'] = val;
let val = delete options.headers['content-type']
options.headers['Content-Type'] = val
}
if (!options.headers['Content-Type']) {
options.headers['Content-Type'] = utils.getJsonContentType(operation.consumes);
options.headers['Content-Type'] = utils.getJsonContentType(operation.consumes)
}
} else {
options.headers = {};
options.headers['Content-Type'] = utils.getJsonContentType(operation.consumes);
options.headers = {}
options.headers['Content-Type'] = utils.getJsonContentType(operation.consumes)
}
let request = null;
request = new HttpRequest();
request = request.prepare(options);
return request;
let request = null
request = new HttpRequest()
request = request.prepare(options)
return request
}
/*
@ -354,47 +373,53 @@ class WireFormatGenerator {
* @return {object} result - The validation result.
*/
processXmsExampleResponses(operation: any, exampleResponseValue: any) {
let self = this;
let result: any = {};
let self = this
let result: any = {}
if (operation === null || operation === undefined || typeof operation !== 'object') {
throw new Error('operation cannot be null or undefined and must be of type \'object\'.');
throw new Error('operation cannot be null or undefined and must be of type \'object\'.')
}
if (exampleResponseValue === null || exampleResponseValue === undefined || typeof exampleResponseValue !== 'object') {
throw new Error('operation cannot be null or undefined and must be of type \'object\'.');
if (exampleResponseValue === null
|| exampleResponseValue === undefined
|| typeof exampleResponseValue !== 'object') {
throw new Error('operation cannot be null or undefined and must be of type \'object\'.')
}
let responsesInSwagger: any = {};
let responsesInSwagger: any = {}
let responses = operation.getResponses().map(function (response: any) {
responsesInSwagger[response.statusCode] = response.statusCode;
return response.statusCode;
});
responsesInSwagger[response.statusCode] = response.statusCode
return response.statusCode
})
if (operation['x-ms-long-running-operation']) {
result.longrunning = { initialResponse: undefined, finalResponse: undefined };
result.longrunning = { initialResponse: undefined, finalResponse: undefined }
} else {
result.standard = { finalResponse: undefined };
result.standard = { finalResponse: undefined }
}
for (let exampleResponseStatusCode of utils.getKeys(exampleResponseValue)) {
let response = operation.getResponse(exampleResponseStatusCode);
let response = operation.getResponse(exampleResponseStatusCode)
if (response) {
let exampleResponseHeaders = exampleResponseValue[exampleResponseStatusCode]['headers'] || {};
let exampleResponseBody = exampleResponseValue[exampleResponseStatusCode]['body'];
let exampleResponseHeaders = exampleResponseValue[exampleResponseStatusCode]['headers'] || {}
let exampleResponseBody = exampleResponseValue[exampleResponseStatusCode]['body']
//ensure content-type header is present
if (!(exampleResponseHeaders['content-type'] || exampleResponseHeaders['Content-Type'])) {
exampleResponseHeaders['content-type'] = utils.getJsonContentType(operation.produces);
exampleResponseHeaders['content-type'] = utils.getJsonContentType(operation.produces)
}
let exampleResponse = new ResponseWrapper(exampleResponseStatusCode, exampleResponseBody, exampleResponseHeaders);
let exampleResponse = new ResponseWrapper(
exampleResponseStatusCode, exampleResponseBody, exampleResponseHeaders)
if (operation['x-ms-long-running-operation']) {
if (exampleResponseStatusCode === '202' || exampleResponseStatusCode === '201') result.longrunning.initialResponse = exampleResponse;
if ((exampleResponseStatusCode === '200' || exampleResponseStatusCode === '204') && !result.longrunning.finalResponse) result.longrunning.finalResponse = exampleResponse;
if (exampleResponseStatusCode === '202' || exampleResponseStatusCode === '201')
result.longrunning.initialResponse = exampleResponse
if ((exampleResponseStatusCode === '200' || exampleResponseStatusCode === '204')
&& !result.longrunning.finalResponse)
result.longrunning.finalResponse = exampleResponse
} else {
if (!result.standard.finalResponse) result.standard.finalResponse = exampleResponse;
if (!result.standard.finalResponse) result.standard.finalResponse = exampleResponse
}
}
}
return result;
return result
}
}
module.exports = WireFormatGenerator;
export = WireFormatGenerator

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

@ -1,14 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
'use strict';
var util = require('util'),
fs = require('fs'),
pathlib = require('path'),
recursive = require('recursive-readdir'),
utils = require('./util/utils'),
log = require('./util/logging');
import util = require('util')
import fs = require('fs')
import pathlib = require('path')
import recursive = require('recursive-readdir')
import utils = require('./util/utils')
import log = require('./util/logging')
/**
* @class
@ -33,229 +31,243 @@ class xMsExampleExtractor {
* @param {object} [options.output] Output folder for the generated examples.
*/
constructor(specPath: string, recordings: any, options: any) {
if (specPath === null || specPath === undefined || typeof specPath.valueOf() !== 'string' || !specPath.trim().length) {
throw new Error('specPath is a required property of type string and it cannot be an empty string.');
if (specPath === null
|| specPath === undefined
|| typeof specPath.valueOf() !== 'string'
|| !specPath.trim().length) {
throw new Error('specPath is a required property of type string and it cannot be an empty string.')
}
if (recordings === null || recordings === undefined || typeof recordings.valueOf() !== 'string' || !recordings.trim().length) {
throw new Error('recordings is a required property of type string and it cannot be an empty string.');
if (recordings === null
|| recordings === undefined
|| typeof recordings.valueOf() !== 'string'
|| !recordings.trim().length) {
throw new Error('recordings is a required property of type string and it cannot be an empty string.')
}
this.specPath = specPath;
this.recordings = recordings;
this.specDir = pathlib.dirname(this.specPath);
if (!options) options = {};
this.specPath = specPath
this.recordings = recordings
this.specDir = pathlib.dirname(this.specPath)
if (!options) options = {}
if (options.output === null || options.output === undefined) {
options.output = process.cwd() + '/output';
options.output = process.cwd() + '/output'
}
if (options.shouldResolveXmsExamples === null || options.shouldResolveXmsExamples === undefined) {
options.shouldResolveXmsExamples = true;
options.shouldResolveXmsExamples = true
}
if (options.matchApiVersion === null || options.matchApiVersion === undefined) {
options.matchApiVersion = false;
options.matchApiVersion = false
}
this.options = options;
log.debug(`specPath : ${this.specPath}`);
log.debug(`recordings : ${this.recordings}`);
log.debug(`options.output : ${this.options.output}`);
log.debug(`options.matchApiVersion : ${this.options.matchApiVersion}`);
this.options = options
log.debug(`specPath : ${this.specPath}`)
log.debug(`recordings : ${this.recordings}`)
log.debug(`options.output : ${this.options.output}`)
log.debug(`options.matchApiVersion : ${this.options.matchApiVersion}`)
}
/**
* Extracts x-ms-examples from the recordings
*/
extract() {
let self = this;
self.mkdirSync(self.options.output);
self.mkdirSync(self.options.output + "/examples");
self.mkdirSync(self.options.output + "/swagger");
let self = this
self.mkdirSync(self.options.output)
self.mkdirSync(self.options.output + "/examples")
self.mkdirSync(self.options.output + "/swagger")
let outputExamples = self.options.output + "/examples/";
let relativeExamplesPath = "../examples/";
let specName = self.specPath.split("/");
let outputSwagger = self.options.output + "/swagger/" + specName[specName.length - 1].split(".")[0] + ".json";
let outputExamples = self.options.output + "/examples/"
let relativeExamplesPath = "../examples/"
let specName = self.specPath.split("/")
let outputSwagger =
self.options.output + "/swagger/" + specName[specName.length - 1].split(".")[0] + ".json"
var swaggerObject = require(self.specPath);
var SwaggerParser = require('swagger-parser');
var parser = new SwaggerParser();
var swaggerObject = require(self.specPath)
var SwaggerParser = require('swagger-parser')
var parser = new SwaggerParser()
var accErrors: any = {};
var filesArray: any = [];
self.getFileList(self.recordings, filesArray);
var accErrors: any = {}
var filesArray: any = []
self.getFileList(self.recordings, filesArray)
let recordingFiles = filesArray;
var example = {};
let recordingFiles = filesArray
var example = {}
parser.parse(swaggerObject).then(function (api: any) {
for (let recordingFileName of utils.getValues(recordingFiles)) {
log.debug(`Processing recording file: ${recordingFileName}`);
log.debug(`Processing recording file: ${recordingFileName}`)
try {
let recording = JSON.parse(fs.readFileSync(recordingFileName));
let paths = api.paths;
let pathIndex = 0;
var pathParams: any = {};
let recording = JSON.parse(fs.readFileSync(recordingFileName).toString())
let paths = api.paths
let pathIndex = 0
var pathParams: any = {}
for (let path of utils.getKeys(paths)) {
pathIndex++;
let searchResult = path.match(/\/{\w*\}/g);
let pathParts = path.split('/');
let pathToMatch = path;
pathParams = {};
pathIndex++
let searchResult = path.match(/\/{\w*\}/g)
let pathParts = path.split('/')
let pathToMatch = path
pathParams = {}
for (let match of utils.getValues(searchResult)) {
let splitRegEx = /[{}]/;
let pathParam = match.split(splitRegEx)[1];
let splitRegEx = /[{}]/
let pathParam = match.split(splitRegEx)[1]
for (let part of utils.getKeys(pathParts)) {
let pathPart = "/" + pathParts[part];
let pathPart = "/" + pathParts[part as any]
if (pathPart.localeCompare(match) === 0) {
pathParams[pathParam] = part;
pathParams[pathParam] = part
}
}
pathToMatch = pathToMatch.replace(match, "/[^\/]+");
pathToMatch = pathToMatch.replace(match, "/[^\/]+")
}
let newPathToMatch = pathToMatch.replace(/\//g, "\\/");
newPathToMatch = newPathToMatch + "$";
let newPathToMatch = pathToMatch.replace(/\//g, "\\/")
newPathToMatch = newPathToMatch + "$"
//for this API path (and method), try to find it in the recording file, and get the data
var entries = recording.Entries;
let entryIndex = 0;
let queryParams: any = {};
var entries = recording.Entries
let entryIndex = 0
let queryParams: any = {}
for (let entry of utils.getKeys(entries)) {
entryIndex++;
let recordingPath = JSON.stringify(entries[entry]["RequestUri"]);
let recordingPathQueryParams = recordingPath.split('?')[1].slice(0, -1);
let queryParamsArray = recordingPathQueryParams.split('&');
entryIndex++
let recordingPath = JSON.stringify(entries[entry]["RequestUri"])
let recordingPathQueryParams = recordingPath.split('?')[1].slice(0, -1)
let queryParamsArray = recordingPathQueryParams.split('&')
for (let part of utils.getKeys(queryParamsArray)) {
let queryParam = queryParamsArray[part].split('=');
queryParams[queryParam[0]] = queryParam[1];
let queryParam = queryParamsArray[part as any].split('=')
queryParams[queryParam[0]] = queryParam[1]
}
let headerParams = entries[entry]["RequestHeaders"];
let headerParams = entries[entry]["RequestHeaders"]
// if commandline included check for API version, validate api-version from URI in recordings matches the api-version of the spec
if (!self.options.matchApiVersion || (("api-version" in queryParams) && queryParams["api-version"] == api.info.version)) {
recordingPath = recordingPath.replace(/\?.*/, '');
let recordingPathParts = recordingPath.split('/');
let match = recordingPath.match(newPathToMatch);
if (!self.options.matchApiVersion
|| (("api-version" in queryParams) && queryParams["api-version"] == api.info.version)) {
recordingPath = recordingPath.replace(/\?.*/, '')
let recordingPathParts = recordingPath.split('/')
let match = recordingPath.match(newPathToMatch)
if (match !== null) {
log.silly("path: " + path);
log.silly("recording path: " + recordingPath);
log.silly("path: " + path)
log.silly("recording path: " + recordingPath)
var pathParamsValues: any = {};
var pathParamsValues: any = {}
for (let p of utils.getKeys(pathParams)) {
let index = pathParams[p];
pathParamsValues[p] = recordingPathParts[index];
let index = pathParams[p]
pathParamsValues[p] = recordingPathParts[index]
}
//found a match in the recording
let requestMethodFromRecording = entries[entry]["RequestMethod"];
let infoFromOperation = paths[path][requestMethodFromRecording.toLowerCase()];
let requestMethodFromRecording = entries[entry]["RequestMethod"]
let infoFromOperation = paths[path][requestMethodFromRecording.toLowerCase()]
if (typeof infoFromOperation != 'undefined') {
//need to consider each method in operation
let fileName = recordingFileName.split('/');
fileName = fileName[fileName.length - 1];
fileName = fileName.split(".json")[0];
fileName = fileName.replace(/\//g, "-");
let exampleFileName = fileName + "-" + requestMethodFromRecording + "-example-" + pathIndex + entryIndex + ".json";
let ref: any = {};
ref["$ref"] = relativeExamplesPath + exampleFileName;
let exampleFriendlyName = fileName + requestMethodFromRecording + pathIndex + entryIndex;
log.debug(`exampleFriendlyName: ${exampleFriendlyName}`);
let fileName = recordingFileName.split('/')
fileName = fileName[fileName.length - 1]
fileName = fileName.split(".json")[0]
fileName = fileName.replace(/\//g, "-")
let exampleFileName = fileName
+ "-"
+ requestMethodFromRecording
+ "-example-"
+ pathIndex
+ entryIndex
+ ".json"
let ref: any = {}
ref["$ref"] = relativeExamplesPath + exampleFileName
let exampleFriendlyName = fileName + requestMethodFromRecording + pathIndex + entryIndex
log.debug(`exampleFriendlyName: ${exampleFriendlyName}`)
if (!("x-ms-examples" in infoFromOperation)) {
infoFromOperation["x-ms-examples"] = {};
infoFromOperation["x-ms-examples"] = {}
}
infoFromOperation["x-ms-examples"][exampleFriendlyName] = ref;
let example: any = {};
example["parameters"] = {};
example["responses"] = {};
let params = infoFromOperation["parameters"];
infoFromOperation["x-ms-examples"][exampleFriendlyName] = ref
let example: any = {}
example["parameters"] = {}
example["responses"] = {}
let params = infoFromOperation["parameters"]
for (let param of utils.getKeys(pathParamsValues)) {
example['parameters'][param] = pathParamsValues[param];
example['parameters'][param] = pathParamsValues[param]
}
for (let param of utils.getKeys(queryParams)) {
example['parameters'][param] = queryParams[param];
example['parameters'][param] = queryParams[param]
}
for (let param of utils.getKeys(headerParams)) {
example['parameters'][param] = headerParams[param];
example['parameters'][param] = headerParams[param]
}
for (let param of utils.getKeys(infoFromOperation["parameters"])) {
if (params[param]["in"] == "body") {
let bodyParamName = params[param]["name"];
let bodyParamValue = entries[entry]["RequestBody"];
let bodyParamExample: any = {};
bodyParamExample[bodyParamName] = bodyParamValue;
let bodyParamName = params[param]["name"]
let bodyParamValue = entries[entry]["RequestBody"]
let bodyParamExample: any = {}
bodyParamExample[bodyParamName] = bodyParamValue
if (bodyParamValue !== "") {
example['parameters'][bodyParamName] = JSON.parse(bodyParamValue);
example['parameters'][bodyParamName] = JSON.parse(bodyParamValue)
}
else {
example['parameters'][bodyParamName] = "";
example['parameters'][bodyParamName] = ""
}
}
}
let responses = infoFromOperation["responses"];
let responses = infoFromOperation["responses"]
for (var response of utils.getKeys(responses)) {
let statusCodeFromRecording = entries[entry]["StatusCode"];
let responseBody = entries[entry]["ResponseBody"];
example['responses'][statusCodeFromRecording] = {};
let statusCodeFromRecording = entries[entry]["StatusCode"]
let responseBody = entries[entry]["ResponseBody"]
example['responses'][statusCodeFromRecording] = {}
if (responseBody !== "") {
example['responses'][statusCodeFromRecording]['body'] = JSON.parse(responseBody);
example['responses'][statusCodeFromRecording]['body'] = JSON.parse(responseBody)
}
else {
example['responses'][statusCodeFromRecording]['body'] = "";
example['responses'][statusCodeFromRecording]['body'] = ""
}
}
log.info(`Writing x-ms-examples at ${outputExamples + exampleFileName}`);
fs.writeFile(outputExamples + exampleFileName, JSON.stringify(example, null, 2));
log.info(`Writing x-ms-examples at ${outputExamples + exampleFileName}`)
fs.writeFileSync(outputExamples + exampleFileName, JSON.stringify(example, null, 2))
}
}
}
}
}
log.info(`Writing updated swagger with x-ms-examples at ${outputSwagger}`);
fs.writeFile(outputSwagger, JSON.stringify(swaggerObject, null, 2));
log.info(`Writing updated swagger with x-ms-examples at ${outputSwagger}`)
fs.writeFileSync(outputSwagger, JSON.stringify(swaggerObject, null, 2))
}
catch (err) {
accErrors[recordingFileName] = err.toString();
log.warn(`Error pricessing recording file: "${recordingFileName}"`);
log.warn(`Error: "${err.toString()} "`);
accErrors[recordingFileName] = err.toString()
log.warn(`Error pricessing recording file: "${recordingFileName}"`)
log.warn(`Error: "${err.toString()} "`)
}
}
if (JSON.stringify(accErrors) != "{}") {
log.error(`Errors loading/parsing recording files.`);
log.error(`${JSON.stringify(accErrors)}`);
log.error(`Errors loading/parsing recording files.`)
log.error(`${JSON.stringify(accErrors)}`)
}
}).catch(function (err: any) {
process.exitCode = 1;
log.error(err);
});
process.exitCode = 1
log.error(err)
})
}
mkdirSync(path: any) {
try {
fs.mkdirSync(path);
fs.mkdirSync(path)
} catch (e) {
if (e.code != 'EEXIST') throw e;
if (e.code != 'EEXIST') throw e
}
}
getFileList(dir: any, filelist: any) {
let self = this;
var files = fs.readdirSync(dir);
filelist = filelist || [];
let self = this
var files = fs.readdirSync(dir)
filelist = filelist || []
files.forEach(function (file: any) {
if (fs.statSync(pathlib.join(dir, file)).isDirectory()) {
filelist = self.getFileList(pathlib.join(dir, file), filelist);
filelist = self.getFileList(pathlib.join(dir, file), filelist)
}
else {
filelist.push(pathlib.join(dir, file));
filelist.push(pathlib.join(dir, file))
}
});
return filelist;
return filelist
}
}
module.exports = xMsExampleExtractor;
export = xMsExampleExtractor

4
lib/yuml2svc.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,4 @@
declare function defaultYuml2Svg(_0: any, _1: any, _2: any) : any
declare module "yuml2svg" {
export = defaultYuml2Svg
}

99
package-lock.json сгенерированный
Просмотреть файл

@ -1,6 +1,6 @@
{
"name": "oav",
"version": "0.4.38",
"version": "0.4.39",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -17,6 +17,12 @@
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.1.tgz",
"integrity": "sha512-FhlMa34NHp9K5MY1Uz8yb+ZvuX0pnvn3jScRSNAb75KHGB8d3rEU6hqMs3Z2vjuytcMfRg6c5CHMc3wtYyD2/A=="
},
"@types/events": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz",
"integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==",
"dev": true
},
"@types/form-data": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.1.tgz",
@ -25,6 +31,47 @@
"@types/node": "8.10.15"
}
},
"@types/glob": {
"version": "5.0.35",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.35.tgz",
"integrity": "sha512-wc+VveszMLyMWFvXLkloixT4n0harUIVZjnpzztaZ0nKLuul7Z32iMt2fUFGAaZ4y1XWjFRMtCI5ewvyh4aIeg==",
"dev": true,
"requires": {
"@types/events": "1.2.0",
"@types/minimatch": "3.0.3",
"@types/node": "8.10.15"
}
},
"@types/js-yaml": {
"version": "3.11.1",
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-3.11.1.tgz",
"integrity": "sha512-M5qhhfuTt4fwHGqqANNQilp3Htb5cHwBxlMHDUw/TYRVkEp3s3IIFSH3Fe9HIAeEtnO4p3SSowLmCVavdRYfpw==",
"dev": true
},
"@types/json-pointer": {
"version": "1.0.30",
"resolved": "https://registry.npmjs.org/@types/json-pointer/-/json-pointer-1.0.30.tgz",
"integrity": "sha1-uXPB95sfYdQkt9krlU4B5saO5m0=",
"dev": true
},
"@types/jsonpath": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@types/jsonpath/-/jsonpath-0.2.0.tgz",
"integrity": "sha512-v7qlPA0VpKUlEdhghbDqRoKMxFB3h3Ch688TApBJ6v+XLDdvWCGLJIYiPKGZnS6MAOie+IorCfNYVHOPIHSWwQ==",
"dev": true
},
"@types/lodash": {
"version": "4.14.109",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.109.tgz",
"integrity": "sha512-hop8SdPUEzbcJm6aTsmuwjIYQo1tqLseKCM+s2bBqTU2gErwI4fE+aqUVOlscPSQbKHKgtMMPoC+h4AIGOJYvw==",
"dev": true
},
"@types/minimatch": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
"integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
"dev": true
},
"@types/mocha": {
"version": "2.2.48",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-2.2.48.tgz",
@ -36,6 +83,15 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.15.tgz",
"integrity": "sha512-qNb+m5Cuj6YUMK7YFcvuSgcHCKfVg1uXAUOP91SWvAakZlZTzbGmJaBi99CgDWEAyfZo51NlUhXkuP5WtXsgjg=="
},
"@types/recursive-readdir": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@types/recursive-readdir/-/recursive-readdir-2.2.0.tgz",
"integrity": "sha512-HGk753KRu2N4mWduovY4BLjYq4jTOL29gV2OfGdGxHcPSWGFkC5RRIdk+VTs5XmYd7MVAD+JwKrcb5+5Y7FOCg==",
"dev": true,
"requires": {
"@types/node": "8.10.15"
}
},
"@types/request": {
"version": "2.47.0",
"resolved": "https://registry.npmjs.org/@types/request/-/request-2.47.0.tgz",
@ -66,6 +122,21 @@
"@types/node": "8.10.15"
}
},
"@types/winston": {
"version": "2.3.9",
"resolved": "https://registry.npmjs.org/@types/winston/-/winston-2.3.9.tgz",
"integrity": "sha512-zzruYOEtNgfS3SBjcij1F6HlH6My5n8WrBNhP3fzaRM22ba70QBC2ATs18jGr88Fy43c0z8vFJv5wJankfxv2A==",
"dev": true,
"requires": {
"@types/node": "8.10.15"
}
},
"@types/yargs": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-11.0.0.tgz",
"integrity": "sha512-vFql3tOxs6clgh+WVoLW3nOkNGCdeKsMU6mQZkOerJpV/CR9Xc1c1lZ+kYU+hNSobrQIOcNovWfPFDJIhcG5Pw==",
"dev": true
},
"JSONSelect": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/JSONSelect/-/JSONSelect-0.4.0.tgz",
@ -551,7 +622,7 @@
"requires": {
"lru-cache": "4.1.3",
"shebang-command": "1.2.0",
"which": "1.3.0"
"which": "1.3.1"
}
},
"cryptiles": {
@ -855,11 +926,6 @@
"requires": {
"ansi-regex": "3.0.0"
}
},
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
}
}
},
@ -1445,9 +1511,9 @@
}
},
"js-base64": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.3.tgz",
"integrity": "sha512-H7ErYLM34CvDMto3GbD6xD0JLUGYXR3QTcH6B/tr4Hi/QpSThnCsIp+Sy5FRTw3B0d6py4HcNkW7nO/wdtGWEw=="
"version": "2.4.5",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.5.tgz",
"integrity": "sha512-aUnNwqMOXw3yvErjMPSQu6qIIzUmT1e5KcU1OZxRDU1g/am6mzBvcrmLAYwzmB59BHPrh5/tKaiF4OPhqRWESQ=="
},
"js-tokens": {
"version": "3.0.2",
@ -2803,6 +2869,11 @@
"is-utf8": "0.2.1"
}
},
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
},
"superagent": {
"version": "3.8.2",
"resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.2.tgz",
@ -2892,7 +2963,7 @@
"requires": {
"debug": "3.1.0",
"faker": "4.1.0",
"js-base64": "2.4.3",
"js-base64": "2.4.5",
"js-yaml": "3.11.0",
"json-refs": "3.0.4",
"json-schema-faker": "0.5.0-rc9",
@ -3131,9 +3202,9 @@
"integrity": "sha512-+Eb+Dxf2kC2h079msx61hkblxAKE0S2j78+8QpnigLAO2aIIjkCwTIH34etBrU8E8VItRinec7YEwULx9at5bQ=="
},
"which": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
"integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==",
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"requires": {
"isexe": "2.0.0"
}

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

@ -32,8 +32,16 @@
"yuml2svg": "^3.1.0"
},
"devDependencies": {
"@types/glob": "^5.0.35",
"@types/js-yaml": "^3.11.1",
"@types/json-pointer": "^1.0.30",
"@types/jsonpath": "^0.2.0",
"@types/lodash": "^4.14.109",
"@types/mocha": "^2.2.46",
"@types/recursive-readdir": "^2.2.0",
"@types/should": "^8.1.30",
"@types/winston": "^2.3.9",
"@types/yargs": "^11.0.0",
"mocha": "^4.1.0",
"should": "5.2.0",
"typescript": "^2.8.3"
@ -50,7 +58,10 @@
"bin": {
"oav": "./cli.js"
},
"files": [ "**/*.js", "**/*.d.ts" ],
"files": [
"**/*.js",
"**/*.d.ts"
],
"scripts": {
"tsc": "tsc",
"test": "tsc && mocha -t 100000 --reporter min",

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

@ -2,15 +2,14 @@
// Licensed under the MIT License. See License.txt in the project root for license information.
import assert = require('assert')
var
path = require('path'),
os = require('os'),
glob = require('glob'),
LiveValidator = require('../lib/validators/liveValidator.js'),
Constants = require('../lib/util/constants'),
utils = require('../lib/util/utils');
import path = require('path')
import os = require('os')
import glob = require('glob')
import LiveValidator = require('../lib/validators/liveValidator.js')
import Constants = require('../lib/util/constants')
import utils = require('../lib/util/utils');
const livePaths = glob.sync(path.join(__dirname, 'liveValidation/swaggers/**/live/*.json'));
const livePaths = glob.sync(path.join(__dirname, 'liveValidation/swaggers/**/live/*.json'))
describe('Live Validator', function () {
describe('Initialization', function () {
it('should initialize with defaults', function () {
@ -22,12 +21,12 @@ describe('Live Validator', function () {
},
"directory": path.resolve(os.homedir(), 'repo')
};
let validator = new LiveValidator();
assert.deepEqual(validator.cache, {});
assert.deepEqual(validator.options, options);
});
let validator = new LiveValidator()
assert.deepEqual(validator.cache, {})
assert.deepEqual(validator.options, options)
})
it('should initialize with user provided swaggerPaths', function () {
let swaggerPaths = ["swaggerPath1", "swaggerPath2"];
let swaggerPaths = ["swaggerPath1", "swaggerPath2"]
let options = {
"swaggerPaths": swaggerPaths,
"git": {
@ -35,13 +34,13 @@ describe('Live Validator', function () {
"shouldClone": false
},
"directory": path.resolve(os.homedir(), 'repo')
};
let validator = new LiveValidator({ "swaggerPaths": swaggerPaths });
assert.deepEqual(validator.cache, {});
assert.deepEqual(validator.options, options);
});
}
let validator = new LiveValidator({ "swaggerPaths": swaggerPaths })
assert.deepEqual(validator.cache, {})
assert.deepEqual(validator.options, options)
})
it('should initialize with user provided swaggerPaths & directory', function () {
let swaggerPaths = ["swaggerPath1", "swaggerPath2"];
let swaggerPaths = ["swaggerPath1", "swaggerPath2"]
let directory = "/Users/username/repos/"
let options = {
"swaggerPaths": swaggerPaths,
@ -50,13 +49,13 @@ describe('Live Validator', function () {
"shouldClone": false
},
"directory": directory
};
let validator = new LiveValidator({ "swaggerPaths": swaggerPaths, "directory": directory });
assert.deepEqual(validator.cache, {});
assert.deepEqual(validator.options, options);
});
}
let validator = new LiveValidator({ "swaggerPaths": swaggerPaths, "directory": directory })
assert.deepEqual(validator.cache, {})
assert.deepEqual(validator.options, options)
})
it('should initialize with user provided partial git configuration', function () {
let swaggerPaths = ["swaggerPath1", "swaggerPath2"];
let swaggerPaths = ["swaggerPath1", "swaggerPath2"]
let directory = "/Users/username/repos/"
let git = {
"url": "https://github.com/Azure/azure-rest-api-specs.git"
@ -68,13 +67,14 @@ describe('Live Validator', function () {
"shouldClone": false
},
"directory": directory
};
let validator = new LiveValidator({ "swaggerPaths": swaggerPaths, "directory": directory, "git": git });
assert.deepEqual(validator.cache, {});
assert.deepEqual(validator.options, options);
});
}
let validator = new LiveValidator({
"swaggerPaths": swaggerPaths, "directory": directory, "git": git })
assert.deepEqual(validator.cache, {})
assert.deepEqual(validator.options, options)
})
it('should initialize with user provided full git configuration', function () {
let swaggerPaths = ["swaggerPath1", "swaggerPath2"];
let swaggerPaths = ["swaggerPath1", "swaggerPath2"]
let directory = "/Users/username/repos/"
let git = {
"url": "https://github.com/vladbarosan/azure-rest-api-specs.git",
@ -85,207 +85,229 @@ describe('Live Validator', function () {
"swaggerPaths": swaggerPaths,
"git": git,
"directory": directory
};
let validator = new LiveValidator({ "swaggerPaths": swaggerPaths, "directory": directory, "git": git });
assert.deepEqual(validator.cache, {});
assert.deepEqual(validator.options, options);
});
}
let validator = new LiveValidator({
"swaggerPaths": swaggerPaths, "directory": directory, "git": git })
assert.deepEqual(validator.cache, {})
assert.deepEqual(validator.options, options)
})
it('should throw on invalid options types', function () {
assert.throws(() => {
new LiveValidator('string');
}, /must be of type "object"/);
new LiveValidator('string')
}, /must be of type "object"/)
assert.throws(() => {
new LiveValidator({ "swaggerPaths": "should be array" });
}, /must be of type "array"/);
new LiveValidator({ "swaggerPaths": "should be array" })
}, /must be of type "array"/)
assert.throws(() => {
new LiveValidator({ "git": 1 });
}, /must be of type "object"/);
new LiveValidator({ "git": 1 })
}, /must be of type "object"/)
assert.throws(() => {
new LiveValidator({ "git": { "url": [] } });
}, /must be of type "string"/);
new LiveValidator({ "git": { "url": [] } })
}, /must be of type "string"/)
assert.throws(() => {
new LiveValidator({ "git": { "url": "url", "shouldClone": "no" } });
}, /must be of type "boolean"/);
});
});
new LiveValidator({ "git": { "url": "url", "shouldClone": "no" } })
}, /must be of type "boolean"/)
})
})
describe('Initialize cache', function () {
it('should initialize for arm-mediaservices', function (done) {
let expectedProvider = 'microsoft.media';
let expectedApiVersion = '2015-10-01';
let expectedProvider = 'microsoft.media'
let expectedApiVersion = '2015-10-01'
let options = {
"directory": "./test/liveValidation/swaggers/"
};
let validator = new LiveValidator(options);
}
let validator = new LiveValidator(options)
validator.initialize().then(function () {
assert.equal(true, expectedProvider in validator.cache);
assert.equal(6, Object.keys(validator.cache).length);
assert.equal(true, expectedApiVersion in (validator.cache[expectedProvider]));
assert.equal(1, Object.keys(validator.cache[expectedProvider]).length);
assert.equal(2, validator.cache[expectedProvider][expectedApiVersion]['get'].length);
assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['put'].length);
assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['patch'].length);
assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['delete'].length);
assert.equal(4, validator.cache[expectedProvider][expectedApiVersion]['post'].length);
done();
assert.equal(true, expectedProvider in validator.cache)
assert.equal(6, Object.keys(validator.cache).length)
assert.equal(true, expectedApiVersion in (validator.cache[expectedProvider]))
assert.equal(1, Object.keys(validator.cache[expectedProvider]).length)
assert.equal(2, validator.cache[expectedProvider][expectedApiVersion]['get'].length)
assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['put'].length)
assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['patch'].length)
assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['delete'].length)
assert.equal(4, validator.cache[expectedProvider][expectedApiVersion]['post'].length)
done()
}).catch((err: any) => {
assert.ifError(err);
done();
}).catch(done);
});
assert.ifError(err)
done()
}).catch(done)
})
it('should initialize for arm-resources', function (done) {
let expectedProvider = 'microsoft.resources';
let expectedApiVersion = '2016-09-01';
let expectedProvider = 'microsoft.resources'
let expectedApiVersion = '2016-09-01'
let options = {
"directory": "./test/liveValidation/swaggers/"
};
let validator = new LiveValidator(options);
}
let validator = new LiveValidator(options)
validator.initialize().then(function () {
assert.equal(true, expectedProvider in validator.cache);
assert.equal(6, Object.keys(validator.cache).length);
assert.equal(true, expectedApiVersion in (validator.cache[expectedProvider]));
assert.equal(1, Object.keys(validator.cache[expectedProvider]).length);
assert.equal(true, expectedProvider in validator.cache)
assert.equal(6, Object.keys(validator.cache).length)
assert.equal(true, expectedApiVersion in (validator.cache[expectedProvider]))
assert.equal(1, Object.keys(validator.cache[expectedProvider]).length)
// 'microsoft.resources' -> '2016-09-01'
assert.equal(2, validator.cache[expectedProvider][expectedApiVersion]['get'].length);
assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['delete'].length);
assert.equal(3, validator.cache[expectedProvider][expectedApiVersion]['post'].length);
assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['head'].length);
assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['put'].length);
assert.equal(2, validator.cache[expectedProvider][expectedApiVersion]['get'].length)
assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['delete'].length)
assert.equal(3, validator.cache[expectedProvider][expectedApiVersion]['post'].length)
assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['head'].length)
assert.equal(1, validator.cache[expectedProvider][expectedApiVersion]['put'].length)
// 'microsoft.unknown' -> 'unknown-api-version'
assert.equal(4, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['post'].length);
assert.equal(11, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['get'].length);
assert.equal(3, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['head'].length);
assert.equal(5, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['put'].length);
assert.equal(5, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['delete'].length);
assert.equal(1, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['patch'].length);
done();
assert.equal(
4, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['post'].length)
assert.equal(
11, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['get'].length)
assert.equal(
3, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['head'].length)
assert.equal(
5, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['put'].length)
assert.equal(
5, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['delete'].length)
assert.equal(
1, validator.cache[Constants.unknownResourceProvider][Constants.unknownApiVersion]['patch'].length)
done()
}).catch((err: any) => {
assert.ifError(err);
done();
}).catch(done);
});
assert.ifError(err)
done()
}).catch(done)
})
it('should initialize for all swaggers', function (done) {
let options = {
"directory": "./test/liveValidation/swaggers/"
};
let validator = new LiveValidator(options);
}
let validator = new LiveValidator(options)
validator.initialize().then(function () {
assert.equal(6, Object.keys(validator.cache).length);
assert.equal(2, validator.cache['microsoft.resources']['2016-09-01']['get'].length);
assert.equal(1, validator.cache['microsoft.resources']['2016-09-01']['head'].length);
assert.equal(1, validator.cache['microsoft.media']['2015-10-01']['patch'].length);
assert.equal(4, validator.cache['microsoft.media']['2015-10-01']['post'].length);
assert.equal(2, validator.cache['microsoft.search']['2015-02-28']['get'].length);
assert.equal(3, validator.cache['microsoft.search']['2015-08-19']['get'].length);
assert.equal(1, validator.cache['microsoft.storage']['2015-05-01-preview']['patch'].length);
assert.equal(4, validator.cache['microsoft.storage']['2015-06-15']['get'].length);
assert.equal(3, validator.cache['microsoft.storage']['2016-01-01']['post'].length);
assert.equal(4, validator.cache['microsoft.test']['2016-01-01']['post'].length);
done();
assert.equal(6, Object.keys(validator.cache).length)
assert.equal(2, validator.cache['microsoft.resources']['2016-09-01']['get'].length)
assert.equal(1, validator.cache['microsoft.resources']['2016-09-01']['head'].length)
assert.equal(1, validator.cache['microsoft.media']['2015-10-01']['patch'].length)
assert.equal(4, validator.cache['microsoft.media']['2015-10-01']['post'].length)
assert.equal(2, validator.cache['microsoft.search']['2015-02-28']['get'].length)
assert.equal(3, validator.cache['microsoft.search']['2015-08-19']['get'].length)
assert.equal(1, validator.cache['microsoft.storage']['2015-05-01-preview']['patch'].length)
assert.equal(4, validator.cache['microsoft.storage']['2015-06-15']['get'].length)
assert.equal(3, validator.cache['microsoft.storage']['2016-01-01']['post'].length)
assert.equal(4, validator.cache['microsoft.test']['2016-01-01']['post'].length)
done()
}).catch((err: any) => {
assert.ifError(err);
done();
}).catch(done);
});
});
assert.ifError(err)
done()
}).catch(done)
})
})
describe('Initialize cache and search', function () {
it('should return one matched operation for arm-storage', function (done) {
let options = {
"directory": "./test/liveValidation/swaggers/"
};
let listRequestUrl = "https://management.azure.com/subscriptions/subscriptionId/providers/Microsoft.Storage/storageAccounts?api-version=2015-06-15";
let postRequestUrl = "https://management.azure.com/subscriptions/subscriptionId/providers/Microsoft.Storage/checkNameAvailability?api-version=2015-06-15";
let deleteRequestUrl = "https://management.azure.com/subscriptions/subscriptionId/resourceGroups/myRG/providers/Microsoft.Storage/storageAccounts/accname?api-version=2015-06-15";
let validator = new LiveValidator(options);
}
let listRequestUrl =
"https://management.azure.com/subscriptions/subscriptionId/providers/Microsoft.Storage/storageAccounts?api-version=2015-06-15"
let postRequestUrl =
"https://management.azure.com/subscriptions/subscriptionId/providers/Microsoft.Storage/checkNameAvailability?api-version=2015-06-15"
let deleteRequestUrl =
"https://management.azure.com/subscriptions/subscriptionId/resourceGroups/myRG/providers/Microsoft.Storage/storageAccounts/accname?api-version=2015-06-15"
let validator = new LiveValidator(options)
validator.initialize().then(function () {
// Operations to match is StorageAccounts_List
let operations = validator.getPotentialOperations(listRequestUrl, 'Get').operations;
assert.equal(1, operations.length);
assert.equal("/subscriptions/{subscriptionId}/providers/Microsoft.Storage/storageAccounts", operations[0].pathObject.path);
let operations = validator.getPotentialOperations(listRequestUrl, 'Get').operations
assert.equal(
1, operations.length)
assert.equal(
"/subscriptions/{subscriptionId}/providers/Microsoft.Storage/storageAccounts",
operations[0].pathObject.path)
// Operations to match is StorageAccounts_CheckNameAvailability
operations = validator.getPotentialOperations(postRequestUrl, 'PoSt').operations;
assert.equal(1, operations.length);
assert.equal("/subscriptions/{subscriptionId}/providers/Microsoft.Storage/checkNameAvailability", operations[0].pathObject.path);
operations = validator.getPotentialOperations(postRequestUrl, 'PoSt').operations
assert.equal(1, operations.length)
assert.equal(
"/subscriptions/{subscriptionId}/providers/Microsoft.Storage/checkNameAvailability",
operations[0].pathObject.path)
// Operations to match is StorageAccounts_Delete
operations = validator.getPotentialOperations(deleteRequestUrl, 'delete').operations;
assert.equal(1, operations.length);
assert.equal("/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{accountName}", operations[0].pathObject.path);
done();
operations = validator.getPotentialOperations(deleteRequestUrl, 'delete').operations
assert.equal(1, operations.length)
assert.equal(
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/{accountName}",
operations[0].pathObject.path)
done()
}).catch((err: any) => {
assert.ifError(err);
done();
}).catch(done);
});
assert.ifError(err)
done()
}).catch(done)
})
it('should return reason for not matched operations', function (done) {
let options = {
"directory": "./test/liveValidation/swaggers/"
};
let nonCachedApiUrl = "https://management.azure.com/subscriptions/subscriptionId/providers/Microsoft.Storage/storageAccounts?api-version=2015-08-15";
let nonCachedProviderUrl = "https://management.azure.com/subscriptions/subscriptionId/providers/Hello.World/checkNameAvailability?api-version=2015-06-15";
let nonCachedVerbUrl = "https://management.azure.com/subscriptions/subscriptionId/resourceGroups/myRG/providers/Microsoft.Storage/storageAccounts/accname?api-version=2015-06-15";
let nonCachedPath = "https://management.azure.com/subscriptions/subscriptionId/providers/Microsoft.Storage/storageAccounts/accountName/properties?api-version=2015-06-15";
let validator = new LiveValidator(options);
}
let nonCachedApiUrl =
"https://management.azure.com/subscriptions/subscriptionId/providers/Microsoft.Storage/storageAccounts?api-version=2015-08-15"
let nonCachedProviderUrl =
"https://management.azure.com/subscriptions/subscriptionId/providers/Hello.World/checkNameAvailability?api-version=2015-06-15"
let nonCachedVerbUrl =
"https://management.azure.com/subscriptions/subscriptionId/resourceGroups/myRG/providers/Microsoft.Storage/storageAccounts/accname?api-version=2015-06-15"
let nonCachedPath =
"https://management.azure.com/subscriptions/subscriptionId/providers/Microsoft.Storage/storageAccounts/accountName/properties?api-version=2015-06-15"
let validator = new LiveValidator(options)
validator.initialize().then(function () {
// Operations to match is StorageAccounts_List with api-version 2015-08-15 [non cached api version]
let result = validator.getPotentialOperations(nonCachedApiUrl, 'Get');
let operations = result.operations;
let reason = result.reason;
assert.equal(0, operations.length);
assert.equal(Constants.ErrorCodes.OperationNotFoundInCacheWithApi.name, reason.code);
let result = validator.getPotentialOperations(nonCachedApiUrl, 'Get')
let operations = result.operations
let reason = result.reason
assert.equal(0, operations.length)
assert.equal(Constants.ErrorCodes.OperationNotFoundInCacheWithApi.name, reason.code)
// Operations to match is StorageAccounts_CheckNameAvailability with provider "Hello.World" [non cached provider]
result = validator.getPotentialOperations(nonCachedProviderUrl, 'PoSt');
operations = result.operations;
reason = result.reason;
assert.equal(0, operations.length);
assert.equal(Constants.ErrorCodes.OperationNotFoundInCacheWithProvider.name, reason.code);
result = validator.getPotentialOperations(nonCachedProviderUrl, 'PoSt')
operations = result.operations
reason = result.reason
assert.equal(0, operations.length)
assert.equal(Constants.ErrorCodes.OperationNotFoundInCacheWithProvider.name, reason.code)
// Operations to match is StorageAccounts_Delete with verb "head" [non cached http verb]
result = validator.getPotentialOperations(nonCachedVerbUrl, 'head');
operations = result.operations;
reason = result.reason;
assert.equal(0, operations.length);
assert.equal(Constants.ErrorCodes.OperationNotFoundInCacheWithVerb.name, reason.code);
result = validator.getPotentialOperations(nonCachedVerbUrl, 'head')
operations = result.operations
reason = result.reason
assert.equal(0, operations.length)
assert.equal(Constants.ErrorCodes.OperationNotFoundInCacheWithVerb.name, reason.code)
// Operations to match is with path "subscriptions/subscriptionId/providers/Microsoft.Storage/storageAccounts/storageAccounts/accountName/properties/" [non cached path]
result = validator.getPotentialOperations(nonCachedPath, 'get');
operations = result.operations;
reason = result.reason;
assert.equal(0, operations.length);
assert.equal(Constants.ErrorCodes.OperationNotFoundInCache.name, reason.code);
done();
result = validator.getPotentialOperations(nonCachedPath, 'get')
operations = result.operations
reason = result.reason
assert.equal(0, operations.length)
assert.equal(Constants.ErrorCodes.OperationNotFoundInCache.name, reason.code)
done()
}).catch((err: any) => {
assert.ifError(err);
done();
}).catch(done);
});
assert.ifError(err)
done()
}).catch(done)
})
it('it should create an implicit default response and find it', function (done) {
let options = {
"directory": "./test/liveValidation/swaggers/specification/scenarios",
"swaggerPathsPattern": "**/*.json",
"shouldModelImplicitDefaultResponse": true
};
let apiUrl = "https://management.azure.com/subscriptions/subscriptionId/providers/Microsoft.Test/storageAccounts?api-version=2016-01-01";
}
let apiUrl =
"https://management.azure.com/subscriptions/subscriptionId/providers/Microsoft.Test/storageAccounts?api-version=2016-01-01"
let validator = new LiveValidator(options);
let validator = new LiveValidator(options)
validator.initialize().then(() => {
// Operations to match is StorageAccounts_List
let operations = validator.cache['microsoft.test']['2016-01-01']['post'];
let operations = validator.cache['microsoft.test']['2016-01-01']['post']
for (const operation of operations) {
assert(operation.responses.default);
assert.deepEqual(operation.responses.default.schema.properties.error, utils.CloudError);
assert(operation.responses.default)
assert.deepEqual(operation.responses.default.schema.properties.error, utils.CloudError)
}
done();
done()
}).catch((err: any) => {
assert.ifError(err);
done();
}).catch(done);
});
});
assert.ifError(err)
done()
}).catch(done)
})
})
describe('Initialize cache and validate', function () {
livePaths.forEach((livePath: any) => {
@ -293,18 +315,18 @@ describe('Live Validator', function () {
let options = {
"directory": "./test/liveValidation/swaggers/specification/storage",
"swaggerPathsPattern": "**/*.json"
};
let validator = new LiveValidator(options);
}
let validator = new LiveValidator(options)
validator.initialize().then(function () {
let reqRes = require(livePath);
let validationResult = validator.validateLiveRequestResponse(reqRes);
console.dir(validationResult, { depth: null, colors: true });
done();
let reqRes = require(livePath)
let validationResult = validator.validateLiveRequestResponse(reqRes)
console.dir(validationResult, { depth: null, colors: true })
done()
}).catch((err: any) => {
assert.ifError(err);
done();
}).catch(done);
});
});
});
});
assert.ifError(err)
done()
}).catch(done)
})
})
})
})

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

@ -2,376 +2,435 @@
// Licensed under the MIT License. See License.txt in the project root for license information.
import assert = require('assert');
const validate = require('../lib/validate');
import validate = require('../lib/validate')
const specPath = `${__dirname}/modelValidation/swaggers/specification/scenarios/resource-manager/Microsoft.Test/2016-01-01/test.json`;
const specPath =
`${__dirname}/modelValidation/swaggers/specification/scenarios/resource-manager/Microsoft.Test/2016-01-01/test.json`
describe('Model Validation', function () {
describe('Path validation - ', function () {
it('should pass when path parameter has forward slashes', function (done) {
let operationIds = "StorageAccounts_pathParameterWithForwardSlashes";
let operationIds = "StorageAccounts_pathParameterWithForwardSlashes"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for paths in x-ms-paths with question mark', function (done) {
let operationIds = "StorageAccounts_pathParameterWithQuestionMark";
let operationIds = "StorageAccounts_pathParameterWithQuestionMark"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for paths with quotes', function (done) {
let operationIds = "Path_WithQuotes";
let operationIds = "Path_WithQuotes"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should fail for paths with path parameter value resulting in duplicate forward slashes', function (done) {
let operationIds = "StorageAccounts_duplicateforwardslashes";
let operationIds = "StorageAccounts_duplicateforwardslashes"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === false, `swagger "${specPath}" with operation "${operationIds}" contains passed incorrectly.`);
console.log(result);
done();
assert(
result.validityStatus === false,
`swagger "${specPath}" with operation "${operationIds}" contains passed incorrectly.`)
console.log(result)
done()
}).catch((err: any) => {
try {
assert.equal(err.code, 'REQUEST_VALIDATION_ERROR');
assert.equal(err.innerErrors[0].code, 'DOUBLE_FORWARD_SLASHES_IN_URL');
done();
assert.equal(err.code, 'REQUEST_VALIDATION_ERROR')
assert.equal(err.innerErrors[0].code, 'DOUBLE_FORWARD_SLASHES_IN_URL')
done()
} catch (er) {
done(er);
done(er)
}
});
});
});
})
})
})
describe('Polymorphic models - ', function () {
it('should pass for Activity_List', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/polymorphic/polymorphicSwagger.json`;
let operationIds = "Activity_List";
let specPath = `${__dirname}/modelValidation/swaggers/specification/polymorphic/polymorphicSwagger.json`
let operationIds = "Activity_List"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for Activity_Dictionary', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/polymorphic/polymorphicSwagger.json`;
let operationIds = "Activity_Dictionary";
let specPath = `${__dirname}/modelValidation/swaggers/specification/polymorphic/polymorphicSwagger.json`
let operationIds = "Activity_Dictionary"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for CircularAnimal_List', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/polymorphic/polymorphicSwagger.json`;
let operationIds = "CircularAnimal_List";
let specPath =
`${__dirname}/modelValidation/swaggers/specification/polymorphic/polymorphicSwagger.json`
let operationIds = "CircularAnimal_List"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should fail for CircularAnimal_IncorrectSibling_List', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/polymorphic/polymorphicSwagger.json`;
let operationIds = "CircularAnimal_IncorrectSibling_List";
let specPath = `${__dirname}/modelValidation/swaggers/specification/polymorphic/polymorphicSwagger.json`
let operationIds = "CircularAnimal_IncorrectSibling_List"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === false, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
let responseError = result.operations['CircularAnimal_IncorrectSibling_List']
['x-ms-examples']['scenarios']['Tests ploymorphic circular array, dictionary of animals with incorrect sibling (negative)']['responses']['200'];
assert.equal(responseError.isValid, false);
assert.equal(responseError.error.code, 'RESPONSE_VALIDATION_ERROR');
assert.equal(responseError.error.innerErrors[0].errors[0].code, 'ONE_OF_MISSING');
done();
assert(result.validityStatus === false, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
let responseError = result.operations
['CircularAnimal_IncorrectSibling_List']
['x-ms-examples']
['scenarios']
['Tests ploymorphic circular array, dictionary of animals with incorrect sibling (negative)']
['responses']
['200']
assert.equal(responseError.isValid, false)
assert.equal(responseError.error.code, 'RESPONSE_VALIDATION_ERROR')
assert.equal(responseError.error.innerErrors[0].errors[0].code, 'ONE_OF_MISSING')
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for Entities_Search', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/polymorphic/EntitySearch.json`;
let operationIds = "Entities_Search";
let specPath = `${__dirname}/modelValidation/swaggers/specification/polymorphic/EntitySearch.json`
let operationIds = "Entities_Search"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
});
done(err)
})
})
})
describe('for parameters in formdata', function () {
it('should validate correctly', (done) => {
let specPath = `${__dirname}/modelValidation/swaggers/specification/formdata/spellCheck.json`;
let specPath = `${__dirname}/modelValidation/swaggers/specification/formdata/spellCheck.json`
validate.validateExamples(specPath, undefined, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" contains model validation errors.`);
console.log(result);
done();
assert(result.validityStatus === true, `swagger "${specPath}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
});
done(err)
})
})
})
describe('for parameters in x-ms-parameterized-host', function () {
it('should validate correctly', (done) => {
let specPath = `${__dirname}/modelValidation/swaggers/specification/parameterizedhost/face.json`;
let specPath = `${__dirname}/modelValidation/swaggers/specification/parameterizedhost/face.json`
validate.validateExamples(specPath, undefined, { consoleLogLevel: 'off' }).then((result: any) => {
console.dir(result, { depth: null });
assert(result.validityStatus === true, `swagger "${specPath}" contains model validation errors.`);
console.log(result);
done();
console.dir(result, { depth: null })
assert(result.validityStatus === true, `swagger "${specPath}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should validate the presence of parameters', (done) => {
let specPath = `${__dirname}/modelValidation/swaggers/specification/parameterizedhost/searchservice.json`;
let specPath =
`${__dirname}/modelValidation/swaggers/specification/parameterizedhost/searchservice.json`
validate.validateExamples(specPath, undefined, { consoleLogLevel: 'off' }).then((result: any) => {
console.dir(result, { depth: null });
assert(result.validityStatus === true, `swagger "${specPath}" contains model validation errors.`);
console.log(result);
done();
console.dir(result, { depth: null })
assert(result.validityStatus === true, `swagger "${specPath}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
});
done(err)
})
})
})
describe('Nullable models - ', function () {
it('should pass for regularOperation_Get', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`;
let operationIds = "regularOperation_Get";
let specPath =
`${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`
let operationIds = "regularOperation_Get"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for formatInDefinition_Get', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`;
let operationIds = "formatInDefinition_Get";
let specPath =
`${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`
let operationIds = "formatInDefinition_Get"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for enumInResponse_Get', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`;
let operationIds = "enumInResponse_Get";
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`
let operationIds = "enumInResponse_Get"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for readOnlyProp_Get', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`;
let operationIds = "readOnlyProp_Get";
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`
let operationIds = "readOnlyProp_Get"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for arrayInResponse_List', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`;
let operationIds = "arrayInResponse_List";
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`
let operationIds = "arrayInResponse_List"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for objectInResponse_Get', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`;
let operationIds = "objectInResponse_Get";
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`
let operationIds = "objectInResponse_Get"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for typeArrayInResponse_Get', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`;
let operationIds = "typeArrayInResponse_Get";
let specPath =
`${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`
let operationIds = "typeArrayInResponse_Get"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for xnullableFalse_Get', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`;
let operationIds = "xnullableFalse_Get";
let specPath =
`${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`
let operationIds = "xnullableFalse_Get"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for requiredProp_Get', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`;
let operationIds = "requiredProp_Get";
let specPath =
`${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`
let operationIds = "requiredProp_Get"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for inlineResponse_Get', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`;
let operationIds = "inlineResponse_Get";
let specPath =
`${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`
let operationIds = "inlineResponse_Get"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for RefWithNullableAtTopLevelOperation_Get', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`;
let operationIds = "RefWithNullableAtTopLevelOperation_Get";
let specPath =
`${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`
let operationIds = "RefWithNullableAtTopLevelOperation_Get"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for definitionWithReference_Get', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`;
let operationIds = "definitionWithReference_Get";
let specPath =
`${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`
let operationIds = "definitionWithReference_Get"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for definitionWithReferenceNotNullableOperation_Get', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`;
let operationIds = "definitionWithReferenceNotNullableOperation_Get";
let specPath =
`${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`
let operationIds = "definitionWithReferenceNotNullableOperation_Get"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
done(err)
})
})
it('should pass for nullableTopLevel_Get', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`;
let operationIds = "nullableTopLevel_Get";
let specPath = `${__dirname}/modelValidation/swaggers/specification/nullableTypes/invalid_type_test.json`
let operationIds = "nullableTopLevel_Get"
validate.validateExamples(specPath, operationIds, { consoleLogLevel: 'off' }).then((result: any) => {
assert(result.validityStatus === true, `swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`);
console.log(result);
done();
assert(
result.validityStatus === true,
`swagger "${specPath}" with operation "${operationIds}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
});
done(err)
})
})
})
describe('Content type - ', function () {
it('should pass for consumes application/octet-stream', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/contenttype/datalake.json`;
let specPath = `${__dirname}/modelValidation/swaggers/specification/contenttype/datalake.json`
validate.validateExamples(specPath, undefined, { consoleLogLevel: 'off' }).then((result: any) => {
console.dir(result, { depth: null });
assert(result.validityStatus === true, `swagger "${specPath}" contains model validation errors.`);
console.log(result);
done();
console.dir(result, { depth: null })
assert(result.validityStatus === true, `swagger "${specPath}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
});
done(err)
})
})
})
describe('Queries - ', function () {
it('should pass for various query parameters', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/query/test.json`;
let specPath = `${__dirname}/modelValidation/swaggers/specification/query/test.json`
validate.validateExamples(specPath, undefined, { consoleLogLevel: 'off' }).then((result: any) => {
console.dir(result, { depth: null });
assert(result.validityStatus === true, `swagger "${specPath}" contains model validation errors.`);
console.log(result);
done();
console.dir(result, { depth: null })
assert(result.validityStatus === true, `swagger "${specPath}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
});
done(err)
})
})
})
describe('Headers - ', function () {
it('should pass for various header parameters', function (done) {
let specPath = `${__dirname}/modelValidation/swaggers/specification/header/test.json`;
let specPath = `${__dirname}/modelValidation/swaggers/specification/header/test.json`
validate.validateExamples(specPath, undefined, { consoleLogLevel: 'off' }).then((result: any) => {
console.dir(result, { depth: null });
assert(result.validityStatus === true, `swagger "${specPath}" contains model validation errors.`);
console.log(result);
done();
console.dir(result, { depth: null })
assert(result.validityStatus === true, `swagger "${specPath}" contains model validation errors.`)
console.log(result)
done()
}).catch((err: any) => {
done(err);
});
});
});
});
done(err)
})
})
})
})

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

@ -1,23 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
'use strict';
//Sample standalone script to call live validator.
import assert = require('assert')
var
path = require('path'),
os = require('os'),
LiveValidator = require('../lib/validators/liveValidator.js'),
Constants = require('../lib/util/constants');
import path = require('path')
import os = require('os')
import LiveValidator = require('../lib/validators/liveValidator.js')
import Constants = require('../lib/util/constants');
let options = {
"directory": "./test/swaggers/arm-storage"
};
let validator = new LiveValidator(options);
}
let validator = new LiveValidator(options)
validator.initialize().then(function () {
let reqRes = require(__dirname + '/liveValidation/swaggers/specification/storage/resource-manager/Microsoft.Storage/2016-01-01/live/StorageAccounts_CheckNameAvailability.json');
let reqRes = require(__dirname + '/liveValidation/swaggers/specification/storage/resource-manager/Microsoft.Storage/2016-01-01/live/StorageAccounts_CheckNameAvailability.json')
let requestResponseObj = {
liveRequest: reqRes.request,
liveResponse: reqRes.response
}
validator.validateLiveRequestResponse(requestResponseObj);
});
validator.validateLiveRequestResponse(requestResponseObj)
})

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

@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
import assert = require('assert');
const validate = require('../lib/validate');
import assert = require('assert')
import validate = require('../lib/validate')
describe('Semantic validation', function () {
it('should validate correctly when the spec contains an x-ms-parameterized-host', (done) => {

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

@ -1,17 +1,18 @@
const assert = require('assert');
import validate = require('../lib/validate');
const fs = require('fs');
const specPath = `${__dirname}/modelValidation/swaggers/specification/polymorphic/EntitySearch.json`;
import assert = require('assert')
import validate = require('../lib/validate')
import fs = require('fs')
const specPath = `${__dirname}/modelValidation/swaggers/specification/polymorphic/EntitySearch.json`
describe('Uml generator', () => {
it('should generate class diagram correctly', (done) => {
const svgFile = `${__dirname}/diagram/EntitySearch.svg`;
if (fs.existsSync(svgFile)) fs.unlinkSync(svgFile);
const svgFile = `${__dirname}/diagram/EntitySearch.svg`
if (fs.existsSync(svgFile)) fs.unlinkSync(svgFile)
validate.generateUml(specPath, `${__dirname}/diagram`).then((res: any) => {
assert.equal(fs.existsSync(svgFile), true);
done();
assert.equal(fs.existsSync(svgFile), true)
done()
}).catch((err: any) => {
done(err);
});
});
});
done(err)
})
})
})

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

@ -1,40 +1,41 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
var assert = require('assert');
var utils = require('../lib/util/utils.js');
import assert = require('assert')
import utils = require('../lib/util/utils.js')
describe('Utility functions', function () {
describe('Get Provider', function () {
it('should throw on empty', function () {
assert.throws(() => {
utils.getProvider('');
utils.getProvider('')
})
});
})
it('should throw null', function () {
assert.throws(() => {
utils.getProvider(null);
utils.getProvider(null)
})
});
})
it('should throw undefined', function () {
assert.throws(() => {
utils.getProvider();
utils.getProvider()
})
});
})
it('should return Microsoft.Resources', function () {
let path = "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/{parentResourcePath}/{resourceType}/{resourceName}"
let provider = utils.getProvider(path);
assert.equal(provider, 'Microsoft.Resources');
let path =
"/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/{parentResourcePath}/{resourceType}/{resourceName}"
let provider = utils.getProvider(path)
assert.equal(provider, 'Microsoft.Resources')
})
it('should return undefined', function () {
let path = "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/"
let provider = utils.getProvider(path);
assert.equal(provider, undefined);
let provider = utils.getProvider(path)
assert.equal(provider, undefined)
})
it('should return Microsoft.Authorization', function () {
let path = "/subscriptions/{subscriptionId}/resourcegroups/{resourceGroupName}/providers/Microsoft.Resources/{parentResourcePath}/{resourceType}/{resourceName}/providers/Microsoft.Authorization/roleAssignments"
let provider = utils.getProvider(path);
assert.equal(provider, 'Microsoft.Authorization');
let provider = utils.getProvider(path)
assert.equal(provider, 'Microsoft.Authorization')
})
});
});
})
})

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

@ -1,21 +1,20 @@
import should = require('should')
var
path = require('path'),
glob = require('glob'),
jsYaml = require('js-yaml');
import path = require('path')
import glob = require('glob')
import jsYaml = require('js-yaml')
const yamlPaths = glob.sync(path.join(__dirname, 'swaggers/**/yaml/*.yml'));
const yamlPaths = glob.sync(path.join(__dirname, 'swaggers/**/yaml/*.yml'))
describe('Wireformat generator', () => {
yamlPaths.forEach((yamlPath: any) => {
it(`should generate a valid YAML doc for "${yamlPath}."`, (done) => {
try {
let yamlContent = jsYaml.safeLoad(yamlPath, { strict: true });
should.exist(yamlContent);
done();
let yamlContent = jsYaml.safeLoad(yamlPath, { strict: true })
should.exist(yamlContent)
done()
} catch (err) {
done(err);
done(err)
}
});
});
});
})
})
})