powershell/llcsharp/schema/schema-resolver.ts (122 lines of code) (raw):
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { codeModelSchema, CredentialSchema, ArraySchema, UnixTimeSchema, CodeModel, Schema as NewSchema, StringSchema, BooleanSchema, NumberSchema, ByteArraySchema, DateTimeSchema, ObjectSchema, GroupSchema, isObjectSchema, SchemaType, GroupProperty, ParameterLocation, Operation, Parameter, VirtualParameter, getAllProperties, ImplementationLocation, OperationGroup, Request, SchemaContext, ConstantSchema, ChoiceSchema, DurationSchema, BinarySchema, DateSchema } from '@autorest/codemodel';
import { codemodel, IntegerFormat, NumberFormat, StringFormat, JsonType } from '@azure-tools/codemodel-v3';
import { Schema } from '../code-model';
import * as message from '../messages';
import { ArrayOf } from './array';
import { Binary } from './binary';
import { Boolean } from './boolean';
import { ByteArray } from './byte-array';
import { FixedArrayOf } from './fixed-array';
import { Char } from './char';
import { Date } from './date';
import { DateTime, DateTime1123, UnixTime } from './date-time';
import { Duration } from './duration';
import { EnumImplementation } from './enum';
import { Numeric } from './integer';
import { ObjectImplementation } from './object';
import { String } from './string';
import { Uri } from './uri';
import { Uuid } from './Uuid';
import { EnhancedTypeDeclaration } from './extended-type-declaration';
import { PwshModel } from '../../utils/PwshModel';
import { ModelState } from '../../utils/model-state';
import { Channel, AutorestExtensionHost as Host, Session, startSession } from '@autorest/extension-base';
import { schemaHasEnum } from '../validations';
import { Password } from './password';
export class SchemaDefinitionResolver {
private readonly cache = new Map<string, EnhancedTypeDeclaration>();
private fixedArrayConfig: boolean;
private add(schema: NewSchema, value: EnhancedTypeDeclaration): EnhancedTypeDeclaration {
this.cache.set(schema.language?.csharp?.fullname || '', value);
return value;
}
constructor(fixedArrayConfig: boolean) {
this.fixedArrayConfig = fixedArrayConfig;
}
// isFixedArray is used to determine if we want to use a fixed array or not
resolveTypeDeclaration(schema: NewSchema | undefined, required: boolean, state: ModelState<CodeModel>, isFixedArray?: boolean): EnhancedTypeDeclaration {
if (!schema) {
throw new Error('SCHEMA MISSING?');
}
// determine if we need a new model class for the type or just a known type object
switch (schema.type) {
case SchemaType.Array: {
// can be recursive!
// handle boolean arrays as booleans (powershell will try to turn it into switches!)
const ar = <ArraySchema>schema;
const elementType = (ar.elementType.type === SchemaType.Boolean) ? new Boolean(<BooleanSchema>schema, true) : this.resolveTypeDeclaration(ar.elementType, true, state.path('items'), this.fixedArrayConfig);
if (isFixedArray) {
return new FixedArrayOf(schema, required, elementType, ar.minItems, ar.maxItems, ar.uniqueItems);
} else {
return new ArrayOf(schema, required, elementType, ar.minItems, ar.maxItems, ar.uniqueItems);
}
}
case SchemaType.Any:
case SchemaType.Dictionary:
case SchemaType.Object: {
const result = schema.language.csharp && this.cache.get(schema.language.csharp.fullname || '');
if (result) {
return result;
}
return this.add(schema, new ObjectImplementation(<ObjectSchema>schema));
}
case SchemaType.Time:
case SchemaType.ArmId:
case SchemaType.String: {
return new String(<StringSchema>schema, required);
}
case SchemaType.Credential: {
return new Password(<CredentialSchema>schema, required);
}
case SchemaType.Binary:
return new Binary(<BinarySchema>schema, required);
case SchemaType.Duration:
return new Duration(<DurationSchema>schema, required);
case SchemaType.Uri:
return new Uri(<StringSchema>schema, required);
case SchemaType.Uuid:
return new Uuid(<StringSchema>schema, required);
case SchemaType.DateTime:
if ((<DateTimeSchema>schema).format === StringFormat.DateTimeRfc1123) {
return new DateTime1123(<DateTimeSchema>schema, required);
}
return new DateTime(<DateTimeSchema>schema, required);
case SchemaType.Date:
return new Date(<DateSchema>schema, required);
case SchemaType.ByteArray:
return new ByteArray(<ByteArraySchema>schema, required);
case SchemaType.Boolean:
return new Boolean(<BooleanSchema>schema, required);
case SchemaType.Integer:
switch ((<NumberSchema>schema).precision) {
case 64:
return new Numeric(<NumberSchema>schema, required, required ? 'long' : 'long?');
// skip-for-time-being
// case IntegerFormat.UnixTime:
// return new UnixTime(schema, required);
case 16:
case 32:
return new Numeric(<NumberSchema>schema, required, required ? 'int' : 'int?');
}
// fallback to int if the format isn't recognized
return new Numeric(<NumberSchema>schema, required, required ? 'int' : 'int?');
case SchemaType.UnixTime:
return new UnixTime(<UnixTimeSchema>schema, required);
case SchemaType.Number:
switch ((<NumberSchema>schema).precision) {
case 64:
return new Numeric(<NumberSchema>schema, required, required ? 'double' : 'double?');
case 32:
return new Numeric(<NumberSchema>schema, required, required ? 'float' : 'float?');
case 128:
return new Numeric(<NumberSchema>schema, required, required ? 'decimal' : 'decimal?');
}
// fallback to float if the format isn't recognized
return new Numeric(<NumberSchema>schema, required, required ? 'float' : 'float?');
case SchemaType.Constant:
return this.resolveTypeDeclaration((<ConstantSchema>schema).valueType, required, state);
case SchemaType.Choice:
case SchemaType.SealedChoice: {
return this.resolveTypeDeclaration((<ChoiceSchema>schema).choiceType, required, state);
}
case undefined:
if (schema.extensions && schema.extensions['x-ms-enum']) {
return this.resolveTypeDeclaration((<ChoiceSchema>schema).choiceType, required, state);
}
// "any" case
// this can happen when a model is just an all-of something else. (sub in the other type?)
break;
}
state.error(`Schema '${schema.language.csharp?.name}' is declared with invalid type '${schema.type}'`, message.UnknownJsonType);
throw new Error('Unknown Model. Fatal.');
}
}