@autorest/go
Version:
AutoRest Go Generator
214 lines • 8.96 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as m4 from '@autorest/codemodel';
import { values } from '@azure-tools/linq';
// aggregates the Parameter in op.parameters and the first request
export function aggregateParameters(op) {
let params = new Array();
if (op.parameters) {
params = params.concat(op.parameters);
}
// Loop through each request in an operation to account for all parameters in the initial naming transform.
// After the transform stage, operations will only have one request and the loop will always traverse only
// one request per operation.
for (const req of values(op.requests)) {
if (req.parameters) {
params = params.concat(req.parameters);
}
}
return params;
}
// returns ArraySchema type predicate if the schema is an ArraySchema
export function isArraySchema(resp) {
return resp.type === m4.SchemaType.Array;
}
// returns DictionarySchema type predicate if the schema is a DictionarySchema
export function isDictionarySchema(resp) {
return resp.type === m4.SchemaType.Dictionary;
}
// returns SchemaResponse type predicate if the response has a schema
export function isSchemaResponse(resp) {
return resp.schema !== undefined;
}
// returns BinaryResponse type predicate if the response is a binary response
export function isBinaryResponse(resp) {
return resp.binary !== undefined;
}
// returns true if the operation is pageable
export function isPageableOperation(op) {
return op.language.go.paging !== undefined;
}
// returns true if the operation is a long-running operation
export function isLROOperation(op) {
return op.extensions?.['x-ms-long-running-operation'] === true;
}
// returns ObjectSchema type predicate if the schema is an ObjectSchema
export function isObjectSchema(obj) {
return obj.type === m4.SchemaType.Object;
}
// returns the additional properties schema if the ObjectSchema defines 'additionalProperties'
export function hasAdditionalProperties(obj) {
for (const parent of values(obj.parents?.immediate)) {
if (parent.type === m4.SchemaType.Dictionary) {
return parent;
}
}
return undefined;
}
// returns true if the object contains a property that's a discriminated type
export function hasPolymorphicField(obj) {
for (const prop of values(obj.properties)) {
if (isObjectSchema(prop.schema)) {
if (prop.schema.discriminator !== undefined) {
return true;
}
}
else if (isArraySchema(prop.schema) && isObjectSchema(prop.schema.elementType)) {
if (prop.schema.elementType.discriminator !== undefined) {
return true;
}
}
else if (isDictionarySchema(prop.schema) && isObjectSchema(prop.schema.elementType)) {
if (prop.schema.elementType.discriminator !== undefined) {
return true;
}
}
}
return false;
}
// returns the schema response for this operation.
// calling this on multi-response operations will result in an error.
export function getSchemaResponse(op) {
if (!op.responses) {
return undefined;
}
// get the list and count of distinct schema responses
const schemaResponses = new Array();
for (const response of values(op.responses)) {
// perform the comparison by name as some responses have different objects for the same underlying response type
if (isSchemaResponse(response) && !values(schemaResponses).where(sr => sr.schema.language.go.name === response.schema.language.go.name).any()) {
schemaResponses.push(response);
}
}
if (schemaResponses.length === 0) {
return undefined;
}
else if (schemaResponses.length === 1) {
return schemaResponses[0];
}
// multiple schema responses, for LROs find the best fit.
if (!isLROOperation(op)) {
throw new Error('getSchemaResponse() called for multi-response operation');
}
// for LROs, there are a couple of corner-cases we need to handle WRT response types.
// 1. 200 Foo / 20x Bar - we take Foo and display a warning
// 2. 201 Foo / 202 Bar - this is a hard error
// 3. 200 void / 20x Bar - we take Bar
// since we always assume responses[0] has the return type we need to fix up
// the list of responses so that it points to the schema we select.
// multiple schemas, find the one for 200 status code
// note that case #3 was handled earlier
let with200;
for (const response of values(schemaResponses)) {
if (response.protocol.http.statusCodes.indexOf('200') > -1) {
with200 = response;
break;
}
}
if (with200 === undefined) {
// case #2
throw new Error(`LRO ${op.language.go.clientName}.${op.language.go.name} contains multiple response types which is not supported`);
}
// case #1
// TODO: log warning
return with200;
}
// returns true if the operation returns multiple response types
export function isMultiRespOperation(op) {
// treat LROs as single-response ops
if (!op.responses || op.responses.length === 1 || isLROOperation(op)) {
return false;
}
// count the number of distinct schemas returned by this operation
const schemaResponses = new Array();
for (const response of values(op.responses)) {
// perform the comparison by name as some responses have different objects for the same underlying response type
if (isSchemaResponse(response) && !values(schemaResponses).where(sr => sr.schema.language.go.name === response.schema.language.go.name).any()) {
schemaResponses.push(response);
}
}
return schemaResponses.length > 1;
}
// returns the BinaryResponse if the operation returns a binary response or undefined.
// throws an error if called on a multi-response operation.
export function isBinaryResponseOperation(op) {
if (!op.responses) {
return undefined;
}
else if (isMultiRespOperation(op)) {
throw new Error('isBinaryResponseOperation() called for multi-response operation');
}
if (isBinaryResponse(op.responses[0])) {
return op.responses[0];
}
return undefined;
}
// returns true if the type is implicitly passed by value (map, slice, etc)
export function isTypePassedByValue(schema) {
if (schema.type === m4.SchemaType.Any ||
schema.type === m4.SchemaType.AnyObject ||
schema.type === m4.SchemaType.Array ||
schema.type === m4.SchemaType.ByteArray ||
schema.type === m4.SchemaType.Binary ||
schema.type === m4.SchemaType.Dictionary ||
(isObjectSchema(schema) && schema.discriminator)) {
return true;
}
return false;
}
// returns a Go-formatted constant value
export function formatConstantValue(schema) {
// null check must come before any type checks
if (schema.value.value === null) {
return 'nil';
}
else if (schema.valueType.type === m4.SchemaType.String) {
return `"${schema.value.value}"`;
}
return schema.value.value;
}
// aggregate the properties from the provided type and its parent types
export function aggregateProperties(obj) {
const allProps = new Array();
for (const prop of values(obj.properties)) {
allProps.push(prop);
}
for (const parent of values(obj.parents?.all)) {
if (isObjectSchema(parent)) {
for (const parentProp of values(parent.properties)) {
// ensure that the parent doesn't contain any properties with the same name but different type
const exists = values(allProps).where(p => { return p.language.go.name === parentProp.language.go.name; }).first();
if (exists) {
if (exists.schema.language.go.name !== parentProp.schema.language.go.name) {
const msg = `type ${obj.language.go.name} contains duplicate property ${exists.language.go.name} with mismatched types`;
throw new Error(msg);
}
// don't add the duplicate
continue;
}
allProps.push(parentProp);
}
}
}
return allProps;
}
// returns the leaf element type for an array or dictionary
export function recursiveUnwrapArrayDictionary(item) {
if (isArraySchema(item.elementType) || isDictionarySchema(item.elementType)) {
return recursiveUnwrapArrayDictionary(item.elementType);
}
return item.elementType;
}
//# sourceMappingURL=helpers.js.map