@radiantearth/stac-migrate 1.5.0 → 2.0.0-beta.1

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 (3) hide show
  1. package/README.md +68 -66
  2. package/migrate.js +996 -886
  3. package/package.json +43 -39
package/migrate.js CHANGED
@@ -4,977 +4,1087 @@
4
4
 
5
5
  var compareVersions = require('compare-versions');
6
6
 
7
- const LATEST_VERSION = '1.0.0';
7
+ const LATEST_VERSION = '1.1.0-beta.1';
8
8
  const DONE = true; // This is used to verify in code coverage whether something has been used or not
9
9
  const SCHEMAS = {
10
- 'classification': 'https://stac-extensions.github.io/classification/v1.1.0/schema.json',
11
- 'datacube': 'https://stac-extensions.github.io/datacube/v2.1.0/schema.json',
12
- 'eo': 'https://stac-extensions.github.io/eo/v1.0.0/schema.json',
13
- 'file': 'https://stac-extensions.github.io/file/v1.0.0/schema.json',
14
- 'item-assets': 'https://stac-extensions.github.io/item-assets/v1.0.0/schema.json',
15
- 'label': 'https://stac-extensions.github.io/label/v1.0.1/schema.json',
16
- 'pointcloud': 'https://stac-extensions.github.io/pointcloud/v1.0.0/schema.json',
17
- 'processing': 'https://stac-extensions.github.io/processing/v1.1.0/schema.json',
18
- 'projection': 'https://stac-extensions.github.io/projection/v1.0.0/schema.json',
19
- 'raster': 'https://stac-extensions.github.io/raster/v1.1.0/schema.json',
20
- 'sar': 'https://stac-extensions.github.io/sar/v1.0.0/schema.json',
21
- 'sat': 'https://stac-extensions.github.io/sat/v1.0.0/schema.json',
22
- 'scientific': 'https://stac-extensions.github.io/scientific/v1.0.0/schema.json',
23
- 'table': 'https://stac-extensions.github.io/table/v1.2.0/schema.json',
24
- 'timestamps': 'https://stac-extensions.github.io/timestamps/v1.0.0/schema.json',
25
- 'version': 'https://stac-extensions.github.io/version/v1.0.0/schema.json',
26
- 'view': 'https://stac-extensions.github.io/view/v1.0.0/schema.json'
10
+ 'classification': 'https://stac-extensions.github.io/classification/v2.0.0/schema.json',
11
+ 'datacube': 'https://stac-extensions.github.io/datacube/v2.2.0/schema.json',
12
+ 'eo': 'https://stac-extensions.github.io/eo/v2.0.0-beta.1/schema.json',
13
+ 'file': 'https://stac-extensions.github.io/file/v2.1.0/schema.json',
14
+ 'item-assets': 'https://stac-extensions.github.io/item-assets/v1.0.0/schema.json',
15
+ 'label': 'https://stac-extensions.github.io/label/v1.0.1/schema.json',
16
+ 'pointcloud': 'https://stac-extensions.github.io/pointcloud/v1.0.0/schema.json',
17
+ 'processing': 'https://stac-extensions.github.io/processing/v1.2.0/schema.json',
18
+ 'projection': 'https://stac-extensions.github.io/projection/v2.0.0/schema.json',
19
+ 'raster': 'https://stac-extensions.github.io/raster/v2.0.0-beta.1/schema.json',
20
+ 'sar': 'https://stac-extensions.github.io/sar/v1.0.0/schema.json',
21
+ 'sat': 'https://stac-extensions.github.io/sat/v1.0.0/schema.json',
22
+ 'scientific': 'https://stac-extensions.github.io/scientific/v1.0.0/schema.json',
23
+ 'table': 'https://stac-extensions.github.io/table/v1.2.0/schema.json',
24
+ 'timestamps': 'https://stac-extensions.github.io/timestamps/v1.1.0/schema.json',
25
+ 'version': 'https://stac-extensions.github.io/version/v1.2.0/schema.json',
26
+ 'view': 'https://stac-extensions.github.io/view/v1.0.0/schema.json'
27
27
  };
28
28
  const EXTENSIONS = {
29
- // Add a : at the end to indicate it has a prefix, otherwise list all fields separately (see version extension for example).
30
- itemAndCollection: {
31
- // with prefix
32
- 'cube:': SCHEMAS.datacube,
33
- 'eo:': SCHEMAS.eo,
34
- 'file:': SCHEMAS.file,
35
- 'label:': SCHEMAS.label,
36
- 'pc:': SCHEMAS.pointcloud,
37
- 'processing:': SCHEMAS.processing,
38
- 'proj:': SCHEMAS.projection,
39
- 'raster:': SCHEMAS.raster,
40
- 'sar:': SCHEMAS.sar,
41
- 'sat:': SCHEMAS.sat,
42
- 'sci:': SCHEMAS.scientific,
43
- 'view:': SCHEMAS.view,
44
- // without prefix
45
- 'version': SCHEMAS.version,
46
- 'deprecated': SCHEMAS.version,
47
- 'published': SCHEMAS.timestamps,
48
- 'expires': SCHEMAS.timestamps,
49
- 'unpublished': SCHEMAS.timestamps
50
- },
51
- catalog: {
52
- // None yet
53
- },
54
- collection: {
55
- 'item_assets': SCHEMAS['item-assets']
56
- },
57
- item: {
58
- // None yet
59
- },
29
+ // Add a : at the end to indicate it has a prefix, otherwise list all fields separately (see version extension for example).
30
+ itemAndCollection: {
31
+ // with prefix
32
+ 'classification:': SCHEMAS.classification,
33
+ 'cube:': SCHEMAS.datacube,
34
+ 'eo:': SCHEMAS.eo,
35
+ 'file:': SCHEMAS.file,
36
+ 'label:': SCHEMAS.label,
37
+ 'pc:': SCHEMAS.pointcloud,
38
+ 'processing:': SCHEMAS.processing,
39
+ 'proj:': SCHEMAS.projection,
40
+ 'raster:': SCHEMAS.raster,
41
+ 'sar:': SCHEMAS.sar,
42
+ 'sat:': SCHEMAS.sat,
43
+ 'sci:': SCHEMAS.scientific,
44
+ 'view:': SCHEMAS.view,
45
+ // without prefix
46
+ 'version': SCHEMAS.version,
47
+ 'deprecated': SCHEMAS.version,
48
+ 'published': SCHEMAS.timestamps,
49
+ 'expires': SCHEMAS.timestamps,
50
+ 'unpublished': SCHEMAS.timestamps
51
+ },
52
+ catalog: {
53
+ // None yet
54
+ },
55
+ collection: {
56
+ // None yet
57
+ },
58
+ item: {
59
+ // None yet
60
+ },
60
61
  };
61
62
  EXTENSIONS.collection = Object.assign(EXTENSIONS.collection, EXTENSIONS.itemAndCollection);
62
63
  EXTENSIONS.item = Object.assign(EXTENSIONS.item, EXTENSIONS.itemAndCollection);
63
64
 
64
65
  var Ext = {
65
- parseUrl(url) {
66
- let match = url.match(/^https?:\/\/stac-extensions.github.io\/([^\/]+)\/v([^\/]+)\/[^.]+.json$/i);
67
- if (match) {
68
- return {
69
- id: match[1],
70
- version: match[2]
71
- };
72
- }
73
- }
66
+ parseUrl(url) {
67
+ let match = url.match(/^https?:\/\/stac-extensions.github.io\/([^\/]+)\/v([^\/]+)\/[^.]+.json$/i);
68
+ if (match) {
69
+ return {
70
+ id: match[1],
71
+ version: match[2]
72
+ };
73
+ }
74
+ }
74
75
  };
75
76
 
76
77
  var V = {
77
- version: LATEST_VERSION,
78
- extensions: {},
79
-
80
- set(stac) {
81
- if (typeof stac.stac_version !== 'string') {
82
- V.version = '0.6.0'; // Assume the worst case, it doesn't seem there's a clear indicator for 0.7.0
83
- }
84
- else {
85
- V.version = stac.stac_version;
86
- }
87
-
88
- if (Array.isArray(stac.stac_extensions)) {
89
- for(let ext of stac.stac_extensions) {
90
- let e = Ext.parseUrl(ext);
91
- if (e) {
92
- V.extensions[e.id] = e.version;
93
- }
94
- }
95
- }
96
- },
97
-
98
- before(version, ext = null) {
99
- let compareTo = ext ? V.extensions[ext] : V.version;
100
- if (typeof compareTo === 'undefined') {
101
- return false;
102
- }
103
- else {
104
- return compareVersions.compare(compareTo, version, '<');
105
- }
106
- }
78
+ version: LATEST_VERSION,
79
+ extensions: {},
80
+
81
+ set(stac) {
82
+ if (typeof stac.stac_version !== 'string') {
83
+ V.version = '0.6.0'; // Assume the worst case, it doesn't seem there's a clear indicator for 0.7.0
84
+ }
85
+ else {
86
+ V.version = stac.stac_version;
87
+ }
88
+
89
+ if (Array.isArray(stac.stac_extensions)) {
90
+ for (let ext of stac.stac_extensions) {
91
+ let e = Ext.parseUrl(ext);
92
+ if (e) {
93
+ V.extensions[e.id] = e.version;
94
+ }
95
+ }
96
+ }
97
+ },
98
+
99
+ before(version, ext = null) {
100
+ return V.compare('<', version, ext);
101
+ },
102
+
103
+ compare(comparator, version, ext = null) {
104
+ let compareTo = ext ? V.extensions[ext] : V.version;
105
+ if (typeof compareTo === 'undefined') {
106
+ return false;
107
+ }
108
+ else {
109
+ return compareVersions.compare(compareTo, version, comparator);
110
+ }
111
+ }
112
+
107
113
  };
108
114
 
