Warning, /firebird/packages/firebird-ng/src/lib/provide-firebird.ts is written in an unsupported language. File is not indexed.
0001 /**
0002 * `provideFirebird()`: assembles the event display from Firebird's built-ins
0003 * and the application's features.
0004 */
0005
0006 import { EnvironmentProviders, inject, provideAppInitializer } from '@angular/core';
0007 import {
0008 APP_FEATURE_OWNERS,
0009 AppFeatureInput,
0010 provideAppFeatures,
0011 resolveRegistry,
0012 } from '@dexvis/app-features';
0013 // The /model subpath (initial-bundle file): the core root re-exports the
0014 // painters, which pull three.js; the model imports none.
0015 import { registerEventPieceFactory } from '@dexvis/firebird-core/model';
0016 import type { EventPieceFactory } from '@dexvis/firebird-core';
0017 import { EVENT_PIECE_FACTORIES } from '@dexvis/firebird-ng/api';
0018 import { withFirebirdBuiltins } from './with-firebird-builtins';
0019
0020 /**
0021 * Development-build warning: two packs ship different factory classes for
0022 * one piece type. Only the last one takes effect, which is rarely what both
0023 * packs intend. Replacing a built-in factory is no collision: the built-ins
0024 * are a pack of defaults, and `owners` has no entry for them.
0025 */
0026 function warnPieceTypeCollisions(factories: readonly EventPieceFactory[], owners: ReadonlyMap<unknown, readonly string[]>): void {
0027 const classesByType = new Map<string, Set<Function>>();
0028 for (const factory of factories) {
0029 const classes = classesByType.get(factory.type) ?? new Set<Function>();
0030 classes.add(factory.constructor);
0031 classesByType.set(factory.type, classes);
0032 }
0033 for (const [type, classes] of classesByType) {
0034 if (classes.size < 2) continue;
0035 const packs = new Set([...classes].flatMap(factoryClass => owners.get(factoryClass) ?? []));
0036 if (packs.size < 2) continue;
0037 const sources = [...classes]
0038 .filter(factoryClass => owners.has(factoryClass))
0039 .map(factoryClass => `${factoryClass.name} (${owners.get(factoryClass)!.join(', ')})`);
0040 // A piece factory feature has no id: dropping one of them means dropping its pack
0041 console.warn(`[Firebird] Piece type '${type}' has factories from several packs: ${sources.join(', ')}. ` +
0042 `The last one decodes it. To keep another one, change the order of the packs or drop a pack with withoutFeatures('<pack id>').`);
0043 }
0044 }
0045
0046 /**
0047 * Assembles the Firebird event display: Firebird's built-ins
0048 * (`withFirebirdBuiltins()`), then the application's features.
0049 *
0050 * ```ts
0051 * export const appConfig: ApplicationConfig = {
0052 * providers: [
0053 * provideZonelessChangeDetection(),
0054 * provideRouter(routes),
0055 * provideHttpClient(withFetch()),
0056 * provideFirebird(
0057 * withMyExperiment(),
0058 * withoutFeatures('firebird.navigation-cube'),
0059 * ),
0060 * ],
0061 * };
0062 * ```
0063 *
0064 * The built-ins are installed first, so registration order puts them ahead
0065 * of the application's features. To drop a part of them, pass
0066 * `withoutFeatures()` with the part's feature id (see
0067 * with-firebird-builtins.ts); to replace one, register under its id.
0068 *
0069 * Startup order inside the app initializers (after the initializers that
0070 * features contribute):
0071 * 1. Register DI-contributed event piece factories into the core registry
0072 * (workers call core's `initPieceFactories()` explicitly instead; core stays DI-free).
0073 * 2. Apply feature-contributed config defaults.
0074 * 3. Load the server config (server tier of the config precedence).
0075 * 4. Parse URL query parameters: `config.*` session overrides and startup
0076 * commands (`dex`, `geometry`, `event`, `cmd`). Commands are queued and run
0077 * by the display page once the scene is ready.
0078 *
0079 * Steps 2-4 are `provideAppFeatures()` from `@dexvis/app-features`.
0080 */
0081 export function provideFirebird(...features: AppFeatureInput[]): EnvironmentProviders {
0082 return provideAppFeatures(
0083 withFirebirdBuiltins(),
0084 ...features,
0085 {
0086 kind: 'initializer',
0087 providers: [provideAppInitializer(() => {
0088 const factories = inject(EVENT_PIECE_FACTORIES, { optional: true }) ?? [];
0089 if (typeof ngDevMode !== 'undefined' && ngDevMode) {
0090 warnPieceTypeCollisions(factories, inject(APP_FEATURE_OWNERS, { optional: true }) ?? new Map());
0091 }
0092 for (const factory of resolveRegistry(factories, factory => factory.type)) {
0093 registerEventPieceFactory(factory);
0094 }
0095 })],
0096 },
0097 );
0098 }