• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jumpinjackie / mapguide-react-layout / 15160422871

21 May 2025 11:00AM UTC coverage: 21.479% (-42.8%) from 64.24%
15160422871

Pull #1552

github

web-flow
Merge 3916e4b02 into 236e2ea07
Pull Request #1552: Feature/package updates 2505

840 of 1168 branches covered (71.92%)

11 of 151 new or added lines in 25 files covered. (7.28%)

1332 existing lines in 50 files now uncovered.

4794 of 22319 relevant lines covered (21.48%)

6.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.27
/src/api/builders/deArrayify.ts
1
/**
2
 * deArrayify.ts
3
 *
4
 * This module provides JSON sanitization of JSON responses from the mapagent
5
 *
6
 * Being a transformation of the XML form, and taking a lowest-common-denominator
7
 * approach to JSON conversion, the JSON responses from MapGuide are un-wieldy to
8
 * use from the client-side due to:
9
 *
10
 *  a) All properties being arrays
11
 *  b) All property values being strings
12
 *
13
 * These functions help "clean" those responses to be of the form we expect (and prefer)
14
 */
15
import { MgError } from "../error";
1✔
16
import { ActiveSelectedFeature } from "../common";
17
import { RuleInfo, FeatureStyleInfo, ScaleRangeInfo, FeatureSourceInfo, MapLayer, MapGroup, CoordinateSystemType, EnvCoordinate, Envelope, RuntimeMap } from '../contracts/runtime-map';
18
import { FeatureSetClass, FeatureSetLayer, FeatureSet, SelectionImage, FeatureProperty, SelectedFeature, LayerPropertyMetadata, LayerMetadata, SelectedLayer, SelectedFeatureSet, QueryMapFeaturesResponse } from '../contracts/query';
19
import { WebLayoutMap, WebLayoutControl, WebLayoutInfoPane, MapView, TaskButton, WebLayoutTaskBar, UIItem, WebLayoutTaskPane, CommandUIItem, FlyoutUIItem, ResultColumnSet, ResultColumn, LayerSet, ParameterPair, CommandDef, BasicCommandDef, InvokeScriptCommandDef, InvokeURLCommandDef, SearchCommandDef, WebLayoutCommandSet, WebLayout, WebLayoutToolbar, WebLayoutContextMenu, WebLayoutStatusBar, WebLayoutZoomControl } from '../contracts/weblayout';
20
import { MapSetGroup, MapInitialView, MapConfiguration, MapSet, ContainerItem, FlyoutItem, WidgetItem, ContainerDefinition, Widget, UIWidget, MapWidget, WidgetSet, ApplicationDefinition } from '../contracts/fusion';
21
import { MDF_INFINITY } from '../../constants';
1✔
22
import { MapDefinition, MapDefinitionLayerGroup, MapDefinitionLayer as MdfLayer, TileSetSource } from "../contracts/map-definition";
23
import { BaseMapLayer, BaseMapLayerGroup, TileSetDefinition, TileStoreParameters } from "../contracts/tile-set-definition";
24
import { SiteVersionResponse } from '../contracts/common';
25

26
type ElementType = "string" | "boolean" | "int" | "float";
27

28
function buildPropertyGetter<T>() {
823✔
29
    return (el: any, name: keyof T, type: ElementType = "string") => {
823✔
30
        return tryGetAsProperty<T>(el, name, type);
5,628✔
31
    }
5,628✔
32
}
823✔
33

34
function tryGetAsProperty<T>(el: any, name: keyof T, type: ElementType = "string"): any {
5,628✔
35
    if (!el[name]) {
5,628✔
36
        return null;
536✔
37
    } else if (el[name].length === 1) {
5,628✔
38
        const val: string = el[name][0];
5,092✔
39
        switch (type) {
5,092✔
40
            case "int":
5,092✔
41
                return parseInt(val, 10);
121✔
42
            case "float":
5,092✔
43
                return parseFloat(val);
133✔
44
            case "boolean":
5,092✔
45
                return val.toLowerCase() === "true";
744✔
46
            default:
5,092✔
47
                return val;
4,094✔
48
        }
5,092✔
49
    }
5,092✔
50
}
5,628✔
51

52
function deArrayifyRules(rules: any[]): RuleInfo[] {
46✔
53
    const getter = buildPropertyGetter<RuleInfo>();
46✔
54
    return rules.map(r => {
46✔
55
        const rule: RuleInfo = {
101✔
56
            LegendLabel: getter(r, "LegendLabel"),
101✔
57
            Filter: getter(r, "Filter"),
101✔
58
            Icon: getter(r, "Icon")
101✔
59
        };
101✔
60
        return rule;
101✔
61
    });
46✔
62
}
46✔
63

64
function deArrayifyFeatureStyles(fts: any[]): FeatureStyleInfo[] {
46✔
65
    if (!fts) {
46!
66
        return [];
×
UNCOV
67
    }
×
68
    const getter = buildPropertyGetter<FeatureStyleInfo>();
46✔
69
    return fts.map(ft => {
46✔
70
        const featureStyle: FeatureStyleInfo = {
46✔
71
            Type: getter(ft, "Type", "int"),
46✔
72
            Rule: deArrayifyRules(ft.Rule)
46✔
73
        };
46✔
74
        return featureStyle;
46✔
75
    });
46✔
76
}
46✔
77

78
function deArrayifyScaleRanges(scales: any[]): ScaleRangeInfo[] {
44✔
79
    if (!scales) { //Happens with raster layers (this is probably a bug in CREATERUNTIMEMAP)
44!
80
        const defaultRange: ScaleRangeInfo = {
×
UNCOV
81
            MinScale: 0,
×
UNCOV
82
            MaxScale: MDF_INFINITY,
×
UNCOV
83
            FeatureStyle: []
×
UNCOV
84
        };
×
85
        return [defaultRange];
×
UNCOV
86
    }
×
87
    
88
    const getter = buildPropertyGetter<ScaleRangeInfo>();
44✔
89
    return scales.map(sc => {
44✔
90
        const scale: ScaleRangeInfo = {
46✔
91
            MinScale: getter(sc, "MinScale", "float"),
46✔
92
            MaxScale: getter(sc, "MaxScale", "float"),
46✔
93
            FeatureStyle: deArrayifyFeatureStyles(sc.FeatureStyle)
46✔
94
        };
46✔
95
        return scale;
46✔
96
    });
44✔
97
}
44✔
98

99
function deArrayifyFeatureSourceInfo(fs: any[]): FeatureSourceInfo | undefined {
44✔
100
    if (!fs || fs.length !== 1) {
44!
101
        return undefined;
×
UNCOV
102
    }
×
103
    const getter = buildPropertyGetter<FeatureSourceInfo>();
44✔
104
    return {
44✔
105
        ResourceId: getter(fs[0], "ResourceId"),
44✔
106
        ClassName: getter(fs[0], "ClassName"),
44✔
107
        Geometry: getter(fs[0], "Geometry")
44✔
108
    };
44✔
109
}
44✔
110

