diff --git a/src/convert.ts b/src/convert.ts index 096a880..a2f8b9c 100644 --- a/src/convert.ts +++ b/src/convert.ts @@ -21,8 +21,8 @@ import { geoJsonCatalogItem, groupFromConvertMembersArray, sosCatalogItem, - wmsCatalogItem, } from "./converters/other"; +import { wmsCatalogItem } from "./converters/WmsCatalogItem"; import { inputNotPlainObject, Message, diff --git a/src/converters/WmsCatalogItem.ts b/src/converters/WmsCatalogItem.ts new file mode 100644 index 0000000..79144d0 --- /dev/null +++ b/src/converters/WmsCatalogItem.ts @@ -0,0 +1,136 @@ +import is from "@sindresorhus/is/dist"; +import { missingRequiredProp, ModelType } from "../Message"; +import { CatalogMember, ConversionOptions, MemberResult } from "../types"; +import { + catalogMemberProps, + catalogMemberPropsIgnore, + copyProps, + featureInfoTemplate, + getUnknownProps, + propsToWarnings, + legends, + CopyProps, +} from "./helpers"; + +export function wmsCatalogItem( + item: CatalogMember, + options: ConversionOptions +): MemberResult { + let error; + if (!is.string(item.url)) { + error = missingRequiredProp(ModelType.WmsItem, "url", "string", item.name); + } else if (!is.string(item.layers)) { + error = missingRequiredProp( + ModelType.WmsItem, + "layers", + "string", + item.name + ); + } + if (!options.partial && error) { + return { + member: null, + messages: [error], + }; + } + + const propsToCopy: CopyProps[] = [ + "layers", + "styles", + { + v7: "availableStyles", + v8: "availableStyles", + translationFn: (availableStyles: { [layer: string]: any[] }) => + Object.entries(availableStyles).map(([layerName, styles]) => { + const v8Styles = styles.map((style) => { + return { + name: style.Name, + title: style.Title, + abstract: style.Abstract, + legend: { url: style.legendUri }, + }; + }); + return { + layerName, + styles: v8Styles, + }; + }), + }, + "dimensions", + { + v7: "availableDimensions", + v8: "availableDimensions", + translationFn: (availableDimensions: { [layer: string]: any[] }) => + Object.entries(availableDimensions).map(([layerName, dimensions]) => { + const v8Dimensions = dimensions.map((dim) => { + return { + name: dim.name, + values: dim.options, + units: dim.units, + unitSymbol: dim.unitSymbol, + default: dim.default, + multipleValues: dim.multipleValues, + nearestValue: dim.nearestValue, + }; + }); + return { + layerName, + dimensions: v8Dimensions, + }; + }), + }, + "parameters", + "linkedWcsUrl", + "linkedWcsCoverage", + "chartColor", + "getCapabilitiesUrl", + { v7: "featureTimesProperty", v8: "timeFilterPropertyName" }, + "isGeoServer", + "minScaleDenominator", + "hideLayerAfterMinScaleDenominator", + "maxRefreshIntervals", + "leafletUpdateInterval", + ]; + + const unknownProps = getUnknownProps(item, [ + ...catalogMemberProps, + ...catalogMemberPropsIgnore, + ...propsToCopy, + "chartType", + "featureInfoTemplate", + ]); + const member: MemberResult["member"] = { + type: "wms", + name: item.name, + }; + const messages = propsToWarnings(ModelType.WmsItem, unknownProps, item.name); + + if (options.copyUnknownProperties) { + copyProps(item, member, unknownProps); + } + copyProps(item, member, [...catalogMemberProps, ...propsToCopy]); + + if (item.chartType === "momentPoints") { + member.chartType = "momentPoints"; + } else if (item.chartType === "moment") { + member.chartType = "momentLines"; + } else if (item.chartType !== undefined) { + throw `Chart type ${member.chartType} not supported`; + } + if ( + is.string(item.featureInfoTemplate) || + is.plainObject(item.featureInfoTemplate) + ) { + const result = featureInfoTemplate( + ModelType.WmsItem, + item.name, + item.featureInfoTemplate + ); + member.featureInfoTemplate = result.result; + messages.push(...result.messages); + } + const legendResult = legends(ModelType.WmsItem, item.name, item); + member.legends = legendResult.result; + messages.push(...legendResult.messages); + return { member, messages }; +} diff --git a/src/converters/helpers.ts b/src/converters/helpers.ts index 28916fa..2b534e9 100644 --- a/src/converters/helpers.ts +++ b/src/converters/helpers.ts @@ -28,19 +28,85 @@ export function isCatalogMember(m: any, partial = false): m is CatalogMember { } export const catalogMemberProps: CopyProps[] = [ + "id", "description", "info", + "infoSectionOrder", + "shortReport", + { + v7: "shortReportSections", + v8: "shortReportSections", + translationFn: (srs: any[]) => + srs.map((shortReport) => { + return { + name: shortReport.name, + content: shortReport.content, + show: shortReport.isOpen, + }; + }), + }, { v7: "isShown", v8: "show" }, "splitDirection", "url", "opacity", + "chartDisclaimer", + { + v7: "rectangle", + v8: "rectangle", + translationFn: (rectangle: any[]) => { + return { + west: rectangle[0], + south: rectangle[1], + east: rectangle[2], + north: rectangle[3], + }; + }, + }, + "currentTime", + { + v7: "dateFormat", + v8: "dateFormat", + translationFn: (dateFormat: any) => + dateFormat.timelineTic ?? dateFormat.currentTime, + }, + "disablePreview", + "hideSource", + // Note: if v7 initialTimeSource is not "present", "start", or "end" -> set to v8 currentTime property + { + v7: "initialTimeSource", + v8: "initialTimeSource", + translationFn: (initialTimeSource: any) => + (({ + present: "now", + start: "start", + end: "stop", + } as any)[initialTimeSource]), + }, + { + v7: "initialTimeSource", + v8: "currentTime", + translationFn: (initialTimeSource: any) => + !["now", "start", "end"].includes(initialTimeSource) + ? initialTimeSource + : undefined, + }, + "dataCustodian", + { + v7: "isLegendVisible", + v8: "hideLegendInWorkbench", + translationFn: (isLegendVisible: boolean) => !isLegendVisible, + }, ]; +export const imageryLayerProps: CopyProps[] = ["keepOnTop"]; + export const catalogMemberPropsIgnore = [ "name", "type", "isEnabled", "parents", + "legendUrl", // Handled by legend function + "legendUrls", // ^^ ]; export function getUnknownProps(o: PlainObject, knownProperties: CopyProps[]) { @@ -62,7 +128,9 @@ export function propsToWarnings( return properties.map((prop) => unknownProp(modelType, prop, label)); } -export type CopyProps = string | { v7: string; v8: string }; +export type CopyProps = + | string + | { v7: string; v8: string; translationFn?: (x: any) => any }; export function copyProps( source: PlainObject, @@ -72,13 +140,41 @@ export function copyProps( properties.forEach((prop) => { const propV7 = is.string(prop) ? prop : prop.v7; const propV8 = is.string(prop) ? prop : prop.v8; + if (Object.prototype.hasOwnProperty.call(source, propV7)) { - destination[propV8] = source[propV7]; + destination[propV8] = + !is.string(prop) && typeof prop.translationFn === "function" + ? prop.translationFn(source[propV7]) + : source[propV7]; } }); return destination; } +export function legends( + modelType: ModelType, + label: string, + source: PlainObject +): { + result: any; + messages: Message[]; +} { + const legendUrls = new Set(); + if (typeof source.legendUrl === "string") legendUrls.add(source.legendUrl); + if (Array.isArray(source.legendUrls)) + source.legendUrls + .filter((legendUrl) => typeof legendUrl === "string") + .forEach(legendUrls.add); + + let result = Array.from(legendUrls).map((url) => { + return { url }; + }); + return { + result: result.length > 0 ? result : undefined, + messages: [], + }; +} + export function featureInfoTemplate( modelType: ModelType, label: string, diff --git a/src/converters/other.ts b/src/converters/other.ts index fcfa36c..8176201 100644 --- a/src/converters/other.ts +++ b/src/converters/other.ts @@ -66,76 +66,6 @@ export function groupFromConvertMembersArray( }; } -export function wmsCatalogItem( - item: CatalogMember, - options: ConversionOptions -): MemberResult { - let error; - if (!is.string(item.url)) { - error = missingRequiredProp(ModelType.WmsItem, "url", "string", item.name); - } else if (!is.string(item.layers)) { - error = missingRequiredProp( - ModelType.WmsItem, - "layers", - "string", - item.name - ); - } - if (!options.partial && error) { - return { - member: null, - messages: [error], - }; - } - - const propsToCopy = [ - "layers", - "linkedWcsUrl", - "linkedWcsCoverage", - "chartColor", - { v7: "featureTimesProperty", v8: "timeFilterPropertyName" }, - ]; - - const unknownProps = getUnknownProps(item, [ - ...catalogMemberProps, - ...catalogMemberPropsIgnore, - ...propsToCopy, - "chartType", - "featureInfoTemplate", - ]); - const member: MemberResult["member"] = { - type: "wms", - name: item.name, - }; - const messages = propsToWarnings(ModelType.WmsItem, unknownProps, item.name); - - if (options.copyUnknownProperties) { - copyProps(item, member, unknownProps); - } - copyProps(item, member, [...catalogMemberProps, ...propsToCopy]); - - if (item.chartType === "momentPoints") { - member.chartType = "momentPoints"; - } else if (item.chartType === "moment") { - member.chartType = "momentLines"; - } else if (item.chartType !== undefined) { - throw `Chart type ${member.chartType} not supported`; - } - if ( - is.string(item.featureInfoTemplate) || - is.plainObject(item.featureInfoTemplate) - ) { - const result = featureInfoTemplate( - ModelType.WmsItem, - item.name, - item.featureInfoTemplate - ); - member.featureInfoTemplate = result.result; - messages.push(...result.messages); - } - return { member, messages }; -} - export function sosCatalogItem( item: CatalogMember, options: ConversionOptions