@sap-cloud-sdk/util
Version:
SAP Cloud SDK for JavaScript general utilities
131 lines • 7.31 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.UniqueNameGenerator = void 0;
/**
* Holds state on already used names and provides new names if there are naming conflicts.
*/
class UniqueNameGenerator {
static getNameForComparison(name, caseSensitive) {
return caseSensitive ? name : name.toLowerCase();
}
/**
* Creates an instance of UniqueNameGenerator.
* @param indexSeparator - The separator to be used when adding an index.
* @param usedNames - Sets the already used names considered in the finding process.
*/
constructor(indexSeparator = '_', usedNames = []) {
this.indexSeparator = indexSeparator;
this.usedNames = [];
this.addToUsedNames(...usedNames);
}
/**
* Adds the name(s) to the already used names.
* @param names - Names to be added.
*/
addToUsedNames(...names) {
this.usedNames.push(...names);
}
/**
* Generate a unique name by appending an index separated by the `indexSeparator` if necessary, e.g. if `MyName` is already taken `MyName_1` will be found by default.
* If the name is already unique nothing is appended.
* @param name - The name to get a unique name from.
* @param caseSensitive - Whether to check the already used names in a case sensitive manner.
* @returns A unique name.
*/
generateUniqueName(name, caseSensitive = true) {
return this.generateUniqueNamesWithSuffixes(name, [], caseSensitive)[0];
}
/**
* Generate a unique name by appending an index separated by the `indexSeparator` if necessary, e.g. if `MyName` is already taken `MyName_1` will be found by default.
* The generated name is added to the used names.
* If the name is already unique nothing is appended.
* @param name - The name to get a unique name from.
* @param caseSensitive - Whether to check the already used names in a case sensitive manner.
* @returns A unique name.
*/
generateAndSaveUniqueName(name, caseSensitive = true) {
const uniqueName = this.generateUniqueName(name, caseSensitive);
this.addToUsedNames(uniqueName);
return uniqueName;
}
/**
* Generate unique names by appending an index separated by the `indexSeparator` if necessary, while respecting the given suffixes.
* If the name is already unique nothing is appended.
* Each given suffix is appended to the unique name in the result.
* The resulting names are also checked for uniqueness.
* All names in the result have the same number suffix.
* @example if `MyName` and `MyName_1MySuffix` is already taken, `[MyName_2, MyName_2MySuffix]` will be generated by default.
* @param name - The name to get a unique name from.
* @param suffixes - Additional name of suffixes to be considered for the finding process, as well as the output.
* @param caseSensitive - Whether to check the already used names in a case sensitive manner.
* @returns A list of unique names. The length of this array is one plus the number of suffixes provided. The first entry corresponds to the given name.
*/
generateUniqueNamesWithSuffixes(name, suffixes, caseSensitive = true) {
// Filter names to those that might be relevant for performance reasons
const relevantUsedNames = this.getUsedNamesStartingWith(name, caseSensitive);
const namesWithSuffixes = this.generateNamesWithSuffixes(name, suffixes);
// Names do not need index
if (!this.areNamesUsed(namesWithSuffixes, relevantUsedNames, caseSensitive)) {
return [name, ...namesWithSuffixes];
}
// Names do need index
const index = this.getUniqueIndex(name, relevantUsedNames, suffixes, caseSensitive);
return this.generateNamesWithIndexAndSuffixes(name, index, suffixes);
}
/**
* Generate unique names by appending an index separated by the `indexSeparator` if necessary, while respecting the given suffixes.
* If the name is already unique nothing is appended.
* The generated names are added to the used names.
* Each given suffix is appended to the unique name in the result.
* The resulting names are also checked for uniqueness.
* All names in the result have the same number suffix.
* @example if `MyName` and `MyName_1MySuffix` is already taken, `[MyName_2, MyName_2MySuffix]` will be generated by default.
* @param name - The name to get a unique name from.
* @param suffixes - Additional name of suffixes to be considered for the finding process, as well as the output.
* @param caseSensitive - Whether to check the already used names in a case sensitive manner.
* @returns A list of unique names. The length of this array is one plus the number of suffixes provided. The first entry corresponds to the given name.
*/
generateAndSaveUniqueNamesWithSuffixes(name, suffixes, caseSensitive = true) {
const uniqueNames = this.generateUniqueNamesWithSuffixes(name, suffixes, caseSensitive);
this.addToUsedNames(...uniqueNames);
return uniqueNames;
}
getUsedNamesForComparison(caseSensitive) {
return this.usedNames.map(name => UniqueNameGenerator.getNameForComparison(name, caseSensitive));
}
areNamesUsed(names, usedNames, caseSensitive) {
return names.some(name => usedNames
.map(usedName => UniqueNameGenerator.getNameForComparison(usedName, caseSensitive))
.includes(UniqueNameGenerator.getNameForComparison(name, caseSensitive)));
}
generateNamesWithIndexAndSuffixes(name, index, suffixes) {
const nameWithoutIndex = this.getNameWithoutIndex(name);
return this.generateNamesWithSuffixes(`${nameWithoutIndex}${this.indexSeparator}${index}`, suffixes);
}
generateNamesWithSuffixes(name, suffixes) {
return [name, ...suffixes.map(nameSuffix => `${name}${nameSuffix}`)];
}
getUsedNamesStartingWith(name, caseSensitive) {
const modifiedName = this.getNameWithoutIndex(name);
return this.getUsedNamesForComparison(caseSensitive).filter(used => used.startsWith(UniqueNameGenerator.getNameForComparison(modifiedName, caseSensitive)));
}
getUniqueIndex(name, usedNames, suffixes, caseSensitive) {
let index = 1;
// This algorithm has order N**2 for N identical names. With a sort you could get it down to N*log(N).
// However with the related items in mind this is much easier and N should be small anyway.
while (index < UniqueNameGenerator.MAXIMUM_NUMBER_OF_SUFFIX) {
const newNames = this.generateNamesWithIndexAndSuffixes(name, index, suffixes);
if (!this.areNamesUsed(newNames, usedNames, caseSensitive)) {
return index;
}
index++;
}
throw new Error(`Unable to find a unique name for ${name} within the range of ${UniqueNameGenerator.MAXIMUM_NUMBER_OF_SUFFIX} suffixes.`);
}
getNameWithoutIndex(name) {
return name.replace(new RegExp(`${this.indexSeparator}\\d+$`), '');
}
}
exports.UniqueNameGenerator = UniqueNameGenerator;
UniqueNameGenerator.MAXIMUM_NUMBER_OF_SUFFIX = 1000;
//# sourceMappingURL=unique-name-generator.js.map