Skip to content
This repository has been archived by the owner on Oct 11, 2023. It is now read-only.

Commit

Permalink
Don't prevent duplicate names if lenient-model-deduplication is enabl…
Browse files Browse the repository at this point in the history
…ed (#381)
  • Loading branch information
timotheeguerin authored Jan 19, 2021
1 parent cc1767b commit 4d99ac0
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 34 deletions.
21 changes: 16 additions & 5 deletions modelerfour/src/prenamer/naming-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ interface SetNameOptions {
* Set containing the list of names already used in the given scope.
*/
existingNames?: Set<string>;

/**
* If it should allow duplicate models.(Later in the pipeline duplicate models will be deduplicated.)
*/
lenientModelDeduplication?: boolean;
}

const setNameDefaultOptions: SetNameOptions = Object.freeze({
Expand Down Expand Up @@ -61,21 +66,27 @@ export function setNameAllowEmpty(

const initialName =
defaultValue && isUnassigned(thing.language.default.name) ? defaultValue : thing.language.default.name;

const namingOptions = [
...(options.removeDuplicates ? [styler(initialName, true, overrides)] : []),
styler(initialName, false, overrides),
initialName,
];

for(const newName of namingOptions) {
// Check if the new name is not yet taken.
if (newName && !options.existingNames?.has(newName)) {
for (const newName of namingOptions) {
// Check if the new name is not yet taken or lenientModelDeduplication is enabled then we don't care about duplicates.
if (newName && (!options.existingNames?.has(newName) || options.lenientModelDeduplication)) {
options.existingNames?.add(newName);
thing.language.default.name = newName;
return;
}
}
// We didn't find a compatible name. Ignoring the renaming silently.

if (initialName != "") {
const namingOptionsStr = namingOptions.join(",");
throw new Error(
`Couldn't style name '${initialName}'. All of the following naming possibilities created duplicate names: [${namingOptionsStr}]. You can try using 'modelerfour.lenient-model-deduplication' to allow such duplicates.`,
);
}
}

export function isUnassigned(value: string) {
Expand Down
36 changes: 10 additions & 26 deletions modelerfour/src/prenamer/prenamer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export class PreNamer {
const deduplicateSchemaNames =
!!this.options["lenient-model-deduplication"] || !!this.options["resolve-schema-name-collisons"];

const existingNames = getGlobalScopeNames(this.codeModel);
const existingNames = new Set<string>();

// choice
this.processChoiceNames(this.codeModel.schemas.choices, existingNames, deduplicateSchemaNames);
Expand Down Expand Up @@ -203,7 +203,7 @@ export class PreNamer {

const objectSchemaNames = new Set<string>();
for (const schema of values(this.codeModel.schemas.objects)) {
setName(schema, this.format.type, "", this.format.override, { existingNames });
setName(schema, this.format.type, "", this.format.override, { existingNames, lenientModelDeduplication: this.options["lenient-model-deduplication"] });

if (deduplicateSchemaNames) {
deduplicateSchemaName(
Expand All @@ -221,7 +221,10 @@ export class PreNamer {

const groupSchemaNames = new Set<string>();
for (const schema of values(this.codeModel.schemas.groups)) {
setName(schema, this.format.type, "", this.format.override, { existingNames });
setName(schema, this.format.type, "", this.format.override, {
existingNames,
lenientModelDeduplication: this.options["lenient-model-deduplication"],
});

if (deduplicateSchemaNames) {
deduplicateSchemaName(
Expand Down Expand Up @@ -291,7 +294,10 @@ export class PreNamer {
) {
const choiceSchemaNames = new Set<string>();
for (const schema of values(choices)) {
setName(schema, this.format.choice, `Enum${this.enum++}`, this.format.override, { existingNames });
setName(schema, this.format.choice, `Enum${this.enum++}`, this.format.override, {
existingNames,
lenientModelDeduplication: this.options["lenient-model-deduplication"],
});

if (deduplicateSchemaNames) {
deduplicateSchemaName(schema, choiceSchemaNames, this.session);
Expand Down Expand Up @@ -403,25 +409,3 @@ export class PreNamer {
}
}
}

/**
* Returns a new set containing all the names in the global scopes for the given CodeModel.
* This correspond to the names of
* - Enums/Choices
* - Objects/Models
* - Groups
* - SealedChoices
* @param codeModel CodeModel
*/
const getGlobalScopeNames = (codeModel: CodeModel): Set<string> => {
return new Set(
[
...(codeModel.schemas.choices ?? []),
...(codeModel.schemas.objects ?? []),
...(codeModel.schemas.groups ?? []),
...(codeModel.schemas.sealedChoices ?? []),
]
.map((x) => x.language.default.name)
.filter((x) => !isUnassigned(x)),
);
};
29 changes: 26 additions & 3 deletions modelerfour/test/prenamer/prenamer.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { CodeModel, ObjectSchema } from "@azure-tools/codemodel";
import { ModelerFourOptions } from "modeler/modelerfour-options";
import { PreNamer } from "../../src/prenamer/prenamer";
import { createTestSessionFromModel } from "../utils";

const runPrenamer = async (model: CodeModel) => {
const { session } = await createTestSessionFromModel<CodeModel>({}, model);
const runPrenamer = async (model: CodeModel, options: ModelerFourOptions = {}) => {
const { session } = await createTestSessionFromModel<CodeModel>({ modelerfour: options }, model);
const prenamer = new PreNamer(session);
await prenamer.init();
return prenamer.process();
};

Expand All @@ -31,10 +33,31 @@ describe("Prenamer", () => {

it("Keeps duplicate consecutive words if the new name already exists and still style the word", async () => {
model.schemas.add(new ObjectSchema("FooBar", "Description"));
model.schemas.add(new ObjectSchema("fooBAR-Bar", "Description"));
model.schemas.add(new ObjectSchema("fooBar-Bar", "Description"));
const result = await runPrenamer(model);
expect(result.schemas.objects?.[0].language.default.name).toEqual("FooBar");
expect(result.schemas.objects?.[1].language.default.name).toEqual("FooBarBar");
});

it("throws an error if all styling options are already taken", async () => {
model.schemas.add(new ObjectSchema("FooBar", "Description"));
model.schemas.add(new ObjectSchema("FooBarBar", "Description"));
model.schemas.add(new ObjectSchema("fooBar-Bar", "Description"));

await expect(() => runPrenamer(model)).rejects.toThrowError(
"Couldn't style name 'fooBar-Bar'. All of the following naming possibilities created duplicate names: [FooBar,FooBarBar]. You can try using 'modelerfour.lenient-model-deduplication' to allow such duplicates.",
);
});

it("creates duplicates if there is no options and lenient-model-deduplication is enabled", async () => {
model.schemas.add(new ObjectSchema("FooBar", "Description"));
model.schemas.add(new ObjectSchema("FooBarBar", "Description"));

const result = await runPrenamer(model, {
"lenient-model-deduplication": true,
});
expect(result.schemas.objects?.[0].language.default.name).toEqual("FooBar");
expect(result.schemas.objects?.[1].language.default.name).toEqual("FooBarAutoGenerated");
});
});
});

0 comments on commit 4d99ac0

Please sign in to comment.