Skip to content

Commit 714f1bf

Browse files
authored
Merge branch 'develop' into broadcasting-functions
2 parents 3a19f48 + ef44f12 commit 714f1bf

14 files changed

Lines changed: 255 additions & 102 deletions

File tree

AUTHORS

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,9 +282,10 @@ Richard Taylor <richard.taylor@claconnect.com>
282282
NilsDietrich <61544566+NilsDietrich@users.noreply.github.com>
283283
anslem chibuike <144047596+AnslemHack@users.noreply.github.com>
284284
Ayomide Bamigbade <iamtryve@gmail.com>
285-
Chibuike Anselm <chibuikeanselm@Chibuikes-MacBook-Pro.local>
286-
Adriano Fantini <a.fantini@higecomore.com>
287285
Anadian <willanad@yandex.com>
288286
Dheemanth D <165369664+Dheemanth07@users.noreply.github.com>
287+
Adriano Fantini <adrfantini@users.noreply.github.com>
288+
Chibuike Anselm <chibuikeanselm@Chibuikes-MacBook-Pro.local>
289+
Jos de Jong <email@josdejong.com>
289290

290291
# Generated by tools/update-authors.js

HISTORY.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
# History
22

3-
# Unpublished changes since 15.1.1 (for release 15.2)
3+
# unpublished changes since 15.2.0
4+
5+
- Docs: fix the browser example `rocket_trajectory_optimization.html` (#3654).
6+
Thanks @dvd101x.
7+
8+
# 2026-04-07, 15.2.0
49

5-
- Chore: Provide TypeScript types for [and/or]TransformDependencies (#3639).
6-
Thanks @NilsDietrich.
710
- Feat: Add amp-hour charge unit `Ah` (#3617). Thanks @adrfantini.
811
- Feat: #3595 implement `num` and `den` functions returning the parts of
912
a fraction (#3605). Thanks @AnslemHack.
13+
- Fix: Provide TypeScript types for [and/or]TransformDependencies (#3639).
14+
Thanks @NilsDietrich.
15+
- Fix: two security vulnerabilities that allowed executing arbitrary JavaScript
16+
via the expression parser. Thanks @CykuTW for finding and reporting them.
1017

1118
# 2026-02-10, 15.1.1
1219

examples/browser/rocket_trajectory_optimization.html

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,8 @@ <h1>Rocket trajectory optimization</h1>
151151
label: resultName.slice(7),
152152
data: sim.evaluate(
153153
'concat('
154-
+ `(${resultName}[:,4] - phi0) * r0 / rad / km,` // Surface distance from start (in km)
155-
+ `(${resultName}[:,1] - r0) / km` // Height above surface (in km)
154+
+ `(${resultName}[:,[4]] - phi0) * r0 / rad / km,` // Surface distance from start (in km)
155+
+ `(${resultName}[:,[1]] - r0) / km` // Height above surface (in km)
156156
+ ')'
157157
).toArray().map(([x, y]) => ({ x, y })),
158158
borderColor: i % 2 ? '#999' : '#dc3912',
@@ -173,7 +173,7 @@ <h1>Rocket trajectory optimization</h1>
173173
}])
174174
createChart([{
175175
label: 'height (in km)',
176-
data: sim.evaluate("concat((result[:, 1] - r0), result[:, 6])")
176+
data: sim.evaluate("concat((result[:, [1]] - r0), result[:, [6]])")
177177
.toArray()
178178
.map(([r, t]) => ({ x: t.toNumber('s'), y: r.toNumber('km') })),
179179
}])
@@ -185,7 +185,7 @@ <h1>Rocket trajectory optimization</h1>
185185
}])
186186
createChart([{
187187
label: 'acceleration (in m/s^2)',
188-
data: sim.evaluate("concat(diff(result[:, 2]) ./ diff(result[:, 6]), result[:end-1, 6])")
188+
data: sim.evaluate("concat(diff(result[:, [2]]) ./ diff(result[:, [6]]), result[:end-1, [6]])")
189189
.toArray()
190190
.map(([acc, t]) => ({ x: t.toNumber('s'), y: acc.toNumber('m/s^2') })),
191191
}])
@@ -209,6 +209,7 @@ <h1>Rocket trajectory optimization</h1>
209209
{
210210
data: sim.evaluate("map(0:0.25:360, function(angle) = rotate([r0/km, 0], angle))")
211211
.toArray()
212+
.map(row => row.toArray())
212213
.map(([x, y]) => ({ x, y })),
213214
borderColor: "#999",
214215
fill: true

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mathjs",
3-
"version": "15.1.1",
3+
"version": "15.2.0",
44
"description": "Math.js is an extensive math library for JavaScript and Node.js. It features a flexible expression parser with support for symbolic computation, comes with a large set of built-in functions and constants, and offers an integrated solution to work with different data types like numbers, big numbers, complex numbers, fractions, units, and matrices.",
55
"author": "Jos de Jong <wjosdejong@gmail.com> (https://github.com/josdejong)",
66
"homepage": "https://mathjs.org",

src/utils/array.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,9 @@ export function stretch (arrayToStretch, sizeToStretch, dimToStretch) {
844844
*/
845845
export function get (array, index) {
846846
if (!Array.isArray(array)) { throw new Error('Array expected') }
847+
if (!Array.isArray(index)) {
848+
throw new Error('Array expected for index')
849+
}
847850
const size = arraySize(array)
848851
if (index.length !== size.length) { throw new DimensionError(index.length, size.length) }
849852
for (let x = 0; x < index.length; x++) { validateIndex(index[x], size[x]) }

src/utils/customs.js

Lines changed: 61 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,83 @@
11
import { hasOwnProperty } from './object.js'
22

33
/**
4-
* Get a property of a plain object
4+
* Get a property of a plain object or array
55
* Throws an error in case the object is not a plain object or the
66
* property is not defined on the object itself
77
* @param {Object} object
88
* @param {string} prop
99
* @return {*} Returns the property value when safe
1010
*/
11-
function getSafeProperty (object, prop) {
12-
// only allow getting safe properties of a plain object
13-
if (isSafeProperty(object, prop)) {
11+
export function getSafeProperty (object, prop) {
12+
if (isSafeObjectProperty(object, prop) || isSafeArrayProperty(object, prop)) {
1413
return object[prop]
1514
}
1615

17-
if (typeof object[prop] === 'function' && isSafeMethod(object, prop)) {
18-
throw new Error('Cannot access method "' + prop + '" as a property')
16+
if (isSafeMethod(object, prop)) {
17+
throw new Error(`Cannot access method "${prop}" as a property`)
18+
}
19+
20+
if (object === null || object === undefined) {
21+
throw new TypeError(`Cannot access property "${prop}": object is ${object}`)
1922
}
2023

2124
throw new Error('No access to property "' + prop + '"')
2225
}
2326

2427
/**
25-
* Set a property on a plain object.
28+
* Set a property on a plain object or array.
2629
* Throws an error in case the object is not a plain object or the
2730
* property would override an inherited property like .constructor or .toString
2831
* @param {Object} object
2932
* @param {string} prop
3033
* @param {*} value
3134
* @return {*} Returns the value
3235
*/
33-
// TODO: merge this function into access.js?
34-
function setSafeProperty (object, prop, value) {
35-
// only allow setting safe properties of a plain object
36-
if (isSafeProperty(object, prop)) {
36+
export function setSafeProperty (object, prop, value) {
37+
if (isSafeObjectProperty(object, prop) || isSafeArrayProperty(object, prop)) {
3738
object[prop] = value
3839
return value
3940
}
4041

41-
throw new Error('No access to property "' + prop + '"')
42+
throw new Error(`No access to property "${prop}"`)
4243
}
4344

4445
/**
45-
* Test whether a property is safe to use on an object or Array.
46-
* For example .toString and .constructor are not safe
47-
* @param {Object | Array} object
46+
* Test whether a property is safe for reading and writing on an object
47+
* For example .constructor and .__proto__ are not safe
48+
* @param {Object} object
4849
* @param {string} prop
4950
* @return {boolean} Returns true when safe
5051
*/
51-
function isSafeProperty (object, prop) {
52-
if (!isPlainObject(object) && !Array.isArray(object)) {
52+
export function isSafeObjectProperty (object, prop) {
53+
if (!isPlainObject(object)) {
5354
return false
5455
}
55-
// SAFE: whitelisted
56-
// e.g length
57-
if (hasOwnProperty(safeNativeProperties, prop)) {
58-
return true
59-
}
60-
// UNSAFE: inherited from Object prototype
61-
// e.g constructor
62-
if (prop in Object.prototype) {
63-
// 'in' is used instead of hasOwnProperty for nodejs v0.10
64-
// which is inconsistent on root prototypes. It is safe
65-
// here because Object.prototype is a root object
66-
return false
67-
}
68-
// UNSAFE: inherited from Function prototype
69-
// e.g call, apply
70-
if (prop in Function.prototype) {
71-
// 'in' is used instead of hasOwnProperty for nodejs v0.10
72-
// which is inconsistent on root prototypes. It is safe
73-
// here because Function.prototype is a root object
56+
57+
return !(prop in Object.prototype)
58+
}
59+
60+
/**
61+
* Test whether a property is safe for reading and writing on an Array
62+
* For example .__proto__ and .constructor are not safe
63+
* @param {unknown} array
64+
* @param {string | number} prop
65+
* @return {boolean} Returns true when safe
66+
*/
67+
export function isSafeArrayProperty (array, prop) {
68+
if (!Array.isArray(array)) {
7469
return false
7570
}
76-
return true
71+
72+
return (
73+
typeof prop === 'number' ||
74+
(typeof prop === 'string' && isInteger(prop)) ||
75+
prop === 'length'
76+
)
77+
}
78+
79+
function isInteger (prop) {
80+
return /^\d+$/.test(prop)
7781
}
7882

7983
/**
@@ -83,7 +87,7 @@ function isSafeProperty (object, prop) {
8387
* @param {string} method
8488
* @return {function} Returns the method when valid
8589
*/
86-
function getSafeMethod (object, method) {
90+
export function getSafeMethod (object, method) {
8791
if (!isSafeMethod(object, method)) {
8892
throw new Error('No access to method "' + method + '"')
8993
}
@@ -98,22 +102,32 @@ function getSafeMethod (object, method) {
98102
* @param {string} method
99103
* @return {boolean} Returns true when safe, false otherwise
100104
*/
101-
function isSafeMethod (object, method) {
102-
if (object === null || object === undefined || typeof object[method] !== 'function') {
105+
export function isSafeMethod (object, method) {
106+
if (
107+
object === null ||
108+
object === undefined ||
109+
typeof object[method] !== 'function'
110+
) {
103111
return false
104112
}
113+
105114
// UNSAFE: ghosted
106115
// e.g overridden toString
107116
// Note that IE10 doesn't support __proto__ and we can't do this check there.
108-
if (hasOwnProperty(object, method) &&
109-
(Object.getPrototypeOf && (method in Object.getPrototypeOf(object)))) {
117+
if (
118+
hasOwnProperty(object, method) &&
119+
Object.getPrototypeOf &&
120+
method in Object.getPrototypeOf(object)
121+
) {
110122
return false
111123
}
124+
112125
// SAFE: whitelisted
113126
// e.g toString
114-
if (hasOwnProperty(safeNativeMethods, method)) {
127+
if (safeNativeMethods.has(method)) {
115128
return true
116129
}
130+
117131
// UNSAFE: inherited from Object prototype
118132
// e.g constructor
119133
if (method in Object.prototype) {
@@ -122,6 +136,7 @@ function isSafeMethod (object, method) {
122136
// here because Object.prototype is a root object
123137
return false
124138
}
139+
125140
// UNSAFE: inherited from Function prototype
126141
// e.g call, apply
127142
if (method in Function.prototype) {
@@ -130,27 +145,12 @@ function isSafeMethod (object, method) {
130145
// here because Function.prototype is a root object
131146
return false
132147
}
148+
133149
return true
134150
}
135151

136-
function isPlainObject (object) {
152+
export function isPlainObject (object) {
137153
return typeof object === 'object' && object && object.constructor === Object
138154
}
139155

140-
const safeNativeProperties = {
141-
length: true,
142-
name: true
143-
}
144-
145-
const safeNativeMethods = {
146-
toString: true,
147-
valueOf: true,
148-
toLocaleString: true
149-
}
150-
151-
export { getSafeProperty }
152-
export { setSafeProperty }
153-
export { isSafeProperty }
154-
export { getSafeMethod }
155-
export { isSafeMethod }
156-
export { isPlainObject }
156+
const safeNativeMethods = new Set(['toString', 'valueOf', 'toLocaleString'])

src/utils/map.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { getSafeProperty, isSafeProperty, setSafeProperty } from './customs.js'
1+
import {
2+
getSafeProperty,
3+
isSafeObjectProperty,
4+
setSafeProperty
5+
} from './customs.js'
26
import { isMap, isObject } from './is.js'
37

48
/**
@@ -32,7 +36,7 @@ export class ObjectWrappingMap {
3236
}
3337

3438
has (key) {
35-
return isSafeProperty(this.wrappedObject, key) && key in this.wrappedObject
39+
return isSafeObjectProperty(this.wrappedObject, key) && key in this.wrappedObject
3640
}
3741

3842
entries () {
@@ -46,7 +50,7 @@ export class ObjectWrappingMap {
4650
}
4751

4852
delete (key) {
49-
if (isSafeProperty(this.wrappedObject, key)) {
53+
if (isSafeObjectProperty(this.wrappedObject, key)) {
5054
delete this.wrappedObject[key]
5155
}
5256
}

src/version.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export const version = '15.1.1'
1+
export const version = '15.2.0'
22
// Note: This file is automatically generated when building math.js.
33
// Changes made in this file will be overwritten.

0 commit comments

Comments
 (0)