UNPKG

@deck.gl/json

Version:

JSON format rendering components for deck.gl

615 lines (599 loc) 17.7 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // dist/index.js var dist_exports = {}; __export(dist_exports, { JSONConfiguration: () => JSONConfiguration, JSONConverter: () => JSONConverter, Transport: () => Transport, _convertFunctions: () => convertFunctions, _parseExpressionString: () => parseExpressionString, _shallowEqualObjects: () => shallowEqualObjects }); module.exports = __toCommonJS(dist_exports); // dist/utils/assert.js function assert(condition, message = "") { if (!condition) { throw new Error(`JSON conversion error ${message}`); } } // dist/utils/get.js function get(container, compositeKey) { const keyList = getKeys(compositeKey); let value = container; for (const key of keyList) { value = isObject(value) ? value[key] : void 0; } return value; } function isObject(value) { return value !== null && typeof value === "object"; } var keyMap = {}; function getKeys(compositeKey) { if (typeof compositeKey === "string") { let keyList = keyMap[compositeKey]; if (!keyList) { keyList = compositeKey.split("."); keyMap[compositeKey] = keyList; } return keyList; } return Array.isArray(compositeKey) ? compositeKey : [compositeKey]; } // dist/utils/expression-eval.js var import_jsep = __toESM(require("jsep"), 1); var binops = { "||": (a, b) => { return a || b; }, "&&": (a, b) => { return a && b; }, "|": (a, b) => { return a | b; }, "^": (a, b) => { return a ^ b; }, "&": (a, b) => { return a & b; }, "==": (a, b) => { return a == b; }, "!=": (a, b) => { return a != b; }, "===": (a, b) => { return a === b; }, "!==": (a, b) => { return a !== b; }, "<": (a, b) => { return a < b; }, ">": (a, b) => { return a > b; }, "<=": (a, b) => { return a <= b; }, ">=": (a, b) => { return a >= b; }, "<<": (a, b) => { return a << b; }, ">>": (a, b) => { return a >> b; }, ">>>": (a, b) => { return a >>> b; }, "+": (a, b) => { return a + b; }, "-": (a, b) => { return a - b; }, "*": (a, b) => { return a * b; }, "/": (a, b) => { return a / b; }, "%": (a, b) => { return a % b; } }; var unops = { "-": (a) => { return -a; }, "+": (a) => { return +a; }, "~": (a) => { return ~a; }, "!": (a) => { return !a; } }; function evaluateArray(list, context) { return list.map(function(v) { return evaluate(v, context); }); } function evaluateMember(node, context) { const object = evaluate(node.object, context); let key; if (node.computed) { key = evaluate(node.property, context); } else { key = node.property.name; } if (/^__proto__|prototype|constructor$/.test(key)) { throw Error(`Access to member "${key}" disallowed.`); } return [object, object[key]]; } function evaluate(_node, context) { const node = _node; switch (node.type) { case "ArrayExpression": return evaluateArray(node.elements, context); case "BinaryExpression": return binops[node.operator](evaluate(node.left, context), evaluate(node.right, context)); case "CallExpression": let caller; let fn; let assign; if (node.callee.type === "MemberExpression") { assign = evaluateMember(node.callee, context); caller = assign[0]; fn = assign[1]; } else { fn = evaluate(node.callee, context); } if (typeof fn !== "function") { return void 0; } return fn.apply(caller, evaluateArray(node.arguments, context)); case "ConditionalExpression": return evaluate(node.test, context) ? evaluate(node.consequent, context) : evaluate(node.alternate, context); case "Identifier": return context[node.name]; case "Literal": return node.value; case "LogicalExpression": if (node.operator === "||") { return evaluate(node.left, context) || evaluate(node.right, context); } else if (node.operator === "&&") { return evaluate(node.left, context) && evaluate(node.right, context); } return binops[node.operator](evaluate(node.left, context), evaluate(node.right, context)); case "MemberExpression": return evaluateMember(node, context)[1]; case "ThisExpression": return context; case "UnaryExpression": return unops[node.operator](evaluate(node.argument, context)); default: return void 0; } } // dist/helpers/parse-expression-string.js var cachedExpressionMap = { "-": (object) => object }; function parseExpressionString(propValue, configuration) { if (propValue in cachedExpressionMap) { return cachedExpressionMap[propValue]; } let func; const ast = (0, import_jsep.default)(propValue); if (ast.type === "Identifier") { func = (row) => { return get(row, propValue); }; } else { traverse(ast, (node) => { if (node.type === "CallExpression") { throw new Error("Function calls not allowed in JSON expressions"); } }); func = (row) => { return evaluate(ast, row); }; } cachedExpressionMap[propValue] = func; return func; } function traverse(node, visitor) { if (Array.isArray(node)) { node.forEach((element) => traverse(element, visitor)); } else if (node && typeof node === "object") { if (node.type) { visitor(node); } for (const key in node) { traverse(node[key], visitor); } } } // dist/syntactic-sugar.js var FUNCTION_IDENTIFIER = "@@="; var CONSTANT_IDENTIFIER = "@@#"; var TYPE_KEY = "@@type"; var FUNCTION_KEY = "@@function"; // dist/json-configuration.js var isObject2 = (value) => value && typeof value === "object"; var JSONConfiguration = class { constructor(...configurations) { this.typeKey = TYPE_KEY; this.functionKey = FUNCTION_KEY; this.log = console; this.classes = {}; this.reactComponents = {}; this.enumerations = {}; this.constants = {}; this.functions = {}; this.React = null; this.convertFunction = parseExpressionString; this.preProcessClassProps = (Class, props) => props; this.postProcessConvertedJson = (json) => json; for (const configuration of configurations) { this.merge(configuration); } } merge(configuration) { for (const key in configuration) { switch (key) { case "layers": case "views": Object.assign(this.classes, configuration[key]); break; default: if (key in this) { const value = configuration[key]; this[key] = isObject2(this[key]) ? Object.assign(this[key], value) : value; } } } } validate(configuration) { assert(!this.typeKey || typeof this.typeKey === "string"); assert(isObject2(this.classes)); return true; } }; // dist/helpers/convert-functions.js function hasFunctionIdentifier(value) { return typeof value === "string" && value.startsWith(FUNCTION_IDENTIFIER); } function trimFunctionIdentifier(value) { return value.replace(FUNCTION_IDENTIFIER, ""); } function convertFunctions(props, configuration) { const replacedProps = {}; for (const propName in props) { let propValue = props[propName]; const isFunction = hasFunctionIdentifier(propValue); if (isFunction) { propValue = trimFunctionIdentifier(propValue); propValue = parseExpressionString(propValue, configuration); } replacedProps[propName] = propValue; } return replacedProps; } // dist/helpers/instantiate-class.js function instantiateClass(type, props, configuration) { const Class = configuration.classes[type]; const Component = configuration.reactComponents[type]; if (!Class && !Component) { const { log } = configuration; if (log) { const stringProps = JSON.stringify(props, null, 0).slice(0, 40); log.warn(`JSON converter: No registered class of type ${type}(${stringProps}...) `); } return null; } if (Class) { return instantiateJavaScriptClass(Class, props, configuration); } return instantiateReactComponent(Component, props, configuration); } function instantiateJavaScriptClass(Class, props, configuration) { if (configuration.preProcessClassProps) { props = configuration.preProcessClassProps(Class, props, configuration); } props = convertFunctions(props, configuration); return new Class(props); } function instantiateReactComponent(Component, props, configuration) { const { React } = configuration; const { children = [] } = props; delete props.children; if (configuration.preProcessClassProps) { props = configuration.preProcessClassProps(Component, props, configuration); } props = convertFunctions(props, configuration); return React.createElement(Component, props, children); } // dist/helpers/execute-function.js function executeFunction(targetFunction, props, configuration) { const matchedFunction = configuration.functions[targetFunction]; if (!matchedFunction) { const { log } = configuration; if (log) { const stringProps = JSON.stringify(props, null, 0).slice(0, 40); log.warn(`JSON converter: No registered function ${targetFunction}(${stringProps}...) `); } return null; } return matchedFunction(props); } // dist/helpers/parse-json.js function parseJSON(json) { return typeof json === "string" ? JSON.parse(json) : json; } // dist/json-converter.js var isObject3 = (value) => value && typeof value === "object"; var JSONConverter = class { constructor(props) { this.log = console; this.onJSONChange = () => { }; this.json = null; this.convertedJson = null; this.setProps(props); } // eslint-disable-next-line @typescript-eslint/no-empty-function finalize() { } setProps(props) { if ("configuration" in props) { this.configuration = props.configuration instanceof JSONConfiguration ? props.configuration : new JSONConfiguration(props.configuration); } if ("onJSONChange" in props) { this.onJSONChange = props.onJSONChange; } } mergeConfiguration(config) { this.configuration.merge(config); } convert(json) { if (!json || json === this.json) { return this.convertedJson; } this.json = json; const parsedJSON = parseJSON(json); let convertedJson = convertJSON(parsedJSON, this.configuration); convertedJson = this.configuration.postProcessConvertedJson(convertedJson); this.convertedJson = convertedJson; return convertedJson; } // DEPRECATED: Backwards compatibility convertJson(json) { return this.convert(json); } }; function convertJSON(json, configuration) { configuration = new JSONConfiguration(configuration); return convertJSONRecursively(json, "", configuration); } function convertJSONRecursively(json, key, configuration) { if (Array.isArray(json)) { return json.map((element, i) => convertJSONRecursively(element, String(i), configuration)); } if (isClassInstance(json, configuration)) { return convertClassInstance(json, configuration); } if (isObject3(json)) { if (FUNCTION_KEY in json) { return convertFunctionObject(json, configuration); } return convertPlainObject(json, configuration); } if (typeof json === "string") { return convertString(json, key, configuration); } return json; } function isClassInstance(json, configuration) { const { typeKey } = configuration; const isClass = isObject3(json) && Boolean(json[typeKey]); return isClass; } function convertClassInstance(json, configuration) { const { typeKey } = configuration; const type = json[typeKey]; let props = { ...json }; delete props[typeKey]; props = convertPlainObject(props, configuration); return instantiateClass(type, props, configuration); } function convertFunctionObject(json, configuration) { const { functionKey } = configuration; const targetFunction = json[functionKey]; let props = { ...json }; delete props[functionKey]; props = convertPlainObject(props, configuration); return executeFunction(targetFunction, props, configuration); } function convertPlainObject(json, configuration) { assert(isObject3(json)); const result = {}; for (const key in json) { const value = json[key]; result[key] = convertJSONRecursively(value, key, configuration); } return result; } function convertString(string, key, configuration) { if (string.startsWith(FUNCTION_IDENTIFIER) && configuration.convertFunction) { string = string.replace(FUNCTION_IDENTIFIER, ""); return configuration.convertFunction(string, configuration); } if (string.startsWith(CONSTANT_IDENTIFIER)) { string = string.replace(CONSTANT_IDENTIFIER, ""); if (configuration.constants[string]) { return configuration.constants[string]; } const [enumVarName, enumValName] = string.split("."); return configuration.enumerations[enumVarName][enumValName]; } return string; } // dist/transports/transport.js var state = { onInitialize: (_) => _, onFinalize: (_) => _, onMessage: (_) => _ }; var Transport = class { static setCallbacks({ onInitialize, onFinalize, onMessage }) { if (onInitialize) { state.onInitialize = onInitialize; } if (onFinalize) { state.onFinalize = onFinalize; } if (onMessage) { state.onMessage = onMessage; } } constructor(name = "Transport") { this._messageQueue = []; this.userData = {}; this._destroyed = false; this.name = name; } /** * Return a root DOM element for this transport connection * @return {HTMLElement} default implementation returns document.body * Jupyter Notebook transports will return an element associated with the notebook cell */ getRootDOMElement() { return typeof document !== "undefined" ? document.body : null; } /** * Back-channel messaging */ sendJSONMessage() { console.error("Back-channel not implemented for this transport"); } /** * Back-channel messaging */ sendBinaryMessage() { console.error("Back-channel not implemented for this transport"); } // // API for transports (not intended for apps) // _initialize(options = {}) { const message = { transport: this, ...options }; state.onInitialize(message); } _finalize(options = {}) { const message = { transport: this, ...options }; state.onFinalize(message); this._destroyed = true; } _messageReceived(message = {}) { message = { transport: this, ...message }; console.debug("Delivering transport message", message); state.onMessage(message); } /* // This tries to handle the case that a transport connection initializes before the application // has set the callbacks. // Note: It is not clear that this can actually happen in the in initial Jupyter widget transport _flushQueuedConnections() { if (onInitialize) { state._initPromise.then(initArgs => { onInitialize(initArgs); if (state._onMessage) { // Send any queued messages let message; while ((message = this._messageQueue.pop())) { console.debug('Delivering queued transport message', message); // eslint-disable-line this._onMessage(message); } } }); } } */ static _stringifyJSONSafe(v) { const cache = /* @__PURE__ */ new Set(); return JSON.stringify(v, (key, value) => { if (typeof value === "object" && value !== null) { if (cache.has(value)) { try { return JSON.parse(JSON.stringify(value)); } catch (err) { return void 0; } } cache.add(value); } return value; }); } }; // dist/utils/shallow-equal-objects.js function shallowEqualObjects(a, b) { if (a === b) { return true; } if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) { return false; } if (Object.keys(a).length !== Object.keys(b).length) { return false; } for (const key in a) { if (!(key in b) || a[key] !== b[key]) { return false; } } for (const key in b) { if (!(key in a)) { return false; } } return true; } //# sourceMappingURL=index.cjs.map