@bokeh/bokehjs
Version:
Interactive, novel data visualization
106 lines • 3.51 kB
JavaScript
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