diff --git a/lib/autorestPlugin/pluginHost.js b/lib/autorestPlugin/pluginHost.js new file mode 100644 index 00000000..1df11e05 --- /dev/null +++ b/lib/autorestPlugin/pluginHost.js @@ -0,0 +1,204 @@ +/*--------------------------------------------------------------------------------------------- + * 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 vscode_jsonrpc_1 = require("vscode-jsonrpc"); +const linq = require('linq'); +const jsonPath = require('jsonpath'); +const yaml = require("./yaml.js"); +const utils = require("../util/utils"); +const validator = require("../validate"); +const log = require('../util/logging'); +const SpecValidator = require('../validators/specValidator') + +const openAPIDocUrl = "https://github.com/Azure/oav"; + +exports = module.exports; + +class OpenApiValidationExample { + Process(sessionId, initiator) { + return initiator.ListInputs(sessionId).then(function (swaggerFileNames) { + const promises = []; + for (const swaggerFileName of swaggerFileNames) { + promises.push( + initiator.ReadFile(sessionId, swaggerFileName).then(function (swaggerFile) { + const swagger = yaml.Parse(swaggerFile); + return exports.openApiValidationExample(swagger, swaggerFileName).then(function (exampleValidationResults) { + for (const result of exampleValidationResults) { + initiator.Message(sessionId, { Channel: result.channel, Text: result.text, Details: result.details, Key: result.code, Source: result.source }); + } + console.error(JSON.stringify(exampleValidationResults, null, 2)); + }) + }) + ); + } + return Promise.all(promises).then(_ => true) + }) + } +} + +OpenApiValidationExample.Name = "model-validator"; + +function FormattedOutput(channel, details, code, text, source) { + this.channel = channel; + this.details = details; + this.code = code; + this.text = text; + this.source = source; +} + +exports.openApiValidationExample = function openApiValidationExample(swagger, swaggerFileName) { + var formattedResult = []; + let specVal = new SpecValidator("swagger.json", swagger, { "consoleLogLevel": "off" }); + //console.error(JSON.stringify(swagger, null, 2)); + return specVal.initialize().then(function () { + specVal.validateOperations(); + Promise.resolve(specVal.specValidationResult).then(function (specValidationResult) { + for (var op in specValidationResult.operations) { + const xmsExamplesNode = specValidationResult.operations[op]["x-ms-examples"]; + for (var scenario in xmsExamplesNode.scenarios) { + // invalid? meaning that there's an issue found in the validation + 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"]`)) + .select(x => x.path) + .firstOrDefault(); + if (!xmsexPath) { + 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, ["ExampleModelViolation"], "Model validator found issue (see details).", [{ document: swaggerFileName, Position: { path: xmsexPath } }]) + formattedResult.push(result); + + // request + const request = scenarioItem.request; + if (request.isValid === false) { + const error = request.error; + const innerErrors = error.innerErrors; + if (!innerErrors || !innerErrors.length) { + throw new Error("Model Validator: Unexpected format."); + } + for (const innerError of innerErrors) { + const path = ConvertIndicesFromStringToNumbers(innerError.path); + //console.error(JSON.stringify(error, null, 2)); + result = new FormattedOutput("error", error, [error.code, error.id, "ExampleModelViolation"], + 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 (var responseCode in scenarioItem.responses) { + const response = scenarioItem.responses[responseCode]; + if (response.isValid === false) { + const error = response.error; + const innerErrors = error.innerErrors; + if (!innerErrors || !innerErrors.length) { + throw new Error("Model Validator: Unexpected format."); + } + for (const innerError of innerErrors) { + //console.error(JSON.stringify(error, null, 2)); + result = new FormattedOutput("error", error, [error.code, error.id, "ExampleModelViolation"], + 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; + }).catch(function (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) { + const result = path.slice(); + for (let i = 1; i < result.length; ++i) { + const num = parseInt(result[i]); + if (!isNaN(num) && result[i - 1] === "parameters") { + result[i] = num; + } + } + return result; +} + +class PluginHost { + constructor(initiator) { + this.initiator = initiator; + } + + GetPluginNames() { + return [/*OpenApiValidationSemantic.Name, */ OpenApiValidationExample.Name]; + } + + Process(pluginName, sessionId) { + switch (pluginName) { + // case OpenApiValidationSemantic.Name: + // return new OpenApiValidationSemantic().Process(sessionId, this.initiator); + case OpenApiValidationExample.Name: + return new OpenApiValidationExample().Process(sessionId, this.initiator); + default: + return false; + } + } +} + +var IAutoRestPluginInitiator_Types; +(function (IAutoRestPluginInitiator_Types) { + IAutoRestPluginInitiator_Types.ReadFile = new vscode_jsonrpc_1.RequestType2("ReadFile"); + IAutoRestPluginInitiator_Types.GetValue = new vscode_jsonrpc_1.RequestType2("GetValue"); + IAutoRestPluginInitiator_Types.ListInputs = new vscode_jsonrpc_1.RequestType1("ListInputs"); + IAutoRestPluginInitiator_Types.WriteFile = new vscode_jsonrpc_1.NotificationType4("WriteFile"); + IAutoRestPluginInitiator_Types.Message = new vscode_jsonrpc_1.NotificationType4("Message"); +})(IAutoRestPluginInitiator_Types = exports.IAutoRestPluginInitiator_Types || (exports.IAutoRestPluginInitiator_Types = {})); + +var IAutoRestPluginTarget_Types; +(function (IAutoRestPluginTarget_Types) { + IAutoRestPluginTarget_Types.GetPluginNames = new vscode_jsonrpc_1.RequestType0("GetPluginNames"); + IAutoRestPluginTarget_Types.Process = new vscode_jsonrpc_1.RequestType2("Process"); +})(IAutoRestPluginTarget_Types = exports.IAutoRestPluginTarget_Types || (exports.IAutoRestPluginTarget_Types = {})); + +function main() { + // connection setup + const channel = vscode_jsonrpc_1.createMessageConnection(process.stdin, process.stdout, { + error(message) { console.error(message); }, + info(message) { console.info(message); }, + log(message) { console.log(message); }, + warn(message) { console.warn(message); } + }); + const initiator = { + ReadFile(sessionId, filename) { + return channel.sendRequest(IAutoRestPluginInitiator_Types.ReadFile, sessionId, filename); + }, + GetValue(sessionId, key) { + return channel.sendRequest(IAutoRestPluginInitiator_Types.GetValue, sessionId, key); + }, + ListInputs(sessionId) { + return channel.sendRequest(IAutoRestPluginInitiator_Types.ListInputs, sessionId); + }, + WriteFile(sessionId, filename, content, sourceMap) { + channel.sendNotification(IAutoRestPluginInitiator_Types.WriteFile, sessionId, filename, content, sourceMap); + }, + Message(sessionId, message, path, sourceFile) { + channel.sendNotification(IAutoRestPluginInitiator_Types.Message, sessionId, message, path, sourceFile); + } + }; + const target = new PluginHost(initiator); + channel.onRequest(IAutoRestPluginTarget_Types.GetPluginNames, target.GetPluginNames.bind(target)); + channel.onRequest(IAutoRestPluginTarget_Types.Process, target.Process.bind(target)); + // activate + channel.listen(); +} + +main(); diff --git a/lib/autorestPlugin/stable-object.js b/lib/autorestPlugin/stable-object.js new file mode 100644 index 00000000..4d65b801 --- /dev/null +++ b/lib/autorestPlugin/stable-object.js @@ -0,0 +1,38 @@ +"use strict"; +/*--------------------------------------------------------------------------------------------- + * 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 }); +function NewEmptyObject() { + let keys = []; + return new Proxy({}, { + get(target, key) { + return target[key]; + }, + has(target, key) { + return keys.indexOf(key) !== -1; + }, + set(target, key, value) { + if (keys.indexOf(key) === -1) { + keys.push(key); + } + target[key] = value; + return true; + }, + deleteProperty(target, key) { + if (keys.indexOf(key) !== -1) { + keys = keys.filter(x => x !== key); + } + delete target[key]; + return true; + }, + ownKeys(target) { + return keys; + }, + enumerate(target) { + return keys; + } + }); +} +exports.NewEmptyObject = NewEmptyObject; diff --git a/lib/autorestPlugin/yaml.js b/lib/autorestPlugin/yaml.js new file mode 100644 index 00000000..be03583e --- /dev/null +++ b/lib/autorestPlugin/yaml.js @@ -0,0 +1,177 @@ +"use strict"; +/*--------------------------------------------------------------------------------------------- + * 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 yamlAst = require("yaml-ast-parser"); +const stable_object_1 = require("./stable-object"); +/** + * reexport required elements + */ +var yaml_ast_parser_1 = require("yaml-ast-parser"); +exports.newScalar = yaml_ast_parser_1.newScalar; +exports.Kind = yamlAst.Kind; +exports.CreateYAMLMapping = yamlAst.newMapping; +exports.CreateYAMLScalar = yamlAst.newScalar; +/** + * Parsing +*/ +function ParseToAst(rawYaml) { + return yamlAst.safeLoad(rawYaml, null); +} +exports.ParseToAst = ParseToAst; +function* Descendants(yamlAstNode, currentPath = [], deferResolvingMappings = false) { + const todos = [{ path: currentPath, node: yamlAstNode }]; + let todo; + while (todo = todos.pop()) { + // report self + yield todo; + // traverse + if (todo.node) { + switch (todo.node.kind) { + case exports.Kind.MAPPING: + { + let astSub = todo.node; + if (deferResolvingMappings) { + todos.push({ node: astSub.value, path: todo.path }); + } + else { + todos.push({ node: astSub.value, path: todo.path.concat([astSub.key.value]) }); + } + } + break; + case exports.Kind.MAP: + if (deferResolvingMappings) { + for (let mapping of todo.node.mappings) { + todos.push({ node: mapping, path: todo.path.concat([mapping.key.value]) }); + } + } + else { + for (let mapping of todo.node.mappings) { + todos.push({ node: mapping, path: todo.path }); + } + } + break; + case exports.Kind.SEQ: + { + let astSub = todo.node; + for (let i = 0; i < astSub.items.length; ++i) { + todos.push({ node: astSub.items[i], path: todo.path.concat([i]) }); + } + } + break; + } + } + } +} +exports.Descendants = Descendants; +function ResolveAnchorRef(yamlAstRoot, anchorRef) { + for (let yamlAstNode of Descendants(yamlAstRoot)) { + if (yamlAstNode.node.anchorId === anchorRef) { + return yamlAstNode; + } + } + throw new Error(`Anchor '${anchorRef}' not found`); +} +exports.ResolveAnchorRef = ResolveAnchorRef; +/** + * Populates yamlNode.valueFunc with a function that creates a *mutable* object (i.e. no caching of the reference or such) + */ +function ParseNodeInternal(yamlRootNode, yamlNode, onError) { + if (yamlNode.errors.length > 0) { + for (const error of yamlNode.errors) { + onError(`Syntax error: ${error.reason}`, error.mark.position); + } + return yamlNode.valueFunc = () => null; + } + if (yamlNode.valueFunc) { + return yamlNode.valueFunc; + } + switch (yamlNode.kind) { + case exports.Kind.SCALAR: { + const yamlNodeScalar = yamlNode; + return yamlNode.valueFunc = yamlNodeScalar.valueObject !== undefined + ? () => yamlNodeScalar.valueObject + : () => yamlNodeScalar.value; + } + case exports.Kind.MAPPING: + onError("Syntax error: Encountered bare mapping.", yamlNode.startPosition); + return yamlNode.valueFunc = () => null; + case exports.Kind.MAP: { + const yamlNodeMapping = yamlNode; + return yamlNode.valueFunc = () => { + const result = stable_object_1.NewEmptyObject(); + for (const mapping of yamlNodeMapping.mappings) { + if (mapping.key.kind !== exports.Kind.SCALAR) { + onError("Syntax error: Only scalar keys are allowed as mapping keys.", mapping.key.startPosition); + } + else if (mapping.value === null) { + onError("Syntax error: No mapping value found.", mapping.key.endPosition); + } + else { + result[mapping.key.value] = ParseNodeInternal(yamlRootNode, mapping.value, onError)(); + } + } + return result; + }; + } + case exports.Kind.SEQ: { + const yamlNodeSequence = yamlNode; + return yamlNode.valueFunc = () => yamlNodeSequence.items.map(item => ParseNodeInternal(yamlRootNode, item, onError)()); + } + case exports.Kind.ANCHOR_REF: { + const yamlNodeRef = yamlNode; + return ResolveAnchorRef(yamlRootNode, yamlNodeRef.referencesAnchor).node.valueFunc; + } + case exports.Kind.INCLUDE_REF: + onError("Syntax error: INCLUDE_REF not implemented.", yamlNode.startPosition); + return yamlNode.valueFunc = () => null; + default: + throw new Error("Unknown YAML node kind."); + } +} +function ParseNode(yamlNode, onError = message => { throw new Error(message); }) { + ParseNodeInternal(yamlNode, yamlNode, onError); + return yamlNode.valueFunc(); +} +exports.ParseNode = ParseNode; +function CloneAst(ast) { + if (ast.kind === exports.Kind.MAPPING) { + const astMapping = ast; + return exports.CreateYAMLMapping(CloneAst(astMapping.key), CloneAst(astMapping.value)); + } + return ParseToAst(StringifyAst(ast)); +} +exports.CloneAst = CloneAst; +function StringifyAst(ast) { + return FastStringify(ParseNode(ast)); +} +exports.StringifyAst = StringifyAst; +function Clone(object) { + return Parse(FastStringify(object)); +} +exports.Clone = Clone; +function ToAst(object) { + return ParseToAst(FastStringify(object)); +} +exports.ToAst = ToAst; +function Parse(rawYaml, onError = message => { throw new Error(message); }) { + const node = ParseToAst(rawYaml); + const result = ParseNode(node, onError); + return result; +} +exports.Parse = Parse; +function Stringify(object) { + return "---\n" + yamlAst.safeDump(object, { skipInvalid: true }); +} +exports.Stringify = Stringify; +function FastStringify(obj) { + try { + return JSON.stringify(obj, null, 1); + } + catch (e) { + return Stringify(obj); + } +} +exports.FastStringify = FastStringify; diff --git a/lib/util/constants.js b/lib/util/constants.js index ef2cc879..e846b357 100644 --- a/lib/util/constants.js +++ b/lib/util/constants.js @@ -12,35 +12,35 @@ var Constants = { Errors: 'Errors', Warnings: 'Warnings', ErrorCodes: { - InternalError: 'INTERNAL_ERROR', - InitializationError: 'INITIALIZATION_ERROR', - ResolveSpecError: 'RESOLVE_SPEC_ERROR', - RefNotFoundError: 'REF_NOTFOUND_ERROR', - JsonParsingError: 'JSON_PARSING_ERROR', - RequiredParameterExampleNotFound: 'REQUIRED_PARAMETER_EXAMPLE_NOT_FOUND', - ErrorInPreparingRequest: 'ERROR_IN_PREPARING_REQUEST', - XmsExampleNotFoundError: 'X-MS-EXAMPLE_NOTFOUND_ERROR', - ResponseValidationError: 'RESPONSE_VALIDATION_ERROR', - RequestValidationError: 'REQUEST_VALIDATION_ERROR', - ResponseBodyValidationError: 'RESPONSE_BODY_VALIDATION_ERROR', - ResponseStatusCodeNotInExample: 'RESPONSE_STATUS_CODE_NOT_IN_EXAMPLE', - ResponseStatusCodeNotInSpec: 'RESPONSE_STATUS_CODE_NOT_IN_SPEC', - ResponseSchemaNotInSpec: 'RESPONSE_SCHEMA_NOT_IN_SPEC', - RequiredParameterNotInExampleError: 'REQUIRED_PARAMETER_NOT_IN_EXAMPLE_ERROR', - BodyParameterValidationError: 'BODY_PARAMETER_VALIDATION_ERROR', - TypeValidationError: 'TYPE_VALIDATION_ERROR', - ConstraintValidationError: 'CONSTRAINT_VALIDATION_ERROR', - StatuscodeNotInExampleError: 'STATUS_CODE_NOT_IN_EXAMPLE_ERROR', - SemanticValidationError: 'SEMANTIC_VALIDATION_ERROR', - MultipleOperationsFound: 'MULTIPLE_OPERATIONS_FOUND', - NoOperationFound: 'NO_OPERATION_FOUND', - IncorrectInput: 'INCORRECT_INPUT', - PotentialOperationSearchError: 'POTENTIAL_OPERATION_SEARCH_ERROR', - PathNotFoundInRequestUrl: "PATH_NOT_FOUND_IN_REQUEST_URL", - OperationNotFoundInCache: "OPERATION_NOT_FOUND_IN_CACHE", - OperationNotFoundInCacheWithVerb: "OPERATION_NOT_FOUND_IN_CACHE_WITH_VERB", // Implies we found correct api-version + provider in cache - OperationNotFoundInCacheWithApi: "OPERATION_NOT_FOUND_IN_CACHE_WITH_API", // Implies we found correct provider in cache - OperationNotFoundInCacheWithProvider: "OPERATION_NOT_FOUND_IN_CACHE_WITH_PROVIDER" // Implies we never found correct provider in cache + InternalError: { name: 'INTERNAL_ERROR', id: 'OAV100' }, + InitializationError: { name: 'INITIALIZATION_ERROR', id: 'OAV101' }, + ResolveSpecError: { name: 'RESOLVE_SPEC_ERROR', id: 'OAV102' }, + RefNotFoundError: { name: 'REF_NOTFOUND_ERROR', id: 'OAV103' }, + JsonParsingError: { name: 'JSON_PARSING_ERROR', id: 'OAV104' }, + RequiredParameterExampleNotFound: { name: 'REQUIRED_PARAMETER_EXAMPLE_NOT_FOUND', id: 'OAV105' }, + ErrorInPreparingRequest: { name: 'ERROR_IN_PREPARING_REQUEST', id: 'OAV106' }, + XmsExampleNotFoundError: { name: 'X-MS-EXAMPLE_NOTFOUND_ERROR', id: 'OAV107' }, + ResponseValidationError: { name: 'RESPONSE_VALIDATION_ERROR', id: 'OAV108' }, + RequestValidationError: { name: 'REQUEST_VALIDATION_ERROR', id: 'OAV109' }, + ResponseBodyValidationError: { name: 'RESPONSE_BODY_VALIDATION_ERROR', id: 'OAV110' }, + ResponseStatusCodeNotInExample: { name: 'RESPONSE_STATUS_CODE_NOT_IN_EXAMPLE', id: 'OAV111' }, + ResponseStatusCodeNotInSpec: { name: 'RESPONSE_STATUS_CODE_NOT_IN_SPEC', id: 'OAV112' }, + ResponseSchemaNotInSpec: { nam: 'RESPONSE_SCHEMA_NOT_IN_SPEC', id: 'OAV113' }, + RequiredParameterNotInExampleError: { name: 'REQUIRED_PARAMETER_NOT_IN_EXAMPLE_ERROR', id: 'OAV114' }, + BodyParameterValidationError: { name: 'BODY_PARAMETER_VALIDATION_ERROR', id: 'OAV115' }, + TypeValidationError: { name: 'TYPE_VALIDATION_ERROR', id: 'OAV116' }, + ConstraintValidationError: { name: 'CONSTRAINT_VALIDATION_ERROR', id: 'OAV117' }, + StatuscodeNotInExampleError: { name: 'STATUS_CODE_NOT_IN_EXAMPLE_ERROR', id: 'OAV118' }, + SemanticValidationError: { name: 'SEMANTIC_VALIDATION_ERROR', id: 'OAV119' }, + MultipleOperationsFound: { name: 'MULTIPLE_OPERATIONS_FOUND', id: 'OAV120' }, + NoOperationFound: { name: 'NO_OPERATION_FOUND', id: 'OAV121' }, + IncorrectInput: { name: 'INCORRECT_INPUT', id: 'OAV122' }, + PotentialOperationSearchError: { name: 'POTENTIAL_OPERATION_SEARCH_ERROR', id: 'OAV123' }, + PathNotFoundInRequestUrl: { name: "PATH_NOT_FOUND_IN_REQUEST_URL", id: 'OAV124' }, + OperationNotFoundInCache: { name: "OPERATION_NOT_FOUND_IN_CACHE", id: 'OAV125' }, + OperationNotFoundInCacheWithVerb: { name: "OPERATION_NOT_FOUND_IN_CACHE_WITH_VERB", id: 'OAV126' }, // Implies we found correct api-version + provider in cache + OperationNotFoundInCacheWithApi: { name: "OPERATION_NOT_FOUND_IN_CACHE_WITH_API", id: 'OAV127' }, // Implies we found correct provider in cache + OperationNotFoundInCacheWithProvider: { name: "OPERATION_NOT_FOUND_IN_CACHE_WITH_PROVIDER", id: 'OAV128' } // Implies we never found correct provider in cache }, EnvironmentVariables: { ClientId: 'CLIENT_ID', diff --git a/lib/validators/specResolver.js b/lib/validators/specResolver.js index ae3982d2..d45c57ff 100644 --- a/lib/validators/specResolver.js +++ b/lib/validators/specResolver.js @@ -133,7 +133,8 @@ class SpecResolver { }).catch(function (err) { let e = { message: `An Error occurred while resolving relative references and allOf in model definitions in the swagger spec: "${self.specPath}".`, - code: ErrorCodes.ResolveSpecError, + code: ErrorCodes.ResolveSpecError.name, + id: ErrorCodes.ResolveSpecError.id, innerErrors: [err] }; log.error(err); diff --git a/lib/validators/specValidator.js b/lib/validators/specValidator.js index 21d42506..45d15690 100644 --- a/lib/validators/specValidator.js +++ b/lib/validators/specValidator.js @@ -87,26 +87,47 @@ class SpecValidator { if (self.options.shouldResolveRelativePaths) { utils.clearCache(); } - return utils.parseJson(self.specPath).then(function (result) { - self.specInJson = result; + if (self.specInJson === null) { + return utils.parseJson(self.specPath).then(function (result) { + self.specInJson = result; + self.specResolver = new SpecResolver(self.specPath, self.specInJson, self.options); + return self.specResolver.resolve(); + }).then(function () { + let options = {}; + options.definition = self.specInJson; + options.jsonRefs = {}; + options.jsonRefs.relativeBase = self.specDir; + return Sway.create(options); + }).then(function (api) { + self.swaggerApi = api; + return Promise.resolve(api); + }).catch(function (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); + }); + } + else { self.specResolver = new SpecResolver(self.specPath, self.specInJson, self.options); - return self.specResolver.resolve(); - }).then(function () { - let options = {}; - options.definition = self.specInJson; - options.jsonRefs = {}; - options.jsonRefs.relativeBase = self.specDir; - return Sway.create(options); - }).then(function (api) { - self.swaggerApi = api; - return Promise.resolve(api); - }).catch(function (err) { - let e = self.constructErrorObject(ErrorCodes.ResolveSpecError, err.message, [err]); - self.specValidationResult.resolveSpec = e; - log.error(`${ErrorCodes.ResolveSpecError}: ${err.message}.`); - log.error(err.stack); - return Promise.reject(e); - }); + return self.specResolver.resolve().then(function () { + let options = {}; + options.definition = self.specInJson; + options.jsonRefs = {}; + options.jsonRefs.relativeBase = self.specDir; + return Sway.create(options); + }).then(function (api) { + self.swaggerApi = api; + return Promise.resolve(api); + }).catch(function (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); + }); + } } getProviderNamespace() { @@ -158,7 +179,8 @@ class SpecValidator { */ constructErrorObject(code, message, innerErrors, skipValidityStatusUpdate) { let err = { - code: code, + code: code.name, + id: code.id, message: message, } if (innerErrors) { @@ -181,7 +203,7 @@ class SpecValidator { let e = self.constructErrorObject(ErrorCodes.InitializationError, msg) self.specValidationResult.initialize = e; self.specValidationResult.validateSpec.isValid = false; - log.error(`${ErrorCodes.InitializationError}: ${msg}`); + log.error(`${ErrorCodes.InitializationError.name}: ${msg}`); return Promise.reject(e); } try { @@ -211,7 +233,8 @@ class SpecValidator { return Promise.resolve(validationResult); } catch (err) { let msg = `An Internal Error occurred in validating the spec "${self.specPath}". \t${err.message}.`; - err.code = ErrorCodes.InternalError; + err.code = ErrorCodes.InternalError.name; + err.id = ErrorCodes.InternalError.id; err.message = msg; self.specValidationResult.validateSpec.isValid = false; self.specValidationResult.validateSpec.error = err; diff --git a/lib/wireFormatGenerator.js b/lib/wireFormatGenerator.js index b82ba63a..c1b6a0d2 100644 --- a/lib/wireFormatGenerator.js +++ b/lib/wireFormatGenerator.js @@ -77,7 +77,7 @@ class WireFormatGenerator { }).catch((err) => { let e = self.constructErrorObject(ErrorCodes.ResolveSpecError, err.message, [err]); //self.specValidationResult.resolveSpec = e; - log.error(`${ErrorCodes.ResolveSpecError}: ${err.message}.`); + log.error(`${ErrorCodes.ResolveSpecError.name}: ${err.message}.`); log.error(err.stack); return Promise.reject(e); }); diff --git a/package.json b/package.json index 8562c464..9fc4d803 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,11 @@ "uuid": "^3.0.1", "recursive-readdir": "^2.1.0", "swagger-parser": "^3.4.1", - "swagger-tools": "^0.10.1" + "swagger-tools": "^0.10.1", + "linq":"^3.0.8", + "jsonpath": "^0.2.11", + "vscode-jsonrpc": "^3.2.0", + "yaml-ast-parser": "https://github.com/olydis/yaml-ast-parser/releases/download/0.0.34/yaml-ast-parser-0.0.34.tgz" }, "devDependencies": { "jshint": "2.9.4",