From 8cefc56ac797512ef2c900d3710c53cbd018534a Mon Sep 17 00:00:00 2001 From: Ad5001 Date: Fri, 27 Sep 2024 02:34:42 +0200 Subject: [PATCH] Adding JS polyfills to avoid issues because core-js does not deal well with the environment it's given. --- .../ad5001/LogarithmPlotter/js/autoload.mjs | 2 + .../js/lib/expr-eval/expression.mjs | 5 +- .../LogarithmPlotter/js/lib/polyfills/js.mjs | 126 ++++++++++++++++++ .../{qmlpolyfills.mjs => polyfills/qt.mjs} | 3 +- 4 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/lib/polyfills/js.mjs rename LogarithmPlotter/qml/eu/ad5001/LogarithmPlotter/js/lib/{qmlpolyfills.mjs => polyfills/qt.mjs} (93%) 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} */