UNPKG

@autorest/powershell

Version:
508 lines 25.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Helper = void 0; /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ const schema_1 = require("../utils/schema"); const codemodel_1 = require("@autorest/codemodel"); const linq_1 = require("@azure-tools/linq"); const codegen_1 = require("@azure-tools/codegen"); class Helper { constructor(useDateTimeOffset = false) { this.useDateTimeOffset = useDateTimeOffset; } HasConstrains(schema) { if (schema.minimum !== undefined || schema.maximum !== undefined || schema.maxLength !== undefined || schema.minLength !== undefined || schema.maxItems !== undefined || schema.minItems !== undefined || schema.multipleOf !== undefined || schema.pattern !== undefined || schema.uniqueItems !== undefined) { return true; } return false; } HasConstantProperty(schema) { const virtualProperties = this.GetAllPublicVirtualProperties(schema.language.default.virtualProperties); return virtualProperties.filter(p => p.required && (p.property.schema.type === codemodel_1.SchemaType.Constant || this.IsConstantEnumProperty(p) || (p.property.schema.type === codemodel_1.SchemaType.Object && this.HasConstantProperty(p.property.schema)))).length > 0; } GetCsharpType(schema) { let type = schema.type; if (schema.type === codemodel_1.SchemaType.Integer || schema.type === codemodel_1.SchemaType.Number) { type = type + schema.precision; } const offset = this.useDateTimeOffset ? 'Offset' : ''; const typeMap = new Map([ ['integer', 'int'], ['integer32', 'int'], ['integer64', 'long'], ['number32', 'double'], ['number64', 'double'], ['number128', 'decimal'], ['boolean', 'bool'], ['string', 'string'], ['unixtime', 'System.DateTime'], ['credential', 'string'], ['byte-array', 'byte[]'], ['duration', 'System.TimeSpan'], ['uuid', 'System.Guid'], ['date-time', 'System.DateTime' + offset], ['date', 'System.DateTime'], ['binary', 'string'], ['uri', 'string'], ['arm-id', 'string'] ]); if (typeMap.has(type)) { return typeMap.get(type); } return ''; } isArraySchema(schema) { return schema.type === codemodel_1.SchemaType.Array; } isDictionarySchema(schema) { return schema.type === codemodel_1.SchemaType.Dictionary; } ShouldValidate(schema) { if (!schema) { return false; } const typesToValidate = new Array(); const validatedTypes = new Set(); typesToValidate.push(schema); while (typesToValidate.length > 0) { const modelToValidate = typesToValidate.pop(); if (!modelToValidate) { continue; } else { if (validatedTypes.has(modelToValidate)) { continue; } validatedTypes.add(modelToValidate); if (this.isArraySchema(modelToValidate) || this.isDictionarySchema(modelToValidate)) { typesToValidate.push(modelToValidate.elementType); } else if ((0, codemodel_1.isObjectSchema)(modelToValidate)) { const virtualProperties = modelToValidate.extensions && modelToValidate.extensions['x-ms-azure-resource'] ? (0, schema_1.getAllPublicVirtualPropertiesForSdkWithoutInherited)(modelToValidate.language.default.virtualProperties) : (0, schema_1.getAllPublicVirtualPropertiesForSdk)(modelToValidate.language.default.virtualProperties); (0, linq_1.values)(virtualProperties).where(p => (0, codemodel_1.isObjectSchema)(p.property.schema)).forEach(cp => typesToValidate.push(cp.property.schema)); if ((0, linq_1.values)(virtualProperties).any(p => (p.required && p.property.schema.type !== codemodel_1.SchemaType.Constant && !this.IsConstantEnumProperty(p)) || this.HasConstrains(p.property.schema))) { return true; } } } } return false; } appendConstraintValidations(valueReference, sb, model) { const schema = model; if (schema.maximum !== undefined) { const rule = schema.exclusiveMaximum ? 'ExclusiveMaximum' : 'InclusiveMaximum'; const cmp = schema.exclusiveMaximum ? '>=' : '>'; sb.push(`if (${valueReference} ${cmp} ${schema.maximum})`); sb.push('{'); sb.push(` throw new Microsoft.Rest.ValidationException(Microsoft.Rest.ValidationRules.${rule}, "${valueReference.replace('this.', '')}", ${schema.maximum});`); sb.push('}'); } if (schema.minimum !== undefined) { const rule = schema.exclusiveMinimum ? 'ExclusiveMinimum' : 'InclusiveMinimum'; const cmp = schema.exclusiveMinimum ? '<=' : '<'; sb.push(`if (${valueReference} ${cmp} ${schema.minimum})`); sb.push('{'); sb.push(` throw new Microsoft.Rest.ValidationException(Microsoft.Rest.ValidationRules.${rule}, "${valueReference.replace('this.', '')}", ${schema.minimum});`); sb.push('}'); } if (schema.maxItems !== undefined) { sb.push(`if (${valueReference}.Count > ${schema.maxItems})`); sb.push('{'); sb.push(` throw new Microsoft.Rest.ValidationException(Microsoft.Rest.ValidationRules.MaxItems, "${valueReference.replace('this.', '')}", ${schema.maxItems});`); sb.push('}'); } if (schema.maxLength !== undefined) { sb.push(`if (${valueReference}.Length > ${schema.maxLength})`); sb.push('{'); sb.push(` throw new Microsoft.Rest.ValidationException(Microsoft.Rest.ValidationRules.MaxLength, "${valueReference.replace('this.', '')}", ${schema.maxLength});`); sb.push('}'); } if (schema.minLength !== undefined) { sb.push(`if (${valueReference}.Length < ${schema.minLength})`); sb.push('{'); sb.push(` throw new Microsoft.Rest.ValidationException(Microsoft.Rest.ValidationRules.MinLength, "${valueReference.replace('this.', '')}", ${schema.minLength});`); sb.push('}'); } if (schema.minItems !== undefined) { sb.push(`if (${valueReference}.Count < ${schema.minItems})`); sb.push('{'); sb.push(` throw new Microsoft.Rest.ValidationException(Microsoft.Rest.ValidationRules.MinItems, "${valueReference.replace('this.', '')}", ${schema.minItems});`); sb.push('}'); } if (schema.multipleOf !== undefined) { sb.push(`if (${valueReference} % ${schema.multipleOf} != 0)`); sb.push('{'); sb.push(` throw new Microsoft.Rest.ValidationException(Microsoft.Rest.ValidationRules.MultipleOf, "${valueReference.replace('this.', '')}", ${schema.multipleOf});`); sb.push('}'); } if (schema.pattern !== undefined) { // eslint-disable-next-line const constraintValue = "\"" + schema.pattern.replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + "\""; let condition = `!System.Text.RegularExpressions.Regex.IsMatch(${valueReference}, ${constraintValue})`; if (schema.type === codemodel_1.SchemaType.Dictionary) { condition = `!System.Linq.Enumerable.All(${valueReference}.Values, value => System.Text.RegularExpressions.Regex.IsMatch(value, ${constraintValue}))`; } sb.push(`if (${condition})`); sb.push('{'); sb.push(` throw new Microsoft.Rest.ValidationException(Microsoft.Rest.ValidationRules.Pattern, "${valueReference.replace('this.', '')}", ${constraintValue});`); sb.push('}'); } if (schema.uniqueItems !== undefined && 'true' === schema.uniqueItems.toString()) { sb.push(`if (${valueReference}.Count != System.Linq.Enumerable.Count(System.Linq.Enumerable.Distinct(${valueReference})))`); sb.push('{'); sb.push(` throw new Microsoft.Rest.ValidationException(Microsoft.Rest.ValidationRules.UniqueItems, "${valueReference.replace('this.', '')}");`); sb.push('}'); } } isKindOfString(schema, required = false) { var _a; if (schema.type === codemodel_1.SchemaType.String) { return true; } else if (schema.type === codemodel_1.SchemaType.Constant && schema.valueType.type === codemodel_1.SchemaType.String) { return true; } else if (schema.type === codemodel_1.SchemaType.Choice && schema.choiceType.type === codemodel_1.SchemaType.String) { return true; } else if (schema.type === codemodel_1.SchemaType.SealedChoice && schema.choiceType.type === codemodel_1.SchemaType.String && (((_a = schema.extensions) === null || _a === void 0 ? void 0 : _a['x-ms-model-as-string']) === true || (required && schema.choices.length === 1))) { return true; } // ToDo: we need to figure how to handle the case when schema type is enum // Skip it since there is a bug in IsKindOfString in the csharp generator // if (schema.type === SchemaType.Choice && (<ChoiceSchema>schema).choiceType.type === SchemaType.String) { // return true; // } // if (schema.type === SchemaType.SealedChoice // && (<ChoiceSchema>schema).choiceType.type === SchemaType.String) { // // currently assume modelAsString true // return true; // } return false; } PathParameterString(parameter, clientPrefix) { var _a; if (!['path', 'query'].includes((_a = parameter.protocol.http) === null || _a === void 0 ? void 0 : _a.in)) { return ''; } const prefix = parameter.implementation === 'Client' ? `this${clientPrefix}.` : ''; let res = ''; if (this.isKindOfString(parameter.schema, parameter.required)) { res = `${prefix}${parameter.language.default.name}`; } else { let serializationSettings = `this${clientPrefix}.SerializationSettings`; if (this.IsValueType(parameter.schema.type)) { if (parameter.schema.type === codemodel_1.SchemaType.Date) { serializationSettings = 'new Microsoft.Rest.Serialization.DateJsonConverter()'; } else if (parameter.schema.type === codemodel_1.SchemaType.DateTime && parameter.schema.format === 'date-time-rfc1123') { serializationSettings = 'new Microsoft.Rest.Serialization.DateTimeRfc1123JsonConverter()'; } else if (parameter.schema.type === codemodel_1.SchemaType.Uri) { serializationSettings = 'new Microsoft.Rest.Serialization.Base64UrlJsonConverter()'; } else if (parameter.schema.type === codemodel_1.SchemaType.UnixTime) { serializationSettings = 'new Microsoft.Rest.Serialization.UnixTimeJsonConverter()'; } } res = `Microsoft.Rest.Serialization.SafeJsonConvert.SerializeObject(${prefix}${parameter.language.default.name}, ${serializationSettings}).Trim('"')`; } if (parameter.extensions && parameter.extensions['x-ms-skip-url-encoding']) { return res; } else { return `System.Uri.EscapeDataString(${res})`; } } ValidateType(schema, scope, valueReference, isNullable, indentation = 3) { const indentationSpaces = ' '.repeat(indentation); const sb = new Array(); if (!scope) { throw new Error('scope is null'); } if (!!schema && (0, codemodel_1.isObjectSchema)(schema) && this.ShouldValidateChain(schema)) { sb.push(`${valueReference}.Validate();`); } if (this.HasConstrains(schema)) { this.appendConstraintValidations(valueReference, sb, schema); } if (schema && this.isArraySchema(schema) && this.ShouldValidateChain(schema)) { // ToDo: Should try to get a unique name instead of element let elementVar = 'element'; if (valueReference.startsWith(elementVar)) { elementVar = valueReference + '1'; } const innerValidation = this.ValidateType(schema.elementType, scope, elementVar, true, 1); if (innerValidation) { sb.push(`foreach (var ${elementVar} in ${valueReference})`); sb.push('{'); innerValidation.split('\r\n').map(str => sb.push(str)); sb.push('}'); } } else if (schema && this.isDictionarySchema(schema) && this.ShouldValidateChain(schema)) { // ToDo: Should try to get a unique name instead of valueElement let valueVar = 'valueElement'; if (valueReference.startsWith(valueVar)) { valueVar = valueReference + '1'; } const innerValidation = this.ValidateType(schema.elementType, scope, valueVar, true, 1); if (innerValidation) { sb.push(`foreach (var ${valueVar} in ${valueReference}.Values)`); sb.push('{'); innerValidation.split('\r\n').map(str => sb.push(str)); sb.push('}'); } } if (sb.length > 0) { if (this.IsValueType(schema.type) && !isNullable) { return sb.map(str => indentationSpaces + str).join('\r\n'); } else { return `${indentationSpaces}if (${valueReference} != null)\r\n${indentationSpaces}{\r\n${sb.map(str => indentationSpaces + ' ' + str).join('\r\n')}\r\n${indentationSpaces}}`; } } return ''; } ShouldValidateChain(schema) { if (!schema) { return false; } const typesToValidate = new Array(); const validatedTypes = new Set(); typesToValidate.push(schema); while (typesToValidate.length > 0) { const modelToValidate = typesToValidate.pop(); if (!modelToValidate) { continue; } else { validatedTypes.add(modelToValidate); if (this.isArraySchema(modelToValidate) || this.isDictionarySchema(modelToValidate)) { typesToValidate.push(modelToValidate.elementType); } else if ((0, codemodel_1.isObjectSchema)(modelToValidate)) { if (this.ShouldValidate(modelToValidate)) { return true; } if (modelToValidate.parents && (modelToValidate.parents.immediate.length === 1 && !(modelToValidate.extensions && modelToValidate.extensions['x-ms-azure-resource']))) { typesToValidate.push(modelToValidate.parents.immediate[0]); } } } } return false; } GetDeserializationSettings(schema, ref) { if (schema.type === codemodel_1.SchemaType.Date) { return 'new Microsoft.Rest.Serialization.DateJsonConverter()'; } else if (schema.type === codemodel_1.SchemaType.Uri) { return 'new Microsoft.Rest.Serialization.Base64UrlJsonConverter()'; } else if (schema.type === codemodel_1.SchemaType.UnixTime) { return 'new Microsoft.Rest.Serialization.UnixTimeJsonConverter()'; } return ref + '.DeserializationSettings'; } GetSerializationSettings(schema, ref) { if (schema.type === codemodel_1.SchemaType.Date) { return 'new Microsoft.Rest.Serialization.DateJsonConverter()'; } else if (schema.type === codemodel_1.SchemaType.Uri) { return 'new Microsoft.Rest.Serialization.Base64UrlJsonConverter()'; } else if (schema.type === codemodel_1.SchemaType.UnixTime) { return 'new Microsoft.Rest.Serialization.UnixTimeJsonConverter()'; } return ref + '.SerializationSettings'; } IsNullCheckRequiredForVirtualProperty(virtualProperty) { return !((this.IsValueType(virtualProperty.property.schema.type) || (virtualProperty.property.schema.type === codemodel_1.SchemaType.SealedChoice && (virtualProperty.property.schema.choiceType.type !== codemodel_1.SchemaType.String || (virtualProperty.property.schema.extensions && !virtualProperty.property.schema.extensions['x-ms-model-as-string'])))) && (virtualProperty.required || virtualProperty.property.nullable === false)); } CamelCase(str) { // str = str.replace(/(?:^\w|[A-Z]|\b\w)/g, function (word, index) { // return index === 0 ? word.toLowerCase() : word.toUpperCase(); // }).replace(/\s+/g, ''); return (0, codegen_1.camelCase)(str); } PascalCase(str) { return (0, codegen_1.pascalCase)(str); } GetAllPublicVirtualProperties(virtualProperties) { return (0, schema_1.getAllPublicVirtualPropertiesForSdk)(virtualProperties); } GetAllPublicVirtualPropertiesWithoutInherited(virtualProperties) { return (0, schema_1.getAllPublicVirtualPropertiesForSdkWithoutInherited)(virtualProperties); } NeedsTransformationConverter(object) { for (const property of (0, linq_1.values)(object.properties)) { if (property.extensions && property.extensions['x-ms-client-flatten']) { return true; } } return false; } IsValueType(type) { if (['boolean', 'integer', 'number', 'unixtime', 'duration', 'uuid', 'date-time', 'date'].includes(type)) { return true; } return false; } HandleConstParameters(operation) { const result = new Array(); const bodyParameters = operation.requests && operation.requests.length > 0 ? (operation.requests[0].parameters || []).filter(each => each.protocol.http && each.protocol.http.in === 'body' && !(each.extensions && each.extensions['x-ms-client-flatten']) && each.implementation !== 'Client') : []; const nonBodyParameters = operation.parameters ? operation.parameters.filter(each => each.implementation !== 'Client') : []; const parameters = [...nonBodyParameters, ...bodyParameters].filter(each => this.IsConstantEnumParameter(each)); for (const parameter of (0, linq_1.values)(parameters)) { const quote = parameter.schema.choiceType.type === codemodel_1.SchemaType.String ? '"' : ''; const csharpType = this.GetCsharpType((parameter.schema).choiceType); result.push(` ${csharpType} ${parameter.language.default.name} = ${quote}${parameter.schema.choices[0].value}${quote};`); } return result.join('\r\n'); } IsConstantEnumParameter(parameter) { if (!parameter.required) { // const parameters are always required return false; } // skip parameter.schema.type === SchemaType.Constant, since there is a bug if ((parameter.schema.type === codemodel_1.SchemaType.SealedChoice && (parameter.schema).choices.length === 1) || (parameter.schema.type === codemodel_1.SchemaType.Choice && (parameter.schema).choices.length === 1)) { return true; } return false; } IsConstantParameter(parameter) { if (this.IsConstantEnumParameter(parameter)) { return true; } if (parameter.schema.type === codemodel_1.SchemaType.Constant) { return true; } return false; } IsConstantEnumProperty(property) { if (!property.required) { // const parameters are always required return false; } // skip parameter.schema.type === SchemaType.Constant, since there is a bug if ((property.property.schema.type === codemodel_1.SchemaType.SealedChoice && (property.property.schema).choices.length === 1) || (property.property.schema.type === codemodel_1.SchemaType.Choice && (property.property.schema).choices.length === 1)) { return true; } return false; } IsConstantProperty(property) { if (this.IsConstantEnumProperty(property)) { return true; } if (property.property.schema.type === codemodel_1.SchemaType.Constant) { return true; } return false; } GetUniqueName(name, usedNames) { let uniqueName = name; let i = 0; while (usedNames.includes(uniqueName)) { uniqueName = `${name}${++i}`; } return uniqueName; } GetValidCsharpName(name) { let validChars = name.replace(/[^a-zA-Z0-9_]/g, ''); // prepend '_' if the name starts with a digit if (!/^[a-zA-Z_]/.test(validChars)) { validChars = '_' + validChars; } return validChars; } IsEnum(schema) { if (schema.type === codemodel_1.SchemaType.SealedChoice && schema.choiceType.type === codemodel_1.SchemaType.String && schema.extensions && !schema.extensions['x-ms-model-as-string']) { return true; } return false; } ConvertToValidMethodGroupKey(key) { return key.replace(/Operations$/, ''); } isCloudErrorName(name) { // This is to work around the fact that some CloudError will be generated as CloudErrorAutoGenerated in m4 const reg = new RegExp('^CloudErrorAutoGenerated\\d{0,1}$'); if (name === 'CloudError' || reg.test(name)) { return true; } return false; } IsCloudErrorException(operation) { return (!operation.exceptions || !operation.exceptions[0].schema || this.isCloudErrorName(operation.exceptions[0].schema.language.default.name)); } PopulateGroupParameters(parameter) { var _a; const groupParameter = parameter.language.default.name; const result = Array(); for (const virtualProperty of (0, linq_1.values)((parameter.schema.language.default.virtualProperties.owned))) { let type = ((_a = virtualProperty.property.schema.language.csharp) === null || _a === void 0 ? void 0 : _a.fullname) || ''; type = (this.IsValueType(virtualProperty.property.schema.type) || (virtualProperty.property.schema.type === codemodel_1.SchemaType.SealedChoice && virtualProperty.property.schema.choiceType.type === codemodel_1.SchemaType.String && virtualProperty.property.schema.extensions && !virtualProperty.property.schema.extensions['x-ms-model-as-string'])) && !virtualProperty.required ? `${type}?` : type; const CamelName = (0, codegen_1.camelCase)(virtualProperty.name); result.push(` ${type} ${CamelName} = default(${type});`); result.push(` if (${groupParameter} != null)`); result.push(' {'); result.push(` ${CamelName} = ${groupParameter}.${(0, codegen_1.pascalCase)(CamelName)};`); result.push(' }'); } if (result.length > 0) { return result.join('\r\n'); } return ''; } wrapComments(indentation, prefix, comments) { const defaultMaximumCommentColumns = 80; if (comments === null || comments === undefined || comments.length === 0) { return ''; } //cannot predict indentation because we cannot get last line generated const length = defaultMaximumCommentColumns - prefix.length - 1; const result = this.lineBreak(comments, length); for (let i = 0; i < result.length; i++) { if (i != 0) { result[i] = prefix + result[i]; } } return result.join('\n' + indentation); } lineBreak(comments, length) { const splitter = /\r\n|\r|\n/i; const lines = new Array(); for (const line of comments.split(splitter)) { let processedLine = line; while (processedLine.length > 0) { processedLine = processedLine.trim(); const whiteSpacePositions = [...new Array(processedLine.length).keys()].filter(i => /\s/.test(processedLine[i])).concat([processedLine.length]); let preWidthWrapAt = 0; let postWidthWrapAt = 0; for (const index of whiteSpacePositions) { if (index <= length) { preWidthWrapAt = index; } else if (postWidthWrapAt === 0) { postWidthWrapAt = index; } } const wrapAt = preWidthWrapAt != 0 ? preWidthWrapAt : (postWidthWrapAt != 0 ? postWidthWrapAt : processedLine.length); lines.push(processedLine.substring(0, wrapAt)); processedLine = processedLine.substring(wrapAt); } } return lines; } } exports.Helper = Helper; //# sourceMappingURL=utility.js.map