diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/autoload.mjs b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/autoload.mjs
index 2507d88..47a9424 100644
--- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/autoload.mjs
+++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/autoload.mjs
@@ -16,6 +16,8 @@
* along with this program. If not, see .
*/
+import js from "./lib/polyfills/js.mjs"
+
// Loading modules in order
import * as Objects from "./module/objects.mjs"
import * as ExprParser from "./module/expreval.mjs"
diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/lib/expr-eval/expression.mjs b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/lib/expr-eval/expression.mjs
index 57b4e0e..89831c7 100644
--- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/lib/expr-eval/expression.mjs
+++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/lib/expr-eval/expression.mjs
@@ -482,7 +482,7 @@ export class ExprEvalExpression {
/**
* Calculates the value of the expression by giving all variables and their corresponding values.
- * @param {Object} values
+ * @param {Object} values
* @returns {number}
*/
evaluate(values) {
@@ -512,8 +512,7 @@ export class ExprEvalExpression {
* as constants or functions.
* @returns {string[]}
*/
- variables(options) {
- options = options || {}
+ variables(options = {}) {
const vars = []
getSymbols(this.tokens, vars, options)
const functions = this.functions
diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/lib/polyfills/js.mjs b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/lib/polyfills/js.mjs
new file mode 100644
index 0000000..43ed375
--- /dev/null
+++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/lib/polyfills/js.mjs
@@ -0,0 +1,126 @@
+/**
+ * LogarithmPlotter - 2D plotter software to make BODE plots, sequences and distribution functions.
+ * Copyright (C) 2021-2024 Ad5001
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+// JS polyfills to add because they're not implemented in the QML Scripting engine.
+// CoreJS does not work well with it (as well as doubles the compiled size), so this is preferable.
+function notPolyfilled(name) {
+ return function() { throw new Error(`${name} not polyfilled`) }
+}
+
+/**
+ * @param {number} depth
+ * @this {Array}
+ * @returns {Array}
+ */
+function arrayFlat(depth = 1) {
+ const newArray = []
+ for(const element of this) {
+ if(element instanceof Array)
+ newArray.push(...(depth > 1 ? element.flat(depth - 1) : element))
+ else
+ newArray.push(element)
+ }
+ return newArray
+}
+
+/**
+ * @param {function(any, number, Array): any} callbackFn
+ * @param {object} thisArg
+ * @this {Array}
+ * @returns {Array}
+ */
+function arrayFlatMap(callbackFn, thisArg) {
+ const newArray = []
+ for(let i = 0; i < this.length; i++) {
+ const value = callbackFn.call(thisArg ?? this, this[i], i, this)
+ if(value instanceof Array)
+ newArray.push(...value)
+ else
+ newArray.push(value)
+ }
+ return newArray
+}
+
+/**
+ * Replaces all instances of from by to.
+ * @param {string} from
+ * @param {string} to
+ * @this {string}
+ * @return {String}
+ */
+function stringReplaceAll(from, to) {
+ let str = this
+ while(str.includes(from))
+ str = str.replace(from, to)
+ return str
+}
+
+
+const polyfills = {
+ 2017: [
+ [Object, "entries", notPolyfilled("Object.entries")],
+ [Object, "values", notPolyfilled("Object.values")],
+ [Object, "getOwnPropertyDescriptors", notPolyfilled("Object.getOwnPropertyDescriptors")],
+ [String.prototype, "padStart", notPolyfilled("String.prototype.padStart")],
+ [String.prototype, "padEnd", notPolyfilled("String.prototype.padEnd")]
+ ],
+ 2018: [
+ [Promise.prototype, "finally", notPolyfilled("Object.entries")]
+ ],
+ 2019: [
+ [String.prototype, "trimStart", notPolyfilled("String.prototype.trimStart")],
+ [String.prototype, "trimEnd", notPolyfilled("String.prototype.trimEnd")],
+ [Object, "fromEntries", notPolyfilled("Object.fromEntries")],
+ [Array.prototype, "flat", arrayFlat],
+ [Array.prototype, "flatMap", arrayFlatMap]
+ ],
+ 2020: [
+ [String.prototype, "matchAll", notPolyfilled("String.prototype.matchAll")],
+ [Promise, "allSettled", notPolyfilled("Promise.allSettled")]
+ ],
+ 2021: [
+ [Promise, "any", notPolyfilled("Promise.any")],
+ [String.prototype, "replaceAll", stringReplaceAll]
+ ],
+ 2022: [
+ [Array.prototype, "at", notPolyfilled("Array.prototype.at")],
+ [String.prototype, "at", notPolyfilled("String.prototype.at")],
+ [Object, "hasOwn", notPolyfilled("Object.hasOwn")]
+ ],
+ 2023: [
+ [Array.prototype, "findLast", notPolyfilled("Array.prototype.findLast")],
+ [Array.prototype, "toReversed", notPolyfilled("Array.prototype.toReversed")],
+ [Array.prototype, "toSorted", notPolyfilled("Array.prototype.toSorted")],
+ [Array.prototype, "toSpliced", notPolyfilled("Array.prototype.toSpliced")],
+ [Array.prototype, "with", notPolyfilled("Array.prototype.with")]
+ ],
+ 2024: [
+ [Object, "groupBy", notPolyfilled("Object.groupBy")],
+ [Map, "groupBy", notPolyfilled("Map.groupBy")]
+ ]
+}
+
+// Fulfill polyfill.
+for(const [year, entries] of Object.entries(polyfills)) {
+ const defined = entries.filter(x => x[0][x[1]] !== undefined)
+ console.info(`ES${year} support: ${defined.length === entries.length} (${defined.length}/${entries.length})`)
+ // Apply polyfills
+ for(const [context, functionName, polyfill] of entries.filter(x => x[0][x[1]] === undefined)) {
+ context[functionName] = polyfill
+ }
+}
\ No newline at end of file
diff --git a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/lib/qmlpolyfills.mjs b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/lib/polyfills/qt.mjs
similarity index 93%
rename from LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/lib/qmlpolyfills.mjs
rename to LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/lib/polyfills/qt.mjs
index daefa6c..7cbb2f7 100644
--- a/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/lib/qmlpolyfills.mjs
+++ b/LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/lib/polyfills/qt.mjs
@@ -18,6 +18,7 @@
// Type polyfills for IDEs.
// Never directly imported.
+// Might need to be reimplemented in other implemententations.
Modules = Modules || {}
/** @type {function(string, string): string} */
@@ -25,7 +26,7 @@ qsTranslate = qsTranslate || function(category, string) { throw new Error('qsTra
/** @type {function(string): string} */
qsTr = qsTr || function(string) { throw new Error('qsTr not implemented.'); }
/** @type {function(string, string): string} */
-QT_TRANSLATE_NOOP = QT_TRANSLATE_NOOP || function(string, string) { throw new Error('QT_TRANSLATE_NOOP not implemented.'); }
+QT_TRANSLATE_NOOP = QT_TRANSLATE_NOOP || function(category, string) { throw new Error('QT_TRANSLATE_NOOP not implemented.'); }
/** @type {function(string): string} */
QT_TR_NOOP = QT_TR_NOOP || function(string) { throw new Error('QT_TR_NOOP not implemented.'); }
/** @type {function(string|boolean|int): string} */