simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

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 }