111
function deArrayifyLayers(layers: any[]): MapLayer[] {
3✔
112
    if (!layers)
3✔
113
        return layers;
3!
114

115
    const getter = buildPropertyGetter<MapLayer>();
3✔
116
    return layers.map(lyr => {
3✔
117
        const layer: MapLayer = {
44✔
118
            Type: getter(lyr, "Type", "int"),
44✔
119
            Selectable: getter(lyr, "Selectable", "boolean"),
44✔
120
            LayerDefinition: getter(lyr, "LayerDefinition"),
44✔
121
            Name: getter(lyr, "Name"),
44✔
122
            LegendLabel: getter(lyr, "LegendLabel"),
44✔
123
            ObjectId: getter(lyr, "ObjectId"),
44✔
124
            ParentId: getter(lyr, "ParentId"),
44✔
125
            DisplayInLegend: getter(lyr, "DisplayInLegend", "boolean"),
44✔
126
            ExpandInLegend: getter(lyr, "ExpandInLegend", "boolean"),
44✔
127
            Visible: getter(lyr, "Visible", "boolean"),
44✔
128
            ActuallyVisible: getter(lyr, "ActuallyVisible", "boolean"),
44✔
129
            FeatureSource: deArrayifyFeatureSourceInfo(lyr.FeatureSource),
44✔
130
            ScaleRange: deArrayifyScaleRanges(lyr.ScaleRange)
44✔
131
        };
44✔
132
        //This is either a raster or drawing layer, in this case disregard the
133
        //selectability flag (and set it to false). This is to prevent false positive
134
        //errors trying to do tooltip/selections against raster/drawing layers
135
        if (!lyr.ScaleRange) {
44!
136
            layer.Selectable = false;
×
UNCOV
137
        }
×
138
        return layer;
44✔
139
    });
3✔
140
}
3✔
141

142
function deArrayifyGroups(groups: any[]): MapGroup[] | undefined {
3✔
143
    if (!groups)
3✔
144
        return undefined;
3!
145

146
    const getter = buildPropertyGetter<MapGroup>();
3✔
147
    return groups.map(grp => {
3✔
148
        const group: MapGroup = {
16✔
149
            Type: getter(grp, "Type", "int"),
16✔
150
            Name: getter(grp, "Name"),
16✔
151
            LegendLabel: getter(grp, "LegendLabel"),
16✔
152
            ObjectId: getter(grp, "ObjectId"),
16✔
153
            ParentId: getter(grp, "ParentId"),
16✔
154
            DisplayInLegend: getter(grp, "DisplayInLegend", "boolean"),
16✔
155
            ExpandInLegend: getter(grp, "ExpandInLegend", "boolean"),
16✔
156
            Visible: getter(grp, "Visible", "boolean"),
16✔
157
            ActuallyVisible: getter(grp, "ActuallyVisible", "boolean")
16✔
158
        };
16✔
159
        return group;
16✔
160
    });
3✔
161
}
3✔
162

163
function deArrayifyCoordinateSystem(cs: any[]): CoordinateSystemType {
3✔
164
    if (!cs || cs.length !== 1) {
3!
165
        throw new MgError("Malformed input. Expected CoordinateSystem element");
×
UNCOV
166
    }
×
167
    const getter = buildPropertyGetter<CoordinateSystemType>();
3✔
168
    const res: CoordinateSystemType = {
3✔
169
        Wkt: getter(cs[0], "Wkt"),
3✔
170
        MentorCode: getter(cs[0], "MentorCode"),
3✔
171
        EpsgCode: getter(cs[0], "EpsgCode"),
3✔
172
        MetersPerUnit: getter(cs[0], "MetersPerUnit", "float")
3✔
173
    };
3✔
174
    return res;
3✔
175
}
3✔
176

177
function deArrayifyCoordinate(coord: any[]): EnvCoordinate {
6✔
178
    if (!coord || coord.length !== 1) {
6!
179
        throw new MgError("Malformed input. Expected coordinate array");
×
UNCOV
180
    }
×
181
    const getter = buildPropertyGetter<EnvCoordinate>();
6✔
182
    return {
6✔
183
        X: getter(coord[0], "X", "float"),
6✔
184
        Y: getter(coord[0], "Y", "float")
6✔
185
    };
6✔
186
}
6✔
187

188
function deArrayifyExtents(extents: any[]): Envelope {
3✔
189
    if (!extents || extents.length !== 1) {
3!
190
        throw new MgError("Malformed input. Expected extent element");
×
UNCOV
191
    }
×
192
    const env: Envelope = {
3✔
193
        LowerLeftCoordinate: deArrayifyCoordinate(extents[0].LowerLeftCoordinate),
3✔
194
        UpperRightCoordinate: deArrayifyCoordinate(extents[0].UpperRightCoordinate)
3✔
195
    };
3✔
196
    return env;
3✔
197
}
3✔
198

199
function deArrayifyFiniteDisplayScales(fds: any[]): number[] | undefined {
3✔
200
    if (!fds)
3✔
201
        return undefined;
3!
202

203
    return fds.map(parseFloat);
×
UNCOV
204
}
×
205

206
function deArrayifyRuntimeMap(json: any): RuntimeMap {
3✔
207
    const root = json;
3✔
208
    const getter = buildPropertyGetter<RuntimeMap>();
3✔
209
    const rtMap: RuntimeMap = {
3✔
210
        SessionId: getter(root, "SessionId"),
3✔
211
        SiteVersion: getter(root, "SiteVersion"),
3✔
212
        Name: getter(root, "Name"),
3✔
213
        MapDefinition: getter(root, "MapDefinition"),
3✔
214
        TileSetDefinition: getter(root, "TileSetDefinition"),
3✔
215
        TileWidth: getter(root, "TileWidth", "int"),
3✔
216
        TileHeight: getter(root, "TileHeight", "int"),
3✔
217
        BackgroundColor: getter(root, "BackgroundColor"),
3✔
218
        DisplayDpi: getter(root, "DisplayDpi", "int"),
3✔
219
        IconMimeType: getter(root, "IconMimeType"),
3✔
220
        CoordinateSystem: deArrayifyCoordinateSystem(root.CoordinateSystem),
3✔
221
        Extents: deArrayifyExtents(root.Extents),
3✔
222
        Group: deArrayifyGroups(root.Group),
3✔
223
        Layer: deArrayifyLayers(root.Layer),
3✔
224
        FiniteDisplayScale: deArrayifyFiniteDisplayScales(root.FiniteDisplayScale),
3✔
225
        TilePixelRatio: getter(root, "TilePixelRatio", "int"),
3✔
226
        TileSetProvider: getter(root, "TileSetProvider")
3✔
227
    };
3✔
228
    return rtMap;
3✔
229
}
3✔
230

231
function deArrayifyFeatureSetClass(json: any): FeatureSetClass {
1✔
232
    const root = json;
1✔
233
    const getter = buildPropertyGetter<FeatureSetClass>();
1✔
234
    if (root.length != 1) {
1!
235
        throw new MgError("Malformed input. Expected Class element");
×
UNCOV
236
    }
×
237
    const cls = {
1✔
238
        "@id": getter(root[0], "@id"),
1✔
239
        ID: root[0].ID
1✔
240
    };
1✔
241
    return cls;
1✔
242
}
1✔
243

244
function deArrayifyFeatureSetLayers(json: any[]): FeatureSetLayer[] {
1✔
245
    const getter = buildPropertyGetter<FeatureSetLayer>();
1✔
246
    return (json || []).map(root => {
1!
247
        const layer = {
1✔
248
            "@id": getter(root, "@id"),
1✔
249
            "@name": getter(root, "@name"),
1✔
250
            Class: deArrayifyFeatureSetClass(root.Class)
1✔
251
        };
1✔
252
        return layer;
1✔
253
    });
1✔
254
}
1✔
255

256
function deArrayifyFeatureSet(json: any): FeatureSet | undefined {
1✔
257
    const root = json;
1✔
258
    if (root == null || root.length != 1) {
1!
259
        return undefined;
×
UNCOV
260
    }
×
261
    const fs = {
1✔
262
        Layer: deArrayifyFeatureSetLayers(root[0].Layer)
1✔
263
    };
1✔
264
    return fs;
1✔
265
}
1✔
266

