62 lines
1.8 KiB
TypeScript
62 lines
1.8 KiB
TypeScript
import type {
|
|
SvgNode,
|
|
SvgPlugin,
|
|
SvgPluginOptions,
|
|
} from "../../types/common.js";
|
|
|
|
const CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
|
|
function toShortId(n: number): string {
|
|
if (n < CHARS.length) return CHARS[n]!;
|
|
return (
|
|
toShortId(Math.floor(n / CHARS.length) - 1) + CHARS[n % CHARS.length]!
|
|
);
|
|
}
|
|
|
|
export function createMangleIds(): SvgPlugin {
|
|
const idMap = new Map<string, string>();
|
|
let counter = 0;
|
|
|
|
function mangle(originalId: string): string {
|
|
const existing = idMap.get(originalId);
|
|
if (existing !== undefined) return existing;
|
|
const newId = toShortId(counter++);
|
|
idMap.set(originalId, newId);
|
|
return newId;
|
|
}
|
|
|
|
function rewriteRef(ref: string): string {
|
|
const originalId = ref.slice(1);
|
|
return `#${mangle(originalId)}`;
|
|
}
|
|
|
|
return {
|
|
name: "mangleIds",
|
|
apply(node: SvgNode, _options: SvgPluginOptions): SvgNode | null {
|
|
if (node.type !== "element") return node;
|
|
const attrs = node.attributes;
|
|
if (!attrs) return node;
|
|
|
|
let changed = false;
|
|
const next: Record<string, string> = { ...attrs };
|
|
|
|
if (next["id"]) {
|
|
next["id"] = mangle(next["id"]);
|
|
changed = true;
|
|
}
|
|
if (next["href"]?.startsWith("#")) {
|
|
next["href"] = rewriteRef(next["href"]);
|
|
changed = true;
|
|
}
|
|
if (next["xlink:href"]?.startsWith("#")) {
|
|
next["xlink:href"] = rewriteRef(next["xlink:href"]!);
|
|
changed = true;
|
|
}
|
|
|
|
return changed ? { ...node, attributes: next } : node;
|
|
},
|
|
};
|
|
}
|
|
|
|
export const mangleIds: SvgPlugin = createMangleIds();
|