Phase 1 PWA: prayer times, qibla, quran, hijri, tasbih, 99 names
This commit is contained in:
+538
@@ -0,0 +1,538 @@
|
||||
/***********************************************************************
|
||||
|
||||
A JavaScript tokenizer / parser / beautifier / compressor.
|
||||
https://github.com/mishoo/UglifyJS2
|
||||
|
||||
-------------------------------- (C) ---------------------------------
|
||||
|
||||
Author: Mihai Bazon
|
||||
<mihai.bazon@gmail.com>
|
||||
http://mihai.bazon.net/blog
|
||||
|
||||
Distributed under the BSD license:
|
||||
|
||||
Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
import { AST_Array, AST_Dot, AST_New, AST_Number, AST_SymbolRef } from "../ast.js";
|
||||
import { makePredicate } from "../utils/index.js";
|
||||
import { is_undeclared_ref } from "./inference.js";
|
||||
|
||||
// Lists of native methods, useful for `unsafe` option which assumes they exist.
|
||||
// Note: Lots of methods and functions are missing here, in case they aren't pure
|
||||
// or not available in all JS environments.
|
||||
|
||||
const make_nested_lookup = (feature_callback) => (compressor) => {
|
||||
const obj = feature_callback(feature_variables(compressor));
|
||||
|
||||
const out = new Map();
|
||||
for (var key of Object.keys(obj)) {
|
||||
if (obj[key]) {
|
||||
out.set(key, makePredicate(remove_false(obj[key])));
|
||||
}
|
||||
}
|
||||
|
||||
const does_have = (global_name, fname) => {
|
||||
const inner_map = out.get(global_name);
|
||||
return inner_map != null && inner_map.has(fname);
|
||||
};
|
||||
return does_have;
|
||||
};
|
||||
|
||||
const make_lookup = (feature_callback) => (compressor) => {
|
||||
const obj = feature_callback(feature_variables(compressor));
|
||||
|
||||
const predicate = makePredicate(remove_false(obj));
|
||||
const does_have = (global_name) => {
|
||||
return predicate.has(global_name);
|
||||
};
|
||||
return does_have;
|
||||
};
|
||||
|
||||
function remove_false(arr) {
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
if (arr[i] === false) {
|
||||
arr.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
/** Generate the object with arguments seen below */
|
||||
function feature_variables(compressor) {
|
||||
return {
|
||||
sloppy: compressor.option("unsafe"),
|
||||
es: compressor.option("builtins_ecma"),
|
||||
};
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
export const pure_access_globals = make_lookup(({ sloppy, es }) => [
|
||||
"Array",
|
||||
"Boolean",
|
||||
"clearInterval",
|
||||
"clearTimeout",
|
||||
"console",
|
||||
"Date",
|
||||
"decodeURI",
|
||||
"decodeURIComponent",
|
||||
"encodeURI",
|
||||
"encodeURIComponent",
|
||||
"Error",
|
||||
"escape",
|
||||
"eval",
|
||||
"EvalError",
|
||||
"Function",
|
||||
es >= 2020 && "globalThis",
|
||||
"isFinite",
|
||||
"isNaN",
|
||||
"JSON",
|
||||
"Math",
|
||||
"Number",
|
||||
"parseFloat",
|
||||
"parseInt",
|
||||
"RangeError",
|
||||
"ReferenceError",
|
||||
"RegExp",
|
||||
"Object",
|
||||
"setInterval",
|
||||
"setTimeout",
|
||||
"String",
|
||||
"SyntaxError",
|
||||
"TypeError",
|
||||
"unescape",
|
||||
"URIError",
|
||||
]);
|
||||
|
||||
// Objects which are safe to access without throwing or causing a side effect.
|
||||
// Usually we'd check the `unsafe` option first but these are way too common for that
|
||||
export const pure_prop_access_globals = new Set([
|
||||
"Number",
|
||||
"String",
|
||||
"Array",
|
||||
"Object",
|
||||
"Function",
|
||||
"Promise",
|
||||
]);
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
export const is_pure_native_fn = make_lookup(({ sloppy, es }) => [
|
||||
sloppy && es >= 2021 && "AggregateError",
|
||||
"Array",
|
||||
"ArrayBuffer",
|
||||
es >= 2020 && "BigInt",
|
||||
es >= 2020 && "BigInt64Array",
|
||||
es >= 2020 && "BigUint64Array",
|
||||
"Boolean",
|
||||
"Date",
|
||||
sloppy && "decodeURI",
|
||||
sloppy && "decodeURIComponent",
|
||||
sloppy && "encodeURI",
|
||||
sloppy && "encodeURIComponent",
|
||||
"Error",
|
||||
"escape",
|
||||
"EvalError",
|
||||
es >= 2021 && "FinalizationRegistry",
|
||||
es >= 2026 && "Float16Array",
|
||||
"Float32Array",
|
||||
"Float64Array",
|
||||
"Int16Array",
|
||||
"Int32Array",
|
||||
"Int8Array",
|
||||
"isFinite",
|
||||
"isNaN",
|
||||
es >= 2026 && "Iterator",
|
||||
es >= 2015 && "Map",
|
||||
"Number",
|
||||
"parseFloat",
|
||||
"parseInt",
|
||||
es >= 2015 && "Promise",
|
||||
es >= 2015 && "Proxy",
|
||||
"RangeError",
|
||||
"ReferenceError",
|
||||
sloppy && "RegExp",
|
||||
es >= 2015 && "Set",
|
||||
"String",
|
||||
es >= 2015 && "Symbol",
|
||||
"SyntaxError",
|
||||
"TypeError",
|
||||
"Uint16Array",
|
||||
"Uint32Array",
|
||||
"Uint8Array",
|
||||
"Uint8ClampedArray",
|
||||
sloppy && "unescape",
|
||||
"URIError",
|
||||
sloppy && es >= 2015 && "WeakMap",
|
||||
sloppy && es >= 2021 && "WeakRef",
|
||||
sloppy && es >= 2015 && "WeakSet",
|
||||
]);
|
||||
|
||||
const arg1_is_iterable = new Set([
|
||||
"Map",
|
||||
"Set",
|
||||
"WeakMap",
|
||||
"WeakSet",
|
||||
]);
|
||||
const arg1_is_range_or_iterable = new Set([
|
||||
"ArrayBuffer",
|
||||
"Float32Array",
|
||||
"Float64Array",
|
||||
"Int16Array",
|
||||
"Int32Array",
|
||||
"Int8Array",
|
||||
"Uint16Array",
|
||||
"Uint32Array",
|
||||
"Uint8Array",
|
||||
"Uint8ClampedArray",
|
||||
]);
|
||||
const lone_arg_is_range = new Set(["Array"]);
|
||||
|
||||
const object_methods = [
|
||||
"constructor",
|
||||
"toString",
|
||||
"valueOf",
|
||||
];
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
export const is_pure_native_method = make_nested_lookup(({ sloppy, es }) => ({
|
||||
Array: [
|
||||
es >= 2022 && "at",
|
||||
es >= 2019 && "flat",
|
||||
es >= 2016 && "includes",
|
||||
"indexOf",
|
||||
"join",
|
||||
"lastIndexOf",
|
||||
"slice",
|
||||
...object_methods,
|
||||
],
|
||||
Boolean: object_methods,
|
||||
Function: object_methods,
|
||||
Number: [
|
||||
"toExponential",
|
||||
"toFixed",
|
||||
"toPrecision",
|
||||
...object_methods,
|
||||
],
|
||||
Object: object_methods,
|
||||
RegExp: [
|
||||
"test",
|
||||
...object_methods,
|
||||
],
|
||||
String: [
|
||||
es >= 2022 && "at",
|
||||
"charAt",
|
||||
"charCodeAt",
|
||||
es >= 2015 && "codePointAt",
|
||||
"concat",
|
||||
es >= 2025 && "endsWith",
|
||||
es >= 2015 && "includes",
|
||||
"indexOf",
|
||||
"italics",
|
||||
"lastIndexOf",
|
||||
es >= 2020 && "localeCompare",
|
||||
"match",
|
||||
es >= 2020 && "matchAll",
|
||||
es >= 2015 && "normalize",
|
||||
es >= 2017 && "padStart",
|
||||
es >= 2017 && "padEnd",
|
||||
es >= 2015 && sloppy && "repeat",
|
||||
"replace",
|
||||
es >= 2021 && "replaceAll",
|
||||
"search",
|
||||
"slice",
|
||||
"split",
|
||||
es >= 2015 && "startsWith",
|
||||
"substr",
|
||||
"substring",
|
||||
es >= 2015 && "repeat",
|
||||
"toLocaleLowerCase",
|
||||
"toLocaleUpperCase",
|
||||
"toLowerCase",
|
||||
"toUpperCase",
|
||||
"trim",
|
||||
es >= 2019 && "trimEnd",
|
||||
es >= 2019 && "trimStart",
|
||||
es >= 2019 && "trimLeft",
|
||||
es >= 2019 && "trimRight",
|
||||
...object_methods,
|
||||
],
|
||||
}));
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
export const is_pure_native_static_fn = make_nested_lookup(({ sloppy, es }) => ({
|
||||
Array: [
|
||||
"isArray",
|
||||
es >= 2015 && "of",
|
||||
],
|
||||
ArrayBuffer: [
|
||||
"isView",
|
||||
],
|
||||
BigInt: es >= 2020 && [
|
||||
sloppy && "asIntN",
|
||||
sloppy && "asUintN",
|
||||
],
|
||||
BigInt64Array: sloppy && es >= 2020 && ["of"],
|
||||
BigUint64Array: sloppy && es >= 2020 && ["of"],
|
||||
Date: [
|
||||
"now",
|
||||
"parse",
|
||||
"UTC",
|
||||
],
|
||||
Error: [
|
||||
es >= 2026 && "isError",
|
||||
],
|
||||
Float16Array: sloppy && es >= 2026 && ["of"],
|
||||
Float32Array: sloppy && ["of"],
|
||||
Float64Array: sloppy && ["of"],
|
||||
Int16Array: sloppy && ["of"],
|
||||
Int32Array: sloppy && ["of"],
|
||||
Int8Array: sloppy && ["of"],
|
||||
Math: [
|
||||
"abs",
|
||||
"acos",
|
||||
es >= 2015 && "acosh",
|
||||
"asin",
|
||||
es >= 2015 && "asinh",
|
||||
"atan",
|
||||
"atan2",
|
||||
es >= 2015 && "atanh",
|
||||
es >= 2015 && "cbrt",
|
||||
"ceil",
|
||||
es >= 2015 && "clz32",
|
||||
"cos",
|
||||
es >= 2015 && "cosh",
|
||||
"exp",
|
||||
es >= 2015 && "expm1",
|
||||
"floor",
|
||||
es >= 2026 && "f16round",
|
||||
es >= 2015 && "fround",
|
||||
es >= 2015 && "hypot",
|
||||
es >= 2015 && "imul",
|
||||
"log",
|
||||
es >= 2015 && "log10",
|
||||
es >= 2015 && "log1p",
|
||||
es >= 2015 && "log2",
|
||||
"max",
|
||||
"min",
|
||||
"pow",
|
||||
"round",
|
||||
es >= 2015 && "sign",
|
||||
"sin",
|
||||
es >= 2015 && "sinh",
|
||||
"sqrt",
|
||||
"tan",
|
||||
es >= 2015 && "tanh",
|
||||
es >= 2015 && "trunc",
|
||||
],
|
||||
Number: [
|
||||
es >= 2015 && "isFinite",
|
||||
es >= 2015 && "isInteger",
|
||||
es >= 2015 && "isSafeInteger",
|
||||
es >= 2015 && "isNaN",
|
||||
es >= 2015 && "parseFloat",
|
||||
es >= 2015 && "parseInt",
|
||||
],
|
||||
Object: [
|
||||
sloppy && "create",
|
||||
sloppy && "getOwnPropertyDescriptor",
|
||||
es >= 2017 && sloppy && "getOwnPropertyDescriptors",
|
||||
sloppy && "getOwnPropertyNames",
|
||||
es >= 2015 && sloppy && "getOwnPropertySymbols",
|
||||
sloppy && "getPrototypeOf",
|
||||
es >= 2022 && sloppy && "hasOwn",
|
||||
es >= 2015 && "is",
|
||||
"isExtensible",
|
||||
"isFrozen",
|
||||
"isSealed",
|
||||
es >= 2015 && sloppy && "keys",
|
||||
],
|
||||
Promise: es >= 2015 && [
|
||||
es >= 2024 && "withResolvers",
|
||||
],
|
||||
Proxy: es >= 2015 && [
|
||||
sloppy && "revocable",
|
||||
],
|
||||
Reflect: es >= 2015 && [
|
||||
sloppy && "has",
|
||||
sloppy && "isExtensible",
|
||||
sloppy && "ownKeys",
|
||||
],
|
||||
RegExp: [
|
||||
es >= 2026 && sloppy && "escape",
|
||||
],
|
||||
String: [
|
||||
"fromCharCode",
|
||||
sloppy && es >= 2025 && "fromCodePoint",
|
||||
],
|
||||
Uint16Array: ["of"],
|
||||
Uint32Array: ["of"],
|
||||
Uint8Array: ["of"],
|
||||
Uint8ClampedArray: ["of"],
|
||||
}));
|
||||
|
||||
// Known numeric values which come with JS environments
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
export const is_pure_native_static_property = make_nested_lookup(({ sloppy, es }) => ({
|
||||
Math: [
|
||||
"E",
|
||||
"LN10",
|
||||
"LN2",
|
||||
"LOG2E",
|
||||
"LOG10E",
|
||||
"PI",
|
||||
"SQRT1_2",
|
||||
"SQRT2",
|
||||
],
|
||||
Number: [
|
||||
es >= 2015 && "EPSILON",
|
||||
es >= 2015 && "MAX_SAFE_VALUE",
|
||||
"MAX_VALUE",
|
||||
es >= 2015 && "MIN_SAFE_VALUE",
|
||||
"MIN_VALUE",
|
||||
"NaN",
|
||||
"NEGATIVE_INFINITY",
|
||||
"POSITIVE_INFINITY",
|
||||
],
|
||||
RegExp: [
|
||||
"$_",
|
||||
"$0",
|
||||
"$1",
|
||||
"$2",
|
||||
"$3",
|
||||
"$4",
|
||||
"$5",
|
||||
"$6",
|
||||
"$7",
|
||||
"$8",
|
||||
"$9",
|
||||
"input",
|
||||
"lastMatch",
|
||||
"lastParen",
|
||||
"leftContext",
|
||||
"rightContext",
|
||||
],
|
||||
}));
|
||||
|
||||
const re_uppercase_first_letter = /^[A-Z]/;
|
||||
export function is_pure_builtin_call(compressor, call) {
|
||||
let builtin = "";
|
||||
let method = "";
|
||||
|
||||
let exp = call.expression;
|
||||
if (is_undeclared_ref(exp)) {
|
||||
builtin = exp.name;
|
||||
} else if (exp instanceof AST_Dot) {
|
||||
method = exp.property;
|
||||
|
||||
exp = exp.expression;
|
||||
if (is_undeclared_ref(exp)) {
|
||||
if (
|
||||
// globalThis.pureFunc()
|
||||
exp.name === "globalThis"
|
||||
&& compressor.option("builtins_ecma") >= 2020
|
||||
) {
|
||||
builtin = method;
|
||||
method = "";
|
||||
} else {
|
||||
// SomeBuiltin.pureFunc()
|
||||
builtin = exp.name;
|
||||
}
|
||||
} else if (exp instanceof AST_Dot) {
|
||||
if (
|
||||
is_undeclared_ref(exp.expression)
|
||||
&& exp.expression.name === "globalThis"
|
||||
&& compressor.option("builtins_ecma") >= 2020
|
||||
) {
|
||||
// globalThis.SomeBuiltin.pureFunc()
|
||||
builtin = exp.property;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!method) {
|
||||
if (compressor.is_pure_native_fn(builtin)) {
|
||||
// some require `new`, others throw if you use it
|
||||
const is_new = call instanceof AST_New;
|
||||
const should_be_new = re_uppercase_first_letter.test(builtin); // true of all `is_pure_native_fn`
|
||||
if (is_new !== should_be_new) return false;
|
||||
|
||||
if (!is_builtin_pure_with_these_args(builtin, call.args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
return compressor.is_pure_native_static_fn(builtin, method);
|
||||
}
|
||||
}
|
||||
|
||||
/** Some builtins are listed above but their purity is subject to some conditions */
|
||||
function is_builtin_pure_with_these_args(builtin, args) {
|
||||
// all the builtins we deal with here are ok with getting 0 args
|
||||
if (args.length === 0) return true;
|
||||
|
||||
let arg1 = args[0];
|
||||
if (arg1 instanceof AST_SymbolRef) {
|
||||
arg1 = arg1.fixed_value();
|
||||
}
|
||||
|
||||
if (lone_arg_is_range.has(builtin)) { // new Array(number)
|
||||
const arg_valid = args.length > 1
|
||||
|| arg1 instanceof AST_Number
|
||||
&& arg1.value >= 0 && arg1.value <= 0xffffffff;
|
||||
// TODO: or, we are asked to ignore TypeError
|
||||
if (!arg_valid) return false;
|
||||
}
|
||||
|
||||
if (arg1_is_range_or_iterable.has(builtin)) { // new Float32Array(number | Array)
|
||||
const arg_valid = args.length === 0
|
||||
|| arg1 instanceof AST_Array
|
||||
|| arg1 instanceof AST_Number
|
||||
&& arg1.value >= 0 && arg1.value <= 0xffffffff;
|
||||
if (!arg_valid) return false;
|
||||
}
|
||||
|
||||
if (arg1_is_iterable.has(builtin)) { // new Set(iterable)
|
||||
const arg_valid = args.length === 0 || arg1 instanceof AST_Array;
|
||||
if (!arg_valid) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user