Skip to content
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
5 changes: 4 additions & 1 deletion powershell/autorest-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,12 @@ pipeline:
# --- extension powershell based on modelerfour
tweakcodemodel-v2:
input: modelerfour/identity

tweakcodemodelazure-v2:
input: tweakcodemodel-v2

create-commands-v2:
input: tweakcodemodel-v2
input: tweakcodemodelazure-v2

create-virtual-properties-v2:
input: create-commands-v2
Expand Down
19 changes: 9 additions & 10 deletions powershell/cmdlets/class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1837,7 +1837,7 @@ export class NewCmdletClass extends Class {
name: p.language.csharp?.name,
param: values($this.properties).
where(each => each.metadata.parameterDefinition).
first(each => each.metadata.parameterDefinition.details.csharp.uid === p.language.csharp?.uid),
first(each => each.metadata.parameterDefinition.schema === p.schema),
isPathParam: $this.isViaIdentity && p.protocol.http?.in === ParameterLocation.Path
};

Expand Down Expand Up @@ -2576,7 +2576,7 @@ export class NewCmdletClass extends Class {
regularCmdletParameter.add(new Attribute(AllowEmptyCollectionAttribute));
}

NewAddInfoAttribute(regularCmdletParameter, propertyType, vParam.required, false, vParam.description, vParam.origin.name);
NewAddInfoAttribute(regularCmdletParameter, propertyType, vParam.required, false, vParam.description, origin.details.default.name);
NewAddCompleterInfo(regularCmdletParameter, vParam);
addDefaultInfo(regularCmdletParameter, vParam);

Expand All @@ -2586,16 +2586,15 @@ export class NewCmdletClass extends Class {
}

const httpParam = origin.details.csharp.httpParameter;
const uid = httpParam ? httpParam.details.csharp.uid : 'no-parameter';
//const uid = httpParam ? httpParam.details.csharp.uid : 'no-parameter';

// skip-for-time-being
// const cat = values(operation.callGraph[0].parameters).
// where(each => !(each.details.csharp.constantValue)).
// first(each => each.details.csharp.uid === uid);
const cat = values(operation.callGraph[0].parameters).
where(each => !(each.language.csharp?.constantValue)).
first(each => each.schema === httpParam.schema);

// if (cat) {
// regularCmdletParameter.add(new Attribute(CategoryAttribute, { parameters: [`${ParameterCategory}.${pascalCase(cat.in)}`] }));
// }
if (cat) {
regularCmdletParameter.add(new Attribute(CategoryAttribute, { parameters: [`${ParameterCategory}.${pascalCase((cat.protocol.http?.in))}`] }));
}


if (origin.details.csharp.completer) {
Expand Down
1 change: 0 additions & 1 deletion powershell/cmdlets/namespace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ export class NewCmdletNamespace extends Namespace {
if (this.state.project.azure && operation.details.csharp.verb === 'Set' && operation.details.csharp.name.indexOf('ViaIdentity') > 0) {
continue;
}
// skip-for-time-being
this.addClass(await new NewCmdletClass(this, operation, this.state.path('commands', 'operations', index)).init());
}
return this;
Expand Down
127 changes: 90 additions & 37 deletions powershell/llcsharp/model/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import { KnownMediaType, JsonType, getPolymorphicBases } from '@azure-tools/code
import { Expression, ExpressionOrLiteral, Interface, Namespace, OneOrMoreStatements, Variable, Access, InterfaceProperty, Attribute, StringExpression, LiteralExpression, Property, TypeDeclaration } from '@azure-tools/codegen-csharp';
import { ClientRuntime } from '../clientruntime';
import { Schema } from '../code-model';
import { Schema as NewSchema, Language } from '@azure-tools/codemodel';
import { Schema as NewSchema, Language, ObjectSchema } from '@azure-tools/codemodel';
import { State, NewState } from '../generator';
import { EnhancedTypeDeclaration, NewEnhancedTypeDeclaration } from '../schema/extended-type-declaration';
import { ModelClass, NewModelClass } from './model-class';
import { TypeContainer } from '@azure-tools/codegen-csharp';
import { DeepPartial } from '@azure-tools/codegen';
import { values } from '@azure-tools/linq';
import { VirtualProperty as NewVirtualProperty, VirtualProperties as NewVirtualProperties } from '../../utils/schema'


export function addInfoAttribute(targetProperty: Property, pType: TypeDeclaration, isRequired: boolean, isReadOnly: boolean, description: string, serializedName: string) {
Expand Down Expand Up @@ -70,6 +71,58 @@ export function addInfoAttribute(targetProperty: Property, pType: TypeDeclaratio
}));
}

