1 | function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
2 |
|
3 | import { isAccessorNode, isFunctionAssignmentNode, isIndexNode, isNode, isSymbolNode } from '../../utils/is.js';
|
4 | import { escape } from '../../utils/string.js';
|
5 | import { hasOwnProperty } from '../../utils/object.js';
|
6 | import { map } from '../../utils/array.js';
|
7 | import { getSafeProperty, validateSafeMethod } from '../../utils/customs.js';
|
8 | import { factory } from '../../utils/factory.js';
|
9 | import { defaultTemplate, latexFunctions } from '../../utils/latex.js';
|
10 | var name = 'FunctionNode';
|
11 | var dependencies = ['math', 'Node', 'SymbolNode'];
|
12 | export var createFunctionNode = factory(name, dependencies, (_ref) => {
|
13 | var {
|
14 | math,
|
15 | Node,
|
16 | SymbolNode
|
17 | } = _ref;
|
18 |
|
19 | |
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | function FunctionNode(fn, args) {
|
28 | if (!(this instanceof FunctionNode)) {
|
29 | throw new SyntaxError('Constructor must be called with the new operator');
|
30 | }
|
31 |
|
32 | if (typeof fn === 'string') {
|
33 | fn = new SymbolNode(fn);
|
34 | }
|
35 |
|
36 |
|
37 | if (!isNode(fn)) throw new TypeError('Node expected as parameter "fn"');
|
38 |
|
39 | if (!Array.isArray(args) || !args.every(isNode)) {
|
40 | throw new TypeError('Array containing Nodes expected for parameter "args"');
|
41 | }
|
42 |
|
43 | this.fn = fn;
|
44 | this.args = args || [];
|
45 |
|
46 | Object.defineProperty(this, 'name', {
|
47 | get: function () {
|
48 | return this.fn.name || '';
|
49 | }.bind(this),
|
50 | set: function set() {
|
51 | throw new Error('Cannot assign a new name, name is read-only');
|
52 | }
|
53 | });
|
54 | }
|
55 |
|
56 | FunctionNode.prototype = new Node();
|
57 | FunctionNode.prototype.type = 'FunctionNode';
|
58 | FunctionNode.prototype.isFunctionNode = true;
|
59 | |
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 | FunctionNode.prototype._compile = function (math, argNames) {
|
74 | if (!(this instanceof FunctionNode)) {
|
75 | throw new TypeError('No valid FunctionNode');
|
76 | }
|
77 |
|
78 |
|
79 | var evalArgs = map(this.args, function (arg) {
|
80 | return arg._compile(math, argNames);
|
81 | });
|
82 |
|
83 | if (isSymbolNode(this.fn)) {
|
84 |
|
85 | var _name = this.fn.name;
|
86 | var fn = _name in math ? getSafeProperty(math, _name) : undefined;
|
87 | var isRaw = typeof fn === 'function' && fn.rawArgs === true;
|
88 |
|
89 | if (isRaw) {
|
90 |
|
91 |
|
92 | var rawArgs = this.args;
|
93 | return function evalFunctionNode(scope, args, context) {
|
94 | return (_name in scope ? getSafeProperty(scope, _name) : fn)(rawArgs, math, _extends({}, scope, args));
|
95 | };
|
96 | } else {
|
97 |
|
98 | if (evalArgs.length === 1) {
|
99 | var evalArg0 = evalArgs[0];
|
100 | return function evalFunctionNode(scope, args, context) {
|
101 | return (_name in scope ? getSafeProperty(scope, _name) : fn)(evalArg0(scope, args, context));
|
102 | };
|
103 | } else if (evalArgs.length === 2) {
|
104 | var _evalArg = evalArgs[0];
|
105 | var evalArg1 = evalArgs[1];
|
106 | return function evalFunctionNode(scope, args, context) {
|
107 | return (_name in scope ? getSafeProperty(scope, _name) : fn)(_evalArg(scope, args, context), evalArg1(scope, args, context));
|
108 | };
|
109 | } else {
|
110 | return function evalFunctionNode(scope, args, context) {
|
111 | return (_name in scope ? getSafeProperty(scope, _name) : fn).apply(null, map(evalArgs, function (evalArg) {
|
112 | return evalArg(scope, args, context);
|
113 | }));
|
114 | };
|
115 | }
|
116 | }
|
117 | } else if (isAccessorNode(this.fn) && isIndexNode(this.fn.index) && this.fn.index.isObjectProperty()) {
|
118 |
|
119 | var evalObject = this.fn.object._compile(math, argNames);
|
120 |
|
121 | var prop = this.fn.index.getObjectProperty();
|
122 | var _rawArgs = this.args;
|
123 | return function evalFunctionNode(scope, args, context) {
|
124 | var object = evalObject(scope, args, context);
|
125 | validateSafeMethod(object, prop);
|
126 | var isRaw = object[prop] && object[prop].rawArgs;
|
127 | return isRaw ? object[prop](_rawArgs, math, _extends({}, scope, args))
|
128 | : object[prop].apply(object, map(evalArgs, function (evalArg) {
|
129 |
|
130 | return evalArg(scope, args, context);
|
131 | }));
|
132 | };
|
133 | } else {
|
134 |
|
135 |
|
136 | var evalFn = this.fn._compile(math, argNames);
|
137 |
|
138 | var _rawArgs2 = this.args;
|
139 | return function evalFunctionNode(scope, args, context) {
|
140 | var fn = evalFn(scope, args, context);
|
141 | var isRaw = fn && fn.rawArgs;
|
142 | return isRaw ? fn(_rawArgs2, math, _extends({}, scope, args))
|
143 | : fn.apply(fn, map(evalArgs, function (evalArg) {
|
144 |
|
145 | return evalArg(scope, args, context);
|
146 | }));
|
147 | };
|
148 | }
|
149 | };
|
150 | |
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 | FunctionNode.prototype.forEach = function (callback) {
|
157 | callback(this.fn, 'fn', this);
|
158 |
|
159 | for (var i = 0; i < this.args.length; i++) {
|
160 | callback(this.args[i], 'args[' + i + ']', this);
|
161 | }
|
162 | };
|
163 | |
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 |
|
171 | FunctionNode.prototype.map = function (callback) {
|
172 | var fn = this._ifNode(callback(this.fn, 'fn', this));
|
173 |
|
174 | var args = [];
|
175 |
|
176 | for (var i = 0; i < this.args.length; i++) {
|
177 | args[i] = this._ifNode(callback(this.args[i], 'args[' + i + ']', this));
|
178 | }
|
179 |
|
180 | return new FunctionNode(fn, args);
|
181 | };
|
182 | |
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 | FunctionNode.prototype.clone = function () {
|
189 | return new FunctionNode(this.fn, this.args.slice(0));
|
190 | };
|
191 |
|
192 |
|
193 |
|
194 | var nodeToString = FunctionNode.prototype.toString;
|
195 | |
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 | FunctionNode.prototype.toString = function (options) {
|
209 | var customString;
|
210 | var name = this.fn.toString(options);
|
211 |
|
212 | if (options && typeof options.handler === 'object' && hasOwnProperty(options.handler, name)) {
|
213 |
|
214 | customString = options.handler[name](this, options);
|
215 | }
|
216 |
|
217 | if (typeof customString !== 'undefined') {
|
218 | return customString;
|
219 | }
|
220 |
|
221 |
|
222 | return nodeToString.call(this, options);
|
223 | };
|
224 | |
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 |
|
231 | FunctionNode.prototype._toString = function (options) {
|
232 | var args = this.args.map(function (arg) {
|
233 | return arg.toString(options);
|
234 | });
|
235 | var fn = isFunctionAssignmentNode(this.fn) ? '(' + this.fn.toString(options) + ')' : this.fn.toString(options);
|
236 |
|
237 | return fn + '(' + args.join(', ') + ')';
|
238 | };
|
239 | |
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 | FunctionNode.prototype.toJSON = function () {
|
246 | return {
|
247 | mathjs: 'FunctionNode',
|
248 | fn: this.fn,
|
249 | args: this.args
|
250 | };
|
251 | };
|
252 | |
253 |
|
254 |
|
255 |
|
256 |
|
257 |
|
258 |
|
259 |
|
260 |
|
261 | FunctionNode.fromJSON = function (json) {
|
262 | return new FunctionNode(json.fn, json.args);
|
263 | };
|
264 | |
265 |
|
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 | FunctionNode.prototype.toHTML = function (options) {
|
272 | var args = this.args.map(function (arg) {
|
273 | return arg.toHTML(options);
|
274 | });
|
275 |
|
276 | return '<span class="math-function">' + escape(this.fn) + '</span><span class="math-paranthesis math-round-parenthesis">(</span>' + args.join('<span class="math-separator">,</span>') + '<span class="math-paranthesis math-round-parenthesis">)</span>';
|
277 | };
|
278 | |
279 |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 |
|
287 |
|
288 | function expandTemplate(template, node, options) {
|
289 | var latex = '';
|
290 |
|
291 |
|
292 | var regex = /\$(?:\{([a-z_][a-z_0-9]*)(?:\[([0-9]+)\])?\}|\$)/gi;
|
293 | var inputPos = 0;
|
294 |
|
295 | var match;
|
296 |
|
297 | while ((match = regex.exec(template)) !== null) {
|
298 |
|
299 |
|
300 | latex += template.substring(inputPos, match.index);
|
301 | inputPos = match.index;
|
302 |
|
303 | if (match[0] === '$$') {
|
304 |
|
305 | latex += '$';
|
306 | inputPos++;
|
307 | } else {
|
308 |
|
309 | inputPos += match[0].length;
|
310 | var property = node[match[1]];
|
311 |
|
312 | if (!property) {
|
313 | throw new ReferenceError('Template: Property ' + match[1] + ' does not exist.');
|
314 | }
|
315 |
|
316 | if (match[2] === undefined) {
|
317 |
|
318 | switch (typeof property) {
|
319 | case 'string':
|
320 | latex += property;
|
321 | break;
|
322 |
|
323 | case 'object':
|
324 | if (isNode(property)) {
|
325 | latex += property.toTex(options);
|
326 | } else if (Array.isArray(property)) {
|
327 |
|
328 | latex += property.map(function (arg, index) {
|
329 | if (isNode(arg)) {
|
330 | return arg.toTex(options);
|
331 | }
|
332 |
|
333 | throw new TypeError('Template: ' + match[1] + '[' + index + '] is not a Node.');
|
334 | }).join(',');
|
335 | } else {
|
336 | throw new TypeError('Template: ' + match[1] + ' has to be a Node, String or array of Nodes');
|
337 | }
|
338 |
|
339 | break;
|
340 |
|
341 | default:
|
342 | throw new TypeError('Template: ' + match[1] + ' has to be a Node, String or array of Nodes');
|
343 | }
|
344 | } else {
|
345 |
|
346 | if (isNode(property[match[2]] && property[match[2]])) {
|
347 | latex += property[match[2]].toTex(options);
|
348 | } else {
|
349 | throw new TypeError('Template: ' + match[1] + '[' + match[2] + '] is not a Node.');
|
350 | }
|
351 | }
|
352 | }
|
353 | }
|
354 |
|
355 | latex += template.slice(inputPos);
|
356 |
|
357 | return latex;
|
358 | }
|
359 |
|
360 |
|
361 |
|
362 | var nodeToTex = FunctionNode.prototype.toTex;
|
363 | |
364 |
|
365 |
|
366 |
|
367 |
|
368 |
|
369 |
|
370 |
|
371 |
|
372 |
|
373 |
|
374 |
|
375 | FunctionNode.prototype.toTex = function (options) {
|
376 | var customTex;
|
377 |
|
378 | if (options && typeof options.handler === 'object' && hasOwnProperty(options.handler, this.name)) {
|
379 |
|
380 | customTex = options.handler[this.name](this, options);
|
381 | }
|
382 |
|
383 | if (typeof customTex !== 'undefined') {
|
384 | return customTex;
|
385 | }
|
386 |
|
387 |
|
388 | return nodeToTex.call(this, options);
|
389 | };
|
390 | |
391 |
|
392 |
|
393 |
|
394 |
|
395 |
|
396 |
|
397 | FunctionNode.prototype._toTex = function (options) {
|
398 | var args = this.args.map(function (arg) {
|
399 |
|
400 | return arg.toTex(options);
|
401 | });
|
402 | var latexConverter;
|
403 |
|
404 | if (latexFunctions[this.name]) {
|
405 | latexConverter = latexFunctions[this.name];
|
406 | }
|
407 |
|
408 |
|
409 | if (math[this.name] && (typeof math[this.name].toTex === 'function' || typeof math[this.name].toTex === 'object' || typeof math[this.name].toTex === 'string')) {
|
410 |
|
411 | latexConverter = math[this.name].toTex;
|
412 | }
|
413 |
|
414 | var customToTex;
|
415 |
|
416 | switch (typeof latexConverter) {
|
417 | case 'function':
|
418 |
|
419 | customToTex = latexConverter(this, options);
|
420 | break;
|
421 |
|
422 | case 'string':
|
423 |
|
424 | customToTex = expandTemplate(latexConverter, this, options);
|
425 | break;
|
426 |
|
427 | case 'object':
|
428 |
|
429 | switch (typeof latexConverter[args.length]) {
|
430 | case 'function':
|
431 | customToTex = latexConverter[args.length](this, options);
|
432 | break;
|
433 |
|
434 | case 'string':
|
435 | customToTex = expandTemplate(latexConverter[args.length], this, options);
|
436 | break;
|
437 | }
|
438 |
|
439 | }
|
440 |
|
441 | if (typeof customToTex !== 'undefined') {
|
442 | return customToTex;
|
443 | }
|
444 |
|
445 | return expandTemplate(defaultTemplate, this, options);
|
446 | };
|
447 | |
448 |
|
449 |
|
450 |
|
451 |
|
452 |
|
453 | FunctionNode.prototype.getIdentifier = function () {
|
454 | return this.type + ':' + this.name;
|
455 | };
|
456 |
|
457 | return FunctionNode;
|
458 | }, {
|
459 | isClass: true,
|
460 | isNode: true
|
461 | }); |
\ | No newline at end of file |