Files
astrolabe/src/core/naming.ts
T

47 lines
2.0 KiB
TypeScript

/**
* Name uniqueness for datasets (spec §05 → Naming & Uniqueness;
* docs/architecture/07 §2).
*
* Portable core: no browser APIs, no React, no store access — plain data in,
* plain data out. Dataset names are the key snippets reference via
* `datasetRefs` and the contract a Vega-Lite spec uses through
* `{ "data": { "name": "..." } }`, so they must be unique. Comparisons are
* **case-insensitive** throughout (`Sales` and `sales` collide) so a single
* display name maps to a single dataset regardless of how a reference is typed.
*
* - `isNameTaken` — reject duplicate create/rename in the UI. `excludeId` lets
* a rename ignore the record being renamed (renaming `Sales` to `Sales`, or a
* case-only edit, is not a self-collision).
* - `makeUniqueName` — for non-interactive paths (import, extract, build chart)
* where blocking the user is worse than a silent, reported rename: derive the
* next free `${base} ${n}` (n ≥ 2). We never parse meaning out of a name; a
* base already ending in a number still just gets a suffix (`Q1 2024 2`).
*/
/** Case-insensitive: is `desired` already used by another dataset (minus `excludeId`)? */
export function isNameTaken(
desired: string,
datasets: ReadonlyArray<{ id: number; name: string }>,
excludeId?: number,
): boolean {
const lower = desired.trim().toLowerCase();
return datasets.some((d) => d.id !== excludeId && d.name.toLowerCase() === lower);
}
/**
* Returns `desired` (trimmed) if free, else the first available `${desired} ${n}`
* (n ≥ 2). `existingNames` is the set of names already in the collection.
* Comparison is case-insensitive; the returned name preserves `desired`'s casing.
*/
export function makeUniqueName(desired: string, existingNames: Iterable<string>): string {
const taken = new Set<string>();
for (const n of existingNames) taken.add(n.toLowerCase());
const base = desired.trim();
if (!taken.has(base.toLowerCase())) return base;
let n = 2;
while (taken.has(`${base} ${n}`.toLowerCase())) n++;
return `${base} ${n}`;
}