@equinor/fusion-framework-module-context 8.0.3 → 9.0.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/README.md +78 -2
  3. package/dist/esm/ContextModuleConfig.js +2 -0
  4. package/dist/esm/ContextModuleConfig.js.map +1 -0
  5. package/dist/esm/ContextModuleConfigurator.interface.js +2 -0
  6. package/dist/esm/ContextModuleConfigurator.interface.js.map +1 -0
  7. package/dist/esm/ContextModuleConfigurator.js +211 -0
  8. package/dist/esm/ContextModuleConfigurator.js.map +1 -0
  9. package/dist/esm/ContextProvider.js +1 -1
  10. package/dist/esm/ContextProvider.js.map +1 -1
  11. package/dist/esm/__tests__/ContextModuleConfigurator.test.js +282 -0
  12. package/dist/esm/__tests__/ContextModuleConfigurator.test.js.map +1 -0
  13. package/dist/esm/__tests__/mock/context-mock.test.js +101 -0
  14. package/dist/esm/__tests__/mock/context-mock.test.js.map +1 -0
  15. package/dist/esm/__tests__/mock/create-context-item-factory.test.js +45 -0
  16. package/dist/esm/__tests__/mock/create-context-item-factory.test.js.map +1 -0
  17. package/dist/esm/__tests__/mock/create-context-items.test.js +46 -0
  18. package/dist/esm/__tests__/mock/create-context-items.test.js.map +1 -0
  19. package/dist/esm/index.js +1 -1
  20. package/dist/esm/index.js.map +1 -1
  21. package/dist/esm/mock/ContextMockConfigurator.js +206 -0
  22. package/dist/esm/mock/ContextMockConfigurator.js.map +1 -0
  23. package/dist/esm/mock/fixtures/create-context-item-factory.js +50 -0
  24. package/dist/esm/mock/fixtures/create-context-item-factory.js.map +1 -0
  25. package/dist/esm/mock/fixtures/create-context-items.js +53 -0
  26. package/dist/esm/mock/fixtures/create-context-items.js.map +1 -0
  27. package/dist/esm/mock/fixtures/index.js +22 -0
  28. package/dist/esm/mock/fixtures/index.js.map +1 -0
  29. package/dist/esm/mock/fixtures/string-to-seed.js +15 -0
  30. package/dist/esm/mock/fixtures/string-to-seed.js.map +1 -0
  31. package/dist/esm/mock/index.js +31 -0
  32. package/dist/esm/mock/index.js.map +1 -0
  33. package/dist/esm/mock/module.js +41 -0
  34. package/dist/esm/mock/module.js.map +1 -0
  35. package/dist/esm/module.js +35 -6
  36. package/dist/esm/module.js.map +1 -1
  37. package/dist/esm/{get-context-selector.js → selectors/get-context-selector.js} +1 -4
  38. package/dist/esm/selectors/get-context-selector.js.map +1 -0
  39. package/dist/esm/selectors/index.js +13 -0
  40. package/dist/esm/selectors/index.js.map +1 -0
  41. package/dist/esm/{query-context-selector.js → selectors/query-context-selector.js} +1 -1
  42. package/dist/esm/selectors/query-context-selector.js.map +1 -0
  43. package/dist/esm/{related-context-selector.js → selectors/related-context-selector.js} +1 -1
  44. package/dist/esm/selectors/related-context-selector.js.map +1 -0
  45. package/dist/esm/utils/enable-context.js +1 -1
  46. package/dist/esm/utils/enable-context.js.map +1 -1
  47. package/dist/esm/utils/index.js +2 -0
  48. package/dist/esm/utils/index.js.map +1 -1
  49. package/dist/esm/utils/parse-context-item.js.map +1 -0
  50. package/dist/esm/utils/resolve-initial-context.js +3 -1
  51. package/dist/esm/utils/resolve-initial-context.js.map +1 -1
  52. package/dist/esm/version.js +1 -1
  53. package/dist/esm/version.js.map +1 -1
  54. package/dist/tsconfig.tsbuildinfo +1 -1
  55. package/dist/types/{configurator.d.ts → ContextModuleConfig.d.ts} +4 -64
  56. package/dist/types/ContextModuleConfigurator.d.ts +97 -0
  57. package/dist/types/{ContextConfigBuilder.d.ts → ContextModuleConfigurator.interface.d.ts} +27 -47
  58. package/dist/types/ContextProvider.d.ts +1 -1
  59. package/dist/types/__tests__/ContextModuleConfigurator.test.d.ts +1 -0
  60. package/dist/types/__tests__/mock/context-mock.test.d.ts +1 -0
  61. package/dist/types/__tests__/mock/create-context-item-factory.test.d.ts +1 -0
  62. package/dist/types/__tests__/mock/create-context-items.test.d.ts +1 -0
  63. package/dist/types/index.d.ts +3 -1
  64. package/dist/types/mock/ContextMockConfigurator.d.ts +155 -0
  65. package/dist/types/mock/fixtures/create-context-item-factory.d.ts +40 -0
  66. package/dist/types/mock/fixtures/create-context-items.d.ts +59 -0
  67. package/dist/types/mock/fixtures/index.d.ts +21 -0
  68. package/dist/types/mock/fixtures/string-to-seed.d.ts +12 -0
  69. package/dist/types/mock/index.d.ts +30 -0
  70. package/dist/types/mock/module.d.ts +38 -0
  71. package/dist/types/module.d.ts +5 -3
  72. package/dist/types/{get-context-selector.d.ts → selectors/get-context-selector.d.ts} +1 -3
  73. package/dist/types/selectors/index.d.ts +12 -0
  74. package/dist/types/{query-context-selector.d.ts → selectors/query-context-selector.d.ts} +1 -1
  75. package/dist/types/{related-context-selector.d.ts → selectors/related-context-selector.d.ts} +1 -1
  76. package/dist/types/utils/enable-context.d.ts +4 -5
  77. package/dist/types/utils/index.d.ts +2 -0
  78. package/dist/types/{parse-context-item.d.ts → utils/parse-context-item.d.ts} +1 -1
  79. package/dist/types/utils/resolve-initial-context.d.ts +1 -1
  80. package/dist/types/version.d.ts +1 -1
  81. package/docs/data-model.md +134 -0
  82. package/docs/lifecycle.md +163 -0
  83. package/docs/recipes.md +89 -0
  84. package/package.json +36 -8
  85. package/src/ContextModuleConfig.ts +147 -0
  86. package/src/ContextModuleConfigurator.interface.ts +145 -0
  87. package/src/ContextModuleConfigurator.ts +295 -0
  88. package/src/ContextProvider.ts +1 -2
  89. package/src/__tests__/ContextModuleConfigurator.test.ts +412 -0
  90. package/src/__tests__/mock/context-mock.test.ts +137 -0
  91. package/src/__tests__/mock/create-context-item-factory.test.ts +60 -0
  92. package/src/__tests__/mock/create-context-items.test.ts +58 -0
  93. package/src/index.ts +3 -5
  94. package/src/mock/ContextMockConfigurator.ts +244 -0
  95. package/src/mock/fixtures/create-context-item-factory.ts +62 -0
  96. package/src/mock/fixtures/create-context-items.ts +80 -0
  97. package/src/mock/fixtures/index.ts +28 -0
  98. package/src/mock/fixtures/string-to-seed.ts +18 -0
  99. package/src/mock/index.ts +33 -0
  100. package/src/mock/module.ts +54 -0
  101. package/src/module.ts +45 -17
  102. package/src/{get-context-selector.ts → selectors/get-context-selector.ts} +2 -6
  103. package/src/selectors/index.ts +12 -0
  104. package/src/{query-context-selector.ts → selectors/query-context-selector.ts} +2 -2
  105. package/src/{related-context-selector.ts → selectors/related-context-selector.ts} +2 -2
  106. package/src/utils/enable-context.ts +6 -10
  107. package/src/utils/index.ts +2 -0
  108. package/src/{parse-context-item.ts → utils/parse-context-item.ts} +1 -1
  109. package/src/utils/resolve-initial-context.ts +5 -2
  110. package/src/version.ts +1 -1
  111. package/tsconfig.json +6 -0
  112. package/vitest.config.ts +11 -0
  113. package/dist/esm/ContextConfigBuilder.js +0 -175
  114. package/dist/esm/ContextConfigBuilder.js.map +0 -1
  115. package/dist/esm/configurator.js +0 -104
  116. package/dist/esm/configurator.js.map +0 -1
  117. package/dist/esm/get-context-selector.js.map +0 -1
  118. package/dist/esm/parse-context-item.js.map +0 -1
  119. package/dist/esm/query-context-selector.js.map +0 -1
  120. package/dist/esm/related-context-selector.js.map +0 -1
  121. package/src/ContextConfigBuilder.ts +0 -258
  122. package/src/configurator.ts +0 -300
  123. /package/dist/esm/{parse-context-item.js → utils/parse-context-item.js} +0 -0
