From c0e809d519cb91d8fe43931f4cd209975ea77043 Mon Sep 17 00:00:00 2001 From: Yves Choquette Date: Fri, 10 May 2024 12:00:47 -0400 Subject: [PATCH] Input and internal schema validation plus maxExtent default issue --- .../types/classes/map-feature-config.ts | 23 +- .../src/api/config/types/config-constants.ts | 46 +-- .../types/config-validation-schema.json | 342 ++++++++++-------- 3 files changed, 229 insertions(+), 182 deletions(-) diff --git a/packages/geoview-core/src/api/config/types/classes/map-feature-config.ts b/packages/geoview-core/src/api/config/types/classes/map-feature-config.ts index eca05625c57..48c44e4251f 100644 --- a/packages/geoview-core/src/api/config/types/classes/map-feature-config.ts +++ b/packages/geoview-core/src/api/config/types/classes/map-feature-config.ts @@ -17,6 +17,7 @@ import { TypeNavBarProps, TypeOverviewMapProps, TypeServiceUrls, + TypeValidMapProjectionCodes, TypeValidVersions, VALID_PROJECTION_CODES, VALID_VERSIONS, @@ -33,6 +34,7 @@ import { CV_DEFAULT_MAP_FEATURE_CONFIG, CV_MAP_CENTER, CV_MAP_CONFIG_SCHEMA_PATH, + CV_MAP_EXTENTS, } from '@config/types/config-constants'; import { isvalidComparedToSchema } from '@config/utils'; import { isJsonString, removeCommentsFromJSON } from '@/core/utils/utilities'; @@ -87,7 +89,8 @@ export class MapFeatureConfig { /** * ISO 639-1 code indicating the languages supported by the configuration file. It will use value(s) provided here to * access bilangual configuration nodes. For value(s) provided here, each bilingual configuration node MUST provide a value. - * */ + */ + // TODO: Delete the suportedLanguages property from the viewer. suportedLanguages: TypeListOfLocalizedLanguages; /** @@ -116,7 +119,7 @@ export class MapFeatureConfig { // set map configuration const gvMap = clonedJsonConfig.map as TypeJsonObject; if (gvMap) (gvMap.listOfGeoviewLayerConfig as TypeJsonArray) = (gvMap.listOfGeoviewLayerConfig || []) as TypeJsonArray; - this.map = Cast(defaultsDeep(gvMap, CV_DEFAULT_MAP_FEATURE_CONFIG.map)); + this.map = Cast(defaultsDeep(gvMap, this.#getDefaultMapConfig(gvMap?.viewSettings?.projection as TypeValidMapProjectionCodes))); this.map.listOfGeoviewLayerConfig = (gvMap.listOfGeoviewLayerConfig as TypeJsonArray) .map((geoviewLayerConfig) => { return MapFeatureConfig.nodeFactory(geoviewLayerConfig, this.#language, this); @@ -136,7 +139,7 @@ export class MapFeatureConfig { ...((clonedJsonConfig.externalPackages || CV_DEFAULT_MAP_FEATURE_CONFIG.externalPackages) as TypeExternalPackages), ]; this.suportedLanguages = [ - ...((clonedJsonConfig.suportedLanguages || CV_DEFAULT_MAP_FEATURE_CONFIG.supportedLanguages) as TypeListOfLocalizedLanguages), + ...((clonedJsonConfig.suportedLanguages || CV_DEFAULT_MAP_FEATURE_CONFIG.suportedLanguages) as TypeListOfLocalizedLanguages), ]; this.schemaVersionUsed = (clonedJsonConfig.schemaVersionUsed as TypeValidVersions) || CV_DEFAULT_MAP_FEATURE_CONFIG.schemaVersionUsed; this.#errorDetected = this.#errorDetected || !isvalidComparedToSchema(CV_MAP_CONFIG_SCHEMA_PATH, this); @@ -272,6 +275,20 @@ export class MapFeatureConfig { return undefined; } + /** + * Get the default values for the mapFeatureConfig.map using the projection code. + * @param {TypeValidMapProjectionCodes} projection The projection code. + * + * @returns {TypeMapConfig} The default map configuration associated to the projection. + */ + #getDefaultMapConfig(projection?: TypeValidMapProjectionCodes): TypeMapConfig { + const proj = projection && VALID_PROJECTION_CODES.includes(projection) ? projection : CV_DEFAULT_MAP_FEATURE_CONFIG.map.viewSettings.projection; + const mapConfig = cloneDeep(CV_DEFAULT_MAP_FEATURE_CONFIG.map); + mapConfig.viewSettings.maxExtent = [...CV_MAP_EXTENTS[proj]]; + + return mapConfig; + } + /** * This method attempts to recover a valid configuration following the detection of an error. It will attempt to replace the * erroneous values with the default values associated with the properties in error. There is a limit to this recovery diff --git a/packages/geoview-core/src/api/config/types/config-constants.ts b/packages/geoview-core/src/api/config/types/config-constants.ts index b4ee40d4c8d..748d86ee78c 100644 --- a/packages/geoview-core/src/api/config/types/config-constants.ts +++ b/packages/geoview-core/src/api/config/types/config-constants.ts @@ -1,25 +1,13 @@ // TODO: When we are done with the config extraction, do a review of all the constants, types and utilities to // TODOCONT: remove code duplication. -import { AbstractGeoviewLayerConfig } from '@config/types/classes/geoview-config/abstract-geoview-layer-config'; -import { LayerEntryTypesKey, LayerTypesKey, TypeGeoviewLayerType } from '@config/types/config-types'; +import { Cast, LayerEntryTypesKey, LayerTypesKey, TypeGeoviewLayerType } from '@config/types/config-types'; import { - TypeAppBarProps, TypeBasemapId, - TypeBasemapOptions, - TypeDisplayTheme, - TypeExternalPackages, - TypeInteraction, TypeLayerEntryType, - TypeListOfLocalizedLanguages, - TypeMapConfig, - TypeNavBarProps, - TypeOverviewMapProps, - TypeServiceUrls, TypeValidMapProjectionCodes, - TypeValidVersions, - TypeViewSettings, } from '@config/types/map-schema-types'; +import { MapFeatureConfig } from '@config/types/classes/map-feature-config'; /** The default geocore url */ export const CV_CONFIG_GEOCORE_URL = 'https://geocore-stage.api.geo.ca'; @@ -136,9 +124,9 @@ export const CV_MAP_EXTENTS: Record = { * Definition of the MapFeatureConfig default values. All the default values that applies to the map feature configuration are * defined here. */ -export const CV_DEFAULT_MAP_FEATURE_CONFIG = { +export const CV_DEFAULT_MAP_FEATURE_CONFIG = Cast({ map: { - interaction: 'dynamic' as TypeInteraction, + interaction: 'dynamic', viewSettings: { initialView: { zoomAndCenter: [3.5, [-90, 60]], @@ -149,29 +137,29 @@ export const CV_DEFAULT_MAP_FEATURE_CONFIG = { maxZoom: 50, maxExtent: [-125, 30, -60, 89], projection: 3978, - } as TypeViewSettings, + }, basemapOptions: { basemapId: 'transport', shaded: true, labeled: true, - } as TypeBasemapOptions, - listOfGeoviewLayerConfig: [] as AbstractGeoviewLayerConfig[], + }, + listOfGeoviewLayerConfig: [], extraOptions: {}, - } as TypeMapConfig, - theme: 'geo.ca' as TypeDisplayTheme, + }, + theme: 'geo.ca', components: ['north-arrow', 'overview-map'], - appBar: { tabs: { core: ['geolocator'] } } as TypeAppBarProps, - navBar: ['zoom', 'fullscreen', 'home'] as TypeNavBarProps, + appBar: { tabs: { core: ['geolocator'] } }, + navBar: ['zoom', 'fullscreen', 'home'], corePackages: [], - overviewMap: undefined as TypeOverviewMapProps | undefined, - externalPackages: [] as TypeExternalPackages, + overviewMap: undefined, + externalPackages: [], serviceUrls: { geocoreUrl: CV_CONFIG_GEOCORE_URL, geolocator: CV_CONFIG_GEOLOCATOR_URL, - } as TypeServiceUrls, - supportedLanguages: ['en', 'fr'] as TypeListOfLocalizedLanguages, - schemaVersionUsed: '1.0' as TypeValidVersions, -}; + }, + suportedLanguages: ['en', 'fr'], + schemaVersionUsed: '1.0', +}); /** * Definition of the initial settings default values. diff --git a/packages/geoview-core/src/api/config/types/config-validation-schema.json b/packages/geoview-core/src/api/config/types/config-validation-schema.json index 2b475384e20..93feba3b396 100644 --- a/packages/geoview-core/src/api/config/types/config-validation-schema.json +++ b/packages/geoview-core/src/api/config/types/config-validation-schema.json @@ -746,19 +746,6 @@ "type": "string", "description": "The id of the layer to display on the map." }, - "layerName": { - "oneOf": [ - { - "$ref": "#/definitions/TypeLocalizedString", - "description": "Used by the input schema." - }, - { - "type": "string", - "description": "Used by the internal schema." - } - ], - "description": "The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this information." - }, "geometryType": { "$ref": "#/definitions/TypeGeometryType", "description": "The type of geometry used by the layer." @@ -796,15 +783,34 @@ }, "style": { "$ref": "#/definitions/TypeStyleConfig" + } + }, + "if": { + "properties": { + "entryType": { + "enum": ["vector"], + "description": "The entryType property is not defined by the user but by the viewer according to the geoview layer type. It is used as a flag indicating the type of schema used (input/internal)." + } }, - "not": { - "listOfLayerEntryConfig": { - "$ref": "#/definitions/TypeListOfLayerEntryConfig", - "description": "The list of layer entry configurations to use from the GeoView layer group." + "required": ["entryType"] + }, + "then": { + "properties": { + "layerName": { + "type": "string", + "description": "Used by the internal schema." } } }, - "required": ["entryType", "layerId"] + "else": { + "properties": { + "layerName": { + "$ref": "#/definitions/TypeLocalizedString", + "description": "Used by the input schema. The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this information." + } + } + }, + "required": ["layerId"] }, "TypeVectorTileLayerEntryConfig": { "additionalProperties": false, @@ -818,19 +824,6 @@ "type": "string", "description": "The id of the layer to display on the map." }, - "layerName": { - "oneOf": [ - { - "$ref": "#/definitions/TypeLocalizedString", - "description": "Used by the input schema." - }, - { - "type": "string", - "description": "Used by the internal schema." - } - ], - "description": "The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this information." - }, "geometryType": { "$ref": "#/definitions/TypeGeometryType", "description": "The type of geometry used by the layer." @@ -869,15 +862,34 @@ }, "style": { "$ref": "#/definitions/TypeStyleConfig" + } + }, + "if": { + "properties": { + "entryType": { + "enum": ["vector-tile"], + "description": "The entryType property is not defined by the user but by the viewer according to the geoview layer type. It is used as a flag indicating the type of schema used (input/internal)." + } }, - "not": { - "listOfLayerEntryConfig": { - "$ref": "#/definitions/TypeListOfLayerEntryConfig", - "description": "The list of layer entry configurations to use from the GeoView layer group." + "required": ["entryType"] + }, + "then": { + "properties": { + "layerName": { + "type": "string", + "description": "Used by the internal schema." } } }, - "required": ["entryType", "layerId"] + "else": { + "properties": { + "layerName": { + "$ref": "#/definitions/TypeLocalizedString", + "description": "Used by the input schema. The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this information." + } + } + }, + "required": ["layerId"] }, "TypeVectorTileSourceInitialConfig": { "additionalProperties": false, @@ -911,19 +923,6 @@ "type": "string", "description": "The id of the layer to display on the map." }, - "layerName": { - "oneOf": [ - { - "$ref": "#/definitions/TypeLocalizedString", - "description": "Used by the input schema." - }, - { - "type": "string", - "description": "Used by the internal schema." - } - ], - "description": "The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this information." - }, "attributions": { "type": "array", "items": { @@ -957,15 +956,34 @@ }, "style": { "$ref": "#/definitions/TypeStyleConfig" + } + }, + "if": { + "properties": { + "entryType": { + "enum": ["raster-image"], + "description": "The entryType property is not defined by the user but by the viewer according to the geoview layer type. It is used as a flag indicating the type of schema used (input/internal)." + } }, - "not": { - "listOfLayerEntryConfig": { - "$ref": "#/definitions/TypeListOfLayerEntryConfig", - "description": "The list of layer entry configurations to use from the GeoView layer group." + "required": ["entryType"] + }, + "then": { + "properties": { + "layerName": { + "type": "string", + "description": "Used by the internal schema." } } }, - "required": ["entryType", "layerId"] + "else": { + "properties": { + "layerName": { + "$ref": "#/definitions/TypeLocalizedString", + "description": "Used by the input schema. The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this information." + } + } + }, + "required": ["layerId"] }, "TypeEsriDynamicLayerEntryConfig": { "additionalProperties": false, @@ -1028,15 +1046,34 @@ }, "style": { "$ref": "#/definitions/TypeStyleConfig" + } + }, + "if": { + "properties": { + "entryType": { + "enum": ["raster-image"], + "description": "The entryType property is not defined by the user but by the viewer according to the geoview layer type. It is used as a flag indicating the type of schema used (input/internal)." + } }, - "not": { - "listOfLayerEntryConfig": { - "$ref": "#/definitions/TypeListOfLayerEntryConfig", - "description": "The list of layer entry configurations to use from the GeoView layer group." + "required": ["entryType"] + }, + "then": { + "properties": { + "layerName": { + "type": "string", + "description": "Used by the internal schema." } } }, - "required": ["entryType", "layerId"] + "else": { + "properties": { + "layerName": { + "$ref": "#/definitions/TypeLocalizedString", + "description": "Used by the input schema. The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this information." + } + } + }, + "required": ["layerId"] }, "TypeEsriImageLayerEntryConfig": { "additionalProperties": false, @@ -1049,19 +1086,6 @@ "type": "string", "description": "The id of the layer to display on the map." }, - "layerName": { - "oneOf": [ - { - "$ref": "#/definitions/TypeLocalizedString", - "description": "Used by the input schema." - }, - { - "type": "string", - "description": "Used by the internal schema." - } - ], - "description": "The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this information." - }, "attributions": { "type": "array", "items": { @@ -1095,15 +1119,34 @@ }, "style": { "$ref": "#/definitions/TypeStyleConfig" + } + }, + "if": { + "properties": { + "entryType": { + "enum": ["raster-image"], + "description": "The entryType property is not defined by the user but by the viewer according to the geoview layer type. It is used as a flag indicating the type of schema used (input/internal)." + } }, - "not": { - "listOfLayerEntryConfig": { - "$ref": "#/definitions/TypeListOfLayerEntryConfig", - "description": "The list of layer entry configurations to use from the GeoView layer group." + "required": ["entryType"] + }, + "then": { + "properties": { + "layerName": { + "type": "string", + "description": "Used by the internal schema." } } }, - "required": ["entryType", "layerId"] + "else": { + "properties": { + "layerName": { + "$ref": "#/definitions/TypeLocalizedString", + "description": "Used by the input schema. The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this information." + } + } + }, + "required": ["layerId"] }, "TypeImageStaticLayerEntryConfig": { "additionalProperties": false, @@ -1116,19 +1159,6 @@ "type": "string", "description": "The id of the layer to display on the map." }, - "layerName": { - "oneOf": [ - { - "$ref": "#/definitions/TypeLocalizedString", - "description": "Used by the input schema." - }, - { - "type": "string", - "description": "Used by the internal schema." - } - ], - "description": "The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this information." - }, "attributions": { "type": "array", "items": { @@ -1159,15 +1189,34 @@ }, "source": { "$ref": "#/definitions/TypeSourceImageStaticInitialConfig" + } + }, + "if": { + "properties": { + "entryType": { + "enum": ["raster-image"], + "description": "The entryType property is not defined by the user but by the viewer according to the geoview layer type. It is used as a flag indicating the type of schema used (input/internal)." + } }, - "not": { - "listOfLayerEntryConfig": { - "$ref": "#/definitions/TypeListOfLayerEntryConfig", - "description": "The list of layer entry configurations to use from the GeoView layer group." + "required": ["entryType"] + }, + "then": { + "properties": { + "layerName": { + "type": "string", + "description": "Used by the internal schema." } } }, - "required": ["entryType", "layerId"] + "else": { + "properties": { + "layerName": { + "$ref": "#/definitions/TypeLocalizedString", + "description": "Used by the input schema. The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this information." + } + } + }, + "required": ["layerId"] }, "TypeTileLayerEntryConfig": { "additionalProperties": false, @@ -1180,19 +1229,6 @@ "type": "string", "description": "The id of the layer to display on the map." }, - "layerName": { - "oneOf": [ - { - "$ref": "#/definitions/TypeLocalizedString", - "description": "Used by the input schema." - }, - { - "type": "string", - "description": "Used by the internal schema." - } - ], - "description": "The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this information." - }, "attributions": { "type": "array", "items": { @@ -1223,15 +1259,34 @@ }, "source": { "$ref": "#/definitions/TypeSourceTileInitialConfig" + } + }, + "if": { + "properties": { + "entryType": { + "enum": ["raster-tile"], + "description": "The entryType property is not defined by the user but by the viewer according to the geoview layer type. It is used as a flag indicating the type of schema used (input/internal)." + } }, - "not": { - "listOfLayerEntryConfig": { - "$ref": "#/definitions/TypeListOfLayerEntryConfig", - "description": "The list of layer entry configurations to use from the GeoView layer group." + "required": ["entryType"] + }, + "then": { + "properties": { + "layerName": { + "type": "string", + "description": "Used by the internal schema." } } }, - "required": ["entryType", "layerId"] + "else": { + "properties": { + "layerName": { + "$ref": "#/definitions/TypeLocalizedString", + "description": "Used by the input schema. The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this information." + } + } + }, + "required": ["layerId"] }, "TypeLayerEntryType": { "enum": ["vector", "vector-tile", "raster-tile", "raster-image", "geoCore"], @@ -1249,19 +1304,6 @@ "type": "string", "description": "The id of the layer group to display on the map." }, - "layerName": { - "oneOf": [ - { - "$ref": "#/definitions/TypeLocalizedString", - "description": "Used by the input schema." - }, - { - "type": "string", - "description": "Used by the internal schema." - } - ], - "description": "The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this information." - }, "bounds": { "type": "array", "minItems": 4, @@ -1279,32 +1321,32 @@ "description": "The list of layer entry configurations to use from the GeoView layer group." } }, - "required": ["entryType", "layerId", "listOfLayerEntryConfig"] - }, - "TypeLayerEntryConfig": { - "oneOf": [ - { - "$ref": "#/definitions/TypeLayerGroupEntryConfig" - }, - { - "$ref": "#/definitions/TypeVectorTileLayerEntryConfig" - }, - { - "$ref": "#/definitions/TypeVectorLayerEntryConfig" - }, - { - "$ref": "#/definitions/TypeOgcWmsLayerEntryConfig" - }, - { - "$ref": "#/definitions/TypeEsriDynamicLayerEntryConfig" - }, - { - "$ref": "#/definitions/TypeEsriImageLayerEntryConfig" + "if": { + "properties": { + "entryType": { + "enum": ["group"], + "description": "The entryType property is not defined by the user but by the viewer according to the geoview layer type. It is used as a flag indicating the type of schema used (input/internal)." + } }, - { - "$ref": "#/definitions/TypeTileLayerEntryConfig" + "required": ["entryType"] + }, + "then": { + "properties": { + "layerName": { + "type": "string", + "description": "Used by the internal schema." + } } - ] + }, + "else": { + "properties": { + "layerName": { + "$ref": "#/definitions/TypeLocalizedString", + "description": "Used by the input schema. The display name of the layer (English/French). If it is not present the viewer will make an attempt to scrape this information." + } + } + }, + "required": ["layerId", "listOfLayerEntryConfig"] }, "TypeListOfLayerEntryConfig": { "type": "array",