create.js (7464B)
1 import _extends from "@babel/runtime/helpers/extends"; 2 import './../utils/polyfills.js'; 3 import { deepFlatten, isLegacyFactory, values } from '../utils/object.js'; 4 import * as emitter from './../utils/emitter.js'; 5 import { importFactory } from './function/import.js'; 6 import { configFactory } from './function/config.js'; 7 import { factory, isFactory } from '../utils/factory.js'; 8 import { isAccessorNode, isArray, isArrayNode, isAssignmentNode, isBigNumber, isBlockNode, isBoolean, isChain, isCollection, isComplex, isConditionalNode, isConstantNode, isDate, isDenseMatrix, isFraction, isFunction, isFunctionAssignmentNode, isFunctionNode, isHelp, isIndex, isIndexNode, isMatrix, isNode, isNull, isNumber, isObject, isObjectNode, isOperatorNode, isParenthesisNode, isRange, isRangeNode, isRegExp, isResultSet, isSparseMatrix, isString, isSymbolNode, isUndefined, isUnit } from '../utils/is.js'; 9 import { ArgumentsError } from '../error/ArgumentsError.js'; 10 import { DimensionError } from '../error/DimensionError.js'; 11 import { IndexError } from '../error/IndexError.js'; 12 import { DEFAULT_CONFIG } from './config.js'; 13 /** 14 * Create a mathjs instance from given factory functions and optionally config 15 * 16 * Usage: 17 * 18 * const mathjs1 = create({ createAdd, createMultiply, ...}) 19 * const config = { number: 'BigNumber' } 20 * const mathjs2 = create(all, config) 21 * 22 * @param {Object} [factories] An object with factory functions 23 * The object can contain nested objects, 24 * all nested objects will be flattened. 25 * @param {Object} [config] Available options: 26 * {number} epsilon 27 * Minimum relative difference between two 28 * compared values, used by all comparison functions. 29 * {string} matrix 30 * A string 'Matrix' (default) or 'Array'. 31 * {string} number 32 * A string 'number' (default), 'BigNumber', or 'Fraction' 33 * {number} precision 34 * The number of significant digits for BigNumbers. 35 * Not applicable for Numbers. 36 * {boolean} predictable 37 * Predictable output type of functions. When true, 38 * output type depends only on the input types. When 39 * false (default), output type can vary depending 40 * on input values. For example `math.sqrt(-4)` 41 * returns `complex('2i')` when predictable is false, and 42 * returns `NaN` when true. 43 * {string} randomSeed 44 * Random seed for seeded pseudo random number generator. 45 * Set to null to randomly seed. 46 * @returns {Object} Returns a bare-bone math.js instance containing 47 * functions: 48 * - `import` to add new functions 49 * - `config` to change configuration 50 * - `on`, `off`, `once`, `emit` for events 51 */ 52 53 export function create(factories, config) { 54 var configInternal = _extends({}, DEFAULT_CONFIG, config); // simple test for ES5 support 55 56 57 if (typeof Object.create !== 'function') { 58 throw new Error('ES5 not supported by this JavaScript engine. ' + 'Please load the es5-shim and es5-sham library for compatibility.'); 59 } // create the mathjs instance 60 61 62 var math = emitter.mixin({ 63 // only here for backward compatibility for legacy factory functions 64 isNumber, 65 isComplex, 66 isBigNumber, 67 isFraction, 68 isUnit, 69 isString, 70 isArray, 71 isMatrix, 72 isCollection, 73 isDenseMatrix, 74 isSparseMatrix, 75 isRange, 76 isIndex, 77 isBoolean, 78 isResultSet, 79 isHelp, 80 isFunction, 81 isDate, 82 isRegExp, 83 isObject, 84 isNull, 85 isUndefined, 86 isAccessorNode, 87 isArrayNode, 88 isAssignmentNode, 89 isBlockNode, 90 isConditionalNode, 91 isConstantNode, 92 isFunctionAssignmentNode, 93 isFunctionNode, 94 isIndexNode, 95 isNode, 96 isObjectNode, 97 isOperatorNode, 98 isParenthesisNode, 99 isRangeNode, 100 isSymbolNode, 101 isChain 102 }); // load config function and apply provided config 103 104 math.config = configFactory(configInternal, math.emit); 105 math.expression = { 106 transform: {}, 107 mathWithTransform: { 108 config: math.config 109 } 110 }; // cached factories and instances used by function load 111 112 var legacyFactories = []; 113 var legacyInstances = []; 114 /** 115 * Load a function or data type from a factory. 116 * If the function or data type already exists, the existing instance is 117 * returned. 118 * @param {Function} factory 119 * @returns {*} 120 */ 121 122 function load(factory) { 123 if (isFactory(factory)) { 124 return factory(math); 125 } 126 127 var firstProperty = factory[Object.keys(factory)[0]]; 128 129 if (isFactory(firstProperty)) { 130 return firstProperty(math); 131 } 132 133 if (!isLegacyFactory(factory)) { 134 console.warn('Factory object with properties `type`, `name`, and `factory` expected', factory); 135 throw new Error('Factory object with properties `type`, `name`, and `factory` expected'); 136 } 137 138 var index = legacyFactories.indexOf(factory); 139 var instance; 140 141 if (index === -1) { 142 // doesn't yet exist 143 if (factory.math === true) { 144 // pass with math namespace 145 instance = factory.factory(math.type, configInternal, load, math.typed, math); 146 } else { 147 instance = factory.factory(math.type, configInternal, load, math.typed); 148 } // append to the cache 149 150 151 legacyFactories.push(factory); 152 legacyInstances.push(instance); 153 } else { 154 // already existing function, return the cached instance 155 instance = legacyInstances[index]; 156 } 157 158 return instance; 159 } 160 161 var importedFactories = {}; // load the import function 162 163 function lazyTyped() { 164 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { 165 args[_key] = arguments[_key]; 166 } 167 168 return math.typed.apply(math.typed, args); 169 } 170 171 var internalImport = importFactory(lazyTyped, load, math, importedFactories); 172 math.import = internalImport; // listen for changes in config, import all functions again when changed 173 // TODO: move this listener into the import function? 174 175 math.on('config', () => { 176 values(importedFactories).forEach(factory => { 177 if (factory && factory.meta && factory.meta.recreateOnConfigChange) { 178 // FIXME: only re-create when the current instance is the same as was initially created 179 // FIXME: delete the functions/constants before importing them again? 180 internalImport(factory, { 181 override: true 182 }); 183 } 184 }); 185 }); // the create function exposed on the mathjs instance is bound to 186 // the factory functions passed before 187 188 math.create = create.bind(null, factories); // export factory function 189 190 math.factory = factory; // import the factory functions like createAdd as an array instead of object, 191 // else they will get a different naming (`createAdd` instead of `add`). 192 193 math.import(values(deepFlatten(factories))); 194 math.ArgumentsError = ArgumentsError; 195 math.DimensionError = DimensionError; 196 math.IndexError = IndexError; 197 return math; 198 }