ogcopenapis 0.0.12 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +310 -72
  3. package/lib/OgcOpenApiCrsTools.d.ts +10 -9
  4. package/lib/OgcOpenApiCrsTools.d.ts.map +1 -0
  5. package/lib/OgcOpenApiCrsTools.js +40 -39
  6. package/lib/OgcOpenApiCrsTools.js.map +1 -0
  7. package/lib/OgcOpenApiFeatureStore.d.ts +94 -93
  8. package/lib/OgcOpenApiFeatureStore.d.ts.map +1 -0
  9. package/lib/OgcOpenApiFeatureStore.js +200 -244
  10. package/lib/OgcOpenApiFeatureStore.js.map +1 -0
  11. package/lib/OgcOpenApiFetchTools.d.ts +37 -30
  12. package/lib/OgcOpenApiFetchTools.d.ts.map +1 -0
  13. package/lib/OgcOpenApiFetchTools.js +68 -50
  14. package/lib/OgcOpenApiFetchTools.js.map +1 -0
  15. package/lib/OgcOpenApiGetCapabilities.d.ts +209 -112
  16. package/lib/OgcOpenApiGetCapabilities.d.ts.map +1 -0
  17. package/lib/OgcOpenApiGetCapabilities.js +424 -277
  18. package/lib/OgcOpenApiGetCapabilities.js.map +1 -0
  19. package/lib/OgcOpenApiMapsModel.d.ts +41 -36
  20. package/lib/OgcOpenApiMapsModel.d.ts.map +1 -0
  21. package/lib/OgcOpenApiMapsModel.js +88 -75
  22. package/lib/OgcOpenApiMapsModel.js.map +1 -0
  23. package/lib/OgcOpenApiMvtTools.d.ts +12 -0
  24. package/lib/OgcOpenApiMvtTools.d.ts.map +1 -0
  25. package/lib/OgcOpenApiMvtTools.js +100 -0
  26. package/lib/OgcOpenApiMvtTools.js.map +1 -0
  27. package/lib/OgcOpenApiStyleTools.d.ts +51 -0
  28. package/lib/OgcOpenApiStyleTools.d.ts.map +1 -0
  29. package/lib/OgcOpenApiStyleTools.js +155 -0
  30. package/lib/OgcOpenApiStyleTools.js.map +1 -0
  31. package/lib/OgcOpenApiTileMatrixTools.d.ts +41 -0
  32. package/lib/OgcOpenApiTileMatrixTools.d.ts.map +1 -0
  33. package/lib/OgcOpenApiTileMatrixTools.js +88 -0
  34. package/lib/OgcOpenApiTileMatrixTools.js.map +1 -0
  35. package/lib/OgcOpenApiTilesModel.d.ts +56 -31
  36. package/lib/OgcOpenApiTilesModel.d.ts.map +1 -0
  37. package/lib/OgcOpenApiTilesModel.js +167 -128
  38. package/lib/OgcOpenApiTilesModel.js.map +1 -0
  39. package/lib/OgcOpenApiVectorTilesModel.d.ts +39 -0
  40. package/lib/OgcOpenApiVectorTilesModel.d.ts.map +1 -0
  41. package/lib/OgcOpenApiVectorTilesModel.js +122 -0
  42. package/lib/OgcOpenApiVectorTilesModel.js.map +1 -0
  43. package/lib/OgcOpenApiWmtsTools.d.ts +30 -0
  44. package/lib/OgcOpenApiWmtsTools.d.ts.map +1 -0
  45. package/lib/OgcOpenApiWmtsTools.js +89 -0
  46. package/lib/OgcOpenApiWmtsTools.js.map +1 -0
  47. package/package.json +56 -27
  48. package/src/OgcOpenApiCrsTools.ts +40 -0
  49. package/src/OgcOpenApiFeatureStore.ts +296 -0
  50. package/src/OgcOpenApiFetchTools.ts +84 -0
  51. package/src/OgcOpenApiGetCapabilities.ts +641 -0
  52. package/src/OgcOpenApiMapsModel.ts +128 -0
  53. package/src/OgcOpenApiMvtTools.ts +104 -0
  54. package/src/OgcOpenApiStyleTools.ts +187 -0
  55. package/src/OgcOpenApiTileMatrixTools.ts +111 -0
  56. package/src/OgcOpenApiTilesModel.ts +214 -0
  57. package/src/OgcOpenApiVectorTilesModel.ts +141 -0
  58. package/src/OgcOpenApiWmtsTools.ts +114 -0
  59. package/lib/OgcOpenApiGetCollectionTiles.d.ts +0 -7
  60. package/lib/OgcOpenApiGetCollectionTiles.js +0 -7
