diff --git a/powershell/autorest-configuration.md b/powershell/autorest-configuration.md index 6eca7c67537..4ed72061ef5 100644 --- a/powershell/autorest-configuration.md +++ b/powershell/autorest-configuration.md @@ -119,8 +119,14 @@ pipeline: input: tweakcodemodel # --- extension powershell based on modelerfour - tweakcodemodel-v2: + + # Fix the code model gap between m3 and m4 + tweakm4codemodel: input: modelerfour/identity + + tweakcodemodel-v2: + input: tweakm4codemodel + # input: clicommon/identity tweakcodemodelazure-v2: input: tweakcodemodel-v2 @@ -446,4 +452,17 @@ verb-mapping: Write: Write ``` - +``` yaml +cli: + reason: 'Keep same as modelerfour' + naming: + default: + parameter: 'camel' + property: 'camel' + operation: 'pascal' + operationGroup: 'pascal' + choice: 'pascal' + choiceValue: 'pascal' + constant: 'pascal' + type: 'pascal' +``` \ No newline at end of file diff --git a/powershell/enums/namespace.ts b/powershell/enums/namespace.ts index 23f9f6b302a..63d3ff41670 100644 --- a/powershell/enums/namespace.ts +++ b/powershell/enums/namespace.ts @@ -130,7 +130,7 @@ export class NewEnumNamespace extends Namespace { super('Support', parent); this.apply(objectInitializer); //const enumInfos = [...state.model.schemas.sealedChoices ?? [], ...state.model.schemas.choices ?? []] - const enumInfos = [...state.model.schemas.sealedChoices || []] + const enumInfos = [...state.model.schemas.sealedChoices ?? []] .filter((choice) => !choice.language.csharp?.skip) .map((choice) => { return { diff --git a/powershell/internal/project.ts b/powershell/internal/project.ts index 0a0a071cedf..4878ced8f6f 100644 --- a/powershell/internal/project.ts +++ b/powershell/internal/project.ts @@ -17,7 +17,7 @@ import { codemodel, PropertyDetails, exportedModels as T, ModelState, JsonType, import { DeepPartial } from '@azure-tools/codegen'; import { PwshModel } from '../utils/PwshModel'; import { NewModelState } from '../utils/model-state'; -import { Schema as NewSchema, BooleanSchema, SchemaType } from '@azure-tools/codemodel'; +import { BooleanSchema, Schema as NewSchema, SchemaType } from '@azure-tools/codemodel'; export type Schema = T.SchemaT, LanguageDetails>; diff --git a/powershell/llcsharp/model/model-class.ts b/powershell/llcsharp/model/model-class.ts index c80abb95ba9..7a962bd4363 100644 --- a/powershell/llcsharp/model/model-class.ts +++ b/powershell/llcsharp/model/model-class.ts @@ -18,7 +18,7 @@ import { PropertyOriginAttribute, DoNotFormatAttribute, FormatTableAttribute } f import { Schema } from '../code-model'; import { DictionaryImplementation } from './model-class-dictionary'; import { Languages, Language, Schema as NewSchema } from '@azure-tools/codemodel'; -import { VirtualProperty as NewVirtualProperty } from '../../utils/schema'; +import { VirtualProperty as NewVirtualProperty, getAllVirtualProperties as newGetAllVirtualProperties } from '../../utils/schema'; export function getVirtualPropertyName(vp?: VirtualProperty): string { @@ -928,23 +928,23 @@ export class NewModelClass extends Class implements NewEnhancedTypeDeclaration { } } private addHeaderDeserializer() { - const avp = getAllVirtualProperties(this.schema.language.csharp?.virtualProperties); + const avp = newGetAllVirtualProperties(this.schema.language.csharp?.virtualProperties); const headers = new Parameter('headers', System.Net.Http.Headers.HttpResponseHeaders); const readHeaders = new Method(`${ClientRuntime.IHeaderSerializable}.ReadHeaders`, undefined, { access: Access.Explicit, parameters: [headers], }); - const used = false; + let used = false; - // skip-for-time-being - // for (const headerProperty of values(avp).where(each => each.property.details.csharp[HeaderProperty] === HeaderPropertyType.HeaderAndBody || each.property.details.csharp[HeaderProperty] === HeaderPropertyType.Header)) { - // used = true; - // const t = `((${headerProperty.originalContainingSchema.details.csharp.fullInternalInterfaceName})this)`; - // const values = `__${camelCase([...deconstruct(headerProperty.property.serializedName), 'Header'])}`; - // const td = this.state.project.modelsNamespace.resolveTypeDeclaration(headerProperty.property.schema, false, this.state.path('schema')); - // readHeaders.add(If(`${valueOf(headers)}.TryGetValues("${headerProperty.property.serializedName}", out var ${values})`, `${t}.${headerProperty.name} = ${td.deserializeFromContainerMember(KnownMediaType.Header, headers, values, td.defaultOfType)};`)); - // } + for (const headerProperty of values(avp).where(each => each.property.language.csharp?.[HeaderProperty] === HeaderPropertyType.HeaderAndBody || each.property.language.csharp?.[HeaderProperty] === HeaderPropertyType.Header)) { + used = true; + headerProperty.property.schema + const t = `((${headerProperty.originalContainingSchema.language.csharp?.fullInternalInterfaceName})this)`; + const values = `__${camelCase([...deconstruct(headerProperty.property.serializedName), 'Header'])}`; + const td = this.state.project.modelsNamespace.NewResolveTypeDeclaration(headerProperty.property.schema, false, this.state); + readHeaders.add(If(`${valueOf(headers)}.TryGetValues("${headerProperty.property.serializedName}", out var ${values})`, `${t}.${headerProperty.name} = ${td.deserializeFromContainerMember(KnownMediaType.Header, headers, values, td.defaultOfType)};`)); + } if (used) { this.interfaces.push(ClientRuntime.IHeaderSerializable); this.add(readHeaders); diff --git a/powershell/llcsharp/model/namespace.ts b/powershell/llcsharp/model/namespace.ts index a437aa8ce57..8f1dbe0d54b 100644 --- a/powershell/llcsharp/model/namespace.ts +++ b/powershell/llcsharp/model/namespace.ts @@ -184,6 +184,11 @@ export class NewModelsNamespace extends Namespace { this.NewResolveTypeDeclaration(schema, true, state); } } + if (schemas.sealedChoices) { + for (const schema of schemas.sealedChoices) { + this.NewResolveTypeDeclaration(schema, true, state); + } + } //todo, need to add support for other types } diff --git a/powershell/llcsharp/operation/api-class.ts b/powershell/llcsharp/operation/api-class.ts index f3045b86c00..34aa980a8be 100644 --- a/powershell/llcsharp/operation/api-class.ts +++ b/powershell/llcsharp/operation/api-class.ts @@ -57,7 +57,9 @@ export class ApiClass extends Class { for (const operation of operationGroup.operations) { const operationMethod = new NewOperationMethod(this, operation, false, state); this.addMethod(operationMethod); - if ([...values(operation.parameters).where(each => each.protocol.http?.in === ParameterLocation.Path)].length > 0) { + // Compare with m3, m4 operation has one more parameter called '$host'. We should skip it + const parameters = operation.parameters?.filter((param) => param.language.default.serializedName !== '$host'); + if ([...values(parameters).select(each => each.protocol.http?.in === ParameterLocation.Path)].length > 0) { // method has parameters in the path, so it could support '...ViaIdentity' const identityMethod = new NewOperationMethod(this, operation, true, state); identityMethod.emitCall(false); diff --git a/powershell/llcsharp/operation/method.ts b/powershell/llcsharp/operation/method.ts index 80569568164..1efd7117ed6 100644 --- a/powershell/llcsharp/operation/method.ts +++ b/powershell/llcsharp/operation/method.ts @@ -346,7 +346,6 @@ export class NewOperationMethod extends Method { this.description = this.operation.language.csharp?.description || ''; // add body paramter if there should be one. - // skip-for-time-being if (this.operation.requests && this.operation.requests.length && this.operation.requests[0].parameters && this.operation.requests[0].parameters.length) { // this request does have a request body. const param = this.operation.requests[0].parameters[0]; @@ -359,11 +358,8 @@ export class NewOperationMethod extends Method { } for (const response of [...values(this.operation.responses), ...values(this.operation.exceptions)]) { - const responseType = (response).schema ? state.project.modelsNamespace.NewResolveTypeDeclaration(((response).schema), true, state) : null; - //skip-for-time-being - //const headerType = response.headerSchema ? state.project.modelsNamespace.NewResolveTypeDeclaration(response.headerSchema, true, state) : null; - const headerType = null; + const headerType = response.language.default.headerSchema ? state.project.modelsNamespace.NewResolveTypeDeclaration(response.language.default.headerSchema, true, state) : null; const newCallbackParameter = new NewCallbackParameter(response.language.csharp?.name || '', responseType, headerType, this.state, { description: response.language.csharp?.description }); this.addParameter(newCallbackParameter); this.callbacks.push(newCallbackParameter); @@ -473,7 +469,7 @@ export class NewOperationMethod extends Method { // content length is set when the request body is set continue; } - yield hp.serializeToContainerMember(KnownMediaType.Header, new LocalVariable('request.Headers', dotnet.Var), hp.param.language.csharp?.name || hp.param.language.default.name, ClientRuntime.SerializationMode.None); + yield hp.serializeToContainerMember(KnownMediaType.Header, new LocalVariable('request.Headers', dotnet.Var), hp.param.language.csharp?.serializedName || hp.param.language.default.serializedName, ClientRuntime.SerializationMode.None); } yield EOL; } diff --git a/powershell/llcsharp/schema/schema-resolver.ts b/powershell/llcsharp/schema/schema-resolver.ts index 0885d402d7e..6a9faa67bee 100644 --- a/powershell/llcsharp/schema/schema-resolver.ts +++ b/powershell/llcsharp/schema/schema-resolver.ts @@ -181,6 +181,7 @@ export class NewSchemaDefinitionResolver { } return this.add(schema, new NewObjectImplementation(schema)); } + case SchemaType.SealedChoice: case SchemaType.String: { return new NewString(schema, required); @@ -226,8 +227,6 @@ export class NewSchemaDefinitionResolver { throw new Error('Unknown Model. Fatal.'); } case SchemaType.Choice: - return new NewString(schema, required); - case SchemaType.SealedChoice: return new NewEnumImplementation(schema, required); case undefined: if (schema.extensions && schema.extensions['x-ms-enum']) { diff --git a/powershell/llcsharp/schema/string.ts b/powershell/llcsharp/schema/string.ts index 8d8316e78fe..b49b4ac7b43 100644 --- a/powershell/llcsharp/schema/string.ts +++ b/powershell/llcsharp/schema/string.ts @@ -12,7 +12,7 @@ import { OneOrMoreStatements } from '@azure-tools/codegen-csharp'; import { Variable } from '@azure-tools/codegen-csharp'; import { ClientRuntime } from '../clientruntime'; import { Schema } from '../code-model'; -import { ChoiceSchema, Schema as NewSchema, StringSchema } from '@azure-tools/codemodel'; +import { ChoiceSchema, Schema as NewSchema, SchemaType, SealedChoiceSchema, StringSchema } from '@azure-tools/codemodel'; import { popTempVar, pushTempVar } from './primitive'; import { EnhancedTypeDeclaration, NewEnhancedTypeDeclaration } from './extended-type-declaration'; import { length } from '@azure-tools/linq'; @@ -398,10 +398,10 @@ ${this.validateEnum(eventListener, property)} return `await ${eventListener}.AssertRegEx(${nameof(property.value)},${property},@"${pattern}");`; } private validateEnum(eventListener: Variable, property: Variable): string { - if (!(this.schema instanceof ChoiceSchema)) { + if (this.schema.type !== SchemaType.SealedChoice) { return ''; } - const choiceValues = this.schema.choices.map((c) => c.value); + const choiceValues = (this.schema).choices.map((c) => c.value); return `await ${eventListener}.AssertEnum(${nameof(property.value)},${property},${choiceValues.joinWith((v) => `@"${v}"`)});`; } } diff --git a/powershell/main.ts b/powershell/main.ts index 5aa78458fc3..b8cfe84ed64 100644 --- a/powershell/main.ts +++ b/powershell/main.ts @@ -21,6 +21,7 @@ import { llcsharpV2 } from './plugins/llcsharp-v2'; import { powershellV2 } from './plugins/powershell-v2'; import { addCompleterV2 } from './plugins/add-azure-completers-v2'; import { applyModifiersV2 } from './plugins/modifiers-v2'; +import { tweakM4ModelPlugin } from './plugins/plugin-tweak-m4-model'; require('source-map-support').install(); @@ -34,6 +35,7 @@ export async function main() { pluginHost.Add('csnamer', csnamer); pluginHost.Add('llcsharp', llcsharp); // Following are plugins moved from remodeler + pluginHost.Add('tweakm4codemodel', tweakM4ModelPlugin); pluginHost.Add('tweakcodemodel-v2', tweakModelPlugin); pluginHost.Add('tweakcodemodelazure-v2', tweakModelAzurePluginV2); pluginHost.Add('create-virtual-properties-v2', createInlinedPropertiesPlugin); diff --git a/powershell/plugins/cs-namer-v2.ts b/powershell/plugins/cs-namer-v2.ts index 753d2e9338c..ac6aa0c28da 100644 --- a/powershell/plugins/cs-namer-v2.ts +++ b/powershell/plugins/cs-namer-v2.ts @@ -200,7 +200,8 @@ async function setOperationNames(state: State, resolver: NewSchemaDefinitionReso // per responseCode const response = rsp; const responseTypeDefinition = response.schema ? resolver.resolveTypeDeclaration(response.schema, true, state) : undefined; - // const headerTypeDefinition = response.headerSchema ? resolver.resolveTypeDeclaration(response.headerSchema, true, state.path('schemas', response.headerSchema.details.default.name)) : undefined; + const headerSchema = response.language.default.headerSchema; + const headerTypeDefinition = headerSchema ? resolver.resolveTypeDeclaration(headerSchema, true, state.path('schemas', headerSchema.language.default.name)) : undefined; let code = (System.Net.HttpStatusCode[response.protocol.http?.statusCodes[0]] ? System.Net.HttpStatusCode[response.protocol.http?.statusCodes[0]].value : response.protocol.http?.statusCodes[0]).replace('global::System.Net.HttpStatusCode', ''); let rawValue = code.replace(/\./, ''); if (response.protocol.http?.statusCodes[0] === 'default' || rawValue === 'default' || '') { @@ -211,7 +212,7 @@ async function setOperationNames(state: State, resolver: NewSchemaDefinitionReso response.language.csharp = { ...response.language.default, responseType: responseTypeDefinition ? responseTypeDefinition.declaration : '', - headerType: '', + headerType: headerTypeDefinition ? headerTypeDefinition.declaration : '', name: (length(response.protocol.http?.mimeTypes) <= 1) ? camelCase(fixLeadingNumber(deconstruct(`on ${code}`))) : // the common type (or the only one.) camelCase(fixLeadingNumber(deconstruct(`on ${code} ${response.protocol.http?.mimeTypes[0]}`))), diff --git a/powershell/plugins/plugin-tweak-m4-model.ts b/powershell/plugins/plugin-tweak-m4-model.ts new file mode 100644 index 00000000000..7cb8e0f7413 --- /dev/null +++ b/powershell/plugins/plugin-tweak-m4-model.ts @@ -0,0 +1,83 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import { CodeModel, HttpHeader, ObjectSchema, Property } from '@azure-tools/codemodel'; +import { serialize } from '@azure-tools/codegen'; +import { PwshModel } from '../utils/PwshModel'; +import { NewModelState } from '../utils/model-state'; +import { StatusCodes } from '../utils/http-definitions'; + +import { Host } from '@azure-tools/autorest-extension-base'; + + +type State = NewModelState; + +async function tweakModel(state: State): Promise { + const model = state.model; + + addResponseHeaderSchema(model); + + return model; +} + +function addResponseHeaderSchema(model: CodeModel) { + // In remodler, each operations response headers will has its own scheam. Each header will be schema's property. But in m4, there won't be a schema for headers. + // To keep backward compatiable, we will create headers schema here + + model.operationGroups.forEach((group) => { + group.operations?.forEach((op) => { + if (!op.responses) { + return; + } + op.responses.forEach((resp) => { + const headers = resp.protocol.http?.headers as Array; + if (headers === undefined) { + return; + } + + const responseCode = resp.protocol.http?.statusCodes?.[0]; + if (responseCode === undefined) { + return; + } + + // Follow naming pattern in m3 + const code = ((StatusCodes)[responseCode] || '') || responseCode; + const schemaName = `${group.language.default.name}_${op.language.default.name} ${code} ResponseHeaders`; + + const newSchema = model.schemas.objects?.find((schema) => schema.language.default.name === schemaName) || + new ObjectSchema(schemaName, ''); + newSchema.language.default.isHeaderModel = true; + + if (!model.schemas.objects) { + model.schemas.objects = []; + } + model.schemas.objects.push(newSchema); + + headers.forEach((head) => { + // We lost description and x-ms-client-name in m4. So newProp's description is empty and use header as serializedName + const newProp = new Property(head.header, '', head.schema, { + readOnly: false, + required: false, + serializedName: head.header + }); + newProp.language.default.HeaderProperty = 'Header'; + + if (!newSchema.properties) { + newSchema.properties = []; + } + newSchema.properties.push(newProp); + }); + + // Set response header use new schema + resp.language.default.headerSchema = newSchema; + }); + }); + }); +} + + +export async function tweakM4ModelPlugin(service: Host) { + const state = await new NewModelState(service).init(); + await service.WriteFile('code-model-v4-tweakm4codemodel.yaml', serialize(await tweakModel(state)), undefined, 'code-model-v4'); +} \ No newline at end of file diff --git a/powershell/plugins/plugin-tweak-model.ts b/powershell/plugins/plugin-tweak-model.ts index 9f94a288b98..4b09be14815 100644 --- a/powershell/plugins/plugin-tweak-model.ts +++ b/powershell/plugins/plugin-tweak-model.ts @@ -2,10 +2,10 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Property, codeModelSchema, CodeModel, Schema, StringSchema, ObjectSchema, GroupSchema, isObjectSchema, SchemaType, GroupProperty, ParameterLocation, Operation, Parameter, VirtualParameter, getAllProperties, ImplementationLocation, OperationGroup, Request, SchemaContext, ChoiceSchema } from '@azure-tools/codemodel'; +import { Property, codeModelSchema, CodeModel, StringSchema, ObjectSchema, GroupSchema, isObjectSchema, SchemaType, GroupProperty, ParameterLocation, Operation, Parameter, VirtualParameter, getAllProperties, ImplementationLocation, OperationGroup, Request, SchemaContext, ChoiceSchema, Scheme, Schema } from '@azure-tools/codemodel'; //import { ModelState } from '@azure-tools/codemodel-v3'; //import { KnownMediaType, knownMediaType, ParameterLocation, getPolymorphicBases, isSchemaObject, JsonType, Property, Schema, processCodeModel, StringFormat, codemodel, ModelState } from '@azure-tools/codemodel-v3'; -import { pascalCase, deconstruct, fixLeadingNumber, serialize } from '@azure-tools/codegen'; +import { pascalCase, deconstruct, fixLeadingNumber, serialize, KnownMediaType } from '@azure-tools/codegen'; import { items, keys, values, Dictionary, length } from '@azure-tools/linq'; import { PwshModel } from '../utils/PwshModel'; import { NewModelState } from '../utils/model-state'; @@ -13,6 +13,7 @@ import { NewModelState } from '../utils/model-state'; import { Channel, Host, Session, startSession } from '@azure-tools/autorest-extension-base'; import { defaultCipherList } from 'constants'; import { NewString } from '../llcsharp/schema/string'; +import { JsonType } from '../utils/schema'; export const HeaderProperty = 'HeaderProperty'; export enum HeaderPropertyType { @@ -76,12 +77,8 @@ async function tweakModelV2(state: State): Promise { const model = state.model; const schemas = model.schemas; - const allSchemas: Schema[] = []; - for (const prop of Object.values(schemas)) { - if (Array.isArray(prop) && prop.length > 0 && prop[0] instanceof Schema) { - allSchemas.push(...prop); - } - } + // xichen: do we need other schema types? + const allSchemas: Schema[] = [...schemas.objects ?? [], ...schemas.choices ?? [], ...schemas.sealedChoices ?? []]; model.commands = { operations: new Dictionary(), @@ -129,6 +126,133 @@ async function tweakModelV2(state: State): Promise { universalId.properties.push(idProp); } + // xichen: do nothing in m3 logic. Comment it out + // if an operation has a response that has a schema with string/binary we should make the response application/octet-stream + // for (const operationGroups of values(model.operationGroups)) { + // for (const operation of values(operationGroups.operations)) { + // for (const response of values(operation.responses)) { + // if ((response as any).schema) { + // const respSchema = response as any; + // if (respSchema.type === SchemaType.String && respSchema.format === StringFormat.Binary) { + // // WHY WAS THIS HERE?! + // // response.mimeTypes = [KnownMediaType.Stream]; + // } + // } + // } + // } + // } + + // xichen: should be no duplicate properties in m4. Skip + // schemas that have parents and implement properties that are in the parent schemas + // will have the property dropped in the child schema + // for (const schema of values(model.schemas)) { + // if (length(schema.allOf) > 0) { + // if (!dropDuplicatePropertiesInChildSchemas(schema, state)) { + // throw new Error('Schemas are in conflict.'); + // } + // } + // } + + + if (await state.getValue('use-storage-pipeline', false)) { + // we're going to create new models for the reponse headers ? + + } else { + + // if an operation has a body parameter with string/binary, we should make the request application/octet-stream + + // === Header Schemas === + // go thru the operations, find responses that have header values, and add a property to the schemas that are returned with those values + for (const operationGroups of values(model.operationGroups)) { + for (const operation of values(operationGroups.operations)) { + for (const response of values(operation.responses)) { + // for a given response, find the possible models that can be returned from the service + for (const header of values(response.protocol.http?.headers)) { + + if (!(response as any).schema) { + // no response schema? can we fake one? + // service.Message({ Channel: Channel.Debug, Text: `${header.key} is in ${operation.details.default.name} but there is no response model` }); + continue; + } + + + // if the method response has a schema and it's an object, we're going to add our properties to the schema object. + // yes, this means that the reponse model may have properties that are undefined if the server doesn't send back the header + // and other operations might add other headers that are not the same. + + // if the method's response is a primitive value (string, boolean, null, number) or an array, we can't modify that type obviously + // in which case, we're going to add a header + + // work with schemas that have objects only. + + if ((response as any).schema.type === SchemaType.Object) { + const respSchema = (response as any).schema as ObjectSchema; + const curHeader = header as any; + const headerKey = curHeader as string; + + respSchema.language.default.hasHeaders = true; + + const property = values(getAllProperties(respSchema)).first((each) => each.language.default.name === headerKey); + if (!property) { + state.message({ Channel: Channel.Debug, Text: `Adding header property '${headerKey}' to model ${respSchema.language.default.name}` }); + + // create a property for the header value + const newProperty = new Property(headerKey, curHeader.description, curHeader.schema); + newProperty.language.default.required = false; + + // mark it that it's a header-only property + newProperty.language.default[HeaderProperty] = HeaderPropertyType.Header; + + // add it to this model. + if (!respSchema.properties) { + respSchema.properties = []; + } + respSchema.properties.push(newProperty); + } else { + // there is a property with this name already. + // was this previously declared as a header only property? + if (!property.language.default[HeaderProperty]) { + + state.message({ Channel: Channel.Debug, Text: `Property ${headerKey} in model ${respSchema.language.default.name} can also come from the header.` }); + // no.. There is duplication between header and body property. Probably because of etags. + // tell it to be a header-and-body property. + property.language.default[HeaderProperty] = HeaderPropertyType.HeaderAndBody; + property.language.default.name = headerKey; + } + } + } + } + } + } + } + } + + // remove well-known header parameters from operations and add mark the operation has supporting that feature + + for (const operationGruops of values(model.operationGroups)) { + for (const operation of values(operationGruops.operations)) { + // if we have an operation with a body, and content-type is a multipart/formdata + // then we should go thru the parameters of the body and look for a string/binary parameters + // and remember to add another parameter for the filename of the string/binary + const request = operation.requests?.[0]; + request?.parameters?.filter((param) => param.schema.type !== SchemaType.Object && param.protocol.http?.in === 'body' && param.protocol.http?.style === KnownMediaType.Multipart) + .forEach((param) => { + for (const prop of values(getAllProperties(param.schema as ObjectSchema))) { + if (prop.schema.type === SchemaType.Binary) { + prop.language.default.isNamedStream = true; + } + } + }); + + // move well-known hearder parameters into details, and we can process them in the generator how we please. + // operation.details.default.headerparameters = values(operation.parameters).where(p => p.in === ParameterLocation.Header && ['If-Match', 'If-None-Match'].includes(p.name)).toArray(); + + // remove if-match and if-none-match parameters from the operation itself. + // operation.parameters = values(operation.parameters).where(p => !(p.in === ParameterLocation.Header && ['If-Match', 'If-None-Match'].includes(p.name))).toArray(); + + } + } + // identify models that are polymorphic in nature for (const schema of allSchemas) { if (schema instanceof ObjectSchema) { @@ -172,13 +296,39 @@ async function tweakModelV2(state: State): Promise { // properties with an enum single value are constants // add the constant value property.language.default.constantValue = choiceSchema.choices[0].value; - - // xichen: Do we need skip? } } } } + // xichen: Do we need skip? + // const enumsToSkip = new Set(); + // // identify properties that are constants + // for (const schema of values(model.schemas)) { + // for (const property of values(schema.properties)) { + // if (property.details.default.required && length(property.schema.enum) === 1) { + // // properties with an enum single value are constants + // // add the constant value + // property.details.default.constantValue = property.schema.enum[0]; + + // // mark as skip the generation of this model + // enumsToSkip.add(property.schema.details.default.uid); + + // // make it a string and keep its name + // property.schema = new Schema(property.schema.details.default.name, { type: property.schema.type }); + // } else { + // enumsToSkip.delete(property.schema.details.default.uid); + // } + // } + // } + + // // mark enums that shouldn't be generated + // for (const schema of values(model.schemas)) { + // if (enumsToSkip.has(schema.details.default.uid)) { + // schema.details.default.skip = true; + // } + // } + return model; } // async function tweakModel(state: State): Promise { diff --git a/powershell/utils/http-definitions.ts b/powershell/utils/http-definitions.ts new file mode 100644 index 00000000000..cbf5a9cfd79 --- /dev/null +++ b/powershell/utils/http-definitions.ts @@ -0,0 +1,44 @@ +export const StatusCodes = { + 100: 'Continue', + 101: 'SwitchingProtocols', + 200: 'OK', + 201: 'Created', + 202: 'Accepted', + 203: 'NonAuthoritativeInformation', + 204: 'NoContent', + 205: 'ResetContent', + 206: 'PartialContent', + 300: 'Ambiguous', + 301: 'Moved', + 302: 'Redirect', + 303: 'SeeOther', + 304: 'NotModified', + 305: 'UseProxy', + 306: 'Unused', + 307: 'TemporaryRedirect', + 400: 'BadRequest', + 401: 'Unauthorized', + 402: 'PaymentRequired', + 403: 'Forbidden', + 404: 'NotFound', + 405: 'MethodNotAllowed', + 406: 'NotAcceptable', + 407: 'ProxyAuthenticationRequired', + 408: 'RequestTimeout', + 409: 'Conflict', + 410: 'Gone', + 411: 'LengthRequired', + 412: 'PreconditionFailed', + 413: 'RequestEntityTooLarge', + 414: 'RequestUriTooLong', + 415: 'UnsupportedMediaType', + 416: 'RequestedRangeNotSatisfiable', + 417: 'ExpectationFailed', + 426: 'UpgradeRequired', + 500: 'InternalServerError', + 501: 'NotImplemented', + 502: 'BadGateway', + 503: 'ServiceUnavailable', + 504: 'GatewayTimeout', + 505: 'HttpVersionNotSupported' +}; \ No newline at end of file