6.7.0 - Alpha8 - 新增 cvt/fmt 模块及 (cvt/fmt/s13n).bytes 方法, 用于字节数据处理
This commit is contained in:
@@ -3,8 +3,13 @@
|
|||||||
"v6.7.0": {
|
"v6.7.0": {
|
||||||
"released_date": "2025/10/26",
|
"released_date": "2025/10/26",
|
||||||
"feature": [
|
"feature": [
|
||||||
|
"cvt 模块, 用于数据单位转换 (参阅 项目文档 > [单位转换](https://docs.autojs6.com/#/cvt))",
|
||||||
|
"fmt 模块, 用于数据格式化 (参阅 项目文档 > [格式化](https://docs.autojs6.com/#/fmt))",
|
||||||
"zip 模块, 用于文件压缩与解压缩操作 (Ref to [Auto.js Pro](https://g.pro.autojs.org/)) (参阅 项目文档 > [Zip](https://docs.autojs6.com/#/zip))",
|
"zip 模块, 用于文件压缩与解压缩操作 (Ref to [Auto.js Pro](https://g.pro.autojs.org/)) (参阅 项目文档 > [Zip](https://docs.autojs6.com/#/zip))",
|
||||||
"mediainfo 模块, 用于查看媒体文件的详细信息 (参阅 项目文档 > [媒体信息](https://docs.autojs6.com/#/mediainfo))",
|
"mediainfo 模块, 用于查看媒体文件的详细信息 (参阅 项目文档 > [媒体信息](https://docs.autojs6.com/#/mediainfo))",
|
||||||
|
"cvt.bytes 方法, 用于字节数据单位转换 (参阅 项目文档 > [单位转换](https://docs.autojs6.com/#/cvt))",
|
||||||
|
"fmt.bytes 方法, 用于字节数据格式化 (参阅 项目文档 > [数据格式化](https://docs.autojs6.com/#/fmt))",
|
||||||
|
"s13n.bytes 方法, 用于标准化字节数据 (参阅 项目文档 > [标准化](https://docs.autojs6.com/#/s13n))",
|
||||||
"UiObject#isShifted 方法, 用于检测控件位置变化",
|
"UiObject#isShifted 方法, 用于检测控件位置变化",
|
||||||
"device.getSharedDeviceId 方法, 用于跨应用获取统一共享设备 ID _[`issue #455`](http://issues.autojs6.com/455)_",
|
"device.getSharedDeviceId 方法, 用于跨应用获取统一共享设备 ID _[`issue #455`](http://issues.autojs6.com/455)_",
|
||||||
"structuredClone 全局方法, 用于深拷贝 JavaScript 对象 (参阅 [MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/structuredClone))",
|
"structuredClone 全局方法, 用于深拷贝 JavaScript 对象 (参阅 [MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/structuredClone))",
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import org.mozilla.javascript.NativeError
|
|||||||
import org.mozilla.javascript.Scriptable
|
import org.mozilla.javascript.Scriptable
|
||||||
import org.mozilla.javascript.UniqueTag.NOT_FOUND
|
import org.mozilla.javascript.UniqueTag.NOT_FOUND
|
||||||
import org.mozilla.javascript.Wrapper
|
import org.mozilla.javascript.Wrapper
|
||||||
|
import java.math.BigInteger
|
||||||
|
|
||||||
object AnyExtensions {
|
object AnyExtensions {
|
||||||
|
|
||||||
@@ -82,8 +83,8 @@ object AnyExtensions {
|
|||||||
fun <T> T?.jsSanitize() = if (this.isJsNullish()) null else this
|
fun <T> T?.jsSanitize() = if (this.isJsNullish()) null else this
|
||||||
|
|
||||||
fun Any?.jsUnwrapped(): Any? = when (this) {
|
fun Any?.jsUnwrapped(): Any? = when (this) {
|
||||||
is String -> this
|
is String, is ConsString -> Context.toString(this)
|
||||||
is ConsString -> this.toString()
|
is BigInteger -> this
|
||||||
is Number -> Context.toNumber(this)
|
is Number -> Context.toNumber(this)
|
||||||
is Boolean -> Context.toBoolean(this)
|
is Boolean -> Context.toBoolean(this)
|
||||||
is Wrapper -> this.unwrap().jsUnwrapped()
|
is Wrapper -> this.unwrap().jsUnwrapped()
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import android.content.Context
|
|||||||
import android.content.res.AssetManager
|
import android.content.res.AssetManager
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import org.autojs.autojs.app.GlobalAppContext
|
import org.autojs.autojs.app.GlobalAppContext
|
||||||
import org.autojs.autojs.core.pref.Language
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes
|
||||||
import org.autojs.autojs.tool.Func1
|
import org.autojs.autojs.tool.Func1
|
||||||
import org.autojs.autojs.util.EnvironmentUtils
|
import org.autojs.autojs.util.EnvironmentUtils
|
||||||
import org.autojs.autojs.util.FileUtils
|
import org.autojs.autojs.util.FileUtils
|
||||||
@@ -19,8 +19,6 @@ import java.io.IOException
|
|||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
import kotlin.math.ln
|
|
||||||
import kotlin.math.pow
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Stardust on Apr 1, 2017.
|
* Created by Stardust on Apr 1, 2017.
|
||||||
@@ -60,14 +58,9 @@ object PFiles {
|
|||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun create(path: String): Boolean {
|
fun create(path: String): Boolean {
|
||||||
val f = File(path)
|
val f = File(path)
|
||||||
return if (path.endsWith(separator)) {
|
return when {
|
||||||
f.mkdir()
|
path.endsWith(separator) -> f.mkdir()
|
||||||
} else {
|
else -> runCatching { f.createNewFile() }.isSuccess
|
||||||
try {
|
|
||||||
f.createNewFile()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +88,7 @@ object PFiles {
|
|||||||
fun ensureDir(path: String): Boolean {
|
fun ensureDir(path: String): Boolean {
|
||||||
val i = path.lastIndexOf(separator)
|
val i = path.lastIndexOf(separator)
|
||||||
return if (i >= 0) {
|
return if (i >= 0) {
|
||||||
val folder = path.substring(0, i)
|
val folder = path.take(i)
|
||||||
val file = File(folder)
|
val file = File(folder)
|
||||||
file.exists() || file.mkdirs()
|
file.exists() || file.mkdirs()
|
||||||
} else false
|
} else false
|
||||||
@@ -355,7 +348,7 @@ object PFiles {
|
|||||||
val fileName = getName(filePath)
|
val fileName = getName(filePath)
|
||||||
var b = fileName.lastIndexOf('.')
|
var b = fileName.lastIndexOf('.')
|
||||||
if (b < 0) b = fileName.length
|
if (b < 0) b = fileName.length
|
||||||
return fileName.substring(0, b)
|
return fileName.take(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun copyAssetToTmpFile(context: Context, path: String): File {
|
fun copyAssetToTmpFile(context: Context, path: String): File {
|
||||||
@@ -450,14 +443,18 @@ object PFiles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getHumanReadableSize(bytes: Long): String {
|
@JvmOverloads
|
||||||
val unit = 1024
|
fun getHumanReadableSize(bytes: Long, useIecIdentifier: Boolean = false): String {
|
||||||
if (bytes < unit) return "$bytes B"
|
return Bytes.string(
|
||||||
val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt()
|
source = bytes.toDouble(),
|
||||||
|
fromUnit = "B",
|
||||||
@Suppress("SpellCheckingInspection")
|
toUnit = "AUTO",
|
||||||
val pre = "KMGTPE".substring(exp - 1, exp)
|
useIecIdentifier = useIecIdentifier,
|
||||||
return String.format(Language.getPrefLanguage().locale, "%.1f %sB", bytes / unit.toDouble().pow(exp.toDouble()), pre)
|
useSpace = true,
|
||||||
|
fractionDigits = 1,
|
||||||
|
trimTrailingZero = false,
|
||||||
|
signature = "PFiles.getHumanReadableSize",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@@ -511,10 +508,6 @@ object PFiles {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun closeSilently(closeable: Closeable?) {
|
fun closeSilently(closeable: Closeable?) {
|
||||||
try {
|
runCatching { closeable?.close() }
|
||||||
closeable?.close()
|
|
||||||
} catch (ignored: IOException) {
|
|
||||||
/* Ignored. */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -44,6 +44,7 @@ import org.autojs.autojs.runtime.api.augment.colors.Color
|
|||||||
import org.autojs.autojs.runtime.api.augment.colors.Colors
|
import org.autojs.autojs.runtime.api.augment.colors.Colors
|
||||||
import org.autojs.autojs.runtime.api.augment.console.Console
|
import org.autojs.autojs.runtime.api.augment.console.Console
|
||||||
import org.autojs.autojs.runtime.api.augment.continuation.Continuation
|
import org.autojs.autojs.runtime.api.augment.continuation.Continuation
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.Converter
|
||||||
import org.autojs.autojs.runtime.api.augment.cryptyo.Crypto
|
import org.autojs.autojs.runtime.api.augment.cryptyo.Crypto
|
||||||
import org.autojs.autojs.runtime.api.augment.device.Device
|
import org.autojs.autojs.runtime.api.augment.device.Device
|
||||||
import org.autojs.autojs.runtime.api.augment.dialogs.Dialogs
|
import org.autojs.autojs.runtime.api.augment.dialogs.Dialogs
|
||||||
@@ -52,6 +53,7 @@ import org.autojs.autojs.runtime.api.augment.events.Events
|
|||||||
import org.autojs.autojs.runtime.api.augment.events.Keys
|
import org.autojs.autojs.runtime.api.augment.events.Keys
|
||||||
import org.autojs.autojs.runtime.api.augment.files.Files
|
import org.autojs.autojs.runtime.api.augment.files.Files
|
||||||
import org.autojs.autojs.runtime.api.augment.floaty.Floaty
|
import org.autojs.autojs.runtime.api.augment.floaty.Floaty
|
||||||
|
import org.autojs.autojs.runtime.api.augment.formatter.Formatter
|
||||||
import org.autojs.autojs.runtime.api.augment.global.Global
|
import org.autojs.autojs.runtime.api.augment.global.Global
|
||||||
import org.autojs.autojs.runtime.api.augment.global.GlobalClasses
|
import org.autojs.autojs.runtime.api.augment.global.GlobalClasses
|
||||||
import org.autojs.autojs.runtime.api.augment.global.IsNullish
|
import org.autojs.autojs.runtime.api.augment.global.IsNullish
|
||||||
@@ -160,6 +162,8 @@ import org.autojs.autojs.runtime.api.Toaster as ApiToaster
|
|||||||
import org.autojs.autojs.runtime.api.UI as ApiUI
|
import org.autojs.autojs.runtime.api.UI as ApiUI
|
||||||
import org.autojs.autojs.runtime.api.Util as ApiUtil
|
import org.autojs.autojs.runtime.api.Util as ApiUtil
|
||||||
import org.autojs.autojs.runtime.api.augment.autojs.Version as AutojsVersion
|
import org.autojs.autojs.runtime.api.augment.autojs.Version as AutojsVersion
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.Bytes as BytesCvt
|
||||||
|
import org.autojs.autojs.runtime.api.augment.formatter.Bytes as BytesFmt
|
||||||
import org.autojs.autojs.runtime.api.augment.global.Legacy as GlobalLegacy
|
import org.autojs.autojs.runtime.api.augment.global.Legacy as GlobalLegacy
|
||||||
import org.autojs.autojs.runtime.api.augment.notice.Channel as NoticeChannel
|
import org.autojs.autojs.runtime.api.augment.notice.Channel as NoticeChannel
|
||||||
import org.autojs.autojs.runtime.api.augment.util.Inspect as UtilInspect
|
import org.autojs.autojs.runtime.api.augment.util.Inspect as UtilInspect
|
||||||
@@ -714,20 +718,20 @@ class ScriptRuntime private constructor(builder: Builder) {
|
|||||||
|
|
||||||
private fun augment(target: ScriptableObject) {
|
private fun augment(target: ScriptableObject) {
|
||||||
|
|
||||||
Global(this).assignWithGlobal(target, topLevelScope, GlobalClasses)
|
Global(this).assignWithRuntime(target, this, GlobalClasses)
|
||||||
GlobalLegacy(this).assignWithGlobal(target, topLevelScope)
|
GlobalLegacy(this).assignWithRuntime(target, this)
|
||||||
IsNullish.augmentWithGlobal(target, topLevelScope, false)
|
IsNullish.augmentWithRuntime(target, this, false)
|
||||||
Util.augmentWithGlobal(target, topLevelScope, util, true).apply {
|
Util.augmentWithRuntime(target, this, util, true).also { util ->
|
||||||
UtilJava.augmentWithGlobal(this, topLevelScope, false)
|
UtilJava.augmentWithRuntime(util, this, false)
|
||||||
UtilVersion.augmentWithGlobal(this, topLevelScope, false)
|
UtilVersion.augmentWithRuntime(util, this, false)
|
||||||
UtilVersionCodes.augmentWithGlobal(this, topLevelScope, VersionCodesInfo.obj, false)
|
UtilVersionCodes.augmentWithRuntime(util, this, VersionCodesInfo.obj, false)
|
||||||
UtilInspect.augmentWithGlobal(this, topLevelScope, false)
|
UtilInspect.augmentWithRuntime(util, this, false)
|
||||||
UtilMorseCode.augmentWithGlobal(this, topLevelScope, false)
|
UtilMorseCode.augmentWithRuntime(util, this, false)
|
||||||
}
|
}
|
||||||
Species.augmentWithGlobal(target, topLevelScope, true)
|
Species.augmentWithRuntime(target, this, true)
|
||||||
App(this).augment(target, app, true).also { augmentedApp = it }
|
App(this).augment(target, app, true).also { augmentedApp = it }
|
||||||
Autojs(this).augment(target, true).also { augmentedAutojs = it }.apply {
|
Autojs(this).augment(target, true).also { augmentedAutojs = it }.also { autojs ->
|
||||||
AutojsVersion.augmentWithGlobal(this, topLevelScope, false)
|
AutojsVersion.augmentWithRuntime(autojs, this, false)
|
||||||
}
|
}
|
||||||
Shell(this).augment(target, true)
|
Shell(this).augment(target, true)
|
||||||
Timers(this).augment(target, timers, true)
|
Timers(this).augment(target, timers, true)
|
||||||
@@ -735,26 +739,32 @@ class ScriptRuntime private constructor(builder: Builder) {
|
|||||||
Automator(this).augment(target, true)
|
Automator(this).augment(target, true)
|
||||||
Selector(this).augment(target, true, READONLY)
|
Selector(this).augment(target, true, READONLY)
|
||||||
Events(this).augment(target, events, true)
|
Events(this).augment(target, events, true)
|
||||||
Keys.augmentWithGlobal(target, topLevelScope, true)
|
Keys.augmentWithRuntime(target, this, true)
|
||||||
Images(this).augment(target, true)
|
Images(this).augment(target, true)
|
||||||
Ocr(this).augment(target, true).apply {
|
Ocr(this).augment(target, true).also { ocr ->
|
||||||
OcrMLKit(this@ScriptRuntime).augment(this, false).also { augmentedOcrMLKit = it }
|
OcrMLKit(this).augment(ocr, false).also { augmentedOcrMLKit = it }
|
||||||
OcrPaddle(this@ScriptRuntime).augment(this, false).also { augmentedOcrPaddle = it }
|
OcrPaddle(this).augment(ocr, false).also { augmentedOcrPaddle = it }
|
||||||
OcrRapid(this@ScriptRuntime).augment(this, false).also { augmentedOcrRapid = it }
|
OcrRapid(this).augment(ocr, false).also { augmentedOcrRapid = it }
|
||||||
}
|
}
|
||||||
Barcode(this).augment(target, true)
|
Barcode(this).augment(target, true)
|
||||||
QrCode(this).augment(target, true)
|
QrCode(this).augment(target, true)
|
||||||
Threads(this).augment(target, threads, true)
|
Threads(this).augment(target, threads, true)
|
||||||
UI(this).proxying(target, ui, true)
|
UI(this).proxying(target, ui, true)
|
||||||
Colors.augmentWithGlobal(target, topLevelScope, listOf(colors, Colors), true)
|
Colors.augmentWithRuntime(target, this, listOf(colors, Colors), true)
|
||||||
Color.augmentWithGlobal(target, topLevelScope, false)
|
Color.augmentWithRuntime(target, this, false)
|
||||||
Tasks(this).augment(target, true)
|
Tasks(this).augment(target, true)
|
||||||
Dialogs(this).augment(target, true)
|
Dialogs(this).augment(target, true)
|
||||||
Continuation(this).augment(target, js_mod_continuation, true, READONLY)
|
Continuation(this).augment(target, js_mod_continuation, true, READONLY)
|
||||||
Http(this).augment(target, http, true)
|
Http(this).augment(target, http, true)
|
||||||
Web(this).augment(target, true)
|
Web(this).augment(target, true)
|
||||||
WebSocket(this).augment(target, WebSocketFields, false)
|
WebSocket(this).augment(target, WebSocketFields, false)
|
||||||
S13n.augmentWithGlobal(target, topLevelScope, true)
|
S13n.augmentWithRuntime(target, this, true)
|
||||||
|
Converter.augmentWithRuntime(target, this, true).also { cvt ->
|
||||||
|
BytesCvt.augmentWithRuntime(cvt, this, false)
|
||||||
|
}
|
||||||
|
Formatter.augmentWithRuntime(target, this, true).also { fmt ->
|
||||||
|
BytesFmt.augmentWithRuntime(fmt, this, false)
|
||||||
|
}
|
||||||
Console(this).proxying(target, console, true).also { consoleProxyObject = it }
|
Console(this).proxying(target, console, true).also { consoleProxyObject = it }
|
||||||
Plugins(this).augment(target, true)
|
Plugins(this).augment(target, true)
|
||||||
Arrayx(this).augment(target, false)
|
Arrayx(this).augment(target, false)
|
||||||
@@ -762,29 +772,29 @@ class ScriptRuntime private constructor(builder: Builder) {
|
|||||||
Mathx(this).augment(target, false)
|
Mathx(this).augment(target, false)
|
||||||
Jsox(this).augment(target, true)
|
Jsox(this).augment(target, true)
|
||||||
Files(this).augment(target, files, true)
|
Files(this).augment(target, files, true)
|
||||||
Crypto.augmentWithGlobal(target, topLevelScope, CoreCrypto, true)
|
Crypto.augmentWithRuntime(target, this, CoreCrypto, true)
|
||||||
RootAutomator(this).augment(target, false)
|
RootAutomator(this).augment(target, false)
|
||||||
Engines(this).augment(target, true)
|
Engines(this).augment(target, true)
|
||||||
Floaty(this).augment(target, true)
|
Floaty(this).augment(target, true)
|
||||||
Storages.augmentWithGlobal(target, topLevelScope, true)
|
Storages.augmentWithRuntime(target, this, true)
|
||||||
Device(this).augment(target, device, true)
|
Device(this).augment(target, device, true)
|
||||||
Recorder(this).augment(target, recorder, true)
|
Recorder(this).augment(target, recorder, true)
|
||||||
Toast(this).augment(target, true)
|
Toast(this).augment(target, true)
|
||||||
Media.augmentWithGlobal(target, topLevelScope, media, true)
|
Media.augmentWithRuntime(target, this, media, true)
|
||||||
Sensors.augmentWithGlobal(target, topLevelScope, sensors, true)
|
Sensors.augmentWithRuntime(target, this, sensors, true)
|
||||||
Base64.augmentWithGlobal(target, topLevelScope, true)
|
Base64.augmentWithRuntime(target, this, true)
|
||||||
Notice(this).augment(target, true).apply {
|
Notice(this).augment(target, true).also { notice ->
|
||||||
NoticeChannel(this@ScriptRuntime).augment(this, false)
|
NoticeChannel(this).augment(notice, false)
|
||||||
}
|
}
|
||||||
Shizuku(this).augment(target, shizuku, true)
|
Shizuku(this).augment(target, shizuku, true)
|
||||||
OpenCC.augmentWithGlobal(target, topLevelScope, true)
|
OpenCC.augmentWithRuntime(target, this, true)
|
||||||
Mime(this).augment(target, mime, true)
|
Mime(this).augment(target, mime, true)
|
||||||
SysProps(this).augment(target, true)
|
SysProps(this).augment(target, true)
|
||||||
SQLite(this).augment(target, true)
|
SQLite(this).augment(target, true)
|
||||||
Zip(this).augment(target, true)
|
Zip(this).augment(target, true)
|
||||||
NanoID.augmentWithGlobal(target, topLevelScope, true)
|
NanoID.augmentWithRuntime(target, this, true)
|
||||||
Pinyin.augmentWithGlobal(target, topLevelScope, true)
|
Pinyin.augmentWithRuntime(target, this, true)
|
||||||
Pinyin4j.augmentWithGlobal(target, topLevelScope, true)
|
Pinyin4j.augmentWithRuntime(target, this, true)
|
||||||
Mediainfo(this).augment(target, true)
|
Mediainfo(this).augment(target, true)
|
||||||
|
|
||||||
augmentedApp.defineProp(Autojs::class.java.simpleName.lowercase(), augmentedAutojs)
|
augmentedApp.defineProp(Autojs::class.java.simpleName.lowercase(), augmentedAutojs)
|
||||||
|
|||||||
@@ -192,8 +192,9 @@ class Files(private val scriptRuntime: ScriptRuntime) {
|
|||||||
return PFiles.isEmptyDir(path(path))
|
return PFiles.isEmptyDir(path(path))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getHumanReadableSize(bytes: Long): String {
|
@JvmOverloads
|
||||||
return PFiles.getHumanReadableSize(bytes)
|
fun getHumanReadableSize(bytes: Long, useIecIdentifier: Boolean = false): String {
|
||||||
|
return PFiles.getHumanReadableSize(bytes, useIecIdentifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSimplifiedPath(path: String?): String {
|
fun getSimplifiedPath(path: String?): String {
|
||||||
|
|||||||
@@ -138,19 +138,19 @@ abstract class Augmentable(private val scriptRuntime: ScriptRuntime? = null) : F
|
|||||||
|
|
||||||
fun originateKeyName() = also { mIsOriginalKeyName = true }
|
fun originateKeyName() = also { mIsOriginalKeyName = true }
|
||||||
|
|
||||||
fun augmentWithGlobal(target: Scriptable, specifiedGlobal: ScriptableObject, withDollarPrefix: Boolean = true, additionalAttributes: Int = 0): ScriptableObject {
|
fun augmentWithRuntime(target: Scriptable, specifiedRuntime: ScriptRuntime, withDollarPrefix: Boolean = true, additionalAttributes: Int = 0): ScriptableObject {
|
||||||
return augment(target, withDollarPrefix, additionalAttributes, specifiedGlobal)
|
return augment(target, withDollarPrefix, additionalAttributes, specifiedRuntime)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun augmentWithGlobal(target: Scriptable, specifiedGlobal: ScriptableObject, proto: Any, withDollarPrefix: Boolean = true, additionalAttributes: Int = 0): ScriptableObject {
|
fun augmentWithRuntime(target: Scriptable, specifiedRuntime: ScriptRuntime, proto: Any, withDollarPrefix: Boolean = true, additionalAttributes: Int = 0): ScriptableObject {
|
||||||
return augment(target, proto, withDollarPrefix, additionalAttributes, specifiedGlobal)
|
return augment(target, proto, withDollarPrefix, additionalAttributes, specifiedRuntime)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun augment(target: Scriptable, withDollarPrefix: Boolean = true, additionalAttributes: Int = 0, specifiedGlobal: ScriptableObject? = null): ScriptableObject {
|
fun augment(target: Scriptable, withDollarPrefix: Boolean = true, additionalAttributes: Int = 0, specifiedRuntime: ScriptRuntime? = null): ScriptableObject {
|
||||||
return augment(target, emptyList<Any>(), withDollarPrefix, additionalAttributes, specifiedGlobal)
|
return augment(target, emptyList<Any>(), withDollarPrefix, additionalAttributes, specifiedRuntime)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun augment(target: Scriptable, proto: Any, withDollarPrefix: Boolean = true, additionalAttributes: Int = 0, specifiedGlobal: ScriptableObject? = null): ScriptableObject {
|
fun augment(target: Scriptable, proto: Any, withDollarPrefix: Boolean = true, additionalAttributes: Int = 0, specifiedRuntime: ScriptRuntime? = null): ScriptableObject {
|
||||||
val callFunc: (args: Array<out Any?>) -> Any? = { args ->
|
val callFunc: (args: Array<out Any?>) -> Any? = { args ->
|
||||||
try {
|
try {
|
||||||
(this as Invokable).invoke(*args)
|
(this as Invokable).invoke(*args)
|
||||||
@@ -191,7 +191,7 @@ abstract class Augmentable(private val scriptRuntime: ScriptRuntime? = null) : F
|
|||||||
else -> RhinoUtils.newObject(target)
|
else -> RhinoUtils.newObject(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
assign(newObj, proto, specifiedGlobal)
|
assign(newObj, proto, specifiedRuntime)
|
||||||
|
|
||||||
val keys = mutableListOf(key)
|
val keys = mutableListOf(key)
|
||||||
if (withDollarPrefix) keys += "\$$key"
|
if (withDollarPrefix) keys += "\$$key"
|
||||||
@@ -203,17 +203,17 @@ abstract class Augmentable(private val scriptRuntime: ScriptRuntime? = null) : F
|
|||||||
return newObj
|
return newObj
|
||||||
}
|
}
|
||||||
|
|
||||||
fun assignWithGlobal(target: ScriptableObject, specifiedGlobal: ScriptableObject, proto: Any? = null) {
|
fun assignWithRuntime(target: ScriptableObject, specifiedRuntime: ScriptRuntime, proto: Any? = null) {
|
||||||
assign(target, proto, specifiedGlobal)
|
assign(target, proto, specifiedRuntime)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the subclass calls assign, the value of key will be ignored.
|
* When the subclass calls assign, the value of key will be ignored.
|
||||||
* zh-CN: 子类调用 assign 时将忽略 key 的值.
|
* zh-CN: 子类调用 assign 时将忽略 key 的值.
|
||||||
*/
|
*/
|
||||||
fun assign(target: ScriptableObject, proto: Any? = null, specifiedGlobal: ScriptableObject? = null) {
|
fun assign(target: ScriptableObject, proto: Any? = null, specifiedRuntime: ScriptRuntime? = null) {
|
||||||
|
|
||||||
val global: ScriptableObject = specifiedGlobal ?: scriptRuntime?.topLevelScope ?: ScriptableObject.getTopLevelScope(target) as ScriptableObject
|
val global: ScriptableObject = (specifiedRuntime ?: scriptRuntime)?.topLevelScope ?: ScriptableObject.getTopLevelScope(target) as ScriptableObject
|
||||||
|
|
||||||
val protos = when (proto) {
|
val protos = when (proto) {
|
||||||
null -> emptyList()
|
null -> emptyList()
|
||||||
|
|||||||
@@ -40,7 +40,13 @@ import org.autojs.autojs.util.RhinoUtils.withRhinoContext
|
|||||||
import org.autojs.autojs.util.StringUtils.lowercaseFirstChar
|
import org.autojs.autojs.util.StringUtils.lowercaseFirstChar
|
||||||
import org.autojs.autojs.util.StringUtils.uppercaseFirstChar
|
import org.autojs.autojs.util.StringUtils.uppercaseFirstChar
|
||||||
import org.autojs.autojs6.R
|
import org.autojs.autojs6.R
|
||||||
import org.mozilla.javascript.*
|
import org.mozilla.javascript.BaseFunction
|
||||||
|
import org.mozilla.javascript.Context
|
||||||
|
import org.mozilla.javascript.NativeArray
|
||||||
|
import org.mozilla.javascript.NativeError
|
||||||
|
import org.mozilla.javascript.NativeObject
|
||||||
|
import org.mozilla.javascript.ScriptableObject
|
||||||
|
import org.mozilla.javascript.Undefined
|
||||||
|
|
||||||
@Suppress("unused", "UNUSED_PARAMETER")
|
@Suppress("unused", "UNUSED_PARAMETER")
|
||||||
class Console(scriptRuntime: ScriptRuntime) : AugmentableProxy(scriptRuntime) {
|
class Console(scriptRuntime: ScriptRuntime) : AugmentableProxy(scriptRuntime) {
|
||||||
@@ -226,38 +232,38 @@ class Console(scriptRuntime: ScriptRuntime) : AugmentableProxy(scriptRuntime) {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@RhinoRuntimeFunctionInterface
|
@RhinoRuntimeFunctionInterface
|
||||||
fun log(scriptRuntime: ScriptRuntime, args: Array<out Any?>) = unwrapArguments(args) {
|
fun log(scriptRuntime: ScriptRuntime, args: Array<out Any?>) {
|
||||||
scriptRuntime.console.log(Util.formatRhino(*it))
|
return scriptRuntime.console.log(Util.formatRhino(*args))
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@RhinoRuntimeFunctionInterface
|
@RhinoRuntimeFunctionInterface
|
||||||
fun verbose(scriptRuntime: ScriptRuntime, args: Array<out Any?>) = unwrapArguments(args) {
|
fun verbose(scriptRuntime: ScriptRuntime, args: Array<out Any?>) {
|
||||||
scriptRuntime.console.verbose(Util.formatRhino(*it))
|
return scriptRuntime.console.verbose(Util.formatRhino(*args))
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@RhinoRuntimeFunctionInterface
|
@RhinoRuntimeFunctionInterface
|
||||||
fun info(scriptRuntime: ScriptRuntime, args: Array<out Any?>) = unwrapArguments(args) {
|
fun info(scriptRuntime: ScriptRuntime, args: Array<out Any?>) {
|
||||||
scriptRuntime.console.info(Util.formatRhino(*it))
|
return scriptRuntime.console.info(Util.formatRhino(*args))
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@RhinoRuntimeFunctionInterface
|
@RhinoRuntimeFunctionInterface
|
||||||
fun warn(scriptRuntime: ScriptRuntime, args: Array<out Any?>) = unwrapArguments(args) {
|
fun warn(scriptRuntime: ScriptRuntime, args: Array<out Any?>) {
|
||||||
scriptRuntime.console.warn(Util.formatRhino(*it))
|
return scriptRuntime.console.warn(Util.formatRhino(*args))
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@RhinoRuntimeFunctionInterface
|
@RhinoRuntimeFunctionInterface
|
||||||
fun error(scriptRuntime: ScriptRuntime, args: Array<out Any?>) = unwrapArguments(args) {
|
fun error(scriptRuntime: ScriptRuntime, args: Array<out Any?>) {
|
||||||
scriptRuntime.console.error(Util.formatRhino(*it))
|
return scriptRuntime.console.error(Util.formatRhino(*args))
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@RhinoRuntimeFunctionInterface
|
@RhinoRuntimeFunctionInterface
|
||||||
fun print(scriptRuntime: ScriptRuntime, args: Array<out Any?>) = unwrapArguments(args) {
|
fun print(scriptRuntime: ScriptRuntime, args: Array<out Any?>) {
|
||||||
scriptRuntime.console.print(Log.DEBUG, Util.formatRhino(*it))
|
return scriptRuntime.console.print(Log.DEBUG, Util.formatRhino(*args))
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
|||||||
@@ -0,0 +1,215 @@
|
|||||||
|
@file:Suppress("MayBeConstant")
|
||||||
|
|
||||||
|
package org.autojs.autojs.runtime.api.augment.converter
|
||||||
|
|
||||||
|
import org.autojs.autojs.annotation.RhinoSingletonFunctionInterface
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.isJsBoolean
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.isJsNullish
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.isJsNumber
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.isJsObject
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.isJsString
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.jsBrief
|
||||||
|
import org.autojs.autojs.extension.ScriptableObjectExtensions.inquire
|
||||||
|
import org.autojs.autojs.runtime.api.augment.Augmentable
|
||||||
|
import org.autojs.autojs.runtime.api.augment.Invokable
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.AUTO
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.DEFAULT_BYTES_STRICT
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.IEC_DIV
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.SI_DIV
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.Tough
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.Tough.LOOSE
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.Tough.NONE
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.Tough.STRICT
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.UNITS
|
||||||
|
import org.autojs.autojs.util.RhinoUtils.coerceBoolean
|
||||||
|
import org.mozilla.javascript.ScriptableObject
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes as CoreBytes
|
||||||
|
|
||||||
|
object Bytes : Augmentable(), Invokable {
|
||||||
|
|
||||||
|
override val selfAssignmentProperties = listOf(
|
||||||
|
"UNITS" to UNITS,
|
||||||
|
"AUTO" to AUTO,
|
||||||
|
"IEC_DIV" to IEC_DIV,
|
||||||
|
"SI_DIV" to SI_DIV,
|
||||||
|
)
|
||||||
|
|
||||||
|
override val selfAssignmentFunctions = listOf(
|
||||||
|
::strict.name,
|
||||||
|
::loose.name,
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun invoke(vararg args: Any?): Any = ensureArgumentsLengthInRange(args, 1..4) { call(args) }
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@RhinoSingletonFunctionInterface
|
||||||
|
fun call(args: Array<out Any?>, tough: Tough = NONE): Any = ensureArgumentsLengthInRange(args, 1..4) { argList ->
|
||||||
|
val (arg0, arg1, arg2, arg3) = argList
|
||||||
|
|
||||||
|
when (argList.size) {
|
||||||
|
4 -> when {
|
||||||
|
arg3.isJsObject() -> {
|
||||||
|
val opts = arg3 as ScriptableObject
|
||||||
|
listOf("source", "fromUnit", "toUnit", "options").forBytesNumber(
|
||||||
|
source = arg0,
|
||||||
|
fromUnit = opts.inquire("fromUnit", arg1),
|
||||||
|
toUnit = opts.inquire("toUnit", arg2),
|
||||||
|
fractionDigits = opts.inquire("fractionDigits"),
|
||||||
|
autoCarryThreshold = opts.inquire("autoCarryThreshold"),
|
||||||
|
strict = opts.inquire("strict"),
|
||||||
|
tough = tough,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg3.isJsBoolean() -> {
|
||||||
|
listOf("source", "fromUnit", "toUnit", "useIecIdentifier").forBytesNumber(
|
||||||
|
source = arg0,
|
||||||
|
fromUnit = arg1,
|
||||||
|
toUnit = arg2,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg3.isJsNumber() -> {
|
||||||
|
listOf("source", "fromUnit", "toUnit", "fractionDigits").forBytesNumber(
|
||||||
|
source = arg0,
|
||||||
|
fromUnit = arg1,
|
||||||
|
toUnit = arg2,
|
||||||
|
fractionDigits = arg3,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> throw IllegalArgumentException("Invalid argument[3] ${arg3.jsBrief()} for ${Converter.key}.bytes")
|
||||||
|
}
|
||||||
|
3 -> when {
|
||||||
|
arg2.isJsObject() -> {
|
||||||
|
val opts = arg2 as ScriptableObject
|
||||||
|
listOf("source", "toUnit", "options").forBytesNumber(
|
||||||
|
source = arg0,
|
||||||
|
fromUnit = opts.inquire("fromUnit"),
|
||||||
|
toUnit = opts.inquire("toUnit", arg1),
|
||||||
|
fractionDigits = opts.inquire("fractionDigits"),
|
||||||
|
autoCarryThreshold = opts.inquire("autoCarryThreshold"),
|
||||||
|
strict = opts.inquire("strict"),
|
||||||
|
tough = tough,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg2.isJsString() -> {
|
||||||
|
listOf("source", "fromUnit", "toUnit").forBytesNumber(
|
||||||
|
source = arg0,
|
||||||
|
fromUnit = arg1,
|
||||||
|
toUnit = arg2,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg2.isJsBoolean() -> {
|
||||||
|
listOf("source", "toUnit", "useIecIdentifier").forBytesNumber(
|
||||||
|
source = arg0,
|
||||||
|
toUnit = arg1,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg2.isJsNumber() -> {
|
||||||
|
listOf("source", "toUnit", "fractionDigits").forBytesNumber(
|
||||||
|
source = arg0,
|
||||||
|
toUnit = arg1,
|
||||||
|
fractionDigits = arg2,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> throw IllegalArgumentException("Invalid argument[2] ${arg2.jsBrief()} for ${Converter.key}.bytes")
|
||||||
|
}
|
||||||
|
2 -> when {
|
||||||
|
arg1.isJsObject() -> {
|
||||||
|
val opts = arg1 as ScriptableObject
|
||||||
|
listOf("source", "options").forBytesNumber(
|
||||||
|
source = arg0,
|
||||||
|
fromUnit = opts.inquire("fromUnit"),
|
||||||
|
toUnit = opts.inquire("toUnit"),
|
||||||
|
fractionDigits = opts.inquire("fractionDigits"),
|
||||||
|
autoCarryThreshold = opts.inquire("autoCarryThreshold"),
|
||||||
|
strict = opts.inquire("strict"),
|
||||||
|
tough = tough,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg1.isJsString() -> {
|
||||||
|
listOf("source", "toUnit").forBytesNumber(
|
||||||
|
source = arg0,
|
||||||
|
toUnit = arg1,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg1.isJsBoolean() -> {
|
||||||
|
listOf("source", "useIecIdentifier").forBytesNumber(
|
||||||
|
source = arg0,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg1.isJsNumber() -> {
|
||||||
|
listOf("source", "fractionDigits").forBytesNumber(
|
||||||
|
source = arg0,
|
||||||
|
fractionDigits = arg1,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> throw IllegalArgumentException("Invalid argument[1] ${arg1.jsBrief()} for ${Converter.key}.bytes")
|
||||||
|
}
|
||||||
|
1 -> listOf("source").forBytesNumber(
|
||||||
|
source = arg0,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
else -> throw IllegalArgumentException("Invalid arguments length ${argList.size} for ${Converter.key}.bytes")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@RhinoSingletonFunctionInterface
|
||||||
|
fun strict(args: Array<out Any?>): Any = ensureArgumentsLengthInRange(args, 1..4) {
|
||||||
|
call(args, STRICT)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@RhinoSingletonFunctionInterface
|
||||||
|
fun loose(args: Array<out Any?>): Any = ensureArgumentsLengthInRange(args, 1..4) {
|
||||||
|
call(args, LOOSE)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<String>.forBytesNumber(
|
||||||
|
source: Any? = null,
|
||||||
|
fromUnit: Any? = null,
|
||||||
|
toUnit: Any? = null,
|
||||||
|
fractionDigits: Any? = null,
|
||||||
|
autoCarryThreshold: Any? = null,
|
||||||
|
strict: Any? = null,
|
||||||
|
tough: Tough = NONE,
|
||||||
|
): Any {
|
||||||
|
val (niceStrict, signature) = when (tough) {
|
||||||
|
STRICT -> {
|
||||||
|
val signature = "${Converter.key}.bytes.strict(${this.joinToString(", ")})"
|
||||||
|
require(strict.isJsNullish()) {
|
||||||
|
"Option \"strict\" ${strict.jsBrief()} must be nullish when in strict mode for $signature"
|
||||||
|
}
|
||||||
|
true to signature
|
||||||
|
}
|
||||||
|
LOOSE -> {
|
||||||
|
val signature = "${Converter.key}.bytes.loose(${this.joinToString(", ")})"
|
||||||
|
require(strict.isJsNullish()) {
|
||||||
|
"Option \"strict\" ${strict.jsBrief()} must be nullish when in loose mode for $signature"
|
||||||
|
}
|
||||||
|
false to signature
|
||||||
|
}
|
||||||
|
NONE -> {
|
||||||
|
val signature = "${Converter.key}.bytes(${this.joinToString(", ")})"
|
||||||
|
coerceBoolean(strict, DEFAULT_BYTES_STRICT) to signature
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CoreBytes.numberRhino(
|
||||||
|
source,
|
||||||
|
fromUnit,
|
||||||
|
toUnit,
|
||||||
|
fractionDigits,
|
||||||
|
autoCarryThreshold,
|
||||||
|
niceStrict,
|
||||||
|
signature,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.autojs.autojs.runtime.api.augment.converter
|
||||||
|
|
||||||
|
import org.autojs.autojs.runtime.api.augment.Augmentable
|
||||||
|
|
||||||
|
object Converter : Augmentable() {
|
||||||
|
|
||||||
|
override val key = "cvt"
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,455 @@
|
|||||||
|
@file:Suppress("MayBeConstant")
|
||||||
|
|
||||||
|
package org.autojs.autojs.runtime.api.augment.converter.core
|
||||||
|
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.isJsNullish
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.isJsNumber
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.jsBrief
|
||||||
|
import org.autojs.autojs.util.RhinoUtils.MAX_SAFE_INT_IEEE754_BD
|
||||||
|
import org.autojs.autojs.util.RhinoUtils.MIN_SAFE_INT_IEEE754_BD
|
||||||
|
import org.autojs.autojs.util.RhinoUtils.coerceBoolean
|
||||||
|
import org.autojs.autojs.util.RhinoUtils.coerceIntNumber
|
||||||
|
import org.autojs.autojs.util.RhinoUtils.coerceLongNumber
|
||||||
|
import org.autojs.autojs.util.RhinoUtils.coerceNumber
|
||||||
|
import org.autojs.autojs.util.RhinoUtils.coerceString
|
||||||
|
import org.mozilla.javascript.Context
|
||||||
|
import java.math.BigDecimal
|
||||||
|
import java.math.BigInteger
|
||||||
|
import java.math.RoundingMode
|
||||||
|
import kotlin.Double.Companion.NaN
|
||||||
|
import kotlin.text.RegexOption.IGNORE_CASE
|
||||||
|
|
||||||
|
object Bytes {
|
||||||
|
|
||||||
|
// @formatter:off
|
||||||
|
/**
|
||||||
|
* ```md
|
||||||
|
* | Value | IEC | Term |
|
||||||
|
* |---------|-----|--------------------|
|
||||||
|
* | 1024^1 | KiB | Kibibyte (Kilo) |
|
||||||
|
* | 1024^2 | MiB | Mebibyte (Mega) |
|
||||||
|
* | 1024^3 | GiB | Gibibyte (Giga) |
|
||||||
|
* | 1024^4 | TiB | Tebibyte (Tera) |
|
||||||
|
* | 1024^5 | PiB | Pebibyte (Peta) |
|
||||||
|
* | 1024^6 | EiB | Exbibyte (Exa) |
|
||||||
|
* | 1024^7 | ZiB | Zebibyte (Zetta) |
|
||||||
|
* | 1024^8 | YiB | Yobibyte (Yotta) |
|
||||||
|
* | 1024^9 | RiB | Robibyte (Ronna) |
|
||||||
|
* | 1024^10 | QiB | Quebibyte (Quetta) |
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
@JvmField val UNITS = "KMGTPEZYRQ"
|
||||||
|
@JvmField val AUTO = "AUTO"
|
||||||
|
|
||||||
|
@JvmField val IEC_DIV = 1024L
|
||||||
|
@JvmField val SI_DIV = 1000L
|
||||||
|
|
||||||
|
@JvmField val DEFAULT_BYTES_FROM_UNIT = "B"
|
||||||
|
@JvmField val DEFAULT_BYTES_TO_UNIT = AUTO
|
||||||
|
@JvmField val DEFAULT_BYTES_USE_IEC_IDENTIFIER = false
|
||||||
|
@JvmField val DEFAULT_BYTES_USE_IEC_IDENTIFIER_FOR_STRICT = true
|
||||||
|
@JvmField val DEFAULT_BYTES_USE_SPACE = true
|
||||||
|
@JvmField val DEFAULT_BYTES_FRACTION_DIGITS = 2
|
||||||
|
@JvmField val DEFAULT_BYTES_TRIM_TRAILING_ZERO = false
|
||||||
|
@JvmField val DEFAULT_BYTES_AUTO_CARRY_THRESHOLD = IEC_DIV
|
||||||
|
@JvmField val DEFAULT_BYTES_STRICT = false
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
|
private val BI_IEC = BigInteger.valueOf(IEC_DIV)
|
||||||
|
private val BI_SI = BigInteger.valueOf(SI_DIV)
|
||||||
|
private val POW_IEC = Array(UNITS.length + 1) { i -> BI_IEC.pow(i) }
|
||||||
|
private val POW_SI = Array(UNITS.length + 1) { i -> BI_SI.pow(i) }
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun numberRhino(
|
||||||
|
source: Any? = null, /* Double */
|
||||||
|
fromUnit: Any? = null, /* String */
|
||||||
|
toUnit: Any? = null, /* String */
|
||||||
|
fractionDigits: Any? = null, /* Int */
|
||||||
|
autoCarryThreshold: Any? = null, /* Double */
|
||||||
|
strict: Any? = null, /* Boolean */
|
||||||
|
signature: String? = null,
|
||||||
|
): Any {
|
||||||
|
val r = NumberRetrievalHandler(source, fromUnit, toUnit, fractionDigits, autoCarryThreshold, strict, signature).retrieve()
|
||||||
|
return number(
|
||||||
|
r.niceSource, r.niceFromUnit, r.niceToUnit, r.niceFractionDigits, r.niceAutoCarryThreshold, r.niceStrict, signature ?: "bytes.number",
|
||||||
|
).toJavaScriptBigIntOrNumber()
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun number(
|
||||||
|
source: Double,
|
||||||
|
fromUnit: String = DEFAULT_BYTES_FROM_UNIT,
|
||||||
|
toUnit: String = DEFAULT_BYTES_TO_UNIT,
|
||||||
|
fractionDigits: Int = DEFAULT_BYTES_FRACTION_DIGITS,
|
||||||
|
autoCarryThreshold: Long = DEFAULT_BYTES_AUTO_CARRY_THRESHOLD,
|
||||||
|
strict: Boolean = DEFAULT_BYTES_STRICT,
|
||||||
|
signature: String = "Bytes.number",
|
||||||
|
) = parseArguments(source, fromUnit, toUnit, fractionDigits, autoCarryThreshold, strict, signature).let { (bytesBD, baseBI, toUnit) ->
|
||||||
|
computeNumberValue(bytesBD, baseBI, toUnit, fractionDigits, autoCarryThreshold, strict, signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun stringRhino(
|
||||||
|
source: Any? = null,
|
||||||
|
fromUnit: Any? = null,
|
||||||
|
toUnit: Any? = null,
|
||||||
|
useIecIdentifier: Any? = null,
|
||||||
|
useSpace: Any? = null,
|
||||||
|
fractionDigits: Any? = null,
|
||||||
|
trimTrailingZero: Any? = null,
|
||||||
|
autoCarryThreshold: Any? = null,
|
||||||
|
strict: Any? = null,
|
||||||
|
signature: String? = null,
|
||||||
|
): String {
|
||||||
|
val r = StringRetrievalHandler(source, fromUnit, toUnit, useIecIdentifier, useSpace, fractionDigits, trimTrailingZero, autoCarryThreshold, strict, signature).retrieve()
|
||||||
|
return string(r.niceSource, r.niceFromUnit, r.niceToUnit, r.niceUseIecIdentifier, r.niceUseSpace, r.niceFractionDigits, r.niceTrimTrailingZero, r.niceAutoCarryThreshold, r.niceStrict, signature ?: "bytes.string")
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
fun string(
|
||||||
|
source: Double,
|
||||||
|
fromUnit: String = DEFAULT_BYTES_FROM_UNIT,
|
||||||
|
toUnit: String = DEFAULT_BYTES_TO_UNIT,
|
||||||
|
useIecIdentifier: Boolean? = null,
|
||||||
|
useSpace: Boolean = DEFAULT_BYTES_USE_SPACE,
|
||||||
|
fractionDigits: Int = DEFAULT_BYTES_FRACTION_DIGITS,
|
||||||
|
trimTrailingZero: Boolean = DEFAULT_BYTES_TRIM_TRAILING_ZERO,
|
||||||
|
autoCarryThreshold: Long = DEFAULT_BYTES_AUTO_CARRY_THRESHOLD,
|
||||||
|
strict: Boolean = DEFAULT_BYTES_STRICT,
|
||||||
|
signature: String = "Bytes.string",
|
||||||
|
): String {
|
||||||
|
val (bytesBD, baseBI, niceToUnit) = parseArguments(source, fromUnit, toUnit, fractionDigits, autoCarryThreshold, strict, signature)
|
||||||
|
val bd = computeNumberValue(bytesBD, baseBI, niceToUnit, fractionDigits, autoCarryThreshold, strict, signature)
|
||||||
|
val bdFormatted = bd.setScale(fractionDigits, RoundingMode.HALF_UP).toPlainString().let {
|
||||||
|
if (!trimTrailingZero) it else it.replace(Regex("(\\.\\d*?)0+$"), "$1").removeSuffix(".")
|
||||||
|
}
|
||||||
|
val withIec = useIecIdentifier ?: when {
|
||||||
|
strict -> DEFAULT_BYTES_USE_IEC_IDENTIFIER_FOR_STRICT
|
||||||
|
else -> DEFAULT_BYTES_USE_IEC_IDENTIFIER
|
||||||
|
}
|
||||||
|
val space = if (useSpace) " " else ""
|
||||||
|
|
||||||
|
return when {
|
||||||
|
strict -> when (niceToUnit) {
|
||||||
|
AUTO -> {
|
||||||
|
val (_, core) = autoPickBig(bytesBD, baseBI, BigDecimal.valueOf(autoCarryThreshold))
|
||||||
|
val suffix = if (core.isEmpty()) "B" else "${core}iB"
|
||||||
|
"$bdFormatted$space$suffix"
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val coreRaw = niceToUnit.uppercase().removeSuffix("B")
|
||||||
|
val isIEC = coreRaw.endsWith("I")
|
||||||
|
when (val core = if (isIEC) coreRaw.removeSuffix("I") else coreRaw) {
|
||||||
|
"" -> "$bdFormatted${space}B"
|
||||||
|
else -> {
|
||||||
|
val idx = UNITS.indexOf(core)
|
||||||
|
require(idx != -1) { "Argument \"toUnit\" ${toUnit.jsBrief()} is invalid${signature.toSignatureSuffix()}" }
|
||||||
|
when {
|
||||||
|
isIEC -> "$bdFormatted${space}${core}iB"
|
||||||
|
else -> "$bdFormatted${space}${core}B"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> when (niceToUnit) {
|
||||||
|
AUTO -> {
|
||||||
|
val (_, core) = autoPickBig(bytesBD, BI_IEC, BigDecimal.valueOf(autoCarryThreshold))
|
||||||
|
val suffix = if (core.isEmpty()) "B" else if (withIec) "${core}iB" else "${core}B"
|
||||||
|
"$bdFormatted$space$suffix"
|
||||||
|
}
|
||||||
|
else -> when (val core = niceToUnit.removeSuffix("B")) {
|
||||||
|
"" -> "$bdFormatted${space}B"
|
||||||
|
else -> {
|
||||||
|
val idx = UNITS.indexOf(core)
|
||||||
|
require(idx != -1) { "Argument \"toUnit\" ${toUnit.jsBrief()} is invalid${signature.toSignatureSuffix()}" }
|
||||||
|
val suffix = if (withIec) "${core}iB" else "${core}B"
|
||||||
|
"$bdFormatted$space$suffix"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseArguments(
|
||||||
|
source: Double,
|
||||||
|
fromUnit: String = DEFAULT_BYTES_FROM_UNIT,
|
||||||
|
toUnit: String = DEFAULT_BYTES_TO_UNIT,
|
||||||
|
fractionDigits: Int = DEFAULT_BYTES_FRACTION_DIGITS,
|
||||||
|
autoCarryThreshold: Long = DEFAULT_BYTES_AUTO_CARRY_THRESHOLD,
|
||||||
|
strict: Boolean = DEFAULT_BYTES_STRICT,
|
||||||
|
signature: String,
|
||||||
|
): UnitConversionDetails {
|
||||||
|
val signatureSuffix = signature.toSignatureSuffix()
|
||||||
|
|
||||||
|
require(!source.isNaN() && source >= 0.0) {
|
||||||
|
"Argument \"source\" ${source.jsBrief()} must be non-negative number$signatureSuffix"
|
||||||
|
}
|
||||||
|
|
||||||
|
require(fractionDigits >= 0) {
|
||||||
|
"Argument \"fractionDigits\" ${fractionDigits.jsBrief()} must be non-negative$signatureSuffix"
|
||||||
|
}
|
||||||
|
|
||||||
|
val niceToUnit = when {
|
||||||
|
strict -> toUnit.trim().uppercase()
|
||||||
|
else -> toUnit.toSiUnit()
|
||||||
|
}.takeUnless { it.isBlank() } ?: DEFAULT_BYTES_TO_UNIT
|
||||||
|
|
||||||
|
require(autoCarryThreshold > 0) {
|
||||||
|
"Argument \"autoCarryThreshold\" ${autoCarryThreshold.jsBrief()} must be a positive finite number$signatureSuffix"
|
||||||
|
}
|
||||||
|
require(autoCarryThreshold == DEFAULT_BYTES_AUTO_CARRY_THRESHOLD || niceToUnit.equals(AUTO, ignoreCase = true)) {
|
||||||
|
"Argument \"autoCarryThreshold\" is only allowed when argument \"toUnit\" is \"$AUTO\"$signatureSuffix"
|
||||||
|
}
|
||||||
|
|
||||||
|
val (bytesBD, baseBI) = run parseExactBytes@{
|
||||||
|
val valueBD = BigDecimal.valueOf(source)
|
||||||
|
val niceFromUnit = when {
|
||||||
|
strict -> fromUnit.trim()
|
||||||
|
else -> fromUnit.toSiUnit()
|
||||||
|
}.takeUnless { it.isBlank() }?.uppercase() ?: DEFAULT_BYTES_FROM_UNIT
|
||||||
|
val coreRaw = when {
|
||||||
|
niceFromUnit.endsWith("B") -> niceFromUnit.dropLast(1)
|
||||||
|
else -> niceFromUnit
|
||||||
|
}
|
||||||
|
val isIec = strict && coreRaw.endsWith("I")
|
||||||
|
val core = if (isIec) coreRaw.removeSuffix("I") else coreRaw
|
||||||
|
val base = if (!strict) BI_IEC else if (isIec) BI_IEC else BI_SI
|
||||||
|
val idx = if (core.isEmpty()) -1 else UNITS.indexOf(core)
|
||||||
|
require(core.isEmpty() || idx != -1) { "Argument \"fromUnit\" ${fromUnit.jsBrief()} is invalid$signatureSuffix" }
|
||||||
|
val factor = if (idx == -1) BigInteger.ONE else powBI(base, idx + 1)
|
||||||
|
valueBD.multiply(BigDecimal(factor)) to base
|
||||||
|
}
|
||||||
|
|
||||||
|
return UnitConversionDetails(bytesBD, baseBI, niceToUnit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the order of AUTO (avoiding errors from ln/Double), determine whether to carry early (autoCarryThreshold)
|
||||||
|
// zh-CN: 求 AUTO 的阶 (避免 ln/Double 带来的误差), 决策是否提前进位 (autoCarryThreshold).
|
||||||
|
private fun autoPickBig(bytes: BigDecimal, base: BigInteger, carryThreshold: BigDecimal): Pair<Int, String> {
|
||||||
|
if (bytes.compareTo(BigDecimal.ZERO) == 0) return 0 to ""
|
||||||
|
var exp = 0
|
||||||
|
val core = fun() = UNITS.substring((exp - 1).coerceAtLeast(0), exp)
|
||||||
|
// Find max exp such that bytes >= base^exp.
|
||||||
|
// zh-CN: 找到最大的 exp 使 bytes >= base^exp.
|
||||||
|
for (i in 1..UNITS.length) {
|
||||||
|
val th = BigDecimal(powBI(base, i))
|
||||||
|
if (bytes >= th) exp = i else break
|
||||||
|
}
|
||||||
|
if (exp > 0) {
|
||||||
|
val currentVal = bytes.divide(BigDecimal(powBI(base, exp)), DEFAULT_BYTES_FRACTION_DIGITS + 4, RoundingMode.HALF_UP)
|
||||||
|
if (currentVal >= carryThreshold && exp < UNITS.length) {
|
||||||
|
exp += 1
|
||||||
|
return exp to core()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return exp to core()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseSource(source: Any?, fromUnit: Any?, strict: Boolean, signatureSuffix: String): Pair<Double, String> {
|
||||||
|
var bytes: Double
|
||||||
|
var parsedUnitRaw = ""
|
||||||
|
when {
|
||||||
|
source.isJsNumber() -> {
|
||||||
|
val d = coerceNumber(source, NaN)
|
||||||
|
require(!d.isNaN() && d >= 0.0) { "Argument \"source\" ${source.jsBrief()} must be non-negative number for $signatureSuffix" }
|
||||||
|
bytes = d
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val s = coerceString(source, "0").trim()
|
||||||
|
val m = Regex("^(\\d+(?:\\.\\d+)?)\\s*([A-Za-z]*)$", IGNORE_CASE).find(s)
|
||||||
|
?: throw IllegalArgumentException("Invalid bytes value: \"$source\"")
|
||||||
|
bytes = try {
|
||||||
|
Context.toNumber(m.groupValues[1])
|
||||||
|
} catch (_: Throwable) {
|
||||||
|
throw IllegalArgumentException("Invalid bytes value: \"${m.groupValues[1]}\"")
|
||||||
|
}
|
||||||
|
parsedUnitRaw = m.groupValues[2]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val niceFromUnit = run parseFromUnit@{
|
||||||
|
val incoming = coerceString(fromUnit, "").let { if (strict) it.trim() else it.toSiUnit() }
|
||||||
|
val parsed = if (strict) parsedUnitRaw.trim() else parsedUnitRaw.toSiUnit()
|
||||||
|
when {
|
||||||
|
incoming.isBlank() -> parsed
|
||||||
|
parsed.isBlank() -> incoming
|
||||||
|
incoming.equals(parsed, ignoreCase = !strict) -> incoming
|
||||||
|
else -> throw IllegalArgumentException("Ambiguous \"fromUnit\" values: [ $incoming, $parsed ]$signatureSuffix")
|
||||||
|
}.ifBlank { DEFAULT_BYTES_FROM_UNIT }.uppercase()
|
||||||
|
}
|
||||||
|
return bytes to niceFromUnit
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun powBI(base: BigInteger, exp: Int): BigInteger = when {
|
||||||
|
base == BI_IEC && exp in 0..UNITS.length -> POW_IEC[exp]
|
||||||
|
base == BI_SI && exp in 0..UNITS.length -> POW_SI[exp]
|
||||||
|
else -> base.pow(exp)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun computeNumberValue(
|
||||||
|
bytesBD: BigDecimal,
|
||||||
|
baseBI: BigInteger,
|
||||||
|
toUnit: String,
|
||||||
|
fractionDigits: Int,
|
||||||
|
autoCarryThreshold: Long,
|
||||||
|
strict: Boolean,
|
||||||
|
signature: String,
|
||||||
|
): BigDecimal = when {
|
||||||
|
strict -> when (toUnit) {
|
||||||
|
AUTO -> {
|
||||||
|
val (exp, _) = autoPickBig(bytesBD, baseBI, BigDecimal.valueOf(autoCarryThreshold))
|
||||||
|
val value = if (exp == 0) bytesBD else bytesBD.divide(BigDecimal(powBI(baseBI, exp)), fractionDigits, RoundingMode.HALF_UP)
|
||||||
|
value.stripTrailingZeros()
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val coreRaw = toUnit.uppercase().removeSuffix("B")
|
||||||
|
val isIEC = coreRaw.endsWith("I")
|
||||||
|
when (val core = if (isIEC) coreRaw.removeSuffix("I") else coreRaw) {
|
||||||
|
"" -> bytesBD.stripTrailingZeros()
|
||||||
|
else -> {
|
||||||
|
val idx = UNITS.indexOf(core)
|
||||||
|
require(idx != -1) { "Argument \"toUnit\" ${toUnit.jsBrief()} is invalid${signature.toSignatureSuffix()}" }
|
||||||
|
val base = if (isIEC) BI_IEC else BI_SI
|
||||||
|
val value = bytesBD.divide(BigDecimal(powBI(base, idx + 1)), fractionDigits, RoundingMode.HALF_UP)
|
||||||
|
value.stripTrailingZeros()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> when (toUnit) {
|
||||||
|
AUTO -> {
|
||||||
|
val (exp, _) = autoPickBig(bytesBD, BI_IEC, BigDecimal.valueOf(autoCarryThreshold))
|
||||||
|
val value = if (exp == 0) bytesBD else bytesBD.divide(BigDecimal(powBI(BI_IEC, exp)), fractionDigits, RoundingMode.HALF_UP)
|
||||||
|
value.stripTrailingZeros()
|
||||||
|
}
|
||||||
|
else -> when (val core = toUnit.removeSuffix("B")) {
|
||||||
|
"" -> bytesBD
|
||||||
|
else -> {
|
||||||
|
val idx = UNITS.indexOf(core)
|
||||||
|
require(idx != -1) { "Argument \"toUnit\" ${toUnit.jsBrief()} is invalid${signature.toSignatureSuffix()}" }
|
||||||
|
val value = bytesBD.divide(BigDecimal(powBI(BI_IEC, idx + 1)), fractionDigits, RoundingMode.HALF_UP)
|
||||||
|
value.stripTrailingZeros()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.toSiUnit() = this.trim().uppercase().replace(Regex("I(?=B$)"), "")
|
||||||
|
|
||||||
|
private fun String.toSignatureSuffix() = this.takeUnless { it.isBlank() }?.let { " for $it" } ?: ""
|
||||||
|
|
||||||
|
private fun BigDecimal.toJavaScriptBigIntOrNumber(): Any = when (this) {
|
||||||
|
in MIN_SAFE_INT_IEEE754_BD..MAX_SAFE_INT_IEEE754_BD -> {
|
||||||
|
this.toDouble()
|
||||||
|
}
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface RetrievalHandler {
|
||||||
|
fun retrieve(): Any
|
||||||
|
}
|
||||||
|
|
||||||
|
private open class NumberRetrievalHandler(
|
||||||
|
private val source: Any? = null, /* Double */
|
||||||
|
private val fromUnit: Any? = null, /* String */
|
||||||
|
private val toUnit: Any? = null, /* String */
|
||||||
|
private val fractionDigits: Any? = null, /* Int */
|
||||||
|
private val autoCarryThreshold: Any? = null, /* Double */
|
||||||
|
private val strict: Any? = null, /* Boolean */
|
||||||
|
private val signature: String? = null,
|
||||||
|
) : RetrievalHandler {
|
||||||
|
|
||||||
|
override fun retrieve(): NumberRhinoStandardizationDetails {
|
||||||
|
val signatureSuffix = signature?.toSignatureSuffix() ?: ""
|
||||||
|
val niceStrict = coerceBoolean(strict, DEFAULT_BYTES_STRICT)
|
||||||
|
val niceToUnit = when {
|
||||||
|
niceStrict -> coerceString(toUnit, DEFAULT_BYTES_TO_UNIT).trim().uppercase()
|
||||||
|
else -> coerceString(toUnit, DEFAULT_BYTES_TO_UNIT).toSiUnit()
|
||||||
|
}.takeIf { it.isNotEmpty() } ?: DEFAULT_BYTES_TO_UNIT
|
||||||
|
|
||||||
|
val (niceSource, niceFromUnit) = parseSource(source, fromUnit, niceStrict, signatureSuffix)
|
||||||
|
|
||||||
|
val niceFractionDigits = coerceIntNumber(fractionDigits, DEFAULT_BYTES_FRACTION_DIGITS).also {
|
||||||
|
require(it >= 0) { "Argument \"fractionDigits\" ${fractionDigits.jsBrief()} must be non-negative$signatureSuffix" }
|
||||||
|
}
|
||||||
|
|
||||||
|
require(autoCarryThreshold.isJsNullish() || niceToUnit.equals(AUTO, ignoreCase = true)) {
|
||||||
|
"Option \"autoCarryThreshold\" is only allowed when argument \"toUnit\" is \"$AUTO\"$signatureSuffix"
|
||||||
|
}
|
||||||
|
val niceAutoCarryThreshold = coerceLongNumber(autoCarryThreshold, DEFAULT_BYTES_AUTO_CARRY_THRESHOLD).also {
|
||||||
|
require(it > 0) {
|
||||||
|
"Option \"autoCarryThreshold\" ${autoCarryThreshold.jsBrief()} must be a positive finite number$signatureSuffix"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NumberRhinoStandardizationDetails(niceSource, niceFromUnit, niceToUnit, niceFractionDigits, niceAutoCarryThreshold, niceStrict)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class StringRetrievalHandler(
|
||||||
|
source: Any?,
|
||||||
|
fromUnit: Any?,
|
||||||
|
toUnit: Any?,
|
||||||
|
private val useIecIdentifier: Any?,
|
||||||
|
private val useSpace: Any?,
|
||||||
|
fractionDigits: Any?,
|
||||||
|
private val trimTrailingZero: Any?,
|
||||||
|
autoCarryThreshold: Any?,
|
||||||
|
strict: Any?,
|
||||||
|
private val signature: String? = null,
|
||||||
|
) : NumberRetrievalHandler(source, fromUnit, toUnit, fractionDigits, autoCarryThreshold, strict, signature) {
|
||||||
|
|
||||||
|
override fun retrieve(): StringRhinoStandardizationDetails {
|
||||||
|
val sp = super.retrieve()
|
||||||
|
|
||||||
|
val niceSource = sp.niceSource
|
||||||
|
val niceFromUnit = sp.niceFromUnit
|
||||||
|
val niceToUnit = sp.niceToUnit
|
||||||
|
val niceFractionDigits = sp.niceFractionDigits
|
||||||
|
val niceAutoCarryThreshold = sp.niceAutoCarryThreshold
|
||||||
|
val niceStrict = sp.niceStrict
|
||||||
|
val signatureSuffix = signature?.toSignatureSuffix() ?: ""
|
||||||
|
|
||||||
|
require(!niceStrict || useIecIdentifier.isJsNullish()) {
|
||||||
|
"Argument \"useIecIdentifier\" ${useIecIdentifier.jsBrief()} must be nullish when in strict mode$signatureSuffix"
|
||||||
|
}
|
||||||
|
|
||||||
|
val niceUseSpace = coerceBoolean(useSpace, DEFAULT_BYTES_USE_SPACE)
|
||||||
|
|
||||||
|
val niceTrimTrailingZero = coerceBoolean(trimTrailingZero, DEFAULT_BYTES_TRIM_TRAILING_ZERO)
|
||||||
|
val niceUseIecIdentifier = if (useIecIdentifier.isJsNullish()) null else Context.toBoolean(useIecIdentifier)
|
||||||
|
|
||||||
|
return StringRhinoStandardizationDetails(niceSource, niceFromUnit, niceToUnit, niceUseIecIdentifier, niceUseSpace, niceFractionDigits, niceTrimTrailingZero, niceAutoCarryThreshold, niceStrict)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class UnitConversionDetails(val bytesBD: BigDecimal, val baseBI: BigInteger, val toUnit: String)
|
||||||
|
|
||||||
|
private open class NumberRhinoStandardizationDetails(
|
||||||
|
open val niceSource: Double,
|
||||||
|
open val niceFromUnit: String,
|
||||||
|
open val niceToUnit: String,
|
||||||
|
open val niceFractionDigits: Int,
|
||||||
|
open val niceAutoCarryThreshold: Long,
|
||||||
|
open val niceStrict: Boolean,
|
||||||
|
)
|
||||||
|
|
||||||
|
private class StringRhinoStandardizationDetails(
|
||||||
|
override val niceSource: Double,
|
||||||
|
override val niceFromUnit: String,
|
||||||
|
override val niceToUnit: String,
|
||||||
|
val niceUseIecIdentifier: Boolean?,
|
||||||
|
val niceUseSpace: Boolean,
|
||||||
|
override val niceFractionDigits: Int,
|
||||||
|
val niceTrimTrailingZero: Boolean,
|
||||||
|
override val niceAutoCarryThreshold: Long,
|
||||||
|
override val niceStrict: Boolean,
|
||||||
|
) : NumberRhinoStandardizationDetails(niceSource, niceFromUnit, niceToUnit, niceFractionDigits, niceAutoCarryThreshold, niceStrict)
|
||||||
|
|
||||||
|
enum class Tough { STRICT, LOOSE, NONE }
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
@file:Suppress("MayBeConstant")
|
||||||
|
|
||||||
|
package org.autojs.autojs.runtime.api.augment.formatter
|
||||||
|
|
||||||
|
import org.autojs.autojs.annotation.RhinoSingletonFunctionInterface
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.isJsBoolean
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.isJsNullish
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.isJsNumber
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.isJsObject
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.isJsString
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.jsBrief
|
||||||
|
import org.autojs.autojs.extension.ScriptableObjectExtensions.inquire
|
||||||
|
import org.autojs.autojs.runtime.api.augment.Augmentable
|
||||||
|
import org.autojs.autojs.runtime.api.augment.Invokable
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.AUTO
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.DEFAULT_BYTES_STRICT
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.IEC_DIV
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.SI_DIV
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.Tough
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.Tough.LOOSE
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.Tough.NONE
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.Tough.STRICT
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes.UNITS
|
||||||
|
import org.autojs.autojs.util.RhinoUtils.coerceBoolean
|
||||||
|
import org.mozilla.javascript.ScriptableObject
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes as CoreBytes
|
||||||
|
|
||||||
|
object Bytes : Augmentable(), Invokable {
|
||||||
|
|
||||||
|
override val selfAssignmentProperties = listOf(
|
||||||
|
"UNITS" to UNITS,
|
||||||
|
"AUTO" to AUTO,
|
||||||
|
"IEC_DIV" to IEC_DIV,
|
||||||
|
"SI_DIV" to SI_DIV,
|
||||||
|
)
|
||||||
|
|
||||||
|
override val selfAssignmentFunctions = listOf(
|
||||||
|
::strict.name,
|
||||||
|
::loose.name,
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun invoke(vararg args: Any?): String = ensureArgumentsLengthInRange(args, 1..4) { call(args) }
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@RhinoSingletonFunctionInterface
|
||||||
|
fun call(args: Array<out Any?>, tough: Tough = NONE): String = ensureArgumentsLengthInRange(args, 1..4) { argList ->
|
||||||
|
val (arg0, arg1, arg2, arg3) = argList
|
||||||
|
|
||||||
|
when (argList.size) {
|
||||||
|
4 -> when {
|
||||||
|
arg3.isJsObject() -> {
|
||||||
|
val opts = arg3 as ScriptableObject
|
||||||
|
listOf("source", "fromUnit", "toUnit", "options").forBytesString(
|
||||||
|
source = arg0,
|
||||||
|
fromUnit = opts.inquire("fromUnit", arg1),
|
||||||
|
toUnit = opts.inquire("toUnit", arg2),
|
||||||
|
useIecIdentifier = opts.inquire("useIecIdentifier"),
|
||||||
|
useSpace = opts.inquire("useSpace"),
|
||||||
|
fractionDigits = opts.inquire("fractionDigits"),
|
||||||
|
trimTrailingZero = opts.inquire("trimTrailingZero"),
|
||||||
|
autoCarryThreshold = opts.inquire("autoCarryThreshold"),
|
||||||
|
strict = opts.inquire("strict"),
|
||||||
|
tough = tough,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg3.isJsBoolean() -> {
|
||||||
|
listOf("source", "fromUnit", "toUnit", "useIecIdentifier").forBytesString(
|
||||||
|
source = arg0,
|
||||||
|
fromUnit = arg1,
|
||||||
|
toUnit = arg2,
|
||||||
|
useIecIdentifier = arg3,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg3.isJsNumber() -> {
|
||||||
|
listOf("source", "fromUnit", "toUnit", "fractionDigits").forBytesString(
|
||||||
|
source = arg0,
|
||||||
|
fromUnit = arg1,
|
||||||
|
toUnit = arg2,
|
||||||
|
fractionDigits = arg3,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> throw IllegalArgumentException("Invalid argument[3] ${arg3.jsBrief()} for ${Formatter.key}.bytes")
|
||||||
|
}
|
||||||
|
3 -> when {
|
||||||
|
arg2.isJsObject() -> {
|
||||||
|
val opts = arg2 as ScriptableObject
|
||||||
|
listOf("source", "toUnit", "options").forBytesString(
|
||||||
|
source = arg0,
|
||||||
|
fromUnit = opts.inquire("fromUnit"),
|
||||||
|
toUnit = opts.inquire("toUnit", arg1),
|
||||||
|
fractionDigits = opts.inquire("fractionDigits"),
|
||||||
|
useIecIdentifier = opts.inquire("useIecIdentifier"),
|
||||||
|
useSpace = opts.inquire("useSpace"),
|
||||||
|
trimTrailingZero = opts.inquire("trimTrailingZero"),
|
||||||
|
autoCarryThreshold = opts.inquire("autoCarryThreshold"),
|
||||||
|
strict = opts.inquire("strict"),
|
||||||
|
tough = tough,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg2.isJsString() -> {
|
||||||
|
listOf("source", "fromUnit", "toUnit").forBytesString(
|
||||||
|
source = arg0,
|
||||||
|
fromUnit = arg1,
|
||||||
|
toUnit = arg2,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg2.isJsBoolean() -> {
|
||||||
|
listOf("source", "toUnit", "useIecIdentifier").forBytesString(
|
||||||
|
source = arg0,
|
||||||
|
toUnit = arg1,
|
||||||
|
useIecIdentifier = arg2,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg2.isJsNumber() -> {
|
||||||
|
listOf("source", "toUnit", "fractionDigits").forBytesString(
|
||||||
|
source = arg0,
|
||||||
|
toUnit = arg1,
|
||||||
|
fractionDigits = arg2,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> throw IllegalArgumentException("Invalid argument[2] ${arg2.jsBrief()} for ${Formatter.key}.bytes")
|
||||||
|
}
|
||||||
|
2 -> when {
|
||||||
|
arg1.isJsObject() -> {
|
||||||
|
val opts = arg1 as ScriptableObject
|
||||||
|
listOf("source", "options").forBytesString(
|
||||||
|
source = arg0,
|
||||||
|
fromUnit = opts.inquire("fromUnit"),
|
||||||
|
toUnit = opts.inquire("toUnit"),
|
||||||
|
fractionDigits = opts.inquire("fractionDigits"),
|
||||||
|
useIecIdentifier = opts.inquire("useIecIdentifier"),
|
||||||
|
useSpace = opts.inquire("useSpace"),
|
||||||
|
trimTrailingZero = opts.inquire("trimTrailingZero"),
|
||||||
|
autoCarryThreshold = opts.inquire("autoCarryThreshold"),
|
||||||
|
strict = opts.inquire("strict"),
|
||||||
|
tough = tough,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg1.isJsString() -> {
|
||||||
|
listOf("source", "toUnit").forBytesString(
|
||||||
|
source = arg0,
|
||||||
|
toUnit = arg1,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg1.isJsBoolean() -> {
|
||||||
|
listOf("source", "useIecIdentifier").forBytesString(
|
||||||
|
source = arg0,
|
||||||
|
useIecIdentifier = arg1,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
arg1.isJsNumber() -> {
|
||||||
|
listOf("source", "fractionDigits").forBytesString(
|
||||||
|
source = arg0,
|
||||||
|
fractionDigits = arg1,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> throw IllegalArgumentException("Invalid argument[1] ${arg1.jsBrief()} for ${Formatter.key}.bytes")
|
||||||
|
}
|
||||||
|
1 -> listOf("source").forBytesString(
|
||||||
|
source = arg0,
|
||||||
|
strict = tough == STRICT,
|
||||||
|
)
|
||||||
|
else -> throw IllegalArgumentException("Invalid arguments length ${argList.size} for ${Formatter.key}.bytes")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@RhinoSingletonFunctionInterface
|
||||||
|
fun strict(args: Array<out Any?>): String = ensureArgumentsLengthInRange(args, 1..4) {
|
||||||
|
call(args, STRICT)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@RhinoSingletonFunctionInterface
|
||||||
|
fun loose(args: Array<out Any?>): String = ensureArgumentsLengthInRange(args, 1..4) {
|
||||||
|
call(args, LOOSE)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<String>.forBytesString(
|
||||||
|
source: Any? = null,
|
||||||
|
fromUnit: Any? = null,
|
||||||
|
toUnit: Any? = null,
|
||||||
|
useIecIdentifier: Any? = null,
|
||||||
|
useSpace: Any? = null,
|
||||||
|
fractionDigits: Any? = null,
|
||||||
|
trimTrailingZero: Any? = null,
|
||||||
|
autoCarryThreshold: Any? = null,
|
||||||
|
strict: Any? = null,
|
||||||
|
tough: Tough = NONE,
|
||||||
|
): String {
|
||||||
|
val (niceStrict, signature) = when (tough) {
|
||||||
|
STRICT -> {
|
||||||
|
val signature = "${Formatter.key}.bytes.strict(${this.joinToString(", ")})"
|
||||||
|
require(strict.isJsNullish()) {
|
||||||
|
"Option \"strict\" ${strict.jsBrief()} must be nullish when in strict mode for $signature"
|
||||||
|
}
|
||||||
|
true to signature
|
||||||
|
}
|
||||||
|
LOOSE -> {
|
||||||
|
val signature = "${Formatter.key}.bytes.loose(${this.joinToString(", ")})"
|
||||||
|
require(strict.isJsNullish()) {
|
||||||
|
"Option \"strict\" ${strict.jsBrief()} must be nullish when in loose mode for $signature"
|
||||||
|
}
|
||||||
|
false to signature
|
||||||
|
}
|
||||||
|
NONE -> {
|
||||||
|
val signature = "${Formatter.key}.bytes(${this.joinToString(", ")})"
|
||||||
|
coerceBoolean(strict, DEFAULT_BYTES_STRICT) to signature
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CoreBytes.stringRhino(
|
||||||
|
source,
|
||||||
|
fromUnit,
|
||||||
|
toUnit,
|
||||||
|
useIecIdentifier,
|
||||||
|
useSpace,
|
||||||
|
fractionDigits,
|
||||||
|
trimTrailingZero,
|
||||||
|
autoCarryThreshold,
|
||||||
|
niceStrict,
|
||||||
|
signature,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.autojs.autojs.runtime.api.augment.formatter
|
||||||
|
|
||||||
|
import org.autojs.autojs.runtime.api.augment.Augmentable
|
||||||
|
|
||||||
|
object Formatter : Augmentable() {
|
||||||
|
|
||||||
|
override val key = "fmt"
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,10 +1,15 @@
|
|||||||
|
@file:Suppress("MayBeConstant")
|
||||||
|
|
||||||
package org.autojs.autojs.runtime.api.augment.s13n
|
package org.autojs.autojs.runtime.api.augment.s13n
|
||||||
|
|
||||||
|
import org.autojs.autojs.annotation.RhinoFunctionBody
|
||||||
import org.autojs.autojs.annotation.RhinoSingletonFunctionInterface
|
import org.autojs.autojs.annotation.RhinoSingletonFunctionInterface
|
||||||
import org.autojs.autojs.extension.AnyExtensions.isJsNullish
|
import org.autojs.autojs.extension.AnyExtensions.isJsNullish
|
||||||
import org.autojs.autojs.extension.AnyExtensions.isJsObject
|
import org.autojs.autojs.extension.AnyExtensions.isJsObject
|
||||||
|
import org.autojs.autojs.extension.AnyExtensions.isJsString
|
||||||
import org.autojs.autojs.extension.AnyExtensions.jsBrief
|
import org.autojs.autojs.extension.AnyExtensions.jsBrief
|
||||||
import org.autojs.autojs.extension.ScriptableExtensions.prop
|
import org.autojs.autojs.extension.ScriptableExtensions.prop
|
||||||
|
import org.autojs.autojs.extension.ScriptableObjectExtensions.inquire
|
||||||
import org.autojs.autojs.runtime.api.augment.Augmentable
|
import org.autojs.autojs.runtime.api.augment.Augmentable
|
||||||
import org.autojs.autojs.runtime.api.augment.colors.Colors
|
import org.autojs.autojs.runtime.api.augment.colors.Colors
|
||||||
import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException
|
import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException
|
||||||
@@ -25,6 +30,7 @@ import kotlin.math.roundToInt
|
|||||||
import kotlin.reflect.full.declaredMemberFunctions
|
import kotlin.reflect.full.declaredMemberFunctions
|
||||||
import kotlin.text.RegexOption.IGNORE_CASE
|
import kotlin.text.RegexOption.IGNORE_CASE
|
||||||
import android.graphics.Point as AndroidPoint
|
import android.graphics.Point as AndroidPoint
|
||||||
|
import org.autojs.autojs.runtime.api.augment.converter.core.Bytes as CoreBytes
|
||||||
import org.opencv.core.Point as OpencvPoint
|
import org.opencv.core.Point as OpencvPoint
|
||||||
|
|
||||||
object S13n : Augmentable() {
|
object S13n : Augmentable() {
|
||||||
@@ -60,6 +66,7 @@ object S13n : Augmentable() {
|
|||||||
::throwable.name,
|
::throwable.name,
|
||||||
::point.name,
|
::point.name,
|
||||||
::time.name,
|
::time.name,
|
||||||
|
::bytes.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@@ -139,7 +146,7 @@ object S13n : Augmentable() {
|
|||||||
} ?: when {
|
} ?: when {
|
||||||
arg1.isJsObject() -> {
|
arg1.isJsObject() -> {
|
||||||
val options = arg1 as ScriptableObject
|
val options = arg1 as ScriptableObject
|
||||||
time(arrayOf(source, options.prop("fromUnit"), options.prop("toUnit")))
|
time(arrayOf(source, options.inquire("fromUnit"), options.inquire("toUnit")))
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val num = coerceNumber(source, NaN).also { require(!it.isNaN()) { "Failed to make ${arg0.jsBrief()} a number time being" } }
|
val num = coerceNumber(source, NaN).also { require(!it.isNaN()) { "Failed to make ${arg0.jsBrief()} a number time being" } }
|
||||||
@@ -159,6 +166,47 @@ object S13n : Augmentable() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@RhinoSingletonFunctionInterface
|
||||||
|
fun bytes(args: Array<out Any?>): Any = ensureArgumentsLengthInRange(args, 1..2) { argList ->
|
||||||
|
val (arg0, arg1) = argList
|
||||||
|
|
||||||
|
when (argList.size) {
|
||||||
|
2 -> when {
|
||||||
|
arg1.isJsString() -> listOf("source", "fromUnit").forBytes(source = arg0, fromUnit = arg1)
|
||||||
|
else -> throw WrappedIllegalArgumentException("Invalid argument[1] ${arg1.jsBrief()} for $key.bytes")
|
||||||
|
}
|
||||||
|
1 -> listOf("source").forBytes(source = arg0)
|
||||||
|
else -> throw WrappedIllegalArgumentException("Invalid arguments length ${argList.size} for $key.bytes")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@JvmOverloads
|
||||||
|
@RhinoFunctionBody
|
||||||
|
fun bytesRhino(
|
||||||
|
source: Any? = null, /* Double */
|
||||||
|
fromUnit: Any? = null, /* String */
|
||||||
|
funcSignature: List<String> = emptyList(),
|
||||||
|
): Any {
|
||||||
|
val signature = when {
|
||||||
|
funcSignature.isNotEmpty() -> "$key.bytes(${funcSignature.joinToString(", ")})"
|
||||||
|
else -> "$key.bytes()"
|
||||||
|
}
|
||||||
|
return CoreBytes.numberRhino(
|
||||||
|
source = source,
|
||||||
|
fromUnit = fromUnit,
|
||||||
|
toUnit = "B",
|
||||||
|
fractionDigits = 0,
|
||||||
|
signature = signature,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<String>.forBytes(
|
||||||
|
source: Any? = null, /* Double */
|
||||||
|
fromUnit: Any? = null, /* String */
|
||||||
|
) = bytesRhino(source, fromUnit, this)
|
||||||
|
|
||||||
private fun getTimeUnitSourceObject(unit: Any?): TimeUnit = when (unit) {
|
private fun getTimeUnitSourceObject(unit: Any?): TimeUnit = when (unit) {
|
||||||
is TimeUnit -> unit
|
is TimeUnit -> unit
|
||||||
is String -> timeUnitRex.entries.find { it.value.matches(unit) }?.let {
|
is String -> timeUnitRex.entries.find { it.value.matches(unit) }?.let {
|
||||||
|
|||||||
@@ -2,11 +2,8 @@ package org.autojs.autojs.runtime.api.augment.util
|
|||||||
|
|
||||||
import org.autojs.autojs.annotation.RhinoFunctionBody
|
import org.autojs.autojs.annotation.RhinoFunctionBody
|
||||||
import org.autojs.autojs.core.automator.UiObjectCollection
|
import org.autojs.autojs.core.automator.UiObjectCollection
|
||||||
import org.autojs.autojs.extension.AnyExtensions.isJsBoolean
|
|
||||||
import org.autojs.autojs.extension.AnyExtensions.isJsNonNullObject
|
import org.autojs.autojs.extension.AnyExtensions.isJsNonNullObject
|
||||||
import org.autojs.autojs.extension.AnyExtensions.isJsNullish
|
import org.autojs.autojs.extension.AnyExtensions.isJsNullish
|
||||||
import org.autojs.autojs.extension.AnyExtensions.isJsNumber
|
|
||||||
import org.autojs.autojs.extension.AnyExtensions.isJsString
|
|
||||||
import org.autojs.autojs.extension.AnyExtensions.jsBrief
|
import org.autojs.autojs.extension.AnyExtensions.jsBrief
|
||||||
import org.autojs.autojs.extension.ArrayExtensions.toNativeObject
|
import org.autojs.autojs.extension.ArrayExtensions.toNativeObject
|
||||||
import org.autojs.autojs.extension.FlexibleArray.Companion.component1
|
import org.autojs.autojs.extension.FlexibleArray.Companion.component1
|
||||||
@@ -261,7 +258,13 @@ object Inspect : Augmentable(), Invokable {
|
|||||||
private fun formatValue(ctx: Ctx, `val`: Any?, recurseTimes: Int?): String {
|
private fun formatValue(ctx: Ctx, `val`: Any?, recurseTimes: Int?): String {
|
||||||
var value = `val`
|
var value = `val`
|
||||||
|
|
||||||
while (value is Wrapper) value = value.unwrap()
|
while (value is Wrapper) {
|
||||||
|
val unwrapped = value.unwrap()
|
||||||
|
if (unwrapped is Number) {
|
||||||
|
return callToStringFunction(value as Scriptable)
|
||||||
|
}
|
||||||
|
value = unwrapped
|
||||||
|
}
|
||||||
|
|
||||||
if (value is TopLevel) return "[object ${value.className}]"
|
if (value is TopLevel) return "[object ${value.className}]"
|
||||||
|
|
||||||
@@ -579,7 +582,7 @@ object Inspect : Augmentable(), Invokable {
|
|||||||
// For some reason, typeof null is "object", so special case here.
|
// For some reason, typeof null is "object", so special case here.
|
||||||
ctx.stylize("null", "null")
|
ctx.stylize("null", "null")
|
||||||
}
|
}
|
||||||
value.isJsString() -> {
|
value is String -> {
|
||||||
val content = Context.toString(js_json_stringify(value))
|
val content = Context.toString(js_json_stringify(value))
|
||||||
.removeSurrounding("\"")
|
.removeSurrounding("\"")
|
||||||
.replace(Regex("'"), "\\\'")
|
.replace(Regex("'"), "\\\'")
|
||||||
@@ -590,16 +593,15 @@ object Inspect : Augmentable(), Invokable {
|
|||||||
// ! to make a string quoted by single quotation marks.
|
// ! to make a string quoted by single quotation marks.
|
||||||
// ! zh-CN:
|
// ! zh-CN:
|
||||||
// ! 我认为将字符串用单引号包裹起来并不是一个好主意.
|
// ! 我认为将字符串用单引号包裹起来并不是一个好主意.
|
||||||
// ! PS: 我认为不应该翻译为 "我不认为...". :)
|
|
||||||
// !
|
// !
|
||||||
// # ctx.stylize("'$content'", "string")
|
// # ctx.stylize("'$content'", "string")
|
||||||
|
|
||||||
ctx.stylize(content, "string")
|
ctx.stylize(content, "string")
|
||||||
}
|
}
|
||||||
value.isJsNumber() -> {
|
value is Number -> {
|
||||||
ctx.stylize(value.toString(), "number")
|
ctx.stylize(value.toString(), "number")
|
||||||
}
|
}
|
||||||
value.isJsBoolean() -> {
|
value is Boolean -> {
|
||||||
ctx.stylize(Context.toString(value), "boolean")
|
ctx.stylize(Context.toString(value), "boolean")
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import org.mozilla.javascript.Wrapper
|
|||||||
import org.mozilla.javascript.json.JsonParser
|
import org.mozilla.javascript.json.JsonParser
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.lang.reflect.InvocationTargetException
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
import java.math.BigInteger
|
||||||
import kotlin.math.floor
|
import kotlin.math.floor
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
import kotlin.math.roundToLong
|
import kotlin.math.roundToLong
|
||||||
@@ -66,6 +67,23 @@ object RhinoUtils {
|
|||||||
const val DEFAULT_CALLER = 0x03
|
const val DEFAULT_CALLER = 0x03
|
||||||
const val DEFAULT_CONSTRUCTOR = 0x04
|
const val DEFAULT_CONSTRUCTOR = 0x04
|
||||||
|
|
||||||
|
/** [Long]: 2^53 - 1. */
|
||||||
|
const val MAX_SAFE_INT_IEEE754_L = 9_007_199_254_740_991L
|
||||||
|
/** [Long]: -(2^53 - 1). */
|
||||||
|
const val MIN_SAFE_INT_IEEE754_L = -9_007_199_254_740_991L
|
||||||
|
/** [Double]: 2^53 - 1. */
|
||||||
|
const val MAX_SAFE_INT_IEEE754_D = 9_007_199_254_740_991.0
|
||||||
|
/** [Double]: -(2^53 - 1). */
|
||||||
|
const val MIN_SAFE_INT_IEEE754_D = -9_007_199_254_740_991.0
|
||||||
|
/** [java.math.BigDecimal]: 2^53 - 1. */
|
||||||
|
val MAX_SAFE_INT_IEEE754_BD = MAX_SAFE_INT_IEEE754_D.toBigDecimal()
|
||||||
|
/** [java.math.BigDecimal]: -(2^53 - 1). */
|
||||||
|
val MIN_SAFE_INT_IEEE754_BD = MIN_SAFE_INT_IEEE754_D.toBigDecimal()
|
||||||
|
/** [java.math.BigInteger]: 2^53 - 1. */
|
||||||
|
val MAX_SAFE_INT_IEEE754_BI = MAX_SAFE_INT_IEEE754_L.toBigInteger()
|
||||||
|
/** [java.math.BigInteger]: -(2^53 - 1). */
|
||||||
|
val MIN_SAFE_INT_IEEE754_BI = MIN_SAFE_INT_IEEE754_L.toBigInteger()
|
||||||
|
|
||||||
private val TAG = RhinoUtils::class.java.simpleName
|
private val TAG = RhinoUtils::class.java.simpleName
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@@ -274,8 +292,8 @@ object RhinoUtils {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun unwrap(o: Any?): Any? = when (o) {
|
fun unwrap(o: Any?): Any? = when (o) {
|
||||||
is String -> o
|
is String, is ConsString -> Context.toString(o)
|
||||||
is ConsString -> o.toString()
|
is BigInteger -> o
|
||||||
is Number -> Context.toNumber(o)
|
is Number -> Context.toNumber(o)
|
||||||
is Boolean -> Context.toBoolean(o)
|
is Boolean -> Context.toBoolean(o)
|
||||||
is Wrapper -> unwrap(o.unwrap())
|
is Wrapper -> unwrap(o.unwrap())
|
||||||
|
|||||||
Reference in New Issue
Block a user