diff --git a/powershell/internal/project.ts b/powershell/internal/project.ts index 4878ced8f6..7724490d74 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 { BooleanSchema, Schema as NewSchema, SchemaType } from '@azure-tools/codemodel'; +import { BooleanSchema, ConstantSchema, Schema as NewSchema, SchemaType } from '@azure-tools/codemodel'; export type Schema = T.SchemaT, LanguageDetails>; @@ -72,7 +72,7 @@ export class NewPSSchemaResolver extends NewSchemaDefinitionResolver { try { if (!this.inResolve) { this.inResolve = true; - if (schema && schema.type === SchemaType.Boolean) { + if (schema && (schema.type === SchemaType.Boolean || (schema.type === SchemaType.Constant && (schema).valueType.type === SchemaType.Boolean))) { return new NewPSSwitch(schema, required); } } diff --git a/powershell/llcsharp/schema/date-time.ts b/powershell/llcsharp/schema/date-time.ts index 165b1095f6..f09cf4940b 100644 --- a/powershell/llcsharp/schema/date-time.ts +++ b/powershell/llcsharp/schema/date-time.ts @@ -11,7 +11,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 { Schema as NewSchema, DateTimeSchema, UnixTimeSchema } from '@azure-tools/codemodel'; +import { Schema as NewSchema, DateTimeSchema, UnixTimeSchema, DateSchema } from '@azure-tools/codemodel'; import { Primitive, NewPrimitive } from './primitive'; export class DateTime extends Primitive { @@ -183,7 +183,7 @@ export class NewDateTime extends NewPrimitive { } return (`/* serializeToContainerMember doesn't support '${mediaType}' ${__filename}*/`); } - constructor(schema: DateTimeSchema, public isRequired: boolean) { + constructor(schema: DateTimeSchema | DateSchema, public isRequired: boolean) { super(schema); } // public static string DateFormat = "yyyy-MM-dd"; diff --git a/powershell/llcsharp/schema/date.ts b/powershell/llcsharp/schema/date.ts index 0b231bd8b8..62de87bcdf 100644 --- a/powershell/llcsharp/schema/date.ts +++ b/powershell/llcsharp/schema/date.ts @@ -5,7 +5,7 @@ import { StringExpression } from '@azure-tools/codegen-csharp'; import { Schema } from '../code-model'; -import { Schema as NewSchema, DateTimeSchema } from '@azure-tools/codemodel'; +import { DateSchema } from '@azure-tools/codemodel'; import { DateTime, NewDateTime } from './date-time'; export class Date extends DateTime { @@ -17,7 +17,7 @@ export class Date extends DateTime { export class NewDate extends NewDateTime { public DateTimeFormat = new StringExpression('yyyy-MM-dd'); - constructor(schema: DateTimeSchema, isRequired: boolean) { + constructor(schema: DateSchema, isRequired: boolean) { super(schema, isRequired); } } \ No newline at end of file diff --git a/powershell/llcsharp/schema/schema-resolver.ts b/powershell/llcsharp/schema/schema-resolver.ts index 3c724ad42f..b62f79a998 100644 --- a/powershell/llcsharp/schema/schema-resolver.ts +++ b/powershell/llcsharp/schema/schema-resolver.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { codeModelSchema, ArraySchema, 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 } from '@azure-tools/codemodel'; +import { codeModelSchema, ArraySchema, 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 '@azure-tools/codemodel'; import { ModelState, codemodel, IntegerFormat, NumberFormat, StringFormat, JsonType } from '@azure-tools/codemodel-v3'; import { Schema } from '../code-model'; @@ -189,6 +189,8 @@ export class NewSchemaDefinitionResolver { return new NewString(schema, required); } + case SchemaType.Binary: + return new NewBinary(schema, required); case SchemaType.Duration: return new NewDuration(schema, required); case SchemaType.Uuid: @@ -198,6 +200,8 @@ export class NewSchemaDefinitionResolver { return new NewDateTime1123(schema, required); } return new NewDateTime(schema, required); + case SchemaType.Date: + return new NewDate(schema, required); case SchemaType.ByteArray: return new NewByteArray(schema, required); case SchemaType.Boolean: @@ -210,6 +214,7 @@ export class NewSchemaDefinitionResolver { // skip-for-time-being // case IntegerFormat.UnixTime: // return new UnixTime(schema, required); + case 16: case 32: return new NewNumeric(schema, required, required ? 'int' : 'int?'); } @@ -229,18 +234,8 @@ export class NewSchemaDefinitionResolver { return new NewNumeric(schema, required, required ? 'float' : 'float?'); case SchemaType.Constant: - switch ((schema).valueType.type) { - case SchemaType.String: - return new NewString(schema, required); - case SchemaType.DateTime: - if ((schema).valueType.format === StringFormat.DateTimeRfc1123) { - return new NewDateTime1123(schema, required); - } - return new NewDateTime(schema, required); - default: - state.error(`Unsupported constant type. Schema '${schema.language.csharp?.name}' is declared with invalid type '${schema.type}'`, message.UnknownJsonType); - throw new Error('Unknown Model. Fatal.'); - } + return this.resolveTypeDeclaration((schema).valueType, required, state); + case SchemaType.Choice: { const choiceSchema = schema as ChoiceSchema; if ((choiceSchema.choiceType).type === SchemaType.DateTime && (choiceSchema.choiceType).format === StringFormat.DateTimeRfc1123) { @@ -263,4 +258,4 @@ export class NewSchemaDefinitionResolver { state.error(`Schema '${schema.language.csharp?.name}' is declared with invalid type '${schema.type}'`, message.UnknownJsonType); throw new Error('Unknown Model. Fatal.'); } -} \ No newline at end of file +} diff --git a/powershell/models/model-extensions.ts b/powershell/models/model-extensions.ts index 2c3051d2e6..2f0e682375 100644 --- a/powershell/models/model-extensions.ts +++ b/powershell/models/model-extensions.ts @@ -284,57 +284,6 @@ export class NewModelExtensionsNamespace extends Namespace { continue; } - if (schema.type === SchemaType.Dictionary) { - // xichen: - // Case1: dictionary schema is only used in parents: - // "definitions": { - // "PetAPInPropertiesWithAPString": { - // "type": "object", - // "properties": { - // "id": { - // "type": "integer" - // } - // }, - // "additionalProperties": { - // "type": "string" - // } - // } - // } - // - // Case2: we will have a dictionary property: - // "definitions": { - // "PetAPInProperties": { - // "type": "object", - // "properties": { - // "id": { - // "type": "integer" - // }, - // "additionalProperties": { - // "type": "object", - // "additionalProperties": { - // "type": "number" - // } - // } - // } - // } - // } - // - // We only create model class for case 2, because in m3 case 2 will has independent scheam for additionalProperties, - // But for case 1, PetAPInPropertiesWithAPString will only have additionalProperties. - // - // This is to make generated code same as m3. Actually there wont be side effect if we skip this check. - const objSchemas = schemas['objects']; - const usedByProp = schemas['objects']?.some((objSchema) => { - if ((objSchema).properties?.some((prop) => prop.schema === schema)) { - return true; - } - return false; - }); - if (!usedByProp) { - continue; - } - } - const td = this.resolver.resolveTypeDeclaration(schema, true, state); if (td instanceof NewObjectImplementation) { diff --git a/powershell/plugins/create-commands-v2.ts b/powershell/plugins/create-commands-v2.ts index ca67a3e219..25f558d4d7 100644 --- a/powershell/plugins/create-commands-v2.ts +++ b/powershell/plugins/create-commands-v2.ts @@ -287,8 +287,8 @@ export /* @internal */ class Inferrer { })); // let's add a variant where it's expanded out. - // *IF* the body is an object - if (body.schema.type === SchemaType.Object) { + // *IF* the body is an object or dictionary + if (body.schema.type === SchemaType.Object || body.schema.type === SchemaType.Dictionary) { const opExpanded = await this.addCommandOperation(`${vname}Expanded`, parameters, operation, variant, state); opExpanded.details.default.dropBodyParameter = true; opExpanded.parameters.push(new IParameter(`${bodyParameterName}Body`, body.schema, { diff --git a/powershell/plugins/cs-namer-v2.ts b/powershell/plugins/cs-namer-v2.ts index d5c9ac4e34..3443cd53c7 100644 --- a/powershell/plugins/cs-namer-v2.ts +++ b/powershell/plugins/cs-namer-v2.ts @@ -179,14 +179,14 @@ async function setOperationNames(state: State, resolver: NewSchemaDefinitionReso operation.language.csharp = { ...details, // inherit - name: getPascalIdentifier(operationName), + name: operationName, }; // parameters are camelCased. for (const parameter of values(operation.parameters)) { const parameterDetails = parameter.language.default; - let propName = camelCase(fixLeadingNumber(deconstruct(parameterDetails.name))); + let propName = camelCase(fixLeadingNumber(deconstruct(parameterDetails.serializedName))); if (propName === 'default') { propName = '@default'; diff --git a/powershell/plugins/plugin-tweak-m4-model.ts b/powershell/plugins/plugin-tweak-m4-model.ts index 3bf59ab1ca..d3e54b796a 100644 --- a/powershell/plugins/plugin-tweak-m4-model.ts +++ b/powershell/plugins/plugin-tweak-m4-model.ts @@ -2,7 +2,7 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CodeModel, DictionarySchema, getAllProperties, HttpHeader, ObjectSchema, Property, Schema, SchemaType } from '@azure-tools/codemodel'; +import { ArraySchema, CodeModel, DictionarySchema, getAllProperties, HttpHeader, ObjectSchema, Property, Schema, SchemaType } from '@azure-tools/codemodel'; import { serialize } from '@azure-tools/codegen'; import { PwshModel } from '../utils/PwshModel'; import { NewModelState } from '../utils/model-state'; @@ -19,7 +19,7 @@ async function tweakModel(state: State): Promise { addDictionaryApiVersion(model); - removeDictionaryDefaultDescription(model); + removeM4DefaultDescription(model); return model; } @@ -80,7 +80,17 @@ function addResponseHeaderSchema(model: CodeModel) { } function addDictionaryApiVersion(model: CodeModel) { - // If object has dictionary property, this property's schema does not have api version information in m4. We should add this back. + + model.schemas.dictionaries?.forEach((schema) => { + if (schema.apiVersions) { + return; + } + if (schema.elementType && schema.elementType.apiVersions) { + schema.apiVersions = JSON.parse(JSON.stringify(schema.elementType.apiVersions)); + } + }) + + // If we cannot find api version from element type, try to get it from object schema who refers the dict or any. model.schemas.objects?.forEach((schema) => { if (!schema.apiVersions) { @@ -88,54 +98,55 @@ function addDictionaryApiVersion(model: CodeModel) { } for (const prop of getAllProperties(schema)) { - if ((prop.schema.type !== SchemaType.Dictionary && prop.schema.type !== SchemaType.Any) || prop.schema.apiVersions) { + if (prop.schema.type !== SchemaType.Dictionary || prop.schema.apiVersions) { continue; } - const dictSchema = prop.schema as DictionarySchema; - if (dictSchema.elementType && dictSchema.elementType.apiVersions) { - dictSchema.apiVersions = JSON.parse(JSON.stringify(dictSchema.elementType.apiVersions)); - } else { - dictSchema.apiVersions = JSON.parse(JSON.stringify(schema.apiVersions)); - } + prop.schema.apiVersions = JSON.parse(JSON.stringify(schema.apiVersions)); } }) } -function removeDictionaryDefaultDescription(model: CodeModel) { - // For dictionary schema and property, if there is no description assigned, m4 will set a default description like: Dictionary of +function removeM4DefaultDescription(model: CodeModel) { + // For dictionary and arrya schema and property, if there is no description assigned, m4 will set a default description like: Dictionary of or Array of // To keep same action as m3, we will set it to empty string const visited = new Set(); - [...model.schemas.objects ?? [], ...model.schemas.dictionaries ?? []].forEach((schema) => { - recursiveRemoveDefaultDescription(schema, visited); + [...model.schemas.objects ?? [], ...model.schemas.dictionaries ?? [], ...model.schemas.arrays ?? []].forEach((schema) => { + recursiveRemoveM4DefaultDescription(schema, visited); }) } -function recursiveRemoveDefaultDescription(schema: Schema, visited: Set) { - if (visited.has(schema) || (schema.type !== SchemaType.Object && schema.type !== SchemaType.Dictionary)) { +function recursiveRemoveM4DefaultDescription(schema: Schema, visited: Set) { + if (visited.has(schema) || (schema.type !== SchemaType.Object && schema.type !== SchemaType.Dictionary && schema.type !== SchemaType.Array)) { return; } // Default description pattern in m4 - const defaultDescPattern = /Dictionary of <.*>$/; + const defaultDictDescPattern = /Dictionary of <.?>$/; + const defaultArrayDescPattern = /Array of .?$/; visited.add(schema); if (schema.type === SchemaType.Dictionary) { const dictSchema = schema as DictionarySchema; - recursiveRemoveDefaultDescription(dictSchema.elementType, visited); - if (defaultDescPattern.test(dictSchema.language.default.description)) { + recursiveRemoveM4DefaultDescription(dictSchema.elementType, visited); + if (defaultDictDescPattern.test(dictSchema.language.default.description)) { dictSchema.language.default.description = ''; } + } else if (schema.type === SchemaType.Array) { + const arrSchema = schema as ArraySchema; + recursiveRemoveM4DefaultDescription(arrSchema.elementType, visited); + if (defaultArrayDescPattern.test(schema.language.default.description)) { + schema.language.default.description = ''; + } } else if (schema.type === SchemaType.Object) { const objSchema = schema as ObjectSchema; for (const prop of getAllProperties(objSchema)) { - recursiveRemoveDefaultDescription(prop.schema, visited); - if (prop.schema.type === SchemaType.Dictionary && defaultDescPattern.test(prop.language.default.description)) { + recursiveRemoveM4DefaultDescription(prop.schema, visited); + if (prop.schema.type === SchemaType.Dictionary && (defaultDictDescPattern.test(prop.language.default.description) || defaultArrayDescPattern.test(prop.language.default.description))) { prop.language.default.description = ''; } } } } - export async function tweakM4ModelPlugin(service: Host) { const state = await new NewModelState(service).init(); service.WriteFile('code-model-v4-tweakm4codemodel.yaml', serialize(await tweakModel(state)), undefined, 'code-model-v4'); diff --git a/powershell/plugins/plugin-tweak-model.ts b/powershell/plugins/plugin-tweak-model.ts index 4b09be1481..5171af771d 100644 --- a/powershell/plugins/plugin-tweak-model.ts +++ b/powershell/plugins/plugin-tweak-model.ts @@ -2,7 +2,7 @@ * 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, StringSchema, ObjectSchema, GroupSchema, isObjectSchema, SchemaType, GroupProperty, ParameterLocation, Operation, Parameter, VirtualParameter, getAllProperties, ImplementationLocation, OperationGroup, Request, SchemaContext, ChoiceSchema, Scheme, Schema } 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, ConstantSchema } 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, KnownMediaType } from '@azure-tools/codegen'; @@ -99,7 +99,7 @@ async function tweakModelV2(state: State): Promise { for (const operation of values(group.operations)) { for (const param of values(operation.parameters).where(each => each.protocol?.http?.in === ParameterLocation.Path)) { const name = param.language.default.name; - const hasName = universalId.properties?.find((prop) => prop.language.default.name === name); + const hasName = universalId.properties?.find((prop) => prop.language.default.name.toLocaleLowerCase() === name.toLocaleLowerCase()); if (!hasName) { if (!universalId.properties) { universalId.properties = []; @@ -277,10 +277,15 @@ async function tweakModelV2(state: State): Promise { for (const group of values(model.operationGroups)) { for (const operation of values(group.operations)) { for (const parameter of values(operation.parameters)) { - if (parameter.required && parameter.schema instanceof ChoiceSchema) { - const choiceSchema = parameter.schema as ChoiceSchema; - if (choiceSchema.choices.length === 1) { - parameter.language.default.constantValue = choiceSchema.choices[0].value; + if (parameter.required) { + if (parameter.schema.type === SchemaType.Choice) { + const choiceSchema = parameter.schema as ChoiceSchema; + if (choiceSchema.choices.length === 1) { + parameter.language.default.constantValue = choiceSchema.choices[0].value; + } + } else if (parameter.schema.type === SchemaType.Constant) { + const constantSchema = parameter.schema as ConstantSchema; + parameter.language.default.constantValue = constantSchema.value.value; } } } @@ -290,12 +295,17 @@ async function tweakModelV2(state: State): Promise { // identify properties that are constants for (const schema of values(schemas.objects)) { for (const property of values(schema.properties)) { - if (property.required && property.schema instanceof ChoiceSchema) { - const choiceSchema = property.schema as ChoiceSchema; - if (choiceSchema.choices.length === 1) { - // properties with an enum single value are constants - // add the constant value - property.language.default.constantValue = choiceSchema.choices[0].value; + if (property.required) { + if (property.schema.type === SchemaType.Choice) { + const choiceSchema = property.schema as ChoiceSchema; + if (choiceSchema.choices.length === 1) { + // properties with an enum single value are constants + // add the constant value + property.language.default.constantValue = choiceSchema.choices[0].value; + } + } else if (property.schema.type === SchemaType.Constant) { + const constantSchema = property.schema as ConstantSchema; + property.language.default.constantValue = constantSchema.value.value; } } } diff --git a/tests-upgrade/Configuration.json b/tests-upgrade/Configuration.json index 5c27182b76..380e8a9c98 100644 --- a/tests-upgrade/Configuration.json +++ b/tests-upgrade/Configuration.json @@ -37,7 +37,8 @@ "extension-ms-paramlocation", "directive-aliasremoval", "directive-cmdlet", - "directive-parameter" + "directive-parameter", + "datamodels-datatypes-file" ], "BlackList": [ "basic-get-querystr",