UNPKG

@eclipse-scout/core

Version:
153 lines (136 loc) 6.33 kB
/* * Copyright (c) 2010, 2025 BSI Business Systems Integration AG * * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 */ import {BaseDoEntity, Constructor, ObjectFactory, strings} from '../index'; /** * Holds all data object class mappings. * * Data object classes having an @typeName decorator do register themselves automatically into this registry. * The code to do that is automatically created and injected at compile time. * See DataObjectTransformer#_createDoInventoryAddStatement. * Therefore, the API of this class must match the code generated by this transformer. * If this class name, the method name 'get' (static accessor) or 'add' (to register a data object) are changed, the transformer must be adapted as well! */ export class DataObjectInventory { protected static _INSTANCE: DataObjectInventory = null; protected _constructorByTypeName = new Map<string, Constructor<BaseDoEntity>>(); protected _typeNameByObjectType = new Map<string, string>(); protected _objectTypeByTypeName = new Map<string, string>(); protected constructor() { } /** * Adds a new dataobject to the registry. * @param doClass The dataobject class to register. * @param typeName Optional typeName (`_type` attribute) of this dataobject. E.g. `myNamespace.MyEntity`. * If omitted, it will be detected from the given class by creating a new instance and reading the `_type` attribute. * So this attribute must be set either by a `@typeName()` decorator on the class or as part of its constructor. * @param objectType Optional object type of the dataobject. E.g. `myNamespace.MyEntityDo`. * If omitted, it will be read from the `ObjectFactory`. So the constructor must have been registered to the `ObjectFactory` already. * @returns true if the class could be completely registered. false otherwise (e.g. if the typeName or objectType is unknown). */ add(doClass: Constructor<BaseDoEntity>, typeName?: string, objectType?: string): boolean { if (!doClass) { return false; } typeName = typeName || this._readTypeName(doClass); if (!typeName) { return false; } if (this._constructorByTypeName.has(typeName)) { throw new Error(`There is already a constructor registered for type name '${typeName}'.`); } this._constructorByTypeName.set(typeName, doClass); objectType = objectType || ObjectFactory.get().getObjectType(doClass); if (!objectType) { return false; } objectType = strings.removePrefix(objectType, 'scout.'); // scout elements are in the map without namespace. this._typeNameByObjectType.set(objectType, typeName); this._objectTypeByTypeName.set(typeName, objectType); return true; } /** * Removes the dataobject given. * @param item The dataobject class or the typeName (_type) of the dataobject to remove. */ remove(item: Constructor<BaseDoEntity> | string) { if (typeof item === 'string') { this._removeByTypeName(item); } else { this._removeByClass(item); } } protected _removeByClass(doClass: Constructor<BaseDoEntity>) { if (!doClass) { return; } for (const [typeName, doConstructor] of this._constructorByTypeName) { if (doConstructor === doClass) { this._removeByTypeName(typeName); } } } protected _removeByTypeName(typeName: string) { if (!typeName) { return; } this._constructorByTypeName.delete(typeName); const objectType = this._objectTypeByTypeName.get(typeName); if (objectType) { this._typeNameByObjectType.delete(objectType); } this._objectTypeByTypeName.delete(typeName); } protected _readTypeName(DoClass: Constructor<BaseDoEntity>): string { return new DoClass()._type; } /** * @returns All dataobject classes known to the registry. */ getKnownDataObjectClasses(): IterableIterator<Constructor<BaseDoEntity>> { return this._constructorByTypeName.values(); } /** * @param typeNameOrObjectType The typeName (_type like 'scout.Topic') or objectType (like 'scout.TopicDo') for which the dataobject class should be returned. * @returns the dataobject class for given typeName (_type) or objectType. */ toConstructor(typeNameOrObjectType: string): Constructor<BaseDoEntity> { return this._constructorByTypeName.get(typeNameOrObjectType) || this._constructorByTypeName.get(this.toTypeName(typeNameOrObjectType)); } /** * @param objectType The objectType for which the typeName (_type) should be returned. E.g. 'scout.CodeDo' or 'myapp.MySpecialDo'. * @returns the dataobject typeName (_type) for given objectType. E.g. returns 'scout.Topic' for 'scout.TopicDo'. Or 'myApp.MySpecial' for 'myApp.MySpecialDo'. This is the inverse operation of {@link toObjectType}. */ toTypeName(objectType: string): string { objectType = strings.removePrefix(objectType, 'scout.'); // scout elements are in the map without namespace. return this._typeNameByObjectType.get(objectType); } /** * @param typeName The typeName (_type) for which the objectType should be returned. * @returns the dataobject objectType for given typeName (_type). E.g. returns 'TopicDo' for 'scout.Topic'. Or 'myApp.MySpecialDo' for 'myApp.MySpecial'. This is the inverse operation of {@link toTypeName}. */ toObjectType(typeName: string): string { return this._objectTypeByTypeName.get(typeName); } /** * @returns the DataObjectInventory instance. */ static get(): DataObjectInventory { if (!DataObjectInventory._INSTANCE) { // Do not create using scout.create as this registry instance is already used very early during source code parsing. // At this time no object factory is available yet. DataObjectInventory._INSTANCE = new DataObjectInventory(); } return DataObjectInventory._INSTANCE; } } // proactively register this class on the window object to ensure it can be used by dataobjects to register themselves. // See DataObjectTransformer#_createDoInventoryAddStatement. window['scout'] = window['scout'] || {}; window['scout'].DataObjectInventory = DataObjectInventory;