109
115
  var _ = {
110
116
 
111
- type(val) {
112
- let type = typeof val;
113
- if (type === 'object') {
114
- if (val === null) {
115
- return 'null';
116
- }
117
- else if (Array.isArray(val)) {
118
- return 'array';
119
- }
120
- }
121
- return type;
122
- },
123
-
124
- is(val, type) {
125
- return (_.type(val) === type);
126
- },
127
-
128
- isDefined(val) {
129
- return (typeof val !== 'undefined');
130
- },
131
-
132
- isObject(obj) {
133
- return (typeof obj === 'object' && obj === Object(obj) && !Array.isArray(obj));
134
- },
135
-
136
- rename(obj, oldKey, newKey) {
137
- if (typeof obj[oldKey] !== 'undefined' && typeof obj[newKey] === 'undefined') {
138
- obj[newKey] = obj[oldKey];
139
- delete obj[oldKey];
140
- return true;
141
- }
142
- return false;
143
- },
144
-
145
- forAll(obj, key, fn) {
146
- if (obj[key] && typeof obj[key] === 'object') {
147
- for(let i in obj[key]) {
148
- fn(obj[key][i]);
149
- }
150
- }
151
- },
152
-
153
- toArray(obj, key) {
154
- if (typeof obj[key] !== 'undefined' && !Array.isArray(obj[key])) {
155
- obj[key] = [obj[key]];
156
- return true;
157
- }
158
- return false;
159
- },
160
-
161
- flattenArray(obj, key, newKeys, summary = false) {
162
- if (Array.isArray(obj[key])) {
163
- for(let i in obj[key]) {
164
- if (typeof newKeys[i] === 'string') {
165
- let value = obj[key][i];
166
- obj[newKeys[i]] = summary ? [value] : value;
167
- }
168
- }
169
- delete obj[key];
170
- return true;
171
- }
172
- return false;
173
- },
174
-
175
- flattenOneElementArray(obj, key, summary = false) {
176
- if (!summary && Array.isArray(obj[key])) {
177
- if (obj[key].length === 1) {
178
- obj[key] = obj[key][0];
179
- return true;
180
- }
181
- else {
182
- return false; // It's still an array and we don't know which element to choose
183
- }
184
- }
185
- return true; // It's already a single element
186
- },
187
-
188
- removeFromArray(obj, key, valueToRemove) {
189
- if (Array.isArray(obj[key])) {
190
- let index = obj[key].indexOf(valueToRemove);
191
- if (index > -1) {
192
- obj[key].splice(index, 1);
193
- }
194
- return true;
195
- }
196
- return false;
197
- },
198
-
199
- ensure(obj, key, defaultValue) {
200
- if (_.type(defaultValue) !== _.type(obj[key])) {
201
- obj[key] = defaultValue;
202
- }
203
- return true;
204
- },
205
-
206
- upgradeExtension(context, extension) {
207
- let {id, version} = Ext.parseUrl(extension);
208
- let index = context.stac_extensions.findIndex(url => {
209
- let old = Ext.parseUrl(url);
210
- return (old && old.id === id && compareVersions.compare(old.version, version, '<'));
211
- });
212
- if (index !== -1) {
213
- context.stac_extensions[index] = extension;
214
- return true;
215
- }
216
- else {
217
- return false;
218
- }
219
- },
220
-
221
- addExtension(context, newExtension) {
222
- let {id, version} = Ext.parseUrl(newExtension);
223
- let index = context.stac_extensions.findIndex(url => {
224
- if (url === newExtension) {
225
- return true;
226
- }
227
- let old = Ext.parseUrl(url);
228
- if (old && old.id === id && compareVersions.compare(old.version, version, '<')) {
229
- return true;
230
- }
231
- return false;
232
- });
233
- if (index === -1) {
234
- context.stac_extensions.push(newExtension);
235
- }
236
- else {
237
- context.stac_extensions[index] = newExtension;
238
- }
239
-
240
- context.stac_extensions.sort();
241
- return true;
242
- },
243
-
244
- removeExtension(context, oldExtension) {
245
- return _.removeFromArray(context, 'stac_extensions', oldExtension);
246
- },
247
-
248
- migrateExtensionShortnames(context) {
249
- let oldShortnames = Object.keys(SCHEMAS);
250
- let newSchemas = Object.values(SCHEMAS);
251
- return _.mapValues(context, 'stac_extensions', oldShortnames, newSchemas);
252
- },
253
-
254
- populateExtensions(context, type) {
255
- let objectsToCheck = [];
256
- if (type == 'catalog' || type == 'collection') {
257
- objectsToCheck.push(context);
258
- }
259
- if ((type == 'item' || type == 'collection') && _.isObject(context.assets)) {
260
- objectsToCheck = objectsToCheck.concat(Object.values(context.assets));
261
- }
262
- if (type == 'collection' && _.isObject(context.item_assets)) {
263
- objectsToCheck = objectsToCheck.concat(Object.values(context.item_assets));
264
- }
265
- if (type == 'collection' && _.isObject(context.summaries)) {
266
- objectsToCheck.push(context.summaries);
267
- }
268
- if (type == 'item' && _.isObject(context.properties)) {
269
- objectsToCheck.push(context.properties);
270
- }
271
-
272
- for (let obj of objectsToCheck) {
273
- Object.keys(obj).forEach(key => {
274
- let prefix = key.match(/^(\w+:|[^:]+$)/i);
275
- if (Array.isArray(prefix)) {
276
- let ext = EXTENSIONS[type][prefix[0]];
277
- _.is(ext, 'string') && _.addExtension(context, ext) && DONE;
278
- }
279
- });
280
- }
281
- },
282
-
283
- mapValues(obj, key, oldValues, newValues) {
284
- let fn = value => {
285
- let index = oldValues.indexOf(value);
286
- if (index >= 0) {
287
- return newValues[index];
288
- }
289
- return value;
290
- };
291
- if (Array.isArray(obj[key])) {
292
- obj[key] = obj[key].map(fn);
293
- }
294
- else if (typeof obj[key] !== 'undefined') {
295
- obj[key] = fn(obj[key]);
296
- }
297
- return true;
298
- },
299
-
300
- mapObject(obj, fn) {
301
- for(let key in obj) {
302
- obj[key] = fn(obj[key], key);
303
- }
304
- },
305
-
306
- moveTo(obj, key, context, fromSummary = false, mergedSummary = false) {
307
- let condition;
308
- if (fromSummary) {
309
- if (mergedSummary) {
310
- condition = val => Array.isArray(val);
311
- }
312
- else {
313
- condition = val => Array.isArray(val) && val.length === 1;
314
- }
315
- }
316
- else {
317
- condition = _.isDefined
318
- }
319
- if (condition(obj[key])) {
320
- context[key] = fromSummary && !mergedSummary ? obj[key][0] : obj[key];
321
- delete obj[key];
322
- return true;
323
- }
324
- return false;
325
- },
326
-
327
- runAll(migrations, obj, context, summaries) {
328
- for(let fn in migrations) {
329
- if (!fn.startsWith('migrate')) {
330
- migrations[fn](obj, context, summaries);
331
- }
332
- }
333
- },
334
-
335
- toUTC(obj, key) {
336
- if (typeof obj[key] === 'string') {
337
- try {
338
- obj[key] = this.toISOString(obj[key]);
339
- return true;
340
- } catch(error) {}
341
- }
342
- delete obj[key];
343
- return false;
344
- },
345
-
346
- toISOString(date) {
347
- if (!(date instanceof Date)) {
348
- date = new Date(date);
349
- }
350
- return date.toISOString().replace('.000', ''); // Don't export milliseconds if not needed
351
- }
117
+ type(val) {
118
+ let type = typeof val;
119
+ if (type === 'object') {
120
+ if (val === null) {
121
+ return 'null';
122
+ }
123
+ else if (Array.isArray(val)) {
124
+ return 'array';
125
+ }
126
+ }
127
+ return type;
128
+ },
129
+
130
+ is(val, type) {
131
+ if (Array.isArray(type)) {
132
+ return type.includes(_.type(val));
133
+ }
134
+ else {
135
+ return _.type(val) === type;
136
+ }
137
+ },
138
+
139
+ isDefined(val) {
140
+ return (typeof val !== 'undefined');
141
+ },
142
+
143
+ isObject(obj) {
144
+ return (typeof obj === 'object' && obj === Object(obj) && !Array.isArray(obj));
145
+ },
146
+
147
+ rename(obj, oldKey, newKey) {
148
+ if (typeof obj[oldKey] !== 'undefined' && typeof obj[newKey] === 'undefined') {
149
+ obj[newKey] = obj[oldKey];
150
+ delete obj[oldKey];
151
+ return true;
152
+ }
153
+ return false;
154
+ },
155
+
156
+ copy(obj, oldKey, newKey) {
157
+ if (typeof obj[oldKey] !== 'undefined' && typeof obj[newKey] === 'undefined') {
158
+ obj[newKey] = obj[oldKey];
159
+ return true;
160
+ }
161
+ return false;
162
+ },
163
+
164
+ forAll(obj, key, fn) {
165
+ if (obj[key] && typeof obj[key] === 'object') {
166
+ for (let i in obj[key]) {
167
+ fn(obj[key][i]);
168
+ }
169
+ }
170
+ },
171
+
172
+ toArray(obj, key) {
173
+ if (typeof obj[key] !== 'undefined' && !Array.isArray(obj[key])) {
174
+ obj[key] = [obj[key]];
175
+ return true;
176
+ }
177
+ return false;
178
+ },
179
+
180
+ flattenArray(obj, key, newKeys, summary = false) {
181
+ if (Array.isArray(obj[key])) {
182
+ for (let i in obj[key]) {
183
+ if (typeof newKeys[i] === 'string') {
184
+ let value = obj[key][i];
185
+ obj[newKeys[i]] = summary ? [value] : value;
186
+ }
187
+ }
188
+ delete obj[key];
189
+ return true;
190
+ }
191
+ return false;
192
+ },
193
+
194
+ flattenOneElementArray(obj, key, summary = false) {
195
+ if (!summary && Array.isArray(obj[key])) {
196
+ if (obj[key].length === 1) {
197
+ obj[key] = obj[key][0];
198
+ return true;
199
+ }
200
+ else {
201
+ return false; // It's still an array and we don't know which element to choose
202
+ }
203
+ }
204
+ return true; // It's already a single element
205
+ },
206
+
207
+ removeFromArray(obj, key, valueToRemove) {
208
+ if (Array.isArray(obj[key])) {
209
+ let index = obj[key].indexOf(valueToRemove);
210
+ if (index > -1) {
211
+ obj[key].splice(index, 1);
212
+ }
213
+ return true;
214
+ }
215
+ return false;
216
+ },
217
+
218
+ pickFirst(obj, key) {
219
+ if (Array.isArray(obj[key]) && obj[key].length > 0) {
220
+ obj[key] = obj[key][0];
221
+ return true;
222
+ }
223
+ else {
224
+ delete obj[key];
225
+ return false;
226
+ }
227
+ },
228
+
229
+ ensure(obj, key, defaultValue) {
230
+ if (_.type(defaultValue) !== _.type(obj[key])) {
231
+ obj[key] = defaultValue;
232
+ }
233
+ return true;
234
+ },
235
+
236
+ upgradeExtension(context, extension) {
237
+ let { id, version } = Ext.parseUrl(extension);
238
+ let index = context.stac_extensions.findIndex(url => {
239
+ let old = Ext.parseUrl(url);
240
+ return (old && old.id === id && compareVersions.compare(old.version, version, '<'));
241
+ });
242
+ if (index !== -1) {
243
+ context.stac_extensions[index] = extension;
244
+ return true;
245
+ }
246
+ else {
247
+ return false;
248
+ }
249
+ },
250
+
251
+ addExtension(context, newExtension) {
252
+ let { id, version } = Ext.parseUrl(newExtension);
253
+ let index = context.stac_extensions.findIndex(url => {
254
+ if (url === newExtension) {
255
+ return true;
256
+ }
257
+ let old = Ext.parseUrl(url);
258
+ if (old && old.id === id && compareVersions.compare(old.version, version, '<')) {
259
+ return true;
260
+ }
261
+ return false;
262
+ });
263
+ if (index === -1) {
264
+ context.stac_extensions.push(newExtension);
265
+ }
266
+ else {
267
+ context.stac_extensions[index] = newExtension;
268
+ }
269
+
270
+ context.stac_extensions.sort();
271
+ return true;
272
+ },
273
+
274
+ removeExtension(context, oldExtension) {
275
+ return _.removeFromArray(context, 'stac_extensions', oldExtension);
276
+ },
277
+
278
+ migrateExtensionShortnames(context) {
279
+ let oldShortnames = Object.keys(SCHEMAS);
280
+ let newSchemas = Object.values(SCHEMAS);
281
+ return _.mapValues(context, 'stac_extensions', oldShortnames, newSchemas);
282
+ },
283
+
284
+ populateExtensions(context, type) {
285
+ let objectsToCheck = [];
286
+ if (type == 'catalog' || type == 'collection') {
287
+ objectsToCheck.push(context);
288
+ }
289
+ if ((type == 'item' || type == 'collection') && _.isObject(context.assets)) {
290
+ objectsToCheck = objectsToCheck.concat(Object.values(context.assets));
291
+ }
292
+ if (type == 'collection' && _.isObject(context.item_assets)) {
293
+ objectsToCheck = objectsToCheck.concat(Object.values(context.item_assets));
294
+ }
295
+ if (type == 'collection' && _.isObject(context.summaries)) {
296
+ objectsToCheck.push(context.summaries);
297
+ }
298
+ if (type == 'item' && _.isObject(context.properties)) {
299
+ objectsToCheck.push(context.properties);
300
+ }
301
+ objectsToCheck.push(context.links);
302
+
303
+ let obj;
304
+ while(obj = objectsToCheck.pop()) {
305
+ Object.keys(obj).forEach(key => {
306
+ // Add additional objects to check
307
+ if (Array.isArray(obj.bands)) {
308
+ objectsToCheck = objectsToCheck.concat(obj.bands);
309
+ }
310
+
311
+ // Check for fields with extension prefixes
312
+ let prefix = key.match(/^(\w+:|[^:]+$)/i);
313
+ if (Array.isArray(prefix)) {
314
+ let ext = EXTENSIONS[type][prefix[0]];
315
+ _.is(ext, 'string') && _.addExtension(context, ext) && DONE;
316
+ }
317
+ });
318
+ }
319
+ },
320
+
321
+ mapValues(obj, key, oldValues, newValues) {
322
+ let fn = value => {
323
+ let index = oldValues.indexOf(value);
324
+ if (index >= 0) {
325
+ return newValues[index];
326
+ }
327
+ return value;
328
+ };
329
+ if (Array.isArray(obj[key])) {
330
+ obj[key] = obj[key].map(fn);
331
+ }
332
+ else if (typeof obj[key] !== 'undefined') {
333
+ obj[key] = fn(obj[key]);
334
+ }
335
+ return true;
336
+ },
337
+
338
+ mapObject(obj, fn) {
339
+ for (let key in obj) {
340
+ obj[key] = fn(obj[key], key);
341
+ }
342
+ },
343
+
344
+ moveTo(obj, key, context, fromSummary = false, mergedSummary = false) {
345
+ let condition;
346
+ if (fromSummary) {
347
+ if (mergedSummary) {
348
+ condition = val => Array.isArray(val);
349
+ }
350
+ else {
351
+ condition = val => Array.isArray(val) && val.length === 1;
352
+ }
353
+ }
354
+ else {
355
+ condition = _.isDefined
356
+ }
357
+ if (condition(obj[key])) {
358
+ context[key] = fromSummary && !mergedSummary ? obj[key][0] : obj[key];
359
+ delete obj[key];
360
+ return true;
361
+ }
362
+ return false;
363
+ },
364
+
365
+ runAll(migrations, obj, context, summaries) {
366
+ for (let fn in migrations) {
367
+ if (!fn.startsWith('migrate')) {
368
+ migrations[fn](obj, context, summaries);
369
+ }
370
+ }
371
+ },
372
+
373
+ toUTC(obj, key) {
374
+ if (_.is(obj[key], 'string')) {
375
+ try {
376
+ obj[key] = this.toISOString(obj[key]);
377
+ return true;
378
+ } catch (error) { }
379
+ }
380
+ delete obj[key];
381
+ return false;
382
+ },
383
+
384
+ toISOString(date) {
385
+ if (!(date instanceof Date)) {
386
+ date = new Date(date);
387
+ }
388
+ return date.toISOString().replace(/\.0+/, ''); // Don't export milliseconds if not needed
389
+ },
390
+
391
+ formatString(obj, key, format) {
392
+ const formatter = value => {
393
+ if (_.is(value, ['string', 'number'])) {
394
+ return format.replaceAll('{}', value);
395
+ }
396
+ return value;
397
+ };
398
+ if (Array.isArray(obj[key])) {
399
+ obj[key] = obj[key].map(formatter);
400
+ }
401
+ else {
402
+ obj[key] = formatter(obj[key]);
403
+ }
404
+ }
352
405
 
353
406
  };
