@open-pioneer/map 0.12.0-dev.20250725080856 → 1.0.0-dev.20251020091932

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 (161) hide show
  1. package/CHANGELOG.md +199 -2
  2. package/LayerFactory.d.ts +54 -0
  3. package/LayerFactory.js +45 -0
  4. package/LayerFactory.js.map +1 -0
  5. package/MapRegistry.d.ts +81 -0
  6. package/MapRegistry.js +162 -0
  7. package/MapRegistry.js.map +1 -0
  8. package/README.md +231 -62
  9. package/index.d.ts +55 -1
  10. package/index.js +9 -9
  11. package/internalTestSupport.d.ts +9 -1
  12. package/internalTestSupport.js +2 -1
  13. package/internalTestSupport.js.map +1 -1
  14. package/layers/AbstractLayer.d.ts +58 -0
  15. package/{model → layers}/AbstractLayer.js +70 -31
  16. package/layers/AbstractLayer.js.map +1 -0
  17. package/layers/AbstractLayerBase.d.ts +177 -0
  18. package/layers/AbstractLayerBase.js +211 -0
  19. package/layers/AbstractLayerBase.js.map +1 -0
  20. package/layers/GroupLayer.d.ts +60 -0
  21. package/layers/GroupLayer.js +61 -0
  22. package/layers/GroupLayer.js.map +1 -0
  23. package/layers/SimpleLayer.d.ts +42 -0
  24. package/layers/SimpleLayer.js +32 -0
  25. package/layers/SimpleLayer.js.map +1 -0
  26. package/layers/WMSLayer.d.ts +66 -0
  27. package/layers/WMSLayer.js +223 -0
  28. package/layers/WMSLayer.js.map +1 -0
  29. package/layers/WMTSLayer.d.ts +56 -0
  30. package/{model/layers/WMTSLayerImpl.js → layers/WMTSLayer.js} +59 -57
  31. package/layers/WMTSLayer.js.map +1 -0
  32. package/layers/group/GroupLayerCollection.d.ts +48 -0
  33. package/layers/group/GroupLayerCollection.js +84 -0
  34. package/layers/group/GroupLayerCollection.js.map +1 -0
  35. package/layers/shared/AddLayerOptions.d.ts +45 -0
  36. package/layers/shared/ChildrenCollection.d.ts +12 -0
  37. package/layers/shared/LayerConfig.d.ts +65 -0
  38. package/layers/shared/LayerRetrievalOptions.d.ts +34 -0
  39. package/layers/shared/SublayerBaseType.d.ts +22 -0
  40. package/layers/shared/SublayersCollection.d.ts +39 -0
  41. package/layers/shared/SublayersCollection.js +64 -0
  42. package/layers/shared/SublayersCollection.js.map +1 -0
  43. package/{model → layers/shared}/getRecursiveLayers.d.ts +4 -1
  44. package/{model → layers/shared}/getRecursiveLayers.js +16 -4
  45. package/layers/shared/getRecursiveLayers.js.map +1 -0
  46. package/layers/shared/internals.d.ts +44 -0
  47. package/layers/shared/internals.js +31 -0
  48. package/layers/shared/internals.js.map +1 -0
  49. package/layers/unions.d.ts +61 -0
  50. package/{api/layers/base.js → layers/unions.js} +1 -1
  51. package/layers/unions.js.map +1 -0
  52. package/layers/wms/WMSSublayer.d.ts +72 -0
  53. package/layers/wms/WMSSublayer.js +133 -0
  54. package/layers/wms/WMSSublayer.js.map +1 -0
  55. package/layers/wms/getLegendUrl.d.ts +4 -0
  56. package/layers/wms/getLegendUrl.js +31 -0
  57. package/layers/wms/getLegendUrl.js.map +1 -0
  58. package/layers/wmts/getLegendUrl.d.ts +1 -0
  59. package/layers/wmts/getLegendUrl.js +31 -0
  60. package/layers/wmts/getLegendUrl.js.map +1 -0
  61. package/model/Highlights.d.ts +2 -3
  62. package/model/Highlights.js +7 -21
  63. package/model/Highlights.js.map +1 -1
  64. package/model/LayerCollection.d.ts +121 -0
  65. package/model/LayerCollection.js +469 -0
  66. package/model/LayerCollection.js.map +1 -0
  67. package/{api → model}/MapConfig.d.ts +15 -1
  68. package/model/MapModel.d.ts +232 -0
  69. package/model/{MapModelImpl.js → MapModel.js} +128 -24
  70. package/model/MapModel.js.map +1 -0
  71. package/model/createMapModel.d.ts +3 -3
  72. package/model/createMapModel.js +26 -19
  73. package/model/createMapModel.js.map +1 -1
  74. package/package.json +33 -12
  75. package/services.d.ts +2 -1
  76. package/services.js +2 -1
  77. package/services.js.map +1 -1
  78. package/ui/DefaultMapProvider.d.ts +6 -3
  79. package/ui/DefaultMapProvider.js +7 -13
  80. package/ui/DefaultMapProvider.js.map +1 -1
  81. package/ui/MapAnchor.d.ts +7 -0
  82. package/ui/MapAnchor.js.map +1 -1
  83. package/ui/MapContainer.d.ts +9 -2
  84. package/ui/MapContainer.js +4 -16
  85. package/ui/MapContainer.js.map +1 -1
  86. package/ui/MapContainerContext.js.map +1 -1
  87. package/ui/computeMapAnchorStyles.js.map +1 -1
  88. package/ui/{useMapModel.d.ts → hooks/useMapModel.d.ts} +47 -24
  89. package/ui/hooks/useMapModel.js +61 -0
  90. package/ui/hooks/useMapModel.js.map +1 -0
  91. package/ui/styles.css +15 -0
  92. package/ui/styles.css.map +1 -1
  93. package/{api → utils}/BaseFeature.d.ts +2 -0
  94. package/utils/InternalConstructorTag.d.ts +8 -0
  95. package/utils/InternalConstructorTag.js +9 -0
  96. package/utils/InternalConstructorTag.js.map +1 -0
  97. package/utils/fetch.d.ts +2 -0
  98. package/{util/capabilities-utils.js → utils/fetch.js} +3 -3
  99. package/utils/fetch.js.map +1 -0
  100. package/{util → utils}/geometry-utils.d.ts +2 -0
  101. package/utils/geometry-utils.js.map +1 -0
  102. package/{util → utils}/ol-test-support.js.map +1 -1
  103. package/{projections.d.ts → utils/projections.d.ts} +5 -0
  104. package/utils/projections.js.map +1 -0
  105. package/MapRegistryImpl.d.ts +0 -17
  106. package/MapRegistryImpl.js +0 -93
  107. package/MapRegistryImpl.js.map +0 -1
  108. package/api/MapModel.d.ts +0 -255
  109. package/api/MapRegistry.d.ts +0 -48
  110. package/api/index.d.ts +0 -13
  111. package/api/layers/GroupLayer.d.ts +0 -59
  112. package/api/layers/GroupLayer.js +0 -6
  113. package/api/layers/GroupLayer.js.map +0 -1
  114. package/api/layers/SimpleLayer.d.ts +0 -27
  115. package/api/layers/SimpleLayer.js +0 -6
  116. package/api/layers/SimpleLayer.js.map +0 -1
  117. package/api/layers/WMSLayer.d.ts +0 -64
  118. package/api/layers/WMSLayer.js +0 -6
  119. package/api/layers/WMSLayer.js.map +0 -1
  120. package/api/layers/WMTSLayer.d.ts +0 -33
  121. package/api/layers/WMTSLayer.js +0 -6
  122. package/api/layers/WMTSLayer.js.map +0 -1
  123. package/api/layers/base.d.ts +0 -270
  124. package/api/layers/base.js.map +0 -1
  125. package/api/layers/index.d.ts +0 -5
  126. package/api/shared.d.ts +0 -48
  127. package/model/AbstractLayer.d.ts +0 -25
  128. package/model/AbstractLayer.js.map +0 -1
  129. package/model/AbstractLayerBase.d.ts +0 -57
  130. package/model/AbstractLayerBase.js +0 -127
  131. package/model/AbstractLayerBase.js.map +0 -1
  132. package/model/LayerCollectionImpl.d.ts +0 -32
  133. package/model/LayerCollectionImpl.js +0 -329
  134. package/model/LayerCollectionImpl.js.map +0 -1
  135. package/model/MapModelImpl.d.ts +0 -46
  136. package/model/MapModelImpl.js.map +0 -1
  137. package/model/SublayersCollectionImpl.d.ts +0 -19
  138. package/model/SublayersCollectionImpl.js +0 -43
  139. package/model/SublayersCollectionImpl.js.map +0 -1
  140. package/model/getRecursiveLayers.js.map +0 -1
  141. package/model/layers/GroupLayerImpl.d.ts +0 -40
  142. package/model/layers/GroupLayerImpl.js +0 -101
  143. package/model/layers/GroupLayerImpl.js.map +0 -1
  144. package/model/layers/SimpleLayerImpl.d.ts +0 -13
  145. package/model/layers/SimpleLayerImpl.js +0 -19
  146. package/model/layers/SimpleLayerImpl.js.map +0 -1
  147. package/model/layers/WMSLayerImpl.d.ts +0 -41
  148. package/model/layers/WMSLayerImpl.js +0 -302
  149. package/model/layers/WMSLayerImpl.js.map +0 -1
  150. package/model/layers/WMTSLayerImpl.d.ts +0 -17
  151. package/model/layers/WMTSLayerImpl.js.map +0 -1
  152. package/projections.js.map +0 -1
  153. package/ui/useMapModel.js +0 -59
  154. package/ui/useMapModel.js.map +0 -1
  155. package/util/capabilities-utils.d.ts +0 -2
  156. package/util/capabilities-utils.js.map +0 -1
  157. package/util/geometry-utils.js.map +0 -1
  158. /package/{util → utils}/geometry-utils.js +0 -0
  159. /package/{util → utils}/ol-test-support.d.ts +0 -0
  160. /package/{util → utils}/ol-test-support.js +0 -0
  161. /package/{projections.js → utils/projections.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,10 +1,52 @@
1
1
  # @open-pioneer/map
2
2
 
3
- ## 0.12.0-dev.20250725080856
3
+ ## 1.0.0-dev.20251020091932
4
+
5
+ ### Major Changes
6
+
7
+ - b3709f1: **Breaking:** Remove layer constructor types from public API (e.g. `SimpleLayerConstructor`).
8
+ - 9e9bc6e: **Breaking**: Internal layers are no longer returned from getters such as `getItems()` or `getRecursiveLayers()` by default.
9
+
10
+ A new option `includeInternalLayers` has been implemented opt-in into internal layers.
11
+ By default, internal layers are not returned by functions like `getItems()` or `getRecursiveLayers()`.
12
+ If internal layer should be returned this must be specified explicitly with the `includeInternalLayers` option.
13
+
14
+ ```js
15
+ import { MapModel } from "@open-pioneer/map";
16
+
17
+ //internal layers are not included
18
+ const layers = myMapModel.layers.getItems();
19
+ //include internal layers
20
+ const allLayers = myMapModel.layers.getItems({ includeInternalLayers: true });
21
+ ```
22
+
23
+ Note that if internal layers are returned this includes system layers (e.g. for highlights or geolocation) that were not explicitly added to the map.
24
+ The described behavior is aligned for the functions `getItems()`, `getLayers()`, `getAllLayers()` and `getRecursiveLayers()` in `LayerCollection`, `WMSLayer` and `GroupLayer`.
25
+ The function `getRecursiveLayers()` does not return non-internal child layers of an internal layer.
26
+
27
+ - b3709f1: **Breaking:** Remove old event API from layer types and the map model. These were only used for the `"destroy"` event.
28
+
29
+ The destroy event still exists, but is now based on the event system of the [reactivity API](https://github.com/conterra/reactivity/tree/main/packages/reactivity-events):
30
+
31
+ ```ts
32
+ import { on } from "@conterra/reactivity-events";
33
+
34
+ const layer = ...;
35
+ on(layer.destroyed, () => {
36
+ console.debug("layer was destroyed");
37
+ });
38
+
39
+ const mapModel = ...;
40
+ on(mapModel.destroyed, () => {
41
+ console.debug("layer was destroyed");
42
+ });
43
+ ```
4
44
 
5
45
  ### Minor Changes
6
46
 
7
- - 2702df4: Introduce `internal` property for all layer types (including sublayers). If `internal` is `true` (default: `false`) the layer is not considered by any UI widget (e.g. legend and Toc). The `internal` state of a layer is not to be confused with the layer's visibility on the map which is determined by the `visible` property.
47
+ - 2702df4: Introduce `internal` property for all layer types (including sublayers).
48
+ If `internal` is `true` (default: `false`) the layer is not considered by any UI widget (e.g. legend and Toc).
49
+ The `internal` state of a layer is not to be confused with the layer's visibility on the map which is determined by the `visible` property.
8
50
 
9
51
  ```typescript
10
52
  //internal layer is visible on the map but hidden in UI elements like legend and Toc
@@ -17,10 +59,165 @@
17
59
  });
18
60
  ```
19
61
 
62
+ - 5df900f: Add a new hook `useMapModelValue(props?)`.
63
+ The hook returns either the directly configured `map` (via props) or the default map from a parent `DefaultMapProvider`.
64
+ If neither is present, an error will be thrown.
65
+
66
+ This hook is used in all components that work with the map.
67
+ The typical usage works like this:
68
+
69
+ ```ts
70
+ import { MapModelProps, useMapModelValue } from "@open-pioneer/map";
71
+
72
+ // optional `map` property inherited from `MapModelProps`
73
+ export interface MyComponentProps extends MapModelProps {
74
+ // ... other properties
75
+ }
76
+
77
+ export function MyComponent(props) {
78
+ const map = useMapModelValue(props); // looks up the map
79
+ }
80
+ ```
81
+
82
+ You can also call this hook without any arguments:
83
+
84
+ ```ts
85
+ // Map model from DefaultMapProvider or an error.
86
+ const mapModel = useMapModelValue();
87
+ ```
88
+
89
+ This hook should replace _most_ usages `useMapModel`, which can't return the map model directly since it may not have finished construction yet.
90
+
91
+ - 14c484e: Introduce the `LayerFactory` service (interface `"map.LayerFactory"`).
92
+
93
+ The layer factory should be used to construct new layer instances, instead of calling the layer constructor directly.
94
+ Calling the constructor directly (e.g. `new SimpleLayer`) is deprecated (but still fully supported).
95
+
96
+ For example:
97
+
98
+ ```ts
99
+ // OLD
100
+ new SimpleLayer({
101
+ title: "OSM",
102
+ isBaseLayer: true,
103
+ olLayer: new TileLayer({
104
+ source: new OSM()
105
+ })
106
+ });
107
+ ```
108
+
109
+ ```ts
110
+ // NEW
111
+ const layerFactory = ...; // injected
112
+ layerFactory.create({
113
+ type: SimpleLayer,
114
+ title: "OSM",
115
+ isBaseLayer: true,
116
+ olLayer: new TileLayer({
117
+ source: new OSM()
118
+ })
119
+ });
120
+ ```
121
+
122
+ This was done to support passing hidden dependencies from the layer factory to the layer instance (such as the `HttpService`),
123
+ without forcing the user to supply these dependencies manually.
124
+
125
+ The `MapConfigProvider` has been updated as well.
126
+ The `getMapConfig` method will now receive the layer factory as an option.
127
+ This makes it easy to migrate to the new API:
128
+
129
+ ```diff
130
+ # Example MapConfigProvider
131
+ export class MapConfigProviderImpl implements MapConfigProvider {
132
+ mapId = MAP_ID;
133
+
134
+ - async getMapConfig(): Promise<MapConfig> {
135
+ + async getMapConfig({ layerFactory }: MapConfigProviderOptions): Promise<MapConfig> {
136
+ return {
137
+ initialView: {
138
+ kind: "position",
139
+ center: { x: 404747, y: 5757920 },
140
+ zoom: 14
141
+ },
142
+ layers: [
143
+ - new SimpleLayer({
144
+ + layerFactory.create({
145
+ + type: SimpleLayer,
146
+ title: "OSM",
147
+ isBaseLayer: true,
148
+ olLayer: new TileLayer({
149
+ source: new OSM()
150
+ })
151
+ })
152
+ ]
153
+ };
154
+ }
155
+ }
156
+ ```
157
+
158
+ - aeb9000: Add new `"topmost"` option to add layers that are always displayed on the top (above all other layers).
159
+
160
+ A new layers can be added at `topmost` to ensure that this layer will always be displayed on top of the other layers.
161
+ This can be used, for example, to implement highlights or to draw graphics.
162
+ Layers added at `"topmost"` will always be shown above layers at `"top"`.
163
+
164
+ When using the `"above"` or `"below"` options with a `"topmost"` reference layer, that layer becomes `"topmost"` as well.
165
+
166
+ ```typescript
167
+ import { MapModel, SimpleLayer } from "@open-pioneer/map";
168
+
169
+ const highlightLayer = new SimpleLayer({
170
+ title: "highlights",
171
+ olLayer: myOlLayer
172
+ });
173
+ //always displayed at the top
174
+ myMapModel.layers.addLayer(highlightLayer, { at: "topmost" });
175
+ ```
176
+
177
+ - 5df900f: Deprecate the parameter-less signature of `useMapModel()`:
178
+
179
+ ```ts
180
+ // Returns the DefaultMapProvider's map, but wrapped in a result value (loading/resolved/rejected)
181
+ const result = useMapModel();
182
+ ```
183
+
184
+ Use `useMapModelValue()` instead:
185
+
186
+ ```ts
187
+ // Returns the map model directly.
188
+ const mapModel = useMapModelValue();
189
+ ```
190
+
191
+ All other signatures of `useMapModel()` are still fully supported.
192
+
193
+ - 773fa2d: The map now has an appropriate focus outline style by default, which respects the map view's padding.
194
+ For information on disabling this behavior, see the map package documentation.
195
+ - 2abcaaf: Update to chakra-ui 3.27.1
196
+
20
197
  ### Patch Changes
21
198
 
199
+ - c6180c6: Update eslint to version 9.
200
+ - 29a10df: Support buffer for zoom geometries.
201
+
202
+ For example:
203
+
204
+ ```ts
205
+ const map: MapModel = ...;
206
+ const highlight = map.highlightAndZoom(someGeometries, {
207
+ // Grows extent by 10%
208
+ buffer: 0.1
209
+ });
210
+ ```
211
+
22
212
  - 10d2fe7: Update dependencies
213
+ - 12561fe: The default value of the `role` prop on the `MapContainer` was changed to `application` to allow map keyboard navigation while using NVDA screen reader.
23
214
  - 8986b3b: Remove obsolete dependency @types/proj4
215
+ - dfd7c7e: We use the already existing calculateBufferedExtent instead of the highlights buffer.
216
+ Use the `buffer` to specify the size increase. E.g. `1.1` for 10% size increase.
217
+ - 138d85b: Update core packages to 4.1.0
218
+ - 2c8b617: Introduce `MapRegistry.createMapModel` method to create a `MapModel` without a `MapConfigProvider`.
219
+ For more details, see [PR](https://github.com/open-pioneer/trails-openlayers-base-packages/pull/499) and [issue](https://github.com/open-pioneer/trails-openlayers-base-packages/issues/483).
220
+ - b3709f1: Refactor map package internals.
24
221
  - f1f69f2: Update to OpenLayers 10.6.1
25
222
  - da6a410: Update dependencies
26
223
 
@@ -0,0 +1,54 @@
1
+ import { HttpService } from "@open-pioneer/http";
2
+ import { DECLARE_SERVICE_INTERFACE, ServiceOptions } from "@open-pioneer/runtime";
3
+ import { LayerConfig } from "./layers/shared/LayerConfig";
4
+ import { LayerConstructor } from "./layers/shared/internals";
5
+ import { Layer } from "./layers/unions";
6
+ interface References {
7
+ httpService: HttpService;
8
+ }
9
+ /**
10
+ * Options that can be passed to {@link LayerFactory.create}.
11
+ *
12
+ * The `type` option is mandatory and indicates the type of the layer (e.g. `WMSLayer`).
13
+ * The other options depend on the specific layer type.
14
+ *
15
+ * @group Services
16
+ */
17
+ export type LayerCreateOptions<LayerType extends Layer, Config extends LayerConfig> = {
18
+ /** The layer type to construct. */
19
+ type: LayerConstructor<Config, LayerType>;
20
+ } & Config;
21
+ /**
22
+ * Creates instances of layer classes.
23
+ *
24
+ * Use the interface `"map.LayerFactory"` to obtain an instance of this service.
25
+ *
26
+ * @group Services
27
+ */
28
+ export declare class LayerFactory {
29
+ #private;
30
+ [DECLARE_SERVICE_INTERFACE]: "map.LayerFactory";
31
+ constructor(options: ServiceOptions<References>);
32
+ /**
33
+ * Creates a new instance of the given layer type.
34
+ * The `"type"` option is mandatory and specifies which layer type to create.
35
+ *
36
+ * The other configuration options may be dependent on the specific layer type.
37
+ *
38
+ * Example:
39
+ *
40
+ * ```ts
41
+ * import { SimpleLayer } from "@open-pioneer/map";
42
+ *
43
+ * const layerFactory = ...; // injected
44
+ * const layer = layerFactory.create({
45
+ * type: SimpleLayer,
46
+ * title: "Layer title",
47
+ * olLayer: new TileLayer({}),
48
+ * // ... other options
49
+ * });
50
+ * ```
51
+ */
52
+ create<LayerType extends Layer, Config extends LayerConfig>(config: LayerCreateOptions<LayerType, Config>): LayerType;
53
+ }
54
+ export {};
@@ -0,0 +1,45 @@
1
+ import { AbstractLayer } from './layers/AbstractLayer.js';
2
+ import { INTERNAL_CONSTRUCTOR_TAG } from './utils/InternalConstructorTag.js';
3
+
4
+ class LayerFactory {
5
+ #httpService;
6
+ constructor(options) {
7
+ this.#httpService = options.references.httpService;
8
+ }
9
+ /**
10
+ * Creates a new instance of the given layer type.
11
+ * The `"type"` option is mandatory and specifies which layer type to create.
12
+ *
13
+ * The other configuration options may be dependent on the specific layer type.
14
+ *
15
+ * Example:
16
+ *
17
+ * ```ts
18
+ * import { SimpleLayer } from "@open-pioneer/map";
19
+ *
20
+ * const layerFactory = ...; // injected
21
+ * const layer = layerFactory.create({
22
+ * type: SimpleLayer,
23
+ * title: "Layer title",
24
+ * olLayer: new TileLayer({}),
25
+ * // ... other options
26
+ * });
27
+ * ```
28
+ */
29
+ create(config) {
30
+ const { type, ...rest } = config;
31
+ if (!type || !(type.prototype instanceof AbstractLayer)) {
32
+ throw new Error(
33
+ `Invalid layer type option. Use one of the layer classes exported by this package.`
34
+ );
35
+ }
36
+ return new type(
37
+ rest,
38
+ { httpService: this.#httpService },
39
+ INTERNAL_CONSTRUCTOR_TAG
40
+ );
41
+ }
42
+ }
43
+
44
+ export { LayerFactory };
45
+ //# sourceMappingURL=LayerFactory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LayerFactory.js","sources":["LayerFactory.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { HttpService } from \"@open-pioneer/http\";\nimport { DECLARE_SERVICE_INTERFACE, ServiceOptions } from \"@open-pioneer/runtime\";\nimport { AbstractLayer } from \"./layers/AbstractLayer\";\nimport { LayerConfig } from \"./layers/shared/LayerConfig\";\nimport { LayerConstructor } from \"./layers/shared/internals\";\nimport { INTERNAL_CONSTRUCTOR_TAG } from \"./utils/InternalConstructorTag\";\nimport { Layer } from \"./layers/unions\";\n\ninterface References {\n httpService: HttpService;\n}\n\n/**\n * Options that can be passed to {@link LayerFactory.create}.\n *\n * The `type` option is mandatory and indicates the type of the layer (e.g. `WMSLayer`).\n * The other options depend on the specific layer type.\n *\n * @group Services\n */\nexport type LayerCreateOptions<LayerType extends Layer, Config extends LayerConfig> = {\n /** The layer type to construct. */\n type: LayerConstructor<Config, LayerType>;\n} & Config;\n\n/**\n * Creates instances of layer classes.\n *\n * Use the interface `\"map.LayerFactory\"` to obtain an instance of this service.\n *\n * @group Services\n */\nexport class LayerFactory {\n declare [DECLARE_SERVICE_INTERFACE]: \"map.LayerFactory\";\n\n #httpService: HttpService;\n\n constructor(options: ServiceOptions<References>) {\n this.#httpService = options.references.httpService;\n }\n\n /**\n * Creates a new instance of the given layer type.\n * The `\"type\"` option is mandatory and specifies which layer type to create.\n *\n * The other configuration options may be dependent on the specific layer type.\n *\n * Example:\n *\n * ```ts\n * import { SimpleLayer } from \"@open-pioneer/map\";\n *\n * const layerFactory = ...; // injected\n * const layer = layerFactory.create({\n * type: SimpleLayer,\n * title: \"Layer title\",\n * olLayer: new TileLayer({}),\n * // ... other options\n * });\n * ```\n */\n create<LayerType extends Layer, Config extends LayerConfig>(\n config: LayerCreateOptions<LayerType, Config>\n ): LayerType {\n const { type, ...rest } = config;\n if (!type || !(type.prototype instanceof AbstractLayer)) {\n throw new Error(\n `Invalid layer type option. Use one of the layer classes exported by this package.`\n );\n }\n return new type(\n rest as unknown as Config,\n { httpService: this.#httpService },\n INTERNAL_CONSTRUCTOR_TAG\n );\n }\n}\n"],"names":[],"mappings":";;;AAkCO,MAAM,YAAA,CAAa;AAAA,EAGtB,YAAA;AAAA,EAEA,YAAY,OAAA,EAAqC;AAC7C,IAAA,IAAA,CAAK,YAAA,GAAe,QAAQ,UAAA,CAAW,WAAA;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,OACI,MAAA,EACS;AACT,IAAA,MAAM,EAAE,IAAA,EAAM,GAAG,IAAA,EAAK,GAAI,MAAA;AAC1B,IAAA,IAAI,CAAC,IAAA,IAAQ,EAAE,IAAA,CAAK,qBAAqB,aAAA,CAAA,EAAgB;AACrD,MAAA,MAAM,IAAI,KAAA;AAAA,QACN,CAAA,iFAAA;AAAA,OACJ;AAAA,IACJ;AACA,IAAA,OAAO,IAAI,IAAA;AAAA,MACP,IAAA;AAAA,MACA,EAAE,WAAA,EAAa,IAAA,CAAK,YAAA,EAAa;AAAA,MACjC;AAAA,KACJ;AAAA,EACJ;AACJ;;;;"}
@@ -0,0 +1,81 @@
1
+ import { HttpService } from "@open-pioneer/http";
2
+ import { DECLARE_SERVICE_INTERFACE, Service, ServiceOptions } from "@open-pioneer/runtime";
3
+ import OlMap from "ol/Map";
4
+ import { LayerFactory } from "./LayerFactory";
5
+ import { MapConfig } from "./model/MapConfig";
6
+ import { MapModel } from "./model/MapModel";
7
+ /**
8
+ * Options passed to the {@link MapConfigProvider.getMapConfig} method.
9
+ *
10
+ * @group Services
11
+ */
12
+ export interface MapConfigProviderOptions {
13
+ /**
14
+ * A reference to the layer factory, for the construction of new layer instances.
15
+ */
16
+ layerFactory: LayerFactory;
17
+ }
18
+ /**
19
+ * Provides an OpenLayers map configuration with a given map id.
20
+ *
21
+ * The implementor must also provide the interface name `"map.MapConfigProvider"`.
22
+ *
23
+ * @group Services
24
+ */
25
+ export interface MapConfigProvider {
26
+ /**
27
+ * Unique identifier of the map.
28
+ */
29
+ readonly mapId: string;
30
+ /**
31
+ * Returns the map configuration for this map.
32
+ *
33
+ * Called by the {@link MapRegistry} when the map is requested for the first time.
34
+ *
35
+ * See {@link MapConfig} for supported options during map creation.
36
+ * Use {@link MapConfigProviderOptions.layerFactory} to construct new layers.
37
+ */
38
+ getMapConfig(options: MapConfigProviderOptions): Promise<MapConfig>;
39
+ }
40
+ interface References {
41
+ providers: MapConfigProvider[];
42
+ httpService: HttpService;
43
+ layerFactory: LayerFactory;
44
+ }
45
+ /**
46
+ * Provides access to registered map instances.
47
+ *
48
+ * Maps are identified by a unique id.
49
+ *
50
+ * Inject an instance of this service by referencing the interface name `"map.MapRegistry"`.
51
+ *
52
+ * @group Services
53
+ */
54
+ export declare class MapRegistry implements Service {
55
+ #private;
56
+ [DECLARE_SERVICE_INTERFACE]: "map.MapRegistry";
57
+ constructor({ references, intl }: ServiceOptions<References>);
58
+ destroy(): void;
59
+ /**
60
+ * Returns the map model associated with the given id.
61
+ * Returns undefined if there is no such model.
62
+ */
63
+ getMapModel(mapId: string): Promise<MapModel | undefined>;
64
+ /**
65
+ * Like {@link getMapModel}, but throws if no model exists for the given `mapId`.
66
+ */
67
+ expectMapModel(mapId: string): Promise<MapModel>;
68
+ /**
69
+ * Creates a MapModel without the need to provide a {@link MapConfigProvider}.
70
+ * Throws an error if a map with the given id already exists or if the map config is invalid.
71
+ */
72
+ createMapModel(mapId: string, options?: MapConfig): Promise<MapModel>;
73
+ /**
74
+ * Given a raw OpenLayers map instance, returns the associated {@link MapModel} - or undefined
75
+ * if the map is unknown to this registry.
76
+ *
77
+ * All OpenLayers maps created by this registry (e.g. via {@link MapConfigProvider} or {@link createMapModel}) have an associated map model.
78
+ */
79
+ getMapModelByRawInstance(olMap: OlMap): MapModel | undefined;
80
+ }
81
+ export {};
package/MapRegistry.js ADDED
@@ -0,0 +1,162 @@
1
+ import { batch } from '@conterra/reactivity-core';
2
+ import { onSync } from '@conterra/reactivity-events';
3
+ import { createLogger } from '@open-pioneer/core';
4
+ import { createMapModel } from './model/createMapModel.js';
5
+
6
+ const LOG = createLogger("map:MapRegistry");
7
+ class MapRegistry {
8
+ #intl;
9
+ #httpService;
10
+ #layerFactory;
11
+ #configProviders = /* @__PURE__ */ new Map();
12
+ #entries = /* @__PURE__ */ new Map();
13
+ #modelCreationJobs = /* @__PURE__ */ new Map();
14
+ #modelsByOlMap = /* @__PURE__ */ new WeakMap();
15
+ #destroyed = false;
16
+ constructor({ references, intl }) {
17
+ this.#intl = intl;
18
+ this.#httpService = references.httpService;
19
+ this.#layerFactory = references.layerFactory;
20
+ const providers = references.providers;
21
+ for (const provider of providers) {
22
+ this.#configProviders.set(provider.mapId, provider);
23
+ }
24
+ }
25
+ destroy() {
26
+ if (this.#destroyed) {
27
+ return;
28
+ }
29
+ batch(() => {
30
+ LOG.debug(`Destroy map registry and all maps`);
31
+ this.#destroyed = true;
32
+ this.#entries.forEach((entry) => {
33
+ if (entry.kind === "model") {
34
+ entry.listener.destroy();
35
+ entry.model.destroy();
36
+ }
37
+ });
38
+ this.#entries.clear();
39
+ this.#modelCreationJobs.clear();
40
+ });
41
+ }
42
+ /**
43
+ * Returns the map model associated with the given id.
44
+ * Returns undefined if there is no such model.
45
+ */
46
+ async getMapModel(mapId) {
47
+ if (this.#destroyed) {
48
+ throw new Error("MapRegistry has already been destroyed.");
49
+ }
50
+ const entry = this.#entries.get(mapId);
51
+ if (entry) {
52
+ return unbox(entry);
53
+ }
54
+ const creationJob = this.#modelCreationJobs.get(mapId);
55
+ if (creationJob) {
56
+ return await waitForResult(creationJob);
57
+ }
58
+ const provider = this.#configProviders.get(mapId);
59
+ if (!provider) {
60
+ LOG.debug(`Failed to find a config provider for map id '${mapId}'.`);
61
+ return void 0;
62
+ }
63
+ return await this.#createMapModel(
64
+ mapId,
65
+ () => provider.getMapConfig({
66
+ layerFactory: this.#layerFactory
67
+ })
68
+ );
69
+ }
70
+ /**
71
+ * Like {@link getMapModel}, but throws if no model exists for the given `mapId`.
72
+ */
73
+ async expectMapModel(mapId) {
74
+ const model = await this.getMapModel(mapId);
75
+ if (!model) {
76
+ throw new Error(`No configuration available for map with id '${mapId}'.`);
77
+ }
78
+ return model;
79
+ }
80
+ /**
81
+ * Creates a MapModel without the need to provide a {@link MapConfigProvider}.
82
+ * Throws an error if a map with the given id already exists or if the map config is invalid.
83
+ */
84
+ async createMapModel(mapId, options) {
85
+ if (this.#destroyed) {
86
+ throw new Error("MapRegistry has already been destroyed.");
87
+ }
88
+ if (this.#entries.has(mapId)) {
89
+ throw new Error(`Map id '${mapId}' is not unique.`);
90
+ }
91
+ if (this.#modelCreationJobs.has(mapId)) {
92
+ throw new Error(`A map with the id '${mapId}' is already under construction.`);
93
+ }
94
+ return await this.#createMapModel(mapId, () => Promise.resolve(options ?? {}));
95
+ }
96
+ /**
97
+ * Given a raw OpenLayers map instance, returns the associated {@link MapModel} - or undefined
98
+ * if the map is unknown to this registry.
99
+ *
100
+ * All OpenLayers maps created by this registry (e.g. via {@link MapConfigProvider} or {@link createMapModel}) have an associated map model.
101
+ */
102
+ getMapModelByRawInstance(olMap) {
103
+ return this.#modelsByOlMap.get(olMap);
104
+ }
105
+ // Wrapper method to ensure that in-progress construction of maps can be observed.
106
+ #createMapModel(mapId, configProvider) {
107
+ const creationJob = this.#modelCreationJobs.get(mapId);
108
+ if (creationJob) {
109
+ throw new Error("Internal error: a map model is already being created for this mapId");
110
+ }
111
+ const modelPromise = this.#createMapModelImpl(mapId, configProvider).then((mapModel) => {
112
+ if (this.#destroyed) {
113
+ mapModel.destroy();
114
+ throw new Error(`MapRegistry has been destroyed.`);
115
+ }
116
+ const listener = onSync(mapModel.destroyed, () => {
117
+ if (this.#isDynamic(mapId)) {
118
+ const currentEntry = this.#entries.get(mapId);
119
+ if (currentEntry === entry) {
120
+ this.#entries.delete(mapId);
121
+ }
122
+ }
123
+ });
124
+ const entry = { kind: "model", model: mapModel, listener };
125
+ this.#entries.set(mapId, entry);
126
+ this.#modelCreationJobs.delete(mapId);
127
+ this.#modelsByOlMap.set(mapModel.olMap, mapModel);
128
+ return entry;
129
+ }).catch((cause) => {
130
+ const error = new Error(`Failed to construct map '${mapId}'`, { cause });
131
+ const entry = { kind: "error", error };
132
+ this.#modelCreationJobs.delete(mapId);
133
+ if (!this.#isDynamic(mapId)) {
134
+ this.#entries.set(mapId, entry);
135
+ }
136
+ return entry;
137
+ });
138
+ this.#modelCreationJobs.set(mapId, modelPromise);
139
+ return waitForResult(modelPromise);
140
+ }
141
+ async #createMapModelImpl(mapId, configProvider) {
142
+ LOG.info(`Creating map with id '${mapId}'`);
143
+ const mapConfig = await configProvider();
144
+ const mapModel = await createMapModel(mapId, mapConfig, this.#intl, this.#httpService);
145
+ return mapModel;
146
+ }
147
+ #isDynamic(mapId) {
148
+ return !this.#configProviders.has(mapId);
149
+ }
150
+ }
151
+ async function waitForResult(job) {
152
+ return unbox(await job);
153
+ }
154
+ function unbox(entry) {
155
+ if (entry.kind === "error") {
156
+ throw entry.error;
157
+ }
158
+ return entry.model;
159
+ }
160
+
161
+ export { MapRegistry };
162
+ //# sourceMappingURL=MapRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapRegistry.js","sources":["MapRegistry.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\nimport { batch } from \"@conterra/reactivity-core\";\nimport { onSync } from \"@conterra/reactivity-events\";\nimport { createLogger, Resource } from \"@open-pioneer/core\";\nimport { HttpService } from \"@open-pioneer/http\";\nimport {\n DECLARE_SERVICE_INTERFACE,\n PackageIntl,\n Service,\n ServiceOptions\n} from \"@open-pioneer/runtime\";\nimport OlMap from \"ol/Map\";\nimport { LayerFactory } from \"./LayerFactory\";\nimport { createMapModel } from \"./model/createMapModel\";\nimport { MapConfig } from \"./model/MapConfig\";\nimport { MapModel } from \"./model/MapModel\";\n\nconst LOG = createLogger(\"map:MapRegistry\");\n\n/**\n * Options passed to the {@link MapConfigProvider.getMapConfig} method.\n *\n * @group Services\n */\nexport interface MapConfigProviderOptions {\n /**\n * A reference to the layer factory, for the construction of new layer instances.\n */\n layerFactory: LayerFactory;\n}\n\n/**\n * Provides an OpenLayers map configuration with a given map id.\n *\n * The implementor must also provide the interface name `\"map.MapConfigProvider\"`.\n *\n * @group Services\n */\nexport interface MapConfigProvider {\n /**\n * Unique identifier of the map.\n */\n readonly mapId: string;\n\n /**\n * Returns the map configuration for this map.\n *\n * Called by the {@link MapRegistry} when the map is requested for the first time.\n *\n * See {@link MapConfig} for supported options during map creation.\n * Use {@link MapConfigProviderOptions.layerFactory} to construct new layers.\n */\n getMapConfig(options: MapConfigProviderOptions): Promise<MapConfig>;\n}\n\ninterface References {\n providers: MapConfigProvider[];\n httpService: HttpService;\n layerFactory: LayerFactory;\n}\n\ntype ModelJobResult =\n | { kind: \"model\"; model: MapModel; listener: Resource }\n | { kind: \"error\"; error: Error };\n\n/**\n * Provides access to registered map instances.\n *\n * Maps are identified by a unique id.\n *\n * Inject an instance of this service by referencing the interface name `\"map.MapRegistry\"`.\n *\n * @group Services\n */\nexport class MapRegistry implements Service {\n declare [DECLARE_SERVICE_INTERFACE]: \"map.MapRegistry\";\n\n #intl: PackageIntl;\n #httpService: HttpService;\n #layerFactory: LayerFactory;\n\n #configProviders = new Map<string, MapConfigProvider>();\n #entries = new Map<string, ModelJobResult>();\n #modelCreationJobs = new Map<string, Promise<ModelJobResult>>();\n #modelsByOlMap = new WeakMap<OlMap, MapModel>();\n #destroyed = false;\n\n constructor({ references, intl }: ServiceOptions<References>) {\n this.#intl = intl;\n this.#httpService = references.httpService;\n this.#layerFactory = references.layerFactory;\n\n const providers = references.providers;\n for (const provider of providers) {\n this.#configProviders.set(provider.mapId, provider);\n }\n }\n\n destroy(): void {\n if (this.#destroyed) {\n return;\n }\n\n batch(() => {\n LOG.debug(`Destroy map registry and all maps`);\n this.#destroyed = true;\n this.#entries.forEach((entry) => {\n if (entry.kind === \"model\") {\n entry.listener.destroy();\n entry.model.destroy();\n }\n });\n this.#entries.clear();\n this.#modelCreationJobs.clear();\n });\n }\n\n /**\n * Returns the map model associated with the given id.\n * Returns undefined if there is no such model.\n */\n async getMapModel(mapId: string): Promise<MapModel | undefined> {\n if (this.#destroyed) {\n throw new Error(\"MapRegistry has already been destroyed.\");\n }\n\n const entry = this.#entries.get(mapId);\n if (entry) {\n return unbox(entry);\n }\n\n const creationJob = this.#modelCreationJobs.get(mapId);\n if (creationJob) {\n return await waitForResult(creationJob);\n }\n\n const provider = this.#configProviders.get(mapId);\n if (!provider) {\n LOG.debug(`Failed to find a config provider for map id '${mapId}'.`);\n return undefined;\n }\n\n return await this.#createMapModel(mapId, () =>\n provider.getMapConfig({\n layerFactory: this.#layerFactory\n })\n );\n }\n\n /**\n * Like {@link getMapModel}, but throws if no model exists for the given `mapId`.\n */\n async expectMapModel(mapId: string): Promise<MapModel> {\n const model = await this.getMapModel(mapId);\n if (!model) {\n throw new Error(`No configuration available for map with id '${mapId}'.`);\n }\n return model;\n }\n\n /**\n * Creates a MapModel without the need to provide a {@link MapConfigProvider}.\n * Throws an error if a map with the given id already exists or if the map config is invalid.\n */\n async createMapModel(mapId: string, options?: MapConfig): Promise<MapModel> {\n if (this.#destroyed) {\n throw new Error(\"MapRegistry has already been destroyed.\");\n }\n if (this.#entries.has(mapId)) {\n throw new Error(`Map id '${mapId}' is not unique.`);\n }\n if (this.#modelCreationJobs.has(mapId)) {\n throw new Error(`A map with the id '${mapId}' is already under construction.`);\n }\n return await this.#createMapModel(mapId, () => Promise.resolve(options ?? {}));\n }\n\n /**\n * Given a raw OpenLayers map instance, returns the associated {@link MapModel} - or undefined\n * if the map is unknown to this registry.\n *\n * All OpenLayers maps created by this registry (e.g. via {@link MapConfigProvider} or {@link createMapModel}) have an associated map model.\n */\n getMapModelByRawInstance(olMap: OlMap): MapModel | undefined {\n return this.#modelsByOlMap.get(olMap);\n }\n\n // Wrapper method to ensure that in-progress construction of maps can be observed.\n #createMapModel(mapId: string, configProvider: () => Promise<MapConfig>): Promise<MapModel> {\n const creationJob = this.#modelCreationJobs.get(mapId);\n if (creationJob) {\n throw new Error(\"Internal error: a map model is already being created for this mapId\");\n }\n\n const modelPromise = this.#createMapModelImpl(mapId, configProvider)\n .then((mapModel) => {\n if (this.#destroyed) {\n mapModel.destroy();\n throw new Error(`MapRegistry has been destroyed.`);\n }\n\n const listener = onSync(mapModel.destroyed, () => {\n // Allow id reuse for dynamically created maps\n if (this.#isDynamic(mapId)) {\n const currentEntry = this.#entries.get(mapId);\n if (currentEntry === entry) {\n this.#entries.delete(mapId);\n }\n }\n });\n\n const entry: ModelJobResult = { kind: \"model\", model: mapModel, listener };\n this.#entries.set(mapId, entry);\n this.#modelCreationJobs.delete(mapId);\n this.#modelsByOlMap.set(mapModel.olMap, mapModel);\n return entry;\n })\n .catch((cause) => {\n const error = new Error(`Failed to construct map '${mapId}'`, { cause });\n const entry: ModelJobResult = { kind: \"error\", error };\n this.#modelCreationJobs.delete(mapId);\n if (!this.#isDynamic(mapId)) {\n // Don't store errors for dynamically created maps (the caller already got the error via promise).\n this.#entries.set(mapId, entry);\n }\n return entry;\n });\n this.#modelCreationJobs.set(mapId, modelPromise);\n return waitForResult(modelPromise);\n }\n\n async #createMapModelImpl(\n mapId: string,\n configProvider: () => Promise<MapConfig>\n ): Promise<MapModel> {\n LOG.info(`Creating map with id '${mapId}'`);\n const mapConfig = await configProvider();\n const mapModel = await createMapModel(mapId, mapConfig, this.#intl, this.#httpService);\n return mapModel;\n }\n\n #isDynamic(mapId: string): boolean {\n return !this.#configProviders.has(mapId);\n }\n}\n\nasync function waitForResult(job: Promise<ModelJobResult>): Promise<MapModel> {\n return unbox(await job);\n}\n\nfunction unbox(entry: ModelJobResult): MapModel {\n if (entry.kind === \"error\") {\n throw entry.error;\n }\n return entry.model;\n}\n"],"names":[],"mappings":";;;;;AAkBA,MAAM,GAAA,GAAM,aAAa,iBAAiB,CAAA;AAyDnC,MAAM,WAAA,CAA+B;AAAA,EAGxC,KAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EAEA,gBAAA,uBAAuB,GAAA,EAA+B;AAAA,EACtD,QAAA,uBAAe,GAAA,EAA4B;AAAA,EAC3C,kBAAA,uBAAyB,GAAA,EAAqC;AAAA,EAC9D,cAAA,uBAAqB,OAAA,EAAyB;AAAA,EAC9C,UAAA,GAAa,KAAA;AAAA,EAEb,WAAA,CAAY,EAAE,UAAA,EAAY,IAAA,EAAK,EAA+B;AAC1D,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,IAAA,IAAA,CAAK,eAAe,UAAA,CAAW,WAAA;AAC/B,IAAA,IAAA,CAAK,gBAAgB,UAAA,CAAW,YAAA;AAEhC,IAAA,MAAM,YAAY,UAAA,CAAW,SAAA;AAC7B,IAAA,KAAA,MAAW,YAAY,SAAA,EAAW;AAC9B,MAAA,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,QAAA,CAAS,KAAA,EAAO,QAAQ,CAAA;AAAA,IACtD;AAAA,EACJ;AAAA,EAEA,OAAA,GAAgB;AACZ,IAAA,IAAI,KAAK,UAAA,EAAY;AACjB,MAAA;AAAA,IACJ;AAEA,IAAA,KAAA,CAAM,MAAM;AACR,MAAA,GAAA,CAAI,MAAM,CAAA,iCAAA,CAAmC,CAAA;AAC7C,MAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,MAAA,IAAA,CAAK,QAAA,CAAS,OAAA,CAAQ,CAAC,KAAA,KAAU;AAC7B,QAAA,IAAI,KAAA,CAAM,SAAS,OAAA,EAAS;AACxB,UAAA,KAAA,CAAM,SAAS,OAAA,EAAQ;AACvB,UAAA,KAAA,CAAM,MAAM,OAAA,EAAQ;AAAA,QACxB;AAAA,MACJ,CAAC,CAAA;AACD,MAAA,IAAA,CAAK,SAAS,KAAA,EAAM;AACpB,MAAA,IAAA,CAAK,mBAAmB,KAAA,EAAM;AAAA,IAClC,CAAC,CAAA;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAY,KAAA,EAA8C;AAC5D,IAAA,IAAI,KAAK,UAAA,EAAY;AACjB,MAAA,MAAM,IAAI,MAAM,yCAAyC,CAAA;AAAA,IAC7D;AAEA,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,KAAK,CAAA;AACrC,IAAA,IAAI,KAAA,EAAO;AACP,MAAA,OAAO,MAAM,KAAK,CAAA;AAAA,IACtB;AAEA,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,kBAAA,CAAmB,GAAA,CAAI,KAAK,CAAA;AACrD,IAAA,IAAI,WAAA,EAAa;AACb,MAAA,OAAO,MAAM,cAAc,WAAW,CAAA;AAAA,IAC1C;AAEA,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,KAAK,CAAA;AAChD,IAAA,IAAI,CAAC,QAAA,EAAU;AACX,MAAA,GAAA,CAAI,KAAA,CAAM,CAAA,6CAAA,EAAgD,KAAK,CAAA,EAAA,CAAI,CAAA;AACnE,MAAA,OAAO,MAAA;AAAA,IACX;AAEA,IAAA,OAAO,MAAM,IAAA,CAAK,eAAA;AAAA,MAAgB,KAAA;AAAA,MAAO,MACrC,SAAS,YAAA,CAAa;AAAA,QAClB,cAAc,IAAA,CAAK;AAAA,OACtB;AAAA,KACL;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAe,KAAA,EAAkC;AACnD,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,WAAA,CAAY,KAAK,CAAA;AAC1C,IAAA,IAAI,CAAC,KAAA,EAAO;AACR,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,4CAAA,EAA+C,KAAK,CAAA,EAAA,CAAI,CAAA;AAAA,IAC5E;AACA,IAAA,OAAO,KAAA;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAAA,CAAe,KAAA,EAAe,OAAA,EAAwC;AACxE,IAAA,IAAI,KAAK,UAAA,EAAY;AACjB,MAAA,MAAM,IAAI,MAAM,yCAAyC,CAAA;AAAA,IAC7D;AACA,IAAA,IAAI,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,KAAK,CAAA,EAAG;AAC1B,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,QAAA,EAAW,KAAK,CAAA,gBAAA,CAAkB,CAAA;AAAA,IACtD;AACA,IAAA,IAAI,IAAA,CAAK,kBAAA,CAAmB,GAAA,CAAI,KAAK,CAAA,EAAG;AACpC,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mBAAA,EAAsB,KAAK,CAAA,gCAAA,CAAkC,CAAA;AAAA,IACjF;AACA,IAAA,OAAO,MAAM,IAAA,CAAK,eAAA,CAAgB,KAAA,EAAO,MAAM,QAAQ,OAAA,CAAQ,OAAA,IAAW,EAAE,CAAC,CAAA;AAAA,EACjF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,yBAAyB,KAAA,EAAoC;AACzD,IAAA,OAAO,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,KAAK,CAAA;AAAA,EACxC;AAAA;AAAA,EAGA,eAAA,CAAgB,OAAe,cAAA,EAA6D;AACxF,IAAA,MAAM,WAAA,GAAc,IAAA,CAAK,kBAAA,CAAmB,GAAA,CAAI,KAAK,CAAA;AACrD,IAAA,IAAI,WAAA,EAAa;AACb,MAAA,MAAM,IAAI,MAAM,qEAAqE,CAAA;AAAA,IACzF;AAEA,IAAA,MAAM,YAAA,GAAe,KAAK,mBAAA,CAAoB,KAAA,EAAO,cAAc,CAAA,CAC9D,IAAA,CAAK,CAAC,QAAA,KAAa;AAChB,MAAA,IAAI,KAAK,UAAA,EAAY;AACjB,QAAA,QAAA,CAAS,OAAA,EAAQ;AACjB,QAAA,MAAM,IAAI,MAAM,CAAA,+BAAA,CAAiC,CAAA;AAAA,MACrD;AAEA,MAAA,MAAM,QAAA,GAAW,MAAA,CAAO,QAAA,CAAS,SAAA,EAAW,MAAM;AAE9C,QAAA,IAAI,IAAA,CAAK,UAAA,CAAW,KAAK,CAAA,EAAG;AACxB,UAAA,MAAM,YAAA,GAAe,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,KAAK,CAAA;AAC5C,UAAA,IAAI,iBAAiB,KAAA,EAAO;AACxB,YAAA,IAAA,CAAK,QAAA,CAAS,OAAO,KAAK,CAAA;AAAA,UAC9B;AAAA,QACJ;AAAA,MACJ,CAAC,CAAA;AAED,MAAA,MAAM,QAAwB,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAO,UAAU,QAAA,EAAS;AACzE,MAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,KAAA,EAAO,KAAK,CAAA;AAC9B,MAAA,IAAA,CAAK,kBAAA,CAAmB,OAAO,KAAK,CAAA;AACpC,MAAA,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,QAAA,CAAS,KAAA,EAAO,QAAQ,CAAA;AAChD,MAAA,OAAO,KAAA;AAAA,IACX,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,KAAA,KAAU;AACd,MAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,CAAA,yBAAA,EAA4B,KAAK,CAAA,CAAA,CAAA,EAAK,EAAE,OAAO,CAAA;AACvE,MAAA,MAAM,KAAA,GAAwB,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAM;AACrD,MAAA,IAAA,CAAK,kBAAA,CAAmB,OAAO,KAAK,CAAA;AACpC,MAAA,IAAI,CAAC,IAAA,CAAK,UAAA,CAAW,KAAK,CAAA,EAAG;AAEzB,QAAA,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,KAAA,EAAO,KAAK,CAAA;AAAA,MAClC;AACA,MAAA,OAAO,KAAA;AAAA,IACX,CAAC,CAAA;AACL,IAAA,IAAA,CAAK,kBAAA,CAAmB,GAAA,CAAI,KAAA,EAAO,YAAY,CAAA;AAC/C,IAAA,OAAO,cAAc,YAAY,CAAA;AAAA,EACrC;AAAA,EAEA,MAAM,mBAAA,CACF,KAAA,EACA,cAAA,EACiB;AACjB,IAAA,GAAA,CAAI,IAAA,CAAK,CAAA,sBAAA,EAAyB,KAAK,CAAA,CAAA,CAAG,CAAA;AAC1C,IAAA,MAAM,SAAA,GAAY,MAAM,cAAA,EAAe;AACvC,IAAA,MAAM,QAAA,GAAW,MAAM,cAAA,CAAe,KAAA,EAAO,WAAW,IAAA,CAAK,KAAA,EAAO,KAAK,YAAY,CAAA;AACrF,IAAA,OAAO,QAAA;AAAA,EACX;AAAA,EAEA,WAAW,KAAA,EAAwB;AAC/B,IAAA,OAAO,CAAC,IAAA,CAAK,gBAAA,CAAiB,GAAA,CAAI,KAAK,CAAA;AAAA,EAC3C;AACJ;AAEA,eAAe,cAAc,GAAA,EAAiD;AAC1E,EAAA,OAAO,KAAA,CAAM,MAAM,GAAG,CAAA;AAC1B;AAEA,SAAS,MAAM,KAAA,EAAiC;AAC5C,EAAA,IAAI,KAAA,CAAM,SAAS,OAAA,EAAS;AACxB,IAAA,MAAM,KAAA,CAAM,KAAA;AAAA,EAChB;AACA,EAAA,OAAO,KAAA,CAAM,KAAA;AACjB;;;;"}