1 | import { clone, mapObject, deepExtend } from '../../utils/object'
|
2 | import { DEFAULT_CONFIG } from '../config'
|
3 |
|
4 | export const MATRIX_OPTIONS = ['Matrix', 'Array'] // valid values for option matrix
|
5 | export const NUMBER_OPTIONS = ['number', 'BigNumber', 'Fraction'] // valid values for option number
|
6 |
|
7 | export function configFactory (config, emit) {
|
8 | /**
|
9 | * Set configuration options for math.js, and get current options.
|
10 | * Will emit a 'config' event, with arguments (curr, prev, changes).
|
11 | *
|
12 | * This function is only available on a mathjs instance created using `create`.
|
13 | *
|
14 | * Syntax:
|
15 | *
|
16 | * math.config(config: Object): Object
|
17 | *
|
18 | * Examples:
|
19 | *
|
20 | *
|
21 | * import { create, all } from 'mathjs'
|
22 | *
|
23 | * // create a mathjs instance
|
24 | * const math = create(all)
|
25 | *
|
26 | * math.config().number // outputs 'number'
|
27 | * math.evaluate('0.4') // outputs number 0.4
|
28 | * math.config({number: 'Fraction'})
|
29 | * math.evaluate('0.4') // outputs Fraction 2/5
|
30 | *
|
31 | * @param {Object} [options] Available options:
|
32 | * {number} epsilon
|
33 | * Minimum relative difference between two
|
34 | * compared values, used by all comparison functions.
|
35 | * {string} matrix
|
36 | * A string 'Matrix' (default) or 'Array'.
|
37 | * {string} number
|
38 | * A string 'number' (default), 'BigNumber', or 'Fraction'
|
39 | * {number} precision
|
40 | * The number of significant digits for BigNumbers.
|
41 | * Not applicable for Numbers.
|
42 | * {string} parenthesis
|
43 | * How to display parentheses in LaTeX and string
|
44 | * output.
|
45 | * {string} randomSeed
|
46 | * Random seed for seeded pseudo random number generator.
|
47 | * Set to null to randomly seed.
|
48 | * @return {Object} Returns the current configuration
|
49 | */
|
50 | function _config (options) {
|
51 | if (options) {
|
52 | const prev = mapObject(config, clone)
|
53 |
|
54 | // validate some of the options
|
55 | validateOption(options, 'matrix', MATRIX_OPTIONS)
|
56 | validateOption(options, 'number', NUMBER_OPTIONS)
|
57 |
|
58 | // merge options
|
59 | deepExtend(config, options)
|
60 |
|
61 | const curr = mapObject(config, clone)
|
62 |
|
63 | const changes = mapObject(options, clone)
|
64 |
|
65 | // emit 'config' event
|
66 | emit('config', curr, prev, changes)
|
67 |
|
68 | return curr
|
69 | } else {
|
70 | return mapObject(config, clone)
|
71 | }
|
72 | }
|
73 |
|
74 | // attach the valid options to the function so they can be extended
|
75 | _config.MATRIX_OPTIONS = MATRIX_OPTIONS
|
76 | _config.NUMBER_OPTIONS = NUMBER_OPTIONS
|
77 |
|
78 | // attach the config properties as readonly properties to the config function
|
79 | Object.keys(DEFAULT_CONFIG).forEach(key => {
|
80 | Object.defineProperty(_config, key, {
|
81 | get: () => config[key],
|
82 | enumerable: true,
|
83 | configurable: true
|
84 | })
|
85 | })
|
86 |
|
87 | return _config
|
88 | }
|
89 |
|
90 | /**
|
91 | * Test whether an Array contains a specific item.
|
92 | * @param {Array.<string>} array
|
93 | * @param {string} item
|
94 | * @return {boolean}
|
95 | */
|
96 | function contains (array, item) {
|
97 | return array.indexOf(item) !== -1
|
98 | }
|
99 |
|
100 | /**
|
101 | * Find a string in an array. Case insensitive search
|
102 | * @param {Array.<string>} array
|
103 | * @param {string} item
|
104 | * @return {number} Returns the index when found. Returns -1 when not found
|
105 | */
|
106 | function findIndex (array, item) {
|
107 | return array
|
108 | .map(function (i) {
|
109 | return i.toLowerCase()
|
110 | })
|
111 | .indexOf(item.toLowerCase())
|
112 | }
|
113 |
|
114 | /**
|
115 | * Validate an option
|
116 | * @param {Object} options Object with options
|
117 | * @param {string} name Name of the option to validate
|
118 | * @param {Array.<string>} values Array with valid values for this option
|
119 | */
|
120 | function validateOption (options, name, values) {
|
121 | if (options[name] !== undefined && !contains(values, options[name])) {
|
122 | const index = findIndex(values, options[name])
|
123 | if (index !== -1) {
|
124 | // right value, wrong casing
|
125 | // TODO: lower case values are deprecated since v3, remove this warning some day.
|
126 | console.warn('Warning: Wrong casing for configuration option "' + name + '", should be "' + values[index] + '" instead of "' + options[name] + '".')
|
127 |
|
128 | options[name] = values[index] // change the option to the right casing
|
129 | } else {
|
130 | // unknown value
|
131 | console.warn('Warning: Unknown value "' + options[name] + '" for configuration option "' + name + '". Available options: ' + values.map(JSON.stringify).join(', ') + '.')
|
132 | }
|
133 | }
|
134 | }
|