@vitessce/config 4.0.0-test.1 → 4.0.0-test.3

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.
package/dist/index.js ADDED
@@ -0,0 +1,4601 @@
1
+ const FileType = {
2
+ // Joint file types
3
+ ANNDATA_ZARR: "anndata.zarr",
4
+ ANNDATA_ZARR_ZIP: "anndata.zarr.zip",
5
+ SPATIALDATA_ZARR: "spatialdata.zarr",
6
+ SPATIALDATA_ZARR_ZIP: "spatialdata.zarr.zip",
7
+ // OME-Zarr
8
+ IMAGE_OME_ZARR: "image.ome-zarr",
9
+ OBS_SEGMENTATIONS_OME_ZARR: "obsSegmentations.ome-zarr",
10
+ // OME-Zarr - Zipped
11
+ IMAGE_OME_ZARR_ZIP: "image.ome-zarr.zip",
12
+ OBS_SEGMENTATIONS_OME_ZARR_ZIP: "obsSegmentations.ome-zarr.zip",
13
+ // OME-TIFF
14
+ IMAGE_OME_TIFF: "image.ome-tiff",
15
+ OBS_SEGMENTATIONS_OME_TIFF: "obsSegmentations.ome-tiff",
16
+ RASTER_JSON: "raster.json",
17
+ RASTER_OME_ZARR: "raster.ome-zarr"
18
+ };
19
+ const CoordinationType = {
20
+ META_COORDINATION_SCOPES: "metaCoordinationScopes",
21
+ META_COORDINATION_SCOPES_BY: "metaCoordinationScopesBy",
22
+ DATASET: "dataset",
23
+ // Other types
24
+ EMBEDDING_TYPE: "embeddingType",
25
+ SPATIAL_ZOOM: "spatialZoom",
26
+ SPATIAL_TARGET_X: "spatialTargetX",
27
+ SPATIAL_TARGET_Y: "spatialTargetY",
28
+ SPATIAL_IMAGE_LAYER: "spatialImageLayer",
29
+ SPATIAL_SEGMENTATION_LAYER: "spatialSegmentationLayer"
30
+ };
31
+ function getDefaultExportFromCjs(x) {
32
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
33
+ }
34
+ function commonjsRequire(path) {
35
+ throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
36
+ }
37
+ var pluralize$1 = { exports: {} };
38
+ var pluralize = pluralize$1.exports;
39
+ var hasRequiredPluralize;
40
+ function requirePluralize() {
41
+ if (hasRequiredPluralize) return pluralize$1.exports;
42
+ hasRequiredPluralize = 1;
43
+ (function(module2, exports) {
44
+ (function(root, pluralize2) {
45
+ if (typeof commonjsRequire === "function" && true && true) {
46
+ module2.exports = pluralize2();
47
+ } else {
48
+ root.pluralize = pluralize2();
49
+ }
50
+ })(pluralize, function() {
51
+ var pluralRules = [];
52
+ var singularRules = [];
53
+ var uncountables = {};
54
+ var irregularPlurals = {};
55
+ var irregularSingles = {};
56
+ function sanitizeRule(rule) {
57
+ if (typeof rule === "string") {
58
+ return new RegExp("^" + rule + "$", "i");
59
+ }
60
+ return rule;
61
+ }
62
+ function restoreCase(word, token) {
63
+ if (word === token) return token;
64
+ if (word === word.toLowerCase()) return token.toLowerCase();
65
+ if (word === word.toUpperCase()) return token.toUpperCase();
66
+ if (word[0] === word[0].toUpperCase()) {
67
+ return token.charAt(0).toUpperCase() + token.substr(1).toLowerCase();
68
+ }
69
+ return token.toLowerCase();
70
+ }
71
+ function interpolate(str, args) {
72
+ return str.replace(/\$(\d{1,2})/g, function(match, index) {
73
+ return args[index] || "";
74
+ });
75
+ }
76
+ function replace(word, rule) {
77
+ return word.replace(rule[0], function(match, index) {
78
+ var result = interpolate(rule[1], arguments);
79
+ if (match === "") {
80
+ return restoreCase(word[index - 1], result);
81
+ }
82
+ return restoreCase(match, result);
83
+ });
84
+ }
85
+ function sanitizeWord(token, word, rules) {
86
+ if (!token.length || uncountables.hasOwnProperty(token)) {
87
+ return word;
88
+ }
89
+ var len = rules.length;
90
+ while (len--) {
91
+ var rule = rules[len];
92
+ if (rule[0].test(word)) return replace(word, rule);
93
+ }
94
+ return word;
95
+ }
96
+ function replaceWord(replaceMap, keepMap, rules) {
97
+ return function(word) {
98
+ var token = word.toLowerCase();
99
+ if (keepMap.hasOwnProperty(token)) {
100
+ return restoreCase(word, token);
101
+ }
102
+ if (replaceMap.hasOwnProperty(token)) {
103
+ return restoreCase(word, replaceMap[token]);
104
+ }
105
+ return sanitizeWord(token, word, rules);
106
+ };
107
+ }
108
+ function checkWord(replaceMap, keepMap, rules, bool) {
109
+ return function(word) {
110
+ var token = word.toLowerCase();
111
+ if (keepMap.hasOwnProperty(token)) return true;
112
+ if (replaceMap.hasOwnProperty(token)) return false;
113
+ return sanitizeWord(token, token, rules) === token;
114
+ };
115
+ }
116
+ function pluralize2(word, count, inclusive) {
117
+ var pluralized = count === 1 ? pluralize2.singular(word) : pluralize2.plural(word);
118
+ return (inclusive ? count + " " : "") + pluralized;
119
+ }
120
+ pluralize2.plural = replaceWord(
121
+ irregularSingles,
122
+ irregularPlurals,
123
+ pluralRules
124
+ );
125
+ pluralize2.isPlural = checkWord(
126
+ irregularSingles,
127
+ irregularPlurals,
128
+ pluralRules
129
+ );
130
+ pluralize2.singular = replaceWord(
131
+ irregularPlurals,
132
+ irregularSingles,
133
+ singularRules
134
+ );
135
+ pluralize2.isSingular = checkWord(
136
+ irregularPlurals,
137
+ irregularSingles,
138
+ singularRules
139
+ );
140
+ pluralize2.addPluralRule = function(rule, replacement) {
141
+ pluralRules.push([sanitizeRule(rule), replacement]);
142
+ };
143
+ pluralize2.addSingularRule = function(rule, replacement) {
144
+ singularRules.push([sanitizeRule(rule), replacement]);
145
+ };
146
+ pluralize2.addUncountableRule = function(word) {
147
+ if (typeof word === "string") {
148
+ uncountables[word.toLowerCase()] = true;
149
+ return;
150
+ }
151
+ pluralize2.addPluralRule(word, "$0");
152
+ pluralize2.addSingularRule(word, "$0");
153
+ };
154
+ pluralize2.addIrregularRule = function(single, plural) {
155
+ plural = plural.toLowerCase();
156
+ single = single.toLowerCase();
157
+ irregularSingles[single] = plural;
158
+ irregularPlurals[plural] = single;
159
+ };
160
+ [
161
+ // Pronouns.
162
+ ["I", "we"],
163
+ ["me", "us"],
164
+ ["he", "they"],
165
+ ["she", "they"],
166
+ ["them", "them"],
167
+ ["myself", "ourselves"],
168
+ ["yourself", "yourselves"],
169
+ ["itself", "themselves"],
170
+ ["herself", "themselves"],
171
+ ["himself", "themselves"],
172
+ ["themself", "themselves"],
173
+ ["is", "are"],
174
+ ["was", "were"],
175
+ ["has", "have"],
176
+ ["this", "these"],
177
+ ["that", "those"],
178
+ // Words ending in with a consonant and `o`.
179
+ ["echo", "echoes"],
180
+ ["dingo", "dingoes"],
181
+ ["volcano", "volcanoes"],
182
+ ["tornado", "tornadoes"],
183
+ ["torpedo", "torpedoes"],
184
+ // Ends with `us`.
185
+ ["genus", "genera"],
186
+ ["viscus", "viscera"],
187
+ // Ends with `ma`.
188
+ ["stigma", "stigmata"],
189
+ ["stoma", "stomata"],
190
+ ["dogma", "dogmata"],
191
+ ["lemma", "lemmata"],
192
+ ["schema", "schemata"],
193
+ ["anathema", "anathemata"],
194
+ // Other irregular rules.
195
+ ["ox", "oxen"],
196
+ ["axe", "axes"],
197
+ ["die", "dice"],
198
+ ["yes", "yeses"],
199
+ ["foot", "feet"],
200
+ ["eave", "eaves"],
201
+ ["goose", "geese"],
202
+ ["tooth", "teeth"],
203
+ ["quiz", "quizzes"],
204
+ ["human", "humans"],
205
+ ["proof", "proofs"],
206
+ ["carve", "carves"],
207
+ ["valve", "valves"],
208
+ ["looey", "looies"],
209
+ ["thief", "thieves"],
210
+ ["groove", "grooves"],
211
+ ["pickaxe", "pickaxes"],
212
+ ["passerby", "passersby"]
213
+ ].forEach(function(rule) {
214
+ return pluralize2.addIrregularRule(rule[0], rule[1]);
215
+ });
216
+ [
217
+ [/s?$/i, "s"],
218
+ [/[^\u0000-\u007F]$/i, "$0"],
219
+ [/([^aeiou]ese)$/i, "$1"],
220
+ [/(ax|test)is$/i, "$1es"],
221
+ [/(alias|[^aou]us|t[lm]as|gas|ris)$/i, "$1es"],
222
+ [/(e[mn]u)s?$/i, "$1s"],
223
+ [/([^l]ias|[aeiou]las|[ejzr]as|[iu]am)$/i, "$1"],
224
+ [/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i, "$1i"],
225
+ [/(alumn|alg|vertebr)(?:a|ae)$/i, "$1ae"],
226
+ [/(seraph|cherub)(?:im)?$/i, "$1im"],
227
+ [/(her|at|gr)o$/i, "$1oes"],
228
+ [/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|automat|quor)(?:a|um)$/i, "$1a"],
229
+ [/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)(?:a|on)$/i, "$1a"],
230
+ [/sis$/i, "ses"],
231
+ [/(?:(kni|wi|li)fe|(ar|l|ea|eo|oa|hoo)f)$/i, "$1$2ves"],
232
+ [/([^aeiouy]|qu)y$/i, "$1ies"],
233
+ [/([^ch][ieo][ln])ey$/i, "$1ies"],
234
+ [/(x|ch|ss|sh|zz)$/i, "$1es"],
235
+ [/(matr|cod|mur|sil|vert|ind|append)(?:ix|ex)$/i, "$1ices"],
236
+ [/\b((?:tit)?m|l)(?:ice|ouse)$/i, "$1ice"],
237
+ [/(pe)(?:rson|ople)$/i, "$1ople"],
238
+ [/(child)(?:ren)?$/i, "$1ren"],
239
+ [/eaux$/i, "$0"],
240
+ [/m[ae]n$/i, "men"],
241
+ ["thou", "you"]
242
+ ].forEach(function(rule) {
243
+ return pluralize2.addPluralRule(rule[0], rule[1]);
244
+ });
245
+ [
246
+ [/s$/i, ""],
247
+ [/(ss)$/i, "$1"],
248
+ [/(wi|kni|(?:after|half|high|low|mid|non|night|[^\w]|^)li)ves$/i, "$1fe"],
249
+ [/(ar|(?:wo|[ae])l|[eo][ao])ves$/i, "$1f"],
250
+ [/ies$/i, "y"],
251
+ [/\b([pl]|zomb|(?:neck|cross)?t|coll|faer|food|gen|goon|group|lass|talk|goal|cut)ies$/i, "$1ie"],
252
+ [/\b(mon|smil)ies$/i, "$1ey"],
253
+ [/\b((?:tit)?m|l)ice$/i, "$1ouse"],
254
+ [/(seraph|cherub)im$/i, "$1"],
255
+ [/(x|ch|ss|sh|zz|tto|go|cho|alias|[^aou]us|t[lm]as|gas|(?:her|at|gr)o|[aeiou]ris)(?:es)?$/i, "$1"],
256
+ [/(analy|diagno|parenthe|progno|synop|the|empha|cri|ne)(?:sis|ses)$/i, "$1sis"],
257
+ [/(movie|twelve|abuse|e[mn]u)s$/i, "$1"],
258
+ [/(test)(?:is|es)$/i, "$1is"],
259
+ [/(alumn|syllab|vir|radi|nucle|fung|cact|stimul|termin|bacill|foc|uter|loc|strat)(?:us|i)$/i, "$1us"],
260
+ [/(agend|addend|millenni|dat|extrem|bacteri|desiderat|strat|candelabr|errat|ov|symposi|curricul|quor)a$/i, "$1um"],
261
+ [/(apheli|hyperbat|periheli|asyndet|noumen|phenomen|criteri|organ|prolegomen|hedr|automat)a$/i, "$1on"],
262
+ [/(alumn|alg|vertebr)ae$/i, "$1a"],
263
+ [/(cod|mur|sil|vert|ind)ices$/i, "$1ex"],
264
+ [/(matr|append)ices$/i, "$1ix"],
265
+ [/(pe)(rson|ople)$/i, "$1rson"],
266
+ [/(child)ren$/i, "$1"],
267
+ [/(eau)x?$/i, "$1"],
268
+ [/men$/i, "man"]
269
+ ].forEach(function(rule) {
270
+ return pluralize2.addSingularRule(rule[0], rule[1]);
271
+ });
272
+ [
273
+ // Singular words with no plurals.
274
+ "adulthood",
275
+ "advice",
276
+ "agenda",
277
+ "aid",
278
+ "aircraft",
279
+ "alcohol",
280
+ "ammo",
281
+ "analytics",
282
+ "anime",
283
+ "athletics",
284
+ "audio",
285
+ "bison",
286
+ "blood",
287
+ "bream",
288
+ "buffalo",
289
+ "butter",
290
+ "carp",
291
+ "cash",
292
+ "chassis",
293
+ "chess",
294
+ "clothing",
295
+ "cod",
296
+ "commerce",
297
+ "cooperation",
298
+ "corps",
299
+ "debris",
300
+ "diabetes",
301
+ "digestion",
302
+ "elk",
303
+ "energy",
304
+ "equipment",
305
+ "excretion",
306
+ "expertise",
307
+ "firmware",
308
+ "flounder",
309
+ "fun",
310
+ "gallows",
311
+ "garbage",
312
+ "graffiti",
313
+ "hardware",
314
+ "headquarters",
315
+ "health",
316
+ "herpes",
317
+ "highjinks",
318
+ "homework",
319
+ "housework",
320
+ "information",
321
+ "jeans",
322
+ "justice",
323
+ "kudos",
324
+ "labour",
325
+ "literature",
326
+ "machinery",
327
+ "mackerel",
328
+ "mail",
329
+ "media",
330
+ "mews",
331
+ "moose",
332
+ "music",
333
+ "mud",
334
+ "manga",
335
+ "news",
336
+ "only",
337
+ "personnel",
338
+ "pike",
339
+ "plankton",
340
+ "pliers",
341
+ "police",
342
+ "pollution",
343
+ "premises",
344
+ "rain",
345
+ "research",
346
+ "rice",
347
+ "salmon",
348
+ "scissors",
349
+ "series",
350
+ "sewage",
351
+ "shambles",
352
+ "shrimp",
353
+ "software",
354
+ "species",
355
+ "staff",
356
+ "swine",
357
+ "tennis",
358
+ "traffic",
359
+ "transportation",
360
+ "trout",
361
+ "tuna",
362
+ "wealth",
363
+ "welfare",
364
+ "whiting",
365
+ "wildebeest",
366
+ "wildlife",
367
+ "you",
368
+ /pok[eé]mon$/i,
369
+ // Regexes.
370
+ /[^aeiou]ese$/i,
371
+ // "chinese", "japanese"
372
+ /deer$/i,
373
+ // "deer", "reindeer"
374
+ /fish$/i,
375
+ // "fish", "blowfish", "angelfish"
376
+ /measles$/i,
377
+ /o[iu]s$/i,
378
+ // "carnivorous"
379
+ /pox$/i,
380
+ // "chickpox", "smallpox"
381
+ /sheep$/i
382
+ ].forEach(pluralize2.addUncountableRule);
383
+ return pluralize2;
384
+ });
385
+ })(pluralize$1);
386
+ return pluralize$1.exports;
387
+ }
388
+ var pluralizeExports = requirePluralize();
389
+ const plur = /* @__PURE__ */ getDefaultExportFromCjs(pluralizeExports);
390
+ plur.addPluralRule("glomerulus", "glomeruli");
391
+ plur.addPluralRule("interstitium", "interstitia");
392
+ function getNextScope(prevScopes) {
393
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
394
+ const nextCharIndices = [0];
395
+ function next() {
396
+ const r = [];
397
+ nextCharIndices.forEach((charIndex) => {
398
+ r.unshift(chars[charIndex]);
399
+ });
400
+ let increment = true;
401
+ for (let i = 0; i < nextCharIndices.length; i++) {
402
+ const val = ++nextCharIndices[i];
403
+ if (val >= chars.length) {
404
+ nextCharIndices[i] = 0;
405
+ } else {
406
+ increment = false;
407
+ break;
408
+ }
409
+ }
410
+ if (increment) {
411
+ nextCharIndices.push(0);
412
+ }
413
+ return r.join("");
414
+ }
415
+ let nextScope;
416
+ do {
417
+ nextScope = next();
418
+ } while (prevScopes.includes(nextScope));
419
+ return nextScope;
420
+ }
421
+ function createPrefixedGetNextScopeNumeric(prefix) {
422
+ return (prevScopes) => {
423
+ let nextScopeInt = 0;
424
+ let nextScopeStr;
425
+ do {
426
+ nextScopeStr = `${prefix}${nextScopeInt}`;
427
+ nextScopeInt += 1;
428
+ } while (prevScopes.includes(nextScopeStr));
429
+ return nextScopeStr;
430
+ };
431
+ }
432
+ function getInitialCoordinationScopePrefix(datasetUid, dataType) {
433
+ return `init_${datasetUid}_${dataType}_`;
434
+ }
435
+ function getInitialCoordinationScopeName(datasetUid, dataType, i = null) {
436
+ const prefix = getInitialCoordinationScopePrefix(datasetUid, dataType);
437
+ return `${prefix}${i === null ? 0 : i}`;
438
+ }
439
+ var loglevel$1 = { exports: {} };
440
+ var loglevel = loglevel$1.exports;
441
+ var hasRequiredLoglevel;
442
+ function requireLoglevel() {
443
+ if (hasRequiredLoglevel) return loglevel$1.exports;
444
+ hasRequiredLoglevel = 1;
445
+ (function(module2) {
446
+ (function(root, definition) {
447
+ if (module2.exports) {
448
+ module2.exports = definition();
449
+ } else {
450
+ root.log = definition();
451
+ }
452
+ })(loglevel, function() {
453
+ var noop = function() {
454
+ };
455
+ var undefinedType = "undefined";
456
+ var isIE = typeof window !== undefinedType && typeof window.navigator !== undefinedType && /Trident\/|MSIE /.test(window.navigator.userAgent);
457
+ var logMethods = [
458
+ "trace",
459
+ "debug",
460
+ "info",
461
+ "warn",
462
+ "error"
463
+ ];
464
+ var _loggersByName = {};
465
+ var defaultLogger = null;
466
+ function bindMethod(obj, methodName) {
467
+ var method = obj[methodName];
468
+ if (typeof method.bind === "function") {
469
+ return method.bind(obj);
470
+ } else {
471
+ try {
472
+ return Function.prototype.bind.call(method, obj);
473
+ } catch (e) {
474
+ return function() {
475
+ return Function.prototype.apply.apply(method, [obj, arguments]);
476
+ };
477
+ }
478
+ }
479
+ }
480
+ function traceForIE() {
481
+ if (console.log) {
482
+ if (console.log.apply) {
483
+ console.log.apply(console, arguments);
484
+ } else {
485
+ Function.prototype.apply.apply(console.log, [console, arguments]);
486
+ }
487
+ }
488
+ if (console.trace) console.trace();
489
+ }
490
+ function realMethod(methodName) {
491
+ if (methodName === "debug") {
492
+ methodName = "log";
493
+ }
494
+ if (typeof console === undefinedType) {
495
+ return false;
496
+ } else if (methodName === "trace" && isIE) {
497
+ return traceForIE;
498
+ } else if (console[methodName] !== void 0) {
499
+ return bindMethod(console, methodName);
500
+ } else if (console.log !== void 0) {
501
+ return bindMethod(console, "log");
502
+ } else {
503
+ return noop;
504
+ }
505
+ }
506
+ function replaceLoggingMethods() {
507
+ var level = this.getLevel();
508
+ for (var i = 0; i < logMethods.length; i++) {
509
+ var methodName = logMethods[i];
510
+ this[methodName] = i < level ? noop : this.methodFactory(methodName, level, this.name);
511
+ }
512
+ this.log = this.debug;
513
+ if (typeof console === undefinedType && level < this.levels.SILENT) {
514
+ return "No console available for logging";
515
+ }
516
+ }
517
+ function enableLoggingWhenConsoleArrives(methodName) {
518
+ return function() {
519
+ if (typeof console !== undefinedType) {
520
+ replaceLoggingMethods.call(this);
521
+ this[methodName].apply(this, arguments);
522
+ }
523
+ };
524
+ }
525
+ function defaultMethodFactory(methodName, _level, _loggerName) {
526
+ return realMethod(methodName) || enableLoggingWhenConsoleArrives.apply(this, arguments);
527
+ }
528
+ function Logger(name, factory) {
529
+ var self = this;
530
+ var inheritedLevel;
531
+ var defaultLevel;
532
+ var userLevel;
533
+ var storageKey = "loglevel";
534
+ if (typeof name === "string") {
535
+ storageKey += ":" + name;
536
+ } else if (typeof name === "symbol") {
537
+ storageKey = void 0;
538
+ }
539
+ function persistLevelIfPossible(levelNum) {
540
+ var levelName = (logMethods[levelNum] || "silent").toUpperCase();
541
+ if (typeof window === undefinedType || !storageKey) return;
542
+ try {
543
+ window.localStorage[storageKey] = levelName;
544
+ return;
545
+ } catch (ignore) {
546
+ }
547
+ try {
548
+ window.document.cookie = encodeURIComponent(storageKey) + "=" + levelName + ";";
549
+ } catch (ignore) {
550
+ }
551
+ }
552
+ function getPersistedLevel() {
553
+ var storedLevel;
554
+ if (typeof window === undefinedType || !storageKey) return;
555
+ try {
556
+ storedLevel = window.localStorage[storageKey];
557
+ } catch (ignore) {
558
+ }
559
+ if (typeof storedLevel === undefinedType) {
560
+ try {
561
+ var cookie = window.document.cookie;
562
+ var cookieName = encodeURIComponent(storageKey);
563
+ var location = cookie.indexOf(cookieName + "=");
564
+ if (location !== -1) {
565
+ storedLevel = /^([^;]+)/.exec(
566
+ cookie.slice(location + cookieName.length + 1)
567
+ )[1];
568
+ }
569
+ } catch (ignore) {
570
+ }
571
+ }
572
+ if (self.levels[storedLevel] === void 0) {
573
+ storedLevel = void 0;
574
+ }
575
+ return storedLevel;
576
+ }
577
+ function clearPersistedLevel() {
578
+ if (typeof window === undefinedType || !storageKey) return;
579
+ try {
580
+ window.localStorage.removeItem(storageKey);
581
+ } catch (ignore) {
582
+ }
583
+ try {
584
+ window.document.cookie = encodeURIComponent(storageKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC";
585
+ } catch (ignore) {
586
+ }
587
+ }
588
+ function normalizeLevel(input) {
589
+ var level = input;
590
+ if (typeof level === "string" && self.levels[level.toUpperCase()] !== void 0) {
591
+ level = self.levels[level.toUpperCase()];
592
+ }
593
+ if (typeof level === "number" && level >= 0 && level <= self.levels.SILENT) {
594
+ return level;
595
+ } else {
596
+ throw new TypeError("log.setLevel() called with invalid level: " + input);
597
+ }
598
+ }
599
+ self.name = name;
600
+ self.levels = {
601
+ "TRACE": 0,
602
+ "DEBUG": 1,
603
+ "INFO": 2,
604
+ "WARN": 3,
605
+ "ERROR": 4,
606
+ "SILENT": 5
607
+ };
608
+ self.methodFactory = factory || defaultMethodFactory;
609
+ self.getLevel = function() {
610
+ if (userLevel != null) {
611
+ return userLevel;
612
+ } else if (defaultLevel != null) {
613
+ return defaultLevel;
614
+ } else {
615
+ return inheritedLevel;
616
+ }
617
+ };
618
+ self.setLevel = function(level, persist) {
619
+ userLevel = normalizeLevel(level);
620
+ if (persist !== false) {
621
+ persistLevelIfPossible(userLevel);
622
+ }
623
+ return replaceLoggingMethods.call(self);
624
+ };
625
+ self.setDefaultLevel = function(level) {
626
+ defaultLevel = normalizeLevel(level);
627
+ if (!getPersistedLevel()) {
628
+ self.setLevel(level, false);
629
+ }
630
+ };
631
+ self.resetLevel = function() {
632
+ userLevel = null;
633
+ clearPersistedLevel();
634
+ replaceLoggingMethods.call(self);
635
+ };
636
+ self.enableAll = function(persist) {
637
+ self.setLevel(self.levels.TRACE, persist);
638
+ };
639
+ self.disableAll = function(persist) {
640
+ self.setLevel(self.levels.SILENT, persist);
641
+ };
642
+ self.rebuild = function() {
643
+ if (defaultLogger !== self) {
644
+ inheritedLevel = normalizeLevel(defaultLogger.getLevel());
645
+ }
646
+ replaceLoggingMethods.call(self);
647
+ if (defaultLogger === self) {
648
+ for (var childName in _loggersByName) {
649
+ _loggersByName[childName].rebuild();
650
+ }
651
+ }
652
+ };
653
+ inheritedLevel = normalizeLevel(
654
+ defaultLogger ? defaultLogger.getLevel() : "WARN"
655
+ );
656
+ var initialLevel = getPersistedLevel();
657
+ if (initialLevel != null) {
658
+ userLevel = normalizeLevel(initialLevel);
659
+ }
660
+ replaceLoggingMethods.call(self);
661
+ }
662
+ defaultLogger = new Logger();
663
+ defaultLogger.getLogger = function getLogger(name) {
664
+ if (typeof name !== "symbol" && typeof name !== "string" || name === "") {
665
+ throw new TypeError("You must supply a name when creating a logger.");
666
+ }
667
+ var logger = _loggersByName[name];
668
+ if (!logger) {
669
+ logger = _loggersByName[name] = new Logger(
670
+ name,
671
+ defaultLogger.methodFactory
672
+ );
673
+ }
674
+ return logger;
675
+ };
676
+ var _log = typeof window !== undefinedType ? window.log : void 0;
677
+ defaultLogger.noConflict = function() {
678
+ if (typeof window !== undefinedType && window.log === defaultLogger) {
679
+ window.log = _log;
680
+ }
681
+ return defaultLogger;
682
+ };
683
+ defaultLogger.getLoggers = function getLoggers() {
684
+ return _loggersByName;
685
+ };
686
+ defaultLogger["default"] = defaultLogger;
687
+ return defaultLogger;
688
+ });
689
+ })(loglevel$1);
690
+ return loglevel$1.exports;
691
+ }
692
+ var loglevelExports = requireLoglevel();
693
+ const log = /* @__PURE__ */ getDefaultExportFromCjs(loglevelExports);
694
+ class VitessceConfigDatasetFile {
695
+ /**
696
+ * Construct a new file definition instance.
697
+ * @param {string} url The URL to the file.
698
+ * @param {string} dataType The type of data contained in the file.
699
+ * @param {string} fileType The file type.
700
+ * @param {object|array|null} options An optional object or array
701
+ * which may provide additional parameters to the loader class
702
+ * corresponding to the specified fileType.
703
+ */
704
+ constructor(url, fileType, coordinationValues, options, requestInit) {
705
+ this.file = {
706
+ url,
707
+ fileType,
708
+ ...coordinationValues ? { coordinationValues } : {},
709
+ ...options ? { options } : {},
710
+ ...requestInit ? { requestInit } : {}
711
+ };
712
+ }
713
+ /**
714
+ * @returns {object} This dataset file as a JSON object.
715
+ */
716
+ toJSON() {
717
+ return this.file;
718
+ }
719
+ }
720
+ class VitessceConfigDataset {
721
+ /**
722
+ * Construct a new dataset definition instance.
723
+ * @param {string} uid The unique ID for the dataset.
724
+ * @param {string} name The name of the dataset.
725
+ * @param {string} description A description for the dataset.
726
+ */
727
+ constructor(uid, name, description) {
728
+ this.dataset = {
729
+ uid,
730
+ name,
731
+ description,
732
+ files: []
733
+ };
734
+ }
735
+ /**
736
+ * Add a file definition to the dataset.
737
+ * @param {object} params An object with named arguments.
738
+ * @param {string|undefined} params.url The URL to the file.
739
+ * @param {string} params.fileType The file type.
740
+ * @param {object|undefined} params.coordinationValues The coordination values.
741
+ * @param {object|array|undefined} params.options An optional object or array
742
+ * which may provide additional parameters to the loader class
743
+ * corresponding to the specified fileType.
744
+ * @returns {VitessceConfigDataset} This, to allow chaining.
745
+ */
746
+ addFile(params, ...args) {
747
+ let url;
748
+ let fileType;
749
+ let coordinationValues;
750
+ let options;
751
+ let requestInit;
752
+ if (args.length > 0) {
753
+ url = params;
754
+ let dataType;
755
+ if (args.length === 2) {
756
+ [dataType, fileType] = args;
757
+ } else if (args.length === 3) {
758
+ [dataType, fileType, options] = args;
759
+ }
760
+ } else if (typeof params === "object") {
761
+ ({
762
+ url,
763
+ fileType,
764
+ options,
765
+ coordinationValues,
766
+ requestInit
767
+ } = params);
768
+ } else {
769
+ throw new Error("Expected addFile argument to be an object.");
770
+ }
771
+ this.dataset.files.push(
772
+ new VitessceConfigDatasetFile(url, fileType, coordinationValues, options, requestInit)
773
+ );
774
+ return this;
775
+ }
776
+ /**
777
+ * @returns {object} This dataset as a JSON object.
778
+ */
779
+ toJSON() {
780
+ return {
781
+ ...this.dataset,
782
+ files: this.dataset.files.map((f) => f.toJSON())
783
+ };
784
+ }
785
+ }
786
+ function useCoordinationByObjectHelper(scopes, coordinationScopes, coordinationScopesBy) {
787
+ function processLevel(parentType, parentScope, levelType, levelVal) {
788
+ if (Array.isArray(levelVal)) {
789
+ coordinationScopesBy[parentType] = {
790
+ ...coordinationScopesBy[parentType] || {},
791
+ [levelType]: {
792
+ ...coordinationScopesBy[parentType]?.[levelType] || {},
793
+ [parentScope.cScope]: levelVal.map((childVal) => childVal.scope.cScope)
794
+ }
795
+ };
796
+ levelVal.forEach((childVal) => {
797
+ if (childVal.children) {
798
+ Object.entries(childVal.children).forEach(([nextLevelType, nextLevelVal]) => processLevel(
799
+ levelType,
800
+ childVal.scope,
801
+ nextLevelType,
802
+ nextLevelVal
803
+ ));
804
+ }
805
+ });
806
+ } else {
807
+ coordinationScopesBy[parentType] = {
808
+ ...coordinationScopesBy[parentType] || {},
809
+ [levelType]: {
810
+ ...coordinationScopesBy[parentType]?.[levelType] || {},
811
+ [parentScope.cScope]: levelVal.scope.cScope
812
+ }
813
+ };
814
+ if (levelVal.children) {
815
+ Object.entries(levelVal.children).forEach(([nextLevelType, nextLevelVal]) => processLevel(
816
+ levelType,
817
+ levelVal.scope,
818
+ nextLevelType,
819
+ nextLevelVal
820
+ ));
821
+ }
822
+ }
823
+ }
824
+ Object.entries(scopes).forEach(([topLevelType, topLevelVal]) => {
825
+ if (Array.isArray(topLevelVal)) {
826
+ coordinationScopes[topLevelType] = topLevelVal.map((levelVal) => levelVal.scope.cScope);
827
+ topLevelVal.forEach((levelVal) => {
828
+ if (levelVal.children) {
829
+ Object.entries(levelVal.children).forEach(([nextLevelType, nextLevelVal]) => processLevel(
830
+ topLevelType,
831
+ levelVal.scope,
832
+ nextLevelType,
833
+ nextLevelVal
834
+ ));
835
+ }
836
+ });
837
+ } else {
838
+ coordinationScopes[topLevelType] = topLevelVal.scope.cScope;
839
+ if (topLevelVal.children) {
840
+ Object.entries(topLevelVal.children).forEach(([nextLevelType, nextLevelVal]) => processLevel(
841
+ topLevelType,
842
+ topLevelVal.scope,
843
+ nextLevelType,
844
+ nextLevelVal
845
+ ));
846
+ }
847
+ }
848
+ });
849
+ return [coordinationScopes, coordinationScopesBy];
850
+ }
851
+ class VitessceConfigView {
852
+ /**
853
+ * Construct a new view instance.
854
+ * @param {string} component The name of the Vitessce component type.
855
+ * @param {object} coordinationScopes A mapping from coordination type
856
+ * names to coordination scope names.
857
+ * @param {number} x The x-coordinate of the view in the layout.
858
+ * @param {number} y The y-coordinate of the view in the layout.
859
+ * @param {number} w The width of the view in the layout.
860
+ * @param {number} h The height of the view in the layout.
861
+ */
862
+ constructor(component, coordinationScopes, x, y, w, h, uid) {
863
+ this.view = {
864
+ component,
865
+ coordinationScopes,
866
+ coordinationScopesBy: void 0,
867
+ // TODO: initialize from parameter?
868
+ x,
869
+ y,
870
+ w,
871
+ h,
872
+ uid
873
+ };
874
+ }
875
+ /**
876
+ * Attach coordination scopes to this view.
877
+ * @param {...VitessceConfigCoordinationScope} args A variable number of
878
+ * coordination scope instances.
879
+ * @returns {VitessceConfigView} This, to allow chaining.
880
+ */
881
+ useCoordination(...args) {
882
+ const cScopes = args;
883
+ cScopes.forEach((cScope) => {
884
+ this.view.coordinationScopes[cScope.cType] = cScope.cScope;
885
+ });
886
+ return this;
887
+ }
888
+ /**
889
+ * Attach potentially multi-level coordination scopes to this view.
890
+ * @param {object} scopes A value returned by `VitessceConfig.addCoordinationByObject`.
891
+ * Not intended to be a manually-constructed object.
892
+ * @returns {VitessceConfigView} This, to allow chaining.
893
+ */
894
+ useCoordinationByObject(scopes) {
895
+ if (!this.view.coordinationScopes) {
896
+ this.view.coordinationScopes = {};
897
+ }
898
+ if (!this.view.coordinationScopesBy) {
899
+ this.view.coordinationScopesBy = {};
900
+ }
901
+ const [nextCoordinationScopes, nextCoordinationScopesBy] = useCoordinationByObjectHelper(
902
+ scopes,
903
+ this.view.coordinationScopes,
904
+ this.view.coordinationScopesBy
905
+ );
906
+ this.view.coordinationScopes = nextCoordinationScopes;
907
+ this.view.coordinationScopesBy = nextCoordinationScopesBy;
908
+ return this;
909
+ }
910
+ /**
911
+ * Attach meta coordination scopes to this view.
912
+ * @param {VitessceConfigMetaCoordinationScope} metaScope A meta coordination scope instance.
913
+ * @returns {VitessceConfigView} This, to allow chaining.
914
+ */
915
+ useMetaCoordination(metaScope) {
916
+ if (!this.view.coordinationScopes) {
917
+ this.view.coordinationScopes = {};
918
+ }
919
+ this.view.coordinationScopes[CoordinationType.META_COORDINATION_SCOPES] = [
920
+ ...this.view.coordinationScopes[CoordinationType.META_COORDINATION_SCOPES] || [],
921
+ metaScope.metaScope.cScope
922
+ ];
923
+ this.view.coordinationScopes[CoordinationType.META_COORDINATION_SCOPES_BY] = [
924
+ ...this.view.coordinationScopes[CoordinationType.META_COORDINATION_SCOPES_BY] || [],
925
+ metaScope.metaByScope.cScope
926
+ ];
927
+ return this;
928
+ }
929
+ /**
930
+ * Set the x, y, w, h values for this view.
931
+ * @param {number} x The x-coordinate of the view in the layout.
932
+ * @param {number} y The y-coordinate of the view in the layout.
933
+ * @param {number} w The width of the view in the layout.
934
+ * @param {number} h The height of the view in the layout.
935
+ * @returns {VitessceConfigView} This, to allow chaining.
936
+ */
937
+ setXYWH(x, y, w, h) {
938
+ this.view.x = x;
939
+ this.view.y = y;
940
+ this.view.w = w;
941
+ this.view.h = h;
942
+ return this;
943
+ }
944
+ /**
945
+ * Set props for this view.
946
+ * @returns {VitessceConfigView} This, to allow chaining.
947
+ */
948
+ setProps(props) {
949
+ this.view.props = {
950
+ ...this.view.props || {},
951
+ ...props
952
+ };
953
+ return this;
954
+ }
955
+ /**
956
+ * @returns {object} This view as a JSON object.
957
+ */
958
+ toJSON() {
959
+ return this.view;
960
+ }
961
+ }
962
+ class VitessceConfigViewHConcat {
963
+ constructor(views) {
964
+ this.views = views;
965
+ }
966
+ }
967
+ class VitessceConfigViewVConcat {
968
+ constructor(views) {
969
+ this.views = views;
970
+ }
971
+ }
972
+ function hconcat(...views) {
973
+ const vcvhc = new VitessceConfigViewHConcat(views);
974
+ return vcvhc;
975
+ }
976
+ function vconcat(...views) {
977
+ const vcvvc = new VitessceConfigViewVConcat(views);
978
+ return vcvvc;
979
+ }
980
+ class CoordinationLevel {
981
+ constructor(value) {
982
+ this.value = value;
983
+ this.cachedValue = null;
984
+ }
985
+ setCached(processedLevel) {
986
+ this.cachedValue = processedLevel;
987
+ }
988
+ getCached() {
989
+ return this.cachedValue;
990
+ }
991
+ isCached() {
992
+ return this.cachedValue !== null;
993
+ }
994
+ }
995
+ function CL(value) {
996
+ return new CoordinationLevel(value);
997
+ }
998
+ class VitessceConfigCoordinationScope {
999
+ /**
1000
+ * Construct a new coordination scope instance.
1001
+ * @param {string} cType The coordination type for this coordination scope.
1002
+ * @param {string} cScope The name of the coordination scope.
1003
+ * @param {[any]} cValue Optional. The coordination value of the coordination scope.
1004
+ */
1005
+ constructor(cType, cScope, cValue = null) {
1006
+ this.cType = cType;
1007
+ this.cScope = cScope;
1008
+ this.cValue = cValue;
1009
+ }
1010
+ /**
1011
+ * Set the coordination value of the coordination scope.
1012
+ * @param {any} cValue The value to set.
1013
+ * @returns {VitessceConfigCoordinationScope} This, to allow chaining.
1014
+ */
1015
+ setValue(cValue) {
1016
+ this.cValue = cValue;
1017
+ return this;
1018
+ }
1019
+ }
1020
+ class VitessceConfigMetaCoordinationScope {
1021
+ /**
1022
+ * Construct a new coordination scope instance.
1023
+ * @param {string} metaScope The name of the coordination scope for metaCoordinationScopes.
1024
+ * @param {string} metaByScope The name of the coordination scope for metaCoordinationScopesBy.
1025
+ */
1026
+ constructor(metaScope, metaByScope) {
1027
+ this.metaScope = new VitessceConfigCoordinationScope(
1028
+ CoordinationType.META_COORDINATION_SCOPES,
1029
+ metaScope
1030
+ );
1031
+ this.metaByScope = new VitessceConfigCoordinationScope(
1032
+ CoordinationType.META_COORDINATION_SCOPES_BY,
1033
+ metaByScope
1034
+ );
1035
+ }
1036
+ /**
1037
+ * Attach coordination scopes to this meta scope.
1038
+ * @param {...VitessceConfigCoordinationScope} args A variable number of
1039
+ * coordination scope instances.
1040
+ * @returns {VitessceConfigMetaCoordinationScope} This, to allow chaining.
1041
+ */
1042
+ useCoordination(...args) {
1043
+ const cScopes = args;
1044
+ const metaScopesVal = this.metaScope.cValue;
1045
+ cScopes.forEach((cScope) => {
1046
+ metaScopesVal[cScope.cType] = cScope.cScope;
1047
+ });
1048
+ this.metaScope.setValue(metaScopesVal);
1049
+ return this;
1050
+ }
1051
+ /**
1052
+ * Attach potentially multi-level coordination scopes to this meta coordination
1053
+ * scope instance.
1054
+ * @param {object} scopes A value returned by `VitessceConfig.addCoordinationByObject`.
1055
+ * Not intended to be a manually-constructed object.
1056
+ * @returns {VitessceConfigView} This, to allow chaining.
1057
+ */
1058
+ useCoordinationByObject(scopes) {
1059
+ if (!this.metaScope.cValue) {
1060
+ this.metaScope.setValue({});
1061
+ }
1062
+ if (!this.metaByScope.cValue) {
1063
+ this.metaByScope.setValue({});
1064
+ }
1065
+ const [metaScopesVal, metaByScopesVal] = useCoordinationByObjectHelper(
1066
+ scopes,
1067
+ this.metaScope.cValue,
1068
+ this.metaByScope.cValue
1069
+ );
1070
+ this.metaScope.setValue(metaScopesVal);
1071
+ this.metaByScope.setValue(metaByScopesVal);
1072
+ return this;
1073
+ }
1074
+ }
1075
+ class VitessceConfig {
1076
+ /**
1077
+ * Construct a new view config instance.
1078
+ * @param {object} params An object with named arguments.
1079
+ * @param {string} params.schemaVersion The view config schema version. Required.
1080
+ * @param {string} params.name A name for the config. Optional.
1081
+ * @param {string|undefined} params.description A description for the config. Optional.
1082
+ */
1083
+ constructor(params, ...args) {
1084
+ let name;
1085
+ let description;
1086
+ let schemaVersion;
1087
+ if (typeof params === "string") {
1088
+ schemaVersion = "1.0.7";
1089
+ name = params || "";
1090
+ if (args.length === 1) {
1091
+ [description] = args;
1092
+ } else if (args.length > 1) {
1093
+ throw new Error("Expected only one VitessceConfig constructor argument.");
1094
+ }
1095
+ } else if (typeof params === "object") {
1096
+ ({ schemaVersion, name, description } = params);
1097
+ if (!name) {
1098
+ throw new Error("Expected params.name argument in VitessceConfig constructor");
1099
+ }
1100
+ if (!schemaVersion) {
1101
+ throw new Error("Expected params.schemaVersion argument in VitessceConfig constructor");
1102
+ }
1103
+ } else {
1104
+ throw new Error("Expected VitessceConfig constructor argument to be an object.");
1105
+ }
1106
+ this.config = {
1107
+ version: schemaVersion,
1108
+ name,
1109
+ description,
1110
+ datasets: [],
1111
+ coordinationSpace: {},
1112
+ layout: [],
1113
+ initStrategy: "auto"
1114
+ };
1115
+ this.getNextScope = getNextScope;
1116
+ }
1117
+ /**
1118
+ * Add a new dataset to the config.
1119
+ * @param {string} name A name for the dataset. Optional.
1120
+ * @param {string} description A description for the dataset. Optional.
1121
+ * @param {object} options Extra parameters to be used internally. Optional.
1122
+ * @param {string} options.uid Override the automatically-generated dataset ID.
1123
+ * Intended for internal usage by the VitessceConfig.fromJSON code.
1124
+ * @returns {VitessceConfigDataset} A new dataset instance.
1125
+ */
1126
+ addDataset(name = void 0, description = void 0, options = void 0) {
1127
+ const { uid } = options || {};
1128
+ const prevDatasetUids = this.config.datasets.map((d) => d.dataset.uid);
1129
+ const nextUid = uid || this.getNextScope(prevDatasetUids);
1130
+ const newDataset = new VitessceConfigDataset(nextUid, name, description);
1131
+ this.config.datasets.push(newDataset);
1132
+ const [newScope] = this.addCoordination(CoordinationType.DATASET);
1133
+ newScope.setValue(nextUid);
1134
+ return newDataset;
1135
+ }
1136
+ /**
1137
+ * Add a new view to the config.
1138
+ * @param {VitessceConfigDataset} dataset The dataset instance which defines the data
1139
+ * that will be displayed in the view.
1140
+ * @param {string} component A component name, such as "scatterplot"
1141
+ * or "spatial".
1142
+ * @param {object|undefined} options Extra options for the component.
1143
+ * @param {number|undefined} options.x The x-coordinate for the view
1144
+ * in the grid layout.
1145
+ * @param {number|undefined} options.y The y-coordinate for the view
1146
+ * in the grid layout.
1147
+ * @param {number|undefined} options.w The width for the view in the
1148
+ * grid layout.
1149
+ * @param {number|undefined} options.h The height for the view in the
1150
+ * grid layout.
1151
+ * @param {string|undefined} options.mapping A convenience parameter
1152
+ * for setting the EMBEDDING_TYPE
1153
+ * coordination value. Only applicable if the component is "scatterplot".
1154
+ * @returns {VitessceConfigView} A new view instance.
1155
+ */
1156
+ addView(dataset, component, options) {
1157
+ const {
1158
+ x = 0,
1159
+ y = 0,
1160
+ w = 1,
1161
+ h = 1,
1162
+ uid = void 0,
1163
+ mapping = null
1164
+ } = options || {};
1165
+ const datasetMatches = this.config.coordinationSpace[CoordinationType.DATASET] ? Object.entries(this.config.coordinationSpace[CoordinationType.DATASET]).filter(([scopeName, datasetScope2]) => datasetScope2.cValue === dataset.dataset.uid).map(([scopeName]) => scopeName) : [];
1166
+ let datasetScope;
1167
+ if (datasetMatches.length === 1) {
1168
+ [datasetScope] = datasetMatches;
1169
+ } else {
1170
+ throw new Error("No coordination scope matching the dataset parameter could be found in the coordination space.");
1171
+ }
1172
+ const coordinationScopes = {
1173
+ [CoordinationType.DATASET]: datasetScope
1174
+ };
1175
+ const newView = new VitessceConfigView(component, coordinationScopes, x, y, w, h, uid);
1176
+ if (mapping) {
1177
+ const [etScope] = this.addCoordination(CoordinationType.EMBEDDING_TYPE);
1178
+ etScope.setValue(mapping);
1179
+ newView.useCoordination(etScope);
1180
+ }
1181
+ this.config.layout.push(newView);
1182
+ return newView;
1183
+ }
1184
+ /**
1185
+ * Get an array of new coordination scope instances corresponding to coordination types
1186
+ * of interest.
1187
+ * @param {...string} args A variable number of coordination type names.
1188
+ * @returns {VitessceConfigCoordinationScope[]} An array of coordination scope instances.
1189
+ */
1190
+ addCoordination(...args) {
1191
+ const cTypes = args;
1192
+ const result = [];
1193
+ cTypes.forEach((cTypeOrObj) => {
1194
+ let cType;
1195
+ let cScope;
1196
+ let cValue;
1197
+ if (typeof cTypeOrObj === "string") {
1198
+ cType = cTypeOrObj;
1199
+ const prevScopes = this.config.coordinationSpace[cType] ? Object.keys(this.config.coordinationSpace[cType]) : [];
1200
+ cScope = this.getNextScope(prevScopes);
1201
+ } else {
1202
+ cType = cTypeOrObj.cType;
1203
+ cScope = cTypeOrObj.cScope;
1204
+ cValue = cTypeOrObj.cValue;
1205
+ }
1206
+ const scope = new VitessceConfigCoordinationScope(cType, cScope, cValue);
1207
+ if (!this.config.coordinationSpace[scope.cType]) {
1208
+ this.config.coordinationSpace[scope.cType] = {};
1209
+ }
1210
+ this.config.coordinationSpace[scope.cType][scope.cScope] = scope;
1211
+ result.push(scope);
1212
+ });
1213
+ return result;
1214
+ }
1215
+ /**
1216
+ * Initialize a new meta coordination scope in the coordination space,
1217
+ * and get a reference to it in the form of a meta coordination scope instance.
1218
+ * @returns {VitessceConfigMetaCoordinationScope} A new meta coordination scope instance.
1219
+ */
1220
+ addMetaCoordination() {
1221
+ const prevMetaScopes = this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES] ? Object.keys(this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES]) : [];
1222
+ const prevMetaByScopes = this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES_BY] ? Object.keys(this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES_BY]) : [];
1223
+ const metaContainer = new VitessceConfigMetaCoordinationScope(
1224
+ this.getNextScope(prevMetaScopes),
1225
+ this.getNextScope(prevMetaByScopes)
1226
+ );
1227
+ if (!this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES]) {
1228
+ this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES] = {};
1229
+ }
1230
+ if (!this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES_BY]) {
1231
+ this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES_BY] = {};
1232
+ }
1233
+ this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES][metaContainer.metaScope.cScope] = metaContainer.metaScope;
1234
+ this.config.coordinationSpace[CoordinationType.META_COORDINATION_SCOPES_BY][metaContainer.metaByScope.cScope] = metaContainer.metaByScope;
1235
+ return metaContainer;
1236
+ }
1237
+ /**
1238
+ * Set up the initial values for multi-level coordination in the coordination space.
1239
+ * Get a reference to these values to pass to the `useCoordinationByObject` method
1240
+ * of either view or meta coordination scope instances.
1241
+ * @param {object} input A (potentially nested) object with coordination types as keys
1242
+ * and values being either the initial coordination value, a `VitessceConfigCoordinationScope`
1243
+ * instance, or a `CoordinationLevel` instance.
1244
+ * The CL function takes an array of objects as its argument, and returns a CoordinationLevel
1245
+ * instance, to support nesting.
1246
+ * @returns {object} A (potentially nested) object with coordination types as keys and values
1247
+ * being either { scope }, { scope, children }, or an array of these. Not intended to be
1248
+ * manipulated before being passed to a `useCoordinationByObject` function.
1249
+ */
1250
+ addCoordinationByObject(input) {
1251
+ const processLevel = (level) => {
1252
+ const result = {};
1253
+ if (level === null) {
1254
+ return result;
1255
+ }
1256
+ Object.entries(level).forEach(([cType, nextLevelOrInitialValue]) => {
1257
+ if (nextLevelOrInitialValue instanceof CoordinationLevel) {
1258
+ const nextLevel = nextLevelOrInitialValue.value;
1259
+ if (nextLevelOrInitialValue.isCached()) {
1260
+ result[cType] = nextLevelOrInitialValue.getCached();
1261
+ } else if (Array.isArray(nextLevel)) {
1262
+ const processedLevel = nextLevel.map((nextEl) => {
1263
+ const [dummyScope] = this.addCoordination(cType);
1264
+ dummyScope.setValue("__dummy__");
1265
+ return {
1266
+ scope: dummyScope,
1267
+ children: processLevel(nextEl)
1268
+ };
1269
+ });
1270
+ nextLevelOrInitialValue.setCached(processedLevel);
1271
+ result[cType] = processedLevel;
1272
+ } else {
1273
+ const nextEl = nextLevel;
1274
+ const [dummyScope] = this.addCoordination(cType);
1275
+ dummyScope.setValue("__dummy__");
1276
+ const processedLevel = {
1277
+ scope: dummyScope,
1278
+ children: processLevel(nextEl)
1279
+ };
1280
+ nextLevelOrInitialValue.setCached(processedLevel);
1281
+ result[cType] = processedLevel;
1282
+ }
1283
+ } else {
1284
+ const initialValue = nextLevelOrInitialValue;
1285
+ if (initialValue instanceof VitessceConfigCoordinationScope) {
1286
+ result[cType] = { scope: initialValue };
1287
+ } else {
1288
+ const [scope] = this.addCoordination(cType);
1289
+ scope.setValue(initialValue);
1290
+ result[cType] = { scope };
1291
+ }
1292
+ }
1293
+ });
1294
+ return result;
1295
+ };
1296
+ const output = processLevel(input);
1297
+ return output;
1298
+ }
1299
+ /**
1300
+ * A convenience function for setting up new coordination scopes across a set of views.
1301
+ * @param {VitessceConfigView[]} views An array of view objects to link together.
1302
+ * @param {string[]} cTypes The coordination types on which to coordinate the views.
1303
+ * @param {any[]} cValues Initial values corresponding to each coordination type.
1304
+ * Should have the same length as the cTypes array. Optional.
1305
+ * @returns {VitessceConfig} This, to allow chaining.
1306
+ */
1307
+ linkViews(views, cTypes, cValues = null) {
1308
+ const cScopes = this.addCoordination(...cTypes);
1309
+ views.forEach((view) => {
1310
+ cScopes.forEach((cScope) => {
1311
+ view.useCoordination(cScope);
1312
+ });
1313
+ });
1314
+ if (Array.isArray(cValues) && cValues.length === cTypes.length) {
1315
+ cScopes.forEach((cScope, i) => {
1316
+ cScope.setValue(cValues[i]);
1317
+ });
1318
+ }
1319
+ return this;
1320
+ }
1321
+ /**
1322
+ * A convenience function for setting up multi-level and meta-coordination scopes
1323
+ * across a set of views.
1324
+ * @param {VitessceConfigView[]} views An array of view objects to link together.
1325
+ * @param {object} input A (potentially nested) object with coordination types as keys
1326
+ * and values being either the initial coordination value, a `VitessceConfigCoordinationScope`
1327
+ * instance, or a `CoordinationLevel` instance.
1328
+ * The CL function takes an array of objects as its argument, and returns a CoordinationLevel
1329
+ * instance, to support nesting.
1330
+ * @param {object|null} options
1331
+ * @param {bool} options.meta Should meta-coordination be used? Optional.
1332
+ * By default, true.
1333
+ * @param {string|null} options.scopePrefix A prefix to add to all
1334
+ * coordination scope names. Optional.
1335
+ * @returns {VitessceConfig} This, to allow chaining.
1336
+ */
1337
+ linkViewsByObject(views, input, options = null) {
1338
+ const { meta = true, scopePrefix = null } = options || {};
1339
+ if (scopePrefix) {
1340
+ this.getNextScope = createPrefixedGetNextScopeNumeric(scopePrefix);
1341
+ }
1342
+ const scopes = this.addCoordinationByObject(input);
1343
+ if (meta) {
1344
+ const metaScope = this.addMetaCoordination();
1345
+ metaScope.useCoordinationByObject(scopes);
1346
+ views.forEach((view) => {
1347
+ view.useMetaCoordination(metaScope);
1348
+ });
1349
+ } else {
1350
+ views.forEach((view) => {
1351
+ view.useCoordinationByObject(scopes);
1352
+ });
1353
+ }
1354
+ if (scopePrefix) {
1355
+ this.getNextScope = getNextScope;
1356
+ }
1357
+ return this;
1358
+ }
1359
+ /**
1360
+ * Set the value for a coordination scope.
1361
+ * If a coordination object for the coordination type does not yet exist
1362
+ * in the coordination space, it will be created.
1363
+ * @param {string} cType The coordination type.
1364
+ * @param {string} cScope The coordination scope.
1365
+ * @param {any} cValue The initial value for the coordination scope.
1366
+ * @returns {VitessceConfigCoordinationScope} A coordination scope instance.
1367
+ */
1368
+ setCoordinationValue(cType, cScope, cValue) {
1369
+ const scope = new VitessceConfigCoordinationScope(cType, cScope, cValue);
1370
+ if (!this.config.coordinationSpace[scope.cType]) {
1371
+ this.config.coordinationSpace[scope.cType] = {};
1372
+ }
1373
+ this.config.coordinationSpace[scope.cType][scope.cScope] = scope;
1374
+ return scope;
1375
+ }
1376
+ /**
1377
+ * Set the layout of views.
1378
+ * @param {VitessceConfigView|VitessceConfigViewHConcat|VitessceConfigViewVConcat} viewConcat A
1379
+ * view or a concatenation of views.
1380
+ * @returns {VitessceConfig} This, to allow chaining.
1381
+ */
1382
+ layout(viewConcat) {
1383
+ function layoutAux(obj, xMin, xMax, yMin, yMax) {
1384
+ const w = xMax - xMin;
1385
+ const h = yMax - yMin;
1386
+ if (obj instanceof VitessceConfigView) {
1387
+ obj.setXYWH(xMin, yMin, w, h);
1388
+ } else if (obj instanceof VitessceConfigViewHConcat) {
1389
+ const { views } = obj;
1390
+ const numViews = views.length;
1391
+ views.forEach((view, i) => {
1392
+ layoutAux(view, xMin + w / numViews * i, xMin + w / numViews * (i + 1), yMin, yMax);
1393
+ });
1394
+ } else if (obj instanceof VitessceConfigViewVConcat) {
1395
+ const { views } = obj;
1396
+ const numViews = views.length;
1397
+ views.forEach((view, i) => {
1398
+ layoutAux(view, xMin, xMax, yMin + h / numViews * i, yMin + h / numViews * (i + 1));
1399
+ });
1400
+ }
1401
+ }
1402
+ layoutAux(viewConcat, 0, 12, 0, 12);
1403
+ return this;
1404
+ }
1405
+ /**
1406
+ * Convert this instance to a JSON object that can be passed to the Vitessce component.
1407
+ * @returns {object} The view config as a JSON object.
1408
+ */
1409
+ toJSON() {
1410
+ return {
1411
+ ...this.config,
1412
+ datasets: this.config.datasets.map((d) => d.toJSON()),
1413
+ coordinationSpace: Object.fromEntries(
1414
+ Object.entries(this.config.coordinationSpace).map(([cType, cScopes]) => [
1415
+ cType,
1416
+ Object.fromEntries(
1417
+ Object.entries(cScopes).map(([cScopeName, cScope]) => [
1418
+ cScopeName,
1419
+ cScope.cValue
1420
+ ])
1421
+ )
1422
+ ])
1423
+ ),
1424
+ layout: this.config.layout.map((c) => c.toJSON())
1425
+ };
1426
+ }
1427
+ /**
1428
+ * Create a VitessceConfig instance from an existing view config, to enable
1429
+ * manipulation with the JavaScript API.
1430
+ * @param {object} config An existing Vitessce view config as a JSON object.
1431
+ * @returns {VitessceConfig} A new config instance, with values set to match
1432
+ * the config parameter.
1433
+ */
1434
+ static fromJSON(config2) {
1435
+ const { name, description, version: schemaVersion } = config2;
1436
+ const vc = new VitessceConfig({ schemaVersion, name, description });
1437
+ config2.datasets.forEach((d) => {
1438
+ const newDataset = vc.addDataset(d.name, d.description, { uid: d.uid });
1439
+ d.files.forEach((f) => {
1440
+ newDataset.addFile({
1441
+ url: f.url,
1442
+ fileType: f.fileType,
1443
+ coordinationValues: f.coordinationValues,
1444
+ options: f.options
1445
+ });
1446
+ });
1447
+ });
1448
+ Object.keys(config2.coordinationSpace).forEach((cType) => {
1449
+ if (cType !== CoordinationType.DATASET) {
1450
+ const cObj = config2.coordinationSpace[cType];
1451
+ vc.config.coordinationSpace[cType] = {};
1452
+ Object.entries(cObj).forEach(([cScopeName, cScopeValue]) => {
1453
+ const scope = new VitessceConfigCoordinationScope(cType, cScopeName);
1454
+ scope.setValue(cScopeValue);
1455
+ vc.config.coordinationSpace[cType][cScopeName] = scope;
1456
+ });
1457
+ }
1458
+ });
1459
+ config2.layout.forEach((c) => {
1460
+ const newView = new VitessceConfigView(
1461
+ c.component,
1462
+ c.coordinationScopes,
1463
+ c.x,
1464
+ c.y,
1465
+ c.w,
1466
+ c.h,
1467
+ c.uid
1468
+ );
1469
+ vc.config.layout.push(newView);
1470
+ });
1471
+ return vc;
1472
+ }
1473
+ }
1474
+ function getCoordinationSpaceAndScopes(partialCoordinationValues, scopePrefix) {
1475
+ const vc = new VitessceConfig({ schemaVersion: "1.0.16", name: "__dummy__" });
1476
+ vc.getNextScope = createPrefixedGetNextScopeNumeric(scopePrefix);
1477
+ const dataset = vc.addDataset("__dummy__");
1478
+ const v1 = vc.addView(dataset, "__dummy__");
1479
+ vc.linkViewsByObject([v1], partialCoordinationValues, { meta: true });
1480
+ const vcJson = vc.toJSON();
1481
+ const { coordinationSpace } = vcJson;
1482
+ const { coordinationScopes } = vcJson.layout[0];
1483
+ const { coordinationScopesBy } = vcJson.layout[0];
1484
+ return {
1485
+ coordinationSpace,
1486
+ coordinationScopes,
1487
+ coordinationScopesBy
1488
+ };
1489
+ }
1490
+ const SINGLE_CELL_WITH_HEATMAP_VIEWS = {
1491
+ obsSets: { x: 4, y: 0, w: 4, h: 4 },
1492
+ obsSetSizes: { x: 8, y: 0, w: 4, h: 4 },
1493
+ scatterplot: { x: 0, y: 0, w: 4, h: 4 },
1494
+ heatmap: { x: 0, y: 4, w: 8, h: 4 },
1495
+ featureList: { x: 8, y: 4, w: 4, h: 4 }
1496
+ };
1497
+ const SINGLE_CELL_WITHOUT_HEATMAP_VIEWS = {
1498
+ obsSets: { x: 10, y: 6, w: 2, h: 6 },
1499
+ obsSetSizes: { x: 8, y: 1, w: 4, h: 6 },
1500
+ scatterplot: { x: 0, y: 0, w: 8, h: 12 },
1501
+ featureList: { x: 8, y: 6, w: 2, h: 6 }
1502
+ };
1503
+ const SPATIAL_TRANSCRIPTOMICS_VIEWS = {
1504
+ scatterplot: { x: 0, y: 0, w: 3, h: 4 },
1505
+ spatial: { x: 3, y: 0, w: 5, h: 4 },
1506
+ obsSets: { x: 8, y: 0, w: 4, h: 2 },
1507
+ featureList: { x: 8, y: 0, w: 4, h: 2 },
1508
+ heatmap: { x: 0, y: 4, w: 6, h: 4 },
1509
+ obsSetFeatureValueDistribution: { x: 6, y: 4, w: 6, h: 4 }
1510
+ };
1511
+ const SPATIAL_TRANSCRIPTOMICS_WITH_HSITOLOGY_VIEWS = {
1512
+ spatial: { x: 0, y: 0, w: 6, h: 6 },
1513
+ heatmap: { x: 0, y: 6, w: 8, h: 6 },
1514
+ layerController: { x: 8, y: 6, w: 4, h: 6 },
1515
+ obsSets: { x: 9, y: 0, w: 3, h: 6 },
1516
+ featureList: { x: 6, y: 0, w: 3, h: 6 }
1517
+ };
1518
+ const IMAGE_VIEWS = {
1519
+ spatial: { x: 0, y: 0, w: 8, h: 12 },
1520
+ layerController: { x: 8, y: 0, w: 4, h: 7 },
1521
+ description: { x: 8, y: 9, w: 4, h: 5 }
1522
+ };
1523
+ const NO_HINTS_CONFIG = {
1524
+ views: {},
1525
+ coordinationValues: {}
1526
+ };
1527
+ const HINTS_CONFIG = {
1528
+ "No hints are available. Generate config with no hints.": NO_HINTS_CONFIG,
1529
+ Basic: NO_HINTS_CONFIG,
1530
+ "Transcriptomics / scRNA-seq (with heatmap)": {
1531
+ views: SINGLE_CELL_WITH_HEATMAP_VIEWS
1532
+ },
1533
+ "Transcriptomics / scRNA-seq (without heatmap)": {
1534
+ views: SINGLE_CELL_WITHOUT_HEATMAP_VIEWS
1535
+ },
1536
+ "Spatial transcriptomics (with polygon cell segmentations)": {
1537
+ views: SPATIAL_TRANSCRIPTOMICS_VIEWS
1538
+ },
1539
+ "Chromatin accessibility / scATAC-seq (with heatmap)": {
1540
+ views: SINGLE_CELL_WITH_HEATMAP_VIEWS,
1541
+ coordinationValues: {
1542
+ featureType: "peak"
1543
+ }
1544
+ },
1545
+ "Chromatin accessibility / scATAC-seq (without heatmap)": {
1546
+ views: SINGLE_CELL_WITHOUT_HEATMAP_VIEWS,
1547
+ coordinationValues: {
1548
+ featureType: "peak"
1549
+ }
1550
+ },
1551
+ "Spatial transcriptomics (with histology image and polygon cell segmentations)": {
1552
+ views: SPATIAL_TRANSCRIPTOMICS_WITH_HSITOLOGY_VIEWS,
1553
+ coordinationSpaceRequired: true
1554
+ },
1555
+ Image: {
1556
+ views: IMAGE_VIEWS
1557
+ }
1558
+ };
1559
+ const HINT_TYPE_TO_FILE_TYPE_MAP = {
1560
+ "AnnData-Zarr": [
1561
+ "Basic",
1562
+ "Transcriptomics / scRNA-seq (with heatmap)",
1563
+ "Transcriptomics / scRNA-seq (without heatmap)",
1564
+ "Spatial transcriptomics (with polygon cell segmentations)",
1565
+ "Chromatin accessibility / scATAC-seq (with heatmap)",
1566
+ "Chromatin accessibility / scATAC-seq (without heatmap)"
1567
+ ],
1568
+ "OME-TIFF": [
1569
+ "Basic",
1570
+ "Image"
1571
+ ],
1572
+ "AnnData-Zarr,OME-TIFF": [
1573
+ "Basic",
1574
+ "Spatial transcriptomics (with histology image and polygon cell segmentations)"
1575
+ ]
1576
+ };
1577
+ const filterViews = (hintsConfig, possibleViews) => {
1578
+ const requiredViews = Object.keys(hintsConfig.views);
1579
+ if (requiredViews.length === 0) {
1580
+ return possibleViews;
1581
+ }
1582
+ const resultViews = [];
1583
+ requiredViews.forEach((requiredView) => {
1584
+ const match = possibleViews.find((possibleView) => possibleView[0] === requiredView);
1585
+ if (match) resultViews.push(match);
1586
+ });
1587
+ if (resultViews.length === 0) {
1588
+ throw new Error("No views found that are compatible with the supplied dataset URLs and hint.");
1589
+ }
1590
+ return resultViews;
1591
+ };
1592
+ let AbstractAutoConfig$1 = class AbstractAutoConfig {
1593
+ async composeViewsConfig() {
1594
+ throw new Error("The composeViewsConfig() method has not been implemented.");
1595
+ }
1596
+ async composeFileConfig() {
1597
+ throw new Error("The composeFileConfig() method has not been implemented.");
1598
+ }
1599
+ };
1600
+ class OmeTiffAutoConfig extends AbstractAutoConfig$1 {
1601
+ constructor(fileUrl) {
1602
+ super();
1603
+ this.fileUrl = fileUrl;
1604
+ this.fileType = FileType.RASTER_JSON;
1605
+ this.fileName = fileUrl.split("/").at(-1);
1606
+ }
1607
+ async composeViewsConfig(hintsConfig) {
1608
+ return filterViews(
1609
+ hintsConfig,
1610
+ [["description"], ["spatial"], ["layerController"]]
1611
+ );
1612
+ }
1613
+ async composeFileConfig() {
1614
+ return {
1615
+ fileType: this.fileType,
1616
+ options: {
1617
+ images: [
1618
+ {
1619
+ metadata: {
1620
+ isBitmask: false
1621
+ },
1622
+ name: this.fileName,
1623
+ type: "ome-tiff",
1624
+ url: this.fileUrl
1625
+ }
1626
+ ],
1627
+ schemaVersion: "0.0.2",
1628
+ usePhysicalSizeScaling: false
1629
+ }
1630
+ };
1631
+ }
1632
+ }
1633
+ class OmeZarrAutoConfig extends AbstractAutoConfig$1 {
1634
+ constructor(fileUrl) {
1635
+ super();
1636
+ this.fileUrl = fileUrl;
1637
+ this.fileType = FileType.RASTER_OME_ZARR;
1638
+ this.fileName = fileUrl.split("/").at(-1);
1639
+ }
1640
+ async composeViewsConfig(hintsConfig) {
1641
+ return filterViews(
1642
+ hintsConfig,
1643
+ [["description"], ["spatial"], ["layerController"]]
1644
+ );
1645
+ }
1646
+ async composeFileConfig() {
1647
+ return {
1648
+ fileType: this.fileType,
1649
+ type: "raster",
1650
+ url: this.fileUrl
1651
+ };
1652
+ }
1653
+ }
1654
+ class AnndataZarrAutoConfig extends AbstractAutoConfig$1 {
1655
+ constructor(fileUrl) {
1656
+ super();
1657
+ this.fileUrl = fileUrl;
1658
+ this.fileType = FileType.ANNDATA_ZARR;
1659
+ this.fileName = fileUrl.split("/").at(-1);
1660
+ this.metadataSummary = {};
1661
+ }
1662
+ async composeFileConfig() {
1663
+ this.metadataSummary = await this.setMetadataSummary();
1664
+ const options = {
1665
+ obsEmbedding: [],
1666
+ obsFeatureMatrix: {
1667
+ path: "X"
1668
+ }
1669
+ };
1670
+ this.metadataSummary.obsm.forEach((key) => {
1671
+ if (key.toLowerCase().includes("obsm/x_segmentations")) {
1672
+ options.obsSegmentations = { path: key };
1673
+ }
1674
+ if (key.toLowerCase().includes("obsm/x_spatial")) {
1675
+ options.obsLocations = { path: key };
1676
+ }
1677
+ if (key.toLowerCase().includes("obsm/x_umap")) {
1678
+ options.obsEmbedding.push({ path: key, embeddingType: "UMAP" });
1679
+ }
1680
+ if (key.toLowerCase().includes("obsm/x_tsne")) {
1681
+ options.obsEmbedding.push({ path: key, embeddingType: "t-SNE" });
1682
+ }
1683
+ if (key.toLowerCase().includes("obsm/x_pca")) {
1684
+ options.obsEmbedding.push({ path: key, embeddingType: "PCA" });
1685
+ }
1686
+ });
1687
+ const supportedObsSetsKeys = [
1688
+ "cluster",
1689
+ "clusters",
1690
+ "subcluster",
1691
+ "cell_type",
1692
+ "celltype",
1693
+ "leiden",
1694
+ "louvain",
1695
+ "disease",
1696
+ "organism",
1697
+ "self_reported_ethnicity",
1698
+ "tissue",
1699
+ "sex"
1700
+ ];
1701
+ this.metadataSummary.obs.forEach((key) => {
1702
+ supportedObsSetsKeys.forEach((supportedKey) => {
1703
+ if (key.toLowerCase() === ["obs", supportedKey].join("/")) {
1704
+ if (!("obsSets" in options)) {
1705
+ options.obsSets = [
1706
+ {
1707
+ name: "Cell Type",
1708
+ path: [key]
1709
+ }
1710
+ ];
1711
+ } else {
1712
+ options.obsSets[0].path.push(key);
1713
+ }
1714
+ }
1715
+ });
1716
+ });
1717
+ options.obsSets = options.obsSets?.map((obsSet) => {
1718
+ if (obsSet.path.length === 1) {
1719
+ return {
1720
+ ...obsSet,
1721
+ path: obsSet.path[0]
1722
+ };
1723
+ }
1724
+ return obsSet;
1725
+ });
1726
+ return {
1727
+ options,
1728
+ fileType: this.fileType,
1729
+ url: this.fileUrl,
1730
+ coordinationValues: {
1731
+ obsType: "cell",
1732
+ featureType: "gene",
1733
+ featureValueType: "expression"
1734
+ }
1735
+ };
1736
+ }
1737
+ async composeViewsConfig(hintsConfig) {
1738
+ this.metadataSummary = await this.setMetadataSummary();
1739
+ const possibleViews = [];
1740
+ const hasCellSetData = this.metadataSummary.obs.filter((key) => key.toLowerCase().includes("cluster") || key.toLowerCase().includes("cell_type") || key.toLowerCase().includes("celltype"));
1741
+ if (hasCellSetData.length > 0) {
1742
+ possibleViews.push(["obsSets"]);
1743
+ }
1744
+ this.metadataSummary.obsm.forEach((key) => {
1745
+ if (key.toLowerCase().includes("obsm/x_umap")) {
1746
+ possibleViews.push(["scatterplot", { mapping: "UMAP" }]);
1747
+ }
1748
+ if (key.toLowerCase().includes("obsm/x_tsne")) {
1749
+ possibleViews.push(["scatterplot", { mapping: "t-SNE" }]);
1750
+ }
1751
+ if (key.toLowerCase().includes("obsm/x_pca")) {
1752
+ possibleViews.push(["scatterplot", { mapping: "PCA" }]);
1753
+ }
1754
+ if (key.toLowerCase().includes("obsm/x_segmentations")) {
1755
+ possibleViews.push(["layerController"]);
1756
+ }
1757
+ if (key.toLowerCase().includes("obsm/x_spatial")) {
1758
+ possibleViews.push(["spatial"]);
1759
+ }
1760
+ });
1761
+ possibleViews.push(["obsSetSizes"]);
1762
+ possibleViews.push(["obsSetFeatureValueDistribution"]);
1763
+ if (this.metadataSummary.X) {
1764
+ possibleViews.push(["heatmap"]);
1765
+ possibleViews.push(["featureList"]);
1766
+ }
1767
+ const views = filterViews(hintsConfig, possibleViews);
1768
+ return views;
1769
+ }
1770
+ async setMetadataSummaryWithZmetadata(response) {
1771
+ const metadataFile = await response.json();
1772
+ if (!metadataFile.metadata) {
1773
+ throw new Error("Could not generate config: .zmetadata file is not valid.");
1774
+ }
1775
+ const obsmKeys = Object.keys(metadataFile.metadata).filter((key) => key.startsWith("obsm/X_")).map((key) => key.split("/.zarray")[0]);
1776
+ const obsKeysArr = Object.keys(metadataFile.metadata).filter((key) => key.startsWith("obs/")).map((key) => key.split("/.za")[0]);
1777
+ function uniq(a) {
1778
+ return a.sort().filter((item, pos, ary) => !pos || item !== ary[pos - 1]);
1779
+ }
1780
+ const obsKeys = uniq(obsKeysArr);
1781
+ const X = Object.keys(metadataFile.metadata).filter((key) => key.startsWith("X"));
1782
+ return {
1783
+ // Array of keys in obsm that are found by the fetches above
1784
+ obsm: obsmKeys,
1785
+ // Array of keys in obs that are found by the fetches above
1786
+ obs: obsKeys,
1787
+ // Boolean indicating whether the X array was found by the fetches above
1788
+ X: X.length > 0
1789
+ };
1790
+ }
1791
+ async setMetadataSummaryWithoutZmetadata() {
1792
+ const knownMetadataFileSuffixes = [
1793
+ "/obsm/X_pca/.zarray",
1794
+ "/obsm/X_umap/.zarray",
1795
+ "/obsm/X_tsne/.zarray",
1796
+ "/obsm/X_spatial/.zarray",
1797
+ "/obsm/X_segmentations/.zarray",
1798
+ "/obs/.zattrs",
1799
+ "/X/.zarray",
1800
+ "/X/data/.zarray"
1801
+ // for https://data-1.vitessce.io/0.0.33/main/human-lymph-node-10x-visium/human_lymph_node_10x_visium.h5ad.zarr
1802
+ ];
1803
+ const getObsmKey = (url) => {
1804
+ const obsmKeyStartIndex = `${this.fileUrl}/`.length;
1805
+ const obsmKeyEndIndex = url.length - "/.zarray".length;
1806
+ return url.substring(obsmKeyStartIndex, obsmKeyEndIndex);
1807
+ };
1808
+ const promises = knownMetadataFileSuffixes.map((suffix) => fetch(`${this.fileUrl}${suffix}`));
1809
+ const fetchResults = await Promise.all(promises);
1810
+ const okFetchResults = fetchResults.filter((j) => j.ok);
1811
+ const metadataSummary = {
1812
+ // Array of keys in obsm that are found by the fetches above
1813
+ obsm: [],
1814
+ // Array of keys in obs that are found by the fetches above
1815
+ obs: [],
1816
+ // Boolean indicating whether the X array was found by the fetches above
1817
+ X: false
1818
+ };
1819
+ const obsPromiseResult = okFetchResults.find(
1820
+ (r) => r.url === `${this.fileUrl}/obs/.zattrs`
1821
+ );
1822
+ const isObsValid = (obsAttr) => Object.keys(obsAttr).includes("column-order") && Object.keys(obsAttr).includes("encoding-version") && Object.keys(obsAttr).includes("encoding-type") && obsAttr["encoding-type"] === "dataframe" && (obsAttr["encoding-version"] === "0.1.0" || obsAttr["encoding-version"] === "0.2.0");
1823
+ if (obsPromiseResult) {
1824
+ const obsAttrs = await obsPromiseResult.json();
1825
+ if (isObsValid(obsAttrs)) {
1826
+ obsAttrs["column-order"].forEach((key) => metadataSummary.obs.push(`obs/${key}`));
1827
+ } else {
1828
+ throw new Error("Could not generate config: /obs/.zattrs file is not valid.");
1829
+ }
1830
+ }
1831
+ okFetchResults.forEach((r) => {
1832
+ if (r.url.startsWith(`${this.fileUrl}/obsm`)) {
1833
+ const obsmKey = getObsmKey(r.url);
1834
+ if (obsmKey) {
1835
+ metadataSummary.obsm.push(obsmKey);
1836
+ }
1837
+ } else if (r.url.startsWith(`${this.fileUrl}/X`)) {
1838
+ metadataSummary.X = true;
1839
+ }
1840
+ });
1841
+ return metadataSummary;
1842
+ }
1843
+ async setMetadataSummary() {
1844
+ if (Object.keys(this.metadataSummary).length > 0) {
1845
+ return this.metadataSummary;
1846
+ }
1847
+ const metadataExtension = ".zmetadata";
1848
+ const url = [this.fileUrl, metadataExtension].join("/");
1849
+ return fetch(url).then((response) => {
1850
+ if (response.ok) {
1851
+ return this.setMetadataSummaryWithZmetadata(response);
1852
+ }
1853
+ if (response.status === 404) {
1854
+ return this.setMetadataSummaryWithoutZmetadata();
1855
+ }
1856
+ throw new Error(`Could not generate config: ${response.statusText}`);
1857
+ }).catch((error) => {
1858
+ throw new Error(`Could not generate config for URL ${this.fileUrl}: ${error}`);
1859
+ });
1860
+ }
1861
+ }
1862
+ const configClasses = [
1863
+ {
1864
+ extensions: [".ome.tif", ".ome.tiff", ".ome.tf2", ".ome.tf8"],
1865
+ class: OmeTiffAutoConfig,
1866
+ name: "OME-TIFF"
1867
+ },
1868
+ {
1869
+ extensions: [".h5ad.zarr", ".adata.zarr", ".anndata.zarr"],
1870
+ class: AnndataZarrAutoConfig,
1871
+ name: "AnnData-Zarr"
1872
+ },
1873
+ {
1874
+ extensions: ["ome.zarr"],
1875
+ class: OmeZarrAutoConfig,
1876
+ name: "OME-Zarr"
1877
+ }
1878
+ ];
1879
+ function calculateCoordinates(viewsNumb) {
1880
+ const rows = Math.ceil(Math.sqrt(viewsNumb));
1881
+ const cols = Math.ceil(viewsNumb / rows);
1882
+ const width = 12 / cols;
1883
+ const height = 12 / rows;
1884
+ const coords = [];
1885
+ for (let i = 0; i < viewsNumb; i++) {
1886
+ const row = Math.floor(i / cols);
1887
+ const col = i % cols;
1888
+ const x = col * width;
1889
+ const y = row * height;
1890
+ coords.push([
1891
+ Math.floor(x),
1892
+ Math.floor(y),
1893
+ // Ensure width/height is at least 1.
1894
+ Math.max(1, Math.floor(width)),
1895
+ Math.max(1, Math.floor(height))
1896
+ ]);
1897
+ }
1898
+ return coords;
1899
+ }
1900
+ const spatialSegmentationLayerValue = {
1901
+ radius: 65,
1902
+ stroked: true,
1903
+ visible: true,
1904
+ opacity: 1
1905
+ };
1906
+ function insertCoordinationSpaceForSpatial(views, vc) {
1907
+ const [
1908
+ spatialSegmentationLayer,
1909
+ spatialImageLayer,
1910
+ spatialZoom,
1911
+ spatialTargetX,
1912
+ spatialTargetY
1913
+ ] = vc.addCoordination(
1914
+ CoordinationType.SPATIAL_SEGMENTATION_LAYER,
1915
+ CoordinationType.SPATIAL_IMAGE_LAYER,
1916
+ CoordinationType.SPATIAL_ZOOM,
1917
+ CoordinationType.SPATIAL_TARGET_X,
1918
+ CoordinationType.SPATIAL_TARGET_Y
1919
+ );
1920
+ spatialSegmentationLayer.setValue(spatialSegmentationLayerValue);
1921
+ spatialImageLayer.setValue([
1922
+ {
1923
+ type: "raster",
1924
+ index: 0,
1925
+ colormap: null,
1926
+ transparentColor: null,
1927
+ opacity: 1,
1928
+ domainType: "Min/Max",
1929
+ channels: [
1930
+ {
1931
+ selection: {
1932
+ c: 0
1933
+ },
1934
+ color: [
1935
+ 255,
1936
+ 0,
1937
+ 0
1938
+ ],
1939
+ visible: true,
1940
+ slider: [
1941
+ 0,
1942
+ 255
1943
+ ]
1944
+ },
1945
+ {
1946
+ selection: {
1947
+ c: 1
1948
+ },
1949
+ color: [
1950
+ 0,
1951
+ 255,
1952
+ 0
1953
+ ],
1954
+ visible: true,
1955
+ slider: [
1956
+ 0,
1957
+ 255
1958
+ ]
1959
+ },
1960
+ {
1961
+ selection: {
1962
+ c: 2
1963
+ },
1964
+ color: [
1965
+ 0,
1966
+ 0,
1967
+ 255
1968
+ ],
1969
+ visible: true,
1970
+ slider: [
1971
+ 0,
1972
+ 255
1973
+ ]
1974
+ }
1975
+ ]
1976
+ }
1977
+ ]);
1978
+ views.forEach((view) => {
1979
+ if (view.view.component === "spatial" || view.view.component === "layerController") {
1980
+ view.useCoordination(spatialImageLayer);
1981
+ view.useCoordination(spatialSegmentationLayer);
1982
+ view.useCoordination(spatialZoom);
1983
+ view.useCoordination(spatialTargetX);
1984
+ view.useCoordination(spatialTargetY);
1985
+ }
1986
+ });
1987
+ }
1988
+ function getFileType(url) {
1989
+ const match = configClasses.find((obj) => obj.extensions.filter(
1990
+ (ext) => url.endsWith(ext)
1991
+ ).length === 1);
1992
+ if (!match) {
1993
+ throw new Error("One or more of the URLs provided point to unsupported file types.");
1994
+ }
1995
+ return match;
1996
+ }
1997
+ async function generateViewDefinition(url, vc, dataset, hintsConfig) {
1998
+ let ConfigClassName;
1999
+ try {
2000
+ ConfigClassName = getFileType(url).class;
2001
+ } catch (err) {
2002
+ return Promise.reject(err);
2003
+ }
2004
+ const configInstance = new ConfigClassName(url);
2005
+ let fileConfig;
2006
+ let viewsConfig;
2007
+ try {
2008
+ fileConfig = await configInstance.composeFileConfig();
2009
+ viewsConfig = await configInstance.composeViewsConfig(hintsConfig);
2010
+ } catch (error) {
2011
+ log.error(error);
2012
+ return Promise.reject(error);
2013
+ }
2014
+ dataset.addFile(fileConfig);
2015
+ let layerControllerView = false;
2016
+ let spatialView = false;
2017
+ const views = [];
2018
+ viewsConfig.forEach((v) => {
2019
+ const view = vc.addView(dataset, ...v);
2020
+ if (v[0] === "layerController") {
2021
+ layerControllerView = view;
2022
+ }
2023
+ if (v[0] === "spatial") {
2024
+ spatialView = view;
2025
+ }
2026
+ if (v[0] === "layerController") {
2027
+ view.setProps({
2028
+ disable3d: [],
2029
+ disableChannelsIfRgbDetected: true
2030
+ });
2031
+ }
2032
+ if (v[0] === "heatmap" && configInstance instanceof AnndataZarrAutoConfig) {
2033
+ view.setProps({ transpose: true });
2034
+ }
2035
+ views.push(view);
2036
+ });
2037
+ if (layerControllerView && spatialView && configInstance instanceof AnndataZarrAutoConfig) {
2038
+ vc.linkViews(
2039
+ [spatialView, layerControllerView],
2040
+ [
2041
+ CoordinationType.SPATIAL_SEGMENTATION_LAYER
2042
+ ],
2043
+ [spatialSegmentationLayerValue]
2044
+ );
2045
+ }
2046
+ return views;
2047
+ }
2048
+ function getHintOptions(fileUrls) {
2049
+ const fileTypes = {};
2050
+ fileUrls.forEach((url) => {
2051
+ const match = getFileType(url);
2052
+ if (match.name === "OME-Zarr") {
2053
+ fileTypes["OME-TIFF"] = true;
2054
+ } else {
2055
+ fileTypes[match.name] = true;
2056
+ }
2057
+ });
2058
+ const datasetType = Object.keys(fileTypes).sort().join(",");
2059
+ return HINT_TYPE_TO_FILE_TYPE_MAP?.[datasetType] || [];
2060
+ }
2061
+ async function generateConfig$1(fileUrls, hintTitle = null) {
2062
+ const vc = new VitessceConfig({
2063
+ schemaVersion: "1.0.15",
2064
+ name: "An automatically generated config. Adjust values and add layout components if needed.",
2065
+ description: "Populate with text relevant to this visualisation."
2066
+ });
2067
+ const allViews = [];
2068
+ const dataset = vc.addDataset("An automatically generated view config for dataset. Adjust values and add layout components if needed.");
2069
+ const hintsConfig = !hintTitle ? { views: {} } : HINTS_CONFIG?.[hintTitle];
2070
+ if (!hintsConfig) {
2071
+ throw new Error(`Hints config not found for the supplied hint: ${hintTitle}.`);
2072
+ }
2073
+ const useHints = Object.keys(hintsConfig?.views)?.length > 0;
2074
+ fileUrls.forEach((url) => {
2075
+ allViews.push(generateViewDefinition(url, vc, dataset, hintsConfig));
2076
+ });
2077
+ return Promise.all(allViews).then((views) => {
2078
+ const flattenedViews = views.flat();
2079
+ if (hintsConfig?.coordinationSpaceRequired) {
2080
+ insertCoordinationSpaceForSpatial(flattenedViews, vc);
2081
+ }
2082
+ if (!useHints) {
2083
+ const coord = calculateCoordinates(flattenedViews.length);
2084
+ for (let i = 0; i < flattenedViews.length; i++) {
2085
+ flattenedViews[i].setXYWH(...coord[i]);
2086
+ }
2087
+ } else {
2088
+ flattenedViews.forEach((vitessceConfigView) => {
2089
+ const coordinates = Object.values(hintsConfig.views[vitessceConfigView.view.component]);
2090
+ vitessceConfigView.setXYWH(...coordinates);
2091
+ });
2092
+ }
2093
+ return vc.toJSON();
2094
+ });
2095
+ }
2096
+ function strip_prefix(path) {
2097
+ return path.slice(1);
2098
+ }
2099
+ function fetch_range(url, offset, length, opts = {}) {
2100
+ if (offset !== void 0 && length !== void 0) {
2101
+ opts = {
2102
+ ...opts,
2103
+ headers: {
2104
+ ...opts.headers,
2105
+ Range: `bytes=${offset}-${offset + length - 1}`
2106
+ }
2107
+ };
2108
+ }
2109
+ return fetch(url, opts);
2110
+ }
2111
+ function merge_init(storeOverrides, requestOverrides) {
2112
+ return {
2113
+ ...storeOverrides,
2114
+ ...requestOverrides,
2115
+ headers: {
2116
+ ...storeOverrides.headers,
2117
+ ...requestOverrides.headers
2118
+ }
2119
+ };
2120
+ }
2121
+ function assert$1(expression, msg = "") {
2122
+ if (!expression)
2123
+ throw new Error(msg);
2124
+ }
2125
+ function resolve(root, path) {
2126
+ const base = typeof root === "string" ? new URL(root) : root;
2127
+ if (!base.pathname.endsWith("/")) {
2128
+ base.pathname += "/";
2129
+ }
2130
+ const resolved = new URL(path.slice(1), base);
2131
+ resolved.search = base.search;
2132
+ return resolved;
2133
+ }
2134
+ async function handle_response(response) {
2135
+ if (response.status === 404) {
2136
+ return void 0;
2137
+ }
2138
+ if (response.status === 200 || response.status === 206) {
2139
+ return new Uint8Array(await response.arrayBuffer());
2140
+ }
2141
+ throw new Error(`Unexpected response status ${response.status} ${response.statusText}`);
2142
+ }
2143
+ async function fetch_suffix(url, suffix_length, init, use_suffix_request) {
2144
+ if (use_suffix_request) {
2145
+ return fetch(url, {
2146
+ ...init,
2147
+ headers: { ...init.headers, Range: `bytes=-${suffix_length}` }
2148
+ });
2149
+ }
2150
+ let response = await fetch(url, { ...init, method: "HEAD" });
2151
+ if (!response.ok) {
2152
+ return response;
2153
+ }
2154
+ let content_length = response.headers.get("Content-Length");
2155
+ let length = Number(content_length);
2156
+ return fetch_range(url, length - suffix_length, length, init);
2157
+ }
2158
+ class FetchStore {
2159
+ #overrides;
2160
+ #use_suffix_request;
2161
+ constructor(url, options = {}) {
2162
+ this.url = url;
2163
+ this.#overrides = options.overrides ?? {};
2164
+ this.#use_suffix_request = options.useSuffixRequest ?? false;
2165
+ }
2166
+ #merge_init(overrides) {
2167
+ return merge_init(this.#overrides, overrides);
2168
+ }
2169
+ async get(key, options = {}) {
2170
+ let href = resolve(this.url, key).href;
2171
+ let response = await fetch(href, this.#merge_init(options));
2172
+ return handle_response(response);
2173
+ }
2174
+ async getRange(key, range, options = {}) {
2175
+ let url = resolve(this.url, key);
2176
+ let init = this.#merge_init(options);
2177
+ let response;
2178
+ if ("suffixLength" in range) {
2179
+ response = await fetch_suffix(url, range.suffixLength, init, this.#use_suffix_request);
2180
+ } else {
2181
+ response = await fetch_range(url, range.offset, range.length, init);
2182
+ }
2183
+ return handle_response(response);
2184
+ }
2185
+ }
2186
+ class BoolArray {
2187
+ #bytes;
2188
+ constructor(x, byteOffset, length) {
2189
+ if (typeof x === "number") {
2190
+ this.#bytes = new Uint8Array(x);
2191
+ } else if (x instanceof ArrayBuffer) {
2192
+ this.#bytes = new Uint8Array(x, byteOffset, length);
2193
+ } else {
2194
+ this.#bytes = new Uint8Array(Array.from(x, (v) => v ? 1 : 0));
2195
+ }
2196
+ }
2197
+ get BYTES_PER_ELEMENT() {
2198
+ return 1;
2199
+ }
2200
+ get byteOffset() {
2201
+ return this.#bytes.byteOffset;
2202
+ }
2203
+ get byteLength() {
2204
+ return this.#bytes.byteLength;
2205
+ }
2206
+ get buffer() {
2207
+ return this.#bytes.buffer;
2208
+ }
2209
+ get length() {
2210
+ return this.#bytes.length;
2211
+ }
2212
+ get(idx) {
2213
+ let value = this.#bytes[idx];
2214
+ return typeof value === "number" ? value !== 0 : value;
2215
+ }
2216
+ set(idx, value) {
2217
+ this.#bytes[idx] = value ? 1 : 0;
2218
+ }
2219
+ fill(value) {
2220
+ this.#bytes.fill(value ? 1 : 0);
2221
+ }
2222
+ *[Symbol.iterator]() {
2223
+ for (let i = 0; i < this.length; i++) {
2224
+ yield this.get(i);
2225
+ }
2226
+ }
2227
+ }
2228
+ class ByteStringArray {
2229
+ #encoder;
2230
+ constructor(chars, x, byteOffset, length) {
2231
+ this.chars = chars;
2232
+ this.#encoder = new TextEncoder();
2233
+ if (typeof x === "number") {
2234
+ this._data = new Uint8Array(x * chars);
2235
+ } else if (x instanceof ArrayBuffer) {
2236
+ if (length)
2237
+ length = length * chars;
2238
+ this._data = new Uint8Array(x, byteOffset, length);
2239
+ } else {
2240
+ let values = Array.from(x);
2241
+ this._data = new Uint8Array(values.length * chars);
2242
+ for (let i = 0; i < values.length; i++) {
2243
+ this.set(i, values[i]);
2244
+ }
2245
+ }
2246
+ }
2247
+ get BYTES_PER_ELEMENT() {
2248
+ return this.chars;
2249
+ }
2250
+ get byteOffset() {
2251
+ return this._data.byteOffset;
2252
+ }
2253
+ get byteLength() {
2254
+ return this._data.byteLength;
2255
+ }
2256
+ get buffer() {
2257
+ return this._data.buffer;
2258
+ }
2259
+ get length() {
2260
+ return this.byteLength / this.BYTES_PER_ELEMENT;
2261
+ }
2262
+ get(idx) {
2263
+ const view = new Uint8Array(this.buffer, this.byteOffset + this.chars * idx, this.chars);
2264
+ return new TextDecoder().decode(view).replace(/\x00/g, "");
2265
+ }
2266
+ set(idx, value) {
2267
+ const view = new Uint8Array(this.buffer, this.byteOffset + this.chars * idx, this.chars);
2268
+ view.fill(0);
2269
+ view.set(this.#encoder.encode(value));
2270
+ }
2271
+ fill(value) {
2272
+ const encoded = this.#encoder.encode(value);
2273
+ for (let i = 0; i < this.length; i++) {
2274
+ this._data.set(encoded, i * this.chars);
2275
+ }
2276
+ }
2277
+ *[Symbol.iterator]() {
2278
+ for (let i = 0; i < this.length; i++) {
2279
+ yield this.get(i);
2280
+ }
2281
+ }
2282
+ }
2283
+ class UnicodeStringArray {
2284
+ #data;
2285
+ constructor(chars, x, byteOffset, length) {
2286
+ this.chars = chars;
2287
+ if (typeof x === "number") {
2288
+ this.#data = new Int32Array(x * chars);
2289
+ } else if (x instanceof ArrayBuffer) {
2290
+ if (length)
2291
+ length *= chars;
2292
+ this.#data = new Int32Array(x, byteOffset, length);
2293
+ } else {
2294
+ const values = x;
2295
+ const d = new UnicodeStringArray(chars, 1);
2296
+ this.#data = new Int32Array(function* () {
2297
+ for (let str of values) {
2298
+ d.set(0, str);
2299
+ yield* d.#data;
2300
+ }
2301
+ }());
2302
+ }
2303
+ }
2304
+ get BYTES_PER_ELEMENT() {
2305
+ return this.#data.BYTES_PER_ELEMENT * this.chars;
2306
+ }
2307
+ get byteLength() {
2308
+ return this.#data.byteLength;
2309
+ }
2310
+ get byteOffset() {
2311
+ return this.#data.byteOffset;
2312
+ }
2313
+ get buffer() {
2314
+ return this.#data.buffer;
2315
+ }
2316
+ get length() {
2317
+ return this.#data.length / this.chars;
2318
+ }
2319
+ get(idx) {
2320
+ const offset = this.chars * idx;
2321
+ let result = "";
2322
+ for (let i = 0; i < this.chars; i++) {
2323
+ result += String.fromCodePoint(this.#data[offset + i]);
2324
+ }
2325
+ return result.replace(/\u0000/g, "");
2326
+ }
2327
+ set(idx, value) {
2328
+ const offset = this.chars * idx;
2329
+ const view = this.#data.subarray(offset, offset + this.chars);
2330
+ view.fill(0);
2331
+ for (let i = 0; i < this.chars; i++) {
2332
+ view[i] = value.codePointAt(i) ?? 0;
2333
+ }
2334
+ }
2335
+ fill(value) {
2336
+ this.set(0, value);
2337
+ let encoded = this.#data.subarray(0, this.chars);
2338
+ for (let i = 1; i < this.length; i++) {
2339
+ this.#data.set(encoded, i * this.chars);
2340
+ }
2341
+ }
2342
+ *[Symbol.iterator]() {
2343
+ for (let i = 0; i < this.length; i++) {
2344
+ yield this.get(i);
2345
+ }
2346
+ }
2347
+ }
2348
+ function json_encode_object(o) {
2349
+ const str = JSON.stringify(o, null, 2);
2350
+ return new TextEncoder().encode(str);
2351
+ }
2352
+ function json_decode_object(bytes) {
2353
+ const str = new TextDecoder().decode(bytes);
2354
+ return JSON.parse(str);
2355
+ }
2356
+ function byteswap_inplace(view, bytes_per_element2) {
2357
+ const numFlips = bytes_per_element2 / 2;
2358
+ const endByteIndex = bytes_per_element2 - 1;
2359
+ let t = 0;
2360
+ for (let i = 0; i < view.length; i += bytes_per_element2) {
2361
+ for (let j = 0; j < numFlips; j += 1) {
2362
+ t = view[i + j];
2363
+ view[i + j] = view[i + endByteIndex - j];
2364
+ view[i + endByteIndex - j] = t;
2365
+ }
2366
+ }
2367
+ }
2368
+ function get_ctr(data_type) {
2369
+ if (data_type === "v2:object") {
2370
+ return globalThis.Array;
2371
+ }
2372
+ let match = data_type.match(/v2:([US])(\d+)/);
2373
+ if (match) {
2374
+ let [, kind, chars] = match;
2375
+ return (kind === "U" ? UnicodeStringArray : ByteStringArray).bind(null, Number(chars));
2376
+ }
2377
+ if (data_type === "string") {
2378
+ return globalThis.Array;
2379
+ }
2380
+ let ctr = {
2381
+ int8: Int8Array,
2382
+ int16: Int16Array,
2383
+ int32: Int32Array,
2384
+ int64: globalThis.BigInt64Array,
2385
+ uint8: Uint8Array,
2386
+ uint16: Uint16Array,
2387
+ uint32: Uint32Array,
2388
+ uint64: globalThis.BigUint64Array,
2389
+ float16: globalThis.Float16Array,
2390
+ float32: Float32Array,
2391
+ float64: Float64Array,
2392
+ bool: BoolArray
2393
+ }[data_type];
2394
+ assert(ctr, `Unknown or unsupported data_type: ${data_type}`);
2395
+ return ctr;
2396
+ }
2397
+ function get_strides(shape, order) {
2398
+ const rank = shape.length;
2399
+ if (typeof order === "string") {
2400
+ order = order === "C" ? Array.from({ length: rank }, (_, i) => i) : Array.from({ length: rank }, (_, i) => rank - 1 - i);
2401
+ }
2402
+ assert(rank === order.length, "Order length must match the number of dimensions.");
2403
+ let step = 1;
2404
+ let stride = new Array(rank);
2405
+ for (let i = order.length - 1; i >= 0; i--) {
2406
+ stride[order[i]] = step;
2407
+ step *= shape[order[i]];
2408
+ }
2409
+ return stride;
2410
+ }
2411
+ function create_chunk_key_encoder({ name, configuration }) {
2412
+ if (name === "default") {
2413
+ const separator = configuration?.separator ?? "/";
2414
+ return (chunk_coords) => ["c", ...chunk_coords].join(separator);
2415
+ }
2416
+ if (name === "v2") {
2417
+ const separator = configuration?.separator ?? ".";
2418
+ return (chunk_coords) => chunk_coords.join(separator) || "0";
2419
+ }
2420
+ throw new Error(`Unknown chunk key encoding: ${name}`);
2421
+ }
2422
+ function coerce_dtype(dtype) {
2423
+ if (dtype === "|O") {
2424
+ return { data_type: "v2:object" };
2425
+ }
2426
+ let match = dtype.match(/^([<|>])(.*)$/);
2427
+ assert(match, `Invalid dtype: ${dtype}`);
2428
+ let [, endian, rest] = match;
2429
+ let data_type = {
2430
+ b1: "bool",
2431
+ i1: "int8",
2432
+ u1: "uint8",
2433
+ i2: "int16",
2434
+ u2: "uint16",
2435
+ i4: "int32",
2436
+ u4: "uint32",
2437
+ i8: "int64",
2438
+ u8: "uint64",
2439
+ f2: "float16",
2440
+ f4: "float32",
2441
+ f8: "float64"
2442
+ }[rest] ?? (rest.startsWith("S") || rest.startsWith("U") ? `v2:${rest}` : void 0);
2443
+ assert(data_type, `Unsupported or unknown dtype: ${dtype}`);
2444
+ if (endian === "|") {
2445
+ return { data_type };
2446
+ }
2447
+ return { data_type, endian: endian === "<" ? "little" : "big" };
2448
+ }
2449
+ function v2_to_v3_array_metadata(meta, attributes = {}) {
2450
+ let codecs = [];
2451
+ let dtype = coerce_dtype(meta.dtype);
2452
+ if (meta.order === "F") {
2453
+ codecs.push({ name: "transpose", configuration: { order: "F" } });
2454
+ }
2455
+ if ("endian" in dtype && dtype.endian === "big") {
2456
+ codecs.push({ name: "bytes", configuration: { endian: "big" } });
2457
+ }
2458
+ for (let { id, ...configuration } of meta.filters ?? []) {
2459
+ codecs.push({ name: id, configuration });
2460
+ }
2461
+ if (meta.compressor) {
2462
+ let { id, ...configuration } = meta.compressor;
2463
+ codecs.push({ name: id, configuration });
2464
+ }
2465
+ return {
2466
+ zarr_format: 3,
2467
+ node_type: "array",
2468
+ shape: meta.shape,
2469
+ data_type: dtype.data_type,
2470
+ chunk_grid: {
2471
+ name: "regular",
2472
+ configuration: {
2473
+ chunk_shape: meta.chunks
2474
+ }
2475
+ },
2476
+ chunk_key_encoding: {
2477
+ name: "v2",
2478
+ configuration: {
2479
+ separator: meta.dimension_separator ?? "."
2480
+ }
2481
+ },
2482
+ codecs,
2483
+ fill_value: meta.fill_value,
2484
+ attributes
2485
+ };
2486
+ }
2487
+ function v2_to_v3_group_metadata(_meta, attributes = {}) {
2488
+ return {
2489
+ zarr_format: 3,
2490
+ node_type: "group",
2491
+ attributes
2492
+ };
2493
+ }
2494
+ function is_dtype(dtype, query) {
2495
+ if (query !== "number" && query !== "bigint" && query !== "boolean" && query !== "object" && query !== "string") {
2496
+ return dtype === query;
2497
+ }
2498
+ let is_boolean = dtype === "bool";
2499
+ if (query === "boolean")
2500
+ return is_boolean;
2501
+ let is_string = dtype.startsWith("v2:U") || dtype.startsWith("v2:S") || dtype === "string";
2502
+ if (query === "string")
2503
+ return is_string;
2504
+ let is_bigint = dtype === "int64" || dtype === "uint64";
2505
+ if (query === "bigint")
2506
+ return is_bigint;
2507
+ let is_object = dtype === "v2:object";
2508
+ if (query === "object")
2509
+ return is_object;
2510
+ return !is_string && !is_bigint && !is_boolean && !is_object;
2511
+ }
2512
+ function is_sharding_codec(codec) {
2513
+ return codec?.name === "sharding_indexed";
2514
+ }
2515
+ function ensure_correct_scalar(metadata) {
2516
+ if ((metadata.data_type === "uint64" || metadata.data_type === "int64") && metadata.fill_value != null) {
2517
+ return BigInt(metadata.fill_value);
2518
+ }
2519
+ return metadata.fill_value;
2520
+ }
2521
+ function rethrow_unless(error, ...errors) {
2522
+ if (!errors.some((ErrorClass) => error instanceof ErrorClass)) {
2523
+ throw error;
2524
+ }
2525
+ }
2526
+ function assert(expression, msg = "") {
2527
+ if (!expression) {
2528
+ throw new Error(msg);
2529
+ }
2530
+ }
2531
+ async function decompress(data, { format, signal }) {
2532
+ const response = data instanceof Response ? data : new Response(data);
2533
+ assert(response.body, "Response does not contain body.");
2534
+ try {
2535
+ const decompressedResponse = new Response(response.body.pipeThrough(new DecompressionStream(format), { signal }));
2536
+ const buffer = await decompressedResponse.arrayBuffer();
2537
+ return buffer;
2538
+ } catch {
2539
+ signal?.throwIfAborted();
2540
+ throw new Error(`Failed to decode ${format}`);
2541
+ }
2542
+ }
2543
+ class BitroundCodec {
2544
+ constructor(configuration, _meta) {
2545
+ this.kind = "array_to_array";
2546
+ assert(configuration.keepbits >= 0, "keepbits must be zero or positive");
2547
+ }
2548
+ static fromConfig(configuration, meta) {
2549
+ return new BitroundCodec(configuration, meta);
2550
+ }
2551
+ /**
2552
+ * Encode a chunk of data with bit-rounding.
2553
+ * @param _arr - The chunk to encode
2554
+ */
2555
+ encode(_arr) {
2556
+ throw new Error("`BitroundCodec.encode` is not implemented. Please open an issue at https://github.com/manzt/zarrita.js/issues.");
2557
+ }
2558
+ /**
2559
+ * Decode a chunk of data (no-op).
2560
+ * @param arr - The chunk to decode
2561
+ * @returns The decoded chunk
2562
+ */
2563
+ decode(arr) {
2564
+ return arr;
2565
+ }
2566
+ }
2567
+ const LITTLE_ENDIAN_OS = system_is_little_endian();
2568
+ function system_is_little_endian() {
2569
+ const a = new Uint32Array([305419896]);
2570
+ const b = new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
2571
+ return !(b[0] === 18);
2572
+ }
2573
+ function bytes_per_element(TypedArray) {
2574
+ if ("BYTES_PER_ELEMENT" in TypedArray) {
2575
+ return TypedArray.BYTES_PER_ELEMENT;
2576
+ }
2577
+ return 4;
2578
+ }
2579
+ class BytesCodec {
2580
+ constructor(configuration, meta) {
2581
+ this.kind = "array_to_bytes";
2582
+ this.#endian = configuration?.endian;
2583
+ this.#TypedArray = get_ctr(meta.data_type);
2584
+ this.#shape = meta.shape;
2585
+ this.#stride = get_strides(meta.shape, "C");
2586
+ const sample = new this.#TypedArray(0);
2587
+ this.#BYTES_PER_ELEMENT = sample.BYTES_PER_ELEMENT;
2588
+ }
2589
+ #stride;
2590
+ #TypedArray;
2591
+ #BYTES_PER_ELEMENT;
2592
+ #shape;
2593
+ #endian;
2594
+ static fromConfig(configuration, meta) {
2595
+ return new BytesCodec(configuration, meta);
2596
+ }
2597
+ encode(arr) {
2598
+ let bytes = new Uint8Array(arr.data.buffer);
2599
+ if (LITTLE_ENDIAN_OS && this.#endian === "big") {
2600
+ byteswap_inplace(bytes, bytes_per_element(this.#TypedArray));
2601
+ }
2602
+ return bytes;
2603
+ }
2604
+ decode(bytes) {
2605
+ if (LITTLE_ENDIAN_OS && this.#endian === "big") {
2606
+ byteswap_inplace(bytes, bytes_per_element(this.#TypedArray));
2607
+ }
2608
+ return {
2609
+ data: new this.#TypedArray(bytes.buffer, bytes.byteOffset, bytes.byteLength / this.#BYTES_PER_ELEMENT),
2610
+ shape: this.#shape,
2611
+ stride: this.#stride
2612
+ };
2613
+ }
2614
+ }
2615
+ class Crc32cCodec {
2616
+ constructor() {
2617
+ this.kind = "bytes_to_bytes";
2618
+ }
2619
+ static fromConfig() {
2620
+ return new Crc32cCodec();
2621
+ }
2622
+ encode(_) {
2623
+ throw new Error("Not implemented");
2624
+ }
2625
+ decode(arr) {
2626
+ return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength - 4);
2627
+ }
2628
+ }
2629
+ class GzipCodec {
2630
+ constructor() {
2631
+ this.kind = "bytes_to_bytes";
2632
+ }
2633
+ static fromConfig(_) {
2634
+ return new GzipCodec();
2635
+ }
2636
+ encode(_bytes) {
2637
+ throw new Error("Gzip encoding is not enabled by default. Please register a custom codec with `numcodecs/gzip`.");
2638
+ }
2639
+ async decode(bytes) {
2640
+ const buffer = await decompress(bytes, { format: "gzip" });
2641
+ return new Uint8Array(buffer);
2642
+ }
2643
+ }
2644
+ function throw_on_nan_replacer(_key, value) {
2645
+ assert(!Number.isNaN(value), "JsonCodec allow_nan is false but NaN was encountered during encoding.");
2646
+ assert(value !== Number.POSITIVE_INFINITY, "JsonCodec allow_nan is false but Infinity was encountered during encoding.");
2647
+ assert(value !== Number.NEGATIVE_INFINITY, "JsonCodec allow_nan is false but -Infinity was encountered during encoding.");
2648
+ return value;
2649
+ }
2650
+ function sort_keys_replacer(_key, value) {
2651
+ return value instanceof Object && !Array.isArray(value) ? Object.keys(value).sort().reduce((sorted, key) => {
2652
+ sorted[key] = value[key];
2653
+ return sorted;
2654
+ }, {}) : value;
2655
+ }
2656
+ class JsonCodec {
2657
+ constructor(configuration = {}) {
2658
+ this.kind = "array_to_bytes";
2659
+ this.configuration = configuration;
2660
+ const { encoding = "utf-8", skipkeys = false, ensure_ascii = true, check_circular = true, allow_nan = true, sort_keys = true, indent, strict = true } = configuration;
2661
+ let separators = configuration.separators;
2662
+ if (!separators) {
2663
+ if (!indent) {
2664
+ separators = [",", ":"];
2665
+ } else {
2666
+ separators = [", ", ": "];
2667
+ }
2668
+ }
2669
+ this.#encoder_config = {
2670
+ encoding,
2671
+ skipkeys,
2672
+ ensure_ascii,
2673
+ check_circular,
2674
+ allow_nan,
2675
+ indent,
2676
+ separators,
2677
+ sort_keys
2678
+ };
2679
+ this.#decoder_config = { strict };
2680
+ }
2681
+ #encoder_config;
2682
+ #decoder_config;
2683
+ static fromConfig(configuration) {
2684
+ return new JsonCodec(configuration);
2685
+ }
2686
+ encode(buf) {
2687
+ const { indent, encoding, ensure_ascii, check_circular, allow_nan, sort_keys } = this.#encoder_config;
2688
+ assert(encoding === "utf-8", "JsonCodec does not yet support non-utf-8 encoding.");
2689
+ const replacer_functions = [];
2690
+ assert(check_circular, "JsonCodec does not yet support skipping the check for circular references during encoding.");
2691
+ if (!allow_nan) {
2692
+ replacer_functions.push(throw_on_nan_replacer);
2693
+ }
2694
+ if (sort_keys) {
2695
+ replacer_functions.push(sort_keys_replacer);
2696
+ }
2697
+ const items = Array.from(buf.data);
2698
+ items.push("|O");
2699
+ items.push(buf.shape);
2700
+ let replacer;
2701
+ if (replacer_functions.length) {
2702
+ replacer = (key, value) => {
2703
+ let new_value = value;
2704
+ for (let sub_replacer of replacer_functions) {
2705
+ new_value = sub_replacer(key, new_value);
2706
+ }
2707
+ return new_value;
2708
+ };
2709
+ }
2710
+ let json_str = JSON.stringify(items, replacer, indent);
2711
+ if (ensure_ascii) {
2712
+ json_str = json_str.replace(/[\u007F-\uFFFF]/g, (chr) => {
2713
+ const full_str = `0000${chr.charCodeAt(0).toString(16)}`;
2714
+ const sub_str = full_str.substring(full_str.length - 4);
2715
+ return `\\u${sub_str}`;
2716
+ });
2717
+ }
2718
+ return new TextEncoder().encode(json_str);
2719
+ }
2720
+ decode(bytes) {
2721
+ const { strict } = this.#decoder_config;
2722
+ assert(strict, "JsonCodec does not yet support non-strict decoding.");
2723
+ const items = json_decode_object(bytes);
2724
+ const shape = items.pop();
2725
+ items.pop();
2726
+ assert(shape, "0D not implemented for JsonCodec.");
2727
+ const stride = get_strides(shape, "C");
2728
+ const data = items;
2729
+ return { data, shape, stride };
2730
+ }
2731
+ }
2732
+ function proxy(arr) {
2733
+ if (arr instanceof BoolArray || arr instanceof ByteStringArray || arr instanceof UnicodeStringArray) {
2734
+ const arrp = new Proxy(arr, {
2735
+ get(target, prop) {
2736
+ return target.get(Number(prop));
2737
+ },
2738
+ set(target, prop, value) {
2739
+ target.set(Number(prop), value);
2740
+ return true;
2741
+ }
2742
+ });
2743
+ return arrp;
2744
+ }
2745
+ return arr;
2746
+ }
2747
+ function empty_like(chunk, order) {
2748
+ let data;
2749
+ if (chunk.data instanceof ByteStringArray || chunk.data instanceof UnicodeStringArray) {
2750
+ data = new chunk.constructor(
2751
+ // @ts-expect-error
2752
+ chunk.data.length,
2753
+ chunk.data.chars
2754
+ );
2755
+ } else {
2756
+ data = new chunk.constructor(chunk.data.length);
2757
+ }
2758
+ return {
2759
+ data,
2760
+ shape: chunk.shape,
2761
+ stride: get_strides(chunk.shape, order)
2762
+ };
2763
+ }
2764
+ function convert_array_order(src, target) {
2765
+ let out = empty_like(src, target);
2766
+ let n_dims = src.shape.length;
2767
+ let size = src.data.length;
2768
+ let index = Array(n_dims).fill(0);
2769
+ let src_data = proxy(src.data);
2770
+ let out_data = proxy(out.data);
2771
+ for (let src_idx = 0; src_idx < size; src_idx++) {
2772
+ let out_idx = 0;
2773
+ for (let dim = 0; dim < n_dims; dim++) {
2774
+ out_idx += index[dim] * out.stride[dim];
2775
+ }
2776
+ out_data[out_idx] = src_data[src_idx];
2777
+ index[0] += 1;
2778
+ for (let dim = 0; dim < n_dims; dim++) {
2779
+ if (index[dim] === src.shape[dim]) {
2780
+ if (dim + 1 === n_dims) {
2781
+ break;
2782
+ }
2783
+ index[dim] = 0;
2784
+ index[dim + 1] += 1;
2785
+ }
2786
+ }
2787
+ }
2788
+ return out;
2789
+ }
2790
+ function get_order(chunk) {
2791
+ let rank = chunk.shape.length;
2792
+ assert(rank === chunk.stride.length, "Shape and stride must have the same length.");
2793
+ return chunk.stride.map((s, i) => ({ stride: s, index: i })).sort((a, b) => b.stride - a.stride).map((entry) => entry.index);
2794
+ }
2795
+ function matches_order(chunk, target) {
2796
+ let source = get_order(chunk);
2797
+ assert(source.length === target.length, "Orders must match");
2798
+ return source.every((dim, i) => dim === target[i]);
2799
+ }
2800
+ class TransposeCodec {
2801
+ constructor(configuration, meta) {
2802
+ this.kind = "array_to_array";
2803
+ let value = configuration.order ?? "C";
2804
+ let rank = meta.shape.length;
2805
+ let order = new Array(rank);
2806
+ let inverseOrder = new Array(rank);
2807
+ if (value === "C") {
2808
+ for (let i = 0; i < rank; ++i) {
2809
+ order[i] = i;
2810
+ inverseOrder[i] = i;
2811
+ }
2812
+ } else if (value === "F") {
2813
+ for (let i = 0; i < rank; ++i) {
2814
+ order[i] = rank - i - 1;
2815
+ inverseOrder[i] = rank - i - 1;
2816
+ }
2817
+ } else {
2818
+ order = value;
2819
+ order.forEach((x, i) => {
2820
+ assert(inverseOrder[x] === void 0, `Invalid permutation: ${JSON.stringify(value)}`);
2821
+ inverseOrder[x] = i;
2822
+ });
2823
+ }
2824
+ this.#order = order;
2825
+ this.#inverseOrder = inverseOrder;
2826
+ }
2827
+ #order;
2828
+ #inverseOrder;
2829
+ static fromConfig(configuration, meta) {
2830
+ return new TransposeCodec(configuration, meta);
2831
+ }
2832
+ encode(arr) {
2833
+ if (matches_order(arr, this.#inverseOrder)) {
2834
+ return arr;
2835
+ }
2836
+ return convert_array_order(arr, this.#inverseOrder);
2837
+ }
2838
+ decode(arr) {
2839
+ return {
2840
+ data: arr.data,
2841
+ shape: arr.shape,
2842
+ stride: get_strides(arr.shape, this.#order)
2843
+ };
2844
+ }
2845
+ }
2846
+ class VLenUTF8 {
2847
+ constructor(shape) {
2848
+ this.kind = "array_to_bytes";
2849
+ this.#shape = shape;
2850
+ this.#strides = get_strides(shape, "C");
2851
+ }
2852
+ #shape;
2853
+ #strides;
2854
+ static fromConfig(_, meta) {
2855
+ return new VLenUTF8(meta.shape);
2856
+ }
2857
+ encode(_chunk) {
2858
+ throw new Error("Method not implemented.");
2859
+ }
2860
+ decode(bytes) {
2861
+ let decoder = new TextDecoder();
2862
+ let view = new DataView(bytes.buffer);
2863
+ let data = Array(view.getUint32(0, true));
2864
+ let pos = 4;
2865
+ for (let i = 0; i < data.length; i++) {
2866
+ let item_length = view.getUint32(pos, true);
2867
+ pos += 4;
2868
+ data[i] = decoder.decode(bytes.buffer.slice(pos, pos + item_length));
2869
+ pos += item_length;
2870
+ }
2871
+ return { data, shape: this.#shape, stride: this.#strides };
2872
+ }
2873
+ }
2874
+ class ZlibCodec {
2875
+ constructor() {
2876
+ this.kind = "bytes_to_bytes";
2877
+ }
2878
+ static fromConfig(_) {
2879
+ return new ZlibCodec();
2880
+ }
2881
+ encode(_bytes) {
2882
+ throw new Error("Zlib encoding is not enabled by default. Please register a codec with `numcodecs/zlib`.");
2883
+ }
2884
+ async decode(bytes) {
2885
+ const buffer = await decompress(bytes, { format: "deflate" });
2886
+ return new Uint8Array(buffer);
2887
+ }
2888
+ }
2889
+ function create_default_registry() {
2890
+ return (/* @__PURE__ */ new Map()).set("blosc", () => import("./blosc-DvQQ1ST0.js").then((m) => m.default)).set("lz4", () => import("./lz4-BIbM36RN.js").then((m) => m.default)).set("zstd", () => import("./zstd-CO575QiM.js").then((m) => m.default)).set("gzip", () => GzipCodec).set("zlib", () => ZlibCodec).set("transpose", () => TransposeCodec).set("bytes", () => BytesCodec).set("crc32c", () => Crc32cCodec).set("vlen-utf8", () => VLenUTF8).set("json2", () => JsonCodec).set("bitround", () => BitroundCodec);
2891
+ }
2892
+ const registry = create_default_registry();
2893
+ function create_codec_pipeline(chunk_metadata) {
2894
+ let codecs;
2895
+ return {
2896
+ async encode(chunk) {
2897
+ if (!codecs)
2898
+ codecs = await load_codecs(chunk_metadata);
2899
+ for (const codec of codecs.array_to_array) {
2900
+ chunk = await codec.encode(chunk);
2901
+ }
2902
+ let bytes = await codecs.array_to_bytes.encode(chunk);
2903
+ for (const codec of codecs.bytes_to_bytes) {
2904
+ bytes = await codec.encode(bytes);
2905
+ }
2906
+ return bytes;
2907
+ },
2908
+ async decode(bytes) {
2909
+ if (!codecs)
2910
+ codecs = await load_codecs(chunk_metadata);
2911
+ for (let i = codecs.bytes_to_bytes.length - 1; i >= 0; i--) {
2912
+ bytes = await codecs.bytes_to_bytes[i].decode(bytes);
2913
+ }
2914
+ let chunk = await codecs.array_to_bytes.decode(bytes);
2915
+ for (let i = codecs.array_to_array.length - 1; i >= 0; i--) {
2916
+ chunk = await codecs.array_to_array[i].decode(chunk);
2917
+ }
2918
+ return chunk;
2919
+ }
2920
+ };
2921
+ }
2922
+ async function load_codecs(chunk_meta) {
2923
+ let promises = chunk_meta.codecs.map(async (meta) => {
2924
+ let Codec = await registry.get(meta.name)?.();
2925
+ assert(Codec, `Unknown codec: ${meta.name}`);
2926
+ return { Codec, meta };
2927
+ });
2928
+ let array_to_array = [];
2929
+ let array_to_bytes;
2930
+ let bytes_to_bytes = [];
2931
+ for await (let { Codec, meta } of promises) {
2932
+ let codec = Codec.fromConfig(meta.configuration, chunk_meta);
2933
+ switch (codec.kind) {
2934
+ case "array_to_array":
2935
+ array_to_array.push(codec);
2936
+ break;
2937
+ case "array_to_bytes":
2938
+ array_to_bytes = codec;
2939
+ break;
2940
+ default:
2941
+ bytes_to_bytes.push(codec);
2942
+ }
2943
+ }
2944
+ if (!array_to_bytes) {
2945
+ assert(is_typed_array_like_meta(chunk_meta), `Cannot encode ${chunk_meta.data_type} to bytes without a codec`);
2946
+ array_to_bytes = BytesCodec.fromConfig({ endian: "little" }, chunk_meta);
2947
+ }
2948
+ return { array_to_array, array_to_bytes, bytes_to_bytes };
2949
+ }
2950
+ function is_typed_array_like_meta(meta) {
2951
+ return meta.data_type !== "v2:object" && meta.data_type !== "string";
2952
+ }
2953
+ class NodeNotFoundError extends Error {
2954
+ constructor(context, options = {}) {
2955
+ super(`Node not found: ${context}`, options);
2956
+ this.name = "NodeNotFoundError";
2957
+ }
2958
+ }
2959
+ class KeyError extends Error {
2960
+ constructor(path) {
2961
+ super(`Missing key: ${path}`);
2962
+ this.name = "KeyError";
2963
+ }
2964
+ }
2965
+ async function get_consolidated_metadata(store, metadataKeyOption) {
2966
+ const metadataKey = metadataKeyOption ?? ".zmetadata";
2967
+ let bytes = await store.get(`/${metadataKey}`);
2968
+ if (!bytes) {
2969
+ throw new NodeNotFoundError("v2 consolidated metadata", {
2970
+ cause: new KeyError(`/${metadataKey}`)
2971
+ });
2972
+ }
2973
+ let meta = json_decode_object(bytes);
2974
+ assert(meta.zarr_consolidated_format === 1, "Unsupported consolidated format.");
2975
+ return meta;
2976
+ }
2977
+ function is_meta_key(key) {
2978
+ return key.endsWith(".zarray") || key.endsWith(".zgroup") || key.endsWith(".zattrs") || key.endsWith("zarr.json");
2979
+ }
2980
+ function is_v3(meta) {
2981
+ return "zarr_format" in meta && meta.zarr_format === 3;
2982
+ }
2983
+ async function withConsolidated(store, opts = {}) {
2984
+ let v2_meta = await get_consolidated_metadata(store, opts.metadataKey);
2985
+ let known_meta = {};
2986
+ for (let [key, value] of Object.entries(v2_meta.metadata)) {
2987
+ known_meta[`/${key}`] = value;
2988
+ }
2989
+ return {
2990
+ async get(...args) {
2991
+ let [key, opts2] = args;
2992
+ if (known_meta[key]) {
2993
+ return json_encode_object(known_meta[key]);
2994
+ }
2995
+ let maybe_bytes = await store.get(key, opts2);
2996
+ if (is_meta_key(key) && maybe_bytes) {
2997
+ let meta = json_decode_object(maybe_bytes);
2998
+ known_meta[key] = meta;
2999
+ }
3000
+ return maybe_bytes;
3001
+ },
3002
+ // Delegate range requests to the underlying store.
3003
+ // Note: Supporting range requests for consolidated metadata is possible
3004
+ // but unlikely to be useful enough to justify the effort.
3005
+ getRange: store.getRange?.bind(store),
3006
+ contents() {
3007
+ let contents = [];
3008
+ for (let [key, value] of Object.entries(known_meta)) {
3009
+ let parts = key.split("/");
3010
+ let filename = parts.pop();
3011
+ let path = parts.join("/") || "/";
3012
+ if (filename === ".zarray")
3013
+ contents.push({ path, kind: "array" });
3014
+ if (filename === ".zgroup")
3015
+ contents.push({ path, kind: "group" });
3016
+ if (is_v3(value)) {
3017
+ contents.push({ path, kind: value.node_type });
3018
+ }
3019
+ }
3020
+ return contents;
3021
+ }
3022
+ };
3023
+ }
3024
+ const MAX_BIG_UINT = 18446744073709551615n;
3025
+ function create_sharded_chunk_getter(location, shard_shape, encode_shard_key, sharding_config) {
3026
+ assert(location.store.getRange, "Store does not support range requests");
3027
+ let get_range = location.store.getRange.bind(location.store);
3028
+ let index_shape = shard_shape.map((d, i) => d / sharding_config.chunk_shape[i]);
3029
+ let index_codec = create_codec_pipeline({
3030
+ data_type: "uint64",
3031
+ shape: [...index_shape, 2],
3032
+ codecs: sharding_config.index_codecs
3033
+ });
3034
+ let cache = {};
3035
+ return async (chunk_coord, options) => {
3036
+ let shard_coord = chunk_coord.map((d, i) => Math.floor(d / index_shape[i]));
3037
+ let shard_path = location.resolve(encode_shard_key(shard_coord)).path;
3038
+ let index;
3039
+ if (shard_path in cache) {
3040
+ index = cache[shard_path];
3041
+ } else {
3042
+ let checksum_size = 4;
3043
+ let index_size = 16 * index_shape.reduce((a, b) => a * b, 1);
3044
+ let bytes = await get_range(shard_path, {
3045
+ suffixLength: index_size + checksum_size
3046
+ }, options);
3047
+ index = cache[shard_path] = bytes ? await index_codec.decode(bytes) : null;
3048
+ }
3049
+ if (index === null) {
3050
+ return void 0;
3051
+ }
3052
+ let { data, shape, stride } = index;
3053
+ let linear_offset = chunk_coord.map((d, i) => d % shape[i]).reduce((acc, sel, idx) => acc + sel * stride[idx], 0);
3054
+ let offset = data[linear_offset];
3055
+ let length = data[linear_offset + 1];
3056
+ if (offset === MAX_BIG_UINT && length === MAX_BIG_UINT) {
3057
+ return void 0;
3058
+ }
3059
+ return get_range(shard_path, {
3060
+ offset: Number(offset),
3061
+ length: Number(length)
3062
+ }, options);
3063
+ };
3064
+ }
3065
+ var _a;
3066
+ class Location {
3067
+ constructor(store, path = "/") {
3068
+ this.store = store;
3069
+ this.path = path;
3070
+ }
3071
+ resolve(path) {
3072
+ let root2 = new URL(`file://${this.path.endsWith("/") ? this.path : `${this.path}/`}`);
3073
+ return new Location(this.store, decodeURIComponent(new URL(path, root2).pathname));
3074
+ }
3075
+ }
3076
+ class Group extends Location {
3077
+ constructor(store, path, metadata) {
3078
+ super(store, path);
3079
+ this.kind = "group";
3080
+ this.#metadata = metadata;
3081
+ }
3082
+ #metadata;
3083
+ get attrs() {
3084
+ return this.#metadata.attributes;
3085
+ }
3086
+ }
3087
+ function get_array_order(codecs) {
3088
+ const maybe_transpose_codec = codecs.find((c) => c.name === "transpose");
3089
+ return maybe_transpose_codec?.configuration?.order ?? "C";
3090
+ }
3091
+ const CONTEXT_MARKER = Symbol("zarrita.context");
3092
+ function create_context(location, metadata) {
3093
+ let { configuration } = metadata.codecs.find(is_sharding_codec) ?? {};
3094
+ let shared_context = {
3095
+ encode_chunk_key: create_chunk_key_encoder(metadata.chunk_key_encoding),
3096
+ TypedArray: get_ctr(metadata.data_type),
3097
+ fill_value: metadata.fill_value
3098
+ };
3099
+ if (configuration) {
3100
+ let native_order2 = get_array_order(configuration.codecs);
3101
+ return {
3102
+ ...shared_context,
3103
+ kind: "sharded",
3104
+ chunk_shape: configuration.chunk_shape,
3105
+ codec: create_codec_pipeline({
3106
+ data_type: metadata.data_type,
3107
+ shape: configuration.chunk_shape,
3108
+ codecs: configuration.codecs
3109
+ }),
3110
+ get_strides(shape) {
3111
+ return get_strides(shape, native_order2);
3112
+ },
3113
+ get_chunk_bytes: create_sharded_chunk_getter(location, metadata.chunk_grid.configuration.chunk_shape, shared_context.encode_chunk_key, configuration)
3114
+ };
3115
+ }
3116
+ let native_order = get_array_order(metadata.codecs);
3117
+ return {
3118
+ ...shared_context,
3119
+ kind: "regular",
3120
+ chunk_shape: metadata.chunk_grid.configuration.chunk_shape,
3121
+ codec: create_codec_pipeline({
3122
+ data_type: metadata.data_type,
3123
+ shape: metadata.chunk_grid.configuration.chunk_shape,
3124
+ codecs: metadata.codecs
3125
+ }),
3126
+ get_strides(shape) {
3127
+ return get_strides(shape, native_order);
3128
+ },
3129
+ async get_chunk_bytes(chunk_coords, options) {
3130
+ let chunk_key = shared_context.encode_chunk_key(chunk_coords);
3131
+ let chunk_path = location.resolve(chunk_key).path;
3132
+ return location.store.get(chunk_path, options);
3133
+ }
3134
+ };
3135
+ }
3136
+ let Array$1 = class Array2 extends (_a = Location, _a) {
3137
+ constructor(store, path, metadata) {
3138
+ super(store, path);
3139
+ this.kind = "array";
3140
+ this.#metadata = {
3141
+ ...metadata,
3142
+ fill_value: ensure_correct_scalar(metadata)
3143
+ };
3144
+ this[CONTEXT_MARKER] = create_context(this, metadata);
3145
+ }
3146
+ #metadata;
3147
+ get attrs() {
3148
+ return this.#metadata.attributes;
3149
+ }
3150
+ get shape() {
3151
+ return this.#metadata.shape;
3152
+ }
3153
+ get chunks() {
3154
+ return this[CONTEXT_MARKER].chunk_shape;
3155
+ }
3156
+ get dtype() {
3157
+ return this.#metadata.data_type;
3158
+ }
3159
+ async getChunk(chunk_coords, options) {
3160
+ let context = this[CONTEXT_MARKER];
3161
+ let maybe_bytes = await context.get_chunk_bytes(chunk_coords, options);
3162
+ if (!maybe_bytes) {
3163
+ let size = context.chunk_shape.reduce((a, b) => a * b, 1);
3164
+ let data = new context.TypedArray(size);
3165
+ data.fill(context.fill_value);
3166
+ return {
3167
+ data,
3168
+ shape: context.chunk_shape,
3169
+ stride: context.get_strides(context.chunk_shape)
3170
+ };
3171
+ }
3172
+ return context.codec.decode(maybe_bytes);
3173
+ }
3174
+ /**
3175
+ * A helper method to narrow `zarr.Array` Dtype.
3176
+ *
3177
+ * ```typescript
3178
+ * let arr: zarr.Array<DataType, FetchStore> = zarr.open(store, { kind: "array" });
3179
+ *
3180
+ * // Option 1: narrow by scalar type (e.g. "bool", "raw", "bigint", "number")
3181
+ * if (arr.is("bigint")) {
3182
+ * // zarr.Array<"int64" | "uint64", FetchStore>
3183
+ * }
3184
+ *
3185
+ * // Option 3: exact match
3186
+ * if (arr.is("float32")) {
3187
+ * // zarr.Array<"float32", FetchStore, "/">
3188
+ * }
3189
+ * ```
3190
+ */
3191
+ is(query) {
3192
+ return is_dtype(this.dtype, query);
3193
+ }
3194
+ };
3195
+ let VERSION_COUNTER = create_version_counter();
3196
+ function create_version_counter() {
3197
+ let version_counts = /* @__PURE__ */ new WeakMap();
3198
+ function get_counts(store) {
3199
+ let counts = version_counts.get(store) ?? { v2: 0, v3: 0 };
3200
+ version_counts.set(store, counts);
3201
+ return counts;
3202
+ }
3203
+ return {
3204
+ increment(store, version) {
3205
+ get_counts(store)[version] += 1;
3206
+ },
3207
+ version_max(store) {
3208
+ let counts = get_counts(store);
3209
+ return counts.v3 > counts.v2 ? "v3" : "v2";
3210
+ }
3211
+ };
3212
+ }
3213
+ async function load_attrs(location) {
3214
+ let meta_bytes = await location.store.get(location.resolve(".zattrs").path);
3215
+ if (!meta_bytes)
3216
+ return {};
3217
+ return json_decode_object(meta_bytes);
3218
+ }
3219
+ async function open_v2(location, options = {}) {
3220
+ let loc = "store" in location ? location : new Location(location);
3221
+ let attrs = {};
3222
+ if (options.attrs ?? true)
3223
+ attrs = await load_attrs(loc);
3224
+ if (options.kind === "array")
3225
+ return open_array_v2(loc, attrs);
3226
+ if (options.kind === "group")
3227
+ return open_group_v2(loc, attrs);
3228
+ return open_array_v2(loc, attrs).catch((err) => {
3229
+ rethrow_unless(err, NodeNotFoundError);
3230
+ return open_group_v2(loc, attrs);
3231
+ });
3232
+ }
3233
+ async function open_array_v2(location, attrs) {
3234
+ let { path } = location.resolve(".zarray");
3235
+ let meta = await location.store.get(path);
3236
+ if (!meta) {
3237
+ throw new NodeNotFoundError("v2 array", {
3238
+ cause: new KeyError(path)
3239
+ });
3240
+ }
3241
+ VERSION_COUNTER.increment(location.store, "v2");
3242
+ return new Array$1(location.store, location.path, v2_to_v3_array_metadata(json_decode_object(meta), attrs));
3243
+ }
3244
+ async function open_group_v2(location, attrs) {
3245
+ let { path } = location.resolve(".zgroup");
3246
+ let meta = await location.store.get(path);
3247
+ if (!meta) {
3248
+ throw new NodeNotFoundError("v2 group", {
3249
+ cause: new KeyError(path)
3250
+ });
3251
+ }
3252
+ VERSION_COUNTER.increment(location.store, "v2");
3253
+ return new Group(location.store, location.path, v2_to_v3_group_metadata(json_decode_object(meta), attrs));
3254
+ }
3255
+ async function _open_v3(location) {
3256
+ let { store, path } = location.resolve("zarr.json");
3257
+ let meta = await location.store.get(path);
3258
+ if (!meta) {
3259
+ throw new NodeNotFoundError("v3 array or group", {
3260
+ cause: new KeyError(path)
3261
+ });
3262
+ }
3263
+ let meta_doc = json_decode_object(meta);
3264
+ if (meta_doc.node_type === "array") {
3265
+ meta_doc.fill_value = ensure_correct_scalar(meta_doc);
3266
+ }
3267
+ return meta_doc.node_type === "array" ? new Array$1(store, location.path, meta_doc) : new Group(store, location.path, meta_doc);
3268
+ }
3269
+ async function open_v3(location, options = {}) {
3270
+ let loc = "store" in location ? location : new Location(location);
3271
+ let node = await _open_v3(loc);
3272
+ VERSION_COUNTER.increment(loc.store, "v3");
3273
+ if (options.kind === void 0)
3274
+ return node;
3275
+ if (options.kind === "array" && node instanceof Array$1)
3276
+ return node;
3277
+ if (options.kind === "group" && node instanceof Group)
3278
+ return node;
3279
+ let kind = node instanceof Array$1 ? "array" : "group";
3280
+ throw new Error(`Expected node of kind ${options.kind}, found ${kind}.`);
3281
+ }
3282
+ async function open(location, options = {}) {
3283
+ let store = "store" in location ? location.store : location;
3284
+ let version_max = VERSION_COUNTER.version_max(store);
3285
+ let open_primary = version_max === "v2" ? open.v2 : open.v3;
3286
+ let open_secondary = version_max === "v2" ? open.v3 : open.v2;
3287
+ return open_primary(location, options).catch((err) => {
3288
+ rethrow_unless(err, NodeNotFoundError);
3289
+ return open_secondary(location, options);
3290
+ });
3291
+ }
3292
+ open.v2 = open_v2;
3293
+ open.v3 = open_v3;
3294
+ function readBlobAsArrayBuffer(blob) {
3295
+ if (blob.arrayBuffer) {
3296
+ return blob.arrayBuffer();
3297
+ }
3298
+ return new Promise((resolve2, reject) => {
3299
+ const reader = new FileReader();
3300
+ reader.addEventListener("loadend", () => {
3301
+ resolve2(reader.result);
3302
+ });
3303
+ reader.addEventListener("error", reject);
3304
+ reader.readAsArrayBuffer(blob);
3305
+ });
3306
+ }
3307
+ async function readBlobAsUint8Array(blob) {
3308
+ const arrayBuffer = await readBlobAsArrayBuffer(blob);
3309
+ return new Uint8Array(arrayBuffer);
3310
+ }
3311
+ function isBlob(v) {
3312
+ return typeof Blob !== "undefined" && v instanceof Blob;
3313
+ }
3314
+ function isSharedArrayBuffer(b) {
3315
+ return typeof SharedArrayBuffer !== "undefined" && b instanceof SharedArrayBuffer;
3316
+ }
3317
+ const isNode = typeof process !== "undefined" && process.versions && typeof process.versions.node !== "undefined" && typeof process.versions.electron === "undefined";
3318
+ function isTypedArraySameAsArrayBuffer(typedArray) {
3319
+ return typedArray.byteOffset === 0 && typedArray.byteLength === typedArray.buffer.byteLength;
3320
+ }
3321
+ class ArrayBufferReader {
3322
+ constructor(arrayBufferOrView) {
3323
+ this.typedArray = arrayBufferOrView instanceof ArrayBuffer || isSharedArrayBuffer(arrayBufferOrView) ? new Uint8Array(arrayBufferOrView) : new Uint8Array(arrayBufferOrView.buffer, arrayBufferOrView.byteOffset, arrayBufferOrView.byteLength);
3324
+ }
3325
+ async getLength() {
3326
+ return this.typedArray.byteLength;
3327
+ }
3328
+ async read(offset, length) {
3329
+ return new Uint8Array(this.typedArray.buffer, this.typedArray.byteOffset + offset, length);
3330
+ }
3331
+ }
3332
+ let BlobReader$1 = class BlobReader {
3333
+ constructor(blob) {
3334
+ this.blob = blob;
3335
+ }
3336
+ async getLength() {
3337
+ return this.blob.size;
3338
+ }
3339
+ async read(offset, length) {
3340
+ const blob = this.blob.slice(offset, offset + length);
3341
+ const arrayBuffer = await readBlobAsArrayBuffer(blob);
3342
+ return new Uint8Array(arrayBuffer);
3343
+ }
3344
+ async sliceAsBlob(offset, length, type = "") {
3345
+ return this.blob.slice(offset, offset + length, type);
3346
+ }
3347
+ };
3348
+ function inflate(data, buf) {
3349
+ var u8 = Uint8Array;
3350
+ if (data[0] == 3 && data[1] == 0) return buf ? buf : new u8(0);
3351
+ var bitsF = _bitsF, bitsE = _bitsE, decodeTiny = _decodeTiny, get17 = _get17;
3352
+ var noBuf = buf == null;
3353
+ if (noBuf) buf = new u8(data.length >>> 2 << 3);
3354
+ var BFINAL = 0, BTYPE = 0, HLIT = 0, HDIST = 0, HCLEN = 0, ML = 0, MD = 0;
3355
+ var off = 0, pos = 0;
3356
+ var lmap, dmap;
3357
+ while (BFINAL == 0) {
3358
+ BFINAL = bitsF(data, pos, 1);
3359
+ BTYPE = bitsF(data, pos + 1, 2);
3360
+ pos += 3;
3361
+ if (BTYPE == 0) {
3362
+ if ((pos & 7) != 0) pos += 8 - (pos & 7);
3363
+ var p8 = (pos >>> 3) + 4, len = data[p8 - 4] | data[p8 - 3] << 8;
3364
+ if (noBuf) buf = _check(buf, off + len);
3365
+ buf.set(new u8(data.buffer, data.byteOffset + p8, len), off);
3366
+ pos = p8 + len << 3;
3367
+ off += len;
3368
+ continue;
3369
+ }
3370
+ if (noBuf) buf = _check(buf, off + (1 << 17));
3371
+ if (BTYPE == 1) {
3372
+ lmap = U.flmap;
3373
+ dmap = U.fdmap;
3374
+ ML = (1 << 9) - 1;
3375
+ MD = (1 << 5) - 1;
3376
+ }
3377
+ if (BTYPE == 2) {
3378
+ HLIT = bitsE(data, pos, 5) + 257;
3379
+ HDIST = bitsE(data, pos + 5, 5) + 1;
3380
+ HCLEN = bitsE(data, pos + 10, 4) + 4;
3381
+ pos += 14;
3382
+ for (var i = 0; i < 38; i += 2) {
3383
+ U.itree[i] = 0;
3384
+ U.itree[i + 1] = 0;
3385
+ }
3386
+ var tl = 1;
3387
+ for (var i = 0; i < HCLEN; i++) {
3388
+ var l = bitsE(data, pos + i * 3, 3);
3389
+ U.itree[(U.ordr[i] << 1) + 1] = l;
3390
+ if (l > tl) tl = l;
3391
+ }
3392
+ pos += 3 * HCLEN;
3393
+ makeCodes(U.itree, tl);
3394
+ codes2map(U.itree, tl, U.imap);
3395
+ lmap = U.lmap;
3396
+ dmap = U.dmap;
3397
+ pos = decodeTiny(U.imap, (1 << tl) - 1, HLIT + HDIST, data, pos, U.ttree);
3398
+ var mx0 = _copyOut(U.ttree, 0, HLIT, U.ltree);
3399
+ ML = (1 << mx0) - 1;
3400
+ var mx1 = _copyOut(U.ttree, HLIT, HDIST, U.dtree);
3401
+ MD = (1 << mx1) - 1;
3402
+ makeCodes(U.ltree, mx0);
3403
+ codes2map(U.ltree, mx0, lmap);
3404
+ makeCodes(U.dtree, mx1);
3405
+ codes2map(U.dtree, mx1, dmap);
3406
+ }
3407
+ while (true) {
3408
+ var code = lmap[get17(data, pos) & ML];
3409
+ pos += code & 15;
3410
+ var lit = code >>> 4;
3411
+ if (lit >>> 8 == 0) {
3412
+ buf[off++] = lit;
3413
+ } else if (lit == 256) {
3414
+ break;
3415
+ } else {
3416
+ var end = off + lit - 254;
3417
+ if (lit > 264) {
3418
+ var ebs = U.ldef[lit - 257];
3419
+ end = off + (ebs >>> 3) + bitsE(data, pos, ebs & 7);
3420
+ pos += ebs & 7;
3421
+ }
3422
+ var dcode = dmap[get17(data, pos) & MD];
3423
+ pos += dcode & 15;
3424
+ var dlit = dcode >>> 4;
3425
+ var dbs = U.ddef[dlit], dst = (dbs >>> 4) + bitsF(data, pos, dbs & 15);
3426
+ pos += dbs & 15;
3427
+ if (noBuf) buf = _check(buf, off + (1 << 17));
3428
+ while (off < end) {
3429
+ buf[off] = buf[off++ - dst];
3430
+ buf[off] = buf[off++ - dst];
3431
+ buf[off] = buf[off++ - dst];
3432
+ buf[off] = buf[off++ - dst];
3433
+ }
3434
+ off = end;
3435
+ }
3436
+ }
3437
+ }
3438
+ return buf.length == off ? buf : buf.slice(0, off);
3439
+ }
3440
+ function _check(buf, len) {
3441
+ var bl = buf.length;
3442
+ if (len <= bl) return buf;
3443
+ var nbuf = new Uint8Array(Math.max(bl << 1, len));
3444
+ nbuf.set(buf, 0);
3445
+ return nbuf;
3446
+ }
3447
+ function _decodeTiny(lmap, LL, len, data, pos, tree) {
3448
+ var bitsE = _bitsE, get17 = _get17;
3449
+ var i = 0;
3450
+ while (i < len) {
3451
+ var code = lmap[get17(data, pos) & LL];
3452
+ pos += code & 15;
3453
+ var lit = code >>> 4;
3454
+ if (lit <= 15) {
3455
+ tree[i] = lit;
3456
+ i++;
3457
+ } else {
3458
+ var ll = 0, n = 0;
3459
+ if (lit == 16) {
3460
+ n = 3 + bitsE(data, pos, 2);
3461
+ pos += 2;
3462
+ ll = tree[i - 1];
3463
+ } else if (lit == 17) {
3464
+ n = 3 + bitsE(data, pos, 3);
3465
+ pos += 3;
3466
+ } else if (lit == 18) {
3467
+ n = 11 + bitsE(data, pos, 7);
3468
+ pos += 7;
3469
+ }
3470
+ var ni = i + n;
3471
+ while (i < ni) {
3472
+ tree[i] = ll;
3473
+ i++;
3474
+ }
3475
+ }
3476
+ }
3477
+ return pos;
3478
+ }
3479
+ function _copyOut(src, off, len, tree) {
3480
+ var mx = 0, i = 0, tl = tree.length >>> 1;
3481
+ while (i < len) {
3482
+ var v = src[i + off];
3483
+ tree[i << 1] = 0;
3484
+ tree[(i << 1) + 1] = v;
3485
+ if (v > mx) mx = v;
3486
+ i++;
3487
+ }
3488
+ while (i < tl) {
3489
+ tree[i << 1] = 0;
3490
+ tree[(i << 1) + 1] = 0;
3491
+ i++;
3492
+ }
3493
+ return mx;
3494
+ }
3495
+ function makeCodes(tree, MAX_BITS) {
3496
+ var max_code = tree.length;
3497
+ var code, bits, n, i, len;
3498
+ var bl_count = U.bl_count;
3499
+ for (var i = 0; i <= MAX_BITS; i++) bl_count[i] = 0;
3500
+ for (i = 1; i < max_code; i += 2) bl_count[tree[i]]++;
3501
+ var next_code = U.next_code;
3502
+ code = 0;
3503
+ bl_count[0] = 0;
3504
+ for (bits = 1; bits <= MAX_BITS; bits++) {
3505
+ code = code + bl_count[bits - 1] << 1;
3506
+ next_code[bits] = code;
3507
+ }
3508
+ for (n = 0; n < max_code; n += 2) {
3509
+ len = tree[n + 1];
3510
+ if (len != 0) {
3511
+ tree[n] = next_code[len];
3512
+ next_code[len]++;
3513
+ }
3514
+ }
3515
+ }
3516
+ function codes2map(tree, MAX_BITS, map) {
3517
+ var max_code = tree.length;
3518
+ var r15 = U.rev15;
3519
+ for (var i = 0; i < max_code; i += 2) if (tree[i + 1] != 0) {
3520
+ var lit = i >> 1;
3521
+ var cl = tree[i + 1], val = lit << 4 | cl;
3522
+ var rest = MAX_BITS - cl, i0 = tree[i] << rest, i1 = i0 + (1 << rest);
3523
+ while (i0 != i1) {
3524
+ var p0 = r15[i0] >>> 15 - MAX_BITS;
3525
+ map[p0] = val;
3526
+ i0++;
3527
+ }
3528
+ }
3529
+ }
3530
+ function revCodes(tree, MAX_BITS) {
3531
+ var r15 = U.rev15, imb = 15 - MAX_BITS;
3532
+ for (var i = 0; i < tree.length; i += 2) {
3533
+ var i0 = tree[i] << MAX_BITS - tree[i + 1];
3534
+ tree[i] = r15[i0] >>> imb;
3535
+ }
3536
+ }
3537
+ function _bitsE(dt, pos, length) {
3538
+ return (dt[pos >>> 3] | dt[(pos >>> 3) + 1] << 8) >>> (pos & 7) & (1 << length) - 1;
3539
+ }
3540
+ function _bitsF(dt, pos, length) {
3541
+ return (dt[pos >>> 3] | dt[(pos >>> 3) + 1] << 8 | dt[(pos >>> 3) + 2] << 16) >>> (pos & 7) & (1 << length) - 1;
3542
+ }
3543
+ function _get17(dt, pos) {
3544
+ return (dt[pos >>> 3] | dt[(pos >>> 3) + 1] << 8 | dt[(pos >>> 3) + 2] << 16) >>> (pos & 7);
3545
+ }
3546
+ const U = function() {
3547
+ var u16 = Uint16Array, u32 = Uint32Array;
3548
+ return {
3549
+ next_code: new u16(16),
3550
+ bl_count: new u16(16),
3551
+ ordr: [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15],
3552
+ of0: [3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 999, 999, 999],
3553
+ exb: [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0, 0],
3554
+ ldef: new u16(32),
3555
+ df0: [1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 65535, 65535],
3556
+ dxb: [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 0, 0],
3557
+ ddef: new u32(32),
3558
+ flmap: new u16(512),
3559
+ fltree: [],
3560
+ fdmap: new u16(32),
3561
+ fdtree: [],
3562
+ lmap: new u16(32768),
3563
+ ltree: [],
3564
+ ttree: [],
3565
+ dmap: new u16(32768),
3566
+ dtree: [],
3567
+ imap: new u16(512),
3568
+ itree: [],
3569
+ //rev9 : new u16( 512)
3570
+ rev15: new u16(1 << 15),
3571
+ lhst: new u32(286),
3572
+ dhst: new u32(30),
3573
+ ihst: new u32(19),
3574
+ lits: new u32(15e3),
3575
+ strt: new u16(1 << 16),
3576
+ prev: new u16(1 << 15)
3577
+ };
3578
+ }();
3579
+ (function() {
3580
+ var len = 1 << 15;
3581
+ for (var i = 0; i < len; i++) {
3582
+ var x = i;
3583
+ x = (x & 2863311530) >>> 1 | (x & 1431655765) << 1;
3584
+ x = (x & 3435973836) >>> 2 | (x & 858993459) << 2;
3585
+ x = (x & 4042322160) >>> 4 | (x & 252645135) << 4;
3586
+ x = (x & 4278255360) >>> 8 | (x & 16711935) << 8;
3587
+ U.rev15[i] = (x >>> 16 | x << 16) >>> 17;
3588
+ }
3589
+ function pushV(tgt, n, sv) {
3590
+ while (n-- != 0) tgt.push(0, sv);
3591
+ }
3592
+ for (var i = 0; i < 32; i++) {
3593
+ U.ldef[i] = U.of0[i] << 3 | U.exb[i];
3594
+ U.ddef[i] = U.df0[i] << 4 | U.dxb[i];
3595
+ }
3596
+ pushV(U.fltree, 144, 8);
3597
+ pushV(U.fltree, 255 - 143, 9);
3598
+ pushV(U.fltree, 279 - 255, 7);
3599
+ pushV(U.fltree, 287 - 279, 8);
3600
+ makeCodes(U.fltree, 9);
3601
+ codes2map(U.fltree, 9, U.flmap);
3602
+ revCodes(U.fltree, 9);
3603
+ pushV(U.fdtree, 32, 5);
3604
+ makeCodes(U.fdtree, 5);
3605
+ codes2map(U.fdtree, 5, U.fdmap);
3606
+ revCodes(U.fdtree, 5);
3607
+ pushV(U.itree, 19, 0);
3608
+ pushV(U.ltree, 286, 0);
3609
+ pushV(U.dtree, 30, 0);
3610
+ pushV(U.ttree, 320, 0);
3611
+ })();
3612
+ ({
3613
+ table: function() {
3614
+ var tab = new Uint32Array(256);
3615
+ for (var n = 0; n < 256; n++) {
3616
+ var c = n;
3617
+ for (var k = 0; k < 8; k++) {
3618
+ if (c & 1) c = 3988292384 ^ c >>> 1;
3619
+ else c = c >>> 1;
3620
+ }
3621
+ tab[n] = c;
3622
+ }
3623
+ return tab;
3624
+ }()
3625
+ });
3626
+ function inflateRaw(file, buf) {
3627
+ return inflate(file, buf);
3628
+ }
3629
+ const config = {
3630
+ numWorkers: 1,
3631
+ workerURL: "",
3632
+ useWorkers: false
3633
+ };
3634
+ let nextId = 0;
3635
+ const waitingForWorkerQueue = [];
3636
+ function startWorker(url) {
3637
+ return new Promise((resolve2, reject) => {
3638
+ const worker = new Worker(url);
3639
+ worker.onmessage = (e) => {
3640
+ if (e.data === "start") {
3641
+ worker.onerror = void 0;
3642
+ worker.onmessage = void 0;
3643
+ resolve2(worker);
3644
+ } else {
3645
+ reject(new Error(`unexpected message: ${e.data}`));
3646
+ }
3647
+ };
3648
+ worker.onerror = reject;
3649
+ });
3650
+ }
3651
+ function dynamicRequire(mod, request) {
3652
+ return mod.require ? mod.require(request) : {};
3653
+ }
3654
+ (function() {
3655
+ if (isNode) {
3656
+ const { Worker: Worker2 } = dynamicRequire(module, "worker_threads");
3657
+ return {
3658
+ async createWorker(url) {
3659
+ return new Worker2(url);
3660
+ },
3661
+ addEventListener(worker, fn) {
3662
+ worker.on("message", (data) => {
3663
+ fn({ target: worker, data });
3664
+ });
3665
+ },
3666
+ async terminate(worker) {
3667
+ await worker.terminate();
3668
+ }
3669
+ };
3670
+ } else {
3671
+ return {
3672
+ async createWorker(url) {
3673
+ try {
3674
+ const worker = await startWorker(url);
3675
+ return worker;
3676
+ } catch (e) {
3677
+ console.warn("could not load worker:", url);
3678
+ }
3679
+ let text;
3680
+ try {
3681
+ const req = await fetch(url, { mode: "cors" });
3682
+ if (!req.ok) {
3683
+ throw new Error(`could not load: ${url}`);
3684
+ }
3685
+ text = await req.text();
3686
+ url = URL.createObjectURL(new Blob([text], { type: "application/javascript" }));
3687
+ const worker = await startWorker(url);
3688
+ config.workerURL = url;
3689
+ return worker;
3690
+ } catch (e) {
3691
+ console.warn("could not load worker via fetch:", url);
3692
+ }
3693
+ if (text !== void 0) {
3694
+ try {
3695
+ url = `data:application/javascript;base64,${btoa(text)}`;
3696
+ const worker = await startWorker(url);
3697
+ config.workerURL = url;
3698
+ return worker;
3699
+ } catch (e) {
3700
+ console.warn("could not load worker via dataURI");
3701
+ }
3702
+ }
3703
+ console.warn("workers will not be used");
3704
+ throw new Error("can not start workers");
3705
+ },
3706
+ addEventListener(worker, fn) {
3707
+ worker.addEventListener("message", fn);
3708
+ },
3709
+ async terminate(worker) {
3710
+ worker.terminate();
3711
+ }
3712
+ };
3713
+ }
3714
+ })();
3715
+ function inflateRawLocal(src, uncompressedSize, type, resolve2) {
3716
+ const dst = new Uint8Array(uncompressedSize);
3717
+ inflateRaw(src, dst);
3718
+ resolve2(type ? new Blob([dst], { type }) : dst.buffer);
3719
+ }
3720
+ async function processWaitingForWorkerQueue() {
3721
+ if (waitingForWorkerQueue.length === 0) {
3722
+ return;
3723
+ }
3724
+ while (waitingForWorkerQueue.length) {
3725
+ const { src, uncompressedSize, type, resolve: resolve2 } = waitingForWorkerQueue.shift();
3726
+ let data = src;
3727
+ if (isBlob(src)) {
3728
+ data = await readBlobAsUint8Array(src);
3729
+ }
3730
+ inflateRawLocal(data, uncompressedSize, type, resolve2);
3731
+ }
3732
+ }
3733
+ function inflateRawAsync(src, uncompressedSize, type) {
3734
+ return new Promise((resolve2, reject) => {
3735
+ waitingForWorkerQueue.push({ src, uncompressedSize, type, resolve: resolve2, reject, id: nextId++ });
3736
+ processWaitingForWorkerQueue();
3737
+ });
3738
+ }
3739
+ function dosDateTimeToDate(date, time) {
3740
+ const day = date & 31;
3741
+ const month = (date >> 5 & 15) - 1;
3742
+ const year = (date >> 9 & 127) + 1980;
3743
+ const millisecond = 0;
3744
+ const second = (time & 31) * 2;
3745
+ const minute = time >> 5 & 63;
3746
+ const hour = time >> 11 & 31;
3747
+ return new Date(year, month, day, hour, minute, second, millisecond);
3748
+ }
3749
+ class ZipEntry {
3750
+ constructor(reader, rawEntry) {
3751
+ this._reader = reader;
3752
+ this._rawEntry = rawEntry;
3753
+ this.name = rawEntry.name;
3754
+ this.nameBytes = rawEntry.nameBytes;
3755
+ this.size = rawEntry.uncompressedSize;
3756
+ this.compressedSize = rawEntry.compressedSize;
3757
+ this.comment = rawEntry.comment;
3758
+ this.commentBytes = rawEntry.commentBytes;
3759
+ this.compressionMethod = rawEntry.compressionMethod;
3760
+ this.lastModDate = dosDateTimeToDate(rawEntry.lastModFileDate, rawEntry.lastModFileTime);
3761
+ this.isDirectory = rawEntry.uncompressedSize === 0 && rawEntry.name.endsWith("/");
3762
+ this.encrypted = !!(rawEntry.generalPurposeBitFlag & 1);
3763
+ this.externalFileAttributes = rawEntry.externalFileAttributes;
3764
+ this.versionMadeBy = rawEntry.versionMadeBy;
3765
+ }
3766
+ // returns a promise that returns a Blob for this entry
3767
+ async blob(type = "application/octet-stream") {
3768
+ return await readEntryDataAsBlob(this._reader, this._rawEntry, type);
3769
+ }
3770
+ // returns a promise that returns an ArrayBuffer for this entry
3771
+ async arrayBuffer() {
3772
+ return await readEntryDataAsArrayBuffer(this._reader, this._rawEntry);
3773
+ }
3774
+ // returns text, assumes the text is valid utf8. If you want more options decode arrayBuffer yourself
3775
+ async text() {
3776
+ const buffer = await this.arrayBuffer();
3777
+ return decodeBuffer(new Uint8Array(buffer));
3778
+ }
3779
+ // returns text with JSON.parse called on it. If you want more options decode arrayBuffer yourself
3780
+ async json() {
3781
+ const text = await this.text();
3782
+ return JSON.parse(text);
3783
+ }
3784
+ }
3785
+ const EOCDR_WITHOUT_COMMENT_SIZE = 22;
3786
+ const MAX_COMMENT_SIZE = 65535;
3787
+ const EOCDR_SIGNATURE = 101010256;
3788
+ const ZIP64_EOCDR_SIGNATURE = 101075792;
3789
+ async function readAs(reader, offset, length) {
3790
+ return await reader.read(offset, length);
3791
+ }
3792
+ async function readAsBlobOrTypedArray(reader, offset, length, type) {
3793
+ if (reader.sliceAsBlob) {
3794
+ return await reader.sliceAsBlob(offset, length, type);
3795
+ }
3796
+ return await reader.read(offset, length);
3797
+ }
3798
+ const crc$1 = {
3799
+ unsigned() {
3800
+ return 0;
3801
+ }
3802
+ };
3803
+ function getUint16LE(uint8View, offset) {
3804
+ return uint8View[offset] + uint8View[offset + 1] * 256;
3805
+ }
3806
+ function getUint32LE(uint8View, offset) {
3807
+ return uint8View[offset] + uint8View[offset + 1] * 256 + uint8View[offset + 2] * 65536 + uint8View[offset + 3] * 16777216;
3808
+ }
3809
+ function getUint64LE(uint8View, offset) {
3810
+ return getUint32LE(uint8View, offset) + getUint32LE(uint8View, offset + 4) * 4294967296;
3811
+ }
3812
+ const utf8Decoder = new TextDecoder();
3813
+ function decodeBuffer(uint8View, isUTF8) {
3814
+ if (isSharedArrayBuffer(uint8View.buffer)) {
3815
+ uint8View = new Uint8Array(uint8View);
3816
+ }
3817
+ return utf8Decoder.decode(uint8View);
3818
+ }
3819
+ async function findEndOfCentralDirector(reader, totalLength) {
3820
+ const size = Math.min(EOCDR_WITHOUT_COMMENT_SIZE + MAX_COMMENT_SIZE, totalLength);
3821
+ const readStart = totalLength - size;
3822
+ const data = await readAs(reader, readStart, size);
3823
+ for (let i = size - EOCDR_WITHOUT_COMMENT_SIZE; i >= 0; --i) {
3824
+ if (getUint32LE(data, i) !== EOCDR_SIGNATURE) {
3825
+ continue;
3826
+ }
3827
+ const eocdr = new Uint8Array(data.buffer, data.byteOffset + i, data.byteLength - i);
3828
+ const diskNumber = getUint16LE(eocdr, 4);
3829
+ if (diskNumber !== 0) {
3830
+ throw new Error(`multi-volume zip files are not supported. This is volume: ${diskNumber}`);
3831
+ }
3832
+ const entryCount = getUint16LE(eocdr, 10);
3833
+ const centralDirectorySize = getUint32LE(eocdr, 12);
3834
+ const centralDirectoryOffset = getUint32LE(eocdr, 16);
3835
+ const commentLength = getUint16LE(eocdr, 20);
3836
+ const expectedCommentLength = eocdr.length - EOCDR_WITHOUT_COMMENT_SIZE;
3837
+ if (commentLength !== expectedCommentLength) {
3838
+ throw new Error(`invalid comment length. expected: ${expectedCommentLength}, actual: ${commentLength}`);
3839
+ }
3840
+ const commentBytes = new Uint8Array(eocdr.buffer, eocdr.byteOffset + 22, commentLength);
3841
+ const comment = decodeBuffer(commentBytes);
3842
+ if (entryCount === 65535 || centralDirectoryOffset === 4294967295) {
3843
+ return await readZip64CentralDirectory(reader, readStart + i, comment, commentBytes);
3844
+ } else {
3845
+ return await readEntries(reader, centralDirectoryOffset, centralDirectorySize, entryCount, comment, commentBytes);
3846
+ }
3847
+ }
3848
+ throw new Error("could not find end of central directory. maybe not zip file");
3849
+ }
3850
+ const END_OF_CENTRAL_DIRECTORY_LOCATOR_SIGNATURE = 117853008;
3851
+ async function readZip64CentralDirectory(reader, offset, comment, commentBytes) {
3852
+ const zip64EocdlOffset = offset - 20;
3853
+ const eocdl = await readAs(reader, zip64EocdlOffset, 20);
3854
+ if (getUint32LE(eocdl, 0) !== END_OF_CENTRAL_DIRECTORY_LOCATOR_SIGNATURE) {
3855
+ throw new Error("invalid zip64 end of central directory locator signature");
3856
+ }
3857
+ const zip64EocdrOffset = getUint64LE(eocdl, 8);
3858
+ const zip64Eocdr = await readAs(reader, zip64EocdrOffset, 56);
3859
+ if (getUint32LE(zip64Eocdr, 0) !== ZIP64_EOCDR_SIGNATURE) {
3860
+ throw new Error("invalid zip64 end of central directory record signature");
3861
+ }
3862
+ const entryCount = getUint64LE(zip64Eocdr, 32);
3863
+ const centralDirectorySize = getUint64LE(zip64Eocdr, 40);
3864
+ const centralDirectoryOffset = getUint64LE(zip64Eocdr, 48);
3865
+ return readEntries(reader, centralDirectoryOffset, centralDirectorySize, entryCount, comment, commentBytes);
3866
+ }
3867
+ const CENTRAL_DIRECTORY_FILE_HEADER_SIGNATURE = 33639248;
3868
+ async function readEntries(reader, centralDirectoryOffset, centralDirectorySize, rawEntryCount, comment, commentBytes) {
3869
+ let readEntryCursor = 0;
3870
+ const allEntriesBuffer = await readAs(reader, centralDirectoryOffset, centralDirectorySize);
3871
+ const rawEntries = [];
3872
+ for (let e = 0; e < rawEntryCount; ++e) {
3873
+ const buffer = allEntriesBuffer.subarray(readEntryCursor, readEntryCursor + 46);
3874
+ const signature = getUint32LE(buffer, 0);
3875
+ if (signature !== CENTRAL_DIRECTORY_FILE_HEADER_SIGNATURE) {
3876
+ throw new Error(`invalid central directory file header signature: 0x${signature.toString(16)}`);
3877
+ }
3878
+ const rawEntry = {
3879
+ // 4 - Version made by
3880
+ versionMadeBy: getUint16LE(buffer, 4),
3881
+ // 6 - Version needed to extract (minimum)
3882
+ versionNeededToExtract: getUint16LE(buffer, 6),
3883
+ // 8 - General purpose bit flag
3884
+ generalPurposeBitFlag: getUint16LE(buffer, 8),
3885
+ // 10 - Compression method
3886
+ compressionMethod: getUint16LE(buffer, 10),
3887
+ // 12 - File last modification time
3888
+ lastModFileTime: getUint16LE(buffer, 12),
3889
+ // 14 - File last modification date
3890
+ lastModFileDate: getUint16LE(buffer, 14),
3891
+ // 16 - CRC-32
3892
+ crc32: getUint32LE(buffer, 16),
3893
+ // 20 - Compressed size
3894
+ compressedSize: getUint32LE(buffer, 20),
3895
+ // 24 - Uncompressed size
3896
+ uncompressedSize: getUint32LE(buffer, 24),
3897
+ // 28 - File name length (n)
3898
+ fileNameLength: getUint16LE(buffer, 28),
3899
+ // 30 - Extra field length (m)
3900
+ extraFieldLength: getUint16LE(buffer, 30),
3901
+ // 32 - File comment length (k)
3902
+ fileCommentLength: getUint16LE(buffer, 32),
3903
+ // 34 - Disk number where file starts
3904
+ // 36 - Internal file attributes
3905
+ internalFileAttributes: getUint16LE(buffer, 36),
3906
+ // 38 - External file attributes
3907
+ externalFileAttributes: getUint32LE(buffer, 38),
3908
+ // 42 - Relative offset of local file header
3909
+ relativeOffsetOfLocalHeader: getUint32LE(buffer, 42)
3910
+ };
3911
+ if (rawEntry.generalPurposeBitFlag & 64) {
3912
+ throw new Error("strong encryption is not supported");
3913
+ }
3914
+ readEntryCursor += 46;
3915
+ const data = allEntriesBuffer.subarray(readEntryCursor, readEntryCursor + rawEntry.fileNameLength + rawEntry.extraFieldLength + rawEntry.fileCommentLength);
3916
+ rawEntry.nameBytes = data.slice(0, rawEntry.fileNameLength);
3917
+ rawEntry.name = decodeBuffer(rawEntry.nameBytes);
3918
+ const fileCommentStart = rawEntry.fileNameLength + rawEntry.extraFieldLength;
3919
+ const extraFieldBuffer = data.slice(rawEntry.fileNameLength, fileCommentStart);
3920
+ rawEntry.extraFields = [];
3921
+ let i = 0;
3922
+ while (i < extraFieldBuffer.length - 3) {
3923
+ const headerId = getUint16LE(extraFieldBuffer, i + 0);
3924
+ const dataSize = getUint16LE(extraFieldBuffer, i + 2);
3925
+ const dataStart = i + 4;
3926
+ const dataEnd = dataStart + dataSize;
3927
+ if (dataEnd > extraFieldBuffer.length) {
3928
+ throw new Error("extra field length exceeds extra field buffer size");
3929
+ }
3930
+ rawEntry.extraFields.push({
3931
+ id: headerId,
3932
+ data: extraFieldBuffer.slice(dataStart, dataEnd)
3933
+ });
3934
+ i = dataEnd;
3935
+ }
3936
+ rawEntry.commentBytes = data.slice(fileCommentStart, fileCommentStart + rawEntry.fileCommentLength);
3937
+ rawEntry.comment = decodeBuffer(rawEntry.commentBytes);
3938
+ readEntryCursor += data.length;
3939
+ if (rawEntry.uncompressedSize === 4294967295 || rawEntry.compressedSize === 4294967295 || rawEntry.relativeOffsetOfLocalHeader === 4294967295) {
3940
+ const zip64ExtraField = rawEntry.extraFields.find((e2) => e2.id === 1);
3941
+ if (!zip64ExtraField) {
3942
+ throw new Error("expected zip64 extended information extra field");
3943
+ }
3944
+ const zip64EiefBuffer = zip64ExtraField.data;
3945
+ let index = 0;
3946
+ if (rawEntry.uncompressedSize === 4294967295) {
3947
+ if (index + 8 > zip64EiefBuffer.length) {
3948
+ throw new Error("zip64 extended information extra field does not include uncompressed size");
3949
+ }
3950
+ rawEntry.uncompressedSize = getUint64LE(zip64EiefBuffer, index);
3951
+ index += 8;
3952
+ }
3953
+ if (rawEntry.compressedSize === 4294967295) {
3954
+ if (index + 8 > zip64EiefBuffer.length) {
3955
+ throw new Error("zip64 extended information extra field does not include compressed size");
3956
+ }
3957
+ rawEntry.compressedSize = getUint64LE(zip64EiefBuffer, index);
3958
+ index += 8;
3959
+ }
3960
+ if (rawEntry.relativeOffsetOfLocalHeader === 4294967295) {
3961
+ if (index + 8 > zip64EiefBuffer.length) {
3962
+ throw new Error("zip64 extended information extra field does not include relative header offset");
3963
+ }
3964
+ rawEntry.relativeOffsetOfLocalHeader = getUint64LE(zip64EiefBuffer, index);
3965
+ index += 8;
3966
+ }
3967
+ }
3968
+ const nameField = rawEntry.extraFields.find((e2) => e2.id === 28789 && e2.data.length >= 6 && // too short to be meaningful
3969
+ e2.data[0] === 1 && // Version 1 byte version of this extra field, currently 1
3970
+ getUint32LE(e2.data, 1), crc$1.unsigned(rawEntry.nameBytes));
3971
+ if (nameField) {
3972
+ rawEntry.fileName = decodeBuffer(nameField.data.slice(5));
3973
+ }
3974
+ if (rawEntry.compressionMethod === 0) {
3975
+ let expectedCompressedSize = rawEntry.uncompressedSize;
3976
+ if ((rawEntry.generalPurposeBitFlag & 1) !== 0) {
3977
+ expectedCompressedSize += 12;
3978
+ }
3979
+ if (rawEntry.compressedSize !== expectedCompressedSize) {
3980
+ throw new Error(`compressed size mismatch for stored file: ${rawEntry.compressedSize} != ${expectedCompressedSize}`);
3981
+ }
3982
+ }
3983
+ rawEntries.push(rawEntry);
3984
+ }
3985
+ const zip = {
3986
+ comment,
3987
+ commentBytes
3988
+ };
3989
+ return {
3990
+ zip,
3991
+ entries: rawEntries.map((e) => new ZipEntry(reader, e))
3992
+ };
3993
+ }
3994
+ async function readEntryDataHeader(reader, rawEntry) {
3995
+ if (rawEntry.generalPurposeBitFlag & 1) {
3996
+ throw new Error("encrypted entries not supported");
3997
+ }
3998
+ const buffer = await readAs(reader, rawEntry.relativeOffsetOfLocalHeader, 30);
3999
+ const totalLength = await reader.getLength();
4000
+ const signature = getUint32LE(buffer, 0);
4001
+ if (signature !== 67324752) {
4002
+ throw new Error(`invalid local file header signature: 0x${signature.toString(16)}`);
4003
+ }
4004
+ const fileNameLength = getUint16LE(buffer, 26);
4005
+ const extraFieldLength = getUint16LE(buffer, 28);
4006
+ const localFileHeaderEnd = rawEntry.relativeOffsetOfLocalHeader + buffer.length + fileNameLength + extraFieldLength;
4007
+ let decompress2;
4008
+ if (rawEntry.compressionMethod === 0) {
4009
+ decompress2 = false;
4010
+ } else if (rawEntry.compressionMethod === 8) {
4011
+ decompress2 = true;
4012
+ } else {
4013
+ throw new Error(`unsupported compression method: ${rawEntry.compressionMethod}`);
4014
+ }
4015
+ const fileDataStart = localFileHeaderEnd;
4016
+ const fileDataEnd = fileDataStart + rawEntry.compressedSize;
4017
+ if (rawEntry.compressedSize !== 0) {
4018
+ if (fileDataEnd > totalLength) {
4019
+ throw new Error(`file data overflows file bounds: ${fileDataStart} + ${rawEntry.compressedSize} > ${totalLength}`);
4020
+ }
4021
+ }
4022
+ return {
4023
+ decompress: decompress2,
4024
+ fileDataStart
4025
+ };
4026
+ }
4027
+ async function readEntryDataAsArrayBuffer(reader, rawEntry) {
4028
+ const { decompress: decompress2, fileDataStart } = await readEntryDataHeader(reader, rawEntry);
4029
+ if (!decompress2) {
4030
+ const dataView = await readAs(reader, fileDataStart, rawEntry.compressedSize);
4031
+ return isTypedArraySameAsArrayBuffer(dataView) ? dataView.buffer : dataView.slice().buffer;
4032
+ }
4033
+ const typedArrayOrBlob = await readAsBlobOrTypedArray(reader, fileDataStart, rawEntry.compressedSize);
4034
+ const result = await inflateRawAsync(typedArrayOrBlob, rawEntry.uncompressedSize);
4035
+ return result;
4036
+ }
4037
+ async function readEntryDataAsBlob(reader, rawEntry, type) {
4038
+ const { decompress: decompress2, fileDataStart } = await readEntryDataHeader(reader, rawEntry);
4039
+ if (!decompress2) {
4040
+ const typedArrayOrBlob2 = await readAsBlobOrTypedArray(reader, fileDataStart, rawEntry.compressedSize, type);
4041
+ if (isBlob(typedArrayOrBlob2)) {
4042
+ return typedArrayOrBlob2;
4043
+ }
4044
+ return new Blob([isSharedArrayBuffer(typedArrayOrBlob2.buffer) ? new Uint8Array(typedArrayOrBlob2) : typedArrayOrBlob2], { type });
4045
+ }
4046
+ const typedArrayOrBlob = await readAsBlobOrTypedArray(reader, fileDataStart, rawEntry.compressedSize);
4047
+ const result = await inflateRawAsync(typedArrayOrBlob, rawEntry.uncompressedSize, type);
4048
+ return result;
4049
+ }
4050
+ async function unzipRaw(source) {
4051
+ let reader;
4052
+ if (typeof Blob !== "undefined" && source instanceof Blob) {
4053
+ reader = new BlobReader$1(source);
4054
+ } else if (source instanceof ArrayBuffer || source && source.buffer && source.buffer instanceof ArrayBuffer) {
4055
+ reader = new ArrayBufferReader(source);
4056
+ } else if (isSharedArrayBuffer(source) || isSharedArrayBuffer(source.buffer)) {
4057
+ reader = new ArrayBufferReader(source);
4058
+ } else if (typeof source === "string") {
4059
+ const req = await fetch(source);
4060
+ if (!req.ok) {
4061
+ throw new Error(`failed http request ${source}, status: ${req.status}: ${req.statusText}`);
4062
+ }
4063
+ const blob = await req.blob();
4064
+ reader = new BlobReader$1(blob);
4065
+ } else if (typeof source.getLength === "function" && typeof source.read === "function") {
4066
+ reader = source;
4067
+ } else {
4068
+ throw new Error("unsupported source type");
4069
+ }
4070
+ const totalLength = await reader.getLength();
4071
+ if (totalLength > Number.MAX_SAFE_INTEGER) {
4072
+ throw new Error(`file too large. size: ${totalLength}. Only file sizes up 4503599627370496 bytes are supported`);
4073
+ }
4074
+ return await findEndOfCentralDirector(reader, totalLength);
4075
+ }
4076
+ async function unzip(source) {
4077
+ const { zip, entries } = await unzipRaw(source);
4078
+ return {
4079
+ zip,
4080
+ entries: Object.fromEntries(entries.map((v) => [v.name, v]))
4081
+ };
4082
+ }
4083
+ function isZipEntryInternal(entry) {
4084
+ if (!("compressionMethod" in entry) || !("_rawEntry" in entry)) {
4085
+ return false;
4086
+ }
4087
+ const rawEntry = entry._rawEntry;
4088
+ return typeof entry.compressionMethod === "number" && typeof rawEntry === "object" && rawEntry !== null && "relativeOffsetOfLocalHeader" in rawEntry && typeof rawEntry.relativeOffsetOfLocalHeader === "number";
4089
+ }
4090
+ class BlobReader2 {
4091
+ constructor(blob) {
4092
+ this.blob = blob;
4093
+ }
4094
+ async getLength() {
4095
+ return this.blob.size;
4096
+ }
4097
+ async read(offset, length) {
4098
+ const blob = this.blob.slice(offset, offset + length);
4099
+ return new Uint8Array(await blob.arrayBuffer());
4100
+ }
4101
+ }
4102
+ class HTTPRangeReader {
4103
+ #overrides;
4104
+ constructor(url, opts = {}) {
4105
+ this.url = url;
4106
+ this.#overrides = opts.overrides ?? {};
4107
+ }
4108
+ async getLength() {
4109
+ if (this.length === void 0) {
4110
+ const req = await fetch(this.url, {
4111
+ ...this.#overrides,
4112
+ method: "HEAD"
4113
+ });
4114
+ assert$1(req.ok, `failed http request ${this.url}, status: ${req.status}: ${req.statusText}`);
4115
+ this.length = Number(req.headers.get("content-length"));
4116
+ if (Number.isNaN(this.length)) {
4117
+ throw Error("could not get length");
4118
+ }
4119
+ }
4120
+ return this.length;
4121
+ }
4122
+ async read(offset, size) {
4123
+ if (size === 0) {
4124
+ return new Uint8Array(0);
4125
+ }
4126
+ const req = await fetch_range(this.url, offset, size, this.#overrides);
4127
+ assert$1(req.ok, `failed http request ${this.url}, status: ${req.status} offset: ${offset} size: ${size}: ${req.statusText}`);
4128
+ return new Uint8Array(await req.arrayBuffer());
4129
+ }
4130
+ }
4131
+ class ZipFileStore {
4132
+ constructor(reader, opts = {}) {
4133
+ this.reader = reader;
4134
+ this.info = unzip(reader).then((info) => {
4135
+ if (opts.transformEntries) {
4136
+ info.entries = opts.transformEntries(info.entries);
4137
+ }
4138
+ return info;
4139
+ });
4140
+ }
4141
+ /**
4142
+ * Compute the byte offset where entry data begins in the zip file.
4143
+ * This requires reading the local file header to get filename and extra field lengths.
4144
+ */
4145
+ async getEntryDataOffset(entry) {
4146
+ const localHeaderOffset = entry._rawEntry.relativeOffsetOfLocalHeader;
4147
+ const header = await this.reader.read(localHeaderOffset, 30);
4148
+ const fileNameLength = header[26] + header[27] * 256;
4149
+ const extraFieldLength = header[28] + header[29] * 256;
4150
+ return localHeaderOffset + 30 + fileNameLength + extraFieldLength;
4151
+ }
4152
+ async get(key) {
4153
+ let entry = (await this.info).entries[strip_prefix(key)];
4154
+ if (!entry)
4155
+ return;
4156
+ return new Uint8Array(await entry.arrayBuffer());
4157
+ }
4158
+ async getRange(key, range) {
4159
+ const entry = (await this.info).entries[strip_prefix(key)];
4160
+ if (!entry)
4161
+ return void 0;
4162
+ if (!isZipEntryInternal(entry)) {
4163
+ throw new Error("ZipFileStore.getRange requires internal unzipit properties that are not available. This may indicate an incompatible version of unzipit.");
4164
+ }
4165
+ if (entry.compressionMethod !== 0) {
4166
+ const bytes = await this.get(key);
4167
+ if (!bytes)
4168
+ return void 0;
4169
+ if ("suffixLength" in range) {
4170
+ return bytes.slice(-range.suffixLength);
4171
+ }
4172
+ return bytes.slice(range.offset, range.offset + range.length);
4173
+ }
4174
+ const dataOffset = await this.getEntryDataOffset(entry);
4175
+ if ("suffixLength" in range) {
4176
+ const start = dataOffset + entry.size - range.suffixLength;
4177
+ return this.reader.read(start, range.suffixLength);
4178
+ }
4179
+ return this.reader.read(dataOffset + range.offset, range.length);
4180
+ }
4181
+ async has(key) {
4182
+ return strip_prefix(key) in (await this.info).entries;
4183
+ }
4184
+ static fromUrl(href, opts = {}) {
4185
+ return new ZipFileStore(new HTTPRangeReader(href, opts), opts);
4186
+ }
4187
+ static fromBlob(blob, opts = {}) {
4188
+ return new ZipFileStore(new BlobReader2(blob), opts);
4189
+ }
4190
+ }
4191
+ function transformEntriesForZipFileStore(entries) {
4192
+ const topLevelZarrDirectories = new Set(Object.keys(entries).map((k) => k.split("/")[0]).filter((firstPathItem) => firstPathItem?.endsWith(".zarr")));
4193
+ if (topLevelZarrDirectories.size === 0) {
4194
+ return entries;
4195
+ }
4196
+ if (topLevelZarrDirectories.size > 1) {
4197
+ throw Error("expected exactly one top-level .zarr directory");
4198
+ }
4199
+ const topLevelZarrDirectory = Array.from(topLevelZarrDirectories)[0];
4200
+ const newEntries = Object.fromEntries(Object.entries(entries).map(([k, v]) => {
4201
+ let newKey = k;
4202
+ if (k.split("/")[0] === topLevelZarrDirectory) {
4203
+ newKey = k.substring(topLevelZarrDirectory.length + 1);
4204
+ }
4205
+ return [newKey, v];
4206
+ }));
4207
+ return newEntries;
4208
+ }
4209
+ function flattenOmeAttrs(rootAttrs) {
4210
+ if (rootAttrs && typeof rootAttrs.ome === "object" && rootAttrs.ome !== null) {
4211
+ return { ...rootAttrs.ome, ...rootAttrs };
4212
+ }
4213
+ return rootAttrs;
4214
+ }
4215
+ class AbstractAutoConfig2 {
4216
+ constructor(parsedStore) {
4217
+ const { url, fileType, zmetadata } = parsedStore;
4218
+ this.url = url;
4219
+ this.fileType = fileType;
4220
+ this.zmetadata = zmetadata;
4221
+ }
4222
+ // eslint-disable-next-line class-methods-use-this
4223
+ addFiles(vc, dataset) {
4224
+ throw new Error("The addFiles() method has not been implemented.");
4225
+ }
4226
+ // eslint-disable-next-line class-methods-use-this
4227
+ addViews(vc, dataset, layoutOption) {
4228
+ throw new Error("The addViews() method has not been implemented.");
4229
+ }
4230
+ }
4231
+ class AnnDataAutoConfig extends AbstractAutoConfig2 {
4232
+ getOptions() {
4233
+ const { zmetadata } = this;
4234
+ const options = {
4235
+ obsEmbedding: [],
4236
+ obsSets: []
4237
+ };
4238
+ zmetadata.forEach(({ path, attrs }) => {
4239
+ const lowerPath = path.toLowerCase();
4240
+ const relPath = path.substring(1);
4241
+ if (["/x"].includes(lowerPath)) {
4242
+ options.obsFeatureMatrix = {
4243
+ path: relPath
4244
+ // TODO: Also check the shape of X.
4245
+ // If X is very large, try to initialize initial-filtering properties
4246
+ // (will require that /var contains a boolean column however.)
4247
+ };
4248
+ }
4249
+ if (["/obsm/x_spatial", "/obsm/spatial"].includes(lowerPath)) {
4250
+ options.obsLocations = {
4251
+ path: relPath
4252
+ };
4253
+ }
4254
+ if (["/obsm/x_umap", "/obsm/umap"].includes(lowerPath)) {
4255
+ options.obsEmbedding.push({ path: relPath, embeddingType: "UMAP" });
4256
+ }
4257
+ if (["/obsm/x_tsne", "/obsm/tsne"].includes(lowerPath)) {
4258
+ options.obsEmbedding.push({ path: relPath, embeddingType: "t-SNE" });
4259
+ }
4260
+ if (["/obsm/x_pca", "/obsm/pca"].includes(lowerPath)) {
4261
+ options.obsEmbedding.push({ path: relPath, embeddingType: "PCA" });
4262
+ }
4263
+ const supportedObsSetsPaths = [
4264
+ "cluster",
4265
+ "clusters",
4266
+ "subcluster",
4267
+ "cell_type",
4268
+ "celltype",
4269
+ "leiden",
4270
+ "louvain",
4271
+ "disease",
4272
+ "organism",
4273
+ "self_reported_ethnicity",
4274
+ "tissue",
4275
+ "sex"
4276
+ ].map((colname) => `/obs/${colname}`);
4277
+ if (supportedObsSetsPaths.includes(lowerPath)) {
4278
+ const name = relPath.split("/").at(-1);
4279
+ options.obsSets.push({ path: relPath, name });
4280
+ }
4281
+ });
4282
+ return options;
4283
+ }
4284
+ addFiles(vc, dataset) {
4285
+ const { url, fileType } = this;
4286
+ dataset.addFile({
4287
+ url,
4288
+ fileType,
4289
+ options: this.getOptions()
4290
+ // TODO: coordination values?
4291
+ });
4292
+ }
4293
+ // eslint-disable-next-line class-methods-use-this
4294
+ addViews(vc, dataset, layoutOption) {
4295
+ }
4296
+ }
4297
+ class SpatialDataAutoConfig extends AbstractAutoConfig2 {
4298
+ getOptions() {
4299
+ const { zmetadata } = this;
4300
+ const options = {};
4301
+ const availableElements = zmetadata.filter(({ path }) => {
4302
+ const relPath = path.substring(1);
4303
+ return relPath.match(/^(tables|table|images|labels|shapes|points)\/([^/]*)$/);
4304
+ });
4305
+ availableElements.forEach(({ path, attrs }) => {
4306
+ const relPath = path.substring(1);
4307
+ const omeAttrs = flattenOmeAttrs(attrs);
4308
+ const firstCoordinateSystem = omeAttrs?.multiscales?.[0]?.coordinateTransformations?.[0]?.output?.name;
4309
+ if (relPath.match(/^(images)\/([^/]*)$/)) {
4310
+ options.image = {
4311
+ path: relPath,
4312
+ coordinateSystem: firstCoordinateSystem
4313
+ // TODO: support a fileUid property in the schema?
4314
+ };
4315
+ }
4316
+ if (relPath.match(/^(labels)\/([^/]*)$/)) {
4317
+ options.obsSegmentations = {
4318
+ path: relPath,
4319
+ coordinateSystem: firstCoordinateSystem
4320
+ // TODO: support a fileUid property in the schema?
4321
+ };
4322
+ }
4323
+ if (relPath.match(/^(shapes)\/([^/]*)$/)) {
4324
+ options.obsSegmentations = {
4325
+ path: relPath,
4326
+ coordinateSystem: firstCoordinateSystem
4327
+ };
4328
+ }
4329
+ if (relPath.match(/^(tables|table)\/([^/]*)$/)) {
4330
+ const tableEls = zmetadata.filter(({ path: subpath }) => subpath.startsWith(path));
4331
+ const hasX = tableEls.find((el) => el.path === `${path}/X`);
4332
+ if (hasX) {
4333
+ options.obsFeatureMatrix = {
4334
+ path: hasX.path.substring(1)
4335
+ // region: null,
4336
+ };
4337
+ }
4338
+ }
4339
+ });
4340
+ return options;
4341
+ }
4342
+ addFiles(vc, dataset) {
4343
+ const { url, fileType } = this;
4344
+ dataset.addFile({
4345
+ url,
4346
+ fileType,
4347
+ options: this.getOptions()
4348
+ // TODO: coordination values?
4349
+ });
4350
+ }
4351
+ // eslint-disable-next-line class-methods-use-this
4352
+ addViews(vc, dataset, layoutOption) {
4353
+ const options = this.getOptions();
4354
+ const spatialView = vc.addView(dataset, "spatialBeta");
4355
+ const lcView = vc.addView(dataset, "layerControllerBeta");
4356
+ const controlViews = [lcView];
4357
+ if (options.obsSets) {
4358
+ const obsSets = vc.addView(dataset, "obsSets");
4359
+ controlViews.push(obsSets);
4360
+ }
4361
+ if (options.obsFeatureMatrix) {
4362
+ const featureList = vc.addView(dataset, "featureList");
4363
+ controlViews.push(featureList);
4364
+ }
4365
+ vc.layout(hconcat(spatialView, vconcat(...controlViews)));
4366
+ }
4367
+ }
4368
+ class OmeAutoConfig extends AbstractAutoConfig2 {
4369
+ addFiles(vc, dataset) {
4370
+ const { url, fileType } = this;
4371
+ dataset.addFile({
4372
+ url,
4373
+ fileType
4374
+ // TODO: options?
4375
+ // TODO: coordination values?
4376
+ });
4377
+ }
4378
+ // eslint-disable-next-line class-methods-use-this
4379
+ addViews(vc, dataset, layoutOption) {
4380
+ const spatialView = vc.addView(dataset, "spatialBeta");
4381
+ const lcView = vc.addView(dataset, "layerControllerBeta");
4382
+ vc.layout(hconcat(spatialView, lcView));
4383
+ }
4384
+ }
4385
+ const FILE_TYPE_DELIM = "$";
4386
+ const fileTypeToExtensions = {
4387
+ [FileType.IMAGE_OME_TIFF]: [".ome.tif", ".ome.tiff", ".ome.tf2", ".ome.tf8"],
4388
+ [FileType.IMAGE_OME_ZARR]: [".ome.zarr"],
4389
+ [FileType.IMAGE_OME_ZARR_ZIP]: [".ome.zarr.zip"],
4390
+ [FileType.ANNDATA_ZARR]: [".ad.zarr", ".h5ad.zarr", ".adata.zarr", ".anndata.zarr"],
4391
+ [FileType.ANNDATA_ZARR_ZIP]: [".ad.zarr.zip", ".h5ad.zarr.zip", ".adata.zarr.zip", ".anndata.zarr.zip"],
4392
+ // TODO: how to handle h5ad-based AnnData (since needs reference JSON file).
4393
+ // Perhaps just assume one H5AD+one JSON (or .ref.json) file correspond to each other?
4394
+ [FileType.SPATIALDATA_ZARR]: [".sd.zarr", ".sdata.zarr", ".spatialdata.zarr"],
4395
+ [FileType.SPATIALDATA_ZARR_ZIP]: [".sd.zarr.zip", ".sdata.zarr.zip", ".spatialdata.zarr.zip"]
4396
+ };
4397
+ const fileTypeToClass = {
4398
+ // OME-TIFF
4399
+ [FileType.IMAGE_OME_TIFF]: OmeAutoConfig,
4400
+ [FileType.OBS_SEGMENTATIONS_OME_TIFF]: OmeAutoConfig,
4401
+ // OME-Zarr
4402
+ [FileType.IMAGE_OME_ZARR]: OmeAutoConfig,
4403
+ [FileType.IMAGE_OME_ZARR_ZIP]: OmeAutoConfig,
4404
+ [FileType.OBS_SEGMENTATIONS_OME_ZARR]: OmeAutoConfig,
4405
+ [FileType.OBS_SEGMENTATIONS_OME_ZARR_ZIP]: OmeAutoConfig,
4406
+ // AnnData
4407
+ [FileType.ANNDATA_ZARR]: AnnDataAutoConfig,
4408
+ [FileType.ANNDATA_ZARR_ZIP]: AnnDataAutoConfig,
4409
+ // SpatialData
4410
+ [FileType.SPATIALDATA_ZARR]: SpatialDataAutoConfig,
4411
+ [FileType.SPATIALDATA_ZARR_ZIP]: SpatialDataAutoConfig
4412
+ };
4413
+ const ZARR_FILETYPES = [
4414
+ FileType.ANNDATA_ZARR,
4415
+ FileType.ANNDATA_ZARR_ZIP,
4416
+ FileType.SPATIALDATA_ZARR,
4417
+ FileType.SPATIALDATA_ZARR_ZIP,
4418
+ FileType.IMAGE_OME_ZARR,
4419
+ FileType.IMAGE_OME_ZARR_ZIP,
4420
+ FileType.OBS_SEGMENTATIONS_OME_ZARR,
4421
+ FileType.OBS_SEGMENTATIONS_OME_ZARR_ZIP
4422
+ ];
4423
+ function urlToFileType(url) {
4424
+ const match = Object.entries(fileTypeToExtensions).find(
4425
+ // eslint-disable-next-line no-unused-vars
4426
+ ([fileType, extensions]) => extensions.some((ext) => url.endsWith(ext))
4427
+ );
4428
+ if (match) {
4429
+ return match[0];
4430
+ }
4431
+ throw new Error("The file extension contained in the URL did not map to a supported fileType.");
4432
+ }
4433
+ function getStore(parsedUrl) {
4434
+ const { fileType, url } = parsedUrl;
4435
+ if (!ZARR_FILETYPES.includes(fileType)) {
4436
+ return null;
4437
+ }
4438
+ return fileType.endsWith(".zip") ? ZipFileStore.fromUrl(url, {
4439
+ transformEntries: transformEntriesForZipFileStore
4440
+ }) : new FetchStore(url);
4441
+ }
4442
+ function ensureStores(parsedUrls) {
4443
+ return parsedUrls.map((parsedUrl) => {
4444
+ if (parsedUrl.store) {
4445
+ return parsedUrl;
4446
+ }
4447
+ const store = getStore(parsedUrl);
4448
+ return {
4449
+ ...parsedUrl,
4450
+ store
4451
+ };
4452
+ });
4453
+ }
4454
+ function parseUrls(arr) {
4455
+ return arr.map((urlWithHash) => {
4456
+ const parts = urlWithHash.split(FILE_TYPE_DELIM);
4457
+ if (parts.length === 1) {
4458
+ const [url] = parts;
4459
+ return {
4460
+ url,
4461
+ fileType: urlToFileType(url)
4462
+ };
4463
+ }
4464
+ if (parts.length === 2) {
4465
+ const [url, fileType] = parts;
4466
+ return {
4467
+ url,
4468
+ fileType
4469
+ };
4470
+ }
4471
+ throw new Error(`Only expected zero or one ${FILE_TYPE_DELIM} character per URL, but received more.`);
4472
+ });
4473
+ }
4474
+ function parseUrlsFromString(s) {
4475
+ const urlsWithHashes = s.split(";");
4476
+ return parseUrls(urlsWithHashes);
4477
+ }
4478
+ async function parsedUrlToZmetadata(parsedUrl) {
4479
+ const { store: initialStore } = parsedUrl;
4480
+ if (!initialStore) {
4481
+ return null;
4482
+ }
4483
+ let store;
4484
+ let promises = [];
4485
+ try {
4486
+ try {
4487
+ store = await withConsolidated(initialStore);
4488
+ } catch {
4489
+ store = await withConsolidated(initialStore, { metadataKey: "zmetadata" });
4490
+ }
4491
+ const contents = store.contents();
4492
+ const consolidatedRoot = await open(store, { kind: "group" });
4493
+ promises = contents.map(async (value) => {
4494
+ let item;
4495
+ try {
4496
+ item = await open(
4497
+ consolidatedRoot.resolve(value.path),
4498
+ { kind: value.kind }
4499
+ );
4500
+ } catch {
4501
+ item = {
4502
+ attrs: {}
4503
+ };
4504
+ }
4505
+ return {
4506
+ ...value,
4507
+ attrs: item.attrs
4508
+ };
4509
+ });
4510
+ } catch {
4511
+ store = initialStore;
4512
+ const keysToTry = [
4513
+ // Note: OME-NGFF metadata is stored in the root attrs.
4514
+ "/",
4515
+ // AnnData keys
4516
+ "/X",
4517
+ "/layers",
4518
+ "/obs",
4519
+ "/var",
4520
+ "/obsm",
4521
+ "/obsm/spatial",
4522
+ "/obsm/X_spatial",
4523
+ "/obsm/pca",
4524
+ "/obsm/X_pca",
4525
+ "/obsm/tsne",
4526
+ "/obsm/X_tsne",
4527
+ "/obsm/umap",
4528
+ "/obsm/X_umap"
4529
+ // TODO: second round of getting metadata for
4530
+ // columns listed in /obs and /var .attrs['column-order'] ?
4531
+ // SpatialData keys
4532
+ // Note: For spatialData, we assume the store is always consolidated.
4533
+ // TODO: throw error if spatialdata + not consolidated?
4534
+ ];
4535
+ const storeRoot = await open(store, { kind: "group" });
4536
+ promises = keysToTry.map(async (k) => {
4537
+ try {
4538
+ const item = await open(storeRoot.resolve(k));
4539
+ return {
4540
+ path: k,
4541
+ kind: item.kind,
4542
+ attrs: item.attrs
4543
+ };
4544
+ } catch {
4545
+ return null;
4546
+ }
4547
+ });
4548
+ }
4549
+ return (await Promise.all(promises)).filter((entry) => entry !== null);
4550
+ }
4551
+ async function generateConfig(parsedUrls, layoutOption = null) {
4552
+ const parsedStores = ensureStores(parsedUrls);
4553
+ const zmetadataStores = await Promise.all(
4554
+ parsedStores.map(async (parsedStore) => ({
4555
+ ...parsedStore,
4556
+ zmetadata: await parsedUrlToZmetadata(parsedStore)
4557
+ }))
4558
+ );
4559
+ const vc = new VitessceConfig({
4560
+ schemaVersion: "1.0.17",
4561
+ name: "Automatically-generated configuration.",
4562
+ // TODO: write a description based on what is known
4563
+ // (fileType(s) and maybe layoutOption).
4564
+ description: "Populate with a description of this visualization."
4565
+ });
4566
+ const dataset = vc.addDataset("Main dataset");
4567
+ zmetadataStores.forEach((parsedStore) => {
4568
+ const { fileType } = parsedStore;
4569
+ const AutoConfigClass = fileTypeToClass[fileType];
4570
+ const autoConfig = new AutoConfigClass(parsedStore);
4571
+ autoConfig.addFiles(vc, dataset);
4572
+ autoConfig.addViews(vc, dataset, layoutOption);
4573
+ });
4574
+ const stores = Object.fromEntries(
4575
+ // Here, we use `parsedUrls` rather than `parsedStores`
4576
+ // so that we do not provide more stores than intended
4577
+ // (i.e., we do not provide stores which were solely created
4578
+ // to obtain zmetadata).
4579
+ parsedUrls.filter((d) => d.store).map((d) => [d.url, d.store])
4580
+ );
4581
+ return {
4582
+ config: vc,
4583
+ stores
4584
+ };
4585
+ }
4586
+ export {
4587
+ CL as CoordinationLevel,
4588
+ HINTS_CONFIG,
4589
+ HINT_TYPE_TO_FILE_TYPE_MAP,
4590
+ VitessceConfig,
4591
+ generateConfig$1 as generateConfig,
4592
+ generateConfig as generateConfigAlt,
4593
+ getCoordinationSpaceAndScopes,
4594
+ getHintOptions,
4595
+ getInitialCoordinationScopeName,
4596
+ getInitialCoordinationScopePrefix,
4597
+ hconcat,
4598
+ parseUrls,
4599
+ parseUrlsFromString,
4600
+ vconcat
4601
+ };