267
function deArrayifyInlineSelectionImage(json: any): SelectionImage | undefined {
1✔
268
    const root = json;
1✔
269
    if (root == null || root.length != 1) {
1!
270
        return undefined;
1✔
271
    }
1!
272
    const getter = buildPropertyGetter<SelectionImage>();
×
273
    const img = {
×
UNCOV
274
        MimeType: getter(root[0], "MimeType"),
×
UNCOV
275
        Content: getter(root[0], "Content")
×
UNCOV
276
    };
×
277
    return img;
×
UNCOV
278
}
×
279

280
function deArrayifyFeatureProperties(json: any[]): FeatureProperty[] {
21✔
281
    const getter = buildPropertyGetter<FeatureProperty>();
21✔
282
    return (json || []).map(root => {
21!
283
        const prop = {
210✔
284
            Name: getter(root, "Name"),
210✔
285
            Value: getter(root, "Value")
210✔
286
        };
210✔
287
        return prop;
210✔
288
    });
21✔
289
}
21✔
290

291
function deArrayifyFeatures(json: any[]): SelectedFeature[] {
1✔
292
    const getter = buildPropertyGetter<SelectedFeature>();
1✔
293
    return (json || []).map(root => {
1!
294
        const feat = {
21✔
295
            Bounds: getter(root, "Bounds"),
21✔
296
            Property: deArrayifyFeatureProperties(root.Property),
21✔
297
            SelectionKey: getter(root, "SelectionKey")
21✔
298
        };
21✔
299
        return feat;
21✔
300
    });
1✔
301
}
1✔
302

303
function deArrayifyLayerMetadataProperties(json: any[]): LayerPropertyMetadata[] {
1✔
304
    const getter = buildPropertyGetter<LayerPropertyMetadata>();
1✔
305
    return (json || []).map(root => {
1!
306
        const prop = {
10✔
307
            DisplayName: getter(root, "DisplayName"),
10✔
308
            Name: getter(root, "Name"),
10✔
309
            Type: getter(root, "Type", "int")
10✔
310
        };
10✔
311
        return prop;
10✔
312
    });
1✔
313
}
1✔
314

315
function deArrayifyLayerMetadata(json: any): LayerMetadata | undefined {
1✔
316
    const root = json;
1✔
317
    //NOTE: root could be null if the layer selected has no properties beyond id/geom
318
    if (root == null || root.length != 1) {
1!
319
        return undefined;
×
UNCOV
320
    }
×
321
    const meta = {
1✔
322
        Property: deArrayifyLayerMetadataProperties(root[0].Property)
1✔
323
    };
1✔
324
    return meta;
1✔
325
}
1✔
326

327
function deArrayifySelectedLayer(json: any[]): SelectedLayer[] {
1✔
328
    const getter = buildPropertyGetter<SelectedLayer>();
1✔
329
    return (json || []).map(root => {
1!
330
        const layer = {
1✔
331
            "@id": getter(root, "@id"),
1✔
332
            "@name": getter(root, "@name"),
1✔
333
            Feature: deArrayifyFeatures(root.Feature),
1✔
334
            LayerMetadata: deArrayifyLayerMetadata(root.LayerMetadata)
1✔
335
        };
1✔
336
        return layer;
1✔
337
    });
1✔
338
}
1✔
339

340
function deArrayifySelectedFeatures(json: any): SelectedFeatureSet | undefined {
1✔
341
    const root = json;
1✔
342
    if (root == null || root.length != 1) {
1!
343
        return undefined;
×
UNCOV
344
    }
×
345
    const sf = {
1✔
346
        SelectedLayer: deArrayifySelectedLayer(root[0].SelectedLayer)
1✔
347
    };
1✔
348
    return sf;
1✔
349
}
1✔
350

351
function deArrayifyFeatureInformation(json: any): QueryMapFeaturesResponse {
1✔
352
    const root = json;
1✔
353
    const getter = buildPropertyGetter<QueryMapFeaturesResponse>();
1✔
354
    const resp = {
1✔
355
        FeatureSet: deArrayifyFeatureSet(root.FeatureSet),
1✔
356
        Hyperlink: getter(root, "Hyperlink"),
1✔
357
        InlineSelectionImage: deArrayifyInlineSelectionImage(root.InlineSelectionImage),
1✔
358
        SelectedFeatures: deArrayifySelectedFeatures(root.SelectedFeatures),
1✔
359
        Tooltip: getter(root, "Tooltip")
1✔
360
    };
1✔
361
    return resp;
1✔
362
}
1✔
363

364
function deArrayifyWebLayoutControl<T extends WebLayoutControl>(json: any): T {
2✔
365
    const root = json;
2✔
366
    if (root == null || root.length != 1) {
2!
367
        throw new MgError("Malformed input. Expected control element");
×
UNCOV
368
    }
×
369
    const getter = buildPropertyGetter<T>();
2✔
370
    const control: any = {
2✔
371
        Visible: getter(root[0], "Visible", "boolean")
2✔
372
    };
2✔
373
    return control;
2✔
374
}
2✔
375

376
function deArrayifyWebLayoutInfoPane(json: any): WebLayoutInfoPane {
1✔
377
    const root = json;
1✔
378
    if (root == null || root.length != 1) {
1!
379
        throw new MgError("Malformed input. Expected InformationPane element");
×
UNCOV
380
    }
×
381
    const getter = buildPropertyGetter<WebLayoutInfoPane>();
1✔
382
    const infoPane = {
1✔
383
        Visible: getter(root[0], "Visible", "boolean"),
1✔
384
        Width: getter(root[0], "Width", "int"),
1✔
385
        LegendVisible: getter(root[0], "LegendVisible", "boolean"),
1✔
386
        PropertiesVisible: getter(root[0], "PropertiesVisible", "boolean")
1✔
387
    };
1✔
388
    return infoPane;
1✔
389
}
1✔
390

391
function deArrayifyWebLayoutInitialView(json: any): MapView | undefined {
1✔
392
    const root = json;
1✔
393
    if (root == null || root.length != 1) {
1!
394
        return undefined;
1✔
395
    }
1!
396
    const getter = buildPropertyGetter<MapView>();
×
397
    const view = {
×
UNCOV
398
        CenterX: getter(root[0], "CenterX", "float"),
×
UNCOV
399
        CenterY: getter(root[0], "CenterY", "float"),
×
UNCOV
400
        Scale: getter(root[0], "Scale", "float")
×
UNCOV
401
    };
×
402
    return view;
×
UNCOV
403
}
×
404

405
function deArrayifyWebLayoutMap(json: any): WebLayoutMap {
1✔
406
    const root = json;
1✔
407
    if (root == null || root.length != 1) {
1!
408
        throw new MgError("Malformed input. Expected Map element");
×
UNCOV
409
    }
×
410
    const getter = buildPropertyGetter<WebLayoutMap>();
1✔
411
    const map = {
1✔
412
        ResourceId: getter(root[0], "ResourceId"),
1✔
413
        InitialView: deArrayifyWebLayoutInitialView(root[0].InitialView),
1✔
414
        HyperlinkTarget: getter(root[0], "HyperlinkTarget"),
1✔
415
        HyperlinkTargetFrame: getter(root[0], "HyperlinkTargetFrame")
1✔
416
    };
1✔
417
    return map;
1✔
418
}
1✔
419

