UNPKG

solid-services

Version:

Solid.js library adding a services layer for global shared state.

160 lines (152 loc) 4.46 kB
'use strict'; Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const solidJs = require('solid-js'); const ServiceRegistryContext = solidJs.createContext(); const ServiceRegistry = (props) => { let registry; return solidJs.createComponent(ServiceRegistryContext.Provider, { get value() { return registry ??= createRegistry({ get expose() { return props.expose; } }); }, get children() { return props.children; } }); }; function useRegistry() { const registry = solidJs.useContext(ServiceRegistryContext); if (!registry) { throw new Error( "Your app needs to be wrapped with <ServiceRegistry> context in order to use services." ); } return registry; } function createSubRoot(fn, owner = solidJs.getOwner()) { return solidJs.createRoot((dispose) => { owner && solidJs.runWithOwner(owner, solidJs.onCleanup.bind(void 0, dispose)); return fn(dispose); }, owner); } function runInSubRoot(fn, owner) { let error; let hasError = false; const result = createSubRoot((dispose) => { try { return fn(dispose); } catch (e) { hasError = true; error = e; dispose(); throw e; } }, owner); if (hasError) { throw error; } return result; } class Service { } class Registry { #owner; #config; #cache; constructor(config = {}) { this.#config = config; this.#owner = solidJs.getOwner(); this.#cache = /* @__PURE__ */ new Map(); } /** * Checks weather the registry has a service registered for the given initializer. * * First it will check in the parent registry and if no service is registered there, * it will check in the current registry. */ has(initializer) { const parentRegistry = this.getParentRegistry(); if (parentRegistry?.isExposing(initializer)) { return parentRegistry.has(initializer); } return this.#cache.has(initializer); } /** * Returns the service registered for the given initializer. * * First it will try to find it in the parent registry and if no service is registered there, * it will check in the current registry. */ get(initializer) { const parentRegistry = this.getParentRegistry(); if (parentRegistry?.isExposing(initializer)) { return parentRegistry.get(initializer); } return this.#cache.get(initializer); } /** * Clears the registry. */ clear() { this.#cache.clear(); } /** * Deletes registered service for the given initializer. */ delete(initializer) { this.#cache.delete(initializer); } /** * Registers a service for the given initializer. * * If the registry has a parent registry, it will check if the service is exposed there. * * If it is exposed, it will register the service in the parent registry. * * If it is not exposed, it will register the service in the current registry. * * If the registry does not have a parent registry, it will register the service in the current registry. */ register(initializer) { const parentRegistry = this.getParentRegistry(); if (parentRegistry?.isExposing(initializer)) { return parentRegistry.register(initializer); } const registration = runInSubRoot( () => this.initializeService(initializer), this.#owner ); this.#cache.set(initializer, registration); return registration; } isExposing(initializer) { return this.#config.expose === true || Array.isArray(this.#config.expose) && this.#config.expose?.includes(initializer); } getParentRegistry() { return this.#owner?.owner ? runInSubRoot((dispose) => { const context = solidJs.useContext(ServiceRegistryContext); dispose(); return context; }, this.#owner.owner) : void 0; } initializeService(initializer) { return initializer.prototype?.constructor ? Reflect.construct(initializer, []) : initializer(); } } function createRegistry(config) { return new Registry(config); } function useService(initializer) { const registry = useRegistry(); return () => registry.get(initializer) || registry.register(initializer); } exports.Registry = Registry; exports.Service = Service; exports.ServiceRegistry = ServiceRegistry; exports.ServiceRegistryContext = ServiceRegistryContext; exports.createRegistry = createRegistry; exports.useRegistry = useRegistry; exports.useService = useService;