support smart flatten
This commit is contained in:
Родитель
f6d7a9c244
Коммит
ad23f4eed3
|
@ -17,8 +17,12 @@ pipeline:
|
|||
input: modelerfour
|
||||
output-artifact: clicommon-prenamer
|
||||
|
||||
clicommon/cli-flatten-setter:
|
||||
clicommon/pre/cli-complex-marker:
|
||||
input: clicommon/cli-prenamer
|
||||
output-artifact: clicommon-complex-marker-pre
|
||||
|
||||
clicommon/cli-flatten-setter:
|
||||
input: clicommon/pre/cli-complex-marker
|
||||
output-artifact: clicommon-flatten-setter
|
||||
|
||||
clicommon:
|
||||
|
@ -52,6 +56,7 @@ pipeline:
|
|||
#- clicommon/cli-poly-as-param-modifier
|
||||
- clicommon/cli-poly-as-resource-modifier
|
||||
- clicommon/cli-complex-marker
|
||||
- clicommon/pre/cli-complex-marker
|
||||
- clicommon/cli-visibility-cleaner
|
||||
scope: scope-clicommon
|
||||
|
||||
|
@ -64,6 +69,7 @@ scope-clicommon:
|
|||
- clicommon-poly-as-resource-modifier
|
||||
#- clicommon-poly-as-param-modifier
|
||||
- clicommon-complex-marker
|
||||
- clicommon-complex-marker-pre
|
||||
- clicommon-visibility-cleaner
|
||||
|
||||
modelerfour:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@autorest/clicommon",
|
||||
"version": "0.4.2",
|
||||
"version": "0.4.3",
|
||||
"description": "Autorest Azure Cli Common Module",
|
||||
"main": "dist/index.js",
|
||||
"engines": {
|
||||
|
|
|
@ -178,8 +178,13 @@ export class NodeHelper {
|
|||
return NodeHelper.getCliProperty(param, NodeHelper.POLY_AS_PARAM_EXPANDED, () => false);
|
||||
}
|
||||
|
||||
public static setComplex(node: M4Node, complexity: CliCommonSchema.CodeModel.Complexity) {
|
||||
public static setComplex(node: M4Node, complexity: CliCommonSchema.CodeModel.Complexity): CliCommonSchema.CodeModel.Complexity {
|
||||
NodeHelper.setCliProperty(node, NodeHelper.CLI_COMPLEXITY, complexity);
|
||||
return complexity;
|
||||
}
|
||||
|
||||
public static clearComplex(node: M4Node) {
|
||||
NodeHelper.clearCliProperty(node, NodeHelper.CLI_COMPLEXITY);
|
||||
}
|
||||
|
||||
public static getComplexity(node: M4Node): CliCommonSchema.CodeModel.Complexity {
|
||||
|
@ -210,6 +215,11 @@ export class NodeHelper {
|
|||
node.language[NodeHelper.CLI][key] = value;
|
||||
}
|
||||
|
||||
public static clearCliProperty(node: M4Node, key: string): void {
|
||||
if (!isNullOrUndefined(node.language[NodeHelper.CLI]) && !isUndefined(node.language[NodeHelper.CLI][key]))
|
||||
delete node.language[NodeHelper.CLI][key];
|
||||
}
|
||||
|
||||
public static getCliProperty(node: M4Node, propertyName: string, defaultWhenNotExist: () => any): any {
|
||||
if (isNullOrUndefined(node.language[NodeHelper.CLI])) {
|
||||
if (isNullOrUndefined(defaultWhenNotExist))
|
||||
|
|
|
@ -79,11 +79,9 @@ class ComplexMarker {
|
|||
if (obj.properties && obj.properties.length > 0) {
|
||||
for (let prop of obj.properties) {
|
||||
if (isObjectSchema(prop.schema)) {
|
||||
let c = this.calculateObject(prop.schema);
|
||||
if (c == CliCommonSchema.CodeModel.Complexity.object_complex) {
|
||||
NodeHelper.setComplex(obj, CliCommonSchema.CodeModel.Complexity.object_complex);
|
||||
return CliCommonSchema.CodeModel.Complexity.object_complex;
|
||||
}
|
||||
this.calculateObject(prop.schema);
|
||||
NodeHelper.setComplex(obj, CliCommonSchema.CodeModel.Complexity.object_complex);
|
||||
return CliCommonSchema.CodeModel.Complexity.object_complex;
|
||||
}
|
||||
else if (prop.schema instanceof ArraySchema) {
|
||||
let c = this.calculateArray(prop.schema);
|
||||
|
@ -104,8 +102,24 @@ class ComplexMarker {
|
|||
|
||||
}
|
||||
|
||||
private clearComplexMarker() {
|
||||
|
||||
}
|
||||
|
||||
public process() {
|
||||
|
||||
this.session.model.schemas.objects.forEach(obj => {
|
||||
NodeHelper.clearComplex(obj);
|
||||
});
|
||||
|
||||
this.session.model.schemas.dictionaries?.forEach(dict => {
|
||||
NodeHelper.clearComplex(dict);
|
||||
});
|
||||
|
||||
this.session.model.schemas.arrays?.forEach(arr => {
|
||||
NodeHelper.clearComplex(arr);
|
||||
})
|
||||
|
||||
this.session.model.schemas.objects.forEach(obj => {
|
||||
this.calculateObject(obj);
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Host, Session, startSession } from "@azure-tools/autorest-extension-base";
|
||||
import { serialize } from "@azure-tools/codegen";
|
||||
import { CodeModel, codeModelSchema, Metadata, ObjectSchema, isObjectSchema, Property, Extensions } from "@azure-tools/codemodel";
|
||||
import { CodeModel, codeModelSchema, Metadata, ObjectSchema, isObjectSchema, Property, Extensions, getAllProperties, Parameter, DictionarySchema, Schema, ArraySchema, ConstantSchema, AnySchema } from "@azure-tools/codemodel";
|
||||
import { isNullOrUndefined, isArray } from "util";
|
||||
import { DESTRUCTION } from "dns";
|
||||
import { Helper } from "../../helper";
|
||||
|
@ -9,7 +9,12 @@ import { CliConst, CliCommonSchema } from "../../schema";
|
|||
import { CliDirectiveManager } from "../modifier/cliDirective";
|
||||
import { Modifier } from "../modifier/modifier";
|
||||
import { FlattenValidator } from "./flattenValidator";
|
||||
import { values } from "@azure-tools/linq";
|
||||
import { values, Dictionary } from "@azure-tools/linq";
|
||||
import { Z_DEFLATED } from "zlib";
|
||||
|
||||
class flattenInfo {
|
||||
public constructor(public propCount: number = 0, public complexity: number = 0) { }
|
||||
};
|
||||
|
||||
export class FlattenSetter {
|
||||
codeModel: CodeModel;
|
||||
|
@ -20,6 +25,126 @@ export class FlattenSetter {
|
|||
this.codeModel = session.model;
|
||||
}
|
||||
|
||||
/**
|
||||
* level N means this is the Nth flatten, 0 means no flatten done which means the top level
|
||||
* @param schema
|
||||
* @param info - should be pre-prepared
|
||||
* @param level
|
||||
*/
|
||||
private calcSchemaForPayloadFlatten(schema: Schema, info: flattenInfo[], level: number, required: boolean): number {
|
||||
|
||||
let weight = required ? 1 : 0.5;
|
||||
|
||||
let increasePropCount = () => {
|
||||
for (let i = level; i < info.length; i++)
|
||||
info[i].propCount++;
|
||||
};
|
||||
|
||||
let increaseComplexity = () => {
|
||||
for (let i = level; i < info.length; i++)
|
||||
info[i].complexity = +weight;
|
||||
};
|
||||
|
||||
let r = level;
|
||||
|
||||
if (schema instanceof ArraySchema) {
|
||||
increasePropCount();
|
||||
if (NodeHelper.getComplexity(schema) === CliCommonSchema.CodeModel.Complexity.array_complex)
|
||||
increaseComplexity();
|
||||
}
|
||||
else if (schema instanceof DictionarySchema) {
|
||||
increasePropCount();
|
||||
if (NodeHelper.getComplexity(schema) === CliCommonSchema.CodeModel.Complexity.dictionary_complex)
|
||||
increaseComplexity();
|
||||
}
|
||||
else if (schema instanceof AnySchema) {
|
||||
increasePropCount();
|
||||
increaseComplexity();
|
||||
}
|
||||
else if (schema instanceof ConstantSchema) {
|
||||
}
|
||||
else if (schema instanceof ObjectSchema) {
|
||||
if (NodeHelper.HasSubClass(schema)) {
|
||||
increasePropCount();
|
||||
increaseComplexity();
|
||||
}
|
||||
else if (NodeHelper.getComplexity(schema) === CliCommonSchema.CodeModel.Complexity.object_simple) {
|
||||
increasePropCount();
|
||||
}
|
||||
else {
|
||||
info[level].propCount++;
|
||||
info[level].complexity += weight;
|
||||
for (let prop of getAllProperties(schema)) {
|
||||
if (prop.readOnly)
|
||||
continue;
|
||||
if (level + 1 < info.length) {
|
||||
r = this.calcSchemaForPayloadFlatten(prop.schema, info, level + 1, prop.required);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
increasePropCount();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
private calcPayloadFlatten(param: Parameter, maxLevel: number, maxPropCount: number, maxComplexity: number): number {
|
||||
let defaultLevel = 1;
|
||||
let info: flattenInfo[] = [];
|
||||
for (let i = maxLevel; i >= 0; i--)
|
||||
info.push(new flattenInfo());
|
||||
|
||||
let r = this.calcSchemaForPayloadFlatten(param.schema, info, 0, true);
|
||||
|
||||
for (let i = 0; i <= r; i++) {
|
||||
Helper.logDebug(`Level-${i}: propCount=${info[i].propCount}, complexity=${info[i].complexity}`)
|
||||
}
|
||||
|
||||
for (let i = r; i >= 0; i--) {
|
||||
if (info[i].propCount <= maxPropCount && info[i].complexity <= maxComplexity) {
|
||||
if (i == 0 && NodeHelper.getComplexity(param.schema) === CliCommonSchema.CodeModel.Complexity.object_simple) {
|
||||
Helper.logDebug(`flatten to level ${i} and ajusted to 1 for top level simple object with maxLevel=${maxLevel}, maxPropCount=${maxPropCount}, maxComplexity=${maxComplexity}`);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
Helper.logDebug(`flatten to level ${i} with maxLevel=${maxLevel}, maxPropCount=${maxPropCount}, maxComplexity=${maxComplexity}`);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return defaultLevel;
|
||||
}
|
||||
|
||||
private flattenSchemaFromPayload(schema: Schema, curLevel: number, maxLevel: number, overwritten: boolean) {
|
||||
|
||||
if (curLevel >= maxLevel)
|
||||
return;
|
||||
if (!(schema instanceof ObjectSchema))
|
||||
return;
|
||||
|
||||
for (let prop of getAllProperties(schema)) {
|
||||
if (prop.readOnly)
|
||||
continue;
|
||||
if (prop.schema instanceof ObjectSchema) {
|
||||
if (!NodeHelper.HasSubClass(prop.schema) && NodeHelper.getComplexity(prop.schema) !== CliCommonSchema.CodeModel.Complexity.object_simple)
|
||||
NodeHelper.setFlatten(prop, true, overwritten);
|
||||
}
|
||||
this.flattenSchemaFromPayload(prop.schema, curLevel + 1, maxLevel, overwritten);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private flattenPayload(param: Parameter, maxLevel: number, maxPropCount: number, maxComplexity: number, overwritten: boolean) {
|
||||
|
||||
let r = this.calcPayloadFlatten(param, maxLevel, maxPropCount, maxComplexity);
|
||||
if (r > 0) {
|
||||
NodeHelper.setFlatten(param, true, overwritten);
|
||||
this.flattenSchemaFromPayload(param.schema, 1, r, overwritten);
|
||||
}
|
||||
}
|
||||
|
||||
async process(host: Host) {
|
||||
|
||||
let overwriteSwagger = await this.session.getValue(CliConst.CLI_FLATTEN_SET_FLATTEN_ALL_OVERWRITE_SWAGGER_KEY, false);
|
||||
|
@ -31,32 +156,43 @@ export class FlattenSetter {
|
|||
if (flattenSchema === true || flattenAll === true) {
|
||||
this.codeModel.schemas.objects.forEach(o => {
|
||||
if (!NodeHelper.HasSubClass(o)) {
|
||||
if (!isNullOrUndefined(o.properties)) {
|
||||
o.properties.forEach(p => {
|
||||
if (isObjectSchema(p.schema)) {
|
||||
NodeHelper.setFlatten(p, !NodeHelper.HasSubClass(p.schema as ObjectSchema), overwriteSwagger);
|
||||
}
|
||||
})
|
||||
for (let p of getAllProperties(o)) {
|
||||
if (isObjectSchema(p.schema)) {
|
||||
NodeHelper.setFlatten(p, !NodeHelper.HasSubClass(p.schema as ObjectSchema), overwriteSwagger);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let maxPropCount = await this.session.getValue(CliConst.CLI_FLATTEN_SET_FLATTEN_PAYLOAD_MAX_PROP_KEY, 32);
|
||||
let maxLevel = await this.session.getValue(CliConst.CLI_FLATTEN_SET_FLATTEN_PAYLOAD_MAX_LEVEL_KEY, 5);
|
||||
let maxComplexity = await this.session.getValue(CliConst.CLI_FLATTEN_SET_FLATTEN_PAYLOAD_MAX_COMPLEXITY_KEY, 1);
|
||||
let flattenPayload = await this.session.getValue(CliConst.CLI_FLATTEN_SET_FLATTEN_PAYLOAD_KEY, false);
|
||||
|
||||
if (flattenPayload === true || flattenAll === true) {
|
||||
this.codeModel.operationGroups.forEach(group => {
|
||||
group.operations.forEach(operation => {
|
||||
values(operation.parameters)
|
||||
values(operation.parameters)
|
||||
.where(p => p.protocol.http?.in === 'body' && p.implementation === 'Method')
|
||||
.forEach(p => NodeHelper.setFlatten(p, !NodeHelper.HasSubClass(p.schema as ObjectSchema), overwriteSwagger));
|
||||
.forEach(p => {
|
||||
if (p.schema instanceof ObjectSchema && !NodeHelper.HasSubClass(p.schema)) {
|
||||
Helper.logDebug(`Try to set flatten for ${group.language.default.name}/${operation.language.default.name}/${p.language.default.name}`);
|
||||
this.flattenPayload(p, maxLevel, maxPropCount, maxComplexity, overwriteSwagger);
|
||||
}
|
||||
});
|
||||
|
||||
operation.requests.forEach(request => {
|
||||
if (!isNullOrUndefined(request.parameters)) {
|
||||
values(request.parameters)
|
||||
operation.requests.forEach(request => {
|
||||
if (!isNullOrUndefined(request.parameters)) {
|
||||
values(request.parameters)
|
||||
.where(p => p.protocol.http?.in === 'body' && p.implementation === 'Method')
|
||||
.forEach(p => NodeHelper.setFlatten(p, !NodeHelper.HasSubClass(p.schema as ObjectSchema), overwriteSwagger));
|
||||
}
|
||||
});
|
||||
.forEach(p => {
|
||||
if (p.schema instanceof ObjectSchema && !NodeHelper.HasSubClass(p.schema))
|
||||
Helper.logDebug(`Try to set flatten for ${group.language.default.name}/${operation.language.default.name}/${p.language.default.name}`);
|
||||
this.flattenPayload(p, maxLevel, maxPropCount, maxComplexity, overwriteSwagger);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
})
|
||||
|
|
|
@ -18,6 +18,9 @@ export namespace CliConst {
|
|||
export const CLI_FLATTEN_SET_FLATTEN_ALL_KEY: string = 'cli.flatten.cli-flatten-all';
|
||||
export const CLI_FLATTEN_SET_FLATTEN_SCHEMA_KEY: string = 'cli.flatten.cli-flatten-schema';
|
||||
export const CLI_FLATTEN_SET_FLATTEN_PAYLOAD_KEY: string = 'cli.flatten.cli-flatten-payload';
|
||||
export const CLI_FLATTEN_SET_FLATTEN_PAYLOAD_MAX_PROP_KEY: string = 'cli.flatten.cli-flatten-payload-max-prop';
|
||||
export const CLI_FLATTEN_SET_FLATTEN_PAYLOAD_MAX_COMPLEXITY_KEY: string = 'cli.flatten.cli-flatten-payload-max-complexity';
|
||||
export const CLI_FLATTEN_SET_FLATTEN_PAYLOAD_MAX_LEVEL_KEY: string = 'cli.flatten.cli-flatten-payload-max-level';
|
||||
export const CLI_FLATTEN_SET_FLATTEN_ALL_OVERWRITE_SWAGGER_KEY: string = 'cli.flatten.cli-flatten-all-overwrite-swagger';
|
||||
|
||||
export const DEFAULT_OPERATION_PARAMETER_INDEX = -1;
|
||||
|
|
Загрузка…
Ссылка в новой задаче