@@ -1,21 +1,18 @@
1
+ import type { AnyModuleInstance, ModuleInstance } from '@equinor/fusion-framework-module';
1
2
  import type { ObservableInput } from 'rxjs';
2
- import type { AnyModuleInstance, ModuleInitializerArgs, ModuleInstance } from '@equinor/fusion-framework-module';
3
- import type { ServicesModule, IApiProvider } from '@equinor/fusion-framework-module-services';
4
- import type { NavigationModule } from '@equinor/fusion-framework-module-navigation';
5
3
  import type { QueryCtorOptions } from '@equinor/fusion-query';
6
4
  import type { ContextFilterFn, ContextItem, QueryContextParameters, RelatedContextParameters } from './types';
7
5
  import type { GetContextParameters } from './client/ContextClient';
8
- import { type ContextConfigBuilderCallback } from './ContextConfigBuilder';
9
6
  import type { IContextProvider } from './ContextProvider';
10
7
  /**
11
8
  * Resolved configuration for the context module.
12
9
  *
13
10
  * Holds query clients, type filters, parent-connection settings, and
14
11
  * optional callbacks for validation, resolution, and path integration.
15
- * Produced by {@link ContextModuleConfigurator.createConfig} after all
16
- * {@link ContextConfigBuilder} callbacks have run.
12
+ * Produced by {@link ContextModuleConfigurator.createConfigAsync} after all
13
+ * registered config builders have run.
17
14
  *
18
- * @see ContextConfigBuilder — fluent API for populating this config.
15
+ * @see IContextModuleConfigurator — fluent API for populating this config.
19
16
  * @see ContextProvider — runtime consumer of this config.
20
17
  */