export function newAddInfoAttribute(targetProperty: Property, pType: TypeDeclaration, isRequired: boolean, isReadOnly: boolean, description: string, serializedName: string) {

let pt = <any>pType;
while (pt.elementType) {
switch (pt.elementType.schema.type) {
case JsonType.Object:
if (pt.elementType.schema.language.csharp.interfaceImplementation) {
pt = {
declaration: pt.elementType.schema.language.csharp.interfaceImplementation.declaration,
schema: pt.elementType.schema,
};
} else {
// arg! it's not done yet. Hope it's not polymorphic itself.
pt = {
declaration: `${pt.elementType.schema.language.csharp.namespace}.${pt.elementType.schema.language.csharp.interfaceName}`,
schema: pt.elementType.schema,
};
}
break;

case JsonType.Array:
pt = pt.elementType;
break;

default:
pt = pt.elementType;
break;
}
}
const ptypes = new Array<string>();

if (pt.schema && pt.schema.language.csharp.byReference) {
ptypes.push(`typeof(${pt.schema.language.csharp.namespace}.${pt.schema.language.csharp.interfaceName}_Reference)`);
// do we need polymorphic types for by-resource ? Don't think so.
} else {
ptypes.push(`typeof(${pt.declaration})`);
if (pt.schema && pt.schema.language.csharp.classImplementation && pt.schema.language.csharp.classImplementation.discriminators) {
ptypes.push(...[...pt.schema.language.csharp.classImplementation.discriminators.values()].map(each => `typeof(${each.modelInterface.fullName})`));
}
}

targetProperty.add(new Attribute(ClientRuntime.InfoAttribute, {
parameters: [
new LiteralExpression(`\nRequired = ${isRequired}`),
new LiteralExpression(`\nReadOnly = ${isReadOnly}`),
new LiteralExpression(`\nDescription = ${new StringExpression(description ?? '').value}`),
new LiteralExpression(`\nSerializedName = ${new StringExpression(serializedName).value}`),
new LiteralExpression(`\nPossibleTypes = new [] { ${ptypes.join(',').replace(/\?/g, '').replace(/undefined\./g, '')} }`),
]
}));
}