420
function deArrayifyTaskButton(json: any): TaskButton {
4✔
421
    const root = json;
4✔
422
    if (root == null || root.length != 1) {
4!
423
        throw new MgError("Malformed input. Expected TaskButton element");
×
UNCOV
424
    }
×
425
    const getter = buildPropertyGetter<TaskButton>();
4✔
426
    const button = {
4✔
427
        Name: getter(root[0], "Name"),
4✔
428
        Tooltip: getter(root[0], "Tooltip"),
4✔
429
        Description: getter(root[0], "Description"),
4✔
430
        ImageURL: getter(root[0], "ImageURL"),
4✔
431
        DisabledImageURL: getter(root[0], "DisabledImageURL")
4✔
432
    };
4✔
433
    return button;
4✔
434
}
4✔
435

436
function deArrayifyWebLayoutTaskBar(json: any): WebLayoutTaskBar {
1✔
437
    const root = json;
1✔
438
    if (root == null || root.length != 1) {
1!
439
        throw new MgError("Malformed input. Expected TaskBar element");
×
UNCOV
440
    }
×
441
    const getter = buildPropertyGetter<WebLayoutTaskBar>();
1✔
442
    const taskbar = {
1✔
443
        Visible: getter(root[0], "Visible", "boolean"),
1✔
444
        Home: deArrayifyTaskButton(root[0].Home),
1✔
445
        Forward: deArrayifyTaskButton(root[0].Forward),
1✔
446
        Back: deArrayifyTaskButton(root[0].Back),
1✔
447
        Tasks: deArrayifyTaskButton(root[0].Tasks),
1✔
448
        MenuButton: [] as UIItem[]
1✔
449
    };
1✔
450
    if (root[0].MenuButton) {
1✔
451
        for (const mb of root[0].MenuButton) {
1✔
452
            taskbar.MenuButton.push(deArrayifyUIItem(mb));
8✔
453
        }
8✔
454
    }
1✔
455
    return taskbar;
1✔
456
}
1✔
457

458
function deArrayifyWebLayoutTaskPane(json: any): WebLayoutTaskPane {
1✔
459
    const root = json;
1✔
460
    if (root == null || root.length != 1) {
1!
461
        throw new MgError("Malformed input. Expected TaskPane element");
×
UNCOV
462
    }
×
463
    const getter = buildPropertyGetter<WebLayoutTaskPane>();
1✔
464
    const taskPane = {
1✔
465
        Visible: getter(root[0], "Visible", "boolean"),
1✔
466
        InitialTask: getter(root[0], "InitialTask"),
1✔
467
        Width: getter(root[0], "Width", "int"),
1✔
468
        TaskBar: deArrayifyWebLayoutTaskBar(root[0].TaskBar)
1✔
469
    };
1✔
470
    return taskPane;
1✔
471
}
1✔
472

473
function deArrayifyUIItem(json: any): UIItem {
58✔
474
    const root = json;
58✔
475
    const getter = buildPropertyGetter<UIItem & CommandUIItem & FlyoutUIItem>();
58✔
476
    const func: string = getter(root, "Function");
58✔
477
    //Wouldn't it be nice if we could incrementally build up a union type that then becomes a specific
478
    //type once certain properties are set?
479
    //
480
    //Well, that's currently not possible. So we have to resort to "any"
481
    const item: any = {
58✔
482
        Function: func
58✔
483
    };
58✔
484
    switch (func) {
58✔
485
        case "Command":
58✔
486
            item.Command = getter(root, "Command");
43✔
487
            break;
43✔
488
        case "Flyout":
58✔
489
            item.Label = getter(root, "Label");
3✔
490
            item.Tooltip = getter(root, "Tooltip");
3✔
491
            item.Description = getter(root, "Description");
3✔
492
            item.ImageURL = getter(root, "ImageURL");
3✔
493
            item.DisabledImageURL = getter(root, "DisabledImageURL");
3✔
494
            item.SubItem = [];
3✔
495
            for (const si of root.SubItem) {
3✔
496
                item.SubItem.push(deArrayifyUIItem(si));
11✔
497
            }
11✔
498
            break;
3✔
499
    }
58✔
500
    return item;
58✔
501
}
58✔
502

503
function deArrayifyItemContainer<T extends WebLayoutControl>(json: any, name: string): T {
2✔
504
    const root = json;
2✔
505
    if (root == null || root.length != 1) {
2!
506
        throw new MgError("Malformed input. Expected container element");
×
UNCOV
507
    }
×
508
    const getter = buildPropertyGetter<T>();
2✔
509
    const container: any = {};
2✔
510
    container[name] = [];
2✔
511
    for (const item of root[0][name]) {
2✔
512
        container[name].push(deArrayifyUIItem(item));
39✔
513
    }
39✔
514
    if (typeof (root[0].Visible) != 'undefined') {
2✔
515
        container.Visible = getter(root[0], "Visible", "boolean");
2✔
516
    }
2✔
517
    return container;
2✔
518
}
2✔
519

UNCOV
520
function deArrayifyWebLayoutSearchResultColumnSet(json: any): ResultColumnSet {
×
521
    const root = json;
×
522
    if (root == null || root.length != 1) {
×
523
        throw new MgError("Malformed input. Expected ResultColumns element");
×
UNCOV
524
    }
×
525
    const getter = buildPropertyGetter<ResultColumn>();
×
526
    const res = {
×
UNCOV
527
        Column: [] as ResultColumn[]
×
UNCOV
528
    };
×
529
    for (const col of root[0].Column) {
×
530
        res.Column.push({
×
UNCOV
531
            Name: getter(col, "Name"),
×
UNCOV
532
            Property: getter(col, "Property")
×
UNCOV
533
        });
×
UNCOV
534
    }
×
535
    return res;
×
UNCOV
536
}
×
537

538
function deArrayifyWebLayoutInvokeURLLayerSet(json: any): LayerSet | undefined {
5✔
539
    const root = json;
5✔
540
    if (root == null || root.length != 1) {
5!
541
        return undefined;
5✔
542
    }
5!
543
    const layerset = {
×
UNCOV
544
        Layer: root[0].Layer
×
UNCOV
545
    };
×
546
    return layerset;
×
UNCOV
547
}
×
548

549
function deArrayifyWebLayoutParameterPairs(json: any): ParameterPair[] {
5✔
550
    const root = json;
5✔
551
    const pairs = [] as ParameterPair[]
5✔
552
    if (!root) {
5✔
553
        return pairs;
5✔
554
    }
5!
555
    const getter = buildPropertyGetter<ParameterPair>();
×
556
    for (const kvp of root) {
×
557
        pairs.push({
×
UNCOV
558
            Key: getter(kvp, "Key"),
×
UNCOV
559
            Value: getter(kvp, "Value")
×
UNCOV
560
        });
×
UNCOV
561
    }
×
562
    return pairs;
×
UNCOV
563
}
×
564

