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.
This commit is contained in:
Родитель
1dcd5c4c36
Коммит
b645fb3d6d
|
@ -27,7 +27,6 @@ words:
|
|||
- cobertura
|
||||
- codehaus
|
||||
- codeql
|
||||
- collisons
|
||||
- Contoso
|
||||
- CORGE
|
||||
- createsorreplacesresource
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<EmitterOptions> = {
|
|||
// 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 },
|
||||
|
|
|
@ -1,251 +0,0 @@
|
|||
import { fixLeadingNumber, removeSequentialDuplicates } from "@azure-tools/codegen";
|
||||
|
||||
export type Styler = (
|
||||
identifier: string | Array<string>,
|
||||
removeDuplicates: boolean | undefined,
|
||||
overrides: Record<string, string> | undefined
|
||||
) => string;
|
||||
type StylerWithUppercasePreservation = (
|
||||
identifier: string | Array<string>,
|
||||
removeDuplicates: boolean | undefined,
|
||||
overrides: Record<string, string> | 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<string>,
|
||||
maxUppercasePreserve: number
|
||||
): Array<string> {
|
||||
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<string>,
|
||||
overrides: Record<string, string> = {},
|
||||
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<string>,
|
||||
removeDuplicates = true,
|
||||
overrides: Record<string, string> = {},
|
||||
maxUppercasePreserve = 0
|
||||
): Array<string> {
|
||||
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<string>,
|
||||
removeDuplicates = true,
|
||||
overrides: Record<string, string> = {},
|
||||
maxUppercasePreserve = 0
|
||||
): string {
|
||||
return (
|
||||
(Object.keys(overrides).includes(<string>identifier) && overrides[<string>identifier]) ||
|
||||
applyFormat(
|
||||
normalize(identifier, removeDuplicates, overrides, maxUppercasePreserve),
|
||||
overrides,
|
||||
"-"
|
||||
).replace(/([^\d])-(\d+)/g, "$1$2")
|
||||
);
|
||||
}
|
||||
|
||||
static space(
|
||||
identifier: string | Array<string>,
|
||||
removeDuplicates = true,
|
||||
overrides: Record<string, string> = {},
|
||||
maxUppercasePreserve = 0
|
||||
): string {
|
||||
return (
|
||||
(Object.keys(overrides).includes(<string>identifier) && overrides[<string>identifier]) ||
|
||||
applyFormat(
|
||||
normalize(identifier, removeDuplicates, overrides, maxUppercasePreserve),
|
||||
overrides,
|
||||
" "
|
||||
).replace(/([^\d]) (\d+)/g, "$1$2")
|
||||
);
|
||||
}
|
||||
|
||||
static snake(
|
||||
identifier: string | Array<string>,
|
||||
removeDuplicates = true,
|
||||
overrides: Record<string, string> = {},
|
||||
maxUppercasePreserve = 0
|
||||
): string {
|
||||
return (
|
||||
(Object.keys(overrides).includes(<string>identifier) && overrides[<string>identifier]) ||
|
||||
applyFormat(
|
||||
normalize(identifier, removeDuplicates, overrides, maxUppercasePreserve),
|
||||
overrides,
|
||||
"_"
|
||||
).replace(/([^\d])_(\d+)/g, "$1$2")
|
||||
);
|
||||
}
|
||||
|
||||
static upper(
|
||||
identifier: string | Array<string>,
|
||||
removeDuplicates = true,
|
||||
overrides: Record<string, string> = {},
|
||||
maxUppercasePreserve = 0
|
||||
): string {
|
||||
return (
|
||||
(Object.keys(overrides).includes(<string>identifier) && overrides[<string>identifier]) ||
|
||||
applyFormat(
|
||||
normalize(identifier, removeDuplicates, overrides, maxUppercasePreserve),
|
||||
overrides,
|
||||
"_",
|
||||
(each) => each.toUpperCase()
|
||||
).replace(/([^\d])_(\d+)/g, "$1$2")
|
||||
);
|
||||
}
|
||||
|
||||
static pascal(
|
||||
identifier: string | Array<string>,
|
||||
removeDuplicates = true,
|
||||
overrides: Record<string, string> = {},
|
||||
maxUppercasePreserve = 0
|
||||
): string {
|
||||
return (
|
||||
(Object.keys(overrides).includes(<string>identifier) && overrides[<string>identifier]) ||
|
||||
applyFormat(
|
||||
normalize(identifier, removeDuplicates, overrides, maxUppercasePreserve),
|
||||
overrides,
|
||||
"",
|
||||
(each) => capitalize(each)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
static camel(
|
||||
identifier: string | Array<string>,
|
||||
removeDuplicates = true,
|
||||
overrides: Record<string, string> = {},
|
||||
maxUppercasePreserve = 0
|
||||
): string {
|
||||
return (
|
||||
(Object.keys(overrides).includes(<string>identifier) && overrides[<string>identifier]) ||
|
||||
applyFormat(
|
||||
normalize(identifier, removeDuplicates, overrides, maxUppercasePreserve),
|
||||
overrides,
|
||||
"",
|
||||
(each, index) =>
|
||||
index
|
||||
? capitalize(each)
|
||||
: IsFullyUpperCase(each, maxUppercasePreserve)
|
||||
? each
|
||||
: uncapitalize(each)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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<string>) {
|
||||
const result = new Set<string>();
|
||||
|
||||
// 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 <typename>.<name>
|
||||
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<string, string>,
|
||||
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<string, string>,
|
||||
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<string, string>;
|
||||
}
|
||||
|
||||
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<string, NamerEntry[]>();
|
||||
|
||||
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<string, Nameable[]> {
|
||||
const processedNames = new Map<string, Nameable[]>();
|
||||
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<string, Nameable[]>) {
|
||||
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<string>): 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);
|
||||
}
|
||||
}
|
|
@ -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: <Record<string, string>>{},
|
||||
};
|
||||
|
||||
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<ChoiceSchema | SealedChoiceSchema> | 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<string>();
|
||||
const collisions = new Set<Parameter>();
|
||||
|
||||
// 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(<ObjectSchema>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<string, number>();
|
||||
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<T>(item: T[] | undefined): T[] {
|
||||
return Object.values(item ?? []);
|
||||
}
|
Загрузка…
Ссылка в новой задаче