export class ModelInterface extends Interface implements EnhancedTypeDeclaration {
get schema(): Schema {
Expand Down Expand Up @@ -302,58 +355,58 @@ export class NewModelInterface extends Interface implements NewEnhancedTypeDecla
//implData.interfaceImplementation = this;
this.description = `${this.schema.language.csharp.description}`;

const virtualProperties = this.schema.language.csharp.virtualProperties || {
const virtualProperties: NewVirtualProperties = this.schema.language.csharp.virtualProperties || {
owned: [],
inherited: [],
inlined: []
};
// skip-for-time-being
// if (this.schema.language.csharp.virtualProperties) {
if (this.schema.language.csharp.virtualProperties) {

// for (const virtualProperty of values(virtualProperties.owned)) {
// if (virtualProperty.private && !this.isInternal) {
// continue;
// }
for (const virtualProperty of values(virtualProperties.owned)) {
if (virtualProperty.private && !this.isInternal) {
continue;
}

// const modelProperty = virtualProperty.property;
const modelProperty = virtualProperty.property;

// const internalSet = !!(!this.isInternal && (modelProperty.details.csharp.readOnly || modelProperty.details.csharp.constantValue));
const internalSet = !!(!this.isInternal && (modelProperty.readOnly || (<any>modelProperty.language.csharp).constantValue));

// const isRequired = !!modelProperty.details.csharp.required;
// const pType = this.state.project.modelsNamespace.resolveTypeDeclaration(<Schema>modelProperty.schema, isRequired, this.state.path('schema'));
// const p = this.add(new InterfaceProperty(virtualProperty.name, pType, {
// description: modelProperty.details.csharp.description,
// setAccess: internalSet ? Access.Internal : Access.Public
// }));
const isRequired = !!modelProperty.required;
const pType = this.state.project.modelsNamespace.NewResolveTypeDeclaration(<NewSchema>modelProperty.schema, isRequired, this.state.path('schema'));
const p = this.add(new InterfaceProperty(virtualProperty.name, pType, {
description: modelProperty.language.default.description,
setAccess: internalSet ? Access.Internal : Access.Public
}));

// this.addInfoAttribute(p, pType, isRequired, internalSet, modelProperty.details.csharp.description, modelProperty.serializedName);
this.addInfoAttribute(p, pType, isRequired, internalSet, modelProperty.language.default.description, modelProperty.serializedName);

// if (!this.isInternal && modelProperty.details.csharp.constantValue !== undefined) {
// p.setAccess = Access.Internal;
// }
// }
if (!this.isInternal && (<any>modelProperty.language.csharp).constantValue !== undefined) {
p.setAccess = Access.Internal;
}
}

// for (const virtualProperty of values(virtualProperties.inlined)) {
for (const virtualProperty of values(virtualProperties.inlined)) {

// // don't publicly expose the 'private' properties.
// if (virtualProperty.private && !this.isInternal) {
// continue;
// }
// don't publicly expose the 'private' properties.
if (virtualProperty.private && !this.isInternal) {
continue;
}

// const modelProperty = virtualProperty.property;
// const isRequired = !!modelProperty.details.csharp.required;
// const pType = this.state.project.modelsNamespace.resolveTypeDeclaration(<Schema>modelProperty.schema, isRequired, this.state.path('schema'));
const modelProperty = virtualProperty.property;
const isRequired = !!modelProperty.required;
const pType = this.state.project.modelsNamespace.NewResolveTypeDeclaration(<NewSchema>modelProperty.schema, isRequired, this.state.path('schema'));

// const internalSet = !!(!this.isInternal && (modelProperty.details.csharp.readOnly || modelProperty.details.csharp.constantValue));
const internalSet = !!(!this.isInternal && (modelProperty.readOnly || (<any>modelProperty.language.csharp).constantValue));

// const p = this.add(new InterfaceProperty(virtualProperty.name, pType, {
// description: modelProperty.details.csharp.description,
// setAccess: internalSet ? Access.Internal : Access.Public
// }));
// this.addInfoAttribute(p, pType, isRequired, internalSet, modelProperty.details.csharp.description, modelProperty.serializedName);
const p = this.add(new InterfaceProperty(virtualProperty.name, pType, {
description: modelProperty.language.default.description,
setAccess: internalSet ? Access.Internal : Access.Public
}));
this.addInfoAttribute(p, pType, isRequired, internalSet, modelProperty.language.default.description, modelProperty.serializedName);

// }
// }
}
}

if (!this.isInternal) {
// mark it as json serializable
Expand All @@ -371,7 +424,7 @@ export class NewModelInterface extends Interface implements NewEnhancedTypeDecla

addInfoAttribute(p: Property, pType: TypeDeclaration, isRequired: boolean, internalSet: boolean, description: string, serializedName: string) {
if (!this.isInternal) {
return addInfoAttribute(p, pType, isRequired, internalSet, description, serializedName);
return newAddInfoAttribute(p, pType, isRequired, internalSet, description, serializedName);
}
}
}
1 change: 0 additions & 1 deletion powershell/llcsharp/model/model-class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ 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';

export function getVirtualPropertyName(vp?: VirtualProperty): string {
Expand Down
50 changes: 23 additions & 27 deletions powershell/llcsharp/operation/method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ function removeEncoding(pp: OperationParameter, paramName: string, kmt: KnownMed
return pp.param.extensions && pp.param.extensions['x-ms-skip-url-encoding'] ? up.replace(/global::System.Uri.EscapeDataString|System.Uri.EscapeDataString/g, '') : up;
}

function newRemoveEncoding(pp: NewOperationParameter, paramName: string, kmt: KnownMediaType): string {
const up = pp.typeDeclaration.serializeToNode(kmt, pp, paramName, ClientRuntime.SerializationMode.None).value;
return pp.param.extensions && pp.param.extensions['x-ms-skip-url-encoding'] ? up.replace(/global::System.Uri.EscapeDataString|System.Uri.EscapeDataString/g, '') : up;
}


export class EventListener {
constructor(protected expression: Expression, protected emitSignals: boolean) {
Expand Down Expand Up @@ -371,6 +376,7 @@ export class NewOperationMethod extends Method {
this.senderParameter = this.addParameter(new Parameter('sender', ClientRuntime.ISendAsync, { description: `an instance of an ${ClientRuntime.ISendAsync} pipeline to use to make the request.` }));

let rx = this.operation.requests ? this.operation.requests[0].protocol.http?.path : '';
const path = rx;
// For post API, Some URI may contain an action string .e.x '/start' at the end
// of the URI, for such cases, we will drop the action string if identityCorrection
// is set in the configuration
Expand Down Expand Up @@ -399,19 +405,19 @@ export class NewOperationMethod extends Method {
// + "`);
// }

// for (const pp of pathParams) {
// rx = rx.replace(`{${pp.param.name}}`, `(?<${pp.param.name}>[^/]+)`);
for (const pp of pathParams) {
rx = rx.replace(`{${pp.param.language.default.name}}`, `(?<${pp.param.language.default.name}>[^/]+)`);

// if (this.viaIdentity) {
// url = url.replace(`{${pp.param.name}}`, `"
// + ${pp.name}
// + "`);
// } else {
// url = url.replace(`{${pp.param.name}}`, `"
// + ${removeEncoding(pp, '', KnownMediaType.UriParameter)}
// + "`);
// }
// }
if (this.viaIdentity) {
url = url.replace(`{${pp.param.language.default.name}}`, `"
+ ${pp.name}
+ "`);
} else {
url = url.replace(`{${pp.param.language.default.name}}`, `"
+ ${newRemoveEncoding(pp, '', KnownMediaType.UriParameter)}
+ "`);
}
}
rx = `"^${rx}$"`;
url = url.replace(/\s*\+ ""/gm, '');

Expand All @@ -429,30 +435,20 @@ export class NewOperationMethod extends Method {

const match = Local('_match', `${System.Text.RegularExpressions.Regex.new(rx).value}.Match(${identity.value})`);
yield match.declarationStatement;
yield If(`!${match}.Success`, `throw new global::System.Exception("Invalid identity for URI '${rx}'");`);
yield If(`!${match}.Success`, `throw new global::System.Exception("Invalid identity for URI '${path}'");`);
yield EOL;
yield '// replace URI parameters with values from identity';
// skip-for-time-being
// for (const pp of pathParams) {
// yield `var ${pp.name} = ${match.value}.Groups["${pp.param.name}"].Value;`;
// }
for (const pp of pathParams) {
yield `var ${pp.name} = ${match.value}.Groups["${pp.param.language.default.name}"].Value;`;
}
}

yield '// construct URL';
// const urlV = new LocalVariable('_url', dotnet.Var, {
// initializer: System.Uri.new(`${System.Text.RegularExpressions.Regex.declaration}.Replace(
// "${url}"
// ${queryParams.length > 0 ? '+ "?"' : ''}${queryParams.joinWith(pp => `
// + ${removeEncoding(pp, pp.param.name, KnownMediaType.QueryParameter)}`, `
// + "&"`
// )}
// ,"\\\\?&*$|&*$|(\\\\?)&+|(&)&+","$1$2")`.replace(/\s*\+ ""/gm, ''))
// });
const urlV = new LocalVariable('_url', dotnet.Var, {
initializer: System.Uri.new(`${System.Text.RegularExpressions.Regex.declaration}.Replace(
"${url}"
${queryParams.length > 0 ? '+ "?"' : ''}${queryParams.joinWith(pp => `
+ ${''}`, `
+ ${newRemoveEncoding(pp, pp.param.language.default.name, KnownMediaType.QueryParameter)}`, `
+ "&"`
)}
,"\\\\?&*$|&*$|(\\\\?)&+|(&)&+","$1$2")`.replace(/\s*\+ ""/gm, ''))
Expand Down
4 changes: 2 additions & 2 deletions powershell/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { csnamer } from './plugins/cs-namer';
import { llcsharp } from './plugins/llcsharp';
import { createInlinedPropertiesPlugin } from './plugins/plugin-create-inline-properties';
import { tweakModelPlugin } from './plugins/plugin-tweak-model';
import { tweakModelAzurePlugin } from './plugins/plugin-tweak-model-azure';
import { tweakModelAzurePluginV2 } from './plugins/plugin-tweak-model-azure-v2';
import { createCommandsV2 } from './plugins/create-commands-v2';
import { csnamerV2 } from './plugins/cs-namer-v2';
import { namerV2 } from './plugins/ps-namer-v2';
Expand All @@ -33,7 +33,7 @@ export async function main() {
pluginHost.Add('llcsharp', llcsharp);
// Following are plugins moved from remodeler
pluginHost.Add('tweakcodemodel-v2', tweakModelPlugin);
pluginHost.Add('tweakcodemodelazure-v2', tweakModelAzurePlugin);
pluginHost.Add('tweakcodemodelazure-v2', tweakModelAzurePluginV2);
pluginHost.Add('create-virtual-properties-v2', createInlinedPropertiesPlugin);
pluginHost.Add('create-commands-v2', createCommandsV2);
pluginHost.Add('csnamer-v2', csnamerV2);
Expand Down
2 changes: 1 addition & 1 deletion powershell/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,4 @@
"source-map-support": "0.5.13",
"xmlbuilder": "10.1.1"
}
}
}
1 change: 1 addition & 0 deletions powershell/plugins/llcsharp-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Model } from '../llcsharp/code-model';
import { State } from '../llcsharp/generator';
import { Project, NewProject } from '../llcsharp/project';
import { PwshModel } from '../utils/PwshModel';
import { Dictionary } from '@azure-tools/linq';

const resources = `${__dirname}/../../resources`;

Expand Down
13 changes: 12 additions & 1 deletion powershell/plugins/llcsharp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,25 @@ import { join } from 'path';
import { Model } from '../llcsharp/code-model';
import { State } from '../llcsharp/generator';
import { Project } from '../llcsharp/project';
import { Dictionary } from '@azure-tools/linq';

const resources = `${__dirname}/../../resources`;

function outerTest(service: Host, project: Project, fname: string, content: string) {
service.WriteFile(join(project.apifolder, fname), test(content, project.overrides), undefined, 'source-file-csharp');
}

function test(content: string, overrides: Dictionary<string>): string {
const a = applyOverrides(content, overrides);
return a;
}

export async function llcsharp(service: Host) {
try {
const project = await new Project(service).init();

await project.writeFiles(async (fname, content) => service.WriteFile(join(project.apifolder, fname), applyOverrides(content, project.overrides), undefined, 'source-file-csharp'));
await project.writeFiles(async (fname, content) => service.WriteFile(join(project.apifolder, fname), test(content, project.overrides), undefined, 'source-file-csharp'));
await project.writeFiles(async (fname, content) => outerTest(service, project, fname, content));

// recursive copy resources
await copyResources(join(resources, 'runtime', 'csharp', 'client'), async (fname, content) => service.WriteFile(join(project.runtimefolder, fname), content, undefined, 'source-file-csharp'), project.overrides);
Expand Down
Loading