@marimo-team/marimo-export 0.0.0 → 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +113 -2
- package/dist/export-6118xT3K.mjs +823 -0
- package/dist/index-Ca3yEJUD.d.mts +15 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.mjs +4 -0
- package/dist/loader/anywidget.d.mts +76 -0
- package/dist/loader/anywidget.mjs +1561 -0
- package/dist/loader/arrow.d.mts +10 -0
- package/dist/loader/arrow.mjs +38 -0
- package/dist/loader/html.d.mts +6 -0
- package/dist/loader/html.mjs +10 -0
- package/dist/loader/json.d.mts +6 -0
- package/dist/loader/json.mjs +15 -0
- package/dist/loader/marimo-cell.d.mts +7 -0
- package/dist/loader/marimo-cell.mjs +16 -0
- package/dist/loader/marimo-output.d.mts +7 -0
- package/dist/loader/marimo-output.mjs +16 -0
- package/dist/loader/numpy.d.mts +19 -0
- package/dist/loader/numpy.mjs +168 -0
- package/dist/loader/parquet.d.mts +14 -0
- package/dist/loader/parquet.mjs +43 -0
- package/dist/loader/text.d.mts +6 -0
- package/dist/loader/text.mjs +10 -0
- package/dist/loader/vegalite.d.mts +18 -0
- package/dist/loader/vegalite.mjs +98 -0
- package/dist/loader-CDfnJ5Yb.mjs +441 -0
- package/dist/marimo-snapshot--nNjqcq_.mjs +280 -0
- package/dist/marimo-snapshot-Df66Xan0.d.mts +74 -0
- package/dist/prepared/index.d.mts +116 -0
- package/dist/prepared/index.mjs +703 -0
- package/dist/schema-SJ_aIgcO.mjs +713 -0
- package/dist/types-D52GHn1Q.d.mts +201 -0
- package/dist/utf8-DI-jI2Nm.mjs +17 -0
- package/package.json +112 -5
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
//#region ../portable-json/src/types.ts
|
|
2
|
+
const MAX_JSON_VALUES = 1e5;
|
|
3
|
+
//#endregion
|
|
4
|
+
//#region ../portable-json/src/convert.ts
|
|
5
|
+
const MAX_DIAGNOSTIC_PATH = 512;
|
|
6
|
+
const TRUNCATED_PATH = "...";
|
|
7
|
+
/** Return a detached portable JSON value. */
|
|
8
|
+
function portableJsonValue(input, path = "value") {
|
|
9
|
+
return convertValue(input, path, 0, {
|
|
10
|
+
active: /* @__PURE__ */ new WeakSet(),
|
|
11
|
+
count: 0
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
/** Return a detached portable JSON object. */
|
|
15
|
+
function portableJsonObject(input, path = "value") {
|
|
16
|
+
const value = portableJsonValue(input, path);
|
|
17
|
+
if (!isJsonObject(value)) throw new TypeError(`${path} must be an object.`);
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
function convertValue(input, path, depth, state) {
|
|
21
|
+
if (depth > 256) throw new TypeError(`${path} exceeds the maximum JSON nesting depth.`);
|
|
22
|
+
countValue(state, path);
|
|
23
|
+
if (input === null) return null;
|
|
24
|
+
if (isBoolean(input)) return input;
|
|
25
|
+
if (isString(input)) return unicodeScalar(input, path);
|
|
26
|
+
if (isNumber(input)) return portableNumber(input, path);
|
|
27
|
+
if (Array.isArray(input)) return convertArray(input, path, depth, state);
|
|
28
|
+
if (!isJsonObject(input)) throw new TypeError(`${path} must be JSON-compatible.`);
|
|
29
|
+
return convertObject(input, path, depth, state);
|
|
30
|
+
}
|
|
31
|
+
function convertArray(input, path, depth, state) {
|
|
32
|
+
enterContainer(input, path, state);
|
|
33
|
+
try {
|
|
34
|
+
if (input.length > 1e5 - state.count) throw new TypeError(`${path} exceeds the maximum JSON value count.`);
|
|
35
|
+
const values = [];
|
|
36
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
37
|
+
if (!Object.hasOwn(input, index)) throw new TypeError(`${childPath(path, `[${index}]`)} must be present.`);
|
|
38
|
+
values.push(convertValue(input[index], childPath(path, `[${index}]`), depth + 1, state));
|
|
39
|
+
}
|
|
40
|
+
return Object.freeze(values);
|
|
41
|
+
} finally {
|
|
42
|
+
state.active.delete(input);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function convertObject(input, path, depth, state) {
|
|
46
|
+
enterContainer(input, path, state);
|
|
47
|
+
try {
|
|
48
|
+
return Object.freeze(Object.fromEntries(Object.entries(input).map(([key, item]) => {
|
|
49
|
+
const keyPath = childPath(path, "<object key>");
|
|
50
|
+
countValue(state, keyPath);
|
|
51
|
+
unicodeScalar(key, keyPath);
|
|
52
|
+
return [key, convertValue(item, childPath(path, key), depth + 1, state)];
|
|
53
|
+
})));
|
|
54
|
+
} finally {
|
|
55
|
+
state.active.delete(input);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function enterContainer(value, path, state) {
|
|
59
|
+
if (state.active.has(value)) throw new TypeError(`${path} contains a cyclic container.`);
|
|
60
|
+
state.active.add(value);
|
|
61
|
+
}
|
|
62
|
+
function countValue(state, path) {
|
|
63
|
+
state.count += 1;
|
|
64
|
+
if (state.count > 1e5) throw new TypeError(`${path} exceeds the maximum JSON value count.`);
|
|
65
|
+
}
|
|
66
|
+
function portableNumber(value, path) {
|
|
67
|
+
if (!Number.isFinite(value)) throw new TypeError(`${path} must not contain NaN or infinity.`);
|
|
68
|
+
if (Number.isInteger(value) && !Number.isSafeInteger(value)) throw new TypeError(`${path} integer must be within the JavaScript safe range.`);
|
|
69
|
+
return Object.is(value, -0) ? 0 : value;
|
|
70
|
+
}
|
|
71
|
+
function unicodeScalar(value, path) {
|
|
72
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
73
|
+
const code = value.charCodeAt(index);
|
|
74
|
+
if (code >= 55296 && code <= 56319) {
|
|
75
|
+
const next = value.charCodeAt(index + 1);
|
|
76
|
+
if (next >= 56320 && next <= 57343) {
|
|
77
|
+
index += 1;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
throw new TypeError(`${path} must contain Unicode scalar values.`);
|
|
81
|
+
}
|
|
82
|
+
if (code >= 56320 && code <= 57343) throw new TypeError(`${path} must contain Unicode scalar values.`);
|
|
83
|
+
}
|
|
84
|
+
return value;
|
|
85
|
+
}
|
|
86
|
+
function isBoolean(value) {
|
|
87
|
+
return Object.prototype.toString.call(value) === "[object Boolean]";
|
|
88
|
+
}
|
|
89
|
+
function isString(value) {
|
|
90
|
+
return Object.prototype.toString.call(value) === "[object String]";
|
|
91
|
+
}
|
|
92
|
+
function isNumber(value) {
|
|
93
|
+
return Object.prototype.toString.call(value) === "[object Number]";
|
|
94
|
+
}
|
|
95
|
+
function isJsonObject(value) {
|
|
96
|
+
return value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
|
|
97
|
+
}
|
|
98
|
+
function childPath(path, segment) {
|
|
99
|
+
if (path === TRUNCATED_PATH || path.length >= MAX_DIAGNOSTIC_PATH) return TRUNCATED_PATH;
|
|
100
|
+
const shown = boundedSegment(segment, MAX_DIAGNOSTIC_PATH - path.length - 1);
|
|
101
|
+
return shown.length === 0 ? TRUNCATED_PATH : `${path}.${shown}`;
|
|
102
|
+
}
|
|
103
|
+
function boundedSegment(value, maximumLength) {
|
|
104
|
+
if (maximumLength < 2) return "";
|
|
105
|
+
const quoted = JSON.stringify(value);
|
|
106
|
+
if (quoted.length <= maximumLength) return quoted;
|
|
107
|
+
if (maximumLength < 5) return "\"\"";
|
|
108
|
+
return `${quoted.slice(0, maximumLength - 4)}..."`;
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/value-types.ts
|
|
112
|
+
function isPrimitiveWithPrototype(value, prototype) {
|
|
113
|
+
const boxed = Object(value);
|
|
114
|
+
return boxed !== value && Object.getPrototypeOf(boxed) === prototype;
|
|
115
|
+
}
|
|
116
|
+
function isStringValue(value) {
|
|
117
|
+
return isPrimitiveWithPrototype(value, String.prototype);
|
|
118
|
+
}
|
|
119
|
+
function isNumberValue(value) {
|
|
120
|
+
return isPrimitiveWithPrototype(value, Number.prototype);
|
|
121
|
+
}
|
|
122
|
+
function isJsonString(value) {
|
|
123
|
+
return isStringValue(value);
|
|
124
|
+
}
|
|
125
|
+
function isJsonNumber(value) {
|
|
126
|
+
return isNumberValue(value);
|
|
127
|
+
}
|
|
128
|
+
function isJsonBoolean(value) {
|
|
129
|
+
return isBooleanValue(value);
|
|
130
|
+
}
|
|
131
|
+
function isBooleanValue(value) {
|
|
132
|
+
return isPrimitiveWithPrototype(value, Boolean.prototype);
|
|
133
|
+
}
|
|
134
|
+
function isRecordValue(value) {
|
|
135
|
+
return value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]";
|
|
136
|
+
}
|
|
137
|
+
function isPropertyOwner(value) {
|
|
138
|
+
return value !== null && Object(value) === value;
|
|
139
|
+
}
|
|
140
|
+
function isCallableValue(value) {
|
|
141
|
+
try {
|
|
142
|
+
Function.prototype.toString.call(value);
|
|
143
|
+
return true;
|
|
144
|
+
} catch {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
//#endregion
|
|
149
|
+
//#region src/types.ts
|
|
150
|
+
const NOTEBOOK_EXPORT_ERROR_BRAND = Symbol.for("@marimo-team/marimo-export.NotebookExportError.v1");
|
|
151
|
+
const NOTEBOOK_EXPORT_ERROR_CODE_SET = /* @__PURE__ */ new Set([
|
|
152
|
+
"abort",
|
|
153
|
+
"asset_invalid",
|
|
154
|
+
"decode_failed",
|
|
155
|
+
"integrity_failed",
|
|
156
|
+
"loader_ambiguous",
|
|
157
|
+
"loader_invalid",
|
|
158
|
+
"loader_unavailable",
|
|
159
|
+
"output_not_found",
|
|
160
|
+
"output_representation_changed",
|
|
161
|
+
"export_invalid",
|
|
162
|
+
"export_noncanonical",
|
|
163
|
+
"read_failed",
|
|
164
|
+
"read_limit_exceeded",
|
|
165
|
+
"state_input_invalid",
|
|
166
|
+
"state_not_found",
|
|
167
|
+
"state_unavailable"
|
|
168
|
+
]);
|
|
169
|
+
var NotebookExportError = class extends Error {
|
|
170
|
+
code;
|
|
171
|
+
details;
|
|
172
|
+
cause;
|
|
173
|
+
constructor(code, message, options = {}) {
|
|
174
|
+
if (!isStringValue(code) || !NOTEBOOK_EXPORT_ERROR_CODE_SET.has(code)) throw new TypeError("NotebookExportError code must be a known code.");
|
|
175
|
+
if (!isStringValue(message)) throw new TypeError("NotebookExportError message must be a string.");
|
|
176
|
+
super(message, options.cause === void 0 ? void 0 : { cause: options.cause });
|
|
177
|
+
Object.defineProperty(this, NOTEBOOK_EXPORT_ERROR_BRAND, { value: true });
|
|
178
|
+
this.name = "NotebookExportError";
|
|
179
|
+
this.code = code;
|
|
180
|
+
this.cause = options.cause;
|
|
181
|
+
this.details = options.details === void 0 ? void 0 : portableJsonObject(options.details);
|
|
182
|
+
Object.freeze(this);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
function isNotebookExportError(value) {
|
|
186
|
+
if (!isPropertyOwner(value)) return false;
|
|
187
|
+
try {
|
|
188
|
+
if (!(NOTEBOOK_EXPORT_ERROR_BRAND in value) || !("code" in value)) return false;
|
|
189
|
+
if (!("details" in value) || !("name" in value) || !("message" in value)) return false;
|
|
190
|
+
const code = value.code;
|
|
191
|
+
const details = value.details;
|
|
192
|
+
if (value[NOTEBOOK_EXPORT_ERROR_BRAND] !== true || value.name !== "NotebookExportError" || !isStringValue(value.message) || !isStringValue(code) || !NOTEBOOK_EXPORT_ERROR_CODE_SET.has(code)) return false;
|
|
193
|
+
if (details !== void 0) portableJsonObject(details, "NotebookExportError.details");
|
|
194
|
+
return true;
|
|
195
|
+
} catch {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
//#endregion
|
|
200
|
+
//#region src/media-type.ts
|
|
201
|
+
const TOKEN = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/u;
|
|
202
|
+
const PRINTABLE_ASCII = /^[\u0020-\u007e]+$/u;
|
|
203
|
+
const encoder = new TextEncoder();
|
|
204
|
+
function parseMediaType(raw) {
|
|
205
|
+
try {
|
|
206
|
+
if (encoder.encode(raw).byteLength > 1024 || !PRINTABLE_ASCII.test(raw) || raw !== raw.trim()) throw new TypeError("Media type must contain at most 1,024 printable ASCII bytes.");
|
|
207
|
+
return new MediaTypeParser(raw).parse();
|
|
208
|
+
} catch (error) {
|
|
209
|
+
if (isNotebookExportError(error)) throw error;
|
|
210
|
+
throw new NotebookExportError("export_invalid", "Export media type is invalid.", { cause: error });
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
var MediaTypeParser = class {
|
|
214
|
+
#raw;
|
|
215
|
+
#offset = 0;
|
|
216
|
+
constructor(raw) {
|
|
217
|
+
this.#raw = raw;
|
|
218
|
+
}
|
|
219
|
+
parse() {
|
|
220
|
+
const type = this.token().toLowerCase();
|
|
221
|
+
this.expect("/");
|
|
222
|
+
const subtype = this.token().toLowerCase();
|
|
223
|
+
const parameters = /* @__PURE__ */ new Map();
|
|
224
|
+
this.whitespace();
|
|
225
|
+
while (!this.done) {
|
|
226
|
+
this.expect(";");
|
|
227
|
+
this.whitespace();
|
|
228
|
+
const name = this.token().toLowerCase();
|
|
229
|
+
this.whitespace();
|
|
230
|
+
this.expect("=");
|
|
231
|
+
this.whitespace();
|
|
232
|
+
const value = this.peek() === "\"" ? this.quoted() : this.token();
|
|
233
|
+
if (parameters.has(name)) throw new TypeError("Media type parameter is repeated.");
|
|
234
|
+
parameters.set(name, value);
|
|
235
|
+
this.whitespace();
|
|
236
|
+
}
|
|
237
|
+
return Object.freeze({
|
|
238
|
+
raw: this.#raw,
|
|
239
|
+
essence: `${type}/${subtype}`,
|
|
240
|
+
type,
|
|
241
|
+
subtype,
|
|
242
|
+
parameters: new FrozenMap(parameters)
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
token() {
|
|
246
|
+
const start = this.#offset;
|
|
247
|
+
while (!this.done && TOKEN.test(this.#raw[this.#offset])) this.#offset += 1;
|
|
248
|
+
if (this.#offset === start) throw new TypeError("Media type token is missing.");
|
|
249
|
+
return this.#raw.slice(start, this.#offset);
|
|
250
|
+
}
|
|
251
|
+
quoted() {
|
|
252
|
+
this.expect("\"");
|
|
253
|
+
let result = "";
|
|
254
|
+
while (!this.done) {
|
|
255
|
+
const character = this.#raw[this.#offset++];
|
|
256
|
+
if (character === "\"") return result;
|
|
257
|
+
if (character === "\\") {
|
|
258
|
+
if (this.done) throw new TypeError("Media type quoted string is truncated.");
|
|
259
|
+
result += this.#raw[this.#offset++];
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
if (character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127) throw new TypeError("Media type quoted string contains a control character.");
|
|
263
|
+
result += character;
|
|
264
|
+
}
|
|
265
|
+
throw new TypeError("Media type quoted string is unterminated.");
|
|
266
|
+
}
|
|
267
|
+
whitespace() {
|
|
268
|
+
while (this.peek() === " " || this.peek() === " ") this.#offset += 1;
|
|
269
|
+
}
|
|
270
|
+
expect(value) {
|
|
271
|
+
if (this.#raw[this.#offset] !== value) throw new TypeError(`Expected ${value}.`);
|
|
272
|
+
this.#offset += 1;
|
|
273
|
+
}
|
|
274
|
+
peek() {
|
|
275
|
+
return this.#raw[this.#offset];
|
|
276
|
+
}
|
|
277
|
+
get done() {
|
|
278
|
+
return this.#offset >= this.#raw.length;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
var FrozenMap = class {
|
|
282
|
+
#map;
|
|
283
|
+
constructor(map) {
|
|
284
|
+
this.#map = map;
|
|
285
|
+
Object.freeze(this);
|
|
286
|
+
}
|
|
287
|
+
get size() {
|
|
288
|
+
return this.#map.size;
|
|
289
|
+
}
|
|
290
|
+
get(key) {
|
|
291
|
+
return this.#map.get(key);
|
|
292
|
+
}
|
|
293
|
+
has(key) {
|
|
294
|
+
return this.#map.has(key);
|
|
295
|
+
}
|
|
296
|
+
entries() {
|
|
297
|
+
return this.#map.entries();
|
|
298
|
+
}
|
|
299
|
+
keys() {
|
|
300
|
+
return this.#map.keys();
|
|
301
|
+
}
|
|
302
|
+
values() {
|
|
303
|
+
return this.#map.values();
|
|
304
|
+
}
|
|
305
|
+
forEach = (callbackfn, thisArg) => {
|
|
306
|
+
for (const [key, value] of this.#map) callbackfn.call(thisArg, value, key, this);
|
|
307
|
+
};
|
|
308
|
+
[Symbol.iterator]() {
|
|
309
|
+
return this.#map[Symbol.iterator]();
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
//#endregion
|
|
313
|
+
//#region src/loader.ts
|
|
314
|
+
const CODECS = /* @__PURE__ */ new Set([
|
|
315
|
+
"marimo.scalar.v1",
|
|
316
|
+
"marimo.json.v1",
|
|
317
|
+
"marimo.output.v1",
|
|
318
|
+
"marimo.cell.v1",
|
|
319
|
+
"numpy.npy.v1",
|
|
320
|
+
"apache.arrow.file.v1",
|
|
321
|
+
"marimo.blob-asset.msgpack.v1"
|
|
322
|
+
]);
|
|
323
|
+
function defineOutputLoader(loader) {
|
|
324
|
+
if (!isRecordValue(loader) || !CODECS.has(loader.codec) || !hasCallableMember(loader, "accepts") || !hasCallableMember(loader, "load")) throw new TypeError("OutputLoader must define a supported codec, accepts, and load.");
|
|
325
|
+
return Object.freeze(loader);
|
|
326
|
+
}
|
|
327
|
+
function defineBlobAssetLoader(definition) {
|
|
328
|
+
if (!isRecordValue(definition) || !hasCallableMember(definition, "load")) throw new TypeError("BlobAssetLoader must define mediaTypes and load.");
|
|
329
|
+
let accepts;
|
|
330
|
+
if (isMediaTypePredicate(definition.mediaTypes)) accepts = definition.mediaTypes;
|
|
331
|
+
else {
|
|
332
|
+
const values = isMediaTypeString(definition.mediaTypes) ? [definition.mediaTypes] : definition.mediaTypes;
|
|
333
|
+
if (!Array.isArray(values) || values.length === 0) throw new TypeError("BlobAssetLoader mediaTypes must not be empty.");
|
|
334
|
+
const essences = new Set(values.map((value) => parseMediaType(value).essence));
|
|
335
|
+
accepts = (mediaType) => essences.has(mediaType.essence);
|
|
336
|
+
}
|
|
337
|
+
return defineOutputLoader({
|
|
338
|
+
codec: "marimo.blob-asset.msgpack.v1",
|
|
339
|
+
accepts: (_descriptor, mediaType) => accepts(mediaType),
|
|
340
|
+
load: (input) => definition.load(input)
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
function resolveOutputLoader(output, loaders) {
|
|
344
|
+
if (!Array.isArray(loaders)) throw new TypeError("loaders must be an array.");
|
|
345
|
+
const matches = [];
|
|
346
|
+
for (const loader of loaders) {
|
|
347
|
+
if (!isRecordValue(loader) || loader.codec !== output.codec) continue;
|
|
348
|
+
if (!hasCallableMember(loader, "accepts") || !hasCallableMember(loader, "load")) throw invalidLoader(output, /* @__PURE__ */ new TypeError("Loader methods are missing."));
|
|
349
|
+
let accepted;
|
|
350
|
+
try {
|
|
351
|
+
accepted = loader.accepts(output.descriptor, output.mediaType);
|
|
352
|
+
} catch (error) {
|
|
353
|
+
throw invalidLoader(output, error);
|
|
354
|
+
}
|
|
355
|
+
if (!isBooleanValue(accepted)) throw invalidLoader(output, /* @__PURE__ */ new TypeError("Loader accepts must return a boolean."));
|
|
356
|
+
if (accepted) matches.push(loader);
|
|
357
|
+
}
|
|
358
|
+
if (matches.length === 0) throw new NotebookExportError("loader_unavailable", `No OutputLoader accepts ${output.codec} with ${output.mediaType.essence}.`, { details: {
|
|
359
|
+
output: output.name,
|
|
360
|
+
codec: output.codec,
|
|
361
|
+
mediaType: output.mediaType.raw
|
|
362
|
+
} });
|
|
363
|
+
if (matches.length > 1) throw new NotebookExportError("loader_ambiguous", `Multiple OutputLoaders accept ${output.codec} with ${output.mediaType.essence}.`, { details: {
|
|
364
|
+
output: output.name,
|
|
365
|
+
codec: output.codec,
|
|
366
|
+
mediaType: output.mediaType.raw,
|
|
367
|
+
matches: matches.length
|
|
368
|
+
} });
|
|
369
|
+
return matches[0];
|
|
370
|
+
}
|
|
371
|
+
function scalarLoader() {
|
|
372
|
+
return defineOutputLoader({
|
|
373
|
+
codec: "marimo.scalar.v1",
|
|
374
|
+
accepts: () => true,
|
|
375
|
+
load: ({ payload }) => payload
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
function imageLoader() {
|
|
379
|
+
return defineBlobAssetLoader({
|
|
380
|
+
mediaTypes: (mediaType) => mediaType.type === "image",
|
|
381
|
+
load: ({ payload }) => Object.freeze({ async mount(element, options = {}) {
|
|
382
|
+
options.signal?.throwIfAborted();
|
|
383
|
+
const blob = new Blob([payload.data.slice()], { type: payload.mediaType.raw });
|
|
384
|
+
const url = URL.createObjectURL(blob);
|
|
385
|
+
const image = document.createElement("img");
|
|
386
|
+
image.src = url;
|
|
387
|
+
image.alt = payload.filename ?? "";
|
|
388
|
+
image.decoding = "async";
|
|
389
|
+
let disposed = false;
|
|
390
|
+
const dispose = () => {
|
|
391
|
+
if (disposed) return;
|
|
392
|
+
disposed = true;
|
|
393
|
+
options.signal?.removeEventListener("abort", dispose);
|
|
394
|
+
image.remove();
|
|
395
|
+
URL.revokeObjectURL(url);
|
|
396
|
+
};
|
|
397
|
+
options.signal?.addEventListener("abort", dispose, { once: true });
|
|
398
|
+
if (options.signal?.aborted) {
|
|
399
|
+
dispose();
|
|
400
|
+
options.signal.throwIfAborted();
|
|
401
|
+
}
|
|
402
|
+
try {
|
|
403
|
+
element.append(image);
|
|
404
|
+
return Object.freeze({ dispose });
|
|
405
|
+
} catch (error) {
|
|
406
|
+
dispose();
|
|
407
|
+
throw error;
|
|
408
|
+
}
|
|
409
|
+
} })
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
function invalidLoader(output, cause) {
|
|
413
|
+
return new NotebookExportError("loader_invalid", "OutputLoader validation failed.", {
|
|
414
|
+
cause,
|
|
415
|
+
details: {
|
|
416
|
+
output: output.name,
|
|
417
|
+
codec: output.codec,
|
|
418
|
+
mediaType: output.mediaType.raw
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
function isMediaTypePredicate(value) {
|
|
423
|
+
return isCallableValue(value);
|
|
424
|
+
}
|
|
425
|
+
function isMediaTypeString(value) {
|
|
426
|
+
return isStringValue(value);
|
|
427
|
+
}
|
|
428
|
+
function hasCallableMember(value, name) {
|
|
429
|
+
let owner = value;
|
|
430
|
+
while (owner !== null) {
|
|
431
|
+
const descriptor = Object.getOwnPropertyDescriptor(owner, name);
|
|
432
|
+
if (descriptor !== void 0) {
|
|
433
|
+
if ("value" in descriptor) return isCallableValue(descriptor.value);
|
|
434
|
+
return isCallableValue(descriptor.get?.call(value));
|
|
435
|
+
}
|
|
436
|
+
owner = Object.getPrototypeOf(owner);
|
|
437
|
+
}
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
//#endregion
|
|
441
|
+
export { portableJsonValue as _, scalarLoader as a, isNotebookExportError as c, isJsonNumber as d, isJsonString as f, portableJsonObject as g, isStringValue as h, resolveOutputLoader as i, isCallableValue as l, isRecordValue as m, defineOutputLoader as n, parseMediaType as o, isPropertyOwner as p, imageLoader as r, NotebookExportError as s, defineBlobAssetLoader as t, isJsonBoolean as u, MAX_JSON_VALUES as v };
|