21
18
  export interface ContextModuleConfig {
@@ -123,60 +120,3 @@ export interface ContextModuleConfig {
123
120
  modules: ModuleInstance;
124
121
  }) => ObservableInput<ContextItem | void>;
125
122
  }
126
- /**
127
- * Public configurator contract for the context module.
128
- *
129
- * Consumers call {@link addConfigBuilder} to register one or more
130
- * {@link ContextConfigBuilderCallback} functions that will run during
131
- * module initialization to populate the {@link ContextModuleConfig}.
132
- */
133
- export interface IContextModuleConfigurator {
134
- /**
135
- * Registers a configuration callback that receives a {@link ContextConfigBuilder}.
136
- *
137
- * Multiple builders can be added; they execute sequentially and merge
138
- * their results into a single {@link ContextModuleConfig}.
139
- *
140
- * @param init - Builder callback invoked during module initialization.
141
- */
142
- addConfigBuilder: (init: ContextConfigBuilderCallback) => void;
143
- }
144
- /**
145
- * Default implementation of {@link IContextModuleConfigurator}.
146
- *
147
- * Collects {@link ContextConfigBuilderCallback} registrations and, when
148
- * {@link createConfig} is called, runs them in order against a
149
- * {@link ContextConfigBuilder} to produce the final {@link ContextModuleConfig}.
150
- *
151
- * If no custom client is configured, the configurator falls back to
152
- * creating one from the {@link ServicesModule} API provider.
153
- */
154
- export declare class ContextModuleConfigurator implements IContextModuleConfigurator {
155
- #private;
156
- /** Default cache TTL (in ms) for context query results. */
157
- defaultExpireTime: number;
158
- /** @inheritdoc */
159
- addConfigBuilder(init: ContextConfigBuilderCallback): void;
160
- /**
161
- * Resolves the services API provider, preferring the local module
162
- * instance and falling back to the parent module.
163
- *
164
- * @param init - Module initializer arguments.
165
- * @returns The resolved API provider.
166
- * @throws Error if no services module is available.
167
- */
168
- protected _getServiceProvider(init: ModuleInitializerArgs<IContextModuleConfigurator, [ServicesModule]>): Promise<IApiProvider>;
169
- /**
170
- * Runs all registered config builders and produces the final
171
- * {@link ContextModuleConfig}.
172
- *
173
- * If no `resolveInitialContext` was set, the default path + parent
174
- * resolver is used. If no `client` was set, one is created from the
175
- * {@link ServicesModule} API provider.
176
- *
177
- * @param init - Module initializer arguments including dependency instances.
178
- * @returns The fully resolved context module configuration.
179
- */
180
- createConfig(init: ModuleInitializerArgs<IContextModuleConfigurator, [ServicesModule, NavigationModule]>): Promise<ContextModuleConfig>;
181
- }
182
- export default ContextModuleConfigurator;
@@ -0,0 +1,97 @@
1
+ import { BaseConfigBuilder, type ModuleInitializerArgs, type Modules, type ModuleType } from '@equinor/fusion-framework-module';
2
+ import type { ServicesModule, IApiProvider } from '@equinor/fusion-framework-module-services';
3
+ import type { NavigationModule } from '@equinor/fusion-framework-module-navigation';
4
+ import type { QueryCtorOptions, QueryFn } from '@equinor/fusion-query';
5
+ import type { ContextItem, QueryContextParameters, RelatedContextParameters } from './types';
6
+ import type { GetContextParameters } from './client/ContextClient';
7
+ import type { ContextModuleConfig } from './ContextModuleConfig';
8
+ import type { ContextConfigBuilderCallback, IContextModuleConfigurator } from './ContextModuleConfigurator.interface';
9
+ export type { ContextModuleConfig } from './ContextModuleConfig';
10
+ export type { ContextConfigBuilderCallback, IContextModuleConfigurator, } from './ContextModuleConfigurator.interface';
11
+ /**
12
+ * Default implementation of {@link IContextModuleConfigurator}.
13
+ *
14
+ * Collects {@link ContextConfigBuilderCallback} registrations and, when
15
+ * {@link createConfigAsync} is called, runs them in order — each callback
16
+ * receives this configurator itself and populates the config through its
17
+ * setter methods, which register into {@link BaseConfigBuilder._set} — to
18
+ * produce the final {@link ContextModuleConfig}.
19
+ *
20
+ * If no custom client is configured, the configurator falls back to
21
+ * creating one from the {@link ServicesModule} API provider.
22
+ *
23
+ * @remarks
24
+ * Extends {@link BaseConfigBuilder} and fully reuses its `_set`/`_buildConfig`
25
+ * machinery. Setters always pass an `async () => value` callback to `_set`,
26
+ * never the raw value directly — `_set` decides whether it received a value
27
+ * or a deferred callback by checking `typeof value_or_cb === 'function'`, so
28
+ * fields that are themselves functions (e.g. `validateContext`) would
29
+ * otherwise be misread as callbacks and invoked instead of stored.
30
+ */
31
+ export declare class ContextModuleConfigurator extends BaseConfigBuilder<ContextModuleConfig> implements IContextModuleConfigurator {
32
+ #private;
33
+ /** Default cache TTL (in ms) for context query results. */
34
+ defaultExpireTime: number;
35
+ /** @inheritdoc */
36
+ addConfigBuilder(init: ContextConfigBuilderCallback): void;
37
+ /** @inheritdoc */
38
+ requireInstance<TKey extends string = Extract<keyof Modules, string>>(module: TKey): Promise<ModuleType<Modules[TKey]>>;
39
+ /** @inheritdoc */
40
+ requireInstance<T>(module: string): Promise<T>;
41
+ /** @inheritdoc */
42
+ setContextType(type: ContextModuleConfig['contextType']): void;
43
+ /** @inheritdoc */
44
+ setContextFilter(filter: ContextModuleConfig['contextFilter']): void;
45
+ /** @inheritdoc */
46
+ connectParentContext(connect: ContextModuleConfig['connectParentContext']): void;
47
+ /** @inheritdoc */
48
+ setContextParameterFn(fn: ContextModuleConfig['contextParameterFn']): void;
49
+ /** @inheritdoc */
50
+ setValidateContext(fn: ContextModuleConfig['validateContext']): void;
51
+ /** @inheritdoc */
52
+ setResolveContext(fn: ContextModuleConfig['resolveContext']): void;
53
+ /** @inheritdoc */
54
+ setContextPathExtractor(fn: ContextModuleConfig['extractContextIdFromPath']): void;
55
+ /** @inheritdoc */
56
+ setContextPathGenerator(fn: ContextModuleConfig['generatePathFromContext']): void;
57
+ /** @inheritdoc */
58
+ setResolveInitialContext(fn: ContextModuleConfig['resolveInitialContext']): void;
59
+ /** @inheritdoc */
60
+ setContextClient(client: {
61
+ get: QueryFn<ContextItem, GetContextParameters> | QueryCtorOptions<ContextItem, GetContextParameters>;
62
+ query: QueryFn<ContextItem[], QueryContextParameters> | QueryCtorOptions<ContextItem[], QueryContextParameters>;
63
+ related?: QueryFn<ContextItem[], RelatedContextParameters> | QueryCtorOptions<ContextItem[], RelatedContextParameters>;
64
+ }, expire?: number): void;
65
+ /**
66
+ * Resolves the services API provider, preferring the local module
67
+ * instance and falling back to the parent module.
68
+ *
69
+ * @param init - Module initializer arguments.
70
+ * @returns The resolved API provider.
71
+ * @throws Error if no services module is available.
72
+ */
73
+ protected _getServiceProvider(init: ModuleInitializerArgs<IContextModuleConfigurator, [ServicesModule]>): Promise<IApiProvider>;
74
+ /**
75
+ * Runs all registered config builders, then resolves the accumulated
76
+ * `_set` registrations into the final {@link ContextModuleConfig}.
77
+ *
78
+ * @param init - Module initializer arguments including dependency instances.
79
+ * @param initial - Optional partial config inherited from a parent module.
80
+ * @returns The fully resolved context module configuration.
81
+ */
82
+ protected _createConfig(init: ModuleInitializerArgs<IContextModuleConfigurator, [ServicesModule, NavigationModule]>, initial?: Partial<ContextModuleConfig>): Promise<ContextModuleConfig>;
83
+ /**
84
+ * Defaults `resolveInitialContext` and `client` when a builder callback
85
+ * didn't set them.
86
+ *
87
+ * If no `resolveInitialContext` was set, the default path + parent
88
+ * resolver is used. If no `client` was set, one is created from the
89
+ * {@link ServicesModule} API provider.
90
+ *
91
+ * @param config - The config accumulated from registered builder callbacks.
92
+ * @param init - Module initializer arguments including dependency instances.
93
+ * @returns The fully resolved context module configuration.
94
+ */
95
+ protected _processConfig(config: Partial<ContextModuleConfig>, init: ModuleInitializerArgs<IContextModuleConfigurator, [ServicesModule, NavigationModule]>): Promise<ContextModuleConfig>;
96
+ }
97
+ export default ContextModuleConfigurator;
@@ -1,65 +1,45 @@
1
- import type { AnyModule, ModuleInitializerArgs, Modules, ModuleType } from '@equinor/fusion-framework-module';
1
+ import type { Modules, ModuleType } from '@equinor/fusion-framework-module';
2
2
  import type { QueryCtorOptions, QueryFn } from '@equinor/fusion-query';
