From b645fb3d6de644757af8250efc4b41af11fe7c4c Mon Sep 17 00:00:00 2001 From: Weidong Xu Date: Thu, 5 Sep 2024 07:12:53 +0800 Subject: [PATCH] http-client-java, remove unused namer module (#4328) History: we originally intend to use m4 prenamer (opt-in via flag/option) to keep names in SDK same as from Swagger (mostly for brownfield). But later we decided to just use `@clientName` in client.tsp to explicitly do the naming, if backward-compatibility is an issue. This flag/option is not used by any service. --- cspell.yaml | 1 - .../emitter/src/code-model-builder.ts | 5 - .../http-client-java/emitter/src/emitter.ts | 5 - .../emitter/src/prenamer/formatter.ts | 251 --------- .../emitter/src/prenamer/naming-utils.ts | 219 -------- .../emitter/src/prenamer/prenamer.ts | 475 ------------------ 6 files changed, 956 deletions(-) delete mode 100644 packages/http-client-java/emitter/src/prenamer/formatter.ts delete mode 100644 packages/http-client-java/emitter/src/prenamer/naming-utils.ts delete mode 100644 packages/http-client-java/emitter/src/prenamer/prenamer.ts diff --git a/cspell.yaml b/cspell.yaml index ad918492b..cd704bbfd 100644 --- a/cspell.yaml +++ b/cspell.yaml @@ -27,7 +27,6 @@ words: - cobertura - codehaus - codeql - - collisons - Contoso - CORGE - createsorreplacesresource diff --git a/packages/http-client-java/emitter/src/code-model-builder.ts b/packages/http-client-java/emitter/src/code-model-builder.ts index 8e4c4ff87..2bc8a2f9d 100644 --- a/packages/http-client-java/emitter/src/code-model-builder.ts +++ b/packages/http-client-java/emitter/src/code-model-builder.ts @@ -143,7 +143,6 @@ import { operationIsMultipart, operationIsMultipleContentTypes, } from "./operation-utils.js"; -import { PreNamer } from "./prenamer/prenamer.js"; import { ProcessingCache, getAccess, @@ -265,10 +264,6 @@ export class CodeModelBuilder { this.processSchemaUsage(); - if (this.options.namer) { - this.codeModel = new PreNamer(this.codeModel).init().process(); - } - this.deduplicateSchemaName(); return this.codeModel; diff --git a/packages/http-client-java/emitter/src/emitter.ts b/packages/http-client-java/emitter/src/emitter.ts index 106c9cc00..b3527bd6e 100644 --- a/packages/http-client-java/emitter/src/emitter.ts +++ b/packages/http-client-java/emitter/src/emitter.ts @@ -25,8 +25,6 @@ export interface EmitterOptions { "skip-special-headers"?: string[]; - namer?: boolean; - "generate-samples"?: boolean; "generate-tests"?: boolean; @@ -73,9 +71,6 @@ const EmitterOptionsSchema: JSONSchemaType = { // header "skip-special-headers": { type: "array", items: { type: "string" }, nullable: true }, - // namer - namer: { type: "boolean", nullable: true, default: false }, - // sample and test "generate-samples": { type: "boolean", nullable: true, default: true }, "generate-tests": { type: "boolean", nullable: true, default: true }, diff --git a/packages/http-client-java/emitter/src/prenamer/formatter.ts b/packages/http-client-java/emitter/src/prenamer/formatter.ts deleted file mode 100644 index 2bf0c5a4a..000000000 --- a/packages/http-client-java/emitter/src/prenamer/formatter.ts +++ /dev/null @@ -1,251 +0,0 @@ -import { fixLeadingNumber, removeSequentialDuplicates } from "@azure-tools/codegen"; - -export type Styler = ( - identifier: string | Array, - removeDuplicates: boolean | undefined, - overrides: Record | undefined -) => string; -type StylerWithUppercasePreservation = ( - identifier: string | Array, - removeDuplicates: boolean | undefined, - overrides: Record | undefined, - maxUppercasePreserve: number | undefined -) => string; - -function capitalize(s: string): string { - return s ? `${s.charAt(0).toUpperCase()}${s.slice(1)}` : s; -} - -function uncapitalize(s: string): string { - return s ? `${s.charAt(0).toLowerCase()}${s.slice(1)}` : s; -} - -function IsFullyUpperCase(identifier: string, maxUppercasePreserve: number) { - const len = identifier.length; - if (len > 1) { - if (len <= maxUppercasePreserve && identifier === identifier.toUpperCase()) { - return true; - } - - if (len <= maxUppercasePreserve + 1 && identifier.endsWith("s")) { - const i = identifier.substring(0, len - 1); - if (i.toUpperCase() === i) { - return true; - } - } - } - return false; -} - -function deconstruct( - identifier: string | Array, - maxUppercasePreserve: number -): Array { - if (Array.isArray(identifier)) { - return [...identifier.flatMap((each) => deconstruct(each, maxUppercasePreserve))]; - } - - return `${identifier}` - .replace(/([a-z]+)([A-Z])/g, "$1 $2") // Add a space in between camelCase words(e.g. fooBar => foo Bar) - .replace(/(\d+)/g, " $1 ") // Adds a space after numbers(e.g. foo123 => foo123 bar) - .replace(/\b([A-Z]+)([A-Z])s([^a-z])(.*)/g, "$1$2« $3$4") // Add a space after a plural upper cased word(e.g. MBsFoo => MBs Foo) - .replace(/\b([A-Z]+)([A-Z])([a-z]+)/g, "$1 $2$3") // Add a space between an upper case word(2 char+) and the last capital case.(e.g. SQLConnection -> SQL Connection) - .replace(/«/g, "s") - .trim() - .split(/[\W|_]+/) - .map((each) => (IsFullyUpperCase(each, maxUppercasePreserve) ? each : each.toLowerCase())); -} - -function wrap( - prefix: string, - postfix: string, - style: StylerWithUppercasePreservation, - maxUppercasePreserve: number -): Styler { - if (postfix || prefix) { - return (i, r, o) => - typeof i === "string" && typeof o === "object" - ? o[i.toLowerCase()] || `${prefix}${style(i, r, o, maxUppercasePreserve)}${postfix}` - : `${prefix}${style(i, r, o, maxUppercasePreserve)}${postfix}`; - } - return (i, r, o) => style(i, r, o, maxUppercasePreserve); -} - -function applyFormat( - normalizedContent: Array, - overrides: Record = {}, - separator = "", - formatter: (s: string, i: number) => string = (s, i) => s -) { - return normalizedContent - .map((each, index) => { - if (Object.keys(overrides).includes(each.toLowerCase())) { - const override = overrides[each.toLowerCase()]; - if (override) { - return override; - } - } - return formatter(each, index); - }) - .join(separator); -} - -function normalize( - identifier: string | Array, - removeDuplicates = true, - overrides: Record = {}, - maxUppercasePreserve = 0 -): Array { - if (!identifier || identifier.length === 0) { - return [""]; - } - return typeof identifier === "string" - ? normalize( - fixLeadingNumber(deconstruct(identifier, maxUppercasePreserve)), - removeDuplicates, - overrides, - maxUppercasePreserve - ) - : removeDuplicates - ? removeSequentialDuplicates(identifier) - : identifier; -} -export class Style { - static select(style: any, fallback: Styler, maxUppercasePreserve: number): Styler { - if (style) { - const styles = /^([a-zA-Z0-9_]*?\+?)([a-zA-Z]+)(\+?[a-zA-Z0-9_]*)$/g.exec( - style.replace(/\s*/g, "") - ); - if (styles) { - const prefix = styles[1] ? styles[1].substring(0, styles[1].length - 1) : ""; - const postfix = styles[3] ? styles[3].substring(1) : ""; - - switch (styles[2]) { - case "camelcase": - case "camel": - return wrap(prefix, postfix, Style.camel, maxUppercasePreserve); - case "pascalcase": - case "pascal": - return wrap(prefix, postfix, Style.pascal, maxUppercasePreserve); - case "snakecase": - case "snake": - return wrap(prefix, postfix, Style.snake, maxUppercasePreserve); - case "uppercase": - case "upper": - return wrap(prefix, postfix, Style.upper, maxUppercasePreserve); - case "kebabcase": - case "kebab": - return wrap(prefix, postfix, Style.kebab, maxUppercasePreserve); - case "spacecase": - case "space": - return wrap(prefix, postfix, Style.space, maxUppercasePreserve); - } - } - } - return wrap("", "", fallback, maxUppercasePreserve); - } - - static kebab( - identifier: string | Array, - removeDuplicates = true, - overrides: Record = {}, - maxUppercasePreserve = 0 - ): string { - return ( - (Object.keys(overrides).includes(identifier) && overrides[identifier]) || - applyFormat( - normalize(identifier, removeDuplicates, overrides, maxUppercasePreserve), - overrides, - "-" - ).replace(/([^\d])-(\d+)/g, "$1$2") - ); - } - - static space( - identifier: string | Array, - removeDuplicates = true, - overrides: Record = {}, - maxUppercasePreserve = 0 - ): string { - return ( - (Object.keys(overrides).includes(identifier) && overrides[identifier]) || - applyFormat( - normalize(identifier, removeDuplicates, overrides, maxUppercasePreserve), - overrides, - " " - ).replace(/([^\d]) (\d+)/g, "$1$2") - ); - } - - static snake( - identifier: string | Array, - removeDuplicates = true, - overrides: Record = {}, - maxUppercasePreserve = 0 - ): string { - return ( - (Object.keys(overrides).includes(identifier) && overrides[identifier]) || - applyFormat( - normalize(identifier, removeDuplicates, overrides, maxUppercasePreserve), - overrides, - "_" - ).replace(/([^\d])_(\d+)/g, "$1$2") - ); - } - - static upper( - identifier: string | Array, - removeDuplicates = true, - overrides: Record = {}, - maxUppercasePreserve = 0 - ): string { - return ( - (Object.keys(overrides).includes(identifier) && overrides[identifier]) || - applyFormat( - normalize(identifier, removeDuplicates, overrides, maxUppercasePreserve), - overrides, - "_", - (each) => each.toUpperCase() - ).replace(/([^\d])_(\d+)/g, "$1$2") - ); - } - - static pascal( - identifier: string | Array, - removeDuplicates = true, - overrides: Record = {}, - maxUppercasePreserve = 0 - ): string { - return ( - (Object.keys(overrides).includes(identifier) && overrides[identifier]) || - applyFormat( - normalize(identifier, removeDuplicates, overrides, maxUppercasePreserve), - overrides, - "", - (each) => capitalize(each) - ) - ); - } - - static camel( - identifier: string | Array, - removeDuplicates = true, - overrides: Record = {}, - maxUppercasePreserve = 0 - ): string { - return ( - (Object.keys(overrides).includes(identifier) && overrides[identifier]) || - applyFormat( - normalize(identifier, removeDuplicates, overrides, maxUppercasePreserve), - overrides, - "", - (each, index) => - index - ? capitalize(each) - : IsFullyUpperCase(each, maxUppercasePreserve) - ? each - : uncapitalize(each) - ) - ); - } -} diff --git a/packages/http-client-java/emitter/src/prenamer/naming-utils.ts b/packages/http-client-java/emitter/src/prenamer/naming-utils.ts deleted file mode 100644 index d8e376158..000000000 --- a/packages/http-client-java/emitter/src/prenamer/naming-utils.ts +++ /dev/null @@ -1,219 +0,0 @@ -import { Languages } from "@autorest/codemodel"; -import { deconstruct, fixLeadingNumber, removeSequentialDuplicates } from "@azure-tools/codegen"; -import pkg from "lodash"; -import { Style, Styler } from "./formatter.js"; -const { last } = pkg; - -export function getNameOptions(typeName: string, components: Array) { - const result = new Set(); - - // add a variant for each incrementally inclusive parent naming scheme. - for (let i = 0; i < components.length; i++) { - const subset = Style.pascal([ - ...removeSequentialDuplicates(components.slice(-1 * i, components.length)), - ]); - result.add(subset); - } - - // add a second-to-last-ditch option as . - result.add( - Style.pascal([ - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - ...removeSequentialDuplicates([ - ...fixLeadingNumber(deconstruct(typeName)), - ...deconstruct(last(components)!), - ]), - ]) - ); - return [...result.values()]; -} - -interface SetNameOptions { - /** - * Remove consecutive duplicate words in the name. - * @example "FooBarBarSomething" -> "FooBarSomething" - */ - removeDuplicates?: boolean; - - /** - * Error message if a name is empty. - */ - nameEmptyErrorMessage?: string; -} - -const setNameDefaultOptions = Object.freeze({ - removeDuplicates: true, -}); - -export interface Nameable { - language: Languages; -} - -export class NamingService { - public constructor() {} - - public setName( - thing: Nameable, - styler: Styler, - defaultValue: string, - overrides: Record, - options?: SetNameOptions - ) { - this.setNameAllowEmpty(thing, styler, defaultValue, overrides, options); - // if (!thing.language.default.name) { - // this.session.error(options?.nameEmptyErrorMessage ?? getNameEmptyError(thing), ["Prenamer", "NameEmpty"], thing); - // } - } - - public setNameAllowEmpty( - thing: Nameable, - styler: Styler, - defaultValue: string, - overrides: Record, - options?: SetNameOptions - ) { - options = { ...setNameDefaultOptions, ...options }; - thing.language.default.name = styler( - defaultValue && isUnassigned(thing.language.default.name) - ? defaultValue - : thing.language.default.name, - options.removeDuplicates, - overrides - ); - } -} - -export function isUnassigned(value: string) { - return !value || value.indexOf("·") > -1; -} - -export interface ScopeNamerOptions { - deduplicateNames?: boolean; - overrides?: Record; -} - -interface NamerEntry { - entity: Nameable; - styler: Styler; - initialName: string; -} - -/** - * Class that will style and resolve unique names for entities in the same scope. - */ -export class ScopeNamer { - private names = new Map(); - - public constructor(private options: ScopeNamerOptions) {} - - /** - * Add a nameable entity to be styled and named. - * @param entity Nameable entity. - * @param styler Styler to use to render name. - * @param defaultName Default name in case entity doesn't have any specified. - */ - public add(entity: Nameable, styler: Styler, defaultName?: string) { - const initialName = - defaultName && isUnassigned(entity.language.default.name) - ? defaultName - : entity.language.default.name; - - const name = styler(initialName, false, this.options.overrides); - const list = this.names.get(name); - const entry = { entity, styler, initialName }; - if (list) { - list.push(entry); - } else { - this.names.set(name, [entry]); - } - } - - /** - * Returns true if the name is already used in this scope. - * @param name Name to check - * @returns Boolean - */ - public isUsed(name: string): boolean { - return this.names.has(name); - } - - /** - * Trigger the renaming process. - * Will go over all the entity and find best possible names. - */ - public process() { - const state = this.processSimplifyNames(); - if (this.options.deduplicateNames) { - this.deduplicateNames(state); - } - } - - /** - * 1st pass of the name resolving where it tries to simplify names with duplicate consecutive words. - */ - private processSimplifyNames(): Map { - const processedNames = new Map(); - for (const [name, entities] of this.names.entries()) { - for (const { entity, styler, initialName } of entities) { - let selectedName = name; - const noDupName = styler(initialName, true, this.options.overrides); - if (noDupName !== name) { - if (!this.names.has(noDupName) && !processedNames.has(noDupName)) { - selectedName = noDupName; - } - } - - entity.language.default.name = selectedName; - const entries = processedNames.get(selectedName); - if (entries) { - entries.push(entity); - } else { - processedNames.set(selectedName, [entity]); - } - } - } - return processedNames; - } - - /** - * 2nd pass of the name resolving where it will deduplicate names used twice. - */ - private deduplicateNames(names: Map) { - const entityNames = new Set(names.keys()); - for (const [_, entries] of names.entries()) { - if (entries.length > 1) { - for (const entity of entries.slice(1)) { - this.deduplicateSchemaName(entity, entityNames); - } - } - } - } - - /** - * Tries to find a new compatible name for the given schema. - */ - private deduplicateSchemaName(schema: Nameable, entityNames: Set): void { - const schemaName = schema.language.default.name; - const maxDedupes = 1000; - if (entityNames.has(schemaName)) { - for (let i = 1; i <= maxDedupes; i++) { - const newName = `${schemaName}AutoGenerated${i === 1 ? "" : i}`; - if (!entityNames.has(newName)) { - schema.language.default.name = newName; - entityNames.add(newName); - // this.session.warning(`Deduplicating schema name: '${schemaName}' -> '${newName}'`, [ - // "PreNamer/DeduplicateName", - // ]); - return; - } - } - - // this.session.error( - // `Attempted to deduplicate schema name '${schema.language.default.name}' more than ${maxDedupes} times and failed.`, - // ["PreNamer/DeduplicateName"], - // ); - } - - entityNames.add(schemaName); - } -} diff --git a/packages/http-client-java/emitter/src/prenamer/prenamer.ts b/packages/http-client-java/emitter/src/prenamer/prenamer.ts deleted file mode 100644 index d10df9f37..000000000 --- a/packages/http-client-java/emitter/src/prenamer/prenamer.ts +++ /dev/null @@ -1,475 +0,0 @@ -import { - getAllParentProperties, - ImplementationLocation, - isObjectSchema, - isVirtualParameter, - Languages, - ObjectSchema, - Parameter, - Response, - SchemaType, -} from "@autorest/codemodel"; -import { selectName } from "@azure-tools/codegen"; -import pkg from "lodash"; -import { CodeModel } from "../common/code-model.js"; -import { Operation, Request } from "../common/operation.js"; -import { ChoiceSchema, SealedChoiceSchema } from "../common/schemas/choice.js"; -import { Style } from "./formatter.js"; -import { getNameOptions, isUnassigned, NamingService, ScopeNamer } from "./naming-utils.js"; -const { partition } = pkg; - -export class PreNamer { - codeModel: CodeModel; - options: any = {}; - format = { - parameter: Style.camel, - property: Style.camel, - operation: Style.camel, - operationGroup: Style.pascal, - responseHeader: Style.camel, - choice: Style.pascal, - choiceValue: Style.upper, - constant: Style.pascal, - constantParameter: Style.camel, - type: Style.pascal, - client: Style.pascal, - local: Style.camel, - global: Style.pascal, - override: >{}, - }; - - enum = 0; - constant = 0; - - private namingService: NamingService; - - constructor(codeModel: CodeModel) { - this.codeModel = codeModel; - this.namingService = new NamingService(); - } - - init() { - // get our configuration for this run. - this.options = { - prenamer: true, - naming: { - parameter: "camel", - property: "camel", - operation: "camel", - operationGroup: "pascal", - choice: "pascal", - choiceValue: "upper", - constant: "pascal", - constantParameter: "camel", - client: "pascal", - type: "pascal", - local: "camel", - global: "camel", - "preserve-uppercase-max-length": 1, - }, - }; - const naming = this.options.naming || {}; - const maxPreserve = Number(naming["preserve-uppercase-max-length"]) || 3; - this.format = { - parameter: Style.select(naming.parameter, Style.camel, maxPreserve), - property: Style.select(naming.property, Style.camel, maxPreserve), - operation: Style.select(naming.operation, Style.camel, maxPreserve), - operationGroup: Style.select(naming.operationGroup, Style.pascal, maxPreserve), - responseHeader: Style.select(naming.header, Style.camel, maxPreserve), - choice: Style.select(naming.choice, Style.pascal, maxPreserve), - choiceValue: Style.select(naming.choiceValue, Style.upper, maxPreserve), - constant: Style.select(naming.constant, Style.pascal, maxPreserve), - constantParameter: Style.select(naming.constantParameter, Style.camel, maxPreserve), - client: Style.select(naming.client, Style.pascal, maxPreserve), - type: Style.select(naming.type, Style.pascal, maxPreserve), - local: Style.select(naming.local, Style.camel, maxPreserve), - global: Style.select(naming.global, Style.pascal, maxPreserve), - override: naming.override || {}, - }; - return this; - } - - process() { - if (this.options["prenamer"] === false) { - return this.codeModel; - } - - const deduplicateSchemaNames = - !!this.options["lenient-model-deduplication"] || - !!this.options["resolve-schema-name-collisons"]; - - const scopeNamer = new ScopeNamer({ - deduplicateNames: deduplicateSchemaNames, - overrides: this.format.override, - }); - - // choice - this.processChoiceNames(this.codeModel.schemas.choices, scopeNamer); - - // sealed choice - this.processChoiceNames(this.codeModel.schemas.sealedChoices, scopeNamer); - - // constant - for (const schema of values(this.codeModel.schemas.constants)) { - this.namingService.setName( - schema, - this.format.constant, - `Constant${this.enum++}`, - this.format.override - ); - } - - // ors - for (const schema of values(this.codeModel.schemas.ors)) { - this.namingService.setName( - schema, - this.format.type, - `Union${this.enum++}`, - this.format.override - ); - } - - // strings - for (const schema of values(this.codeModel.schemas.strings)) { - this.namingService.setName(schema, this.format.type, schema.type, this.format.override); - } - - // number - for (const schema of values(this.codeModel.schemas.numbers)) { - this.namingService.setName(schema, this.format.type, schema.type, this.format.override); - } - - for (const schema of values(this.codeModel.schemas.dates)) { - this.namingService.setName(schema, this.format.type, schema.type, this.format.override); - } - for (const schema of values(this.codeModel.schemas.dateTimes)) { - this.namingService.setName(schema, this.format.type, schema.type, this.format.override); - } - for (const schema of values(this.codeModel.schemas.durations)) { - this.namingService.setName(schema, this.format.type, schema.type, this.format.override); - } - for (const schema of values(this.codeModel.schemas.uuids)) { - this.namingService.setName(schema, this.format.type, schema.type, this.format.override); - } - - for (const schema of values(this.codeModel.schemas.uris)) { - this.namingService.setName(schema, this.format.type, schema.type, this.format.override); - } - - for (const schema of values(this.codeModel.schemas.unixtimes)) { - this.namingService.setName(schema, this.format.type, schema.type, this.format.override); - - if (isUnassigned(schema.language.default.description)) { - schema.language.default.description = "date in seconds since 1970-01-01T00:00:00Z."; - } - } - - for (const schema of values(this.codeModel.schemas.byteArrays)) { - this.namingService.setName(schema, this.format.type, schema.type, this.format.override); - } - - for (const schema of values(this.codeModel.schemas.chars)) { - this.namingService.setName(schema, this.format.type, schema.type, this.format.override); - } - - for (const schema of values(this.codeModel.schemas.booleans)) { - this.namingService.setName(schema, this.format.type, schema.type, this.format.override); - } - - for (const schema of values(this.codeModel.schemas.flags)) { - this.namingService.setName(schema, this.format.type, schema.type, this.format.override); - } - - // dictionary - for (const schema of values(this.codeModel.schemas.dictionaries)) { - this.namingService.setName( - schema, - this.format.type, - `DictionaryOf${schema.elementType.language.default.name}`, - this.format.override - ); - if (isUnassigned(schema.language.default.description)) { - schema.language.default.description = `Dictionary of ${schema.elementType.language.default.name}`; - } - } - - for (const schema of values(this.codeModel.schemas.arrays)) { - this.namingService.setName( - schema, - this.format.type, - `ArrayOf${schema.elementType.language.default.name}`, - this.format.override - ); - if (isUnassigned(schema.language.default.description)) { - schema.language.default.description = `Array of ${schema.elementType.language.default.name}`; - } - } - - for (const schema of values(this.codeModel.schemas.objects)) { - scopeNamer.add(schema, this.format.type, ""); - - const propertyScopeName = new ScopeNamer({ - deduplicateNames: false, - overrides: this.format.override, - }); - - for (const property of values(schema.properties)) { - propertyScopeName.add(property, this.format.property, ""); - } - propertyScopeName.process(); - } - - for (const schema of values(this.codeModel.schemas.groups)) { - scopeNamer.add(schema, this.format.type, ""); - - for (const property of values(schema.properties)) { - this.namingService.setName(property, this.format.property, "", this.format.override); - } - } - - for (const parameter of values(this.codeModel.globalParameters)) { - if (parameter.schema.type === SchemaType.Constant) { - this.namingService.setName( - parameter, - this.format.constantParameter, - "", - this.format.override - ); - } else { - this.namingService.setName(parameter, this.format.parameter, "", this.format.override); - } - } - - for (const operationGroup of this.codeModel.operationGroups) { - this.namingService.setNameAllowEmpty( - operationGroup, - this.format.operationGroup, - operationGroup.$key, - this.format.override, - { - removeDuplicates: false, - } - ); - const operationScopeNamer = new ScopeNamer({ - overrides: this.format.override, - }); - for (const operation of operationGroup.operations) { - operationScopeNamer.add(operation, this.format.operation, ""); - - this.setParameterNames(operation); - for (const request of values(operation.requests)) { - this.setParameterNames(request); - } - - for (const response of values(operation.responses)) { - this.setResponseHeaderNames(response); - } - for (const response of values(operation.exceptions)) { - this.setResponseHeaderNames(response); - } - - const convenienceApi = (operation as Operation).convenienceApi; - if (convenienceApi) { - this.namingService.setName( - convenienceApi, - this.format.operation, - "", - this.format.override - ); - } - - const p = operation.language.default.paging; - if (p) { - p.group = p.group - ? this.format.operationGroup(p.group, true, this.format.override) - : undefined; - p.member = p.member - ? this.format.operation(p.member, true, this.format.override) - : undefined; - } - } - - operationScopeNamer.process(); - } - - scopeNamer.process(); - - // set a styled client name - this.namingService.setName( - this.codeModel, - this.format.client, - this.codeModel.info.title, - this.format.override - ); - - if (this.codeModel.clients) { - // client - for (const client of this.codeModel.clients) { - this.namingService.setName(client, this.format.client, "", this.format.override); - - // operation group - for (const operationGroup of client.operationGroups) { - this.namingService.setNameAllowEmpty( - operationGroup, - this.format.operationGroup, - operationGroup.$key, - this.format.override, - { - removeDuplicates: false, - } - ); - } - } - } - - // fix collisions from flattening on ObjectSchemas - this.fixPropertyCollisions(); - - // fix collisions from flattening on VirtualParameters - this.fixParameterCollisions(); - - return this.codeModel; - } - - private processChoiceNames( - choices: Array | undefined, - scopeNamer: ScopeNamer - ) { - for (const schema of values(choices)) { - scopeNamer.add(schema, this.format.choice, `Enum${this.enum++}`); - - for (const choice of values(schema.choices)) { - this.namingService.setName(choice, this.format.choiceValue, "", this.format.override, { - removeDuplicates: false, - nameEmptyErrorMessage: `Enum '${schema.language.default.name}' cannot have a value '${choice.value}' that result in an empty name. Use x-ms-enum.values to specify the name of the values.`, - }); - } - } - } - - private setParameterNames(parameterContainer: Operation | Request) { - for (const parameter of values(parameterContainer.signatureParameters)) { - if (parameter.schema.type === SchemaType.Constant) { - this.namingService.setName( - parameter, - this.format.constantParameter, - "", - this.format.override - ); - } else { - this.namingService.setName(parameter, this.format.parameter, "", this.format.override); - } - } - for (const parameter of values(parameterContainer.parameters)) { - if ((parameterContainer.signatureParameters ?? []).indexOf(parameter) === -1) { - if (parameter.schema.type === SchemaType.Constant) { - this.namingService.setName( - parameter, - this.format.constantParameter, - "", - this.format.override - ); - } else { - if (parameter.implementation === ImplementationLocation.Client) { - this.namingService.setName(parameter, this.format.global, "", this.format.override); - } else { - this.namingService.setName(parameter, this.format.local, "", this.format.override); - } - } - } - } - } - - private setResponseHeaderNames(response: Response) { - if (response.protocol.http) { - for (const header of Object.values(response.protocol.http.headers ?? {})) { - this.namingService.setName( - header as { language: Languages }, - this.format.responseHeader, - "", - this.format.override - ); - } - } - } - - fixParameterCollisions() { - for (const operation of values(this.codeModel.operationGroups).flatMap( - (each) => each.operations - )) { - for (const request of values(operation.requests)) { - const parameters = values(operation.signatureParameters).concat( - values(request.signatureParameters) - ); - - const usedNames = new Set(); - const collisions = new Set(); - - // we need to make sure we avoid name collisions. operation parameters get first crack. - for (const each of values(parameters)) { - const name = this.format.parameter(each.language.default.name); - - if (usedNames.has(name)) { - collisions.add(each); - } else { - usedNames.add(name); - } - } - - // handle operation parameters - for (const parameter of collisions) { - let options = [parameter.language.default.name]; - if (isVirtualParameter(parameter)) { - options = getNameOptions(parameter.schema.language.default.name, [ - parameter.language.default.name, - ...parameter.pathToProperty.map((each) => each.language.default.name), - ]).map((each) => this.format.parameter(each)); - } - parameter.language.default.name = this.format.parameter(selectName(options, usedNames)); - } - } - } - } - - fixCollisions(schema: ObjectSchema) { - for (const each of values(schema.parents?.immediate).filter((each) => isObjectSchema(each))) { - this.fixCollisions(each); - } - const [owned, flattened] = partition( - schema.properties ?? [], - (each) => each.flattenedNames === undefined || each.flattenedNames.length === 0 - ); - const inherited = [...getAllParentProperties(schema)]; - - const all = [...owned, ...inherited, ...flattened]; - - const inlined = new Map(); - for (const each of all) { - const name = this.format.property(each.language.default.name); - // track number of instances of a given name. - inlined.set(name, (inlined.get(name) || 0) + 1); - } - - const usedNames = new Set(inlined.keys()); - for (const each of flattened /*.sort((a, b) => length(a.nameOptions) - length(b.nameOptions)) */) { - const ct = inlined.get(this.format.property(each.language.default.name)); - if (ct && ct > 1) { - const options = getNameOptions(each.schema.language.default.name, [ - each.language.default.name, - ...values(each.flattenedNames), - ]); - each.language.default.name = this.format.property(selectName(options, usedNames)); - } - } - } - - fixPropertyCollisions() { - for (const schema of values(this.codeModel.schemas.objects)) { - this.fixCollisions(schema); - } - } -} - -function values(item: T[] | undefined): T[] { - return Object.values(item ?? []); -}