565
function deArrayifyCommand(json: any): CommandDef {
33✔
566
    const root = json;
33✔
567
    const getter = buildPropertyGetter<CommandDef & BasicCommandDef & InvokeScriptCommandDef & InvokeURLCommandDef & SearchCommandDef>();
33✔
568
    const cmd: any = {
33✔
569
        "@xsi:type": getter(root, "@xsi:type"),
33✔
570
        Name: getter(root, "Name"),
33✔
571
        Label: getter(root, "Label"),
33✔
572
        Tooltip: getter(root, "Tooltip"),
33✔
573
        Description: getter(root, "Description"),
33✔
574
        ImageURL: getter(root, "ImageURL"),
33✔
575
        DisabledImageURL: getter(root, "DisabledImageURL"),
33✔
576
        TargetViewer: getter(root, "TargetViewer")
33✔
577
    };
33✔
578
    //Basic
579
    if (typeof (root.Action) != 'undefined') {
33✔
580
        cmd.Action = getter(root, "Action");
21✔
581
    }
21✔
582
    //Targeted
583
    if (typeof (root.Target) != 'undefined') {
33✔
584
        cmd.Target = getter(root, "Target");
11✔
585
    }
11✔
586
    if (typeof (root.TargetFrame) != 'undefined') {
33!
587
        cmd.TargetFrame = getter(root, "TargetFrame");
×
UNCOV
588
    }
×
589
    //Search
590
    if (typeof (root.Layer) != 'undefined') {
33!
591
        cmd.Layer = getter(root, "Layer");
×
592
        cmd.Prompt = getter(root, "Prompt");
×
593
        cmd.ResultColumns = deArrayifyWebLayoutSearchResultColumnSet(root.ResultColumns);
×
594
        cmd.Filter = getter(root, "Filter");
×
595
        cmd.MatchLimit = getter(root, "MatchLimit", "int");
×
UNCOV
596
    }
×
597
    //InvokeURL | Help
598
    if (typeof (root.URL) != 'undefined') {
33✔
599
        cmd.URL = getter(root, "URL");
5✔
600
    }
5✔
601
    if (typeof (root.DisableIfSelectionEmpty) != 'undefined') {
33✔
602
        cmd.LayerSet = deArrayifyWebLayoutInvokeURLLayerSet(root.LayerSet);
5✔
603
        cmd.AdditionalParameter = deArrayifyWebLayoutParameterPairs(root.AdditionalParameter);
5✔
604
        cmd.DisableIfSelectionEmpty = getter(root, "DisableIfSelectionEmpty", "boolean");
5✔
605
    }
5✔
606
    //InvokeScript
607
    if (typeof (root.Script) != 'undefined') {
33!
608
        cmd.Script = getter(root, "Script");
×
UNCOV
609
    }
×
610
    return cmd;
33✔
611
}
33✔
612

613
function deArrayifyWebLayoutCommandSet(json: any): WebLayoutCommandSet {
1✔
614
    const root = json;
1✔
615
    if (root == null || root.length != 1) {
1!
616
        throw new MgError("Malformed input. Expected CommandSet element");
×
UNCOV
617
    }
×
618
    const set = {
1✔
619
        Command: [] as CommandDef[]
1✔
620
    };
1✔
621
    if (root[0].Command) {
1✔
622
        for (const cmd of root[0].Command) {
1✔
623
            set.Command.push(deArrayifyCommand(cmd));
33✔
624
        }
33✔
625
    }
1✔
626
    return set;
1✔
627
}
1✔
628

629
function deArrayifyWebLayout(json: any): WebLayout {
1✔
630
    const root = json;
1✔
631
    const getter = buildPropertyGetter<WebLayout>();
1✔
632
    const resp = {
1✔
633
        Title: getter(root, "Title"),
1✔
634
        Map: deArrayifyWebLayoutMap(root.Map),
1✔
635
        EnablePingServer: getter(root, "EnablePingServer", "boolean"),
1✔
636
        SelectionColor: getter(root, "SelectionColor"),
1✔
637
        PointSelectionBuffer: getter(root, "PointSelectionBuffer", "int"),
1✔
638
        MapImageFormat: getter(root, "MapImageFormat"),
1✔
639
        SelectionImageFormat: getter(root, "SelectionImageFormat"),
1✔
640
        StartupScript: getter(root, "StartupScript"),
1✔
641
        ToolBar: deArrayifyItemContainer<WebLayoutToolbar>(root.ToolBar, "Button"),
1✔
642
        InformationPane: deArrayifyWebLayoutInfoPane(root.InformationPane),
1✔
643
        ContextMenu: deArrayifyItemContainer<WebLayoutContextMenu>(root.ContextMenu, "MenuItem"),
1✔
644
        TaskPane: deArrayifyWebLayoutTaskPane(root.TaskPane),
1✔
645
        StatusBar: deArrayifyWebLayoutControl<WebLayoutStatusBar>(root.StatusBar),
1✔
646
        ZoomControl: deArrayifyWebLayoutControl<WebLayoutZoomControl>(root.ZoomControl),
1✔
647
        CommandSet: deArrayifyWebLayoutCommandSet(root.CommandSet)
1✔
648
    };
1✔
649
    return resp;
1✔
650
}
1✔
651

652
function deArrayifyMapGroup(json: any): MapSetGroup {
12✔
653
    const root = json;
12✔
654
    if (root == null) {
12!
655
        throw new MgError("Malformed input. Expected MapGroup element");
×
UNCOV
656
    }
×
657
    const getter = buildPropertyGetter<MapSetGroup & MapInitialView & MapConfiguration>();
12✔
658
    const mapGroup: MapSetGroup = {
12✔
659
        "@id": getter(root, "@id", "string"),
12✔
660
        InitialView: undefined,
12✔
661
        Map: [] as MapConfiguration[]
12✔
662
    };
12✔
663
    if (root.InitialView) {
12✔
664
        const iview = root.InitialView[0];
2✔
665
        mapGroup.InitialView = {
2✔
666
            CenterX: getter(iview, "CenterX", "float"),
2✔
667
            CenterY: getter(iview, "CenterY", "float"),
2✔
668
            Scale: getter(iview, "Scale", "float")
2✔
669
        };
2✔
670
    }
2✔
671
    if (root.Map) {
12✔
672
        for (const m of root.Map) {
12✔
673
            mapGroup.Map.push({
22✔
674
                Type: getter(m, "Type", "string"),
22✔
675
                //SingleTile: getter(m, "SingleTile", "boolean"),
676
                Extension: deArrayifyExtension(m.Extension)
22✔
677
            });
22✔
678
        }
22✔
679
    }
12✔
680
    return mapGroup;
12✔
681
}
12✔
682

683
function deArrayifyMapSet(json: any): MapSet | undefined {
3✔
684
    const root = json;
3✔
685
    if (root == null || root.length != 1) {
3!
686
        throw new MgError("Malformed input. Expected MapSet element");
×
UNCOV
687
    }
×
688
    const set = {
3✔
689
        MapGroup: [] as MapSetGroup[]
3✔
690
    };
3✔
691
    if (root[0].MapGroup) {
3✔
692
        for (const map of root[0].MapGroup) {
3✔
693
            set.MapGroup.push(deArrayifyMapGroup(map));
12✔
694
        }
12✔
695
    }
3✔
696
    return set;
3✔
697
}
3✔
698

699
function deArrayifyContainerItems(json: any[]): ContainerItem[] {
33✔
700
    const items = [] as ContainerItem[];
33✔
701
    const getter = buildPropertyGetter<ContainerItem & FlyoutItem & WidgetItem>();
33✔
702
    if (json && json.length) {
33✔
703
        for (const i of json) {
28✔
704
            const func = getter(i, "Function", "string");
256✔
705
            switch (func) {
256✔
706
                case "Separator":
256✔
707
                    items.push({
25✔
708
                        Function: "Separator"
25✔
709
                    });
25✔
710
                    break;
25✔
711
                case "Widget":
256✔
712
                    items.push({
219✔
713
                        Function: "Widget",
219✔
714
                        Widget: getter(i, "Widget", "string")
219✔
715
                    })
219✔
716
                    break;
219✔
717
                case "Flyout":
256✔
718
                    items.push({
12✔
719
                        Function: "Flyout",
12✔
720
                        Label: getter(i, "Label", "string"),
12✔
721
                        Tooltip: getter(i, "Tooltip", "string"),
12✔
722
                        ImageUrl: getter(i, "ImageUrl", "string"),
12✔
723
                        ImageClass: getter(i, "ImageClass", "string"),
12✔
724
                        Item: deArrayifyContainerItems(i.Item || [])
12✔
725
                    })
12✔
726
                    break;
12✔
727
            }
256✔
728
        }
256✔
729
    }
28✔
730
    return items;
33✔
731
}
33✔
732