@@ -1,277 +1,424 @@
1
- import { OgcOpenApiFetchTools } from "./OgcOpenApiFetchTools";
2
- const SCALE_DENOMINATOR_TOLERANCE = 1e-8;
3
- export var CollectionLinkType;
4
- (function (CollectionLinkType) {
5
- CollectionLinkType["Items"] = "items";
6
- CollectionLinkType["Styles"] = "styles";
7
- CollectionLinkType["Map"] = "map";
8
- CollectionLinkType["Tiles"] = "tiles";
9
- })(CollectionLinkType || (CollectionLinkType = {}));
10
- const CollectionLinkTypeAlternatives = {
11
- [CollectionLinkType.Items]: ["items", "item"],
12
- [CollectionLinkType.Styles]: ["http://www.opengis.net/def/rel/ogc/1.0/styles", "styles"],
13
- [CollectionLinkType.Map]: ["http://www.opengis.net/def/rel/ogc/1.0/map", "map"],
14
- [CollectionLinkType.Tiles]: ["http://www.opengis.net/def/rel/ogc/1.0/tilesets-map", "tilesets-map"],
15
- };
16
- export class OgcOpenApiGetCapabilities {
17
- static fromURL(inputRequest, options) {
18
- return new Promise((resolve, reject) => {
19
- const baseUrl = OgcOpenApiFetchTools.cleanUrl(inputRequest);
20
- const requestUrl = OgcOpenApiFetchTools.cleanUrl(inputRequest);
21
- const serverOptions = OgcOpenApiFetchTools.createFetchOptions({ originalUrl: requestUrl, proxify: options === null || options === void 0 ? void 0 : options.proxify });
22
- OgcOpenApiFetchTools.fetch(requestUrl, {
23
- method: 'GET',
24
- credentials: (options === null || options === void 0 ? void 0 : options.credentials) ? "same-origin" : "omit",
25
- headers: options ? options.requestHeaders : {},
26
- }, serverOptions).then((response) => {
27
- if (response.status === 200) {
28
- response.json().then((jsonObject) => {
29
- if (!jsonObject.links) {
30
- reject("Invalid format: (property 'links' is missing)");
31
- return;
32
- }
33
- let linkToData = jsonObject.links.find((link) => link.rel === 'data' && link.type === 'application/json');
34
- if (!linkToData) {
35
- linkToData = jsonObject.links.find((link) => link.rel === 'data');
36
- }
37
- const linkToApi = jsonObject.links.find((link) => {
38
- return ((link.rel === 'service-desc' || link.rel === 'service') &&
39
- link.type.indexOf('openapi+json') > -1);
40
- });
41
- const promiseArray = [];
42
- if (linkToData) {
43
- const collectionsPromise = OgcOpenApiGetCapabilities.fetchLinkContentAsJSON(linkToData, { credentials: options.credentials, requestHeaders: options.requestHeaders }, serverOptions);
44
- promiseArray.push(collectionsPromise);
45
- if (linkToApi) {
46
- const apiPromise = OgcOpenApiGetCapabilities.fetchLinkContentAsJSON(linkToApi, { credentials: options.credentials, requestHeaders: options.requestHeaders }, serverOptions);
47
- promiseArray.push(apiPromise);
48
- }
49
- Promise.all(promiseArray).then((responses) => {
50
- const responseDataLink = responses[0];
51
- const responseOpenApi = responses.length >= 1 ? responses[1] : undefined;
52
- const crsArray = typeof responseDataLink.crs !== "undefined" ? { crs: responseDataLink.crs } : {};
53
- const foundCollections = responseDataLink.collections.filter(c => options && options.filterCollectionsByLinkType ?
54
- OgcOpenApiGetCapabilities.filterCollectionLinks(c.links, options.filterCollectionsByLinkType).length > 0 : true)
55
- .map((collection) => {
56
- const name = typeof collection.id !== 'undefined'
57
- ? collection.id
58
- : collection.name;
59
- const collectionCrsObject = {};
60
- if (typeof collection.crs !== "undefined")
61
- collectionCrsObject.crs = collection.crs;
62
- if (typeof collection.storageCrs !== "undefined")
63
- collectionCrsObject.storageCrs = collection.storageCrs;
64
- const layer = Object.assign({ description: collection.description, id: name, name, title: collection.title, keywords: collection.keywords
65
- ? collection.keywords
66
- : [], defaultReference: 'CRS:84', links: collection.links, outputFormats: options.filterCollectionsByLinkType ?
67
- this.filterCollectionLinks(collection.links, options.filterCollectionsByLinkType).map(link => this.detectTypeFormat(link))
68
- :
69
- collection.links.map(link => this.detectTypeFormat(link)), extent: collection.extent }, collectionCrsObject);
70
- return layer;
71
- });
72
- // console.log(featureTypes);
73
- const o = Object.assign(Object.assign({ name: '', collections: foundCollections.map(col => (Object.assign(Object.assign({}, col), { crs: col.crs ? col.crs : [], links: col.links.map(l => (Object.assign(Object.assign({}, l), { href: serverOptions.complete(l.href) }))) }))), version: responseOpenApi ? responseOpenApi.openapi : '', service: '', info: responseOpenApi ? responseOpenApi.info : {} }, crsArray), { serverOptions: serverOptions, baseUrl });
74
- resolve(o);
75
- });
76
- }
77
- else {
78
- reject("Invalid format: (property 'links' contains no links with rel=data");
79
- }
80
- }, () => {
81
- reject("Not JSON");
82
- });
83
- }
84
- else {
85
- reject(response.status);
86
- }
87
- }, (err) => {
88
- reject(err);
89
- });
90
- });
91
- }
92
- static fetchLinkContentAsJSON(link, options, serverOptions) {
93
- return new Promise((resolve) => {
94
- OgcOpenApiFetchTools.fetch(link.href, { method: "GET", credentials: options.credentials ? "same-origin" : "omit", headers: options.requestHeaders }, serverOptions).then((result) => {
95
- if (result.status === 200) {
96
- result.json().then((json) => resolve(json));
97
- }
98
- else {
99
- resolve(undefined);
100
- }
101
- }, () => {
102
- resolve(undefined);
103
- });
104
- });
105
- }
106
- static filterCollectionLinks(links, linkType) {
107
- switch (linkType) {
108
- case CollectionLinkType.Items:
109
- case CollectionLinkType.Map:
110
- case CollectionLinkType.Styles:
111
- case CollectionLinkType.Tiles:
112
- return links.filter((link) => CollectionLinkTypeAlternatives[linkType].some(e => e === link.rel));
113
- default:
114
- return [];
115
- }
116
- }
117
- static getDataLink(currentLayer, preferedFormat) {
118
- const dataLink = OgcOpenApiGetCapabilities.filterCollectionLinks(currentLayer.links, CollectionLinkType.Items).find((link) => link.type === preferedFormat);
119
- return dataLink ? dataLink.href : '';
120
- }
121
- static detectTypeFormat(link) {
122
- if (link.type)
123
- return link.type;
124
- let rel = null;
125
- for (let key in CollectionLinkTypeAlternatives) {
126
- if (CollectionLinkTypeAlternatives.hasOwnProperty(key)) {
127
- CollectionLinkTypeAlternatives[key].some(e => e === link.rel);
128
- rel = key;
129
- break;
130
- }
131
- }
132
- if (rel) {
133
- if (CollectionLinkType.Map)
134
- return "image/png";
135
- }
136
- return "application/json";
137
- }
138
- static fetchTileSetsInFull(capabilities, options) {
139
- return new Promise((resolve, reject) => {
140
- this.fetchTileSets(capabilities, options).then((tileSetMetaArray) => {
141
- const promises = tileSetMetaArray.map(tml => this.fetchTileset(capabilities, tml, options));
142
- Promise.all(promises).then((arr) => {
143
- resolve(arr);
144
- });
145
- });
146
- });
147
- }
148
- static getQuadTreeCompatibleLevelOffset(tileMatrixSet) {
149
- const levels = tileMatrixSet.tileMatrices;
150
- const reference = levels[levels.length - 1];
151
- for (let level = levels.length - 2; level >= 0; level--) {
152
- const current = levels[level];
153
- // tslint:disable-next-line:no-bitwise
154
- const multiplier = 1 << (levels.length - level - 1);
155
- const errorMargin = current.scaleDenominator * SCALE_DENOMINATOR_TOLERANCE;
156
- if (Math.abs(current.scaleDenominator - reference.scaleDenominator * multiplier) > errorMargin) {
157
- return level + 1;
158
- }
159
- if (current.pointOfOrigin[0] !== reference.pointOfOrigin[0]) {
160
- return level + 1;
161
- }
162
- if (current.tileWidth !== reference.tileWidth || current.tileHeight !== reference.tileHeight) {
163
- return level + 1;
164
- }
165
- if (typeof current.variableMatrixWidths !== "undefined") {
166
- return level + 1;
167
- }
168
- if (current.matrixWidth !== (reference.matrixWidth / multiplier) || current.matrixHeight !== (reference.matrixHeight / multiplier)) {
169
- return level + 1;
170
- }
171
- }
172
- return 0;
173
- }
174
- static fetchTileSets(capabilities, options) {
175
- return new Promise((resolve, reject) => {
176
- if (capabilities === null)
177
- reject();
178
- const url = capabilities.baseUrl + "tileMatrixSets";
179
- OgcOpenApiFetchTools.fetch(url, {
180
- method: "GET",
181
- credentials: (options === null || options === void 0 ? void 0 : options.credentials) ? "same-origin" : "omit",
182
- headers: (options === null || options === void 0 ? void 0 : options.requestHeaders) ? options.requestHeaders : {}
183
- }, capabilities.serverOptions).then(result => {
184
- if (result.status === 200) {
185
- result.json().then((data) => {
186
- if (data.tileMatrixSets) {
187
- resolve(data.tileMatrixSets.map(tml => (Object.assign(Object.assign({}, tml), { href: capabilities.serverOptions.complete(tml.href) }))));
188
- }
189
- else {
190
- reject({ error: true, message: "tileMatrixSets not defined" });
191
- }
192
- }, () => {
193
- reject({ error: true, message: "Not JSON data" });
194
- });
195
- }
196
- else {
197
- reject({ error: true, message: "Invalid response: " + result.status });
198
- }
199
- }, (err) => {
200
- reject({ error: true, message: err.message });
201
- });
202
- });
203
- }
204
- static getTilesLink(capabilities, currentCollection, tileMatrixId, options) {
205
- return new Promise((resolve, reject) => {
206
- if (capabilities === null)
207
- reject();
208
- const dataLinks = OgcOpenApiGetCapabilities.filterCollectionLinks(currentCollection.links, CollectionLinkType.Tiles);
209
- const link = dataLinks.find((link) => link.type === "application/json");
210
- const href = link ? link.href : dataLinks.length > 0 ? dataLinks[0].href : '';
211
- const tileInfoUrl = OgcOpenApiFetchTools.cleanUrl(href) + tileMatrixId;
212
- OgcOpenApiFetchTools.fetch(tileInfoUrl, {
213
- method: "GET",
214
- credentials: (options === null || options === void 0 ? void 0 : options.credentials) ? "same-origin" : "omit",
215
- headers: (options === null || options === void 0 ? void 0 : options.requestHeaders) ? options === null || options === void 0 ? void 0 : options.requestHeaders : {}
216
- }, capabilities.serverOptions).then(result => {
217
- if (result.status === 200) {
218
- result.json().then((data) => {
219
- if (data.links.length > 0) {
220
- const links = data.links.filter(l => l.rel === "item" || l.rel === "items").map(a => (Object.assign(Object.assign({}, a), { href: capabilities.serverOptions.complete(a.href) })));
221
- if (links) {
222
- resolve(links);
223
- }
224
- else {
225
- reject({ error: true, message: "Invalid" });
226
- }
227
- }
228
- else {
229
- reject({ error: true, message: "Invalid" });
230
- }
231
- }, () => {
232
- reject({ error: true, message: "Not JSON data" });
233
- });
234
- }
235
- else {
236
- reject({ error: true, message: "Invalid response: " + result.status });
237
- }
238
- }, (err) => {
239
- reject({ error: true, message: err.message });
240
- });
241
- });
242
- }
243
- static fetchTileset(capabilities, tileset, options) {
244
- return new Promise((resolve, reject) => {
245
- if (capabilities === null) {
246
- reject();
247
- return;
248
- }
249
- let jsonLink = tileset.links.find(l => l.type ? l.type === "application/json" : false);
250
- jsonLink = jsonLink ? jsonLink : tileset.links[0];
251
- const href = OgcOpenApiFetchTools.cleanUrlToAsset(jsonLink.href);
252
- OgcOpenApiFetchTools.fetch(href, {
253
- method: "GET",
254
- credentials: (options === null || options === void 0 ? void 0 : options.credentials) ? "same-origin" : "omit",
255
- headers: options ? options.requestHeaders : {}
256
- }, capabilities.serverOptions).then(result => {
257
- if (result.status === 200) {
258
- result.json().then((data) => {
259
- if (typeof data.id !== "undefined" && data.tileMatrices && data.crs) {
260
- resolve(data);
261
- }
262
- else {
263
- reject({ error: true, message: "TileSet has invalid data" });
264
- }
265
- }, () => {
266
- reject({ error: true, message: "Not JSON data" });
267
- });
268
- }
269
- else {
270
- reject({ error: true, message: "Invalid response: " + result.status });
271
- }
272
- }, (err) => {
273
- reject({ error: true, message: err.message });
274
- });
275
- });
276
- }
277
- }
1
+ import { OgcOpenApiFetchTools } from "./OgcOpenApiFetchTools.js";
2
+ const SCALE_DENOMINATOR_TOLERANCE = 1e-8;
3
+ export var CollectionLinkType;
4
+ (function (CollectionLinkType) {
5
+ CollectionLinkType["Items"] = "items";
6
+ CollectionLinkType["Styles"] = "styles";
7
+ CollectionLinkType["Map"] = "map";
8
+ CollectionLinkType["Tiles"] = "tiles";
9
+ CollectionLinkType["VectorTiles"] = "vectorTiles";
10
+ })(CollectionLinkType || (CollectionLinkType = {}));
11
+ const CollectionLinkTypeAlternatives = {
12
+ [CollectionLinkType.Items]: ["items", "item"],
13
+ [CollectionLinkType.Styles]: ["http://www.opengis.net/def/rel/ogc/1.0/styles", "styles"],
14
+ [CollectionLinkType.Map]: ["http://www.opengis.net/def/rel/ogc/1.0/map", "map"],
15
+ [CollectionLinkType.Tiles]: ["http://www.opengis.net/def/rel/ogc/1.0/tilesets-map", "tilesets-map"],
16
+ [CollectionLinkType.VectorTiles]: ["http://www.opengis.net/def/rel/ogc/1.0/tilesets-vector", "tilesets-vector"],
17
+ };
18
+ // OGC API link relations are given in full or, by older servers, short: tiling-scheme or http://www.opengis.net/def/rel/ogc/1.0/tiling-scheme
19
+ const OGC_REL = "http://www.opengis.net/def/rel/ogc/1.0/";
20
+ const isRel = (link, rel) => link.rel === OGC_REL + rel || link.rel === rel;
21
+ const CollectionLinkTypeDefaultFormat = {
22
+ [CollectionLinkType.Map]: "image/png",
23
+ [CollectionLinkType.Tiles]: "image/png",
24
+ [CollectionLinkType.VectorTiles]: "application/vnd.mapbox-vector-tile",
25
+ };
26
+ export class OgcOpenApiGetCapabilities {
27
+ static fromURL(inputRequest, fromUrlOptions) {
28
+ const options = fromUrlOptions ? fromUrlOptions : {};
29
+ return new Promise((resolve, reject) => {
30
+ const baseUrl = OgcOpenApiFetchTools.cleanUrl(inputRequest);
31
+ const requestUrl = OgcOpenApiFetchTools.cleanUrl(inputRequest);
32
+ const serverOptions = OgcOpenApiFetchTools.createFetchOptions({ originalUrl: requestUrl, proxify: options?.proxify });
33
+ OgcOpenApiFetchTools.fetch(requestUrl, {
34
+ method: 'GET',
35
+ credentials: options?.credentials ? "same-origin" : "omit",
36
+ headers: options ? options.requestHeaders : {},
37
+ }, serverOptions).then((response) => {
38
+ if (response.status === 200) {
39
+ response.json().then((jsonObject) => {
40
+ if (!jsonObject.links) {
41
+ reject("Invalid format: (property 'links' is missing)");
42
+ return;
43
+ }
44
+ let linkToData = jsonObject.links.find((link) => link.rel === 'data' && link.type === 'application/json');
45
+ if (!linkToData) {
46
+ linkToData = jsonObject.links.find((link) => link.rel === 'data');
47
+ }
48
+ const linkToApi = jsonObject.links.find((link) => {
49
+ return ((link.rel === 'service-desc' || link.rel === 'service') &&
50
+ link.type.indexOf('openapi+json') > -1);
51
+ });
52
+ const tilingSchemes = jsonObject.links.filter((link) => isRel(link, 'tiling-schemes'));
53
+ const linkToTileMatrixSets = tilingSchemes.find((link) => link.type === 'application/json') || tilingSchemes.find((link) => !link.type);
54
+ // The links of the landing page are relative to it, the links of the collections to /collections
55
+ const resolveLink = (link, documentUrl) => ({ ...link, href: OgcOpenApiFetchTools.resolveUrl(link.href, documentUrl, serverOptions) });
56
+ const promiseArray = [];
57
+ if (linkToData) {
58
+ const collectionsLink = resolveLink(linkToData, requestUrl);
59
+ const collectionsPromise = OgcOpenApiGetCapabilities.fetchLinkContentAsJSON(collectionsLink, { credentials: options.credentials, requestHeaders: options.requestHeaders }, serverOptions);
60
+ promiseArray.push(collectionsPromise);
61
+ if (linkToApi) {
62
+ const apiPromise = OgcOpenApiGetCapabilities.fetchLinkContentAsJSON(resolveLink(linkToApi, requestUrl), { credentials: options.credentials, requestHeaders: options.requestHeaders }, serverOptions);
63
+ promiseArray.push(apiPromise);
64
+ }
65
+ Promise.all(promiseArray).then((responses) => {
66
+ const responseDataLink = responses[0];
67
+ const responseOpenApi = responses.length >= 1 ? responses[1] : undefined;
68
+ const crsArray = typeof responseDataLink.crs !== "undefined" ? { crs: responseDataLink.crs } : {};
69
+ const foundCollections = responseDataLink.collections.filter(c => options && options.filterCollectionsByLinkType ?
70
+ OgcOpenApiGetCapabilities.filterCollectionLinks(c.links, options.filterCollectionsByLinkType).length > 0 : true)
71
+ .map((collection) => {
72
+ const name = typeof collection.id !== 'undefined'
73
+ ? collection.id
74
+ : collection.name;
75
+ const collectionCrsObject = {};
76
+ if (typeof collection.crs !== "undefined")
77
+ collectionCrsObject.crs = collection.crs;
78
+ if (typeof collection.storageCrs !== "undefined")
79
+ collectionCrsObject.storageCrs = collection.storageCrs;
80
+ const layer = {
81
+ description: collection.description,
82
+ id: name,
83
+ name,
84
+ title: collection.title,
85
+ keywords: collection.keywords
86
+ ? collection.keywords
87
+ : [],
88
+ defaultReference: 'CRS:84',
89
+ links: collection.links,
90
+ outputFormats: options.filterCollectionsByLinkType ?
91
+ this.filterCollectionLinks(collection.links, options.filterCollectionsByLinkType).map(link => this.detectTypeFormat(link))
92
+ :
93
+ collection.links.map(link => this.detectTypeFormat(link)),
94
+ extent: collection.extent,
95
+ ...collectionCrsObject
96
+ };
97
+ return layer;
98
+ });
99
+ // console.log(featureTypes);
100
+ const o = {
101
+ name: '',
102
+ collections: foundCollections.map(col => ({ ...col, crs: col.crs ? col.crs : [], links: col.links.map(l => resolveLink(l, collectionsLink.href)) })),
103
+ version: responseOpenApi ? responseOpenApi.openapi : '',
104
+ service: '',
105
+ info: responseOpenApi ? responseOpenApi.info : {},
106
+ ...crsArray,
107
+ serverOptions: serverOptions,
108
+ links: jsonObject.links.map(l => resolveLink(l, requestUrl)),
109
+ baseUrl,
110
+ tileMatrixSetsUrl: linkToTileMatrixSets ? resolveLink(linkToTileMatrixSets, requestUrl).href : undefined
111
+ };
112
+ resolve(o);
113
+ });
114
+ }
115
+ else {
116
+ reject("Invalid format: (property 'links' contains no links with rel=data");
117
+ }
118
+ }, () => {
119
+ reject("Not JSON");
120
+ });
121
+ }
122
+ else {
123
+ reject(response.status);
124
+ }
125
+ }, (err) => {
126
+ reject(err);
127
+ });
128
+ });
129
+ }
130
+ static fetchLinkContentAsJSON(link, options, serverOptions) {
131
+ return new Promise((resolve) => {
132
+ OgcOpenApiFetchTools.fetch(link.href, { method: "GET", credentials: options.credentials ? "same-origin" : "omit", headers: options.requestHeaders }, serverOptions).then((result) => {
133
+ if (result.status === 200) {
134
+ result.json().then((json) => resolve(json));
135
+ }
136
+ else {
137
+ resolve(undefined);
138
+ }
139
+ }, () => {
140
+ resolve(undefined);
141
+ });
142
+ });
143
+ }
144
+ static filterCollectionLinks(links, linkType) {
145
+ switch (linkType) {
146
+ case CollectionLinkType.Items:
147
+ case CollectionLinkType.Map:
148
+ case CollectionLinkType.Styles:
149
+ case CollectionLinkType.Tiles:
150
+ case CollectionLinkType.VectorTiles:
151
+ return links.filter((link) => CollectionLinkTypeAlternatives[linkType].some(e => e === link.rel));
152
+ default:
153
+ return [];
154
+ }
155
+ }
156
+ static getDataLink(currentLayer, preferedFormat) {
157
+ const dataLink = OgcOpenApiGetCapabilities.filterCollectionLinks(currentLayer.links, CollectionLinkType.Items).find((link) => link.type === preferedFormat);
158
+ return dataLink ? dataLink.href : '';
159
+ }
160
+ static detectTypeFormat(link) {
161
+ if (link.type)
162
+ return link.type;
163
+ for (const key in CollectionLinkTypeAlternatives) {
164
+ if (CollectionLinkTypeAlternatives.hasOwnProperty(key) && CollectionLinkTypeAlternatives[key].some(e => e === link.rel)) {
165
+ if (CollectionLinkTypeDefaultFormat[key])
166
+ return CollectionLinkTypeDefaultFormat[key];
167
+ break;
168
+ }
169
+ }
170
+ return "application/json";
171
+ }
172
+ /**
173
+ * The tile matrix sets of the server, with their definitions. A definition that cannot be read is left out, so one
174
+ * broken definition does not hide the others. Rejects only when none can be read.
175
+ */
176
+ static async fetchTileSetsInFull(capabilities, options) {
177
+ const tileSetMetaArray = await this.fetchTileSets(capabilities, options);
178
+ const settled = await Promise.all(tileSetMetaArray.map(tml => this.fetchTileset(capabilities, tml, options).then(tileSet => ({ tileSet, error: undefined }), error => ({ tileSet: undefined, error }))));
179
+ const tileSets = settled.filter(s => s.tileSet).map(s => s.tileSet);
180
+ const failed = settled.find(s => !s.tileSet);
181
+ if (tileSets.length === 0 && failed)
182
+ throw failed.error;
183
+ return tileSets;
184
+ }
185
+ static getQuadTreeCompatibleLevelOffset(tileMatrixSet) {
186
+ const levels = tileMatrixSet.tileMatrices;
187
+ const reference = levels[levels.length - 1];
188
+ for (let level = levels.length - 2; level >= 0; level--) {
189
+ const current = levels[level];
190
+ // tslint:disable-next-line:no-bitwise
191
+ const multiplier = 1 << (levels.length - level - 1);
192
+ const errorMargin = current.scaleDenominator * SCALE_DENOMINATOR_TOLERANCE;
193
+ if (Math.abs(current.scaleDenominator - reference.scaleDenominator * multiplier) > errorMargin) {
194
+ return level + 1;
195
+ }
196
+ if (current.pointOfOrigin[0] !== reference.pointOfOrigin[0]) {
197
+ return level + 1;
198
+ }
199
+ if (current.tileWidth !== reference.tileWidth || current.tileHeight !== reference.tileHeight) {
200
+ return level + 1;
201
+ }
202
+ if (typeof current.variableMatrixWidths !== "undefined") {
203
+ return level + 1;
204
+ }
205
+ if (current.matrixWidth !== (reference.matrixWidth / multiplier) || current.matrixHeight !== (reference.matrixHeight / multiplier)) {
206
+ return level + 1;
207
+ }
208
+ }
209
+ return 0;
210
+ }
211
+ static async fetchTileSets(capabilities, options) {
212
+ if (capabilities === null)
213
+ throw { error: true, message: "No capabilities" };
214
+ const url = capabilities.tileMatrixSetsUrl ? capabilities.tileMatrixSetsUrl : capabilities.baseUrl + "tileMatrixSets";
215
+ const data = await OgcOpenApiGetCapabilities.fetchJson(capabilities, url, options);
216
+ if (!data.tileMatrixSets)
217
+ throw { error: true, message: "tileMatrixSets not defined" };
218
+ const resolve = (href) => OgcOpenApiFetchTools.resolveUrl(href, url, capabilities.serverOptions);
219
+ return data.tileMatrixSets.map(tml => ({
220
+ ...tml,
221
+ href: resolve(tml.href),
222
+ links: (tml.links ? tml.links : []).map(l => ({ ...l, href: resolve(l.href) }))
223
+ }));
224
+ }
225
+ // GETs a JSON document. Servers answer JSON for the Accept header, or for the f parameter that their links carry.
226
+ static async fetchJson(capabilities, href, options) {
227
+ let result;
228
+ try {
229
+ result = await OgcOpenApiFetchTools.fetch(href, {
230
+ method: "GET",
231
+ credentials: options?.credentials ? "same-origin" : "omit",
232
+ headers: { Accept: "application/json", ...(options?.requestHeaders ? options.requestHeaders : {}) }
233
+ }, capabilities.serverOptions);
234
+ }
235
+ catch (err) {
236
+ throw { error: true, message: err.message };
237
+ }
238
+ if (result.status !== 200)
239
+ throw { error: true, message: "Invalid response: " + result.status };
240
+ try {
241
+ return await result.json();
242
+ }
243
+ catch (err) {
244
+ throw { error: true, message: "Not JSON data" };
245
+ }
246
+ }
247
+ // The link that identifies the tile matrix set of a tileset, relative to the document that has it
248
+ static getTilingSchemeHref(capabilities, links, documentUrl) {
249
+ const tilingScheme = links.find(l => isRel(l, "tiling-scheme"));
250
+ return tilingScheme ? OgcOpenApiFetchTools.resolveUrl(tilingScheme.href, documentUrl, capabilities.serverOptions) : undefined;
251
+ }
252
+ static getTilesLink(capabilities, currentCollection, tileMatrixId, options, linkType = CollectionLinkType.Tiles) {
253
+ return this.fetchCollectionTileSet(capabilities, currentCollection, tileMatrixId, options, linkType).then(tileSet => tileSet.links);
254
+ }
255
+ // The tilesets link of a collection, the JSON one when the server types its links
256
+ static getTileSetsHref(collection, linkType) {
257
+ const dataLinks = OgcOpenApiGetCapabilities.filterCollectionLinks(collection.links, linkType);
258
+ const link = dataLinks.find((link) => link.type === "application/json");
259
+ return link ? link.href : dataLinks.length > 0 ? dataLinks[0].href : '';
260
+ }
261
+ // The tilesets link of the landing page: the tilesets of the dataset, with all its collections in each tile
262
+ static getDatasetTileSetsHref(capabilities, linkType) {
263
+ const dataLinks = OgcOpenApiGetCapabilities.filterCollectionLinks(capabilities.links ? capabilities.links : [], linkType);
264
+ const link = dataLinks.find((link) => link.type === "application/json") || dataLinks.find((link) => !link.type) || dataLinks[0];
265
+ return link ? link.href : '';
266
+ }
267
+ /**
268
+ * Whether the server tiles the dataset as a whole, all its collections in each tile, for linkType Tiles or VectorTiles
269
+ */
270
+ static hasDatasetTileSets(capabilities, linkType) {
271
+ return capabilities !== null && OgcOpenApiGetCapabilities.getDatasetTileSetsHref(capabilities, linkType) !== '';
272
+ }
273
+ /**
274
+ * Lists the tilesets of a collection: the tile matrix sets the collection is tiled in, which can be fewer than the
275
+ * tile matrix sets of the server.
276
+ */
277
+ static async fetchCollectionTileSets(capabilities, collection, linkType = CollectionLinkType.Tiles, options) {
278
+ if (capabilities === null)
279
+ throw { error: true, message: "No capabilities" };
280
+ const href = OgcOpenApiGetCapabilities.getTileSetsHref(collection, linkType);
281
+ if (href === '')
282
+ throw { error: true, message: "Collection " + collection.id + " has no " + linkType + " link" };
283
+ return OgcOpenApiGetCapabilities.fetchTileSetList(capabilities, href, options);
284
+ }
285
+ /**
286
+ * Lists the tilesets of the dataset (/tiles of the landing page): each tile has the data of all its collections.
287
+ * Some servers tile only the dataset (PDOK).
288
+ */
289
+ static async fetchDatasetTileSets(capabilities, linkType = CollectionLinkType.Tiles, options) {
290
+ if (capabilities === null)
291
+ throw { error: true, message: "No capabilities" };
292
+ const href = OgcOpenApiGetCapabilities.getDatasetTileSetsHref(capabilities, linkType);
293
+ if (href === '')
294
+ throw { error: true, message: "The dataset has no " + linkType + " link" };
295
+ return OgcOpenApiGetCapabilities.fetchTileSetList(capabilities, href, options);
296
+ }
297
+ static async fetchTileSetList(capabilities, href, options) {
298
+ const data = await OgcOpenApiGetCapabilities.fetchJson(capabilities, href, options);
299
+ if (!Array.isArray(data.tilesets))
300
+ throw { error: true, message: "Response has no tilesets" };
301
+ const tileSets = [];
302
+ for (const tileSet of data.tilesets) {
303
+ const links = tileSet.links ? tileSet.links : [];
304
+ const selfLinks = links.filter(l => l.rel === "self");
305
+ const self = selfLinks.find(l => l.type === "application/json") || selfLinks[0];
306
+ if (!self)
307
+ continue;
308
+ tileSets.push({
309
+ tileMatrixSetURI: tileSet.tileMatrixSetURI,
310
+ tileMatrixSetId: tileSet.tileMatrixSetId,
311
+ dataType: tileSet.dataType,
312
+ crs: typeof tileSet.crs === "string" ? tileSet.crs : undefined,
313
+ href: OgcOpenApiFetchTools.resolveUrl(self.href, href, capabilities.serverOptions),
314
+ tilingSchemeHref: OgcOpenApiGetCapabilities.getTilingSchemeHref(capabilities, links, href),
315
+ tileMatrixSet: OgcOpenApiGetCapabilities.getInlineTileMatrixSet(tileSet),
316
+ });
317
+ }
318
+ return tileSets;
319
+ }
320
+ /**
321
+ * The tile matrix set of a tileset among the tile matrix sets of the server (fetchTileSetsInFull): by URI, which
322
+ * servers give with their own ids (CubeWerx: WebMercatorQuad is smerc), then by id.
323
+ */
324
+ static matchTileMatrixSet(tileSet, tileMatrixSets) {
325
+ const lastSegment = (url) => url.split("?")[0].replace(/\/$/, "").split("/").pop();
326
+ const byUri = tileSet.tileMatrixSetURI ? tileMatrixSets.find(t => OgcOpenApiGetCapabilities.sameUri(t.uri, tileSet.tileMatrixSetURI)) : undefined;
327
+ if (byUri)
328
+ return byUri;
329
+ const ids = [tileSet.tileMatrixSetId,
330
+ tileSet.tileMatrixSetURI ? lastSegment(tileSet.tileMatrixSetURI) : undefined,
331
+ tileSet.tilingSchemeHref ? lastSegment(tileSet.tilingSchemeHref) : undefined].filter(id => !!id);
332
+ return tileMatrixSets.find(t => ids.indexOf(t.id) > -1);
333
+ }
334
+ // Both forms name the same resource: http or https, the case of the scheme and host, a trailing slash
335
+ static sameUri(a, b) {
336
+ const normalize = (uri) => uri.trim().replace(/\/$/, "")
337
+ .replace(/^https?:\/\/[^/]*/i, prefix => prefix.toLowerCase().replace(/^https:/, "http:"));
338
+ return !!a && !!b && normalize(a) === normalize(b);
339
+ }
340
+ /**
341
+ * The tile matrix set of a tileset: matched among the tile matrix sets of the server, or otherwise fetched from the
342
+ * tiling-scheme link of the tileset. A tileset in a list of tilesets is a summary that need not identify its tile
343
+ * matrix set, then the tileset itself is read (CubeWerx).
344
+ */
345
+ static async fetchTileMatrixSetOfTileSet(capabilities, tileSet, tileMatrixSets, options) {
346
+ if (capabilities === null)
347
+ throw { error: true, message: "No capabilities" };
348
+ if (tileSet.tileMatrixSet)
349
+ return tileSet.tileMatrixSet;
350
+ let identified = tileSet;
351
+ if (!tileSet.tileMatrixSetURI && !tileSet.tileMatrixSetId && !tileSet.tilingSchemeHref) {
352
+ identified = { ...tileSet, ...await OgcOpenApiGetCapabilities.fetchTileSetIdentity(capabilities, tileSet.href, options) };
353
+ if (identified.tileMatrixSet)
354
+ return identified.tileMatrixSet;
355
+ }
356
+ const match = OgcOpenApiGetCapabilities.matchTileMatrixSet(identified, tileMatrixSets);
357
+ if (match)
358
+ return match;
359
+ if (!identified.tilingSchemeHref) {
360
+ throw { error: true, message: "No tile matrix set for " + (identified.tileMatrixSetURI || identified.href) };
361
+ }
362
+ return OgcOpenApiGetCapabilities.fetchTileset(capabilities, { id: identified.tileMatrixSetId, title: "", links: [{ rel: "self", type: "application/json", title: "", href: identified.tilingSchemeHref }] }, options);
363
+ }
364
+ // What identifies the tile matrix set in a tileset: its URI, its id or its tiling-scheme link
365
+ static async fetchTileSetIdentity(capabilities, href, options) {
366
+ const data = await OgcOpenApiGetCapabilities.fetchJson(capabilities, href, options);
367
+ return {
368
+ tileMatrixSetURI: data.tileMatrixSetURI,
369
+ tileMatrixSetId: data.tileMatrixSetId,
370
+ tilingSchemeHref: OgcOpenApiGetCapabilities.getTilingSchemeHref(capabilities, data.links ? data.links : [], href),
371
+ tileMatrixSet: OgcOpenApiGetCapabilities.getInlineTileMatrixSet(data),
372
+ };
373
+ }
374
+ // A tileset can include the definition of its tile matrix set instead of linking it
375
+ static getInlineTileMatrixSet(tileSet) {
376
+ const tileMatrixSet = tileSet ? tileSet.tileMatrixSet : undefined;
377
+ return tileMatrixSet && typeof tileMatrixSet.id !== "undefined" && Array.isArray(tileMatrixSet.tileMatrices) && tileMatrixSet.crs ?
378
+ tileMatrixSet : undefined;
379
+ }
380
+ /**
381
+ * Fetches the tileset of a collection for one tile matrix set: the tile URL templates (rel item) and, for vector
382
+ * tiles, the layers contained in each tile.
383
+ */
384
+ static async fetchCollectionTileSet(capabilities,
385
+ // null for a tileset of the dataset
386
+ currentCollection,
387
+ // The id of the tile matrix set, or a tileset from fetchCollectionTileSets or fetchDatasetTileSets
388
+ tileMatrix, options, linkType = CollectionLinkType.Tiles) {
389
+ if (capabilities === null)
390
+ throw { error: true, message: "No capabilities" };
391
+ const tileSetsHref = currentCollection ?
392
+ OgcOpenApiGetCapabilities.getTileSetsHref(currentCollection, linkType) :
393
+ OgcOpenApiGetCapabilities.getDatasetTileSetsHref(capabilities, linkType);
394
+ const tileInfoUrl = typeof tileMatrix === "string" ? OgcOpenApiFetchTools.cleanUrl(tileSetsHref) + tileMatrix : tileMatrix.href;
395
+ // pygeoapi answers 500 without f=json or an Accept header
396
+ const data = await OgcOpenApiGetCapabilities.fetchJson(capabilities, tileInfoUrl, options);
397
+ const links = data.links ? data.links.filter(l => l.rel === "item" || l.rel === "items").map(a => ({ ...a, href: OgcOpenApiFetchTools.resolveUrl(a.href, tileInfoUrl, capabilities.serverOptions) })) : [];
398
+ if (links.length === 0)
399
+ throw { error: true, message: "Invalid" };
400
+ return {
401
+ dataType: data.dataType,
402
+ links,
403
+ layers: data.layers ? data.layers : [],
404
+ tileMatrixSetLimits: data.tileMatrixSetLimits,
405
+ boundingBox: data.boundingBox && Array.isArray(data.boundingBox.lowerLeft) && Array.isArray(data.boundingBox.upperRight) ? data.boundingBox : undefined,
406
+ };
407
+ }
408
+ /**
409
+ * Fetches the definition of a tile matrix set, by its JSON link as the server gives it: with the query that tells
410
+ * the server to answer JSON (f=json), if it has one.
411
+ */
412
+ static async fetchTileset(capabilities, tileset, options) {
413
+ if (capabilities === null)
414
+ throw { error: true, message: "No capabilities" };
415
+ const jsonLink = tileset.links.find(l => l.type === "application/json") || tileset.links.find(l => !l.type) || tileset.links[0];
416
+ if (!jsonLink)
417
+ throw { error: true, message: "Tile matrix set " + tileset.id + " has no link" };
418
+ const data = await OgcOpenApiGetCapabilities.fetchJson(capabilities, jsonLink.href, options);
419
+ if (typeof data.id === "undefined" || !data.tileMatrices || !data.crs)
420
+ throw { error: true, message: "TileSet has invalid data" };
421
+ return data;
422
+ }
423
+ }
424
+ //# sourceMappingURL=OgcOpenApiGetCapabilities.js.map