src/senko/polyfill/Polyfill.js
/**
* The script is part of SenkoWSH.
*
* AUTHOR:
* natade (http://twitter.com/natadea)
*
* LICENSE:
* The MIT license https://opensource.org/licenses/MIT
*/
import typeExtendsArray from "./ExtendsArray.js";
import typeExtendsString from "./ExtendsString.js";
/**
* グローバル空間
* 参考
* JavaScript大域変数の存在確認
* https://m-hiyama.hatenablog.com/entry/20071126/1196037633
* @private
*/
var global_var = ( function() { return this; } ).apply( null, [] );
if(!("globalThis" in global_var)) {
// @ts-ignore
globalThis = global_var;
}
if(!("global" in globalThis)) {
// @ts-ignore
global = globalThis;
}
if(!("window" in globalThis)) {
// @ts-ignore
window = globalThis;
}
if(!("JSON" in globalThis)) {
// @ts-ignore
JSON = {};
}
/**
* Class for improving compatibility.
* @ignore
*/
export default class Polyfill {
/**
* Improved compatibility
* @private
* @ignore
*/
static run() {
/**
* @param {any} original
* @param {any} extension
* @returns {any}
* @private
* @ignore
*/
const extendClass = function(original, extension) {
for(const key in extension) {
// 未設定なら設定する
if(!original.prototype[key]) {
original.prototype[key] = function() {
const x = [];
x.push(this);
for(let i = 0 ; i < arguments.length ; i++) {
x.push(arguments[i]);
}
return extension[key].apply(this, x);
};
}
}
};
extendClass(String, typeExtendsString);
// 安定ソートへ差し替え ECMAScript 2019
// @ts-ignore
Array.sort = typeExtendsArray.sort;
// IE9以降の splice 動作の仕様へ差し替え
{
// splice の動作チェック
const A = [0, 0];
A.splice(1);
if(A.length !== 1) {
// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
// 2番目の引数が省略された場合の動作の仕様を合わせる
const splice_buffer = Array.prototype.splice;
Array.prototype.splice = function() {
const x = [];
for(var i = 0 ; i < arguments.length ; i++) {
x.push(arguments[i]);
}
if(arguments.length === 1) {
x.push(this.length - arguments[0]);
}
return splice_buffer.apply(this, x);
};
}
}
if(!Math.imul) {
Math.imul = function(x1, x2) {
let y = ((x1 & 0xFFFF) * (x2 & 0xFFFF)) >>> 0;
let b = (x1 & 0xFFFF) * (x2 >>> 16);
y = (y + ((b & 0xFFFF) << 16)) >>> 0;
b = (x1 >>> 16) * (x2 & 0xFFFF);
y = (y + ((b & 0xFFFF) << 16));
return (y & 0xFFFFFFFF);
};
}
if(!Math.trunc) {
Math.trunc = function(x) {
return x > 0 ? Math.floor(x) : Math.ceil(x);
};
}
if(!Math.cbrt) {
Math.cbrt = function(x) {
return Math.exp(Math.log(x) / 3.0);
};
}
if(!Math.expm1) {
Math.expm1 = function(x) {
return Math.exp(x) - 1.0;
};
}
if(!Math.log1p) {
Math.log1p = function(x) {
return Math.log(x + 1.0);
};
}
if(!Math.log2) {
Math.log2 = function(x) {
return Math.log(x) / Math.log(2);
};
}
if(!Math.log10) {
Math.log10 = function(x) {
return Math.log(x) / Math.log(10);
};
}
if(Math.E === undefined) {
// @ts-ignore
// eslint-disable-next-line no-global-assign
Math.E = 2.718281828459045;
}
if(Math.LN10 === undefined) {
// @ts-ignore
// eslint-disable-next-line no-global-assign
Math.LN10 = Math.log(10);
}
if(Math.LN2 === undefined) {
// @ts-ignore
// eslint-disable-next-line no-global-assign
Math.LN2 = Math.log(2);
}
if(Math.LOG2E === undefined) {
// @ts-ignore
// eslint-disable-next-line no-global-assign
Math.LOG2E = Math.log2(Math.E);
}
if(Math.LOG10E === undefined) {
// @ts-ignore
// eslint-disable-next-line no-global-assign
Math.LOG10E = Math.log10(Math.E);
}
if(Math.PI === undefined) {
// @ts-ignore
// eslint-disable-next-line no-global-assign
Math.PI = 3.141592653589793;
}
if(Math.SQRT1_2 === undefined) {
// @ts-ignore
// eslint-disable-next-line no-global-assign
Math.SQRT1_2 = Math.pow(0.5, 0.5);
}
if(Math.SQRT2 === undefined) {
// @ts-ignore
// eslint-disable-next-line no-global-assign
Math.SQRT2 = Math.pow(2, 0.5);
}
if(!Number.isFinite) {
Number.isFinite = isFinite;
}
if(!Number.isInteger) {
Number.isInteger = function(x) {
// @ts-ignore
return isFinite(x) && Math.trunc(x) === x;
};
}
if(!Number.isNaN) {
Number.isNaN = isNaN;
}
if(Number.NaN === undefined) {
// @ts-ignore
// eslint-disable-next-line no-global-assign
Number.NaN = NaN;
}
if(Number.EPSILON === undefined) {
// @ts-ignore
// eslint-disable-next-line no-global-assign
Number.EPSILON = 2.220446049250313e-16;
}
if(Number.MIN_SAFE_INTEGER === undefined) {
// @ts-ignore
// eslint-disable-next-line no-global-assign
Number.MIN_SAFE_INTEGER = -9007199254740991;
}
if(Number.MAX_SAFE_INTEGER === undefined) {
// @ts-ignore
// eslint-disable-next-line no-global-assign
Number.MAX_SAFE_INTEGER = 9007199254740991;
}
if(!Number.parseFloat) {
Number.parseFloat = parseFloat;
}
if(!Number.parseInt) {
Number.parseInt = parseInt;
}
if(!Number.isSafeInteger) {
// @ts-ignore
Number.isSafeInteger = function(x) {
// @ts-ignore
return Number.isInteger(x) && Math.abs(x) <= Number.MAX_SAFE_INTEGER;
};
}
if(!Array.isArray) {
// @ts-ignore
Array.isArray = function(x) {
return Object.prototype.toString.call(x) === "[object Array]";
};
}
if(!Array.of) {
// @ts-ignore
Array.of = function() {
return Array.prototype.slice.call(arguments);
};
}
if(!String.fromCodePoint) {
/**
* コードポイントの数値データをUTF16の配列に変換
* @param {...(number|Array<number>)} codepoint - 変換したいUTF-32の配列、又はコードポイントを並べた可変引数
* @returns {Array<number>} 変換後のテキスト
* @private
*/
const toUTF16ArrayfromCodePoint = function() {
/**
* @type {Array<number>}
* @private
*/
const utf16_array = [];
/**
* @type {Array<number>}
* @private
*/
let codepoint_array = [];
if(arguments[0].length) {
codepoint_array = arguments[0];
}
else {
for(let i = 0;i < arguments.length;i++) {
codepoint_array[i] = arguments[i];
}
}
for(let i = 0;i < codepoint_array.length;i++) {
const codepoint = codepoint_array[i];
if(0x10000 <= codepoint) {
const high = (( codepoint - 0x10000 ) >> 10) + 0xD800;
const low = (codepoint & 0x3FF) + 0xDC00;
utf16_array.push(high);
utf16_array.push(low);
}
else {
utf16_array.push(codepoint);
}
}
return utf16_array;
}
/**
* コードポイントの数値データを文字列に変換
* @param {...(number|Array<number>)} codepoint - 変換したいコードポイントの数値配列、又は数値を並べた可変引数
* @returns {string} 変換後のテキスト
*/
String.fromCodePoint = function(codepoint) {
let utf16_array = null;
if(codepoint instanceof Array) {
utf16_array = toUTF16ArrayfromCodePoint(codepoint);
}
else {
const codepoint_array = [];
for(let i = 0;i < arguments.length;i++) {
codepoint_array[i] = arguments[i];
}
utf16_array = toUTF16ArrayfromCodePoint(codepoint_array);
}
const text = [];
for(let i = 0;i < utf16_array.length;i++) {
text[text.length] = String.fromCharCode(utf16_array[i]);
}
return text.join("");
};
}
if(!Date.now) {
// @ts-ignore
Date.now = function() {
return (new Date()).getTime();
};
}
if(!JSON.parse) {
JSON.parse = function(json_text) {
return eval("(" + json_text + ")");
};
}
if(!JSON.stringify) {
/**
* @type {Object<string, string>}
*/
const escapeMap = {
"\u0022" : "\\\"",
"\u005C" : "\\\\",
"\u002F" : "\\/",
"\u0008" : "\\b",
"\u000C" : "\\f",
"\u000A" : "\\n",
"\u000D" : "\\r",
"\u0009" : "\\t"
};
/**
* @param {string} str
* @returns {string}
*/
const escapeString = function(str) {
return escapeMap[str];
};
/**
* https://tools.ietf.org/html/rfc8259
* @param {string} str
* @returns {string}
*/
const escape = function(str) {
return str.replace(/[\u0022\u005C\u002F\u0008\u000C\u000A\u000D\u0009]/g, escapeString);;
};
/**
* @param {any} data
* @returns {string}
*/
const stringify = function(data) {
const type = Object.prototype.toString.call(data);
if((type === "[object Number]") || (type === "[object Boolean]")) {
return data.toString();
}
else if(type === "[object String]") {
return "\"" + escape(data) + "\"";
}
else if(type === "[object Date]") {
// JScript には toISOString がないので。
return "\"" + data.toGMTString() + "\"";
}
else if(type === "[object Function]") {
return "null";
}
else if(type === "[object RegExp]") {
return "{}";
}
else if(data === null) {
return "null";
}
else if(data === undefined) {
return "undefined";
}
else if(type === "[object Array]") {
/**
* @type {string[]}
*/
let output = [];
output.push("[");
/**
* @type {string[]}
*/
let array_data = [];
for(let i = 0; i < data.length; i++) {
array_data.push(stringify(data[i]));
}
output.push(array_data.join(","));
output.push("]");
return output.join("");
}
else if(type === "[object Object]") {
/**
* @type {string[]}
*/
let output = [];
output.push("{");
/**
* @type {string[]}
*/
let object_data = [];
for(const key in data) {
const value = data[key];
// 関数の場合は無視する
if(Object.prototype.toString.call(value) === "[object Function]") {
continue;
}
/**
* @type {string[]}
*/
const line = [];
line.push("\"" + key + "\"");
line.push(":");
line.push(stringify(value));
object_data.push(line.join(""));
}
output.push(object_data.join(","));
output.push("}");
return output.join("");
}
else {
return "\"" + escape(data.toString()) + "\""
}
};
JSON.stringify = stringify;
}
}
}
// @ts-ignore
Polyfill.run();