Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support header #648

Merged
merged 5 commits into from
Aug 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions powershell/autorest-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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'
```
2 changes: 1 addition & 1 deletion powershell/enums/namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion powershell/internal/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<SchemaDetails>, LanguageDetails<PropertyDetails>>;

Expand Down
22 changes: 11 additions & 11 deletions powershell/llcsharp/model/model-class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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(<Schema>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);
Expand Down
5 changes: 5 additions & 0 deletions powershell/llcsharp/model/namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,11 @@ export class NewModelsNamespace extends Namespace {
this.NewResolveTypeDeclaration(schema, true, <NewState>state);
}
}
if (schemas.sealedChoices) {
for (const schema of schemas.sealedChoices) {
this.NewResolveTypeDeclaration(schema, true, <NewState>state);
}
}
//todo, need to add support for other types

}
Expand Down
4 changes: 3 additions & 1 deletion powershell/llcsharp/operation/api-class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 2 additions & 6 deletions powershell/llcsharp/operation/method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -359,11 +358,8 @@ export class NewOperationMethod extends Method {
}

for (const response of [...values(this.operation.responses), ...values(this.operation.exceptions)]) {

const responseType = (<SchemaResponse>response).schema ? state.project.modelsNamespace.NewResolveTypeDeclaration(<NewSchema>((<SchemaResponse>response).schema), true, state) : null;
//skip-for-time-being
//const headerType = response.headerSchema ? state.project.modelsNamespace.NewResolveTypeDeclaration(<Schema>response.headerSchema, true, state) : null;
const headerType = null;
const headerType = response.language.default.headerSchema ? state.project.modelsNamespace.NewResolveTypeDeclaration(<NewSchema>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);
Expand Down Expand Up @@ -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;
}
Expand Down
3 changes: 1 addition & 2 deletions powershell/llcsharp/schema/schema-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ export class NewSchemaDefinitionResolver {
}
return this.add(schema, new NewObjectImplementation(<ObjectSchema>schema));
}
case SchemaType.SealedChoice:
case SchemaType.String: {
return new NewString(<StringSchema>schema, required);

Expand Down Expand Up @@ -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']) {
Expand Down
6 changes: 3 additions & 3 deletions powershell/llcsharp/schema/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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 = (<SealedChoiceSchema>this.schema).choices.map((c) => c.value);
return `await ${eventListener}.AssertEnum(${nameof(property.value)},${property},${choiceValues.joinWith((v) => `@"${v}"`)});`;
}
}
2 changes: 2 additions & 0 deletions powershell/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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);
Expand Down
5 changes: 3 additions & 2 deletions powershell/plugins/cs-namer-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@ async function setOperationNames(state: State, resolver: NewSchemaDefinitionReso
// per responseCode
const response = <SchemaResponse>rsp;
const responseTypeDefinition = response.schema ? resolver.resolveTypeDeclaration(<any>response.schema, true, state) : undefined;
// const headerTypeDefinition = response.headerSchema ? resolver.resolveTypeDeclaration(<any>response.headerSchema, true, state.path('schemas', response.headerSchema.details.default.name)) : undefined;
const headerSchema = response.language.default.headerSchema;
const headerTypeDefinition = headerSchema ? resolver.resolveTypeDeclaration(<any>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' || '') {
Expand All @@ -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]}`))),
Expand Down
83 changes: 83 additions & 0 deletions powershell/plugins/plugin-tweak-m4-model.ts
Original file line number Diff line number Diff line change
@@ -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<PwshModel>;

async function tweakModel(state: State): Promise<PwshModel> {
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<HttpHeader>;
if (headers === undefined) {
return;
}

const responseCode = resp.protocol.http?.statusCodes?.[0];
if (responseCode === undefined) {
return;
}

// Follow naming pattern in m3
const code = ((<any>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<PwshModel>(service).init();
await service.WriteFile('code-model-v4-tweakm4codemodel.yaml', serialize(await tweakModel(state)), undefined, 'code-model-v4');
}
Loading