733
function deArrayifyContainer(json: any[]): ContainerDefinition[] {
3✔
734
    const containers = [] as ContainerDefinition[];
3✔
735
    const getter = buildPropertyGetter<ContainerDefinition>();
3✔
736
    for (const c of json) {
3✔
737
        containers.push({
21✔
738
            Name: getter(c, "Name", "string"),
21✔
739
            Type: getter(c, "Type", "string"),
21✔
740
            //Position: getter(c, "Position", "string"),
741
            Extension: deArrayifyExtension(c.Extension),
21✔
742
            Item: deArrayifyContainerItems(c.Item)
21✔
743
        });
21✔
744
    }
21✔
745
    return containers;
3✔
746
}
3✔
747

748
function deArrayifyWidgets(json: any[]): Widget[] {
3✔
749
    const widgets = [] as Widget[];
3✔
750
    for (const w of json) {
3✔
751
        if (w["@xsi:type"] == "UiWidgetType") {
211✔
752
            const uiw = deArrayifyUiWidget(w);
174✔
753
            widgets.push(uiw);
174✔
754
        } else {
211✔
755
            widgets.push(deArrayifyWidget(w));
37✔
756
        }
37✔
757
    }
211✔
758
    return widgets;
3✔
759
}
3✔
760

761
function deArrayifyWidget(json: any): Widget {
37✔
762
    const root = json;
37✔
763
    if (root == null) {
37!
764
        throw new MgError("Malformed input. Expected Widget element");
×
UNCOV
765
    }
×
766
    const getter = buildPropertyGetter<Widget & { "@xsi:type": string }>();
37✔
767
    const w: Widget = {
37✔
768
        WidgetType: getter(root, "@xsi:type", "string"),
37✔
769
        Name: getter(root, "Name", "string"),
37✔
770
        Type: getter(root, "Type", "string"),
37✔
771
        //Location: getter(root, "Location", "string"),
772
        Extension: deArrayifyExtension(root.Extension)
37✔
773
    };
37✔
774
    return w;
37✔
775
}
37✔
776

777
function deArrayifyExtension(json: any, arrayCheck: boolean = true): any {
301✔
778
    const root = json;
301✔
779
    if (root == null) {
301✔
780
        return null;
93✔
781
    }
93✔
782
    if (arrayCheck && root.length != 1) {
301!
783
        throw new MgError("Malformed input. Expected Extension element");
×
UNCOV
784
    }
✔
785
    const getter = buildPropertyGetter<{ Key: string, Value: string, [key: string]: string}>();
208✔
786
    const ext: any = {};
208✔
787
    for (const key in root[0]) {
301✔
788
        if (Array.isArray(root[0][key])) {
571✔
789
            //Special case handling
790
            switch (key) {
530✔
791
                case "AdditionalParameter":
530!
UNCOV
792
                    {
×
793
                        const params = [];
×
794
                        for (const p of root[0][key]) {
×
795
                            params.push({
×
UNCOV
796
                                Key: getter(p, "Key", "string"),
×
UNCOV
797
                                Value: getter(p, "Value", "string")
×
UNCOV
798
                            });
×
UNCOV
799
                        }
×
800
                        ext[key] = params;
×
UNCOV
801
                    }
×
802
                    break;
×
803
                case "Projection":
530✔
804
                    {
2✔
805
                        ext[key] = root[0][key];
2✔
806
                    }
2✔
807
                    break;
2✔
808
                default:
530✔
809
                    ext[key] = getter(root[0], key, "string");
528✔
810
                    break;
528✔
811
            }
530✔
812
        } else {
571✔
813
            ext[key] = deArrayifyExtension(root[0][key], false);
41✔
814
        }
41✔
815
    }
571✔
816
    return ext;
208✔
817
}
208✔
818

819
function deArrayifyUiWidget(json: any): UIWidget {
174✔
820
    const root = json;
174✔
821
    if (root == null) {
174!
822
        throw new MgError("Malformed input. Expected Widget element");
×
UNCOV
823
    }
×
824
    const getter = buildPropertyGetter<UIWidget & { "@xsi:type": string }>();
174✔
825
    const w: UIWidget = {
174✔
826
        WidgetType: getter(root, "@xsi:type", "string"),
174✔
827
        ImageUrl: getter(root, "ImageUrl", "string"),
174✔
828
        ImageClass: getter(root, "ImageClass", "string"),
174✔
829
        Label: getter(root, "Label", "string"),
174✔
830
        Tooltip: getter(root, "Tooltip", "string"),
174✔
831
        StatusText: getter(root, "StatusText", "string"),
174✔
832
        Disabled: getter(root, "Disabled", "boolean"),
174✔
833
        Name: getter(root, "Name", "string"),
174✔
834
        Type: getter(root, "Type", "string"),
174✔
835
        //Location: getter(root, "Location", "string"),
836
        Extension: deArrayifyExtension(root.Extension)
174✔
837
    };
174✔
838
    return w;
174✔
839
}
174✔
840

841
function deArrayifyMapWidget(json: any): MapWidget {
3✔
842
    const root = json;
3✔
843
    if (root == null || root.length != 1) {
3!
844
        throw new MgError("Malformed input. Expected MapWidget element");
×
UNCOV
845
    }
×
846
    const getter = buildPropertyGetter<MapWidget & { "@xsi:type": string }>();
3✔
847
    const mw: MapWidget = {
3✔
848
        WidgetType: getter(root, "@xsi:type", "string"),
3✔
849
        MapId: getter(root, "MapId", "string"),
3✔
850
        Name: getter(root, "Name", "string"),
3✔
851
        Type: getter(root, "Type", "string"),
3✔
852
        //Location: getter(root, "Location", "string"),
853
        Extension: deArrayifyExtension(root.Extension)
3✔
854
    };
3✔
855
    return mw;
3✔
856
}
3✔
857

858
function deArrayifyWidgetSet(json: any): WidgetSet[] {
3✔
859
    const widgetSet = [] as WidgetSet[];
3✔
860
    for (const ws of json) {
3✔
861
        widgetSet.push({
3✔
862
            Container: deArrayifyContainer(ws.Container),
3✔
863
            MapWidget: deArrayifyMapWidget(ws.MapWidget),
3✔
864
            Widget: deArrayifyWidgets(ws.Widget)
3✔
865
        })
3✔
866
    }
3✔
867
    return widgetSet;
3✔
868
}
3✔
869

870
function deArrayifyFlexibleLayout(json: any): ApplicationDefinition {
3✔
871
    const root = json;
3✔
872
    const getter = buildPropertyGetter<ApplicationDefinition>();
3✔
873
    const resp = {
3✔
874
        Title: getter(root, "Title"),
3✔
875
        TemplateUrl: getter(root, "TemplateUrl"),
3✔
876
        MapSet: deArrayifyMapSet(root.MapSet),
3✔
877
        WidgetSet: deArrayifyWidgetSet(root.WidgetSet),
3✔
878
        Extension: deArrayifyExtension(root.Extension)
3✔
879
    };
3✔
880
    return resp;
3✔
881
}
3✔
882

