UNPKG

@bokeh/bokehjs

Version:

Interactive, novel data visualization

106 lines 3.51 kB
import { Callback } from "./callback"; import { entries, to_object } from "../../core/util/object"; import { unzip } from "../../core/util/array"; import { use_strict } from "../../core/util/string"; import { logger } from "../../core/logging"; import { isFunction } from "../../core/util/types"; import { index } from "../../embed/standalone"; export class CustomJS extends Callback { static __name__ = "CustomJS"; constructor(attrs) { super(attrs); } static { this.define(({ Unknown, Str, Dict, Auto, Or, Bool }) => ({ args: [Dict(Unknown), {}], code: [Str], module: [Or(Auto, Bool), "auto"], })); } connect_signals() { super.connect_signals(); const { args, code, module } = this.properties; this.on_change([args, code, module], () => this._state = null); } async _compile_module() { const url = URL.createObjectURL(new Blob([this.code], { type: "text/javascript" })); try { // XXX: eval() to work around transpilation to require() // https://github.com/microsoft/TypeScript/issues/43329 const module = await eval(`import("${url}")`); if (isFunction(module.default)) { return module.default; } else { logger.warn("custom ES module didn't export a default function"); return () => undefined; } } finally { URL.revokeObjectURL(url); } } async _compile_function() { const [names = [], values = []] = unzip(entries(this.args)); const code = use_strict(this.code); const func = new Function(...names, "cb_obj", "cb_data", "cb_context", code); return function (...args) { return func.call(this, ...values, ...args); }; } _is_es_module(code) { return code.split("\n").some((line) => line.trimStart().startsWith("export default")); } async _compile() { const module = (() => { if (this.module == "auto") { return this._is_es_module(this.code); } else { return this.module; } })(); if (module) { return { func: await this._compile_module(), module }; } else { return { func: await this._compile_function(), module }; } } async compile() { if (this._state == null) { this._state = await this._compile(); } } _state = null; async state() { if (this._state == null) { this._state = await this._compile(); } return this._state; } async execute(obj, data = {}) { const { func, module } = await this.state(); const context = { index }; if (module) { return func(to_object(this.args), obj, data, context); } else { return func.call(obj, obj, data, context); } } execute_sync(obj, data = {}) { if (this._state == null) { throw new Error(`${this.type} needs to be compiled first`); } const { func, module } = this._state; const context = { index }; if (module) { return func(to_object(this.args), obj, data, context); } else { return func.call(obj, obj, data, context); } } } //# sourceMappingURL=customjs.js.map