3
- import type { GetContextParameters } from './client/ContextClient';
4
- import type { ContextModuleConfig, ContextModuleConfigurator, IContextModuleConfigurator } from './configurator';
3
+ import type { ContextModuleConfig } from './ContextModuleConfig';
5
4
  import type { ContextItem, QueryContextParameters, RelatedContextParameters } from './types';
5
+ import type { GetContextParameters } from './client/ContextClient';
6
6
  /**
7
7
  * Callback passed to {@link IContextModuleConfigurator.addConfigBuilder}.
8
8
  *
9
- * Receives a {@link ContextConfigBuilder} and may use its setter methods
10
- * to populate the context module configuration. The callback may be async.
11
- *
12
- * @typeParam TDeps - Module dependency array inferred from the configurator.
9
+ * Receives the {@link IContextModuleConfigurator} itself and may use its
10
+ * setter methods to populate the context module configuration. The
11
+ * callback may be async.
13
12
  */
14
- export type ContextConfigBuilderCallback = <TDeps extends Array<AnyModule> = []>(builder: ContextConfigBuilder<TDeps, ModuleInitializerArgs<IContextModuleConfigurator, TDeps>>) => void | Promise<void>;
13
+ export type ContextConfigBuilderCallback = (builder: IContextModuleConfigurator) => void | Promise<void>;
15
14
  /**
16
- * A builder class for configuring and customizing context module behavior within the Fusion Framework.
17
- *
18
- * `ContextConfigBuilder` provides a fluent API for setting up various aspects of context management,
19
- * including context type, filtering, parent context connection, parameter resolution, validation,
20
- * path extraction/generation, and client configuration for fetching context items.
21
- *
22
- * @typeParam TModules - An array of modules that extend `AnyModule`. Defaults to an empty array.
23
- * @typeParam TInit - The initializer arguments for the module, extending `ModuleInitializerArgs`.
24
- *
25
- * @example
26
- * ```typescript
27
- * const builder = new ContextConfigBuilder(init);
28
- * builder.setContextType(['ProjectMaster']);
29
- * builder.setContextFilter(items => items.filter(ctx => ctx.isActive));
30
- * builder.setContextClient({ get: fetchContextItem, query: fetchContextItems });
31
- * ```
32
- *
33
- * @remarks
34
- * - Use the provided setter methods to customize context behavior as needed.
35
- * - The builder pattern allows chaining configuration methods for clarity and convenience.
36
- * - The `requireInstance` method enables asynchronous retrieval of module instances by name.
37
- *
38
- * @todo(#5120) - this should extend the BaseConfigBuilder
15
+ * Public configurator contract for the context module.
39
16
  *
40
- * @see ContextModuleConfig
41
- * @see ModuleInitializerArgs
17
+ * Consumers call {@link addConfigBuilder} to register one or more
18
+ * {@link ContextConfigBuilderCallback} functions that will run during
19
+ * module initialization to populate the {@link ContextModuleConfig}, using
20
+ * the fluent setter methods declared below.
42
21
  */
