org.eframework.uni.util
Version:
EFramework Utility for Unite 是一个轻量级、跨平台的工具集,提供了统一的 API 接口,确保在多平台环境下保持一致的运行结果。
1,712 lines (1,703 loc) • 155 kB
JavaScript
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
function __decorate(decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
}
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
// Copyright (c) 2025 EFramework Organization. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
/**
* XObject 提供了对象操作工具集,支持类型判断、函数绑定、方法劫持等功能。
*
* 功能特性
* - 支持类型判断:判断对象是值类型、引用类型、函数类型或类
* - 实现方法劫持:替换和恢复对象方法
* - 提供对象复制:深度克隆对象及计算哈希码
* - 支持函数绑定:确保方法调用时保持正确的 this 引用
*
* 使用手册
* 1. 类型判断
*
* 1.1 基本类型判断
* ```typescript
* // 判断值类型(数字、字符串、布尔值)
* XObject.IsValue(123); // true
* XObject.IsValue("abc"); // true
* XObject.IsValue(true); // true
* XObject.IsValue(new Date()); // false
*
* // 判断引用类型(对象、数组等非值类型)
* XObject.IsObject({}); // true
* XObject.IsObject([]); // true
* XObject.IsObject(new Date()); // true
* XObject.IsObject(123); // false
* ```
*
* 1.2 函数和类判断
* ```typescript
* // 判断函数类型
* function fn() {}
* XObject.IsFunction(fn); // true
* XObject.IsFunction(() => {}); // true
*
* // 判断类
* class MyClass {}
* XObject.IsClass(MyClass); // true
* XObject.IsClass(fn); // false
* ```
*
* 2. 反射操作
*
* 2.1 键值访问
* ```typescript
* // 获取枚举值对应的键名
* enum Color { Red = 1, Green = 2, Blue = 3 }
* XObject.Key(Color, 2); // 返回 "Green"
*
* // 获取对象中键对应的值
* const obj = { name: "张三", age: 25 };
* XObject.Value(obj, "name"); // 返回 "张三"
* ```
*
* 2.2 反射调用
* ```typescript
* // 通过字符串调用对象方法
* const calculator = {
* add: (a, b) => a + b
* };
* XObject.Invoke(calculator, "add", 1, 2); // 返回 3
* ```
*
* 3. 对象操作
*
* 3.1 对象克隆
* ```typescript
* // 深度克隆对象
* const original = {
* name: "张三",
* info: { age: 25, scores: [90, 85, 92] },
* secret: "密码"
* };
* // 克隆时排除某些字段
* const cloned = XObject.Clone(original, "secret");
* // cloned 包含 name 和 info,但不包含 secret
* ```
*
* 3.2 计算哈希码
* ```typescript
* // 计算对象哈希码
* XObject.HashCode("abc"); // 计算字符串哈希
* XObject.HashCode([1, 2, 3]); // 计算数组哈希
* XObject.HashCode({a: 1, b: 2}); // 计算对象哈希
* ```
*
* 4. 方法劫持
*
* 4.1 替换和恢复方法
* ```typescript
* // 替换对象方法
* const obj = {
* greet() { console.log("你好"); }
* };
*
* // 保存原始方法并替换
* const original = XObject.Hook(obj, "greet", function() {
* console.log("替换后的问候");
* });
*
* obj.greet(); // 输出 "替换后的问候"
*
* // 恢复原始方法
* XObject.Unhook(obj, "greet");
* obj.greet(); // 输出 "你好"
* ```
*
* 5. 函数绑定
*
* 5.1 使用装饰器
* ```typescript
* class MyComponent extends XObject.Base {
* name = "组件1";
*
* @XObject.This()
* getName() {
* return this.name;
* }
* }
*
* const comp = new MyComponent();
* const getName = comp.getName;
* getName(); // 返回 "组件1",即使脱离了对象上下文
* ```
*
* 5.2 继承Base类
* ```typescript
* // 继承Base类自动为标记的方法绑定this
* class Controller extends XObject.Base {
* status = "在线";
*
* @XObject.This()
* getStatus() {
* return this.status;
* }
* }
* ```
*
* 更多信息请参考模块文档。
*/
var XObject;
(function (XObject) {
/**
* 钩子映射。
* 用于存储对象方法的原始引用。
*/
const hooks = {};
const XObjectThis = "__xobject_this";
/**
* 函数this实例绑定器。
* 用于确保方法在任何上下文中调用时都保持正确的 this 引用。
*
* @returns 装饰器函数。
* @example
* ```typescript
* class MyClass {
* @XObject.This()
* myMethod() {
* // this 总是指向 MyClass 实例
* }
* }
* ```
*/
function This() {
return function (target, propertyKey) {
target[XObjectThis] = target[XObjectThis] || new Array();
target[XObjectThis].push(propertyKey);
};
}
XObject.This = This;
/**
* 基础类型。
* 用于标识 JavaScript 的基本数据类型。
*/
class Base {
constructor() {
const othis = this.constructor.prototype[XObjectThis];
if (othis) {
for (let i = 0; i < othis.length; i++) {
let key = othis[i];
let value = this[key];
if (value && typeof (value) == "function") {
this[key] = value.bind(this);
}
}
}
}
}
XObject.Base = Base;
/**
* 判断对象是否为值类型。
*
* @param obj 要判断的对象。
* @returns 如果是值类型返回 true,否则返回 false。
* @example
* ```typescript
* XObject.IsValue(123); // true
* XObject.IsValue(new Date()); // false
* ```
*/
function IsValue(obj) {
if (obj == null)
return false;
else {
if (typeof (obj) == "number")
return true;
else if (typeof (obj) == "string")
return true;
else if (typeof (obj) == "boolean")
return true;
else
return false;
}
}
XObject.IsValue = IsValue;
/**
* 检查对象是否为引用类型。
*
* @param obj 对象实例。
* @returns 对象是否为引用类型。
*/
function IsObject(obj) {
if (obj == null || IsValue(obj) || IsFunction(obj)) {
return false;
}
else {
return true;
}
}
XObject.IsObject = IsObject;
/**
* 检查对象是否为函数类型。
*
* @param obj 对象实例。
* @returns 对象是否为函数类型。
*/
function IsFunction(obj) {
if (obj == null) {
return false;
}
else if (IsValue(obj)) {
return false;
}
else if (typeof (obj) == "function") {
if (obj.prototype != null && obj.prototype.constructor == obj)
return false;
return true;
}
return false;
}
XObject.IsFunction = IsFunction;
/**
* 判断对象是否为类。
*
* @param obj 要判断的对象。
* @returns 如果是类返回 true,否则返回 false。
* @example
* ```typescript
* class MyClass {}
* XObject.IsClass(MyClass); // true
* XObject.IsClass({}); // false
* ```
*/
function IsClass(obj) {
if (obj == null) {
return false;
}
else if (IsValue(obj)) {
return false;
}
else if (typeof (obj) == "function") {
if (obj.prototype != null && obj.prototype.constructor == obj)
return true;
}
return false;
}
XObject.IsClass = IsClass;
/**
* 获取对象中某个值的键。
*
* @param obj 对象实例。
* @param value 值。
* @returns 值的键。
*/
function Key(obj, value) {
if (obj != null && value != null) {
for (let k in obj) {
if (obj[k] == value) {
return k;
}
}
}
return null;
}
XObject.Key = Key;
/**
* 获取对象中某个键的值。
*
* @param obj 对象实例。
* @param key 键。
* @returns 键的值。
*/
function Value(obj, key) {
if (obj != null && key != null) {
let r = obj[key];
if (r != null)
return r;
if (IsClass(obj))
return obj.prototype[key];
}
return null;
}
XObject.Value = Value;
/**
* 反射调用函数。
*
* @param obj 对象实例。
* @param key 键名称。
* @param args 参数。
* @returns 函数调用的结果。
*/
function Invoke(obj, key, ...args) {
if (obj != null && key != null) {
let func = obj[key];
if (func != null && typeof (func) == "function") {
return func.apply(obj, args);
}
}
}
XObject.Invoke = Invoke;
/**
* 对象克隆。
*
* @param obj 对象实例。
* @param exclude 忽略字段。
* @returns 克隆的对象。
*/
function Clone(obj, ...exclude) {
if (obj == null || typeof obj !== "object")
return obj;
let nobj = null;
if (Array.isArray(obj))
nobj = [];
else {
nobj = {};
const proto = Object.getPrototypeOf(obj);
if (proto)
Object.setPrototypeOf(nobj, proto);
}
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
if (exclude.includes(key))
continue;
const value = obj[key];
nobj[key] = (typeof value === "object" && value !== null) ? Clone(value, ...exclude) : value;
}
}
return nobj;
}
XObject.Clone = Clone;
/**
* 对象实例哈希。
*
* @param obj 对象实例。
* @returns 哈希码。
*/
function HashCode(obj) {
let hash = 0;
if (obj == null)
return hash;
if (typeof obj === "boolean")
return obj ? 1 : 0;
if (typeof obj === "number")
hash = Math.floor(obj);
if (typeof obj === "string") {
for (let i = 0; i < obj.length; i++) {
const chr = obj.charCodeAt(i);
hash = ((hash << 5) - hash) + chr;
hash |= 0;
}
}
if (Array.isArray(obj)) {
for (let i = 0; i < obj.length; i++) {
hash = ((hash << 5) - hash) + HashCode(obj[i]);
hash |= 0;
}
}
if (typeof obj === "object") {
const keys = Object.keys(obj).sort();
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const keyHash = HashCode(key);
const valueHash = HashCode(obj[key]);
hash = ((hash << 5) - hash) + keyHash;
hash |= 0;
hash = ((hash << 5) - hash) + valueHash;
hash |= 0;
}
}
return Math.abs(hash);
}
XObject.HashCode = HashCode;
/**
* 替换对象的方法。
*
* @param obj 目标对象。
* @param from 要替换的方法名。
* @param to 新的方法实现。
* @returns 原始方法。
* @example
* ```typescript
* const obj = { method() { console.log('original'); } };
* XObject.Hook(obj, 'method', function() { console.log('hooked'); });
* ```
*/
function Hook(obj, from, to) {
let ret = null;
let err = null;
if (obj != null && to != null && from) {
let hook = hooks[obj];
if (hook == null) {
hook = {};
hooks[obj] = hook;
}
if (!hook[from]) {
ret = XObject.Value(obj, from);
if (ret != null && typeof (ret) == "function") {
if (XObject.IsClass(obj))
obj.prototype[from] = to;
else
obj[from] = to;
hook[from] = ret;
}
else {
err = "hook failed caused by nil or invalid target.";
}
}
else {
err = "hook failed caused by multiple hook.";
}
}
else {
err = "hook failed caused by invalid args.";
}
if (err)
console.error(err);
return ret;
}
XObject.Hook = Hook;
/**
* 恢复对象的原始方法。
*
* @param obj 目标对象。
* @param from 要恢复的方法名。
* @returns 原始方法。
* @example
* ```typescript
* XObject.Unhook(obj, 'method'); // 恢复原始方法
* ```
*/
function Unhook(obj, from) {
let ret = null;
let err = null;
if (obj != null && from) {
let hook = hooks[obj];
if (hook) {
ret = hook[from];
if (ret != null && typeof (ret) == "function") {
if (XObject.IsClass(obj))
obj.prototype[from] = ret;
else
delete obj[from];
}
else {
err = "unhook failed caused by nil or invalid target.";
}
delete hook[from];
let sig = true;
for (let _ in hook) {
sig = false;
break;
}
if (sig) {
delete hooks[obj]; // release references
}
}
else {
err = "unhook failed caused by nil hook map.";
}
}
else {
err = "unhook failed caused by invalid args.";
}
if (err)
console.error(err);
return ret;
}
XObject.Unhook = Unhook;
})(XObject || (XObject = {}));
// Copyright (c) 2025 EFramework Organization. All rights reserved.
/**
* XEnv 是一个环境管理工具,支持多平台及运行时环境识别等功能。
*
* 功能特性
* - 环境检测:自动识别运行环境及平台等信息
* - 应用信息:获取产品名称、版本、作者、标识符等信息
*
* 使用手册
* 1. 环境检测
*
* 1.1 运行时类型
* ```typescript
* // 运行时类型枚举
* enum RuntimeType {
* Node, // Node.js 运行时
* Code, // VSCode 扩展运行时
* Cocos, // Cocos Creator 运行时
* Unity, // Unity 运行时
* Unreal, // Unreal Engine 运行时
* Electron,// Electron 运行时
* Dom // 浏览器 DOM 运行时
* }
*
* // 获取当前运行时类型
* const runtime = XEnv.Runtime; // 返回RuntimeType枚举值
*
* // 使用预定义常量检查特定运行时
* if (XEnv.IsNode) {
* // Node.js环境下的逻辑
* }
* if (XEnv.IsCocos) {
* // Cocos环境下的逻辑
* }
* ```
*
* 1.2 平台类型
* ```typescript
* // 平台类型枚举
* enum PlatformType {
* Unknown, // 未知平台
* Windows, // Windows 平台
* Linux, // Linux 平台
* macOS, // macOS 平台
* Android, // Android 平台
* iOS, // iOS 平台
* Browser // 浏览器平台
* }
*
* // 获取当前平台类型
* const platform = XEnv.Platform; // 返回PlatformType枚举值
*
* // 使用预定义常量检查特定平台
* if (XEnv.IsNative) {
* // 原生平台下的逻辑
* }
* if (XEnv.IsBrowser) {
* // 浏览器环境下的逻辑
* }
* ```
*
* 2. 应用信息
*
* 2.1 获取基本信息
* ```typescript
* // 获取产品信息
* const appName = XEnv.Product;
* const appVersion = XEnv.Version;
* const appAuthor = XEnv.Author;
* const appId = XEnv.Identifier;
* const appDesc = XEnv.Description;
*
* console.log(`${appName} v${appVersion} by ${appAuthor}`);
* ```
*
* 更多信息请参考模块文档。
*/
var XEnv;
(function (XEnv) {
/**
* 运行时类型。
* 用于标识当前代码运行的环境类型。
*/
let RuntimeType;
(function (RuntimeType) {
/** Node.js 运行时 */
RuntimeType[RuntimeType["Node"] = 0] = "Node";
/** VSCode 扩展运行时 */
RuntimeType[RuntimeType["Code"] = 1] = "Code";
/** Cocos Creator 运行时 */
RuntimeType[RuntimeType["Cocos"] = 2] = "Cocos";
/** Unity 运行时 */
RuntimeType[RuntimeType["Unity"] = 3] = "Unity";
/** Unreal Engine 运行时 */
RuntimeType[RuntimeType["Unreal"] = 4] = "Unreal";
/** Electron 运行时 */
RuntimeType[RuntimeType["Electron"] = 5] = "Electron";
/** 浏览器 DOM 运行时 */
RuntimeType[RuntimeType["Dom"] = 6] = "Dom";
})(RuntimeType = XEnv.RuntimeType || (XEnv.RuntimeType = {}));
/**
* 平台类型。
* 用于标识当前运行的操作系统平台。
*/
let PlatformType;
(function (PlatformType) {
/** 未知平台 */
PlatformType[PlatformType["Unknown"] = 0] = "Unknown";
/** Windows 平台 */
PlatformType[PlatformType["Windows"] = 1] = "Windows";
/** Linux 平台 */
PlatformType[PlatformType["Linux"] = 2] = "Linux";
/** macOS 平台 */
PlatformType[PlatformType["macOS"] = 3] = "macOS";
/** Android 平台 */
PlatformType[PlatformType["Android"] = 4] = "Android";
/** iOS 平台 */
PlatformType[PlatformType["iOS"] = 5] = "iOS";
/** 浏览器平台 */
PlatformType[PlatformType["Browser"] = 6] = "Browser";
})(PlatformType = XEnv.PlatformType || (XEnv.PlatformType = {}));
var runtime = null;
/**
* 获取当前运行时类型。
* 通过检测全局对象特征判断运行时环境。
* 结果会被缓存以提高性能。
*/
function getRuntime() {
if (runtime == null) {
if (typeof process !== 'undefined' && !!process.env.VSCODE_PID) {
runtime = RuntimeType.Code;
return runtime;
}
if (typeof cc !== 'undefined') {
runtime = RuntimeType.Cocos;
return runtime;
}
if (typeof CS !== 'undefined') {
runtime = RuntimeType.Unity;
return runtime;
}
if (typeof UE !== 'undefined') {
runtime = RuntimeType.Unity;
return runtime;
}
runtime = RuntimeType.Node;
}
return runtime;
}
var platform = null;
/**
* 获取当前平台类型。
* 基于运行时环境判断具体的操作系统平台。
* 结果会被缓存以提高性能。
*/
function getPlatform() {
if (platform == null) {
if (getRuntime() == RuntimeType.Node) {
if (process.platform == "win32")
platform = PlatformType.Windows;
else if (process.platform == "darwin")
platform = PlatformType.macOS;
else if (process.platform == "linux")
platform = PlatformType.Linux;
else if (process.platform == "android")
platform = PlatformType.Android;
else
platform = PlatformType.Unknown;
}
else if (getRuntime() == RuntimeType.Cocos) {
// refer: https://docs.cocos.com/creator/3.8/api/zh/variable/sys?id=Platform
try {
if (cc.sys.isBrowser)
platform = PlatformType.Browser;
else if (cc.sys.platform == cc.sys.Platform.WIN32)
platform = PlatformType.Windows;
else if (cc.sys.platform == cc.sys.Platform.MACOS)
platform = PlatformType.macOS;
else if (cc.sys.platform == cc.sys.Platform.ANDROID)
platform = PlatformType.Android;
else if (cc.sys.platform == cc.sys.Platform.IOS)
platform = PlatformType.iOS;
else
platform = PlatformType.Unknown;
}
catch (error) {
platform = PlatformType.Unknown;
}
}
else if (getRuntime() == RuntimeType.Unity) {
const plat = CS.UnityEngine.Application.platform;
const platEnum = CS.UnityEngine.RuntimePlatform;
if (plat == platEnum.WindowsPlayer || plat == platEnum.WindowsEditor)
platform = PlatformType.Windows;
else if (plat == platEnum.OSXPlayer || plat == platEnum.OSXEditor)
platform = PlatformType.macOS;
else if (plat == platEnum.LinuxPlayer || plat == platEnum.LinuxEditor)
platform = PlatformType.Linux;
else if (plat == platEnum.Android)
platform = PlatformType.Android;
else if (plat == platEnum.IPhonePlayer)
platform = PlatformType.iOS;
else if (plat == platEnum.WebGLPlayer || plat == platEnum.WindowsWebPlayer || plat == platEnum.OSXWebPlayer)
platform = PlatformType.Browser;
else
platform = PlatformType.Unknown;
}
}
return platform;
}
/**
* 当前平台类型。
*/
XEnv.Platform = getPlatform();
/**
* 当前运行时类型。
*/
XEnv.Runtime = getRuntime();
/**
* 是否为 Node 或 VSCode 运行时。
*/
XEnv.IsNode = getRuntime() == RuntimeType.Node || getRuntime() == RuntimeType.Code;
/**
* 是否为 VSCode 扩展运行时。
*/
XEnv.IsCode = getRuntime() == RuntimeType.Code;
/**
* 是否为 Cocos Creator 运行时。
*/
XEnv.IsCocos = getRuntime() == RuntimeType.Cocos;
/**
* 是否为 Unity 运行时。
*/
XEnv.IsUnity = getRuntime() == RuntimeType.Unity;
/**
* 是否为 Unreal 运行时。
*/
XEnv.IsUnreal = getRuntime() == RuntimeType.Unreal;
/**
* 是否为原生平台。
*/
XEnv.IsNative = getPlatform() != PlatformType.Browser;
/**
* 是否为浏览器平台。
*/
XEnv.IsBrowser = getPlatform() == PlatformType.Browser;
/**
* 不支持的运行时和平台错误。
*/
XEnv.Unsupport = new Error(`Unsupported runtime: ${XObject.Key(XEnv.RuntimeType, XEnv.Runtime)} on platform: ${XObject.Key(XEnv.PlatformType, XEnv.Platform)}`);
const separator = "/";
/**
* 规范化给定的路径。
* 统一路径分隔符,处理相对路径和特殊字符。
*
* @param path 需要规范化的路径。
* @returns 规范化后的路径。
*/
function normalizePath(path) {
if (typeof path !== "string")
throw new TypeError("path must be a string");
let prefix = "";
if (path.startsWith("file://")) {
prefix = "file://";
}
else if (path.startsWith("jar:file://")) {
prefix = "jar:file://";
}
if (prefix != "") {
path = path.substring(prefix.length);
}
path = path.replace(/\\/g, separator);
const parts = path.split(separator);
const nparts = [];
for (let i = 0; i < parts.length; i++) {
let part = parts[i];
if ((part === "." || part === "")) {
if (nparts.length == 0)
nparts.push(part);
}
else if (part === "..") {
if (nparts.length > 0)
nparts.pop();
}
else
nparts.push(part);
}
const npath = nparts.join(separator);
return prefix + npath;
}
/**
* 返回给定路径的目录名称。
*
* @param path 需要获取目录名称的路径。
* @returns 目录名称。
*/
function directoryName(path) {
if (path) {
path = normalizePath(path);
let idx = path.lastIndexOf(separator);
if (idx >= 0)
path = path.substring(0, idx);
if (path == "file:/")
path += separator;
return path;
}
return "";
}
/**
* 将多个路径连接成一个。
*
* @param paths 需要连接的路径。
* @returns 连接后的路径。
*/
function pathJoin(...paths) {
paths = paths.filter(path => typeof path === "string" && path.trim() !== "");
if (paths.length === 0)
return "";
let ret = paths[0];
for (let i = 1; i < paths.length; i++) {
if (!paths[i].startsWith(separator) && !ret.endsWith(separator)) {
ret += separator;
}
ret += paths[i];
}
return normalizePath(ret);
}
/**
* 检查文件是否存在。
*
* @param file 需要检查的文件路径。
* @returns 如果文件存在则返回true,否则返回false。
*/
function hasFile(file) {
if (file) {
try {
const stat = require("fs").statSync(file);
return stat.isFile();
}
catch (_a) { }
}
return false;
}
/**
* 检查目录是否存在。
*
* @param dir 需要检查的目录路径。
* @returns 如果目录存在则返回true,否则返回false。
*/
function hasDirectory(dir) {
if (dir) {
dir = normalizePath(dir);
if (XEnv.IsNode) {
try {
const stat = require("fs").statSync(dir);
return stat.isDirectory();
}
catch (_a) { }
}
else if (XEnv.IsNative) {
if (XEnv.IsCocos) {
return jsb.fileUtils.isDirectoryExist(dir);
}
else if (XEnv.IsUnity) {
return CS.System.IO.Directory.Exists(dir);
}
else if (XEnv.IsUnreal) ;
}
else if (XEnv.IsBrowser) {
for (let i = 0; i < localStorage.length; i++) {
let key = localStorage.key(i);
let tdir = directoryName(key);
if (tdir == dir || key == dir)
return true;
}
}
else
throw XEnv.Unsupport;
}
return false;
}
/**
* 创建目录。
*
* @param dir 需要创建的目录路径。
*/
function createDirectory(dir) {
if (!dir || hasDirectory(dir))
return;
dir = normalizePath(dir);
if (XEnv.IsNode) {
if (dir.startsWith("file://") || dir.startsWith("jar:file://")) {
return;
}
const fs = require("fs");
dir = dir.replace(/\\/g, separator);
const parts = dir.split(separator);
const nparts = [];
for (let i = 0; i < parts.length; i++) {
let part = parts[i];
let sig = false;
if ((part === "." || part === "")) {
if (nparts.length == 0) {
nparts.push(part);
sig = true;
}
}
else if (part === "..") {
if (nparts.length > 0)
nparts.pop();
}
else {
nparts.push(part);
sig = true;
}
if (sig && nparts.length > 1) {
let tmp = nparts.join(separator);
if (!hasDirectory(tmp)) {
fs.mkdirSync(tmp);
}
}
}
}
else if (XEnv.IsNative) {
if (XEnv.IsCocos) {
jsb.fileUtils.createDirectory(dir);
}
else if (XEnv.IsUnity) {
CS.System.IO.Directory.CreateDirectory(dir);
}
else if (XEnv.IsUnreal) ;
}
else if (XEnv.IsBrowser) {
localStorage.setItem(dir, "");
}
else
throw XEnv.Unsupport;
}
var localPath;
/**
* 获取数据存储路径。
* 根据不同运行时环境返回适当的数据存储位置。
*
* @returns 数据存储路径。
*/
function getLocalPath() {
if (localPath == null) {
if (XEnv.IsNode) {
if (typeof jest != "undefined") {
localPath = process.cwd();
}
else {
if (require.main && require.main.filename) {
let dir = directoryName(require.main.filename);
if (hasFile(pathJoin(dir, "package.json"))) {
localPath = dir;
}
else {
dir = pathJoin(dir, "..");
if (hasFile(pathJoin(dir, "package.json"))) {
localPath = dir;
}
}
}
else {
let err = new Error();
if (err.stack) {
let lines = err.stack.split("\n");
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
if (line.indexOf(".js") >= 0) {
let strs = line.split("(");
if (strs.length > 1)
line = strs[1];
strs = line.split("file:///");
if (strs.length > 1)
line = strs[1];
strs = line.split(".js");
let file = strs[0] + ".js";
let dir = directoryName(file);
if (hasFile(pathJoin(dir, "package.json"))) {
localPath = dir;
}
else {
dir = pathJoin(dir, "..");
if (hasFile(pathJoin(dir, "package.json"))) {
localPath = dir;
}
}
}
if (localPath != null)
break;
}
}
}
}
if (localPath == null) {
let dir = __dirname;
if (hasFile(pathJoin(dir, "package.json"))) {
localPath = dir;
}
else {
dir = pathJoin(dir, "..");
if (hasFile(pathJoin(dir, "package.json"))) {
localPath = dir;
}
}
}
if (localPath == null)
localPath = "Unknown";
else
localPath = pathJoin(localPath, "local");
}
else if (XEnv.IsBrowser) {
localPath = "file://";
}
else if (XEnv.IsCocos) {
localPath = pathJoin(jsb.fileUtils.getWritablePath(), "local");
}
else if (XEnv.IsUnity) {
if (CS.UnityEngine.Application.isEditor) {
localPath = pathJoin(CS.UnityEngine.Application.dataPath, "..", "Local");
}
else if (CS.UnityEngine.Application.platform == CS.UnityEngine.RuntimePlatform.WindowsPlayer) {
localPath = pathJoin(CS.UnityEngine.Application.streamingAssetsPath, "..", "Local");
}
else {
localPath = normalizePath(CS.UnityEngine.Application.persistentDataPath);
}
}
if (localPath != "Unknown") {
if (hasDirectory(localPath) == false)
createDirectory(localPath);
}
}
return localPath;
}
/**
* 数据路径。
*/
XEnv.LocalPath = getLocalPath();
/**
* 获取包信息。
* 读取并解析 package.json 文件。
*
* @returns 包信息对象。
*/
function getPackage() {
if (XEnv.IsNode) {
const pf = pathJoin(XEnv.LocalPath, "..", "package.json");
if (hasFile(pf)) {
try {
let str = require("fs").readFileSync(pf);
let pkg = JSON.parse(str.toString());
return pkg;
}
catch (error) { }
}
}
}
var product;
/**
* 获取产品名称。
*
* @returns 产品名称。
*/
function getProduct() {
if (product == null) {
if (XEnv.IsNode) {
const pkg = getPackage();
if (pkg) {
if (pkg.displayName)
product = pkg.displayName;
else
product = pkg.name;
}
}
else if (XEnv.IsUnity)
product = CS.UnityEngine.Application.productName;
if (product == null)
product = "Unknown";
}
return product;
}
/**
* 产品名称。
*/
XEnv.Product = getProduct();
var author;
/**
* 获取作者名称。
*
* @returns 作者名称。
*/
function getAuthor() {
if (author == null) {
if (XEnv.IsNode) {
const pkg = getPackage();
if (pkg) {
if (pkg.publisher)
author = pkg.publisher;
else if (pkg.author) {
if (typeof (pkg.author) == "string")
author = pkg.author;
else
author = pkg.author.name;
}
}
}
if (author == null)
author = "Unknown";
}
return author;
}
/**
* 作者名称。
*/
XEnv.Author = getAuthor();
var identifier;
/**
* 获取标识符。
*
* @returns 标识符。
*/
function getIdentifier() {
if (identifier == null) {
if (XEnv.IsNode) {
const pkg = getPackage();
if (pkg)
identifier = pkg.name;
}
else if (XEnv.IsUnity)
identifier = CS.UnityEngine.Application.identifier;
if (identifier == null || identifier == "")
identifier = "Unknown";
}
return identifier;
}
XEnv.getIdentifier = getIdentifier;
/**
* 应用标识符。
*/
XEnv.Identifier = getIdentifier();
var version;
/**
* 获取版本。
*
* @returns 版本。
*/
function getVersion() {
if (version == null) {
if (XEnv.IsNode) {
const pkg = getPackage();
if (pkg)
version = pkg.version;
}
else if (XEnv.IsUnity)
version = CS.UnityEngine.Application.version;
if (version == null)
version = "0.0";
}
return version;
}
/**
* 应用版本。
*/
XEnv.Version = getVersion();
var description;
/**
* 获取描述。
*
* @returns 描述。
*/
function getDescription() {
if (description == null) {
if (XEnv.IsNode) {
const pkg = getPackage();
if (pkg)
description = pkg.description;
}
if (description == null)
description = "";
}
return description;
}
/**
* 应用描述。
*/
XEnv.Description = getDescription();
})(XEnv || (XEnv = {}));
// Copyright (c) 2025 EFramework Organization. All rights reserved.
/**
* XString 提供了字符串处理工具集,支持查找、替换、格式化以及编码转换等功能。
*
* 功能特性
* - 支持字符串基本操作:判空、查找、截取、分割等常用功能
* - 提供字符串匹配检测:包含、前缀、后缀检查
* - 实现字符串格式化:使用占位符进行文本格式化
* - 提供编码转换:Base64 编码解码、文本与二进制互转
*
* 使用手册
* 1. 字符串基本操作
*
* 1.1 判空与检查
* ```typescript
* // 检查字符串是否为空
* XString.IsNullOrEmpty(""); // true
* XString.IsNullOrEmpty(null); // true
* XString.IsNullOrEmpty("hello"); // false
*
* // 字符串常量
* const emptyStr = XString.Empty; // 空字符串
* ```
*
* 1.2 查找与索引
* ```typescript
* // 查找子字符串位置
* XString.IndexOf("hello world", "world"); // 返回 6
* XString.LastIndexOf("hello.world.js", "."); // 返回 10
*
* // 检查是否包含子字符串
* XString.Contains("hello world", "world"); // true
* XString.Contains("hello world", "xyz"); // false
* ```
*
* 1.3 截取与分割
* ```typescript
* // 截取子字符串
* XString.Sub("hello world", 0, 5); // 返回 "hello"
*
* // 分割字符串
* XString.Split("a,b,c", ","); // 返回 ["a", "b", "c"]
* XString.Split("hello world", " "); // 返回 ["hello", "world"]
* ```
*
* 2. 字符串处理
*
* 2.1 修饰与替换
* ```typescript
* // 去除首尾空格
* XString.Trim(" hello "); // 返回 "hello"
*
* // 替换字符串
* XString.Replace("hello world", "world", "universe"); // 返回 "hello universe"
* ```
*
* 2.2 前缀后缀检查
* ```typescript
* // 检查前缀
* XString.StartsWith("hello world", "hello"); // true
* XString.StartsWith("hello world", "world"); // false
*
* // 检查后缀
* XString.EndsWith("hello world", "world"); // true
* XString.EndsWith("hello world", "hello"); // false
* ```
*
* 3. 字符串格式化
*
* 3.1 使用占位符格式化
* ```typescript
* // 简单替换
* XString.Format("Hello {0}!", "world"); // 返回 "Hello world!"
*
* // 多参数替换
* XString.Format("{0} + {1} = {2}", 1, 2, 3); // 返回 "1 + 2 = 3"
*
* // 复杂对象格式化
* const user = { name: "张三" };
* XString.Format("用户: {0}", user); // 返回 "用户: [object Object]"
* ```
*
* 4. 版本号处理
*
* 4.1 版本号转换
* ```typescript
* // 字符串版本号转为数字
* XString.ToVersion("1.2.3"); // 返回数字表示
* XString.ToVersion("v1.2"); // 同样可以处理
*
* // 数字版本号转为字符串
* XString.FromVersion(10203); // 返回 "1.2.3"
* ```
*
* 5. 编码转换
*
* 5.1 Base64编码
* ```typescript
* // 文本转Base64
* XString.ToBase64("Hello"); // 返回 "SGVsbG8="
*
* // Base64解码
* XString.FromBase64("SGVsbG8="); // 返回 "Hello"
* ```
*
* 5.2 二进制转换
* ```typescript
* // 字符串转ArrayBuffer
* const buffer = XString.ToBuffer("Hello");
*
* // ArrayBuffer转字符串
* const text = XString.FromBuffer(buffer); // 返回 "Hello"
* ```
*
* 更多信息请参考模块文档。
*/
var XString;
(function (XString) {
/**
* 空字符串。
*/
XString.Empty = "";
/**
* 判断字符串是否为空。
*
* @param str 要检查的字符串。
* @returns 如果字符串为 null、undefined 或空字符串返回 true。
* @example
* ```typescript
* XString.IsNullOrEmpty(""); // true
* XString.IsNullOrEmpty(null); // true
* XString.IsNullOrEmpty("hello"); // false
* ```
*/
function IsNullOrEmpty(str) {
return !str || str === "";
}
XString.IsNullOrEmpty = IsNullOrEmpty;
/**
* 字符串索引。
*
* @param str 源字符串。
* @param sub 要查找的子字符串。
* @returns 子字符串的索引,如果未找到返回 -1。
* @example
* ```typescript
* XString.IndexOf("hello world", "world"); // 返回 6
* XString.IndexOf("hello world", "xyz"); // 返回 -1
* ```
*/
function IndexOf(str, sub) {
if (IsNullOrEmpty(str) == false && IsNullOrEmpty(sub) == false) {
return str.indexOf(sub);
}
return -1;
}
XString.IndexOf = IndexOf;
/**
* 查找子字符串最后一次出现的位置。
*
* @param str 源字符串。
* @param sub 要查找的子字符串。
* @returns 子字符串最后一次出现的索引,如果未找到返回 -1。
* @example
* ```typescript
* XString.LastIndexOf("hello.world.js", "."); // 返回 10
* XString.LastIndexOf("hello world", "o"); // 返回 7
* ```
*/
function LastIndexOf(str, sub) {
if (IsNullOrEmpty(str) == false && IsNullOrEmpty(sub) == false) {
return str.lastIndexOf(sub);
}
return -1;
}
XString.LastIndexOf = LastIndexOf;
/**
* 截取字符串的一部分。
*
* @param str 源字符串。
* @param start 起始位置。
* @param end 结束位置(不包含)。
* @returns 截取的子字符串。
* @example
* ```typescript
* XString.Sub("hello world", 0, 5); // 返回 "hello"
* ```
*/
function Sub(str, from, to) {
if (IsNullOrEmpty(str) == false) {
return str.substring(from, to);
}
return null;
}
XString.Sub = Sub;
/**
* 字符串替换。
*
* @param str 字符串实例。
* @param from 源字符串。
* @param to 目标字符串。
* @returns 替换后的字符串。
*/
function Replace(str, from, to) {
if (IsNullOrEmpty(str) == false && IsNullOrEmpty(from) == false) {
return str.replace(new RegExp(from, "gm"), to);
}
return str;
}
XString.Replace = Replace;
/**
* 字符串裁剪。
*
* @param str 字符串实例。
* @returns 裁剪后的字符串。
*/
function Trim(str) {
if (IsNullOrEmpty(str) == false) {
return str.trim();
}
return str;
}
XString.Trim = Trim;
/**
* 字符串分割。
*
* @param str 源字符串。
* @param sep 分隔符。
* @returns 分割后的子字符串数组。
* @example
* ```typescript
* XString.Split("a,b,c", ","); // 返回 ["a", "b", "c"]
* XString.Split("hello world", " "); // 返回 ["hello", "world"]
* ```
*/
function Split(str, sep) {
if (IsNullOrEmpty(str) == false && IsNullOrEmpty(sep) == false) {
return str.split(sep);
}
return null;
}
XString.Split = Split;
/**
* 字符串是否包含。
*
* @param str 源字符串。
* @param sub 要查找的子字符串。
* @returns 是否包含指定的子字符串。
* @example
* ```typescript
* XString.Contains("hello world", "world"); // 返回 true
* XString.Contains("hello world", "xyz"); // 返回 false
* ```
*/
function Contains(str, sub) {
return IndexOf(str, sub) >= 0;
}
XString.Contains = Contains;
/**
* 字符串头部匹配。
*
* @param str 源字符串。
* @param prefix 前缀字符串。
* @returns 是否以指定字符串开头。
* @example
* ```typescript
* XString.StartsWith("hello world", "hello"); // 返回 true
* XString.StartsWith("hello world", "world"); // 返回 false
* ```
*/
function StartsWith(str, prefix) {
return IndexOf(str, prefix) == 0;
}
XString.StartsWith = StartsWith;
/**
* 字符串尾部匹配。
*
* @param str 源字符串。
* @param suffix 后缀字符串。
* @returns 是否以指定字符串结尾。
* @example
* ```typescript
* XString.EndsWith("hello world", "world"); // 返回 true
* XString.EndsWith("hello world", "hello"); // 返回 false
* ```
*/
function EndsWith(str, suffix) {
if (IsNullOrEmpty(str) == false && IsNullOrEmpty(suffix) == false) {
return str.endsWith(suffix);
}
return false;
}
XString.EndsWith = EndsWith;
/**
* 格式化字符串。
* 使用 {n} 作为占位符,n 为参数索引。
*
* @param format 格式字符串。
* @param args 格式化参数。
* @returns 格式化后的字符串。
* @example
* ```typescript
* XString.Format("Hello {0}!", "world"); // 返回 "Hello world!"
* XString.Format("{0} + {1} = {2}", 1, 2, 3); // 返回 "1 + 2 = 3"
* ```
*/
function Format(fmt, ...args) {
if (fmt) {
if (args.length > 0) {
let index = 0;
const doReplace = (rplc) => {
if (rplc == null)
rplc = "undefined";
if (rplc instanceof Array) {
for (let i = 0; i < rplc.length; i++) {
let temp = rplc[i];
doReplace(temp);
}
}
else {
let str;
let reg = new RegExp("({)" + index + "(})", "g");
if (typeof (rplc) == "string") {
str = rplc;
}
else {
str = rplc.toString();
}
fmt = fmt.replace(reg, str);
index++;
}
};
for (let i = 0; i < args.length; i++) {
let temp = args[i];
if (temp != null) {
doReplace(temp);
}
}
}
return fmt;
}
else {
return null;
}
}
XString.Format = Format;
/**
* 将字符串转换为版本号。
* 支持多级版本号格式。
*
* @param str 版本号字符串。
* @returns 标准化的版本号字符串。
* @example
* ```typescript
* XString.ToVersion("1.2.3"); // 返回 "1.2.3"
* XString.ToVersion("v1.2"); // 返回 "1.2.0"
* ```
*/
function ToVersion(version) {
if (IsNullOrEmpty(version)) {
return -1;
}
let strs = version.split(".");
if (strs == null || strs.length == 0) {
return -1;
}
else {
let finalVersion = 0;
let large = (strs.length - 1) * 2;
for (let i = 0; i < strs.length; i++) {
let singleVersion = parseInt(strs[i]);
if (i == 0) {
finalVersion = (large == 0 ? singleVersion : singleVersion * (Math.pow(10, large)));
}
else if (i == strs.length - 1) {
finalVersion += singleVersion;
}
else {
finalVersion += singleVersion * (Math.pow(10, large - i * 2));
}
}
return finalVersion;
}
}
XString.ToVersion = ToVersion;
/**
* 数字转版本号。
*
* @param version 版本号数字。
* @returns 版本号字符串。
*/
function FromVersion(version) {
let finalVersion = "";
let str = version.toString();
let singleVersion = 0;
for (let i = str.length - 1; i >= 0;) {
let length = (i - 1) >= 0 ? 2 : 1;
let from = i - length + 1;
singleVersion = parseInt(str.substr(from, length));
finalVersion = singleVersion + finalVersion;
if (i > 1) {
finalVersion = "." + finalVersion;
}
i -= 2;
}
return finalVersion;
}
XString.FromVersion = FromVersion;
/**
* 将字符串转换为 ArrayBuffer。
*
* @param str 要转换的字符串。
* @returns ArrayBuffer 对象。
* @example
* ```typescript
* const buffer = XString.ToBuffer("Hello");
* ```
*/
function ToBuffer(str) {
const encoder = new TextEncoder();
return encoder.encode(str).buffer;
}
XString.ToBuffer = ToBuffer;
/**
* 将 ArrayBuffer 转换为字符串。
*
* @param buffer ArrayBuffer 对象。
* @returns 转换后的字符串。
* @example
* ```typescript
* const str = XString.FromBuffer(buffer);
* ```
*/
function FromBuffer(buf) {
const decoder = new TextDecoder();
if (XEnv.IsCocos && XEnv.IsCocos)
return decoder.decode(new Uint8Array(buf));
else
return decoder.decode(buf);
}
XString.FromBuffer = FromBuffer;
/**
* 将字符串转换为 Base64 编码。
*
* @param str 要编码的字符串。
* @returns Base64 编码的字符串。
* @example
* ```typescript
* XString.ToBase64("Hello"); // 返回 "SGVsbG8="
* ```
*/
function ToBase64(str) {
if (XEnv.IsBrowser || XEnv.IsCocos) {
let utf8Encoder = new TextEncoder();
let binaryData = utf8Encoder.encode(str);
let binaryArray = Array.from(binaryData);
let binaryString = "";
for (let byte of binaryArray) {
binaryString += String.fromCharCode(byte);
}
return btoa(binaryString);
}
else {
return Buffer.from(str).toString("base64");
}
}
XString.ToBase64 = ToBase64;
/**
* 将 Base64 编码转换为字符串。
*
* @param str Base64 编码的字符串。
* @returns 解码后的字符串。
* @example
* ```typescript
* XString.FromBase64("SGVsbG8="); // 返回 "Hello"
* ```
*/
function FromBase64(str) {
if (XEnv.IsBrowser || XEnv.IsCocos) {
let binaryString = atob(str);
let binaryArray = new Uint8Array(binaryString.length);