public static void ThrowsServiceDefinitionException(Func <object> func, NamedTextPosition position) { ThrowsServiceDefinitionException( () => { func(); }, position); }
internal static string GetDefinitionNameFromRef(string refValue, NamedTextPosition position) { const string refPrefix = "#/definitions/"; if (!refValue.StartsWith(refPrefix, StringComparison.Ordinal)) { throw new ServiceDefinitionException("Definition $ref must start with '#/definitions/'.", position); } return(UnescapeRefPart(refValue.Substring(refPrefix.Length))); }
public static void ThrowsServiceDefinitionException(Action action, NamedTextPosition position) { try { action(); throw new InvalidOperationException("Action did not throw."); } catch (ServiceDefinitionException exception) { Assert.AreSame(position, exception.Position); } }
public void LineNumberOnly() { var position = new NamedTextPosition("source", 3); position.ToString().ShouldBe("source(3)"); }
public void InvalidTypeNameThrows() { var position = new NamedTextPosition("source", 1, 2); TestUtility.ThrowsServiceDefinitionException(() => new ServiceFieldInfo(name: "x", typeName: "4u", position: position), position); }
private static void AddFieldsFromSchema(IList <ServiceFieldInfo> requestFields, SwaggerService swaggerService, NamedTextPosition position, KeyValuePair <string, SwaggerSchema> bodySchema) { if ((bodySchema.Value.Type ?? SwaggerSchemaType.Object) != SwaggerSchemaType.Object) { throw new NotImplementedException(); } foreach (var property in bodySchema.Value.Properties.EmptyIfNull()) { var attributes = new List <ServiceAttributeInfo>(); if (property.Value.Obsolete.GetValueOrDefault()) { attributes.Add(new ServiceAttributeInfo("obsolete")); } string typeName = swaggerService.TryGetFacilityTypeName(property.Value, position); if (typeName != null) { requestFields.Add(new ServiceFieldInfo( property.Key, typeName: typeName, attributes: attributes, summary: PrepareSummary(property.Value.Description), position: position)); } } }
internal static string TryGetFacilityResultOfType(this SwaggerService swaggerService, KeyValuePair <string, SwaggerSchema> swaggerSchema, NamedTextPosition position) { const string nameSuffix = "Result"; if (!swaggerSchema.Key.EndsWith(nameSuffix, StringComparison.Ordinal)) { return(null); } var properties = swaggerSchema.Value.Properties.EmptyIfNull(); if (!properties.Any(x => x.Key == "error" && x.Value.Ref == "#/definitions/Error")) { return(null); } var valueSchema = properties.Where(x => x.Key == "value").Select(x => x.Value).FirstOrDefault(); if (valueSchema == null) { return(null); } return(swaggerService.TryGetFacilityTypeName(valueSchema, position)); }
private static Position ToLspPosition(NamedTextPosition position) { return(new Position(position.LineNumber - 1, position.ColumnNumber - 1)); }
/// <summary> /// Parses Swagger (OpenAPI) 2.0 into a service definition. /// </summary> public ServiceInfo ParseDefinition(NamedText source) { if (string.IsNullOrWhiteSpace(source.Text)) { throw new ServiceDefinitionException("Service definition is missing.", new NamedTextPosition(source.Name, 1, 1)); } SwaggerService swaggerService; SwaggerParserContext context; if (!s_detectJsonRegex.IsMatch(source.Text)) { // parse YAML var yamlDeserializer = new DeserializerBuilder() .IgnoreUnmatchedProperties() .WithNamingConvention(new OurNamingConvention()) .Build(); using (var stringReader = new StringReader(source.Text)) { try { swaggerService = yamlDeserializer.Deserialize <SwaggerService>(stringReader); } catch (YamlException exception) { var exceptionError = exception.InnerException?.Message ?? exception.Message; const string errorStart = "): "; int errorStartIndex = exceptionError.IndexOf(errorStart, StringComparison.OrdinalIgnoreCase); if (errorStartIndex != -1) { exceptionError = exceptionError.Substring(errorStartIndex + errorStart.Length); } var exceptionPosition = new NamedTextPosition(source.Name, exception.End.Line, exception.End.Column); throw new ServiceDefinitionException(exceptionError, exceptionPosition); } } if (swaggerService == null) { throw new ServiceDefinitionException("Service definition is missing.", new NamedTextPosition(source.Name, 1, 1)); } context = SwaggerParserContext.FromYaml(source); } else { // parse JSON using (var stringReader = new StringReader(source.Text)) using (var jsonTextReader = new JsonTextReader(stringReader)) { try { swaggerService = JsonSerializer.Create(SwaggerUtility.JsonSerializerSettings).Deserialize <SwaggerService>(jsonTextReader); } catch (JsonException exception) { var exceptionPosition = new NamedTextPosition(source.Name, jsonTextReader.LineNumber, jsonTextReader.LinePosition); throw new ServiceDefinitionException(exception.Message, exceptionPosition); } context = SwaggerParserContext.FromJson(source); } } return(ConvertSwaggerService(swaggerService, context)); }
private void AddServiceDto(List <IServiceMemberInfo> members, string name, SwaggerSchema schema, SwaggerService swaggerService, NamedTextPosition position) { var attributes = new List <ServiceAttributeInfo>(); if (schema.Obsolete.GetValueOrDefault()) { attributes.Add(new ServiceAttributeInfo("obsolete")); } var fields = new List <ServiceFieldInfo>(); foreach (var property in schema.Properties.EmptyIfNull()) { var fieldAttributes = new List <ServiceAttributeInfo>(); if (property.Value.Obsolete.GetValueOrDefault()) { fieldAttributes.Add(new ServiceAttributeInfo("obsolete")); } string typeName = swaggerService.TryGetFacilityTypeName(property.Value, position); if (typeName != null) { fields.Add(new ServiceFieldInfo( property.Key, typeName: typeName, attributes: fieldAttributes, summary: PrepareSummary(property.Value.Description), position: position)); } } members.Add(new ServiceDtoInfo( name: name, fields: fields, attributes: attributes, summary: PrepareSummary(schema.Description), remarks: SplitRemarks(schema.Remarks), position: position)); }
public FsdRemarksSection(string name, IReadOnlyList <string> lines, NamedTextPosition position) { Name = name; Lines = lines; Position = position; }
/// <summary> /// Parses an FSD file into a service definition. /// </summary> public ServiceInfo ParseDefinition(NamedText source) { IReadOnlyList <string> definitionLines = null; var remarksSections = new Dictionary <string, FsdRemarksSection>(StringComparer.OrdinalIgnoreCase); // read remarks after definition using (var reader = new StringReader(source.Text)) { string name = null; var lines = new List <string>(); int lineNumber = 0; int headingLineNumber = 0; while (true) { string line = reader.ReadLine(); lineNumber++; Match match = line == null ? null : s_markdownHeading.Match(line); if (match == null || match.Success) { if (name == null) { definitionLines = lines; } else { while (lines.Count != 0 && string.IsNullOrWhiteSpace(lines[0])) { lines.RemoveAt(0); } while (lines.Count != 0 && string.IsNullOrWhiteSpace(lines[lines.Count - 1])) { lines.RemoveAt(lines.Count - 1); } var position = new NamedTextPosition(source.Name, headingLineNumber, 1); if (remarksSections.ContainsKey(name)) { throw new ServiceDefinitionException("Duplicate remarks heading: " + name, position); } remarksSections.Add(name, new FsdRemarksSection(name, lines, position)); } if (match == null) { break; } name = line.Substring(match.Index + match.Length).Trim(); lines = new List <string>(); headingLineNumber = lineNumber; } else { lines.Add(line); } } } source = new NamedText(source.Name, string.Join("\n", definitionLines)); ServiceInfo service; try { service = FsdParsers.ParseDefinition(source, remarksSections); } catch (ParseException exception) { var expectation = exception .Result .GetNamedFailures() .Distinct() .GroupBy(x => x.Position) .Select(x => new { LineColumn = x.Key.GetLineColumn(), Names = x.Select(y => y.Name) }) .OrderByDescending(x => x.LineColumn.LineNumber) .ThenByDescending(x => x.LineColumn.ColumnNumber) .First(); throw new ServiceDefinitionException( "expected " + string.Join(" or ", expectation.Names.Distinct().OrderBy(GetExpectationNameRank).ThenBy(x => x, StringComparer.Ordinal)), new NamedTextPosition(source.Name, expectation.LineColumn.LineNumber, expectation.LineColumn.ColumnNumber), exception); } // check for unused remarks sections foreach (var remarksSection in remarksSections.Values) { string sectionName = remarksSection.Name; if (service.Name != sectionName && service.FindMember(sectionName) == null) { throw new ServiceDefinitionException($"Unused remarks heading: {sectionName}", remarksSection.Position); } } return(service); }
internal static SwaggerResponse ResolveResponse(this SwaggerService swaggerService, SwaggerResponse swaggerResponse, NamedTextPosition position) { if (swaggerResponse.Ref != null) { const string refPrefix = "#/responses/"; if (!swaggerResponse.Ref.StartsWith(refPrefix, StringComparison.Ordinal)) { throw new ServiceDefinitionException("Response $ref must start with '#/responses/'.", position); } string name = UnescapeRefPart(swaggerResponse.Ref.Substring(refPrefix.Length)); if (!swaggerService.Responses.TryGetValue(name, out swaggerResponse)) { throw new ServiceDefinitionException($"Missing response named '{name}'.", position); } } return(swaggerResponse); }
internal static KeyValuePair <string, SwaggerSchema> ResolveDefinition(this SwaggerService swaggerService, SwaggerSchema swaggerDefinition, NamedTextPosition position) { string name = null; if (swaggerDefinition.Ref != null) { name = GetDefinitionNameFromRef(swaggerDefinition.Ref, position); if (!swaggerService.Definitions.TryGetValue(name, out swaggerDefinition)) { throw new ServiceDefinitionException($"Missing definition named '{name}'.", position); } } return(new KeyValuePair <string, SwaggerSchema>(name, swaggerDefinition)); }
public void FullPosition() { var position = new NamedTextPosition("source", 3, 14); position.ToString().ShouldBe("source(3,14)"); }
private void AddRequestFields(IList <ServiceFieldInfo> requestFields, SwaggerParameter swaggerParameter, string serviceMethodName, string httpMethod, SwaggerService swaggerService, NamedTextPosition position) { string kind = swaggerParameter.In; if (kind == SwaggerParameterKind.Path || kind == SwaggerParameterKind.Query || kind == SwaggerParameterKind.Header) { string typeName = swaggerService.TryGetFacilityTypeName(swaggerParameter, position); if (typeName != null) { if (typeName.EndsWith("[]", StringComparison.Ordinal)) { typeName = "string"; } var attributes = new List <ServiceAttributeInfo>(); if (swaggerParameter.Obsolete.GetValueOrDefault()) { attributes.Add(new ServiceAttributeInfo("obsolete")); } string fieldName = swaggerParameter.Identifier ?? swaggerParameter.Name; if (!ServiceDefinitionUtility.IsValidName(fieldName)) { fieldName = CodeGenUtility.ToCamelCase(fieldName); } if (kind == SwaggerParameterKind.Query) { var parameters = new List <ServiceAttributeParameterInfo>(); if (httpMethod != "GET") { parameters.Add(new ServiceAttributeParameterInfo("from", "query")); } if (fieldName != swaggerParameter.Name) { parameters.Add(new ServiceAttributeParameterInfo("name", swaggerParameter.Name)); } if (parameters.Count != 0) { attributes.Add(new ServiceAttributeInfo("http", parameters)); } } else if (kind == SwaggerParameterKind.Header) { attributes.Add(new ServiceAttributeInfo("http", new[] { new ServiceAttributeParameterInfo("from", "header"), new ServiceAttributeParameterInfo("name", swaggerParameter.Name), })); } requestFields.Add(new ServiceFieldInfo( fieldName, typeName: typeName, attributes: attributes, summary: PrepareSummary(swaggerParameter.Description), position: position)); } } else if (kind == SwaggerParameterKind.Body) { var bodySchema = swaggerService.ResolveDefinition(swaggerParameter.Schema, position); if ((bodySchema.Value.Type ?? SwaggerSchemaType.Object) == SwaggerSchemaType.Object && (bodySchema.Key == null || bodySchema.Key.Equals(serviceMethodName + "Request", StringComparison.OrdinalIgnoreCase))) { AddFieldsFromSchema(requestFields, swaggerService, position, bodySchema); } else { string typeName = bodySchema.Key ?? SwaggerUtility.FilterBodyTypeName(swaggerService.TryGetFacilityTypeName(bodySchema.Value, position)); if (typeName != null) { requestFields.Add(new ServiceFieldInfo( bodySchema.Value.Identifier ?? "body", typeName: typeName, attributes: new[] { new ServiceAttributeInfo("http", new[] { new ServiceAttributeParameterInfo("from", "body", position) }) }, summary: PrepareSummary(swaggerParameter.Description), position: position)); } } } }
public void SourceNameOnly() { var position = new NamedTextPosition("source"); position.ToString().ShouldBe("source"); }
private void AddResponseFields(IList <ServiceFieldInfo> responseFields, string statusCode, SwaggerResponse swaggerResponse, string serviceMethodName, IList <ServiceAttributeParameterInfo> httpAttributeValues, bool isOnlyResponse, SwaggerService swaggerService, NamedTextPosition position) { var bodySchema = default(KeyValuePair <string, SwaggerSchema>); if (swaggerResponse.Schema != null) { bodySchema = swaggerService.ResolveDefinition(swaggerResponse.Schema, position); } if (bodySchema.Value != null && (bodySchema.Value.Type ?? SwaggerSchemaType.Object) == SwaggerSchemaType.Object && (bodySchema.Key == null || bodySchema.Key.Equals(serviceMethodName + "Response", StringComparison.OrdinalIgnoreCase))) { httpAttributeValues.Add(new ServiceAttributeParameterInfo("code", statusCode, position)); AddFieldsFromSchema(responseFields, swaggerService, position, bodySchema); } else if (swaggerResponse.Identifier == null && isOnlyResponse && swaggerResponse.Schema == null) { httpAttributeValues.Add(new ServiceAttributeParameterInfo("code", statusCode, position)); } else { responseFields.Add(new ServiceFieldInfo( swaggerResponse.Identifier ?? CodeGenUtility.ToCamelCase(bodySchema.Key) ?? GetBodyFieldNameForStatusCode(statusCode), typeName: bodySchema.Key ?? (bodySchema.Value != null ? SwaggerUtility.FilterBodyTypeName(swaggerService.TryGetFacilityTypeName(bodySchema.Value, position)) : null) ?? "boolean", attributes: new[] { new ServiceAttributeInfo("http", new[] { new ServiceAttributeParameterInfo("from", "body", position), new ServiceAttributeParameterInfo("code", statusCode, position), }) }, summary: PrepareSummary(swaggerResponse.Description), position: position)); } }
public void InvalidNameThrows() { var position = new NamedTextPosition("source"); TestUtility.ThrowsServiceDefinitionException(() => new ServiceDtoInfo(name: "4u", position: position), position); }
internal static string TryGetFacilityTypeName(this SwaggerService swaggerService, ISwaggerSchema swaggerSchema, NamedTextPosition position) { switch (swaggerSchema.Type ?? SwaggerSchemaType.Object) { case SwaggerSchemaType.String: return(swaggerSchema.Format == SwaggerSchemaTypeFormat.Byte ? "bytes" : "string"); case SwaggerSchemaType.Number: return(swaggerSchema.Format == SwaggerSchemaTypeFormat.Decimal ? "decimal" : "double"); case SwaggerSchemaType.Integer: return(swaggerSchema.Format == SwaggerSchemaTypeFormat.Int64 ? "int64" : "int32"); case SwaggerSchemaType.Boolean: return("boolean"); case SwaggerSchemaType.Array: return(swaggerSchema.Items?.Type == SwaggerSchemaType.Array ? null : $"{swaggerService.TryGetFacilityTypeName(swaggerSchema.Items, position)}[]"); case SwaggerSchemaType.Object: var fullSchema = swaggerSchema as SwaggerSchema; if (fullSchema != null) { if (fullSchema.Ref != null) { var resolvedSchema = swaggerService.ResolveDefinition(fullSchema, position); if (swaggerService.IsFacilityError(resolvedSchema)) { return("error"); } string resultOfType = swaggerService.TryGetFacilityResultOfType(resolvedSchema, position); if (resultOfType != null) { return($"result<{resultOfType}>"); } return(resolvedSchema.Key); } if (fullSchema.AdditionalProperties != null) { return($"map<{swaggerService.TryGetFacilityTypeName(fullSchema.AdditionalProperties, position)}>"); } } return("object"); } return(null); }