43
- export declare class ContextConfigBuilder<TModules extends Array<AnyModule> = [], TInit extends ModuleInitializerArgs<any, any> = ModuleInitializerArgs<ContextModuleConfigurator, TModules>> {
44
- #private;
45
- config: Partial<ContextModuleConfig>;
22
+ export interface IContextModuleConfigurator {
46
23
  /**
47
- * Creates a new `ContextConfigBuilder`.
48
- * @param init - Module initializer arguments used to resolve module instances.
49
- * @param config - The partial context module config to build upon.
24
+ * Registers a configuration callback that receives this configurator.
25
+ *
26
+ * Multiple builders can be added; they execute sequentially against the
27
+ * same configurator instance, so later calls win when they touch the
28
+ * same field.
29
+ *
30
+ * @param init - Builder callback invoked during module initialization.
50
31
  */
51
- constructor(init: TInit, config?: Partial<ContextModuleConfig>);
32
+ addConfigBuilder: (init: ContextConfigBuilderCallback) => void;
52
33
  /**
53
- * Requires a module instance by its registered key.
54
- * @param module - The key of the module to resolve.
34
+ * Requires a module instance by its registered key or name.
35
+ *
36
+ * Only resolvable from within a {@link ContextConfigBuilderCallback} —
37
+ * throws if called before module initialization has started.
38
+ *
39
+ * @param module - The key or name of the module to resolve.
55
40
  * @returns A promise that resolves to the requested module instance.
56
41
  */
57
42
  requireInstance<TKey extends string = Extract<keyof Modules, string>>(module: TKey): Promise<ModuleType<Modules[TKey]>>;
58
- /**
59
- * Requires a module instance by name.
60
- * @param module - The name of the module to resolve.
61
- * @returns A promise that resolves to the requested module instance.
62
- */
63
43
  requireInstance<T>(module: string): Promise<T>;
64
44
  /**
65
45
  * Sets the context type for the current configuration.
@@ -1,5 +1,5 @@
1
1
  import { Observable, Subscription } from 'rxjs';
2
- import type { ContextModuleConfig } from './configurator';
2
+ import type { ContextModuleConfig } from './ContextModuleConfig';
3
3
  import { BaseModuleProvider } from '@equinor/fusion-framework-module/provider';
4
4
  import { ContextClient } from './client/ContextClient';
5
5
  import type { ContextItem, QueryContextParameters, RelatedContextParameters } from './types';
@@ -0,0 +1 @@
1
+ export {};
@@ -10,7 +10,9 @@
10
10
  *
11
11
  * @packageDocumentation
12
12
  */
13
- export { ContextModuleConfigurator, IContextModuleConfigurator, ContextModuleConfig, } from './configurator';
13
+ export { ContextModuleConfigurator } from './ContextModuleConfigurator';
14
+ export type { IContextModuleConfigurator } from './ContextModuleConfigurator.interface';
15
+ export type { ContextModuleConfig } from './ContextModuleConfig';
14
16
  export { IContextProvider, ContextProvider } from './ContextProvider';
15
17
  export { default, ContextModule, module as contextModule, moduleKey as contextModuleKey, } from './module';
16
18
  export { enableContext } from './utils/enable-context';
@@ -0,0 +1,155 @@
1
+ import type { ModuleInitializerArgs } from '@equinor/fusion-framework-module';
2
+ import type { NavigationModule } from '@equinor/fusion-framework-module-navigation';
3
+ import type { ServicesModule } from '@equinor/fusion-framework-module-services';
4
+ import { ContextModuleConfigurator } from '../ContextModuleConfigurator';
5
+ import type { ContextModuleConfig } from '../ContextModuleConfig';
6
+ import type { IContextModuleConfigurator } from '../ContextModuleConfigurator.interface';
7
+ import type { ContextItem } from '../types';
8
+ /**
9
+ * Resolves a context item by id, or `undefined` if none matches.
10
+ *
11
+ * @remarks
12
+ * The escape hatch for {@link ContextMockConfigurator.setResolver} — anything
13
+ * the friendly seeding methods did not anticipate can be expressed here instead.
14
+ */
15
+ export type ContextResolverFn = (id: string) => ContextItem | undefined;
16
+ /**
17
+ * A {@link ContextModuleConfigurator} backed by in-memory context items instead
18
+ * of a real context API, for seeding context in tests.
19
+ *
20
+ * @remarks
21
+ * Two layers cover different needs, both running through the real
22
+ * `ContextProvider` logic underneath — only the data source is substituted,
23
+ * never `validateContext`, `resolveContext`, or parent-context propagation:
24
+ *
25
+ * - **Friendly layer** — {@link setCurrentContext}, {@link setContexts},
26
+ * {@link addContext}, {@link setRelatedContexts} — a small, context-domain
27
+ * vocabulary for the common case: seed a known item, get it back.
28
+ * - **Escape hatch** — {@link setResolver} — a raw id-lookup function for a
29
+ * custom id-based resolution strategy or a shape the friendly layer did not
30
+ * cover. Only replaces id-based lookup (used by `setCurrentContextById` and
31
+ * the initial context); it does not affect related-context resolution by
32
+ * item, which always goes through {@link setRelatedContexts} instead.
33
+ *
34
+ * Seeding the initial context (via {@link setCurrentContext}) overrides
35
+ * `resolveInitialContext` directly with the seeded item, so a test never needs
36
+ * to construct a fake navigation module or parent framework instance to make an
37
+ * app start up with a known context selected. Resolving a context id from a URL
38
+ * path on startup is not covered — that needs a fake router, which is separate,
39
+ * not-yet-built work.
40
+ *
41
+ * Seeded ids are never generated for you — every item is looked up and
42
+ * returned exactly by the id it was seeded with, so a test never sees a
43
+ * different id than the one it wrote. Use `createContextItemFactory` or
44
+ * `createContextItems` for fixtures needing ids of their own, rather than a
45
+ * random generator that would change on every run.
46
+ *
47
+ * Related-context resolution defaults to the same seeded pool, filtered to
48
+ * whichever type(s) the query asked for — related context is the same
49
+ * context, just a different type, exactly as `ContextProvider.resolveContext`
50
+ * uses it to resolve an item of an unexpected type into one of the configured
51
+ * type. Seed items of both types and resolution works with no extra wiring;
52
+ * {@link setRelatedContexts} overrides that default for one specific item.
53
+ *
54
+ * @example Seed and select a known context item
55
+ * ```ts
56
+ * enableContextMock(configurator, (mock) => {
57
+ * mock.setCurrentContext({ id: 'my-ctx', type: { id: 'ProjectMaster' }, value: {} });
58
+ * });
59
+ * ```
60
+ *
61
+ * @example Resolve a child-typed item into its parent type
62
+ * ```ts
63
+ * enableContextMock(configurator, (mock) => {
64
+ * // no explicit wiring needed — relatedContexts filters this same pool by type
65
+ * mock.setContexts([project, facility]);
66
+ * });
67
+ * ```
68
+ *
69
+ * @example Override related contexts for one specific item
70
+ * ```ts
71
+ * enableContextMock(configurator, (mock) => {
72
+ * mock.addContext(project);
73
+ * mock.setRelatedContexts(project.id, [facilityA, facilityB]);
74
+ * });
75
+ * ```
76
+ *
77
+ * @example Escape hatch for a custom resolution need
78
+ * ```ts
79
+ * enableContextMock(configurator, (mock) => {
80
+ * mock.setResolver((id) => (id === 'special' ? specialContextItem : undefined));
81
+ * });
82
+ * ```
83
+ */
84
+ export declare class ContextMockConfigurator extends ContextModuleConfigurator {
85
+ #private;
86
+ /**
87
+ * Registers the in-memory client up front, so `createConfig` never falls
88
+ * back to building one from a real `ServicesModule` — a mock needs neither
89
+ * an API provider nor a network to answer `get`/`query`/`related`.
90
+ */
91
+ constructor();
92
+ /**
93
+ * Seeds a context item and selects it as the context the app resolves on startup.
94
+ *
95
+ * @param item - The context item to seed and select.
96
+ * @returns This configurator, for chaining.
97
+ */
98
+ setCurrentContext(item: ContextItem): this;
99
+ /**
100
+ * Seeds multiple context items, making each resolvable by id.
101
+ *
102
+ * @remarks
103
+ * Does not select any of them as current — pair with {@link setCurrentContext}
104
+ * for that.
105
+ *
106
+ * @param items - The context items to seed.
107
+ * @returns This configurator, for chaining.
108
+ */
109
+ setContexts(items: ContextItem[]): this;
110
+ /**
111
+ * Seeds a single context item, making it resolvable by id.
112
+ *
113
+ * @param item - The context item to seed.
114
+ * @returns This configurator, for chaining.
115
+ */
116
+ addContext(item: ContextItem): this;
117
+ /**
118
+ * Overrides related-context resolution for one specific source item.
119
+ *
120
+ * @remarks
121
+ * Without this, `relatedContexts` filters the seeded pool by the requested
122
+ * type(s) — this is only needed when a test wants a specific item to resolve
123
+ * something other than that default (e.g. no related items at all).
124
+ *
125
+ * @param itemId - The id of the item relations are being overridden for.
126
+ * @param items - The context items to return from `relatedContexts` for that item.
127
+ * @returns This configurator, for chaining.
128
+ */
129
+ setRelatedContexts(itemId: string, items: ContextItem[]): this;
130
+ /**
131
+ * Escape hatch: overrides id-based context resolution directly.
132
+ *
133
+ * @remarks
134
+ * For a custom id-lookup strategy or a shape the friendly seeding methods
135
+ * above did not cover — reaching for this means they were already tried
136
+ * and did not fit. Only replaces lookup by id (used by
137
+ * `setCurrentContextById` and the seeded initial context) — related-context
138
+ * resolution by item always goes through {@link setRelatedContexts} instead,
139
+ * regardless of this setting.
140
+ *
141
+ * @param fn - Resolves a context item by id, or returns `undefined` if none matches.
142
+ * @returns This configurator, for chaining.
143
+ */
144
+ setResolver(fn: ContextResolverFn): this;
145
+ /**
146
+ * Defaults `resolveInitialContext` from the seeded/resolved state, once the
147
+ * real config has been assembled.
148
+ *
149
+ * @param config - The context module config assembled by the base configurator.
150
+ * @param init - Module initializer arguments.
151
+ * @returns The context module configuration, backed by seeded/resolved data.
152
+ */
153
+ protected _processConfig(config: Partial<ContextModuleConfig>, init: ModuleInitializerArgs<IContextModuleConfigurator, [ServicesModule, NavigationModule]>): Promise<ContextModuleConfig>;
154
+ }
155
+ export default ContextMockConfigurator;
@@ -0,0 +1,40 @@
1
+ import type { ContextItem } from '../../types';
2
+ /**
3
+ * Creates one {@link ContextItem} fixture per call, for a single factory instance.
4
+ *
5
+ * @param overrides - Fields to override on the generated item. Supplying `id`
6
+ * skips the sequential generator for that one item.
7
+ * @returns A fully-formed {@link ContextItem}.
8
+ */
9
+ export type MockContextItemFactory = (overrides?: Partial<ContextItem>) => ContextItem;
10
+ /**
11
+ * Builds a {@link MockContextItemFactory} producing deterministic, sequential
12
+ * ids of the form `<prefix>-<n>`, with a realistic `title` filled in by
13
+ * {@link https://fakerjs.dev/ | faker} (`@faker-js/faker`, a peer dependency —
14
+ * only required if this factory is imported).
15
+ *
16
+ * @remarks
17
+ * Ids are scoped to the returned factory, not shared globally, so two tests
18
+ * creating their own factory each start counting from `1` — a random id (e.g.
19
+ * `crypto.randomUUID()`) would change on every run and break any assertion
20
+ * that seeds one item and expects to see that same id again. The faker seed
21
+ * is derived from that same id, so the generated `title` is just as
22
+ * deterministic. For fixtures spanning several context types (e.g. a
23
+ * parent/child type hierarchy), use `createContextItems` instead — it
24
+ * assigns ids per type and wires the type hierarchy for you.
25
+ *
26
+ * @param prefix - The id prefix. Defaults to `'ctx'`.
27
+ * @returns A function creating one {@link ContextItem} fixture per call.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const createContextItem = createContextItemFactory();
32
+ *
33
+ * const project = createContextItem(); // id: 'ctx-1', title: a deterministic faker company name
34
+ * const facility = createContextItem({ title: 'Facility A' }); // id: 'ctx-2', title overridden
35
+ *
36
+ * mock.setContexts([project, facility]);
37
+ * ```
38
+ */
39
+ export declare const createContextItemFactory: (prefix?: string) => MockContextItemFactory;
40
+ export default createContextItemFactory;
@@ -0,0 +1,59 @@
1
+ import type { ContextItem } from '../../types';
2
+ /** Overridable {@link ContextItem} fields. `id` and `type` are always assigned by the type seed itself. */
3
+ export type ContextItemOverrides = Partial<Omit<ContextItem, 'id' | 'type'>>;
4
+ /**
5
+ * Describes one context type to generate fixtures for.
6
+ *
7
+ * @param type - The context type id (e.g. `'ProjectMaster'`, `'Contract'`).
8
+ * @param count - Number of items to generate for this type. Defaults to `1`.
9
+ * @param parentTypeIds - Parent type ids, when this type is a child in the
10
+ * type hierarchy — sets `type.isChildType`/`type.parentTypeIds` on every
11
+ * generated item of this type.
12
+ * @param item - Per-item overrides, called with the item's 1-based index
13
+ * within this type.
14
+ */
15
+ export interface ContextTypeSeed {
16
+ type: string;
17
+ count?: number;
18
+ parentTypeIds?: string[];
19
+ item?: (index: number) => ContextItemOverrides;
20
+ }
21
+ /**
22
+ * Generates a batch of {@link ContextItem} fixtures across one or more
23
+ * context types, with deterministic ids, a realistic `title` from
24
+ * {@link https://fakerjs.dev/ | faker} (`@faker-js/faker`, a peer dependency —
25
+ * only required if this factory is imported), and a consistent type hierarchy.
26
+ *
27
+ * @remarks
28
+ * Ids are `<type>-<n>` (lowercased type, 1-based per type), so results are
29
+ * stable across runs and readable in test failures. `title` is filled in from
30
+ * a faker instance seeded by that same id, so it's just as deterministic.
31
+ * Feeding the result to `ContextMockConfigurator.setContexts` is enough to
32
+ * make related-context resolution work across types — the mock's
33
+ * `relatedContexts` filters this same seeded pool by type, so a child-typed
34
+ * item resolves into a parent of its `parentTypeIds` without any per-item
35
+ * wiring. That default is a simplification: the real context API resolves
36
+ * relations per specific instance (a `Contract` belongs to one particular
37
+ * `ProjectMaster`, not every `ProjectMaster` in the system) — seed only one
38
+ * instance per type when that distinction doesn't matter to the test, or use
39
+ * `ContextMockConfigurator.setRelatedContexts` to pin a specific item's
40
+ * relations when it does.
41
+ *
42
+ * @param types - The context types, and how many items to generate for each.
43
+ * @returns The generated context items, in the order the type seeds were given.
44
+ *
45
+ * @example Seed a project type and a child contract type
46
+ * ```ts
47
+ * const [project] = createContextItems([{ type: 'ProjectMaster' }]);
48
+ * const [contract] = createContextItems([
49
+ * { type: 'Contract', parentTypeIds: ['ProjectMaster'] },
50
+ * ]);
51
+ *
52
+ * enableContextMock(configurator, (mock) => {
53
+ * mock.setContexts([project, contract]);
54
+ * // relatedContexts({ item: contract, filter: { type: ['ProjectMaster'] } }) now resolves `project`
55
+ * });
56
+ * ```
57
+ */
58
+ export declare const createContextItems: (types: ContextTypeSeed[]) => ContextItem[];
59
+ export default createContextItems;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Fixture generators for {@link ContextMockConfigurator} test data.
3
+ *
4
+ * @remarks
5
+ * A separate entry point from `@equinor/fusion-framework-module-context/mock`
6
+ * because these factories use {@link https://fakerjs.dev/ | faker}
7
+ * (`@faker-js/faker`) for realistic values — an optional peer dependency, only
8
+ * required if this entry point is imported. `enableContextMock` and
9
+ * `ContextMockConfigurator` on the main `/mock` entry point never require it.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * import { createContextItems } from '@equinor/fusion-framework-module-context/mock/fixtures';
14
+ *
15
+ * const [project] = createContextItems([{ type: 'ProjectMaster' }]);
16
+ * ```
17
+ *
18
+ * @packageDocumentation
19
+ */
20
+ export { createContextItemFactory, type MockContextItemFactory, } from './create-context-item-factory';
21
+ export { createContextItems, type ContextTypeSeed, type ContextItemOverrides, } from './create-context-items';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Derives a numeric seed from a string, for a deterministic {@link https://fakerjs.dev/ | faker} instance.
3
+ *
4
+ * @remarks
5
+ * A pure-JS hash (no `node:crypto`) so fixtures stay usable in browser-like test
6
+ * environments, not just Node. Same id in, same seed out, every run.
7
+ *
8
+ * @param value - The string to derive a seed from (typically a generated item id).
9
+ * @returns A 32-bit unsigned integer seed.
10
+ */
11
+ export declare const stringToSeed: (value: string) => number;
12
+ export default stringToSeed;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Mock context module for tests: real provider, real configurator, in-memory data.
3
+ *
4
+ * @remarks
5
+ * Substituting the data source is the smallest change that removes the context
6
+ * API, HTTP mocking, and service-discovery mocking from a test. Everything
7
+ * above it — validation, resolution, parent-context propagation, initial-context
8
+ * selection — is the production code path.
9
+ *
10
+ * This is one of two ways to mock context data in tests: a small, static,
11
+ * in-memory pool (this module — no HTTP layer involved at all). The other is
12
+ * mocking the context API's HTTP responses directly (e.g. with MSW), which
13
+ * exercises the real `ContextModuleConfigurator`/services/HTTP pipeline —
14
+ * reach for that instead when the test needs to cover that pipeline itself.
15
+ * For fixture generators with realistic fake data, see
16
+ * `@equinor/fusion-framework-module-context/mock/fixtures`.
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * import { enableContextMock } from '@equinor/fusion-framework-module-context/mock';
21
+ *
22
+ * enableContextMock(configurator, (mock) => {
23
+ * mock.setCurrentContext({ id: 'my-ctx', type: { id: 'ProjectMaster' }, value: {} });
24
+ * });
25
+ * ```
26
+ *
27
+ * @packageDocumentation
28
+ */
29
+ export { ContextMockConfigurator, type ContextResolverFn, } from './ContextMockConfigurator';
30
+ export { enableContextMock, contextMockModule, type ContextMockConfigFn } from './module';