68 lines
2.3 KiB
TypeScript
68 lines
2.3 KiB
TypeScript
/**
|
|
* ParticlePath is a branded string type representing a URL-style path
|
|
* to a particle in the hierarchy: /{networkId}/{segment1}/{segment2}/...
|
|
*
|
|
* Using a branded type prevents accidentally passing raw strings where
|
|
* a validated particle path is expected.
|
|
*/
|
|
declare const __brand: unique symbol;
|
|
export type ParticlePath = string & { readonly [__brand]: true };
|
|
|
|
/**
|
|
* Construct a ParticlePath from a network ID and optional particle segments.
|
|
*
|
|
* @example
|
|
* particlePath("net1", []) // => "/net1"
|
|
* particlePath("net1", ["p1"]) // => "/net1/p1"
|
|
* particlePath("net1", ["p1","p2"])// => "/net1/p1/p2"
|
|
*/
|
|
export function particlePath(networkId: string, segments: string[] = []): ParticlePath {
|
|
return `/${[networkId, ...segments].join("/")}` as ParticlePath;
|
|
}
|
|
|
|
/**
|
|
* Parse a ParticlePath back into its network ID and particle segments.
|
|
*/
|
|
export function parseParticlePath(path: ParticlePath): {
|
|
networkId: string;
|
|
segments: string[];
|
|
} {
|
|
const parts = path.split("/").filter(Boolean);
|
|
return { networkId: parts[0], segments: parts.slice(1) };
|
|
}
|
|
|
|
/**
|
|
* Convert a ParticlePath to the Firestore document path for that particle.
|
|
*
|
|
* Firestore structure:
|
|
* /net1 → networks/net1/particles (collection)
|
|
* /net1/p1 → networks/net1/particles/p1 (document)
|
|
* /net1/p1/p2 → networks/net1/particles/p1/children/p2 (document)
|
|
*/
|
|
export function toFirestoreDocPath(path: ParticlePath): string {
|
|
const { networkId, segments } = parseParticlePath(path);
|
|
const base = `networks/${networkId}/particles`;
|
|
if (segments.length === 0) return base;
|
|
|
|
const parts: string[] = [base, segments[0]];
|
|
for (let i = 1; i < segments.length; i++) {
|
|
parts.push("children", segments[i]);
|
|
}
|
|
return parts.join("/");
|
|
}
|
|
|
|
/**
|
|
* Convert a ParticlePath to the Firestore collection path for its children.
|
|
*
|
|
* /net1 → networks/net1/particles (root particles)
|
|
* /net1/p1 → networks/net1/particles/p1/children
|
|
* /net1/p1/p2 → networks/net1/particles/p1/children/p2/children
|
|
*/
|
|
export function toFirestoreChildrenPath(path: ParticlePath): string {
|
|
const { segments } = parseParticlePath(path);
|
|
if (segments.length === 0) {
|
|
return toFirestoreDocPath(path);
|
|
}
|
|
return `${toFirestoreDocPath(path)}/children`;
|
|
}
|