UNPKG

@speckle/shared

Version:

Shared code between various Speckle JS packages

239 lines 7.22 kB
import { isString, uniq, uniqBy } from '#lodash'; export const ViewerResourceType = { Model: 'Model', Object: 'Object', ModelFolder: 'ModelFolder', AllModels: 'all-models' }; export class ViewerAllModelsResource { type = ViewerResourceType.AllModels; toString() { return 'all'; } } export class ViewerModelResource { type; modelId; versionId; constructor(modelId, versionId) { this.type = ViewerResourceType.Model; this.modelId = modelId.toLowerCase(); this.versionId = versionId?.toLowerCase(); } toString() { return (this.versionId ? `${this.modelId}@${this.versionId}` : this.modelId).toLowerCase(); } } export class ViewerVersionResource extends ViewerModelResource { versionId; constructor(modelId, versionId) { super(modelId, versionId); this.versionId = versionId?.toLowerCase(); } toJSON() { return this.toString(); } } export class ViewerObjectResource { type; objectId; constructor(objectId) { this.type = ViewerResourceType.Object; this.objectId = objectId.toLowerCase(); } toString() { return this.objectId.toLowerCase(); } } export class ViewerModelFolderResource { type; folderName; constructor(folderName) { this.type = ViewerResourceType.ModelFolder; this.folderName = folderName; } toString() { return '$' + this.folderName; } } export const parseResourceFromString = (resourceId) => { if (resourceId === 'all') { return new ViewerAllModelsResource(); } else if (resourceId.includes('@')) { const [modelId, versionId] = resourceId.split('@'); return new ViewerVersionResource(modelId, versionId); } else if (resourceId.startsWith('$')) { return new ViewerModelFolderResource(resourceId.substring(1)); } else if (resourceId.length === 32) { return new ViewerObjectResource(resourceId); } else { return new ViewerModelResource(resourceId); } }; export function parseUrlParameters(resourceGetParam) { if (!resourceGetParam?.length) return []; const parts = resourceGetParam .split(',') .filter((i) => i.trim().length) .sort(); const resources = []; for (const part of parts) { const resource = parseResourceFromString(part); if (resource) { resources.push(resource); } } // Remove duplicates return uniqBy(resources, (r) => r.toString()); } export function createGetParamFromResources(resources) { const resourceParts = uniq(resources.map((r) => r.toString())).sort(); return resourceParts.join(','); } export const isAllModelsResource = (r) => r.type === ViewerResourceType.AllModels; export const isModelResource = (r) => r.type === ViewerResourceType.Model; export const isObjectResource = (r) => r.type === ViewerResourceType.Object; export const isModelFolderResource = (r) => r.type === ViewerResourceType.ModelFolder; const toViewerResourceArray = (res) => { if (res instanceof ViewerResourceBuilder) { return res.toResources(); } const fixString = (r) => isString(r) ? parseUrlParameters(r) : [r]; if (Array.isArray(res)) { return res.flatMap(fixString); } else { return fixString(res); } }; class ViewerResourceBuilder { #resources = []; #order() { this.#resources = uniq(this.#resources).sort(); } addAllModels() { this.#resources.push(new ViewerAllModelsResource()); this.#order(); return this; } addModel(modelId, versionId) { this.#resources.push(new ViewerModelResource(modelId, versionId)); this.#order(); return this; } addModelFolder(folderName) { this.#resources.push(new ViewerModelFolderResource(folderName)); this.#order(); return this; } addObject(objectId) { this.#resources.push(new ViewerObjectResource(objectId)); this.#order(); return this; } /** * @deprecated Use 'addResources' or 'addNew' instead */ addFromString(stringResources) { const strings = Array.isArray(stringResources) ? stringResources : [stringResources]; for (const resourceIdString of strings) { const resources = parseUrlParameters(resourceIdString.toLowerCase()); this.#resources.push(...resources); } this.#order(); return this; } addResources(res) { this.#resources.push(...toViewerResourceArray(res)); this.#order(); return this; } /** * Only add those resources that are not already in the builder. */ addNew(incoming, options) { const { requireExactMatch = false } = options || {}; const resources = toViewerResourceArray(incoming); const newResources = this.#resources.slice(); for (const resource of resources) { // check if newResources has a resource w/ same modelId (check w/ isModelResource) if (isModelResource(resource) && !requireExactMatch) { const existing = newResources.find((r) => isModelResource(r) && r.modelId === resource.modelId); if (!existing) { newResources.push(resource); } } else if (!newResources.some((r) => r.toString() === resource.toString())) { newResources.push(resource); } } this.#resources = newResources; this.#order(); return this; } toString() { return createGetParamFromResources(this.#resources); } toResources() { return this.#resources.slice(); } toResourceIds() { return this.toResources().map((r) => r.toString()); } clear() { this.#resources = []; return this; } clone() { const clone = new ViewerResourceBuilder(); const resources = this.toString(); clone.addResources(resources); return clone; } get length() { return this.#resources.length; } /** * Remove specified versionIds from any model resources */ clearVersions() { this.#resources.forEach((r) => { if (!isModelResource(r)) return; r.versionId = undefined; }); return this; } isEqualTo(resource) { const incomingBuilder = resourceBuilder().addResources(resource); return this.toString() === incomingBuilder.toString(); } forEach(callback) { this.#resources.forEach(callback); return this; } filter(callback) { return this.#resources.filter(callback); } find(callback) { return this.#resources.find(callback); } map(callback) { return this.#resources.map(callback); } [Symbol.iterator]() { return this.#resources[Symbol.iterator](); } } /** * Fluent API for easier resource building */ export function resourceBuilder() { return new ViewerResourceBuilder(); } //# sourceMappingURL=route.js.map