UNPKG

@loaders.gl/wms

Version:

Framework-independent loaders for the WMS (Web Map Service) standard

4 lines 125 kB
{ "version": 3, "sources": ["../src/index.ts", "../src/lib/parsers/csw/parse-csw-capabilities.ts", "../src/lib/parsers/csw/parse-exception-report.ts", "../src/csw-capabilities-loader.ts", "../src/lib/parsers/csw/parse-csw-domain.ts", "../src/csw-domain-loader.ts", "../src/lib/parsers/csw/parse-csw-records.ts", "../src/csw-records-loader.ts", "../src/lib/parsers/wms/parse-wms-error.ts", "../src/wms-error-loader.ts", "../src/lib/parsers/wms/parse-wms-capabilities.ts", "../src/lib/parsers/xml/parse-xml-helpers.ts", "../src/wms-capabilities-loader.ts", "../src/lib/parsers/wms/parse-wms-features.ts", "../src/wip/wms-feature-info-loader.ts", "../src/lib/parsers/wms/parse-wms-layer-description.ts", "../src/wip/wms-layer-description-loader.ts", "../src/lib/parsers/wfs/parse-wfs-capabilities.ts", "../src/wfs-capabilities-loader.ts", "../src/lib/parsers/gml/parse-gml.ts", "../src/lib/parsers/gml/deep-strict-equal.ts", "../src/gml-loader.ts", "../src/wms-source.ts", "../src/arcgis/arcgis-server.ts", "../src/arcgis/arcgis-image-source.ts", "../src/lib/deprecated/create-image-source.ts"], "sourcesContent": ["// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\n// CSW - Catalog Service for the Web\n\nexport type {CSWLoaderOptions} from './csw-capabilities-loader';\n\nexport type {CSWCapabilities} from './csw-capabilities-loader';\nexport {CSWCapabilitiesLoader} from './csw-capabilities-loader';\n\nexport type {CSWDomain} from './csw-domain-loader';\nexport {CSWDomainLoader} from './csw-domain-loader';\n\nexport type {CSWRecords} from './csw-records-loader';\nexport {CSWRecordsLoader} from './csw-records-loader';\n\n// WMS - Web Map Service\n\nexport {WMSErrorLoader} from './wms-error-loader';\n\nexport type {\n WMSCapabilities,\n WMSLayer,\n WMSBoundingBox,\n WMSDimension\n} from './wms-capabilities-loader';\nexport type {WMSCapabilitiesLoaderOptions} from './wms-capabilities-loader';\nexport {WMSCapabilitiesLoader} from './wms-capabilities-loader';\n\nexport type {WMSFeatureInfo as _WMSFeatureInfo} from './wip/wms-feature-info-loader';\nexport {WMSFeatureInfoLoader as _WMSFeatureInfoLoader} from './wip/wms-feature-info-loader';\n\nexport type {WMSLayerDescription as _WMSLayerDescription} from './wip/wms-layer-description-loader';\nexport {WMSLayerDescriptionLoader as _WMSLayerDescriptionLoader} from './wip/wms-layer-description-loader';\n\n// WMTS - Web Map Tile Service\n\n// export type {WMTSLoaderOptions as _WMTSLoaderOptions} from './wip/wmts-capabilities-loader';\n// export type {WMTSCapabilities as _WMTSCapabilities} from './wip/wmts-capabilities-loader';\n// export {WMTSCapabilitiesLoader as _WMTSCapabilitiesLoader} from './wip/wmts-capabilities-loader';\n\n// WFS - Web Feature Service\n\nexport type {WFSLoaderOptions as _WFSLoaderOptions} from './wfs-capabilities-loader';\nexport type {WFSCapabilities as _WFSCapabilities} from './wfs-capabilities-loader';\nexport {WFSCapabilitiesLoader as _WFSCapabilitiesLoader} from './wfs-capabilities-loader';\n\n// GML - Geographic Markup Language\n\nexport type {GeoJSON as _GeoJSON} from '@loaders.gl/schema';\nexport type {GMLLoaderOptions as _GMLLoaderOptions} from './gml-loader';\nexport {GMLLoader as _GMLLoader} from './gml-loader';\n\n// EXPERIMENTAL: DATA SOURCES\n\n// OGC Services\n\n// export {CSWSource} from './csw-source';\nexport {WMSSource, WMSImageSource} from './wms-source';\n\n// ArcGIS SourceLoaders\n\nexport {getArcGISServices as _getArcGISServices} from './arcgis/arcgis-server';\nexport {ArcGISImageServerSource as _ArcGISImageServerSource} from './arcgis/arcgis-image-source';\n\nexport {ImageSource} from '@loaders.gl/loader-utils';\nexport type {ImageType} from '@loaders.gl/images';\nexport {createImageSource} from './lib/deprecated/create-image-source';\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport type {XMLLoaderOptions} from '@loaders.gl/xml';\nimport {XMLLoader} from '@loaders.gl/xml';\nimport {parseExceptionReport} from './parse-exception-report';\n\n// CSW:GetCapabilitiesResponse\n\n/** All capabilities of a CSW service - response to a CSW `GetCapabilities` data structure extracted from XML */\nexport type CSWCapabilities = {\n serviceIdentification: {\n title: string;\n serviceTypeVersion: string;\n serviceType: string;\n };\n\n serviceProvider: {\n providerName: string;\n providerSite: string;\n serviceContact: {\n individualName: string;\n positionName: string;\n contactInfo: {\n address: {\n administrativeArea: string;\n city: string;\n country: string;\n deliveryPoint: string;\n electronicMailAddress: string;\n postalCode: string;\n };\n phone: {\n voice: string;\n };\n };\n };\n };\n\n operationsMetadata: {\n GetCapabilities: any;\n GetFeatureInfo: any;\n GetTile: any;\n };\n\n contents: {\n layers: {\n abstract: string;\n identifier: string;\n title: string;\n formats: string[];\n styles: {\n identifier: string;\n isDefault: string;\n title: string;\n abstract?: string;\n }[];\n bounds: {\n left: number;\n right: number;\n bottom: number;\n top: number;\n };\n tileMatrixSetLinks: {\n tileMatrixSet: string;\n }[];\n tileMatrixSets: {\n identifier: string;\n matrixIds: {\n identifier: string;\n matrixHeight: number;\n matrixWidth: number;\n scaleDenominator: number;\n tileWidth: number;\n tileHeight: number;\n topLeftCorner: {\n lon: number;\n lat: number;\n };\n }[];\n };\n }[];\n };\n};\n\n/**\n * Parses a typed data structure from raw XML for `GetCapabilities` response\n * @note Error handlings is fairly weak\n */\nexport function parseCSWCapabilities(text: string, options?: XMLLoaderOptions): CSWCapabilities {\n const parsedXML = XMLLoader.parseTextSync?.(text, {\n ...options,\n xml: {\n ...options?.xml,\n removeNSPrefix: true,\n uncapitalizeKeys: true\n }\n });\n\n parseExceptionReport(parsedXML);\n\n const xmlCapabilities: any = parsedXML.capabilities || parsedXML;\n return xmlCapabilities;\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\n// import type {XMLLoaderOptions} from '@loaders.gl/xml';\n// import {XMLLoader} from '@loaders.gl/xml';\n\n/**\n * Parses a typed data structure from raw XML for `GetDomain` response\n * @note Error handlings is fairly weak\n */\nexport function parseExceptionReport(parsedXML: any): void {\n // const parsedXML = XMLLoader.parseTextSync?.(text, {\n // ...options,\n // xml: {\n // ...options?.xml,\n // removeNSPrefix: true,\n // uncapitalizeKeys: true\n // }\n // });\n\n const exceptionReport: any = parsedXML.exceptionReport;\n if (!exceptionReport) {\n return;\n }\n const errorMessage =\n exceptionReport.exception?.exceptionText ||\n exceptionReport.exception?.exceptionCode ||\n exceptionReport.exception?.locator ||\n 'server error';\n\n throw new Error(`Catalog Server: ${errorMessage}`);\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport type {LoaderWithParser} from '@loaders.gl/loader-utils';\nimport type {XMLLoaderOptions} from '@loaders.gl/xml';\nimport type {CSWCapabilities} from './lib/parsers/csw/parse-csw-capabilities';\nimport {parseCSWCapabilities} from './lib/parsers/csw/parse-csw-capabilities';\n\n// __VERSION__ is injected by babel-plugin-version-inline\n// @ts-ignore TS2304: Cannot find name '__VERSION__'.\nconst VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest';\n\n// parsed data type\nexport type {CSWCapabilities};\n\n/** CSW loader options */\nexport type CSWLoaderOptions = XMLLoaderOptions & {\n csw?: {};\n};\n\n/**\n * Loader for the response to the CSW GetCapability request\n */\nexport const CSWCapabilitiesLoader = {\n dataType: null as unknown as CSWCapabilities,\n batchType: null as never,\n\n id: 'csw-capabilities',\n name: 'CSW Capabilities',\n module: 'wms',\n version: VERSION,\n worker: false,\n extensions: ['xml'],\n mimeTypes: ['application/vnd.ogc.csw_xml', 'application/xml', 'text/xml'],\n testText: testXMLFile,\n options: {\n csw: {}\n },\n parse: async (arrayBuffer: ArrayBuffer, options?: CSWLoaderOptions) =>\n parseCSWCapabilities(new TextDecoder().decode(arrayBuffer), options),\n parseTextSync: (text: string, options?: CSWLoaderOptions) => parseCSWCapabilities(text, options)\n} as const satisfies LoaderWithParser<CSWCapabilities, never, CSWLoaderOptions>;\n\nfunction testXMLFile(text: string): boolean {\n // TODO - There could be space first.\n return text.startsWith('<?xml');\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport type {XMLLoaderOptions} from '@loaders.gl/xml';\nimport {XMLLoader} from '@loaders.gl/xml';\nimport {parseExceptionReport} from './parse-exception-report';\n\n/** Describes the values of resource */\nexport type CSWDomain = {\n domainValues: {\n type: string;\n propertyName: string;\n values: {\n [key: string]: unknown;\n }[];\n }[];\n};\n\n/**\n * Parses a typed data structure from raw XML for `GetDomain` response\n * @note Error handlings is fairly weak\n */\nexport function parseCSWDomain(text: string, options?: XMLLoaderOptions): CSWDomain {\n const parsedXML = XMLLoader.parseTextSync?.(text, {\n ...options,\n xml: {\n ...options?.xml,\n removeNSPrefix: true,\n uncapitalizeKeys: true,\n arrayPaths: [\n 'GetDomainResponse.DomainValues',\n 'GetDomainResponse.DomainValues.ListOfValues.value'\n ]\n }\n });\n\n parseExceptionReport(parsedXML);\n\n const xmlDomain: any = parsedXML.getDomainResponse;\n for (const domainValue of xmlDomain.domainValues) {\n // Drop the nested <listOfValues><value><value><listOfValues> => values[]\n domainValue.values = domainValue.listOfValues?.value;\n delete domainValue.listOfValues;\n }\n return xmlDomain as CSWDomain;\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport type {LoaderWithParser} from '@loaders.gl/loader-utils';\nimport type {XMLLoaderOptions} from '@loaders.gl/xml';\nimport type {CSWDomain} from './lib/parsers/csw/parse-csw-domain';\nimport {parseCSWDomain} from './lib/parsers/csw/parse-csw-domain';\n\n// __VERSION__ is injected by babel-plugin-version-inline\n// @ts-ignore TS2304: Cannot find name '__VERSION__'.\nconst VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest';\n\nexport type {CSWDomain};\n\nexport type CSWLoaderOptions = XMLLoaderOptions & {\n csw?: {};\n};\n\n/**\n * Loader for the response to the CSW GetCapability request\n */\nexport const CSWDomainLoader = {\n dataType: null as unknown as CSWDomain,\n batchType: null as never,\n\n id: 'csw-domain',\n name: 'CSW Domain',\n\n module: 'wms',\n version: VERSION,\n worker: false,\n extensions: ['xml'],\n mimeTypes: ['application/vnd.ogc.csw_xml', 'application/xml', 'text/xml'],\n testText: testXMLFile,\n options: {\n csw: {}\n },\n parse: async (arrayBuffer: ArrayBuffer, options?: CSWLoaderOptions) =>\n parseCSWDomain(new TextDecoder().decode(arrayBuffer), options),\n parseTextSync: (text: string, options?: CSWLoaderOptions) => parseCSWDomain(text, options)\n} as const satisfies LoaderWithParser<CSWDomain, never, CSWLoaderOptions>;\n\nfunction testXMLFile(text: string): boolean {\n // TODO - There could be space first.\n return text.startsWith('<?xml');\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport {XMLLoaderOptions, convertXMLFieldToArrayInPlace, XMLLoader} from '@loaders.gl/xml';\nimport {parseExceptionReport} from './parse-exception-report';\n\nexport type CSWRecords = {\n searchStatus: {\n timestamp?: string;\n };\n searchResults: {\n numberOfRecordsMatched: number;\n numberOfRecordsReturned: number;\n elementSet: string;\n nextRecord: number;\n };\n records: {\n type: string;\n title: string;\n abstract: string;\n subject: string[];\n boundingBoxes: {\n crs: string;\n value: [number, number, number, number];\n }[];\n references: {\n value: string;\n scheme: string;\n }[];\n }[];\n};\n\n/**\n * Parses a typed data structure from raw XML for `GetRecords` response\n * @note Error handlings is fairly weak\n */\nexport function parseCSWRecords(text: string, options?: XMLLoaderOptions): CSWRecords {\n const parsedXML = XMLLoader.parseTextSync?.(text, {\n ...options,\n xml: {\n ...options?.xml,\n removeNSPrefix: true,\n uncapitalizeKeys: true,\n arrayPaths: [],\n _fastXML: {\n ...options?.xml?._fastXML,\n parseAttributeValue: true\n }\n }\n });\n\n parseExceptionReport(parsedXML);\n\n const xmlRecords: any = parsedXML.getRecordsResponse;\n\n // Move results to top\n const elementSet = xmlRecords.searchResults.elementSet;\n const recordsFieldName = `${elementSet}Record`;\n xmlRecords.records = xmlRecords.searchResults[recordsFieldName];\n delete xmlRecords.searchResults[recordsFieldName];\n\n convertXMLFieldToArrayInPlace(xmlRecords, 'records');\n\n for (const record of xmlRecords.records) {\n record.boundingBoxes = record.boundingBox;\n delete record.boundingBox;\n\n convertXMLFieldToArrayInPlace(record, 'boundingBoxes');\n\n for (const boundingBox of record.boundingBoxes) {\n boundingBox.value = [\n boundingBox.upperCorner[0],\n boundingBox.upperCorner[1],\n boundingBox.lowerCorner[0],\n boundingBox.lowerCorner[1]\n ];\n delete boundingBox.upperCorner;\n delete boundingBox.lowerCorner;\n }\n }\n\n return xmlRecords as CSWRecords;\n}\n\nexport function renameXMLTags(xml: any, renameKeys: Record<string, string>): void {\n for (const [oldKey, newKey] of Object.entries(renameKeys)) {\n xml[newKey] = xml[oldKey];\n delete xml[oldKey];\n }\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport type {LoaderWithParser} from '@loaders.gl/loader-utils';\nimport type {XMLLoaderOptions} from '@loaders.gl/xml';\nimport type {CSWRecords} from './lib/parsers/csw/parse-csw-records';\nimport {parseCSWRecords} from './lib/parsers/csw/parse-csw-records';\n\n// __VERSION__ is injected by babel-plugin-version-inline\n// @ts-ignore TS2304: Cannot find name '__VERSION__'.\nconst VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest';\n\nexport {CSWRecords};\n\nexport type CSWLoaderOptions = XMLLoaderOptions & {\n csw?: {};\n};\n\n/**\n * Loader for the response to the CSW GetCapability request\n */\nexport const CSWRecordsLoader = {\n dataType: null as unknown as CSWRecords,\n batchType: null as never,\n\n id: 'csw-records',\n name: 'CSW Records',\n module: 'wms',\n version: VERSION,\n worker: false,\n extensions: ['xml'],\n mimeTypes: ['application/vnd.ogc.csw_xml', 'application/xml', 'text/xml'],\n testText: testXMLFile,\n options: {\n csw: {}\n },\n parse: async (arrayBuffer: ArrayBuffer, options?: CSWLoaderOptions) =>\n parseCSWRecords(new TextDecoder().decode(arrayBuffer), options),\n parseTextSync: (text: string, options?: CSWLoaderOptions) => parseCSWRecords(text, options)\n} as const satisfies LoaderWithParser<CSWRecords, never, CSWLoaderOptions>;\n\nfunction testXMLFile(text: string): boolean {\n // TODO - There could be space first.\n return text.startsWith('<?xml');\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport {XMLLoader} from '@loaders.gl/xml';\n\n/**\n * Extract an error message from WMS error response XML\n * @param text\n * @param options\n * @returns a string with a human readable message\n */\nexport function parseWMSError(text: string, options): string {\n const parsedXML = XMLLoader.parseTextSync?.(text, options);\n const serviceExceptionXML =\n parsedXML?.ServiceExceptionReport?.ServiceException ||\n parsedXML?.['ogc:ServiceExceptionReport']?.['ogc:ServiceException'];\n // Sigh, can be either a string or an object\n const message =\n typeof serviceExceptionXML === 'string'\n ? serviceExceptionXML\n : serviceExceptionXML.value || serviceExceptionXML.code || 'Unknown error';\n return message;\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport type {LoaderWithParser, LoaderOptions} from '@loaders.gl/loader-utils';\nimport {parseWMSError} from './lib/parsers/wms/parse-wms-error';\n\n// __VERSION__ is injected by babel-plugin-version-inline\n// @ts-ignore TS2304: Cannot find name '__VERSION__'.\nconst VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest';\n\nexport type WMSLoaderOptions = LoaderOptions & {\n wms?: {\n /** By default the error loader will throw an error with the parsed error message */\n throwOnError?: boolean;\n /** Do not add any text to errors */\n minimalErrors?: boolean;\n };\n};\n\n/**\n * Loader for the response to the WMS GetCapability request\n */\nexport const WMSErrorLoader = {\n dataType: null as unknown as string,\n batchType: null as never,\n\n id: 'wms-error',\n name: 'WMS Error',\n\n module: 'wms',\n version: VERSION,\n worker: false,\n extensions: ['xml'],\n mimeTypes: ['application/vnd.ogc.se_xml', 'application/xml', 'text/xml'],\n testText: testXMLFile,\n options: {\n wms: {\n throwOnError: false\n }\n },\n parse: async (arrayBuffer: ArrayBuffer, options?: WMSLoaderOptions): Promise<string> =>\n parseTextSync(new TextDecoder().decode(arrayBuffer), options),\n parseSync: (arrayBuffer: ArrayBuffer, options?: WMSLoaderOptions): string =>\n parseTextSync(new TextDecoder().decode(arrayBuffer), options),\n parseTextSync: (text: string, options?: WMSLoaderOptions): string => parseTextSync(text, options)\n} as const satisfies LoaderWithParser<string, never, WMSLoaderOptions>;\n\nfunction testXMLFile(text: string): boolean {\n // TODO - There could be space first.\n return text.startsWith('<?xml');\n}\n\nfunction parseTextSync(text: string, options?: WMSLoaderOptions): string {\n const wmsOptions: WMSLoaderOptions['wms'] = {...WMSErrorLoader.options.wms, ...options?.wms};\n const error = parseWMSError(text, wmsOptions);\n const message = wmsOptions.minimalErrors ? error : `WMS Service error: ${error}`;\n if (wmsOptions.throwOnError) {\n throw new Error(message);\n }\n return message;\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport {XMLLoader} from '@loaders.gl/xml';\nimport {\n getXMLArray,\n getXMLStringArray,\n getXMLInteger,\n getXMLFloat,\n getXMLBoolean\n} from '../xml/parse-xml-helpers';\n\n/** All capabilities of a WMS service - response to a WMS `GetCapabilities` data structure extracted from XML */\nexport type WMSCapabilities = {\n /** Version of the WMS service */\n version?: string; // '1.3.0' | '1.1.1' | '1.1.0' | '1.0.0'\n /** A short name for the service */\n name: string;\n /** A human readable name for the service */\n title?: string;\n /** A more extensive description of the service */\n abstract?: string;\n /** A set of keywords e.g. for searching services */\n keywords: string[];\n /** A field of unspecified format, if present describes any access constraints required to use the service. */\n accessConstraints?: string;\n /** A field of unspecified format, if present describes any fees associated with the use of the service */\n fees?: string;\n /** If present, the max number of layers that can be rendered by the service */\n layerLimit?: number;\n /** If present, the widest image that can be rendered by the service */\n maxWidth?: number;\n /** If present, the tallest image that can be rendered by the service */\n maxHeight?: number;\n /** Hierarchical list of layers. */\n layers: WMSLayer[];\n /** A map with information about supported WMS requests. If a record is present, the request is supported by the service */\n requests: Record<string, WMSRequest>;\n /** Information about any exceptions that the service will report (HTTP status != 2xx) */\n exceptions?: WMSExceptions;\n /** Only if `options.json`: raw untyped JSON parsed from XML. Can include information not extracted in the typed response. */\n json?: Record<string, unknown>;\n /** Only if `options.xml`, the unparsed XML string can be requested */\n xml?: string;\n};\n\n/**\n * Metadata about a layer\n * Layers inherit many properties from their parent layers, see description of individual props for details.\n * @see https://www.ogc.org/standard/wms/ 7.2.4.6\n */\nexport type WMSLayer = {\n /** The title is a human readable name. It is mandatory on each layer. Not inherited. */\n title: string;\n /** A layer is renderable if it has a name. A named parent layer will render all its sublayers. Not inherited. */\n name?: string;\n /** A narrative description of the map layer. */\n abstract?: string;\n /** A set of keywords e.g. for searching layers */\n keywords: string[];\n /** layer limits in unspecified CRS:84-like lng/lat, for quick access w/o CRS calculations. Defined or inherited. */\n geographicBoundingBox?: [min: [x: number, y: number], max: [x: number, y: number]];\n /** Supported CRS. Either defined or inherited. */\n crs?: string[];\n /** Bounding boxes in specific CRS:es */\n boundingBoxes?: WMSBoundingBox[];\n\n // minScale: number;\n // maxScale: number;\n // dimensions: ?? 7.2.4.6.10\n // MetadataURL\n // Attribution\n // Identifier and AuthorityURL\n // FeatureListURL\n // DataURL\n\n /** any extra dimension such as time */\n dimensions?: WMSDimension[];\n\n /** Whether queries can be performed on the layer */\n queryable?: boolean;\n /** `false` if layer has significant no-data areas that the client can display as transparent. */\n opaque?: boolean;\n /** WMS cascading allows server to expose layers coming from other WMS servers as if they were local layers */\n cascaded?: boolean;\n // noSubsets: boolean\n // fixedWith: number\n // fixedHeight: number\n\n /** A list of styles. @note not yet supported by WMSCapabilitiesLoader */\n styles?: unknown[];\n\n /** Sublayers - these inherit crs and boundingBox) if not overridden) */\n layers?: WMSLayer[];\n};\n\n/**\n * A bounding box specifies the coordinate range for data in the layer.\n * No data is available outside the bounding box.\n */\nexport type WMSBoundingBox = {\n /** CRS indicates the Layer CRS that applies to this bounding box. */\n crs: string;\n /** `[[w, s], [e, n]]`, indicates the limits of the bounding box using the axis units and order of the specified CRS. */\n boundingBox: [min: [x: number, y: number], max: [x: number, y: number]];\n /** Spatial horizontal resolution of data in same units as bounding box */\n xResolution?: number;\n /** Spatial vertical resolution of data in same units as bounding box */\n yResolution?: number;\n};\n\n/**\n * An optional dimension that can be queried using the `name=...` parameter\n * Note that layers that have at least one dimension without `default` value\n * become unrenderable unless the dimension value is supplied to GetMap requests.\n */\nexport type WMSDimension = {\n /** name of dimension, becomes a valid parameter key for this layer */\n name: string;\n /** Textual units for this dimensional axis */\n units: string;\n /** Unit symbol for this dimensional axis */\n unitSymbol?: string;\n /** Default value if no value is supplied. If dimension lacks defaultValue, requests fail if no value is supplied */\n defaultValue?: string;\n /** Can multiple values of the dimension be requested? */\n multipleValues?: boolean;\n /* Will nearest values will be substituted when out of range, if false exact values are required */\n nearestValue?: boolean;\n /** A special value \"current\" is supported, typically for time dimension */\n current?: boolean;\n /** Text content indicating available values for dimension */\n extent: string;\n};\n\n/** Metadata about a supported WMS request */\nexport type WMSRequest = {\n /** MIMEtypes that can be returned by this request. */\n mimeTypes: string[];\n};\n\nexport type WMSExceptions = {\n /** MIME types for exception response payloads. */\n mimeTypes: string[];\n};\n\nexport type ParseWMSCapabilitiesOptions = {\n /** Add inherited layer information to sub layers */\n inheritedLayerProps?: boolean;\n /** Include the \"raw\" JSON (parsed but untyped, unprocessed XML). May contain additional fields */\n includeRawJSON?: boolean;\n /** Include the original XML document text. May contain additional information. */\n includeXMLText?: boolean;\n};\n\n/**\n * Parses a typed data structure from raw XML for `GetCapabilities` response\n * @note Error handlings is fairly weak\n */\nexport function parseWMSCapabilities(\n xmlText: string,\n options?: ParseWMSCapabilitiesOptions\n): WMSCapabilities {\n const parsedXML = XMLLoader.parseTextSync?.(xmlText, options);\n const xmlCapabilities: any =\n parsedXML.WMT_MS_Capabilities || parsedXML.WMS_Capabilities || parsedXML;\n const capabilities = extractCapabilities(xmlCapabilities);\n // In case the processed, normalized capabilities do not contain everything,\n // the user can get the parsed XML structure.\n if (options?.inheritedLayerProps) {\n // Traverse layers and inject missing props from parents\n for (const layer of capabilities.layers) {\n addInheritedLayerProps(layer, null);\n }\n // Not yet implemented\n }\n\n if (options?.includeRawJSON) {\n capabilities.json = xmlCapabilities;\n }\n\n if (options?.includeXMLText) {\n capabilities.xml = xmlText;\n }\n\n return capabilities;\n}\n\n/** Extract typed capability data from XML */\nfunction extractCapabilities(xml: any): WMSCapabilities {\n const capabilities: WMSCapabilities = {\n version: String(xml.version || ''),\n name: String(xml.Service?.Name || 'unnamed'),\n title: xml.Service?.Title ? String(xml.Service?.Title) : undefined,\n abstract: xml.Service?.Abstract ? String(xml.Service?.Abstract) : undefined,\n keywords: getXMLStringArray(xml.Service?.KeywordList?.Keyword),\n fees: xml.Service?.Fees ? JSON.stringify(xml.Service?.Fees) : undefined,\n accessConstraints: xml.Service?.AccessConstraints\n ? JSON.stringify(xml.Service?.AccessConstraints)\n : undefined,\n layerLimit: getXMLInteger(xml.Service?.LayerLimit),\n maxWidth: getXMLInteger(xml.Service?.maxWidth),\n maxHeight: getXMLInteger(xml.Service?.maxHeight),\n layers: [],\n requests: extractRequests(xml.Capability?.Request),\n exceptions: extractExceptions(xml.Exception)\n // contact field is a mess of largely irrelevant information, put it last\n // contact: xml.Service?.Contact ? JSON.stringify(xml.Service?.Contact) : undefined,\n };\n\n // LAYERS\n const xmlLayers = getXMLArray(xml.Capability?.Layer);\n for (const xmlSubLayer of xmlLayers) {\n capabilities.layers.push(extractLayer(xmlSubLayer));\n }\n\n // Clean up object\n for (const [key, value] of Object.entries(capabilities)) {\n if (value === undefined) {\n delete capabilities[key];\n }\n }\n\n return capabilities;\n}\n\n/** Extract typed request metadata from XML requests field */\nfunction extractRequests(xmlRequests: any): Record<string, WMSRequest> {\n const requests: Record<string, WMSRequest> = {};\n for (const [name, xmlRequest] of Object.entries(xmlRequests || {}) as any) {\n const mimeTypes = getXMLStringArray(xmlRequest?.Format);\n requests[name] = {mimeTypes};\n }\n return requests;\n}\n\nfunction extractExceptions(xmlException: any): WMSExceptions | undefined {\n const xmlExceptionFormats = getXMLArray(xmlException?.Format);\n if (xmlExceptionFormats.length > 0) {\n return {\n mimeTypes: getXMLStringArray(xmlException)\n };\n }\n return undefined;\n}\n\n/** Extract request data */\n// eslint-disable-next-line complexity, max-statements\nfunction extractLayer(xmlLayer: any): WMSLayer {\n const layer: WMSLayer = {\n // All layers must have a title\n title: String(xmlLayer?.Title || ''),\n // Name is required only if renderable\n name: xmlLayer?.Name && String(xmlLayer?.Name),\n abstract: xmlLayer?.Name && String(xmlLayer?.Abstract),\n keywords: getXMLStringArray(xmlLayer.KeywordList?.Keyword)\n };\n\n // WMS 1.3.0 changes SRS to CRS\n const crs = xmlLayer?.CRS || xmlLayer?.SRS;\n if (crs && Array.isArray(crs) && crs.every((_) => typeof _ === 'string')) {\n layer.crs = crs;\n }\n\n // v1.3.0 extract simple geographic bounding box\n let geographicBoundingBox =\n xmlLayer?.EX_GeographicBoundingBox && extractEXBoundingBox(xmlLayer?.EX_GeographicBoundingBox);\n if (geographicBoundingBox) {\n layer.geographicBoundingBox = geographicBoundingBox;\n }\n\n // v1.1.1 extract simple geographic bounding box\n geographicBoundingBox =\n xmlLayer?.LatLonBoundingBox && extractLatLonBoundingBox(xmlLayer?.LatLonBoundingBox);\n if (geographicBoundingBox) {\n layer.geographicBoundingBox = geographicBoundingBox;\n }\n\n // Extract per-CRS bounding boxes\n const boundingBoxes = xmlLayer?.BoundingBox && extractWMSBoundingBoxes(xmlLayer?.BoundingBox);\n if (boundingBoxes && boundingBoxes.length > 0) {\n layer.boundingBoxes = boundingBoxes;\n }\n\n // Extract dimensions\n const xmlDimensions = getXMLArray(xmlLayer?.Dimension);\n const dimensions = xmlDimensions.map((xml) => extractDimension(xml));\n if (dimensions.length) {\n layer.dimensions = dimensions;\n }\n\n if (xmlLayer?.opaque) {\n layer.opaque = getXMLBoolean(xmlLayer?.opaque);\n }\n if (xmlLayer?.cascaded) {\n layer.cascaded = getXMLBoolean(xmlLayer?.cascaded);\n }\n if (xmlLayer?.queryable) {\n layer.queryable = getXMLBoolean(xmlLayer?.queryable);\n }\n\n // Single layer is not represented as array in XML\n const xmlLayers = getXMLArray(xmlLayer?.Layer);\n const layers: WMSLayer[] = [];\n\n for (const xmlSubLayer of xmlLayers) {\n layers.push(extractLayer(xmlSubLayer));\n }\n\n if (layers.length > 0) {\n layer.layers = layers;\n }\n\n // Clean up object\n for (const [key, value] of Object.entries(layer)) {\n if (value === undefined) {\n delete layer[key];\n }\n }\n\n return layer;\n}\n\n/** WMS 1.3.0 Loosely defined geospatial bounding box in unspecified CRS for quick content searches */\nfunction extractEXBoundingBox(xmlBoundingBox: any): [[number, number], [number, number]] {\n const {\n westBoundLongitude: w,\n northBoundLatitude: n,\n eastBoundLongitude: e,\n southBoundLatitude: s\n } = xmlBoundingBox;\n return [\n [w, s],\n [e, n]\n ];\n}\n\n/** WMS 1.1.1 Loosely defined geospatial bounding box in unspecified CRS for quick content searches */\nfunction extractLatLonBoundingBox(xmlBoundingBox: any): [[number, number], [number, number]] {\n const {minx, miny, maxx, maxy} = xmlBoundingBox;\n return [\n [minx, miny],\n [maxx, maxy]\n ];\n}\n\n/** Loosely defined geospatial bounding box in unspecified CRS for quick content searches */\nfunction extractWMSBoundingBoxes(xmlBoundingBoxes: any): WMSBoundingBox[] {\n const xmlBoxes = getXMLArray(xmlBoundingBoxes);\n return xmlBoxes.map((xmlBox) => extractWMSBoundingBox(xmlBox));\n}\n\n/** Loosely defined geospatial bounding box in unspecified CRS for quick content searches */\nfunction extractWMSBoundingBox(xmlBoundingBox: any): WMSBoundingBox {\n const {CRS, SRS, minx, miny, maxx, maxy, resx, resy} = xmlBoundingBox;\n const boundingBox: WMSBoundingBox = {\n // CRS in 1.3.0, SRS in 1.1.1\n crs: CRS || SRS,\n boundingBox: [\n [getXMLFloat(minx) as number, getXMLFloat(miny) as number],\n [getXMLFloat(maxx) as number, getXMLFloat(maxy) as number]\n ]\n };\n if (resx) {\n boundingBox.xResolution = resx;\n }\n if (resy) {\n boundingBox.yResolution = resy;\n }\n return boundingBox;\n}\n\n/**\n * Extracts optional WMS Dimension layer field\n * @param xmlDimension\n * @example <Dimension name=\"time\" units=\"ISO8601\" default=\"2018-01-01\" nearestValue=\"0\">2001-01-01/2018-01-01/P1Y</Dimension>\n * @see https://mapserver.org/ogc/wms_dimension.html\n */\nfunction extractDimension(xmlDimension: any): WMSDimension {\n const {name, units, value: extent} = xmlDimension;\n\n const dimension: WMSDimension = {name, units, extent};\n\n if (xmlDimension.unitSymbol) {\n dimension.unitSymbol = xmlDimension.unitSymbol;\n }\n if (xmlDimension.default) {\n dimension.defaultValue = xmlDimension.default;\n }\n if (xmlDimension.multipleValues) {\n dimension.multipleValues = getXMLBoolean(xmlDimension.multipleValues);\n }\n if (xmlDimension.nearestValue) {\n dimension.nearestValue = getXMLBoolean(xmlDimension.nearestValue);\n }\n if (xmlDimension.current) {\n dimension.current = getXMLBoolean(xmlDimension.current);\n }\n\n return dimension;\n}\n\n/** Traverse layers and inject missing props from parents */\n// eslint-disable-next-line complexity\nfunction addInheritedLayerProps(layer: WMSLayer, parent: WMSLayer | null): void {\n if (parent?.geographicBoundingBox && !layer.geographicBoundingBox) {\n layer.geographicBoundingBox = [...parent.geographicBoundingBox];\n }\n\n if (parent?.crs && !layer.crs) {\n layer.crs = [...parent.crs];\n }\n\n if (parent?.boundingBoxes && !layer.boundingBoxes) {\n layer.boundingBoxes = [...parent.boundingBoxes];\n }\n\n if (parent?.dimensions && !layer.dimensions) {\n layer.dimensions = [...parent.dimensions];\n }\n\n for (const subLayer of layer.layers || []) {\n addInheritedLayerProps(subLayer, layer);\n }\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\n/** A single element of an array is not represented as an array in XML */\nexport function getXMLArray(xmlValue: any): any[] {\n // Already an array, return as is\n if (Array.isArray(xmlValue)) {\n return xmlValue;\n }\n // Single value, wrap in array\n if (xmlValue) {\n return [xmlValue];\n }\n // nullish, return empty array\n return [];\n}\n\n/** Get a list of strings from XML */\nexport function getXMLStringArray(xmlValue: any): string[] {\n const xmlArray = getXMLArray(xmlValue);\n if (xmlArray.length > 0 && xmlArray.every((_) => typeof _ === 'string')) {\n return xmlArray;\n }\n // TODO - error handling?\n return [];\n}\n\n/** Get XML float */\nexport function getXMLFloat(xmlValue: any, defaultValue = undefined): number | undefined {\n switch (typeof xmlValue) {\n case 'number':\n return xmlValue;\n case 'string':\n return parseFloat(xmlValue);\n default:\n return undefined;\n }\n}\n\n/** Get XML integer */\nexport function getXMLInteger(xmlValue: any, defaultValue = undefined): number | undefined {\n switch (typeof xmlValue) {\n case 'number':\n return xmlValue;\n case 'string':\n return parseInt(xmlValue, 10);\n default:\n return undefined;\n }\n}\n\n/** Somewhat arbitrary boolean parsing */\nexport function getXMLBoolean(xmlValue: any): boolean {\n switch (xmlValue) {\n case 'true':\n return true;\n case 'false':\n return false;\n case '1':\n return true;\n case '0':\n return false;\n default:\n return false;\n }\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport type {LoaderWithParser} from '@loaders.gl/loader-utils';\nimport type {XMLLoaderOptions} from '@loaders.gl/xml';\nimport {WMSCapabilities, parseWMSCapabilities} from './lib/parsers/wms/parse-wms-capabilities';\n\n// __VERSION__ is injected by babel-plugin-version-inline\n// @ts-ignore TS2304: Cannot find name '__VERSION__'.\nconst VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest';\n\n// Parsed data types\nexport type {\n WMSCapabilities,\n WMSLayer,\n WMSBoundingBox,\n WMSDimension,\n WMSRequest,\n WMSExceptions\n} from './lib/parsers/wms/parse-wms-capabilities';\n\nexport type WMSCapabilitiesLoaderOptions = XMLLoaderOptions & {\n wms?: {\n /** Add inherited layer information to sub layers */\n inheritedLayerProps?: boolean;\n /** Include the \"raw\" JSON (parsed but untyped, unprocessed XML). May contain additional fields */\n includeRawJSON?: boolean;\n /** Include the original XML document text. May contain additional information. */\n includeXMLText?: boolean;\n };\n};\n\n/**\n * Loader for the response to the WMS GetCapability request\n */\nexport const WMSCapabilitiesLoader = {\n dataType: null as unknown as WMSCapabilities,\n batchType: null as never,\n\n id: 'wms-capabilities',\n name: 'WMS Capabilities',\n\n module: 'wms',\n version: VERSION,\n worker: false,\n extensions: ['xml'],\n mimeTypes: ['application/vnd.ogc.wms_xml', 'application/xml', 'text/xml'],\n testText: testXMLFile,\n options: {\n wms: {}\n },\n parse: async (arrayBuffer: ArrayBuffer, options?: WMSCapabilitiesLoaderOptions) =>\n // TODO pass in XML options\n parseWMSCapabilities(new TextDecoder().decode(arrayBuffer), options?.wms),\n parseTextSync: (text: string, options?: WMSCapabilitiesLoaderOptions) =>\n // TODO pass in XML options\n parseWMSCapabilities(text, options?.wms)\n} as const satisfies LoaderWithParser<WMSCapabilities, never, WMSCapabilitiesLoaderOptions>;\n\nfunction testXMLFile(text: string): boolean {\n // TODO - There could be space first.\n return text.startsWith('<?xml');\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport {XMLLoader} from '@loaders.gl/xml';\n\n/** WMS Feature info - response to a WMS `GetFeatureInfo` request */\nexport type WMSFeatureInfo = {\n features: WMSFeature[];\n};\n\nexport type WMSFeature = {\n attributes: Record<string, number | string>;\n type: string;\n bounds: {top: number; bottom: number; left: number; right: number};\n};\n\n/**\n * Parses a typed data structure from raw XML for `GetFeatureInfo` response\n * @note Error handlings is fairly weak\n */\nexport function parseWMSFeatureInfo(text: string, options): WMSFeatureInfo {\n const parsedXML = XMLLoader.parseTextSync?.(text, options);\n const xmlFeatureInfo: any = parsedXML.FeatureInfoResponse?.FIELDS || [];\n\n const xmlFeatures = Array.isArray(xmlFeatureInfo) ? xmlFeatureInfo : [xmlFeatureInfo];\n\n return {\n features: xmlFeatures.map((xmlFeature) => extractFeature(xmlFeature))\n };\n}\n\nfunction extractFeature(xmlFeature: any) {\n const xmlFields = xmlFeature || {};\n // TODO - not correct\n return {\n attributes: xmlFields,\n type: '',\n bounds: {bottom: 0, top: 0, left: 0, right: 0}\n };\n}\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright vis.gl contributors\n\nimport type {LoaderWithParser} from '@loaders.gl/loader-utils';\nimport type {XMLLoaderOptions} from '@loaders.gl/xml';\nimport {WMSCapabilitiesLoader} from '../wms-capabilities-loader';\n\nimport type {WMSFeatureInfo} from '../lib/parsers/wms/parse-wms-features';\nimport {parseWMSFeatureInfo} from '../lib/parsers/wms/parse-wms-features';\n\nexport {WMSFeatureInfo};\n\n/**\n * Loader for the response to the WMS GetFeatureInfo request\n */\nexport const WMSFeatureInfoLoader = {\n ...WMSCapabilitiesLoader,\n dataType: null as unknown as WMSFeatureInfo,\n\n id: 'wms-feature-info',\n name: 'WMS FeatureInfo',\n\n parse: async (arrayBuffer: ArrayBuffer, options?: XMLLoaderOptions) =>\n parseWMSFeatureInfo(new TextDecoder().decode(arrayBuffer), options),\n parseTextSync: (text: string, options?: XMLLoaderOptions) => parseWMSFeatureInfo(text, options)\n} as const satisfies LoaderWithParser<WMSFeatureInfo, never, XMLLoaderOptions>;\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\nimport type {XMLLoaderOptions} from '@loaders.gl/xml';\nimport {XMLLoader} from '@loaders.gl/xml';\n\n/** Layer description - response to a WMS `DescribeLayer` request */\nexport type WMSLayerDescription = {\n layers: {}[];\n};\n\n/**\n * Parses a typed data structure from raw XML for `GetFeatureInfo` response\n * @note Error handlings is fairly weak\n */\nexport function parseWMSLayerDescription(\n text: string,\n options?: XMLLoaderOptions\n): WMSLayerDescription {\n const parsedXML = XMLLoader.parseTextSync?.(text, options);\n // TODO - implement parser\n return parsedXML as unknown as WMSLayerDescription;\n}\n", "// loaders.gl, MIT license\n\nimport type {LoaderWithParser} from '@loaders.gl/loader-utils';\nimport type {XMLLoaderOptions} from '@loaders.gl/xml';\nimport {WMSCapabilitiesLoader} from '../wms-capabilities-loader';\n\nimport type {WMSLayerDescription} from '../lib/parsers/wms/parse-wms-layer-description';\nimport {parseWMSLayerDescription} from '../lib/parsers/wms/parse-wms-layer-description';\n\nexport {WMSLayerDescription};\n\n/**\n * Loader for the response to the WMS DescribeLayer request\n */\nexport const WMSLayerDescriptionLoader = {\n ...WMSCapabilitiesLoader,\n dataType: null as unknown as WMSLayerDescription,\n\n id: 'wms-layer-description',\n name: 'WMS DescribeLayer',\n\n parse: async (arrayBuffer: ArrayBuffer, options?: XMLLoaderOptions) =>\n parseWMSLayerDescription(new TextDecoder().decode(arrayBuffer), options),\n parseTextSync: (text: string, options?: XMLLoaderOptions) => parseWMSLayerDescription(text, options)\n} as const satisfies LoaderWithParser<WMSLayerDescription, never, XMLLoaderOptions>;\n", "// loaders.gl, MIT license\n\nimport {XMLLoader} from '@loaders.gl/xml';\n\n/** All capabilities of a WFS service - response to a WFS `GetCapabilities` data structure extracted from XML */\nexport type WFSCapabilities = {\n serviceIdentification: {\n title: string;\n serviceTypeVersion: string;\n serviceType: string;\n };\n\n serviceProvider: {\n providerName: string;\n providerSite: string;\n serviceContact: {\n individualName: string;\n positionName: string;\n contactInfo: {\n address: {\n administrativeArea: string;\n city: string;\n country: string;\n deliveryPoint: string;\n electronicMailAddress: string;\n postalCode: string;\n };\n phone: {\n voice: string;\n };\n };\n };\n };\n\n operationsMetadata: {\n GetCapabilities: any;\n GetFeatureInfo: any;\n GetTile: any;\n };\n\n contents: {\n layers: {\n abstract: string;\n identifier: string;\n title: string;\n formats: string[];\n styles: {\n identifier: string;\n isDefault: string;\n title: string;\n abstract?: string;\n }[];\n bounds: {\n left: number;\n right: number;\n bottom: number;\n top: number;\n };\n tileMatrixSetLinks: {\n tileMatrixSet: string;\n }[];\n tileMatrixSets: {\n identifier: string;\n matrixIds: {\n identifier: string;\n matrixHeight: number;\n matrixWidth: number;\n scaleDenominator: number;\n tileWidth: number;\n tileHeight: number;\n topLeftCorner: {\n lon: number;\n lat: number;\n };\n }[];\n };\n }[];\n };\n};\n\n/**\n * Parses a typed data structure from raw XML for `GetCapabilities` response\n * @note Error handlings is fairly weak\n */\nexport function parseWFSCapabilities(text: string, options): WFSCapabilities {\n const parsedXML = XMLLoader.parseTextSync?.(text, {\n ...options,\n xml: {\n ...options?.xml,\n removeNSPrefix: true,\n uncapitalizeKeys: true\n }\n });\n\n const xmlCapabilities: any = parsedXML.Capabilities || parsedXML;\n return xmlCapabilities;\n}\n", "// loaders.gl, MIT license\n\nimport type {LoaderWithParser, LoaderOptions} from '@loaders.gl/loader-utils';\nimport type {WFSCapabilities} from './lib/parsers/wfs/parse-wfs-capabilities';\nimport {parseWFSCapabilities} from './lib/parsers/wfs/parse-wfs-capabilities';\n\n// __VERSION__ is injected by babel-plugin-version-inline\n// @ts-ignore TS2304: Cannot find name '__VERSION__'.\nconst VERSION = typeof __VERSION__ !== 'undefined' ? __VERSION__ : 'latest';\n\nexport type {WFSCapabilities};\n\nexport type WFSLoaderOptions = LoaderOptions & {\n wfs?: {};\n};\n\n/**\n * Loader for the response to the WFS GetCapability request\n * @deprecated Warning: this loader is still experimental and incomplete\n */\nexport const WFSCapabilitiesLoader = {\n dataType: null as unknown as WFSCapabilities,\n batchType: null as never,\n\n id: 'wfs-capabilities',\n name: 'WFS Capabilities',\n\n module: 'wms',\n version: VERSION,\n worker: false,\n extensions: ['xml'],\n mimeTypes: ['application/vnd.ogc.wfs_xml', 'application/xml', 'text/xml'],\n testText: testXMLFile,\n options: {\n wfs: {}\n },\n parse: async (arrayBuffer: ArrayBuffer, options?: WFSLoaderOptions) =>\n parseWFSCapabilities(new TextDecoder().decode(arrayBuffer), options),\n parseTextSync: (text: string, options?: WFSLoaderOptions) => parseWFSCapabilities(text, options)\n} as const satisfies LoaderWithParser<WFSCapabilities, never, WFSLoaderOptions>;\n\nfunction testXMLFile(text: string): boolean {\n // TODO - There could be space first.\n return text.startsWith('<?xml');\n}\n\nexport const _typecheckWFSCapabilitiesLoader: LoaderWithParser = WFSCapabilitiesLoader;\n", "// loaders.gl\n// SPDX-License-Identifier: MIT\n// Copyright (c) vis.gl contributors\n\n// Forked from https://github.com/derhuerst/parse-gml-polygon/blob/master/index.js\n// under ISC license\n\n/* eslint-disable no-continue, default-case */\n\nimport type {\n // GeoJSON,\n // Feature,\n // FeatureCollection,\n Geometry,\n Position\n // GeoJsonProperties,\n // Point,\n // MultiPoint,\n // LineString,\n // MultiLineString,\n // Polygon,\n // MultiPolygon,\n // GeometryCollection\n} from '@loaders.gl/schema';\n\nimport {XMLLoader} from '@loaders.gl/xml';\nimport {deepStrictEqual} from './deep-strict-equal';\nimport rewind from '@turf/rewind';\n\nfunction noTransform(...coords) {\n return coords;\n}\n\nexport type {Geometry};\n\nexport type ParseGMLOptions = {\n transformCoords?: Function;\n stride?: 2 | 3 | 4;\n};\n\nexport type ParseGMLContext = {\n srsDimension?: number;\n [key: string]: any;\n};\n\n/**\n * Parses a typed data structure from raw XML for GML features\n * @note Error handlings is fairly weak\n */\nexport function parseGML(text: string, options) {\n // GeoJSON | null {\n const parsedXML = XMLLoader.parseTextSync?.(text, options);\n\n options = {transformCoords: noTransform, stride: 2, ...options};\n const context = createChildContext(parsedXML, options, {});\n\n return parseGMLToGeometry(parsedXML, options, context);\n}\n\n/** Parse a GeoJSON geometry from GML XML */\nexport function parseGMLToGeometry(\n inputXML: any,\n options: ParseGMLOptions,\n context: ParseGMLContext\n): Geometry | null {\n const childContext = createChildContext(inputXML, options, context);\n\n let geometry: Geometry | null = null;\n\n const [name, xml] = getFirstKeyValue(inputXML);\n\n switch (name) {\n // case 'gml:MultiPoint':\n // geometry = {\n // type: 'MultiPoint',\n // coordinates: parseMultiPoint(xml, options, childContext)\n // };\n // break;\n\n case 'gml:LineString':\n geometry = {\n type: 'LineString',\n coordinates: parseLinearRingOrLineString(xml, options, childContext)\n };\n break;\n\n // case 'gml:MultiLineString':\n // geometry = {\n // type: 'MultiLineString',\n // coordinates: parseMultiLineString(xml, options, childContext)\n // };\n // break;\n\n case 'gml:Polygon':\n case 'gml:Rectangle':\n geometry = {\n type: 'Polygon',\n coordinates: parsePolygonOrRectangle(xml, options, childContext)\n };\n break;\n case 'gml:Surface':\n geometry = {\n type: 'MultiPolygon',\n coordinates: parseSurface(xml, options, childContext)\n };\n break;\n case 'gml:MultiSurface':\n geometry = {\n type: 'MultiPolygon',\n coordinates: parseMultiSurface(xml, options, childContext)\n };\n break;\n\n default:\n return null;\n }\n\n // todo\n return rewind(geometry, {mutate: true});\n}\n\n/** Parse a list of coordinates from a string */\nfunction parseCoords(s: string, options: ParseGMLOptions, context: ParseGMLContext): Position[] {\n const stride = context.srsDimension || options.stride || 2;\n\n // Handle white space\n const coords = s.replace(/\\s+/g, ' ').trim().split(' ');\n\n if (coords.length === 0 || coords.length % stride !== 0) {\n throw new Error(`invalid coordinates list (stride ${stride})`);\n }\n\n const points: Position[] = [];\n for (let i = 0; i < coords.length - 1; i += stride) {\n const point = coords.slice(i, i + stride).map(parseFloat);\n points.push(options.transformCoords?.(...point) || point);\n }\n\n return points;\n}\n\nexport function parsePosList(xml: any, options: ParseGMLOptions, context: ParseGMLContext) {\n const childContext = createChildContext(xml, options, context);\n\n const coords = textOf(xml);\n if (!coords) {\n throw new Error('invalid gml:posList element');\n }\n\n return parseCoords(coords, options, childContext);\n}\n\nexport function parsePos(xml: a