883
function deArrayifyMapDefinitionGroups(json: any): MapDefinitionLayerGroup[] {
4✔
884
    const groups = [] as MapDefinitionLayerGroup[];
4✔
885
    const getter = buildPropertyGetter<MapDefinitionLayerGroup>();
4✔
886
    for (const g of json) {
4✔
887
        groups.push({
16✔
888
            Name: getter(g, "Name"),
16✔
889
            ExpandInLegend: getter(g, "ExpandInLegend", "boolean"),
16✔
890
            ShowInLegend: getter(g, "ShowInLegend", "boolean"),
16✔
891
            Visible: getter(g, "Visible", "boolean"),
16✔
892
            LegendLabel: getter(g, "LegendLabel"),
16✔
893
            Group: getter(g, "Group")
16✔
894
        });
16✔
895
    }
16✔
896
    return groups;
4✔
897
}
4✔
898

899
function deArrayifyMapDefinitionLayers(json: any): MdfLayer[] {
4✔
900
    const layers = [] as MdfLayer[];
4✔
901
    const getter = buildPropertyGetter<MdfLayer>();
4✔
902
    for (const g of json) {
4✔
903
        layers.push({
50✔
904
            Name: getter(g, "Name"),
50✔
905
            ResourceId: getter(g, "ResourceId"),
50✔
906
            ExpandInLegend: getter(g, "ExpandInLegend", "boolean"),
50✔
907
            ShowInLegend: getter(g, "ShowInLegend", "boolean"),
50✔
908
            Selectable: getter(g, "Selectable", "boolean"),
50✔
909
            Visible: getter(g, "Visible", "boolean"),
50✔
910
            LegendLabel: getter(g, "LegendLabel"),
50✔
911
            Group: getter(g, "Group"),
50✔
912
        });
50✔
913
    }
50✔
914
    return layers;
4✔
915
}
4✔
916

917
function deArrayifyMapDefinition(json: any): MapDefinition {
4✔
918
    const root = json;
4✔
919
    const getter = buildPropertyGetter<MapDefinition>();
4✔
920
    const eGetter = buildPropertyGetter<MapDefinition["Extents"]>();
4✔
921
    const resp: MapDefinition = {
4✔
922
        BackgroundColor: getter(root, "BackgroundColor"),
4✔
923
        CoordinateSystem: getter(root, "CoordinateSystem"),
4✔
924
        Extents: {
4✔
925
            MinX: eGetter(root.Extents[0], "MinX", "float"),
4✔
926
            MinY: eGetter(root.Extents[0], "MinY", "float"),
4✔
927
            MaxX: eGetter(root.Extents[0], "MaxX", "float"),
4✔
928
            MaxY: eGetter(root.Extents[0], "MaxY", "float")
4✔
929
        },
4✔
930
        MapLayer: deArrayifyMapDefinitionLayers(root.MapLayer ?? []),
4!
931
        MapLayerGroup: deArrayifyMapDefinitionGroups(root.MapLayerGroup ?? [])
4✔
932
    };
4✔
933
    if (root.TileSetSource) {
4!
934
        const tGetter = buildPropertyGetter<TileSetSource>();
×
935
        resp.TileSetSource = {
×
UNCOV
936
            ResourceId: tGetter(root.TileSetSource, "ResourceId")
×
UNCOV
937
        };
×
UNCOV
938
    }
×
939
    return resp;
4✔
940
}
4✔
941

942
function deArrayifyTileSetDefinitionLayers(json: any): BaseMapLayer[] {
1✔
943
    const getter = buildPropertyGetter<BaseMapLayer>();
1✔
944
    const layers = [] as BaseMapLayer[];
1✔
945
    for (const l of json) {
1✔
946
        layers.push({
7✔
947
            Name: getter(l, "Name"),
7✔
948
            ResourceId: getter(l, "ResourceId"),
7✔
949
            Selectable: getter(l, "Selectable", "boolean"),
7✔
950
            ShowInLegend: getter(l, "ShowInLegend", "boolean"),
7✔
951
            LegendLabel: getter(l, "LegendLabel"),
7✔
952
            ExpandInLegend: getter(l, "ExpandInLegend", "boolean")
7✔
953
        })
7✔
954
    }
7✔
955
    return layers;
1✔
956
}
1✔
957

958
function deArrayifyTileSetDefinitionGroups(json: any): BaseMapLayerGroup[] {
1✔
959
    const getter = buildPropertyGetter<BaseMapLayerGroup>();
1✔
960
    const groups = []  as BaseMapLayerGroup[];
1✔
961
    for (const g of json) {
1✔
962
        groups.push({
1✔
963
            Name: getter(g, "Name"),
1✔
964
            Visible: getter(g, "Visible", "boolean"),
1✔
965
            ShowInLegend: getter(g, "ShowInLegend", "boolean"),
1✔
966
            ExpandInLegend: getter(g, "ExpandInLegend", "boolean"),
1✔
967
            LegendLabel: getter(g, "LegendLabel"),
1✔
968
            BaseMapLayer: deArrayifyTileSetDefinitionLayers(g.BaseMapLayer)
1✔
969
        });
1✔
970
    }
1✔
971
    return groups;
1✔
972
}
1✔
973

974
function deArrayifyTileSetDefinitionParamList(root: any): { Name: string, Value: string }[] {
1✔
975
    const getter = buildPropertyGetter<{ Name: string, Value: string }>();
1✔
976
    const params = [] as { Name: string, Value: string }[];
1✔
977
    for (const p of root) {
1✔
978
        params.push({
2✔
979
            Name: getter(p, "Name"),
2✔
980
            Value: getter(p, "Value")
2✔
981
        });
2✔
982
    }
2✔
983
    return params;
1✔
984
}
1✔
985

986
function deArrayifyTileSetDefinitionParams(root: any): TileStoreParameters {
1✔
987
    const getter = buildPropertyGetter<TileStoreParameters>();
1✔
988
    const tsp: TileStoreParameters = {
1✔
989
        TileProvider: getter(root, "TileProvider"),
1✔
990
        Parameter: deArrayifyTileSetDefinitionParamList(root[0].Parameter)
1✔
991
    };
1✔
992
    return tsp;
1✔
993
}
1✔
994

995
function deArrayifyTileSetDefinition(json: any): TileSetDefinition {
1✔
996
    const root = json;
1✔
997
    const eGetter = buildPropertyGetter<TileSetDefinition["Extents"]>();
1✔
998
    const resp: TileSetDefinition = {
1✔
999
        Extents: {
1✔
1000
            MinX: eGetter(root.Extents[0], "MinX", "float"),
1✔
1001
            MinY: eGetter(root.Extents[0], "MinY", "float"),
1✔
1002
            MaxX: eGetter(root.Extents[0], "MaxX", "float"),
1✔
1003
            MaxY: eGetter(root.Extents[0], "MaxY", "float")
1✔
1004
        },
1✔
1005
        TileStoreParameters: deArrayifyTileSetDefinitionParams(json.TileStoreParameters),
1✔
1006
        BaseMapLayerGroup: deArrayifyTileSetDefinitionGroups(json.BaseMapLayerGroup)
1✔
1007
    };
1✔
1008
    return resp;
1✔
1009
}
1✔
1010

1011
/**
1012
 * Indicates if the de-arrayified result is a {@link WebLayout}
1013
 * 
1014
 * @since 0.14
1015
 */
1016
export function isWebLayout(arg: DeArrayifiedResult): arg is WebLayout {
1✔
1017
    return (arg as any).CommandSet != null
1✔
1018
        && (arg as any).ContextMenu != null
1✔
1019
        && (arg as any).Map != null
1✔
1020
}
1✔
1021

1022
/**
1023
 * Indicates if the de-arrayified result is an {@link ApplicationDefinition}
1024
 * 
1025
 * @since 0.14
1026
 */