354
407
 
355
408
  var Checksum = {
356
409
 
357
- multihash: null,
358
-
359
- hexToUint8(hexString) {
360
- if(hexString.length === 0 || hexString.length % 2 !== 0){
361
- throw new Error(`The string "${hexString}" is not valid hex.`)
362
- }
363
- return new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
364
- },
365
-
366
- uint8ToHex(bytes) {
367
- return bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
368
- },
369
-
370
- toMultihash(obj, key, algo) {
371
- if (!Checksum.multihash || !_.is(obj[key], 'string')) {
372
- return false;
373
- }
374
- try {
375
- const encoded = Checksum.multihash.encode(Checksum.hexToUint8(obj[key]), algo);
376
- obj[key] = Checksum.uint8ToHex(encoded);
377
- return true;
378
- } catch (error) {
379
- console.warn(error);
380
- return false;
381
- }
382
- }
410
+ multihash: null,
411
+
412
+ hexToUint8(hexString) {
413
+ if (hexString.length === 0 || hexString.length % 2 !== 0) {
414
+ throw new Error(`The string "${hexString}" is not valid hex.`)
415
+ }
416
+ return new Uint8Array(hexString.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
417
+ },
418
+
419
+ uint8ToHex(bytes) {
420
+ return bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
421
+ },
422
+
423
+ toMultihash(obj, key, algo) {
424
+ if (!Checksum.multihash || !_.is(obj[key], 'string')) {
425
+ return false;
426
+ }
427
+ try {
428
+ const encoded = Checksum.multihash.encode(Checksum.hexToUint8(obj[key]), algo);
429
+ obj[key] = Checksum.uint8ToHex(encoded);
430
+ return true;
431
+ } catch (error) {
432
+ console.warn(error);
433
+ return false;
434
+ }
435
+ }
383
436
 
384
437
  };
385
438
 
386
439
  var Catalog = {
387
440
 
388
- migrate(catalog, updateVersionNumber = true) {
389
- V.set(catalog);
390
- if (updateVersionNumber) {
391
- catalog.stac_version = LATEST_VERSION;
392
- }
393
- catalog.type = 'Catalog';
394
-
395
- _.ensure(catalog, 'stac_extensions', []) && DONE;
396
- V.before('1.0.0-rc.1') && _.migrateExtensionShortnames(catalog) && DONE;
441
+ migrate(catalog, updateVersionNumber = true) {
442
+ V.set(catalog);
443
+ if (updateVersionNumber) {
444
+ catalog.stac_version = LATEST_VERSION;
445
+ }
446
+ catalog.type = 'Catalog';
397
447
 
398
- _.ensure(catalog, 'id', '') && DONE;
399
- _.ensure(catalog, 'description', '') && DONE;
400
- _.ensure(catalog, 'links', []) && DONE;
448
+ _.ensure(catalog, 'stac_extensions', []) && DONE;
449
+ V.before('1.0.0-rc.1') && _.migrateExtensionShortnames(catalog) && DONE;
401
450
 
402
- _.runAll(Catalog, catalog, catalog);
451
+ _.ensure(catalog, 'id', '') && DONE;
452
+ _.ensure(catalog, 'description', '') && DONE;
453
+ _.ensure(catalog, 'links', []) && DONE;
403
454
 
404
- V.before('0.8.0') && _.populateExtensions(catalog, 'catalog') && DONE;
455
+ _.runAll(Catalog, catalog, catalog);
405
456
 
406
- return catalog;
407
- },
457
+ V.before('0.8.0') && _.populateExtensions(catalog, 'catalog') && DONE;
408
458
 
409
- openeo(obj) {
410
- _.rename(obj, 'api_version', 'openeo:api_version') && DONE;
411
- _.rename(obj, 'backend_version', 'openeo:backend_version') && DONE;
412
- _.rename(obj, 'production', 'openeo:production') && DONE;
413
- _.rename(obj, 'endpoints', 'openeo:endpoints') && DONE;
414
- _.rename(obj, 'billing', 'openeo:billing') && DONE;
415
- },
459
+ return catalog;
460
+ },
416
461
 
417
462
  };
418
463
 
419
464
  var Collection = {
420
465
 
421
- migrate(collection, updateVersionNumber = true) {
422
- Catalog.migrate(collection, updateVersionNumber); // Migrates stac_version, stac_extensions, id, title, description, links
423
- collection.type = 'Collection';
424
-
425
- V.before('1.0.0-rc.1') && _.migrateExtensionShortnames(collection) && DONE;
426
-
427
- _.ensure(collection, 'license', 'proprietary') && DONE;
428
- _.ensure(collection, 'extent', {
429
- spatial: {
430
- bbox: []
431
- },
432
- temporal: {
433
- interval: []
434
- }
435
- }) && DONE;
436
-
437
- _.runAll(Collection, collection, collection);
438
-
439
- // Migrate Commons extension - part 3
440
- if (_.isObject(collection.properties)) {
441
- _.removeFromArray(collection, 'stac_extensions', 'commons') && DONE;
442
- delete collection.properties;
443
- }
444
-
445
- V.before('0.8.0') && _.populateExtensions(collection, 'collection') && DONE;
446
- V.before('1.0.0-beta.1') && _.mapValues(collection, 'stac_extensions', ['assets'], ['item-assets']) && DONE;
447
-
448
- return collection;
449
- },
450
-
451
- extent(collection) {
452
- _.ensure(collection, "extent", {});
453
-
454
- if (V.before('0.8.0')) {
455
- // Restructure spatial extent
456
- if (Array.isArray(collection.extent.spatial)) {
457
- collection.extent.spatial = {
458
- bbox: [
459
- collection.extent.spatial
460
- ]
461
- };
462
- }
463
- // Restructure temporal extent
464
- if (Array.isArray(collection.extent.temporal)) {
465
- collection.extent.temporal = {
466
- interval: [
467
- collection.extent.temporal
468
- ]
469
- };
470
- }
471
- }
472
-
473
- _.ensure(collection.extent, "spatial", {});
474
- _.ensure(collection.extent.spatial, "bbox", []);
475
- _.ensure(collection.extent, "temporal", {});
476
- _.ensure(collection.extent.temporal, "interval", []);
477
-
478
- if (V.before('1.0.0-rc.3')) {
479
- // The first extent in a Collection is always the overall extent, followed by more specific extents.
480
- if (collection.extent.temporal.interval.length > 1) {
481
- let min, max;
482
- for(let interval of collection.extent.temporal.interval) {
483
- if (interval[0] === null) {
484
- min = null;
485
- }
486
- else if (typeof interval[0] === 'string' && min !== null) {
487
- try {
488
- let start = new Date(interval[0]);
489
- if (typeof min === 'undefined' || start < min) {
490
- min = start;
491
- }
492
- } catch (error) {}
493
- }
494
-
495
- if (interval[1] === null) {
496
- max = null;
497
- }
498
- else if (typeof interval[1] === 'string' && max !== null) {
499
- try {
500
- let end = new Date(interval[1]);
501
- if (typeof max === 'undefined' || end > max) {
502
- max = end;
503
- }
504
- } catch (error) {}
505
- }
506
- }
507
- collection.extent.temporal.interval.unshift([
508
- min ? _.toISOString(min) : null,
509
- max ? _.toISOString(max) : null
510
- ]);
511
- }
512
- if (collection.extent.spatial.bbox.length > 1) {
513
- let count = collection.extent.spatial.bbox.reduce((val, bbox) => Array.isArray(bbox) ? Math.max(bbox.length, val) : val, 4);
514
- if (count >= 4) {
515
- let union = new Array(count).fill(null);
516
- let middle = count / 2;
517
- for(let bbox of collection.extent.spatial.bbox) {
518
- if (!Array.isArray(bbox) || bbox.length < 4) {
519
- break;
520
- }
521
- for(let i in bbox) {
522
- let c = bbox[i];
523
- if (union[i] === null) {
524
- union[i] = c;
525
- }
526
- else if (i < middle) {
527
- union[i] = Math.min(c, union[i]);
528
- }
529
- else {
530
- union[i] = Math.max(c, union[i]);
531
- }
532
-
533
- }
534
- }
535
- if (union.findIndex(c => c === null) === -1) {
536
- collection.extent.spatial.bbox.unshift(union);
537
- }
538
- }
539
- }
540
- }
541
- },
542
-
543
- collectionAssets(collection) {
544
- V.before('1.0.0-rc.1') && _.removeExtension(collection, 'collection-assets') && DONE;
545
-
546
- Asset.migrateAll(collection);
547
- },
548
-
549
- itemAsset(collection) {
550
- V.before('1.0.0-beta.2') && _.rename(collection, 'item_assets', 'assets');
551
-
552
- Asset.migrateAll(collection, 'item_assets');
553
- },
554
-
555
- summaries(collection) {
556
- _.ensure(collection, 'summaries', {});
557
-
558
- // other_properties: An early version of the Collection summaries with a similar structure
559
- // Was mostly used in standalone collctions from openEO and GEE. Move other_properties to summaries.
560
- if (V.before('0.8.0') && _.isObject(collection.other_properties)) {
561
- for(let key in collection.other_properties) {
562
- let prop = collection.other_properties[key];
563
- if (Array.isArray(prop.extent) && prop.extent.length === 2) {
564
- collection.summaries[key] = {
565
- minimum: prop.extent[0],
566
- maximum: prop.extent[1],
567
- };
568
- }
569
- else if (Array.isArray(prop.values)) {
570
- if (prop.values.filter(v => Array.isArray(v)).length === prop.values.length) {
571
- // If it is an array of arrays, merge the arrays
572
- collection.summaries[key] = prop.values.reduce((a, b) => a.concat(b), []);
573
- }
574
- else {
575
- collection.summaries[key] = prop.values;
576
- }
577
- }
578
- }
579
- delete collection.other_properties;
580
- }
581
-
582
- // Migrate Commons extension - part 2
583
- // Move properties to (single element) summaries if the Collection is standalone
584
- // see also https://github.com/stac-utils/stac-migrate/issues/3
585
- if (V.before('1.0.0-beta.1') && _.isObject(collection.properties) && !collection.links.find(link => ['child', 'item'].includes(link.rel))) {
586
- for(let key in collection.properties) {
587
- let value = collection.properties[key];
588
- if (!Array.isArray(value)) {
589
- value = [value];
590
- }
591
- collection.summaries[key] = value;
592
- }
593
- }
594
-
595
- if (V.before('1.0.0-rc.1')) {
596
- _.mapObject(collection.summaries, val => {
597
- _.rename(val, 'min', 'minimum') && DONE;
598
- _.rename(val, 'max', 'maximum') && DONE;
599
- return val;
600
- });
601
- }
602
-
603
- // now we can work on all summaries and migrate them
604
- Fields.migrate(collection.summaries, collection, true);
605
-
606
- // Some fields should usually be on root-level if there's only one element
607
- _.moveTo(collection.summaries, 'sci:doi', collection, true) && _.addExtension(collection, SCHEMAS.scientific) && DONE;
608
- _.moveTo(collection.summaries, 'sci:publications', collection, true, true) && _.addExtension(collection, SCHEMAS.scientific) && DONE;
609
- _.moveTo(collection.summaries, 'sci:citation', collection, true) && _.addExtension(collection, SCHEMAS.scientific) && DONE;
610
- _.moveTo(collection.summaries, 'cube:dimensions', collection, true) && _.addExtension(collection, SCHEMAS.datacube) && DONE;
611
-
612
- // Remove summary field if empty
613
- if (Object.keys(collection.summaries).length === 0) {
614
- delete collection.summaries;
615
- }
616
- }
466
+ migrate(collection, updateVersionNumber = true) {
467
+ Catalog.migrate(collection, updateVersionNumber); // Migrates stac_version, stac_extensions, id, title, description, links
468
+ collection.type = 'Collection';
469
+
470
+ V.before('1.0.0-rc.1') && _.migrateExtensionShortnames(collection) && DONE;
471
+
472
+ _.ensure(collection, 'license', 'other') && DONE;
473
+ _.ensure(collection, 'extent', {
474
+ spatial: {
475
+ bbox: []
476
+ },
477
+ temporal: {
478
+ interval: []
479
+ }
480
+ }) && DONE;
481
+
482
+ _.runAll(Collection, collection, collection);
483
+
484
+ // Migrate Commons extension - part 3
485
+ if (_.isObject(collection.properties)) {
486
+ _.removeFromArray(collection, 'stac_extensions', 'commons') && DONE;
487
+ delete collection.properties;
488
+ }
489
+
490
+ V.before('0.8.0') && _.populateExtensions(collection, 'collection') && DONE;
491
+ V.before('1.0.0-beta.1') && _.mapValues(collection, 'stac_extensions', ['assets'], ['item-assets']) && DONE;
492
+
493
+ return collection;
494
+ },
495
+
496
+ extent(collection) {
497
+ _.ensure(collection, "extent", {});
498
+
499
+ if (V.before('0.8.0')) {
500
+ // Restructure spatial extent
501
+ if (Array.isArray(collection.extent.spatial)) {
502
+ collection.extent.spatial = {
503
+ bbox: [
504
+ collection.extent.spatial
505
+ ]
506
+ };
507
+ }
508
+ // Restructure temporal extent
509
+ if (Array.isArray(collection.extent.temporal)) {
510
+ collection.extent.temporal = {
511
+ interval: [
512
+ collection.extent.temporal
513
+ ]
514
+ };
515
+ }
516
+ }
517
+
518
+ _.ensure(collection.extent, "spatial", {});
519
+ _.ensure(collection.extent.spatial, "bbox", []);
520
+ _.ensure(collection.extent, "temporal", {});
521
+ _.ensure(collection.extent.temporal, "interval", []);
522
+
523
+ if (V.before('1.0.0-rc.3')) {
524
+ // The first extent in a Collection is always the overall extent, followed by more specific extents.
525
+ if (collection.extent.temporal.interval.length > 1) {
526
+ let min, max;
527
+ for (let interval of collection.extent.temporal.interval) {
528
+ if (interval[0] === null) {
529
+ min = null;
530
+ }
531
+ else if (typeof interval[0] === 'string' && min !== null) {
532
+ try {
533
+ let start = new Date(interval[0]);
534
+ if (typeof min === 'undefined' || start < min) {
535
+ min = start;
536
+ }
537
+ } catch (error) { }
538
+ }
539
+
540
+ if (interval[1] === null) {
541
+ max = null;
542
+ }
543
+ else if (typeof interval[1] === 'string' && max !== null) {
544
+ try {
545
+ let end = new Date(interval[1]);
546
+ if (typeof max === 'undefined' || end > max) {
547
+ max = end;
548
+ }
549
+ } catch (error) { }
550
+ }
551
+ }
552
+ collection.extent.temporal.interval.unshift([
553
+ min ? _.toISOString(min) : null,
554
+ max ? _.toISOString(max) : null
555
+ ]);
556
+ }
557
+ if (collection.extent.spatial.bbox.length > 1) {
558
+ let count = collection.extent.spatial.bbox.reduce((val, bbox) => Array.isArray(bbox) ? Math.max(bbox.length, val) : val, 4);
559
+ if (count >= 4) {
560
+ let union = new Array(count).fill(null);
561
+ let middle = count / 2;
562
+ for (let bbox of collection.extent.spatial.bbox) {
563
+ if (!Array.isArray(bbox) || bbox.length < 4) {
564
+ break;
565
+ }
566
+ for (let i in bbox) {
567
+ let c = bbox[i];
568
+ if (union[i] === null) {
569
+ union[i] = c;
570
+ }
571
+ else if (i < middle) {
572
+ union[i] = Math.min(c, union[i]);
573
+ }
574
+ else {
575
+ union[i] = Math.max(c, union[i]);
576
+ }
577
+
578
+ }
579
+ }
580
+ if (union.findIndex(c => c === null) === -1) {
581
+ collection.extent.spatial.bbox.unshift(union);
582
+ }
583
+ }
584
+ }
585
+ }
586
+ },
587
+
588
+ collectionAssets(collection) {
589
+ V.before('1.0.0-rc.1') && _.removeExtension(collection, 'collection-assets') && DONE;
590
+
591
+ Asset.migrateAll(collection);
592
+ },
593
+
594
+ itemAsset(collection) {
595
+ V.before('1.0.0-beta.2') && _.rename(collection, 'item_assets', 'assets');
596
+
597
+ _.removeExtension(collection, SCHEMAS['item-assets']) && DONE;
598
+
599
+ Asset.migrateAll(collection, 'item_assets');
600
+ },
601
+
602
+ summaries(collection) {
603
+ _.ensure(collection, 'summaries', {});
604
+
605
+ // other_properties: An early version of the Collection summaries with a similar structure
606
+ // Was mostly used in standalone collections from openEO and GEE. Move other_properties to summaries.
607
+ if (V.before('0.8.0') && _.isObject(collection.other_properties)) {
608
+ for (let key in collection.other_properties) {
609
+ let prop = collection.other_properties[key];
610
+ if (Array.isArray(prop.extent) && prop.extent.length === 2) {
611
+ collection.summaries[key] = {
612
+ minimum: prop.extent[0],
613
+ maximum: prop.extent[1],
614
+ };
615
+ }
616
+ else if (Array.isArray(prop.values)) {
617
+ if (prop.values.filter(v => Array.isArray(v)).length === prop.values.length) {
618
+ // If it is an array of arrays, merge the arrays
619
+ collection.summaries[key] = prop.values.reduce((a, b) => a.concat(b), []);
620
+ }
621
+ else {
622
+ collection.summaries[key] = prop.values;
623
+ }
624
+ }
625
+ }
626
+ delete collection.other_properties;
627
+ }
628
+
629
+ // Migrate Commons extension - part 2
630
+ // Move properties to (single element) summaries if the Collection is standalone
631
+ // see also https://github.com/stac-utils/stac-migrate/issues/3
632
+ if (V.before('1.0.0-beta.1') && _.isObject(collection.properties) && !collection.links.find(link => ['child', 'item'].includes(link.rel))) {
633
+ for (let key in collection.properties) {
634
+ let value = collection.properties[key];
635
+ if (!Array.isArray(value)) {
636
+ value = [value];
637
+ }
638
+ collection.summaries[key] = value;
639
+ }
640
+ }
641
+
642
+ if (V.before('1.0.0-rc.1')) {
643
+ _.mapObject(collection.summaries, val => {
644
+ _.rename(val, 'min', 'minimum') && DONE;
645
+ _.rename(val, 'max', 'maximum') && DONE;
646
+ return val;
647
+ });
648
+ }
649
+
650
+ // now we can work on all summaries and migrate them
651
+ Fields.migrate(collection.summaries, collection, true);
652
+
653
+ // Some fields should usually be on root-level if there's only one element
654
+ _.moveTo(collection.summaries, 'sci:doi', collection, true) && _.addExtension(collection, SCHEMAS.scientific) && DONE;
655
+ _.moveTo(collection.summaries, 'sci:publications', collection, true, true) && _.addExtension(collection, SCHEMAS.scientific) && DONE;
656
+ _.moveTo(collection.summaries, 'sci:citation', collection, true) && _.addExtension(collection, SCHEMAS.scientific) && DONE;
657
+ _.moveTo(collection.summaries, 'cube:dimensions', collection, true) && _.addExtension(collection, SCHEMAS.datacube) && DONE;
658
+
659
+ // Remove summary field if empty
660
+ if (Object.keys(collection.summaries).length === 0) {
661
+ delete collection.summaries;
662
+ }
663
+ }
617
664
 
618
665
  };
619
666
 
620
667
  var Item = {
621
668
 
622
- migrate(item, collection = null, updateVersionNumber = true) {
623
- V.set(item);
624
- if (updateVersionNumber) {
625
- item.stac_version = LATEST_VERSION;
626
- }
627
-
628
- _.ensure(item, 'stac_extensions', []) && DONE;
629
- V.before('1.0.0-rc.1') && _.migrateExtensionShortnames(item) && DONE;
669
+ migrate(item, collection = null, updateVersionNumber = true) {
670
+ V.set(item);
671
+ if (updateVersionNumber) {
672
+ item.stac_version = LATEST_VERSION;
673
+ }
630
674
 
631
- _.ensure(item, 'id', '') && DONE;
632
- _.ensure(item, 'type', 'Feature') && DONE;
633
- if (!_.isObject(item.geometry)) {
634
- item.geometry = null;
635
- }
636
- if (item.geometry !== null) {
637
- _.ensure(item, 'bbox', []) && DONE;
638
- }
639
- _.ensure(item, 'properties', {}) && DONE;
640
- _.ensure(item, 'links', []) && DONE;
641
- _.ensure(item, 'assets', {}) && DONE;
675
+ _.ensure(item, 'stac_extensions', []) && DONE;
676
+ V.before('1.0.0-rc.1') && _.migrateExtensionShortnames(item) && DONE;
642
677
 
643
- // Migrate Commons extension - part 1
644
- let commons = false;
645
- if (_.isObject(collection) && _.isObject(collection.properties)) {
646
- _.removeFromArray(item, 'stac_extensions', 'commons');
647
- item.properties = Object.assign({}, collection.properties, item.properties);
648
- commons = true;
649
- }
678
+ _.ensure(item, 'id', '') && DONE;
679
+ _.ensure(item, 'type', 'Feature') && DONE;
680
+ if (!_.isObject(item.geometry)) {
681
+ item.geometry = null;
682
+ }
683
+ if (item.geometry !== null) {
684
+ _.ensure(item, 'bbox', []) && DONE;
685
+ }
686
+ _.ensure(item, 'properties', {}) && DONE;
687
+ _.ensure(item, 'links', []) && DONE;
688
+ _.ensure(item, 'assets', {}) && DONE;
689
+
690
+ // Migrate Commons extension - part 1
691
+ let commons = false;
692
+ if (_.isObject(collection) && _.isObject(collection.properties)) {
693
+ _.removeFromArray(item, 'stac_extensions', 'commons');
694
+ item.properties = Object.assign({}, collection.properties, item.properties);
695
+ commons = true;
696
+ }
650
697
 
651
- _.runAll(Item, item, item);
698
+ _.runAll(Item, item, item);
652
699
 
653
- Fields.migrate(item.properties, item);
700
+ Fields.migrate(item.properties, item);
654
701
 
655
- Asset.migrateAll(item);
702
+ Asset.migrateAll(item);
656
703
 
657
- // Also populate extensions if commons has been implemented
658
- (V.before('0.8.0') || commons) && _.populateExtensions(item, 'item') && DONE;
704
+ // Also populate extensions if commons has been implemented
705
+ (V.before('0.8.0') || commons) && _.populateExtensions(item, 'item') && DONE;
659
706
 
660
- return item;
661
- }
707
+ return item;
708
+ }
662
709
 
663
710
  };
664
711
 
665
712
  var CollectionCollection = {
666
713
 
667
- migrate(object, updateVersionNumber = true) {
668
- _.ensure(object, 'collections', []) && DONE;
669
- _.ensure(object, 'links', []) && DONE;
714
+ migrate(object, updateVersionNumber = true) {
715
+ _.ensure(object, 'collections', []) && DONE;
716
+ _.ensure(object, 'links', []) && DONE;
670
717
 
671
- _.runAll(CollectionCollection, object, object);
718
+ _.runAll(CollectionCollection, object, object);
672
719
 
673
- object.collections = object.collections.map(collection => Collection.migrate(collection, updateVersionNumber));
720
+ object.collections = object.collections.map(collection => Collection.migrate(collection, updateVersionNumber));
674
721
 
675
- return object;
676
- },
722
+ return object;
723
+ },
677
724
 
678
725
  };
679
726
 
680
727
  var ItemCollection = {
681
728
 
682
- migrate(itemCollection, updateVersionNumber = true) {
683
- _.ensure(itemCollection, 'type', 'FeatureCollection') && DONE;
684
- _.ensure(itemCollection, 'features', []) && DONE;
685
- _.ensure(itemCollection, 'links', []) && DONE;
729
+ migrate(itemCollection, updateVersionNumber = true) {
730
+ _.ensure(itemCollection, 'type', 'FeatureCollection') && DONE;
731
+ _.ensure(itemCollection, 'features', []) && DONE;
732
+ _.ensure(itemCollection, 'links', []) && DONE;
686
733
 
687
- _.runAll(ItemCollection, itemCollection, itemCollection);
734
+ _.runAll(ItemCollection, itemCollection, itemCollection);
688
735
 
689
- itemCollection.features = itemCollection.features.map(feature => Item.migrate(feature, null, updateVersionNumber));
736
+ itemCollection.features = itemCollection.features.map(feature => Item.migrate(feature, null, updateVersionNumber));
690
737
 
691
- return itemCollection;
692
- },
738
+ return itemCollection;
739
+ },
693
740
 
694
741
  };
695
742
 
696
743
  var Asset = {
697
744
 
698
- migrateAll(context, field = 'assets') {
699
- for(let key in context[field]) {
700
- Asset.migrate(context[field][key], context);
701
- }
702
- },
703
-
704
- migrate(asset, context) {
705
- _.runAll(Asset, asset, context);
706
-
707
- Fields.migrate(asset, context);
708
-
709
- return asset;
710
- },
711
-
712
- mediaTypes(asset) {
713
- _.is(asset.type, 'string') && _.mapValues(
714
- asset, 'type',
715
- ['image/vnd.stac.geotiff', 'image/vnd.stac.geotiff; cloud-optimized=true'],
716
- ['image/tiff; application=geotiff', 'image/tiff; application=geotiff; profile=cloud-optimized']
717
- );
718
- },
719
-
720
- eo(asset, context) {
721
- let bands = _.isObject(context.properties) && Array.isArray(context.properties['eo:bands']) ? context.properties['eo:bands'] : [];
722
- if (Array.isArray(asset['eo:bands'])) {
723
- for(let i in asset['eo:bands']) {
724
- let band = asset['eo:bands'][i];
725
- if (_.is(band, 'number') && _.isObject(bands[band])) {
726
- band = bands[band];
727
- }
728
- else if (!_.isObject(band)) {
729
- band = {}; // "Fix" invalid band index
730
- }
731
- asset['eo:bands'][i] = band;
732
- }
733
- }
734
- }
745
+ migrateAll(context, field = 'assets') {
746
+ for (let key in context[field]) {
747
+ Asset.migrate(context[field][key], context);
748
+ }
749
+ },
750
+
751
+ migrate(asset, context) {
752
+ _.runAll(Asset, asset, context);
753
+
754
+ Fields.migrate(asset, context);
755
+
756
+ return asset;
757
+ },
758
+
759
+ mediaTypes(asset) {
760
+ _.is(asset.type, 'string') && _.mapValues(
761
+ asset, 'type',
762
+ ['image/vnd.stac.geotiff', 'image/vnd.stac.geotiff; cloud-optimized=true'],
763
+ ['image/tiff; application=geotiff', 'image/tiff; application=geotiff; profile=cloud-optimized']
764
+ );
765
+ }
766
+
767
+ };
768
+
769
+ var Band = {
770
+
771
+ migrateAll(obj, context) {
772
+
773
+ if (V.before('1.0.0')) { // Not sure when the index-based bands were removed
774
+ const bands = _.isObject(context.properties) && Array.isArray(context.properties.bands) ? context.properties.bands : [];
775
+ if (Array.isArray(obj['eo:bands'])) {
776
+ for (let i in obj['eo:bands']) {
777
+ let band = obj['eo:bands'][i];
778
+ if (_.is(band, 'number') && _.isObject(bands[band])) {
779
+ band = bands[band];
780
+ }
781
+ if (!_.isObject(band)) {
782
+ band = {}; // "Fix" invalid band index
783
+ }
784
+ obj['eo:bands'][i] = band;
785
+ }
786
+ }
787
+ }
788
+
789
+ if (V.before("1.1.0-beta.1") && (Array.isArray(obj["raster:bands"]) || Array.isArray(obj["eo:bands"]))) {
790
+ _.ensure(obj, "bands", []);
791
+
792
+ const raster = obj["raster:bands"] || [];
793
+ const eo = obj["eo:bands"] || [];
794
+ const length = Math.max(raster.length, eo.length);
795
+ for (let i = 0; i < length; i++) {
796
+ _.ensure(obj.bands, i, {});
797
+ Object.assign(obj.bands[i], raster[i], eo[i]);
798
+ obj.bands[i] = Band.migrate(obj.bands[i], context);
799
+ }
800
+
801
+ delete obj["raster:bands"];
802
+ delete obj["eo:bands"];
803
+ }
804
+
805
+ },
806
+
807
+ migrate(band, context) {
808
+ _.runAll(Band, band, context);
809
+
810
+ Fields.migrate(band, context);
811
+
812
+ return band;
813
+ },
814
+
815
+ eo(band) {
816
+ if (V.before('2.0.0-beta.1', 'eo')) {
817
+ _.rename(band, 'common_name', 'eo:common_name') && DONE;
818
+ _.rename(band, 'center_wavelength', 'eo:center_wavelength') && DONE;
819
+ _.rename(band, 'full_width_half_max', 'eo:full_width_half_max') && DONE;
820
+ _.rename(band, 'solar_illumination', 'eo:solar_illumination') && DONE;
821
+ }
822
+ },
823
+
824
+ raster(band) {
825
+ if (V.before('2.0.0-beta.1', 'raster')) {
826
+ _.rename(band, 'sampling', 'raster:sampling') && DONE;
827
+ _.rename(band, 'bits_per_sample', 'raster:bits_per_sample') && DONE;
828
+ _.rename(band, 'spatial_resolution', 'raster:spatial_resolution') && DONE;
829
+ _.rename(band, 'scale', 'raster:scale') && DONE;
830
+ _.rename(band, 'offset', 'raster:offset') && DONE;
831
+ _.rename(band, 'histogram', 'raster:histogram') && DONE;
832
+ }
833
+ }
735
834
 
736
835
  };
737
836
 
738
837
  var Fields = {
739
838
 
740
- migrate(obj, context, summaries = false) {
741
- _.runAll(Fields, obj, context, summaries);
742
-
743
- return obj;
744
- },
745
-
746
- _commonMetadata(obj) {
747
- // Timestamps must be always in UTC
748
- // datetime, start_datetime and end_datetime already required UTC before
749
- if (V.before('1.0.0-rc.3')) {
750
- _.toUTC(obj, 'created') && DONE;
751
- _.toUTC(obj, 'updated') && DONE;
752
- }
753
- },
754
-
755
- _timestamps(obj, context) {
756
- // Timestamps must be always in UTC
757
- _.toUTC(obj, 'published') && DONE;
758
- _.toUTC(obj, 'expires') && DONE;
759
- _.toUTC(obj, 'unpublished') && DONE;
760
-
761
- _.upgradeExtension(context, SCHEMAS.timestamps);
762
- },
763
-
764
- _versioningIndicator(obj, context) {
765
- // Nothing to do
766
-
767
- _.upgradeExtension(context, SCHEMAS.version);
768
- },
769
-
770
- checksum(obj, context) {
771
- if (V.before('0.9.0') && Checksum.multihash) {
772
- _.rename(obj, 'checksum:md5', 'checksum:multihash') && Checksum.toMultihash(obj, 'checksum:multihash', 'md5') && DONE;
773
- _.rename(obj, 'checksum:sha1', 'checksum:multihash') && Checksum.toMultihash(obj, 'checksum:multihash', 'sha1') && DONE;
774
- // We assume sha2/3-256 although that may fail in some cases and other lengths are chosen
775
- // Never seen this implemtned in the wild, so let's try this until another use case comes up
776
- _.rename(obj, 'checksum:sha2', 'checksum:multihash') && Checksum.toMultihash(obj, 'checksum:multihash', 'sha2-256') && DONE;
777
- _.rename(obj, 'checksum:sha3', 'checksum:multihash') && Checksum.toMultihash(obj, 'checksum:multihash', 'sha3-256') && DONE;
778
- }
779
-
780
- V.before('1.0.0-rc.1') && _.rename(obj, 'checksum:multihash', 'file:checksum') && _.addExtension(context, SCHEMAS.file) && DONE;
781
-
782
- _.removeExtension(context, 'checksum');
783
- },
784
-
785
- classification(obj, context) {
786
- if (V.before('1.1.0', 'classification')) {
787
- _.forAll(obj, 'classification:classes', o => _.rename(o, 'color-hint', 'color_hint')) && DONE;
788
- }
789
-
790
- _.upgradeExtension(context, SCHEMAS.classification);
791
- },
792
-
793
- cube(obj, context) {
794
- // We'd need to convert proj strings to something else for v1.0 -> v2.0, but that's unfeasible here.
795
- // Nothing else to do here.
796
-
797
- _.upgradeExtension(context, SCHEMAS.datacube);
798
- },
799
-
800
- dtr(obj, context) {
801
- if (V.before('0.9.0')) {
802
- _.rename(obj, 'dtr:start_datetime', 'start_datetime') && DONE;
803
- _.rename(obj, 'dtr:end_datetime', 'end_datetime') && DONE;
804
- _.removeExtension(context, 'datetime-range') && DONE;
805
- }
806
- },
807
-
808
- eo(obj, context) {
809
- if (V.before('0.9.0')) {
810
- _.rename(obj, 'eo:epsg', 'proj:epsg') && _.addExtension(context, SCHEMAS.projection) && DONE;
811
- _.rename(obj, 'eo:platform', 'platform') && DONE;
812
- _.rename(obj, 'eo:instrument', 'instruments') && _.toArray(obj, 'instruments') && DONE;
813
- _.rename(obj, 'eo:constellation', 'constellation') && DONE;
814
- _.rename(obj, 'eo:off_nadir', 'view:off_nadir') && _.addExtension(context, SCHEMAS.view) && DONE;
815
- _.rename(obj, 'eo:azimuth', 'view:azimuth') && _.addExtension(context, SCHEMAS.view) && DONE;
816
- _.rename(obj, 'eo:incidence_angle', 'view:incidence_angle') && _.addExtension(context, SCHEMAS.view) && DONE;
817
- _.rename(obj, 'eo:sun_azimuth', 'view:sun_azimuth') && _.addExtension(context, SCHEMAS.view) && DONE;
818
- _.rename(obj, 'eo:sun_elevation', 'view:sun_elevation') && _.addExtension(context, SCHEMAS.view) && DONE;
819
- }
820
-
821
- V.before('1.0.0-beta.1') && _.rename(obj, 'eo:gsd', 'gsd') && DONE;
822
-
823
- _.upgradeExtension(context, SCHEMAS.eo);
824
- },
825
-
826
- file(obj, context) {
827
- // TODO: Migrate to v2.1.0 - https://github.com/stac-utils/stac-migrate/issues/7
828
-
829
- _.upgradeExtension(context, SCHEMAS.file);
830
- },
831
-
832
- label(obj, context) {
833
- // Migrate 0.8.0-rc1 non-pluralized forms
834
- if (V.before('0.8.0')) {
835
- _.rename(obj, 'label:property', 'label:properties') && DONE;
836
- _.rename(obj, 'label:task', 'label:tasks') && DONE;
837
- _.rename(obj, 'label:overview', 'label:overviews') && _.toArray(obj, 'label:overviews') && DONE;
838
- _.rename(obj, 'label:method', 'label:methods') && DONE;
839
- _.toArray(obj, 'label:classes') && DONE;
840
- }
841
-
842
- _.upgradeExtension(context, SCHEMAS.label);
843
- },
844
-
845
- pc(obj, context) {
846
- V.before('0.8.0') && _.rename(obj, 'pc:schema', 'pc:schemas') && DONE;
847
-
848
- _.upgradeExtension(context, SCHEMAS.pointcloud);
849
- },
850
-
851
- processing(obj, context) {
852
- // Nothing to do
853
-
854
- _.upgradeExtension(context, SCHEMAS.processing);
855
- },
856
-
857
- proj(obj, context) {
858
- // Nothing to do
859
-
860
- _.upgradeExtension(context, SCHEMAS.projection);
861
- },
862
-
863
- raster(obj, context) {
864
- // Nothing to do
865
-
866
- _.upgradeExtension(context, SCHEMAS.raster);
867
- },
868
-
869
- sar(obj, context, summary) {
870
- // Which version have they been (re)moved?
871
- _.rename(obj, 'sar:incidence_angle', 'view:incidence_angle') && _.addExtension(context, SCHEMAS.view) && DONE;
872
- _.rename(obj, 'sar:pass_direction', 'sat:orbit_state') && _.mapValues(obj, 'sat:orbit_state', [null], ['geostationary']) && _.addExtension(context, SCHEMAS.sat) && DONE;
873
-
874
- if (V.before('0.7.0')) {
875
- _.flattenArray(obj, 'sar:resolution', ['sar:resolution_range', 'sar:resolution_azimuth'], summary) && DONE;
876
- _.flattenArray(obj, 'sar:pixel_spacing', ['sar:pixel_spacing_range', 'sar:pixel_spacing_azimuth'], summary) && DONE;
877
- _.flattenArray(obj, 'sar:looks', ['sar:looks_range', 'sar:looks_azimuth', 'sar:looks_equivalent_number'], summary) && DONE;
878
- _.rename(obj, 'sar:off_nadir', 'view:off_nadir') && _.addExtension(context, SCHEMAS.view) && DONE;
879
- }
880
-
881
- if (V.before('0.9.0')) {
882
- _.rename(obj, 'sar:platform', 'platform') && DONE;
883
- _.rename(obj, 'sar:instrument', 'instruments') && _.toArray(obj, 'instruments') && DONE;
884
- _.rename(obj, 'sar:constellation', 'constellation') && DONE;
885
- _.rename(obj, 'sar:type', 'sar:product_type') && DONE;
886
- _.rename(obj, 'sar:polarization', 'sar:polarizations') && DONE;
887
- _.flattenOneElementArray(obj, 'sar:absolute_orbit', summary) && _.rename(obj, 'sar:absolute_orbit', 'sat:absolute_orbit') && _.addExtension(context, SCHEMAS.sat) && DONE;
888
- _.flattenOneElementArray(obj, 'sar:relative_orbit', summary) && _.rename(obj, 'sar:relative_orbit', 'sat:relative_orbit') && _.addExtension(context, SCHEMAS.sat) && DONE;
889
- }
890
-
891
- _.upgradeExtension(context, SCHEMAS.sar);
892
- },
893
-
894
- sat(obj, context) {
895
- // Migrate 0.9.0-rc _angle suffixes
896
- if (V.before('0.9.0')) {
897
- _.rename(obj, 'sat:off_nadir_angle', 'sat:off_nadir') && DONE;
898
- _.rename(obj, 'sat:azimuth_angle', 'sat:azimuth') && DONE;
899
- _.rename(obj, 'sat:sun_azimuth_angle', 'sat:sun_azimuth') && DONE;
900
- _.rename(obj, 'sat:sun_elevation_angle', 'sat:sun_elevation') && DONE;
901
- }
902
-
903
- _.upgradeExtension(context, SCHEMAS.sat);
904
- },
905
-
906
- sci(obj, context) {
907
- // Nothing to do
908
-
909
- _.upgradeExtension(context, SCHEMAS.scientific);
910
- },
911
-
912
- item(obj) { // Single Item
913
- if (V.before('0.8.0')) {
914
- _.rename(obj, 'item:license', 'license') && DONE;
915
- _.rename(obj, 'item:providers', 'providers') && DONE;
916
- // No need to remove the extension from stac_extensions as it was not available before 0.8.0
917
- }
918
- },
839
+ migrate(obj, context, summaries = false) {
840
+ _.runAll(Fields, obj, context, summaries);
841
+
842
+ return obj;
843
+ },
844
+
845
+ _commonMetadata(obj, context) {
846
+ // Timestamps must be always in UTC
847
+ // datetime, start_datetime and end_datetime already required UTC before
848
+ if (V.before('1.0.0-rc.3')) {
849
+ _.toUTC(obj, 'created') && DONE;
850
+ _.toUTC(obj, 'updated') && DONE;
851
+ }
852
+
853
+ Band.migrateAll(obj, context);
854
+ },
855
+
856
+ _timestamps(obj, context) {
857
+ // Timestamps must be always in UTC
858
+ _.toUTC(obj, 'published') && DONE;
859
+ _.toUTC(obj, 'expires') && DONE;
860
+ _.toUTC(obj, 'unpublished') && DONE;
861
+
862
+ _.upgradeExtension(context, SCHEMAS.timestamps);
863
+ },
864
+
865
+ _versioningIndicator(obj, context) {
866
+ // Nothing to do
867
+
868
+ _.upgradeExtension(context, SCHEMAS.version);
869
+ },
870
+
871
+ checksum(obj, context) {
872
+ if (V.before('0.9.0') && Checksum.multihash) {
873
+ _.rename(obj, 'checksum:md5', 'checksum:multihash') && Checksum.toMultihash(obj, 'checksum:multihash', 'md5') && DONE;
874
+ _.rename(obj, 'checksum:sha1', 'checksum:multihash') && Checksum.toMultihash(obj, 'checksum:multihash', 'sha1') && DONE;
875
+ // We assume sha2/3-256 although that may fail in some cases and other lengths are chosen
876
+ // Never seen this implemtned in the wild, so let's try this until another use case comes up
877
+ _.rename(obj, 'checksum:sha2', 'checksum:multihash') && Checksum.toMultihash(obj, 'checksum:multihash', 'sha2-256') && DONE;
878
+ _.rename(obj, 'checksum:sha3', 'checksum:multihash') && Checksum.toMultihash(obj, 'checksum:multihash', 'sha3-256') && DONE;
879
+ }
880
+
881
+ V.before('1.0.0-rc.1') && _.rename(obj, 'checksum:multihash', 'file:checksum') && _.addExtension(context, SCHEMAS.file) && DONE;
882
+
883
+ _.removeExtension(context, 'checksum');
884
+ },
885
+
886
+ classification(obj, context) {
887
+ if (V.before('1.1.0', 'classification')) {
888
+ _.forAll(obj, 'classification:classes', o => _.rename(o, 'color-hint', 'color_hint')) && DONE;
889
+ }
890
+ if (V.before('2.0.0', 'classification')) {
891
+ _.forAll(obj, 'classification:classes', o => _.ensure(o, 'name', o.description)) && DONE;
892
+ }
893
+
894
+ _.upgradeExtension(context, SCHEMAS.classification);
895
+ },
919
896
 
920
- table(obj, context) {
921
- // Nothing to do
897
+ cube(obj, context) {
898
+ // We'd need to convert proj strings to something else for v1.0 -> v2.0, but that's unfeasible here.
899
+ // Nothing else to do here.
922
900
 
923
- _.upgradeExtension(context, SCHEMAS.table);
924
- },
901
+ _.upgradeExtension(context, SCHEMAS.datacube);
902
+ },
925
903
 
926
- view(obj, context) {
927
- // Nothing to do
928
-
929
- _.upgradeExtension(context, SCHEMAS.view);
930
- }
904
+ dtr(obj, context) {
905
+ if (V.before('0.9.0')) {
906
+ _.rename(obj, 'dtr:start_datetime', 'start_datetime') && DONE;
907
+ _.rename(obj, 'dtr:end_datetime', 'end_datetime') && DONE;
908
+ _.removeExtension(context, 'datetime-range') && DONE;
909
+ }
910
+ },
911
+
912
+ eo(obj, context) {
913
+ if (V.before('0.9.0')) {
914
+ _.rename(obj, 'eo:epsg', 'proj:epsg') && _.addExtension(context, SCHEMAS.projection) && DONE;
915
+ _.rename(obj, 'eo:platform', 'platform') && DONE;
916
+ _.rename(obj, 'eo:instrument', 'instruments') && _.toArray(obj, 'instruments') && DONE;
917
+ _.rename(obj, 'eo:constellation', 'constellation') && DONE;
918
+ _.rename(obj, 'eo:off_nadir', 'view:off_nadir') && _.addExtension(context, SCHEMAS.view) && DONE;
919
+ _.rename(obj, 'eo:azimuth', 'view:azimuth') && _.addExtension(context, SCHEMAS.view) && DONE;
920
+ _.rename(obj, 'eo:incidence_angle', 'view:incidence_angle') && _.addExtension(context, SCHEMAS.view) && DONE;
921
+ _.rename(obj, 'eo:sun_azimuth', 'view:sun_azimuth') && _.addExtension(context, SCHEMAS.view) && DONE;
922
+ _.rename(obj, 'eo:sun_elevation', 'view:sun_elevation') && _.addExtension(context, SCHEMAS.view) && DONE;
923
+ }
924
+
925
+ V.before('1.0.0-beta.1') && _.rename(obj, 'eo:gsd', 'gsd') && DONE;
926
+
927
+ _.upgradeExtension(context, SCHEMAS.eo);
928
+ },
929
+
930
+ file(obj, context, summaries) {
931
+ _.rename(obj, 'file:bits_per_sample', 'raster:bits_per_sample') && _.addExtension(context, SCHEMAS.raster) && DONE;
932
+ _.rename(obj, 'file:data_type', 'data_type') && _.addExtension(context, SCHEMAS.raster) && DONE;
933
+ _.rename(obj, 'file:unit', 'unit') && _.addExtension(context, SCHEMAS.raster) && DONE;
934
+
935
+ if (Array.isArray(obj['file:nodata']) && obj['file:nodata'].length > 1) {
936
+ // In case of more than one no-data value we need to create a custom property
937
+ // as there's no alternative for multiple no-data values yet
938
+ _.copy(obj, 'file:nodata', 'nodata:values') && DONE;
939
+ }
940
+ _.rename(obj, 'file:nodata', 'nodata') && !summaries && _.pickFirst(obj, 'nodata') && DONE;
941
+ _.upgradeExtension(context, SCHEMAS.file);
942
+ },
943
+
944
+ label(obj, context) {
945
+ // Migrate 0.8.0-rc1 non-pluralized forms
946
+ if (V.before('0.8.0')) {
947
+ _.rename(obj, 'label:property', 'label:properties') && DONE;
948
+ _.rename(obj, 'label:task', 'label:tasks') && DONE;
949
+ _.rename(obj, 'label:overview', 'label:overviews') && _.toArray(obj, 'label:overviews') && DONE;
950
+ _.rename(obj, 'label:method', 'label:methods') && DONE;
951
+ _.toArray(obj, 'label:classes') && DONE;
952
+ }
953
+
954
+ _.upgradeExtension(context, SCHEMAS.label);
955
+ },
956
+
957
+ pc(obj, context) {
958
+ V.before('0.8.0') && _.rename(obj, 'pc:schema', 'pc:schemas') && DONE;
959
+
960
+ _.upgradeExtension(context, SCHEMAS.pointcloud);
961
+ },
962
+
963
+ processing(obj, context) {
964
+ // Nothing to do
965
+
966
+ _.upgradeExtension(context, SCHEMAS.processing);
967
+ },
968
+
969
+ proj(obj, context) {
970
+ _.rename(obj, 'proj:epsg', 'proj:code') && _.formatString(obj, 'proj:code', 'EPSG:{}') && DONE;
971
+
972
+ _.upgradeExtension(context, SCHEMAS.projection);
973
+ },
974
+
975
+ raster(obj, context) {
976
+ _.upgradeExtension(context, SCHEMAS.raster);
977
+ },
978
+
979
+ sar(obj, context, summary) {
980
+ // Which version have they been (re)moved?
981
+ _.rename(obj, 'sar:incidence_angle', 'view:incidence_angle') && _.addExtension(context, SCHEMAS.view) && DONE;
982
+ _.rename(obj, 'sar:pass_direction', 'sat:orbit_state') && _.mapValues(obj, 'sat:orbit_state', [null], ['geostationary']) && _.addExtension(context, SCHEMAS.sat) && DONE;
983
+
984
+ if (V.before('0.7.0')) {
985
+ _.flattenArray(obj, 'sar:resolution', ['sar:resolution_range', 'sar:resolution_azimuth'], summary) && DONE;
986
+ _.flattenArray(obj, 'sar:pixel_spacing', ['sar:pixel_spacing_range', 'sar:pixel_spacing_azimuth'], summary) && DONE;
987
+ _.flattenArray(obj, 'sar:looks', ['sar:looks_range', 'sar:looks_azimuth', 'sar:looks_equivalent_number'], summary) && DONE;
988
+ _.rename(obj, 'sar:off_nadir', 'view:off_nadir') && _.addExtension(context, SCHEMAS.view) && DONE;
989
+ }
990
+
991
+ if (V.before('0.9.0')) {
992
+ _.rename(obj, 'sar:platform', 'platform') && DONE;
993
+ _.rename(obj, 'sar:instrument', 'instruments') && _.toArray(obj, 'instruments') && DONE;
994
+ _.rename(obj, 'sar:constellation', 'constellation') && DONE;
995
+ _.rename(obj, 'sar:type', 'sar:product_type') && DONE;
996
+ _.rename(obj, 'sar:polarization', 'sar:polarizations') && DONE;
997
+ _.flattenOneElementArray(obj, 'sar:absolute_orbit', summary) && _.rename(obj, 'sar:absolute_orbit', 'sat:absolute_orbit') && _.addExtension(context, SCHEMAS.sat) && DONE;
998
+ _.flattenOneElementArray(obj, 'sar:relative_orbit', summary) && _.rename(obj, 'sar:relative_orbit', 'sat:relative_orbit') && _.addExtension(context, SCHEMAS.sat) && DONE;
999
+ }
1000
+
1001
+ _.upgradeExtension(context, SCHEMAS.sar);
1002
+ },
1003
+
1004
+ sat(obj, context) {
1005
+ // Migrate 0.9.0-rc _angle suffixes
1006
+ if (V.before('0.9.0')) {
1007
+ _.rename(obj, 'sat:off_nadir_angle', 'sat:off_nadir') && DONE;
1008
+ _.rename(obj, 'sat:azimuth_angle', 'sat:azimuth') && DONE;
1009
+ _.rename(obj, 'sat:sun_azimuth_angle', 'sat:sun_azimuth') && DONE;
1010
+ _.rename(obj, 'sat:sun_elevation_angle', 'sat:sun_elevation') && DONE;
1011
+ }
1012
+
1013
+ _.upgradeExtension(context, SCHEMAS.sat);
1014
+ },
1015
+
1016
+ sci(obj, context) {
1017
+ // Nothing to do
1018
+
1019
+ _.upgradeExtension(context, SCHEMAS.scientific);
1020
+ },
1021
+
1022
+ item(obj) { // Single Item
1023
+ if (V.before('0.8.0')) {
1024
+ _.rename(obj, 'item:license', 'license') && DONE;
1025
+ _.rename(obj, 'item:providers', 'providers') && DONE;
1026
+ // No need to remove the extension from stac_extensions as it was not available before 0.8.0
1027
+ }
1028
+ },
1029
+
1030
+ table(obj, context) {
1031
+ // Nothing to do
1032
+
1033
+ _.upgradeExtension(context, SCHEMAS.table);
1034
+ },
1035
+
1036
+ view(obj, context) {
1037
+ // Nothing to do
1038
+
1039
+ _.upgradeExtension(context, SCHEMAS.view);
1040
+ }
931
1041
 
932
1042
  };
933
1043
 
934
1044
  var Migrate = {
935
1045
 
936
- item(item, collection = null, updateVersionNumber = true) {
937
- return Item.migrate(item, collection, updateVersionNumber);
938
- },
939
-
940
- catalog(catalog, updateVersionNumber = true) {
941
- return Catalog.migrate(catalog, updateVersionNumber);
942
- },
943
-
944
- collection(collection, updateVersionNumber = true) {
945
- return Collection.migrate(collection, updateVersionNumber);
946
- },
947
-
948
- collectionCollection(collections, updateVersionNumber = true) {
949
- return CollectionCollection.migrate(collections, updateVersionNumber);
950
- },
951
-
952
- itemCollection(itemCollection, updateVersionNumber = true) {
953
- return ItemCollection.migrate(itemCollection, updateVersionNumber);
954
- },
955
-
956
- stac(object, updateVersionNumber = true) {
957
- if (object.type === 'Feature') {
958
- return Migrate.item(object, null, updateVersionNumber);
959
- }
960
- else if (object.type === 'FeatureCollection') {
961
- return Migrate.itemCollection(object, updateVersionNumber);
962
- }
963
- else if (object.type === 'Collection' || (!object.type && _.isDefined(object.extent) && _.isDefined(object.license))) {
964
- return Migrate.collection(object, updateVersionNumber);
965
- }
1046
+ item(item, collection = null, updateVersionNumber = true) {
1047
+ return Item.migrate(item, collection, updateVersionNumber);
1048
+ },
1049
+
1050
+ catalog(catalog, updateVersionNumber = true) {
1051
+ return Catalog.migrate(catalog, updateVersionNumber);
1052
+ },
1053
+
1054
+ collection(collection, updateVersionNumber = true) {
1055
+ return Collection.migrate(collection, updateVersionNumber);
1056
+ },
1057
+
1058
+ collectionCollection(collections, updateVersionNumber = true) {
1059
+ return CollectionCollection.migrate(collections, updateVersionNumber);
1060
+ },
1061
+
1062
+ itemCollection(itemCollection, updateVersionNumber = true) {
1063
+ return ItemCollection.migrate(itemCollection, updateVersionNumber);
1064
+ },
1065
+
1066
+ stac(object, updateVersionNumber = true) {
1067
+ if (object.type === 'Feature') {
1068
+ return Migrate.item(object, null, updateVersionNumber);
1069
+ }
1070
+ else if (object.type === 'FeatureCollection') {
1071
+ return Migrate.itemCollection(object, updateVersionNumber);
1072
+ }
1073
+ else if (object.type === 'Collection' || (!object.type && _.isDefined(object.extent) && _.isDefined(object.license))) {
1074
+ return Migrate.collection(object, updateVersionNumber);
1075
+ }
966
1076
  else if (!object.type && Array.isArray(object.collections)) {
967
- return Migrate.collectionCollection(object, updateVersionNumber);
1077
+ return Migrate.collectionCollection(object, updateVersionNumber);
1078
+ }
1079
+ else {
1080
+ return Migrate.catalog(object, updateVersionNumber);
968
1081
  }
969
- else {
970
- return Migrate.catalog(object, updateVersionNumber);
971
- }
972
- },
1082
+ },
973
1083
 
974
- enableMultihash(multihash) {
975
- Checksum.multihash = multihash;
976
- }
1084
+ enableMultihash(multihash) {
1085
+ Checksum.multihash = multihash;
1086
+ }
977
1087
 
978
1088
  };
979
1089
 
980
- module.exports = Migrate;
1090
+ module.exports = Migrate;