duplicate-name
Version:
duplicate name (1) duplicate name (2) duplicate name (3)
67 lines (66 loc) • 2.33 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.uniqueNameForList = uniqueNameForList;
const DEFAULT_TAG_RE = /\s\(([1-9]\d*)\)$/;
function defaultParse(name) {
const m = name.match(DEFAULT_TAG_RE);
if (!m)
return { base: name.trimEnd(), n: null };
const base = name.slice(0, name.length - m[0].length).trimEnd();
return { base, n: Number(m[1]) };
}
function defaultFormat(base, n) {
return `${base} (${n})`;
}
function uniqueNameForList(existingNames, desiredName, opts = {}) {
const { strategy = "end", keepProvidedNumber = true, caseSensitive = true, formatter = defaultFormat, } = opts;
const norm = (s) => (caseSensitive ? s : s.toLowerCase());
const existingSet = new Set();
for (const s of existingNames)
existingSet.add(norm(s.trimEnd()));
const desired = desiredName.trimEnd();
const { base, n } = defaultParse(desired);
const used = new Set();
for (const name of existingSet) {
const { base: b, n: k } = defaultParse(name);
if (norm(b) !== norm(base))
continue;
used.add(k !== null && k !== void 0 ? k : 0);
}
const taken = (candidate) => existingSet.has(norm(candidate));
if (n === null) {
if (base === "" && !taken(base))
return base;
if (used.size === 0 && !taken(base))
return base;
const pickByEnd = () => {
const max = used.size ? Math.max(...used) : 0;
return Math.max(1, max + 1);
};
const pickByFirstEmpty = () => {
let k = 1;
while (used.has(k))
k++;
return k;
};
const k = strategy === "firstEmpty" ? pickByFirstEmpty() : pickByEnd();
return formatter(base, k);
}
if (keepProvidedNumber) {
const candidate = defaultFormat(base, n);
if (!used.has(n) && !taken(candidate))
return candidate;
}
const pickByEnd = () => {
const max = used.size ? Math.max(...used) : 0;
return Math.max(1, max + 1);
};
const pickByFirstEmpty = () => {
let k = 1;
while (used.has(k))
k++;
return k;
};
const k = strategy === "firstEmpty" ? pickByFirstEmpty() : pickByEnd();
return formatter(base, k);
}