1027
export function isAppDef(arg: DeArrayifiedResult): arg is ApplicationDefinition {
1✔
1028
    return (arg as any).WidgetSet != null;
3✔
1029
}
3✔
1030

1031
/**
1032
 * Indicates if the de-arrayified result is a {@link MapDefinition}
1033
 * 
1034
 * @since 0.14
1035
 */
1036
export function isMapDef(arg: DeArrayifiedResult): arg is MapDefinition {
1✔
1037
    return (arg as any).Extents != null
4✔
1038
        && (arg as any).BackgroundColor != null
4✔
1039
        && (arg as any).CoordinateSystem != null
4✔
1040
        && (arg as any).MapLayer != null
4✔
1041
        && (arg as any).MapLayerGroup != null;
4✔
1042
}
4✔
1043

1044
/**
1045
 * Indicates if the de-arrayified result is a {@link TileSetDefinition}
1046
 * 
1047
 * @since 0.14
1048
 */
1049
export function isTileSet(arg: DeArrayifiedResult): arg is TileSetDefinition {
1✔
1050
    return (arg as any).Extents != null
1✔
1051
        && (arg as any).TileStoreParameters != null
1✔
1052
        && (arg as any).BaseMapLayerGroup != null;
1✔
1053
}
1✔
1054

1055
/**
1056
 * Indicates if the de-arrayified result is a {@link SiteVersionResponse}
1057
 * 
1058
 * @since 0.14
1059
 */
1060
export function isSiteVersion(arg: DeArrayifiedResult): arg is SiteVersionResponse {
1✔
1061
    return (arg as any).Version != null;
×
UNCOV
1062
}
×
1063

1064
/**
1065
 * Indicates if the de-arrayified result is a {@link QueryMapFeaturesResponse}
1066
 * 
1067
 * @since 0.14
1068
 */
1069
export function isQueryMapFeaturesResponse(arg: DeArrayifiedResult): arg is QueryMapFeaturesResponse {
1✔
1070
    return (arg as any).FeatureSet != null
1!
UNCOV
1071
        || (arg as any).Hyperlink != null
×
UNCOV
1072
        || (arg as any).InlineSelectionImage != null
×
UNCOV
1073
        || (arg as any).SelectedFeatures != null
×
UNCOV
1074
        || (arg as any).Tooltip != null;
×
1075
}
1✔
1076

1077
/**
1078
 * The result of the normalization of JSON from the mapagent
1079
 * 
1080
 * @since 0.14
1081
 */
1082
export type DeArrayifiedResult = RuntimeMap | QueryMapFeaturesResponse | WebLayout | ApplicationDefinition | MapDefinition | TileSetDefinition | SiteVersionResponse;
1083

1084
/**
1085
 * Normalizes the given JSON object to match the content model of its original XML form
1086
 *
1087
 * @export
1088
 * @param {*} json The JSON object to normalize
1089
 * @returns {*} The normalized JSON object
1090
 */
1091
export function deArrayify(json: any): DeArrayifiedResult {
1✔
1092
    if (json["RuntimeMap"]) {
13✔
1093
        return deArrayifyRuntimeMap(json.RuntimeMap);
3✔
1094
    }
3✔
1095
    if (json["FeatureInformation"]) {
13✔
1096
        return deArrayifyFeatureInformation(json.FeatureInformation);
1✔
1097
    }
1✔
1098
    if (json["WebLayout"]) {
13✔
1099
        return deArrayifyWebLayout(json.WebLayout);
1✔
1100
    }
1✔
1101
    if (json["ApplicationDefinition"]) {
13✔
1102
        return deArrayifyFlexibleLayout(json.ApplicationDefinition);
3✔
1103
    }
3✔
1104
    if (json["MapDefinition"]) {
13✔
1105
        return deArrayifyMapDefinition(json.MapDefinition);
4✔
1106
    }
4✔
1107
    if (json["TileSetDefinition"]) {
1✔
1108
        return deArrayifyTileSetDefinition(json.TileSetDefinition);
1✔
1109
    }
1!
1110
    if (json["SiteVersion"]) {
×
1111
        return {
×
UNCOV
1112
            Version: json.SiteVersion.Version[0]
×
UNCOV
1113
        } as SiteVersionResponse;
×
UNCOV
1114
    }
×
1115
    const keys = [] as string[];
×
1116
    for (const k in json) {
×
1117
        keys.push(k);
×
UNCOV
1118
    }
×
1119
    throw new MgError(`Unsure how to process JSON response. Root elements are: (${keys.join(", ")})`);
×
UNCOV
1120
}
×
1121

1122
/**
1123
 * Builds an XML selection string from the given selection set.
1124
 *
1125
 * @export
1126
 * @param {(FeatureSet | undefined)} selection The selection set
1127
 * @param {string[]} [layerIds] If specified, the selection XML will only include selections from the specified layers
1128
 * @returns {string} The selection XML string
1129
 */
1130
export function buildSelectionXml(selection: FeatureSet | undefined, layerIds?: string[]): string {
1✔
1131
    let idCount = 0;
×
1132
    let xml = '<?xml version="1.0" encoding="utf-8"?>';
×
1133
    xml += '<FeatureSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FeatureSet-1.0.0.xsd">';
×
1134
    if (selection) {
×
1135
        const selLayers = selection.Layer;
×
1136
        for (const layer of selLayers) {
×
1137
            const layerId = layer["@id"];
×
1138
            if (layerIds != null && layerIds.indexOf(layerId) < 0) {
×
1139
                continue;
×
UNCOV
1140
            }
×
1141
            const cls = layer.Class;
×
1142
            if (cls.ID.length === 0) { // Don't bother writing out empty Layer/Class elements
×
1143
                continue;
×
UNCOV
1144
            }
×
1145
            xml += `<Layer id="${layerId}">`;
×
1146
            xml += `<Class id="${cls["@id"]}">`;
×
1147
            for (const id of cls.ID) {
×
1148
                xml += `<ID>${id}</ID>`;
×
1149
                idCount++;
×
UNCOV
1150
            }
×
1151
            xml += '</Class>';
×
1152
            xml += '</Layer>';
×
UNCOV
1153
        }
×
UNCOV
1154
    }
×
1155
    xml += '</FeatureSet>';
×
1156
    // If we didn't write any ids, just return an empty string instead
1157
    return idCount > 0 ? xml : '';
×
UNCOV
1158
}
×
1159

1160
/**
1161
 * Can only be used for a v4.0.0 or higher QUERYMAPFEATURES request
1162
 * 
1163
 * @param selection Current selection set
1164
 * @param feat The active selected feature
1165
 */
1166
export function getActiveSelectedFeatureXml(selection: FeatureSet, feat: ActiveSelectedFeature): string | undefined {
1✔
1167
    for (const layer of selection.Layer) {
×
1168
        const layerId = layer["@id"];
×
1169
        if (layerId == feat.layerId) {
×
1170
            const key = feat.selectionKey;
×
1171
            let xml = '<?xml version="1.0" encoding="utf-8"?>';
×
1172
            xml += '<FeatureSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FeatureSet-1.0.0.xsd">';
×
1173
            xml += `<Layer id="${layerId}">`;
×
1174
            xml += `<Class id="${layer.Class["@id"]}">`;
×
1175
            xml += `<ID>${key}</ID>`;
×
1176
            xml += '</Class>';
×
1177
            xml += '</Layer>';
×
1178
            xml += '</FeatureSet>';
×
1179
            return xml;
×
UNCOV
1180
        }
×
UNCOV
1181
    }
×
UNCOV
1182
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc