@fast-china/utils 2.1.10 → 2.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +5 -2
- package/README.zh.md +5 -2
- package/dist/array/index.mjs +21 -21
- package/dist/array/index.mjs.map +1 -1
- package/dist/async/index.mjs +32 -32
- package/dist/async/index.mjs.map +1 -1
- package/dist/base64/index.mjs +44 -51
- package/dist/base64/index.mjs.map +1 -1
- package/dist/color/index.mjs +33 -33
- package/dist/color/index.mjs.map +1 -1
- package/dist/crypto/index.mjs +153 -155
- package/dist/crypto/index.mjs.map +1 -1
- package/dist/date/index.mjs +79 -46
- package/dist/date/index.mjs.map +1 -1
- package/dist/dom/style.mjs +7 -7
- package/dist/dom/style.mjs.map +1 -1
- package/dist/env/index.mjs +9 -14
- package/dist/env/index.mjs.map +1 -1
- package/dist/function/index.mjs +4 -4
- package/dist/function/index.mjs.map +1 -1
- package/dist/identity/index.mjs +7 -7
- package/dist/identity/index.mjs.map +1 -1
- package/dist/index.d.mts +371 -366
- package/dist/index.global.min.js +2 -2
- package/dist/index.global.min.js.map +1 -1
- package/dist/internal/text.mjs +70 -26
- package/dist/internal/text.mjs.map +1 -1
- package/dist/logger/index.mjs +12 -13
- package/dist/logger/index.mjs.map +1 -1
- package/dist/number/index.mjs +63 -42
- package/dist/number/index.mjs.map +1 -1
- package/dist/object/index.mjs +32 -31
- package/dist/object/index.mjs.map +1 -1
- package/dist/storage/index.mjs +58 -63
- package/dist/storage/index.mjs.map +1 -1
- package/dist/string/index.mjs +60 -64
- package/dist/string/index.mjs.map +1 -1
- package/dist/vue/breakpoints.mjs +14 -10
- package/dist/vue/breakpoints.mjs.map +1 -1
- package/dist/vue/element-size.mjs +4 -4
- package/dist/vue/element-size.mjs.map +1 -1
- package/dist/vue/emits.mjs +7 -7
- package/dist/vue/emits.mjs.map +1 -1
- package/dist/vue/event-listener.mjs +5 -5
- package/dist/vue/event-listener.mjs.map +1 -1
- package/dist/vue/expose.mjs +3 -3
- package/dist/vue/expose.mjs.map +1 -1
- package/dist/vue/func.mjs +2 -2
- package/dist/vue/func.mjs.map +1 -1
- package/dist/vue/install.mjs +24 -24
- package/dist/vue/install.mjs.map +1 -1
- package/dist/vue/now.mjs +4 -5
- package/dist/vue/now.mjs.map +1 -1
- package/dist/vue/props.mjs +5 -5
- package/dist/vue/props.mjs.map +1 -1
- package/dist/vue/render.mjs +2 -2
- package/dist/vue/render.mjs.map +1 -1
- package/dist/vue/resize-observer.mjs +4 -6
- package/dist/vue/resize-observer.mjs.map +1 -1
- package/dist/vue/slots.mjs.map +1 -1
- package/dist/vue/transition.mjs +5 -7
- package/dist/vue/transition.mjs.map +1 -1
- package/dist/vue/window-size.mjs +2 -4
- package/dist/vue/window-size.mjs.map +1 -1
- package/dist/vue/with.mjs +1 -1
- package/dist/vue/with.mjs.map +1 -1
- package/package.json +2 -1
- package/dist/internal/runtime.mjs +0 -32
- package/dist/internal/runtime.mjs.map +0 -1
package/dist/object/index.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* 判断 Query Value 是否为重复参数数组。
|
|
4
4
|
*
|
|
5
|
-
* @param value - 单值或数组形式的 Query Value
|
|
5
|
+
* @param value - 单值或数组形式的 Query Value
|
|
6
6
|
* @returns 是只读原始值数组时返回 `true`。
|
|
7
7
|
*/
|
|
8
8
|
const isQueryPrimitiveArray = (value) => Array.isArray(value);
|
|
@@ -10,9 +10,9 @@ const isQueryPrimitiveArray = (value) => Array.isArray(value);
|
|
|
10
10
|
* 安全写入结果对象的自有可枚举属性。
|
|
11
11
|
*
|
|
12
12
|
* @remarks 使用 `defineProperty` 避免 `__proto__` 触发 Setter,并统一创建可写、可配置的自有可枚举数据属性。
|
|
13
|
-
* @param target -
|
|
14
|
-
* @param key -
|
|
15
|
-
* @param value -
|
|
13
|
+
* @param target - 要写入的结果对象
|
|
14
|
+
* @param key - 自有属性键
|
|
15
|
+
* @param value - 属性值
|
|
16
16
|
*/
|
|
17
17
|
const defineEnumerableProperty = (target, key, value) => {
|
|
18
18
|
Object.defineProperty(target, key, {
|
|
@@ -198,7 +198,7 @@ const equalObjects = (left, right, state) => {
|
|
|
198
198
|
const leftKeys = getEnumerableOwnKeys(left);
|
|
199
199
|
const rightKeys = getEnumerableOwnKeys(right);
|
|
200
200
|
if (leftKeys.length !== rightKeys.length) return false;
|
|
201
|
-
for (const key of leftKeys) if (!Object.
|
|
201
|
+
for (const key of leftKeys) if (!Object.prototype.hasOwnProperty.call(right, key)) return false;
|
|
202
202
|
return compareTrackedPair(left, right, state, () => {
|
|
203
203
|
let compareConstructors = true;
|
|
204
204
|
for (const key of leftKeys) {
|
|
@@ -246,7 +246,7 @@ function isEqualValue(left, right, state) {
|
|
|
246
246
|
/**
|
|
247
247
|
* 判断值是否是普通对象。
|
|
248
248
|
*
|
|
249
|
-
* @param value -
|
|
249
|
+
* @param value - 任意待检查值
|
|
250
250
|
* @returns 原型为 `Object.prototype` 或 `null` 时返回 `true`。
|
|
251
251
|
*/
|
|
252
252
|
function isPlainObject(value) {
|
|
@@ -258,19 +258,19 @@ function isPlainObject(value) {
|
|
|
258
258
|
* 安全判断对象是否拥有自己的属性。
|
|
259
259
|
*
|
|
260
260
|
* @remarks 不调用可能被对象覆盖的 `hasOwnProperty`。
|
|
261
|
-
* @param value -
|
|
262
|
-
* @param key - 字符串、数字或 Symbol
|
|
261
|
+
* @param value - 待检查对象
|
|
262
|
+
* @param key - 字符串、数字或 Symbol 属性键
|
|
263
263
|
* @returns 属性为对象自有属性时返回 `true`,并收窄键类型。
|
|
264
264
|
*/
|
|
265
265
|
function hasOwn(value, key) {
|
|
266
|
-
return Object.
|
|
266
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
267
267
|
}
|
|
268
268
|
/**
|
|
269
269
|
* 递归创建值的深层副本。
|
|
270
270
|
*
|
|
271
271
|
* @remarks 支持循环引用、共享引用、Symbol 键、对象原型、ArrayBuffer、DataView、Date、Map、RegExp、Set 和 TypedArray。
|
|
272
272
|
* Map 的键保持原引用,函数及其他不可克隆值在嵌套位置保持原引用;只复制自有可枚举属性。
|
|
273
|
-
* @param value -
|
|
273
|
+
* @param value - 需要深复制的任意值
|
|
274
274
|
* @returns 与输入类型一致且不共享可克隆嵌套值的新值;原始类型直接返回自身。
|
|
275
275
|
*/
|
|
276
276
|
function cloneDeep(value) {
|
|
@@ -281,8 +281,8 @@ function cloneDeep(value) {
|
|
|
281
281
|
*
|
|
282
282
|
* @remarks 原始值使用 SameValueZero 语义;支持循环引用、数组、对象、ArrayBuffer、DataView、Date、Error、Map、RegExp、Set、Symbol 和 TypedArray。
|
|
283
283
|
* 对象只比较自有可枚举字符串与 Symbol 属性,函数及其他不支持的宿主对象仅在引用相同时相等。
|
|
284
|
-
* @param left -
|
|
285
|
-
* @param right -
|
|
284
|
+
* @param left - 第一待比较值
|
|
285
|
+
* @param right - 第二待比较值
|
|
286
286
|
* @returns 两个值深度等价时返回 `true`。
|
|
287
287
|
*/
|
|
288
288
|
function isEqual(left, right) {
|
|
@@ -304,9 +304,9 @@ function omit(source, keys) {
|
|
|
304
304
|
/**
|
|
305
305
|
* 按条件排除对象的自有可枚举属性。
|
|
306
306
|
*
|
|
307
|
-
* @param source -
|
|
307
|
+
* @param source - 不会被修改的源对象
|
|
308
308
|
* @param predicate - 接收属性值、键和源对象;返回真值时排除该属性。
|
|
309
|
-
* @returns
|
|
309
|
+
* @returns 由未匹配属性组成的新对象
|
|
310
310
|
*/
|
|
311
311
|
function omitBy(source, predicate) {
|
|
312
312
|
const result = {};
|
|
@@ -316,9 +316,9 @@ function omitBy(source, predicate) {
|
|
|
316
316
|
/**
|
|
317
317
|
* 按条件选择对象的自有可枚举属性。
|
|
318
318
|
*
|
|
319
|
-
* @param source -
|
|
319
|
+
* @param source - 不会被修改的源对象
|
|
320
320
|
* @param predicate - 接收属性值、键和源对象;返回真值时保留该属性。
|
|
321
|
-
* @returns
|
|
321
|
+
* @returns 由匹配属性组成的新对象
|
|
322
322
|
*/
|
|
323
323
|
function pickBy(source, predicate) {
|
|
324
324
|
const result = {};
|
|
@@ -328,9 +328,9 @@ function pickBy(source, predicate) {
|
|
|
328
328
|
/**
|
|
329
329
|
* 映射对象的自有可枚举属性值。
|
|
330
330
|
*
|
|
331
|
-
* @param source -
|
|
332
|
-
* @param mapper -
|
|
333
|
-
* @returns
|
|
331
|
+
* @param source - 不会被修改的源对象
|
|
332
|
+
* @param mapper - 接收值、键和源对象的映射函数
|
|
333
|
+
* @returns 保留原键的新对象
|
|
334
334
|
*/
|
|
335
335
|
function mapValues(source, mapper) {
|
|
336
336
|
const result = {};
|
|
@@ -341,8 +341,8 @@ function mapValues(source, mapper) {
|
|
|
341
341
|
* 对自有可枚举属性执行 SameValue 浅比较。
|
|
342
342
|
*
|
|
343
343
|
* @remarks 嵌套对象只比较引用;`NaN` 相等,`0` 与 `-0` 不相等。
|
|
344
|
-
* @param left -
|
|
345
|
-
* @param right -
|
|
344
|
+
* @param left - 第一对象
|
|
345
|
+
* @param right - 第二对象
|
|
346
346
|
* @returns 自有可枚举键集合与对应值均满足 SameValue 时返回 `true`。
|
|
347
347
|
*/
|
|
348
348
|
function shallowEqual(left, right) {
|
|
@@ -350,38 +350,39 @@ function shallowEqual(left, right) {
|
|
|
350
350
|
const leftKeys = Reflect.ownKeys(left).filter((key) => Object.prototype.propertyIsEnumerable.call(left, key));
|
|
351
351
|
const rightKeys = Reflect.ownKeys(right).filter((key) => Object.prototype.propertyIsEnumerable.call(right, key));
|
|
352
352
|
if (leftKeys.length !== rightKeys.length) return false;
|
|
353
|
-
return leftKeys.every((key) => Object.
|
|
353
|
+
return leftKeys.every((key) => Object.prototype.hasOwnProperty.call(right, key) && Object.is(Reflect.get(left, key), Reflect.get(right, key)));
|
|
354
354
|
}
|
|
355
355
|
/**
|
|
356
356
|
* 把 Query 原始值规范化为文本。
|
|
357
357
|
*
|
|
358
|
-
* @param value - 已排除空值的字符串、数字、布尔值或 BigInt
|
|
359
|
-
* @returns 与 URLSearchParams
|
|
358
|
+
* @param value - 已排除空值的字符串、数字、布尔值或 BigInt
|
|
359
|
+
* @returns 与 URLSearchParams 兼容的文本值
|
|
360
360
|
* @throws `RangeError` 当数字不是有限值。
|
|
361
361
|
*/
|
|
362
362
|
const serializeQueryValue = (value) => {
|
|
363
|
-
if (typeof value === "number" && !Number.isFinite(value)) throw new RangeError("
|
|
363
|
+
if (typeof value === "number" && !Number.isFinite(value)) throw new RangeError("Query parameter numbers must be finite.");
|
|
364
364
|
return String(value);
|
|
365
365
|
};
|
|
366
366
|
/**
|
|
367
367
|
* 将对象序列化为标准 URL 查询字符串。
|
|
368
368
|
*
|
|
369
369
|
* @remarks `null` 与 `undefined` 被跳过;数组使用重复键;返回值不会修改输入。
|
|
370
|
-
* @param value -
|
|
371
|
-
* @param options -
|
|
370
|
+
* @param value - 查询参数对象
|
|
371
|
+
* @param options - 排序、空格和问号前缀选项
|
|
372
372
|
* @returns URL 编码后的查询字符串;没有参数时始终返回空字符串。
|
|
373
373
|
* @throws `RangeError` 当参数包含 `NaN` 或无穷数字。
|
|
374
|
+
* @throws `URIError` 当键或值包含孤立的 UTF-16 代理项。
|
|
374
375
|
*/
|
|
375
376
|
function toQueryString(value, options = {}) {
|
|
376
377
|
const entries = Object.entries(value);
|
|
377
378
|
if (options.sort) entries.sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
|
|
378
|
-
const parameters =
|
|
379
|
+
const parameters = [];
|
|
379
380
|
for (const [key, rawValue] of entries) {
|
|
380
381
|
const values = isQueryPrimitiveArray(rawValue) ? rawValue : [rawValue];
|
|
381
|
-
for (const item of values) if (item !== null && item !== void 0) parameters.
|
|
382
|
+
for (const item of values) if (item !== null && item !== void 0) parameters.push(`${encodeURIComponent(key)}=${encodeURIComponent(serializeQueryValue(item))}`);
|
|
382
383
|
}
|
|
383
|
-
let result = parameters.toString();
|
|
384
|
-
if (options.space
|
|
384
|
+
let result = parameters.join("&").replace(/[!'()~]/gu, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
385
|
+
if (options.space !== "percent") result = result.replace(/%20/gu, "+");
|
|
385
386
|
return result && options.prefixQuestionMark ? `?${result}` : result;
|
|
386
387
|
}
|
|
387
388
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/object/index.ts"],"sourcesContent":["/** URL 查询参数支持的单值类型。 */\nexport type QueryPrimitive = bigint | boolean | number | string | null | undefined;\n\n/** URL 查询参数值;数组使用重复键表示。 */\nexport type QueryValue = QueryPrimitive | readonly QueryPrimitive[];\n\n/**\n * 判断 Query Value 是否为重复参数数组。\n *\n * @param value - 单值或数组形式的 Query Value。\n * @returns 是只读原始值数组时返回 `true`。\n */\nconst isQueryPrimitiveArray = (value: QueryValue): value is readonly QueryPrimitive[] => Array.isArray(value);\n\n/** {@link toQueryString} 的序列化选项。 */\nexport interface QueryStringOptions {\n\t/** 返回非空结果时是否添加 `?`;默认 `false`。 */\n\tprefixQuestionMark?: boolean;\n\t/** 是否按键的 UTF-16 码元顺序稳定排序;默认保留对象枚举顺序。 */\n\tsort?: boolean;\n\t/** 空格编码方式;默认遵循表单编码并输出 `+`。 */\n\tspace?: \"percent\" | \"plus\";\n}\n\n/**\n * 安全写入结果对象的自有可枚举属性。\n *\n * @remarks 使用 `defineProperty` 避免 `__proto__` 触发 Setter,并统一创建可写、可配置的自有可枚举数据属性。\n * @param target - 要写入的结果对象。\n * @param key - 自有属性键。\n * @param value - 属性值。\n */\nconst defineEnumerableProperty = (target: object, key: PropertyKey, value: unknown): void => {\n\tObject.defineProperty(target, key, { configurable: true, enumerable: true, value, writable: true });\n};\n\nconst typedArrayTags = new Set([\n\t\"[object BigInt64Array]\",\n\t\"[object BigUint64Array]\",\n\t\"[object Float32Array]\",\n\t\"[object Float64Array]\",\n\t\"[object Int8Array]\",\n\t\"[object Int16Array]\",\n\t\"[object Int32Array]\",\n\t\"[object Uint8Array]\",\n\t\"[object Uint8ClampedArray]\",\n\t\"[object Uint16Array]\",\n\t\"[object Uint32Array]\",\n]);\n\n/** 使用源值的构造器创建同类空实例。 */\nconst createUsingConstructor = (value: object, arguments_: readonly unknown[]): object => {\n\tconst constructor: unknown = Reflect.get(value, \"constructor\");\n\treturn typeof constructor === \"function\" ? (Reflect.construct(constructor, arguments_) as object) : {};\n};\n\n/** 复制 ArrayBufferLike 的当前字节,不与源值共享底层内存。 */\nconst cloneArrayBuffer = (value: ArrayBufferLike): ArrayBufferLike => {\n\tconst result = createUsingConstructor(value, [value.byteLength]) as ArrayBufferLike;\n\tnew Uint8Array(result).set(new Uint8Array(value));\n\treturn result;\n};\n\n/** 递归复制值,并记录已复制对象以还原循环引用和共享引用。 */\nconst cloneDeepValue = (value: unknown, clones: WeakMap<object, object>, isRoot: boolean): unknown => {\n\tif ((typeof value !== \"object\" && typeof value !== \"function\") || value === null) return value;\n\n\tconst source = value;\n\tconst existing = clones.get(source);\n\tif (existing !== undefined) return existing;\n\tif (typeof source === \"function\" && !isRoot) return source;\n\n\tconst tag = Object.prototype.toString.call(source);\n\tlet result: object;\n\tlet pendingBuffer: { source: ArrayBufferLike; result: ArrayBufferLike } | undefined;\n\t// 先登记底层缓冲区,视图登记后再复制其附加属性,避免缓冲区与视图相互引用时重复构造。\n\tconst getBufferClone = (buffer: ArrayBufferLike): ArrayBufferLike => {\n\t\tconst existingBuffer = clones.get(buffer);\n\t\tif (existingBuffer !== undefined) return existingBuffer as ArrayBufferLike;\n\t\tconst clonedBuffer = cloneArrayBuffer(buffer);\n\t\tclones.set(buffer, clonedBuffer);\n\t\tpendingBuffer = { source: buffer, result: clonedBuffer };\n\t\treturn clonedBuffer;\n\t};\n\tif (Array.isArray(source)) {\n\t\t// 只复制实际存在的自有可枚举键,保留空洞、附加字符串属性和 Symbol 属性。\n\t\tresult = createUsingConstructor(source, [source.length]);\n\t} else if (typeof source === \"function\") {\n\t\tresult = {};\n\t} else {\n\t\tswitch (tag) {\n\t\t\tcase \"[object Arguments]\":\n\t\t\t\tresult = {};\n\t\t\t\tbreak;\n\t\t\tcase \"[object ArrayBuffer]\":\n\t\t\tcase \"[object SharedArrayBuffer]\":\n\t\t\t\tresult = cloneArrayBuffer(source as ArrayBufferLike);\n\t\t\t\tbreak;\n\t\t\tcase \"[object Boolean]\":\n\t\t\t\tresult = createUsingConstructor(source, [(source as { valueOf: () => boolean }).valueOf()]);\n\t\t\t\tbreak;\n\t\t\tcase \"[object DataView]\": {\n\t\t\t\tconst view = source as DataView;\n\t\t\t\tresult = createUsingConstructor(source, [getBufferClone(view.buffer), view.byteOffset, view.byteLength]);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"[object Date]\":\n\t\t\t\tresult = createUsingConstructor(source, [(source as Date).getTime()]);\n\t\t\t\tbreak;\n\t\t\tcase \"[object Map]\":\n\t\t\tcase \"[object Set]\":\n\t\t\t\tresult = createUsingConstructor(source, []);\n\t\t\t\tbreak;\n\t\t\tcase \"[object Number]\":\n\t\t\t\tresult = createUsingConstructor(source, [(source as { valueOf: () => number }).valueOf()]);\n\t\t\t\tbreak;\n\t\t\tcase \"[object Object]\": {\n\t\t\t\tconst prototype = Object.getPrototypeOf(source) as object | null;\n\t\t\t\tresult = Object.create(prototype) as object;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"[object RegExp]\": {\n\t\t\t\tconst expression = source as RegExp;\n\t\t\t\tconst clonedExpression = new RegExp(expression.source, expression.flags);\n\t\t\t\tclonedExpression.lastIndex = expression.lastIndex;\n\t\t\t\tresult = clonedExpression;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"[object String]\":\n\t\t\t\tresult = createUsingConstructor(source, [(source as { valueOf: () => string }).valueOf()]);\n\t\t\t\tbreak;\n\t\t\tcase \"[object Symbol]\":\n\t\t\t\tresult = Object((source as { valueOf: () => symbol }).valueOf()) as object;\n\t\t\t\tbreak;\n\t\t\tdefault: {\n\t\t\t\tif (!typedArrayTags.has(tag)) return isRoot ? {} : source;\n\t\t\t\tconst view = source as ArrayBufferView & { readonly length: number };\n\t\t\t\tresult = createUsingConstructor(source, [getBufferClone(view.buffer), view.byteOffset, view.length]);\n\t\t\t}\n\t\t}\n\t}\n\n\tclones.set(source, result);\n\tif (pendingBuffer !== undefined) {\n\t\tcopyCloneProperties(pendingBuffer.source, pendingBuffer.result, clones);\n\t}\n\tif (tag === \"[object Map]\") {\n\t\tfor (const [key, item] of source as Map<unknown, unknown>) {\n\t\t\t(result as Map<unknown, unknown>).set(key, cloneDeepValue(item, clones, false));\n\t\t}\n\t} else if (tag === \"[object Set]\") {\n\t\tfor (const item of source as Set<unknown>) {\n\t\t\t(result as Set<unknown>).add(cloneDeepValue(item, clones, false));\n\t\t}\n\t}\n\n\tcopyCloneProperties(source, result, clones);\n\treturn result;\n};\n\n/** 复制自有可枚举属性,不触发结果原型上的 setter。 */\nfunction copyCloneProperties(source: object, result: object, clones: WeakMap<object, object>): void {\n\tfor (const key of Reflect.ownKeys(source)) {\n\t\tif (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(result, key);\n\t\t// String 包装对象的字符索引由构造器建立,不能重新定义。\n\t\tif (descriptor?.configurable === false && descriptor.writable === false) continue;\n\t\tdefineEnumerableProperty(result, key, cloneDeepValue(Reflect.get(source, key), clones, false));\n\t}\n}\n\n/** 深度比较过程中用于识别循环引用的双向对象映射。 */\ninterface EqualityState {\n\treadonly leftObjects: WeakMap<object, object>;\n\treadonly rightObjects: WeakMap<object, object>;\n}\n\n/** 判断两个值是否满足 SameValueZero 相等。 */\nconst sameValueZero = (left: unknown, right: unknown): boolean =>\n\tleft === right || (typeof left === \"number\" && typeof right === \"number\" && Number.isNaN(left) && Number.isNaN(right));\n\n/** 返回对象的自有可枚举字符串与 Symbol 键。 */\nconst getEnumerableOwnKeys = (value: object): PropertyKey[] =>\n\tReflect.ownKeys(value).filter((key) => Object.prototype.propertyIsEnumerable.call(value, key));\n\n/** 在一次递归分支内记录对象对应关系。 */\nconst compareTrackedPair = (left: object, right: object, state: EqualityState, compare: () => boolean): boolean => {\n\tconst existingRight = state.leftObjects.get(left);\n\tconst existingLeft = state.rightObjects.get(right);\n\tif (existingRight !== undefined || existingLeft !== undefined) return existingRight === right && existingLeft === left;\n\tstate.leftObjects.set(left, right);\n\tstate.rightObjects.set(right, left);\n\ttry {\n\t\treturn compare();\n\t} finally {\n\t\tstate.leftObjects.delete(left);\n\t\tstate.rightObjects.delete(right);\n\t}\n};\n\n/** 按字节比较两个 ArrayBufferLike。 */\nconst equalArrayBuffers = (left: ArrayBufferLike, right: ArrayBufferLike): boolean => {\n\tif (left.byteLength !== right.byteLength) return false;\n\tconst leftBytes = new Uint8Array(left);\n\tconst rightBytes = new Uint8Array(right);\n\tfor (let index = 0; index < leftBytes.length; index += 1) {\n\t\tif (leftBytes[index] !== rightBytes[index]) return false;\n\t}\n\treturn true;\n};\n\n/** 按顺序比较数组或 TypedArray 的元素。 */\nconst equalIndexedValues = (\n\tleft: { readonly [index: number]: unknown; readonly length: number },\n\tright: { readonly [index: number]: unknown; readonly length: number },\n\tstate: EqualityState\n): boolean => {\n\tif (left.length !== right.length) return false;\n\treturn compareTrackedPair(left, right, state, () => {\n\t\tfor (let index = 0; index < left.length; index += 1) {\n\t\t\tif (!isEqualValue(left[index], right[index], state)) return false;\n\t\t}\n\t\treturn true;\n\t});\n};\n\n/** 无序比较 Map 条目或 Set 元素。 */\nconst equalUnorderedValues = (left: readonly unknown[], right: readonly unknown[], state: EqualityState): boolean => {\n\tif (left.length !== right.length) return false;\n\tconst matchedIndexes = new Set<number>();\n\tfor (const leftValue of left) {\n\t\tlet matchedIndex = -1;\n\t\tfor (let index = 0; index < right.length; index += 1) {\n\t\t\tif (matchedIndexes.has(index) || !isEqualValue(leftValue, right[index], state)) continue;\n\t\t\tmatchedIndex = index;\n\t\t\tbreak;\n\t\t}\n\t\tif (matchedIndex < 0) return false;\n\t\tmatchedIndexes.add(matchedIndex);\n\t}\n\treturn true;\n};\n\n/** 比较普通对象或 Arguments 的自有可枚举属性与构造器。 */\nconst equalObjects = (left: object, right: object, state: EqualityState): boolean => {\n\tconst leftKeys = getEnumerableOwnKeys(left);\n\tconst rightKeys = getEnumerableOwnKeys(right);\n\tif (leftKeys.length !== rightKeys.length) return false;\n\tfor (const key of leftKeys) {\n\t\tif (!Object.hasOwn(right, key)) return false;\n\t}\n\n\treturn compareTrackedPair(left, right, state, () => {\n\t\tlet compareConstructors = true;\n\t\tfor (const key of leftKeys) {\n\t\t\tif (!isEqualValue(Reflect.get(left, key), Reflect.get(right, key), state)) return false;\n\t\t\tif (key === \"constructor\") compareConstructors = false;\n\t\t}\n\t\tif (!compareConstructors) return true;\n\t\tconst leftConstructor: unknown = Reflect.get(left, \"constructor\");\n\t\tconst rightConstructor: unknown = Reflect.get(right, \"constructor\");\n\t\tif (leftConstructor === rightConstructor || !(\"constructor\" in left && \"constructor\" in right)) return true;\n\t\treturn (\n\t\t\ttypeof leftConstructor === \"function\" &&\n\t\t\ttypeof rightConstructor === \"function\" &&\n\t\t\tleftConstructor instanceof leftConstructor &&\n\t\t\trightConstructor instanceof rightConstructor\n\t\t);\n\t});\n};\n\n/** 递归比较两个值。 */\nfunction isEqualValue(left: unknown, right: unknown, state: EqualityState): boolean {\n\tif (sameValueZero(left, right)) return true;\n\tif (left === null || left === undefined || right === null || right === undefined) return false;\n\n\tconst leftTag = Object.prototype.toString.call(left);\n\tconst rightTag = Object.prototype.toString.call(right);\n\tconst normalizedLeftTag = leftTag === \"[object Arguments]\" ? \"[object Object]\" : leftTag;\n\tconst normalizedRightTag = rightTag === \"[object Arguments]\" ? \"[object Object]\" : rightTag;\n\tif (normalizedLeftTag !== normalizedRightTag) return false;\n\n\tswitch (normalizedLeftTag) {\n\t\tcase \"[object Boolean]\":\n\t\tcase \"[object Date]\":\n\t\tcase \"[object Number]\":\n\t\t\treturn sameValueZero(Number(left), Number(right));\n\t\tcase \"[object Error]\":\n\t\t\treturn (left as Error).name === (right as Error).name && (left as Error).message === (right as Error).message;\n\t\tcase \"[object RegExp]\":\n\t\t\treturn RegExp.prototype.toString.call(left) === RegExp.prototype.toString.call(right);\n\t\tcase \"[object String]\":\n\t\t\treturn String.prototype.valueOf.call(left) === String.prototype.valueOf.call(right);\n\t\tcase \"[object Symbol]\":\n\t\t\treturn Symbol.prototype.valueOf.call(left) === Symbol.prototype.valueOf.call(right);\n\t}\n\n\tif (typeof left !== \"object\" || typeof right !== \"object\") return false;\n\tif (Array.isArray(left) && Array.isArray(right)) return equalIndexedValues(left, right, state);\n\tif (normalizedLeftTag === \"[object ArrayBuffer]\" || normalizedLeftTag === \"[object SharedArrayBuffer]\") {\n\t\treturn equalArrayBuffers(left as ArrayBufferLike, right as ArrayBufferLike);\n\t}\n\tif (normalizedLeftTag === \"[object DataView]\") {\n\t\tconst leftView = left as DataView;\n\t\tconst rightView = right as DataView;\n\t\treturn (\n\t\t\tleftView.byteLength === rightView.byteLength &&\n\t\t\tleftView.byteOffset === rightView.byteOffset &&\n\t\t\tequalArrayBuffers(leftView.buffer, rightView.buffer)\n\t\t);\n\t}\n\tif (typedArrayTags.has(normalizedLeftTag)) {\n\t\treturn equalIndexedValues(\n\t\t\tleft as ArrayBufferView & { readonly [index: number]: unknown; readonly length: number },\n\t\t\tright as ArrayBufferView & { readonly [index: number]: unknown; readonly length: number },\n\t\t\tstate\n\t\t);\n\t}\n\tif (normalizedLeftTag === \"[object Map]\") {\n\t\treturn compareTrackedPair(left, right, state, () =>\n\t\t\tequalUnorderedValues([...(left as Map<unknown, unknown>)], [...(right as Map<unknown, unknown>)], state)\n\t\t);\n\t}\n\tif (normalizedLeftTag === \"[object Set]\") {\n\t\treturn compareTrackedPair(left, right, state, () => equalUnorderedValues([...(left as Set<unknown>)], [...(right as Set<unknown>)], state));\n\t}\n\tif (normalizedLeftTag === \"[object Object]\") return equalObjects(left, right, state);\n\treturn false;\n}\n\n/**\n * 判断值是否是普通对象。\n *\n * @param value - 任意待检查值。\n * @returns 原型为 `Object.prototype` 或 `null` 时返回 `true`。\n */\nexport function isPlainObject(value: unknown): value is Record<PropertyKey, unknown> {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst prototype = Object.getPrototypeOf(value) as object | null;\n\treturn prototype === null || prototype === Object.prototype;\n}\n\n/**\n * 安全判断对象是否拥有自己的属性。\n *\n * @remarks 不调用可能被对象覆盖的 `hasOwnProperty`。\n * @param value - 待检查对象。\n * @param key - 字符串、数字或 Symbol 属性键。\n * @returns 属性为对象自有属性时返回 `true`,并收窄键类型。\n */\nexport function hasOwn<ObjectType extends object, Key extends PropertyKey>(value: ObjectType, key: Key): key is Key & keyof ObjectType {\n\treturn Object.hasOwn(value, key);\n}\n\n/**\n * 递归创建值的深层副本。\n *\n * @remarks 支持循环引用、共享引用、Symbol 键、对象原型、ArrayBuffer、DataView、Date、Map、RegExp、Set 和 TypedArray。\n * Map 的键保持原引用,函数及其他不可克隆值在嵌套位置保持原引用;只复制自有可枚举属性。\n * @param value - 需要深复制的任意值。\n * @returns 与输入类型一致且不共享可克隆嵌套值的新值;原始类型直接返回自身。\n */\nexport function cloneDeep<Value>(value: Value): Value {\n\treturn cloneDeepValue(value, new WeakMap(), true) as Value;\n}\n\n/**\n * 深度比较两个值是否等价。\n *\n * @remarks 原始值使用 SameValueZero 语义;支持循环引用、数组、对象、ArrayBuffer、DataView、Date、Error、Map、RegExp、Set、Symbol 和 TypedArray。\n * 对象只比较自有可枚举字符串与 Symbol 属性,函数及其他不支持的宿主对象仅在引用相同时相等。\n * @param left - 第一待比较值。\n * @param right - 第二待比较值。\n * @returns 两个值深度等价时返回 `true`。\n */\nexport function isEqual(left: unknown, right: unknown): boolean {\n\treturn isEqualValue(left, right, { leftObjects: new WeakMap(), rightObjects: new WeakMap() });\n}\n\n/**\n * 从对象中选择指定自有可枚举属性。\n *\n * @remarks 固定键元组保留精确返回类型;动态数组中可能被选择或排除的键在返回类型中保持可选。\n * @param source - 不会被修改的源对象。\n * @param keys - 需要保留的键;不存在的键被忽略。\n * @returns 新对象,保持 `keys` 的遍历顺序。\n */\nexport function pick<Source extends object, const Keys extends readonly (keyof Source)[]>(\n\tsource: Source,\n\tkeys: Keys\n): number extends Keys[\"length\"] ? Partial<Pick<Source, Keys[number]>> : Pick<Source, Keys[number]>;\nexport function pick<Source extends object>(source: Source, keys: readonly PropertyKey[]): Partial<Source>;\nexport function pick<Source extends object>(source: Source, keys: readonly PropertyKey[]): Partial<Source> {\n\tconst result: Partial<Source> = {};\n\tfor (const key of keys) {\n\t\tif (Object.prototype.propertyIsEnumerable.call(source, key)) defineEnumerableProperty(result, key, Reflect.get(source, key));\n\t}\n\treturn result;\n}\n\n/**\n * 浅复制对象并删除指定属性。\n *\n * @remarks 固定键元组保留精确返回类型;动态数组中可能被选择或排除的键在返回类型中保持可选。\n * @param source - 不会被修改的源对象。\n * @param keys - 需要排除的键。\n * @returns 包含其余自有可枚举字符串与 Symbol 属性的新对象。\n */\nexport function omit<Source extends object, const Keys extends readonly (keyof Source)[]>(\n\tsource: Source,\n\tkeys: Keys\n): number extends Keys[\"length\"] ? Omit<Source, Keys[number]> & Partial<Pick<Source, Keys[number]>> : Omit<Source, Keys[number]>;\nexport function omit<Source extends object>(source: Source, keys: readonly PropertyKey[]): Partial<Source>;\nexport function omit<Source extends object>(source: Source, keys: readonly PropertyKey[]): Partial<Source> {\n\tconst result = { ...source };\n\tfor (const key of keys) Reflect.deleteProperty(result, key);\n\treturn result;\n}\n\n/**\n * 按条件排除对象的自有可枚举属性。\n *\n * @param source - 不会被修改的源对象。\n * @param predicate - 接收属性值、键和源对象;返回真值时排除该属性。\n * @returns 由未匹配属性组成的新对象。\n */\nexport function omitBy<Source extends object>(\n\tsource: Source,\n\tpredicate: (value: Source[keyof Source], key: keyof Source, source: Source) => unknown\n): Partial<Source> {\n\tconst result: Partial<Source> = {};\n\tfor (const key of getEnumerableOwnKeys(source) as (keyof Source)[]) {\n\t\tif (!predicate(source[key], key, source)) defineEnumerableProperty(result, key, source[key]);\n\t}\n\treturn result;\n}\n\n/**\n * 按条件选择对象的自有可枚举属性。\n *\n * @param source - 不会被修改的源对象。\n * @param predicate - 接收属性值、键和源对象;返回真值时保留该属性。\n * @returns 由匹配属性组成的新对象。\n */\nexport function pickBy<Source extends object>(\n\tsource: Source,\n\tpredicate: (value: Source[keyof Source], key: keyof Source, source: Source) => unknown\n): Partial<Source> {\n\tconst result: Partial<Source> = {};\n\tfor (const key of getEnumerableOwnKeys(source) as (keyof Source)[]) {\n\t\tif (predicate(source[key], key, source)) defineEnumerableProperty(result, key, source[key]);\n\t}\n\treturn result;\n}\n\n/**\n * 映射对象的自有可枚举属性值。\n *\n * @param source - 不会被修改的源对象。\n * @param mapper - 接收值、键和源对象的映射函数。\n * @returns 保留原键的新对象。\n */\nexport function mapValues<Source extends object, Result>(\n\tsource: Source,\n\tmapper: (value: Source[keyof Source], key: keyof Source, source: Source) => Result\n): { [Key in keyof Source]: Result } {\n\tconst result = {} as { [Key in keyof Source]: Result };\n\tfor (const key of Reflect.ownKeys(source) as (keyof Source)[]) {\n\t\tif (Object.prototype.propertyIsEnumerable.call(source, key)) defineEnumerableProperty(result, key, mapper(source[key], key, source));\n\t}\n\treturn result;\n}\n\n/**\n * 对自有可枚举属性执行 SameValue 浅比较。\n *\n * @remarks 嵌套对象只比较引用;`NaN` 相等,`0` 与 `-0` 不相等。\n * @param left - 第一对象。\n * @param right - 第二对象。\n * @returns 自有可枚举键集合与对应值均满足 SameValue 时返回 `true`。\n */\nexport function shallowEqual(left: object, right: object): boolean {\n\tif (Object.is(left, right)) return true;\n\tconst leftKeys = Reflect.ownKeys(left).filter((key) => Object.prototype.propertyIsEnumerable.call(left, key));\n\tconst rightKeys = Reflect.ownKeys(right).filter((key) => Object.prototype.propertyIsEnumerable.call(right, key));\n\tif (leftKeys.length !== rightKeys.length) return false;\n\treturn leftKeys.every((key) => Object.hasOwn(right, key) && Object.is(Reflect.get(left, key), Reflect.get(right, key)));\n}\n\n/**\n * 把 Query 原始值规范化为文本。\n *\n * @param value - 已排除空值的字符串、数字、布尔值或 BigInt。\n * @returns 与 URLSearchParams 兼容的文本值。\n * @throws `RangeError` 当数字不是有限值。\n */\nconst serializeQueryValue = (value: Exclude<QueryPrimitive, null | undefined>): string => {\n\tif (typeof value === \"number\" && !Number.isFinite(value)) {\n\t\tthrow new RangeError(\"查询参数中的数字必须是有限数。\");\n\t}\n\treturn String(value);\n};\n\n/**\n * 将对象序列化为标准 URL 查询字符串。\n *\n * @remarks `null` 与 `undefined` 被跳过;数组使用重复键;返回值不会修改输入。\n * @param value - 查询参数对象。\n * @param options - 排序、空格和问号前缀选项。\n * @returns URL 编码后的查询字符串;没有参数时始终返回空字符串。\n * @throws `RangeError` 当参数包含 `NaN` 或无穷数字。\n */\nexport function toQueryString(value: Readonly<Record<string, QueryValue>>, options: QueryStringOptions = {}): string {\n\tconst entries = Object.entries(value);\n\tif (options.sort) entries.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0));\n\tconst parameters = new URLSearchParams();\n\tfor (const [key, rawValue] of entries) {\n\t\tconst values = isQueryPrimitiveArray(rawValue) ? rawValue : [rawValue];\n\t\tfor (const item of values) {\n\t\t\tif (item !== null && item !== undefined) parameters.append(key, serializeQueryValue(item));\n\t\t}\n\t}\n\tlet result = parameters.toString();\n\tif (options.space === \"percent\") result = result.replace(/\\+/gu, \"%20\");\n\treturn result && options.prefixQuestionMark ? `?${result}` : result;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/object/index.ts"],"sourcesContent":["/** URL 查询参数支持的单值类型。 */\nexport type QueryPrimitive = bigint | boolean | number | string | null | undefined;\n\n/** URL 查询参数值;数组使用重复键表示。 */\nexport type QueryValue = QueryPrimitive | readonly QueryPrimitive[];\n\n/**\n * 判断 Query Value 是否为重复参数数组。\n *\n * @param value - 单值或数组形式的 Query Value\n * @returns 是只读原始值数组时返回 `true`。\n */\nconst isQueryPrimitiveArray = (value: QueryValue): value is readonly QueryPrimitive[] => Array.isArray(value);\n\n/** {@link toQueryString} 的序列化选项 */\nexport interface QueryStringOptions {\n\t/** 返回非空结果时是否添加 `?`;默认 `false`。 */\n\tprefixQuestionMark?: boolean;\n\t/** 是否按键的 UTF-16 码元顺序稳定排序;默认保留对象枚举顺序。 */\n\tsort?: boolean;\n\t/** 空格编码方式;默认遵循表单编码并输出 `+`。 */\n\tspace?: \"percent\" | \"plus\";\n}\n\n/**\n * 安全写入结果对象的自有可枚举属性。\n *\n * @remarks 使用 `defineProperty` 避免 `__proto__` 触发 Setter,并统一创建可写、可配置的自有可枚举数据属性。\n * @param target - 要写入的结果对象\n * @param key - 自有属性键\n * @param value - 属性值\n */\nconst defineEnumerableProperty = (target: object, key: PropertyKey, value: unknown): void => {\n\tObject.defineProperty(target, key, { configurable: true, enumerable: true, value, writable: true });\n};\n\nconst typedArrayTags = new Set([\n\t\"[object BigInt64Array]\",\n\t\"[object BigUint64Array]\",\n\t\"[object Float32Array]\",\n\t\"[object Float64Array]\",\n\t\"[object Int8Array]\",\n\t\"[object Int16Array]\",\n\t\"[object Int32Array]\",\n\t\"[object Uint8Array]\",\n\t\"[object Uint8ClampedArray]\",\n\t\"[object Uint16Array]\",\n\t\"[object Uint32Array]\",\n]);\n\n/** 使用源值的构造器创建同类空实例。 */\nconst createUsingConstructor = (value: object, arguments_: readonly unknown[]): object => {\n\tconst constructor: unknown = Reflect.get(value, \"constructor\");\n\treturn typeof constructor === \"function\" ? (Reflect.construct(constructor, arguments_) as object) : {};\n};\n\n/** 复制 ArrayBufferLike 的当前字节,不与源值共享底层内存。 */\nconst cloneArrayBuffer = (value: ArrayBufferLike): ArrayBufferLike => {\n\tconst result = createUsingConstructor(value, [value.byteLength]) as ArrayBufferLike;\n\tnew Uint8Array(result).set(new Uint8Array(value));\n\treturn result;\n};\n\n/** 递归复制值,并记录已复制对象以还原循环引用和共享引用。 */\nconst cloneDeepValue = (value: unknown, clones: WeakMap<object, object>, isRoot: boolean): unknown => {\n\tif ((typeof value !== \"object\" && typeof value !== \"function\") || value === null) return value;\n\n\tconst source = value;\n\tconst existing = clones.get(source);\n\tif (existing !== undefined) return existing;\n\tif (typeof source === \"function\" && !isRoot) return source;\n\n\tconst tag = Object.prototype.toString.call(source);\n\tlet result: object;\n\tlet pendingBuffer: { source: ArrayBufferLike; result: ArrayBufferLike } | undefined;\n\t// 先登记底层缓冲区,视图登记后再复制其附加属性,避免缓冲区与视图相互引用时重复构造。\n\tconst getBufferClone = (buffer: ArrayBufferLike): ArrayBufferLike => {\n\t\tconst existingBuffer = clones.get(buffer);\n\t\tif (existingBuffer !== undefined) return existingBuffer as ArrayBufferLike;\n\t\tconst clonedBuffer = cloneArrayBuffer(buffer);\n\t\tclones.set(buffer, clonedBuffer);\n\t\tpendingBuffer = { source: buffer, result: clonedBuffer };\n\t\treturn clonedBuffer;\n\t};\n\tif (Array.isArray(source)) {\n\t\t// 只复制实际存在的自有可枚举键,保留空洞、附加字符串属性和 Symbol 属性。\n\t\tresult = createUsingConstructor(source, [source.length]);\n\t} else if (typeof source === \"function\") {\n\t\tresult = {};\n\t} else {\n\t\tswitch (tag) {\n\t\t\tcase \"[object Arguments]\":\n\t\t\t\tresult = {};\n\t\t\t\tbreak;\n\t\t\tcase \"[object ArrayBuffer]\":\n\t\t\tcase \"[object SharedArrayBuffer]\":\n\t\t\t\tresult = cloneArrayBuffer(source as ArrayBufferLike);\n\t\t\t\tbreak;\n\t\t\tcase \"[object Boolean]\":\n\t\t\t\tresult = createUsingConstructor(source, [(source as { valueOf: () => boolean }).valueOf()]);\n\t\t\t\tbreak;\n\t\t\tcase \"[object DataView]\": {\n\t\t\t\tconst view = source as DataView;\n\t\t\t\tresult = createUsingConstructor(source, [getBufferClone(view.buffer), view.byteOffset, view.byteLength]);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"[object Date]\":\n\t\t\t\tresult = createUsingConstructor(source, [(source as Date).getTime()]);\n\t\t\t\tbreak;\n\t\t\tcase \"[object Map]\":\n\t\t\tcase \"[object Set]\":\n\t\t\t\tresult = createUsingConstructor(source, []);\n\t\t\t\tbreak;\n\t\t\tcase \"[object Number]\":\n\t\t\t\tresult = createUsingConstructor(source, [(source as { valueOf: () => number }).valueOf()]);\n\t\t\t\tbreak;\n\t\t\tcase \"[object Object]\": {\n\t\t\t\tconst prototype = Object.getPrototypeOf(source) as object | null;\n\t\t\t\tresult = Object.create(prototype) as object;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"[object RegExp]\": {\n\t\t\t\tconst expression = source as RegExp;\n\t\t\t\tconst clonedExpression = new RegExp(expression.source, expression.flags);\n\t\t\t\tclonedExpression.lastIndex = expression.lastIndex;\n\t\t\t\tresult = clonedExpression;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"[object String]\":\n\t\t\t\tresult = createUsingConstructor(source, [(source as { valueOf: () => string }).valueOf()]);\n\t\t\t\tbreak;\n\t\t\tcase \"[object Symbol]\":\n\t\t\t\tresult = Object((source as { valueOf: () => symbol }).valueOf()) as object;\n\t\t\t\tbreak;\n\t\t\tdefault: {\n\t\t\t\tif (!typedArrayTags.has(tag)) return isRoot ? {} : source;\n\t\t\t\tconst view = source as ArrayBufferView & { readonly length: number };\n\t\t\t\tresult = createUsingConstructor(source, [getBufferClone(view.buffer), view.byteOffset, view.length]);\n\t\t\t}\n\t\t}\n\t}\n\n\tclones.set(source, result);\n\tif (pendingBuffer !== undefined) {\n\t\tcopyCloneProperties(pendingBuffer.source, pendingBuffer.result, clones);\n\t}\n\tif (tag === \"[object Map]\") {\n\t\tfor (const [key, item] of source as Map<unknown, unknown>) {\n\t\t\t(result as Map<unknown, unknown>).set(key, cloneDeepValue(item, clones, false));\n\t\t}\n\t} else if (tag === \"[object Set]\") {\n\t\tfor (const item of source as Set<unknown>) {\n\t\t\t(result as Set<unknown>).add(cloneDeepValue(item, clones, false));\n\t\t}\n\t}\n\n\tcopyCloneProperties(source, result, clones);\n\treturn result;\n};\n\n/** 复制自有可枚举属性,不触发结果原型上的 setter。 */\nfunction copyCloneProperties(source: object, result: object, clones: WeakMap<object, object>): void {\n\tfor (const key of Reflect.ownKeys(source)) {\n\t\tif (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;\n\t\tconst descriptor = Object.getOwnPropertyDescriptor(result, key);\n\t\t// String 包装对象的字符索引由构造器建立,不能重新定义。\n\t\tif (descriptor?.configurable === false && descriptor.writable === false) continue;\n\t\tdefineEnumerableProperty(result, key, cloneDeepValue(Reflect.get(source, key), clones, false));\n\t}\n}\n\n/** 深度比较过程中用于识别循环引用的双向对象映射 */\ninterface EqualityState {\n\treadonly leftObjects: WeakMap<object, object>;\n\treadonly rightObjects: WeakMap<object, object>;\n}\n\n/** 判断两个值是否满足 SameValueZero 相等。 */\nconst sameValueZero = (left: unknown, right: unknown): boolean =>\n\tleft === right || (typeof left === \"number\" && typeof right === \"number\" && Number.isNaN(left) && Number.isNaN(right));\n\n/** 返回对象的自有可枚举字符串与 Symbol 键。 */\nconst getEnumerableOwnKeys = (value: object): PropertyKey[] =>\n\tReflect.ownKeys(value).filter((key) => Object.prototype.propertyIsEnumerable.call(value, key));\n\n/** 在一次递归分支内记录对象对应关系。 */\nconst compareTrackedPair = (left: object, right: object, state: EqualityState, compare: () => boolean): boolean => {\n\tconst existingRight = state.leftObjects.get(left);\n\tconst existingLeft = state.rightObjects.get(right);\n\tif (existingRight !== undefined || existingLeft !== undefined) return existingRight === right && existingLeft === left;\n\tstate.leftObjects.set(left, right);\n\tstate.rightObjects.set(right, left);\n\ttry {\n\t\treturn compare();\n\t} finally {\n\t\tstate.leftObjects.delete(left);\n\t\tstate.rightObjects.delete(right);\n\t}\n};\n\n/** 按字节比较两个 ArrayBufferLike。 */\nconst equalArrayBuffers = (left: ArrayBufferLike, right: ArrayBufferLike): boolean => {\n\tif (left.byteLength !== right.byteLength) return false;\n\tconst leftBytes = new Uint8Array(left);\n\tconst rightBytes = new Uint8Array(right);\n\tfor (let index = 0; index < leftBytes.length; index += 1) {\n\t\tif (leftBytes[index] !== rightBytes[index]) return false;\n\t}\n\treturn true;\n};\n\n/** 按顺序比较数组或 TypedArray 的元素。 */\nconst equalIndexedValues = (\n\tleft: { readonly [index: number]: unknown; readonly length: number },\n\tright: { readonly [index: number]: unknown; readonly length: number },\n\tstate: EqualityState\n): boolean => {\n\tif (left.length !== right.length) return false;\n\treturn compareTrackedPair(left, right, state, () => {\n\t\tfor (let index = 0; index < left.length; index += 1) {\n\t\t\tif (!isEqualValue(left[index], right[index], state)) return false;\n\t\t}\n\t\treturn true;\n\t});\n};\n\n/** 无序比较 Map 条目或 Set 元素。 */\nconst equalUnorderedValues = (left: readonly unknown[], right: readonly unknown[], state: EqualityState): boolean => {\n\tif (left.length !== right.length) return false;\n\tconst matchedIndexes = new Set<number>();\n\tfor (const leftValue of left) {\n\t\tlet matchedIndex = -1;\n\t\tfor (let index = 0; index < right.length; index += 1) {\n\t\t\tif (matchedIndexes.has(index) || !isEqualValue(leftValue, right[index], state)) continue;\n\t\t\tmatchedIndex = index;\n\t\t\tbreak;\n\t\t}\n\t\tif (matchedIndex < 0) return false;\n\t\tmatchedIndexes.add(matchedIndex);\n\t}\n\treturn true;\n};\n\n/** 比较普通对象或 Arguments 的自有可枚举属性与构造器。 */\nconst equalObjects = (left: object, right: object, state: EqualityState): boolean => {\n\tconst leftKeys = getEnumerableOwnKeys(left);\n\tconst rightKeys = getEnumerableOwnKeys(right);\n\tif (leftKeys.length !== rightKeys.length) return false;\n\tfor (const key of leftKeys) {\n\t\tif (!Object.prototype.hasOwnProperty.call(right, key)) return false;\n\t}\n\n\treturn compareTrackedPair(left, right, state, () => {\n\t\tlet compareConstructors = true;\n\t\tfor (const key of leftKeys) {\n\t\t\tif (!isEqualValue(Reflect.get(left, key), Reflect.get(right, key), state)) return false;\n\t\t\tif (key === \"constructor\") compareConstructors = false;\n\t\t}\n\t\tif (!compareConstructors) return true;\n\t\tconst leftConstructor: unknown = Reflect.get(left, \"constructor\");\n\t\tconst rightConstructor: unknown = Reflect.get(right, \"constructor\");\n\t\tif (leftConstructor === rightConstructor || !(\"constructor\" in left && \"constructor\" in right)) return true;\n\t\treturn (\n\t\t\ttypeof leftConstructor === \"function\" &&\n\t\t\ttypeof rightConstructor === \"function\" &&\n\t\t\tleftConstructor instanceof leftConstructor &&\n\t\t\trightConstructor instanceof rightConstructor\n\t\t);\n\t});\n};\n\n/** 递归比较两个值。 */\nfunction isEqualValue(left: unknown, right: unknown, state: EqualityState): boolean {\n\tif (sameValueZero(left, right)) return true;\n\tif (left === null || left === undefined || right === null || right === undefined) return false;\n\n\tconst leftTag = Object.prototype.toString.call(left);\n\tconst rightTag = Object.prototype.toString.call(right);\n\tconst normalizedLeftTag = leftTag === \"[object Arguments]\" ? \"[object Object]\" : leftTag;\n\tconst normalizedRightTag = rightTag === \"[object Arguments]\" ? \"[object Object]\" : rightTag;\n\tif (normalizedLeftTag !== normalizedRightTag) return false;\n\n\tswitch (normalizedLeftTag) {\n\t\tcase \"[object Boolean]\":\n\t\tcase \"[object Date]\":\n\t\tcase \"[object Number]\":\n\t\t\treturn sameValueZero(Number(left), Number(right));\n\t\tcase \"[object Error]\":\n\t\t\treturn (left as Error).name === (right as Error).name && (left as Error).message === (right as Error).message;\n\t\tcase \"[object RegExp]\":\n\t\t\treturn RegExp.prototype.toString.call(left) === RegExp.prototype.toString.call(right);\n\t\tcase \"[object String]\":\n\t\t\treturn String.prototype.valueOf.call(left) === String.prototype.valueOf.call(right);\n\t\tcase \"[object Symbol]\":\n\t\t\treturn Symbol.prototype.valueOf.call(left) === Symbol.prototype.valueOf.call(right);\n\t}\n\n\tif (typeof left !== \"object\" || typeof right !== \"object\") return false;\n\tif (Array.isArray(left) && Array.isArray(right)) return equalIndexedValues(left, right, state);\n\tif (normalizedLeftTag === \"[object ArrayBuffer]\" || normalizedLeftTag === \"[object SharedArrayBuffer]\") {\n\t\treturn equalArrayBuffers(left as ArrayBufferLike, right as ArrayBufferLike);\n\t}\n\tif (normalizedLeftTag === \"[object DataView]\") {\n\t\tconst leftView = left as DataView;\n\t\tconst rightView = right as DataView;\n\t\treturn (\n\t\t\tleftView.byteLength === rightView.byteLength &&\n\t\t\tleftView.byteOffset === rightView.byteOffset &&\n\t\t\tequalArrayBuffers(leftView.buffer, rightView.buffer)\n\t\t);\n\t}\n\tif (typedArrayTags.has(normalizedLeftTag)) {\n\t\treturn equalIndexedValues(\n\t\t\tleft as ArrayBufferView & { readonly [index: number]: unknown; readonly length: number },\n\t\t\tright as ArrayBufferView & { readonly [index: number]: unknown; readonly length: number },\n\t\t\tstate\n\t\t);\n\t}\n\tif (normalizedLeftTag === \"[object Map]\") {\n\t\treturn compareTrackedPair(left, right, state, () =>\n\t\t\tequalUnorderedValues([...(left as Map<unknown, unknown>)], [...(right as Map<unknown, unknown>)], state)\n\t\t);\n\t}\n\tif (normalizedLeftTag === \"[object Set]\") {\n\t\treturn compareTrackedPair(left, right, state, () => equalUnorderedValues([...(left as Set<unknown>)], [...(right as Set<unknown>)], state));\n\t}\n\tif (normalizedLeftTag === \"[object Object]\") return equalObjects(left, right, state);\n\treturn false;\n}\n\n/**\n * 判断值是否是普通对象。\n *\n * @param value - 任意待检查值\n * @returns 原型为 `Object.prototype` 或 `null` 时返回 `true`。\n */\nexport function isPlainObject(value: unknown): value is Record<PropertyKey, unknown> {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst prototype = Object.getPrototypeOf(value) as object | null;\n\treturn prototype === null || prototype === Object.prototype;\n}\n\n/**\n * 安全判断对象是否拥有自己的属性。\n *\n * @remarks 不调用可能被对象覆盖的 `hasOwnProperty`。\n * @param value - 待检查对象\n * @param key - 字符串、数字或 Symbol 属性键\n * @returns 属性为对象自有属性时返回 `true`,并收窄键类型。\n */\nexport function hasOwn<ObjectType extends object, Key extends PropertyKey>(value: ObjectType, key: Key): key is Key & keyof ObjectType {\n\treturn Object.prototype.hasOwnProperty.call(value, key);\n}\n\n/**\n * 递归创建值的深层副本。\n *\n * @remarks 支持循环引用、共享引用、Symbol 键、对象原型、ArrayBuffer、DataView、Date、Map、RegExp、Set 和 TypedArray。\n * Map 的键保持原引用,函数及其他不可克隆值在嵌套位置保持原引用;只复制自有可枚举属性。\n * @param value - 需要深复制的任意值\n * @returns 与输入类型一致且不共享可克隆嵌套值的新值;原始类型直接返回自身。\n */\nexport function cloneDeep<Value>(value: Value): Value {\n\treturn cloneDeepValue(value, new WeakMap(), true) as Value;\n}\n\n/**\n * 深度比较两个值是否等价。\n *\n * @remarks 原始值使用 SameValueZero 语义;支持循环引用、数组、对象、ArrayBuffer、DataView、Date、Error、Map、RegExp、Set、Symbol 和 TypedArray。\n * 对象只比较自有可枚举字符串与 Symbol 属性,函数及其他不支持的宿主对象仅在引用相同时相等。\n * @param left - 第一待比较值\n * @param right - 第二待比较值\n * @returns 两个值深度等价时返回 `true`。\n */\nexport function isEqual(left: unknown, right: unknown): boolean {\n\treturn isEqualValue(left, right, { leftObjects: new WeakMap(), rightObjects: new WeakMap() });\n}\n\n/**\n * 从对象中选择指定自有可枚举属性。\n *\n * @remarks 固定键元组保留精确返回类型;动态数组中可能被选择或排除的键在返回类型中保持可选。\n * @param source - 不会被修改的源对象\n * @param keys - 需要保留的键;不存在的键被忽略。\n * @returns 新对象,保持 `keys` 的遍历顺序。\n */\nexport function pick<Source extends object, const Keys extends readonly (keyof Source)[]>(\n\tsource: Source,\n\tkeys: Keys\n): number extends Keys[\"length\"] ? Partial<Pick<Source, Keys[number]>> : Pick<Source, Keys[number]>;\nexport function pick<Source extends object>(source: Source, keys: readonly PropertyKey[]): Partial<Source>;\nexport function pick<Source extends object>(source: Source, keys: readonly PropertyKey[]): Partial<Source> {\n\tconst result: Partial<Source> = {};\n\tfor (const key of keys) {\n\t\tif (Object.prototype.propertyIsEnumerable.call(source, key)) defineEnumerableProperty(result, key, Reflect.get(source, key));\n\t}\n\treturn result;\n}\n\n/**\n * 浅复制对象并删除指定属性。\n *\n * @remarks 固定键元组保留精确返回类型;动态数组中可能被选择或排除的键在返回类型中保持可选。\n * @param source - 不会被修改的源对象\n * @param keys - 需要排除的键\n * @returns 包含其余自有可枚举字符串与 Symbol 属性的新对象\n */\nexport function omit<Source extends object, const Keys extends readonly (keyof Source)[]>(\n\tsource: Source,\n\tkeys: Keys\n): number extends Keys[\"length\"] ? Omit<Source, Keys[number]> & Partial<Pick<Source, Keys[number]>> : Omit<Source, Keys[number]>;\nexport function omit<Source extends object>(source: Source, keys: readonly PropertyKey[]): Partial<Source>;\nexport function omit<Source extends object>(source: Source, keys: readonly PropertyKey[]): Partial<Source> {\n\tconst result = { ...source };\n\tfor (const key of keys) Reflect.deleteProperty(result, key);\n\treturn result;\n}\n\n/**\n * 按条件排除对象的自有可枚举属性。\n *\n * @param source - 不会被修改的源对象\n * @param predicate - 接收属性值、键和源对象;返回真值时排除该属性。\n * @returns 由未匹配属性组成的新对象\n */\nexport function omitBy<Source extends object>(\n\tsource: Source,\n\tpredicate: (value: Source[keyof Source], key: keyof Source, source: Source) => unknown\n): Partial<Source> {\n\tconst result: Partial<Source> = {};\n\tfor (const key of getEnumerableOwnKeys(source) as (keyof Source)[]) {\n\t\tif (!predicate(source[key], key, source)) defineEnumerableProperty(result, key, source[key]);\n\t}\n\treturn result;\n}\n\n/**\n * 按条件选择对象的自有可枚举属性。\n *\n * @param source - 不会被修改的源对象\n * @param predicate - 接收属性值、键和源对象;返回真值时保留该属性。\n * @returns 由匹配属性组成的新对象\n */\nexport function pickBy<Source extends object>(\n\tsource: Source,\n\tpredicate: (value: Source[keyof Source], key: keyof Source, source: Source) => unknown\n): Partial<Source> {\n\tconst result: Partial<Source> = {};\n\tfor (const key of getEnumerableOwnKeys(source) as (keyof Source)[]) {\n\t\tif (predicate(source[key], key, source)) defineEnumerableProperty(result, key, source[key]);\n\t}\n\treturn result;\n}\n\n/**\n * 映射对象的自有可枚举属性值。\n *\n * @param source - 不会被修改的源对象\n * @param mapper - 接收值、键和源对象的映射函数\n * @returns 保留原键的新对象\n */\nexport function mapValues<Source extends object, Result>(\n\tsource: Source,\n\tmapper: (value: Source[keyof Source], key: keyof Source, source: Source) => Result\n): { [Key in keyof Source]: Result } {\n\tconst result = {} as { [Key in keyof Source]: Result };\n\tfor (const key of Reflect.ownKeys(source) as (keyof Source)[]) {\n\t\tif (Object.prototype.propertyIsEnumerable.call(source, key)) defineEnumerableProperty(result, key, mapper(source[key], key, source));\n\t}\n\treturn result;\n}\n\n/**\n * 对自有可枚举属性执行 SameValue 浅比较。\n *\n * @remarks 嵌套对象只比较引用;`NaN` 相等,`0` 与 `-0` 不相等。\n * @param left - 第一对象\n * @param right - 第二对象\n * @returns 自有可枚举键集合与对应值均满足 SameValue 时返回 `true`。\n */\nexport function shallowEqual(left: object, right: object): boolean {\n\tif (Object.is(left, right)) return true;\n\tconst leftKeys = Reflect.ownKeys(left).filter((key) => Object.prototype.propertyIsEnumerable.call(left, key));\n\tconst rightKeys = Reflect.ownKeys(right).filter((key) => Object.prototype.propertyIsEnumerable.call(right, key));\n\tif (leftKeys.length !== rightKeys.length) return false;\n\treturn leftKeys.every((key) => Object.prototype.hasOwnProperty.call(right, key) && Object.is(Reflect.get(left, key), Reflect.get(right, key)));\n}\n\n/**\n * 把 Query 原始值规范化为文本。\n *\n * @param value - 已排除空值的字符串、数字、布尔值或 BigInt\n * @returns 与 URLSearchParams 兼容的文本值\n * @throws `RangeError` 当数字不是有限值。\n */\nconst serializeQueryValue = (value: Exclude<QueryPrimitive, null | undefined>): string => {\n\tif (typeof value === \"number\" && !Number.isFinite(value)) {\n\t\tthrow new RangeError(\"Query parameter numbers must be finite.\");\n\t}\n\treturn String(value);\n};\n\n/**\n * 将对象序列化为标准 URL 查询字符串。\n *\n * @remarks `null` 与 `undefined` 被跳过;数组使用重复键;返回值不会修改输入。\n * @param value - 查询参数对象\n * @param options - 排序、空格和问号前缀选项\n * @returns URL 编码后的查询字符串;没有参数时始终返回空字符串。\n * @throws `RangeError` 当参数包含 `NaN` 或无穷数字。\n * @throws `URIError` 当键或值包含孤立的 UTF-16 代理项。\n */\nexport function toQueryString(value: Readonly<Record<string, QueryValue>>, options: QueryStringOptions = {}): string {\n\tconst entries = Object.entries(value);\n\tif (options.sort) entries.sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0));\n\tconst parameters: string[] = [];\n\tfor (const [key, rawValue] of entries) {\n\t\tconst values = isQueryPrimitiveArray(rawValue) ? rawValue : [rawValue];\n\t\tfor (const item of values) {\n\t\t\tif (item !== null && item !== undefined) {\n\t\t\t\tparameters.push(`${encodeURIComponent(key)}=${encodeURIComponent(serializeQueryValue(item))}`);\n\t\t\t}\n\t\t}\n\t}\n\t// 补齐表单编码字符集,保留已有查询字符串的输出格式。\n\tlet result = parameters.join(\"&\").replace(/[!'()~]/gu, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`);\n\tif (options.space !== \"percent\") result = result.replace(/%20/gu, \"+\");\n\treturn result && options.prefixQuestionMark ? `?${result}` : result;\n}\n"],"mappings":"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"}
|
package/dist/storage/index.mjs
CHANGED
|
@@ -1,26 +1,22 @@
|
|
|
1
|
-
import { getRuntimeUni, runtimeGlobals } from "../internal/runtime.mjs";
|
|
2
1
|
import { decodeSecureBase64, encodeSecureBase64 } from "../base64/index.mjs";
|
|
3
2
|
//#region src/storage/index.ts
|
|
4
3
|
/**
|
|
5
4
|
* 读取并校验当前运行时的全局 uni-app 同步 Storage。
|
|
6
5
|
*
|
|
7
|
-
* @returns
|
|
6
|
+
* @returns 检测到可用的 uni-app 同步 Storage 时返回 `true`。
|
|
8
7
|
* @throws `TypeError` 当全局 `uni` 存在但缺少本库需要的同步 Storage 方法。
|
|
9
8
|
*/
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
if (
|
|
13
|
-
|
|
14
|
-
const storage = value;
|
|
15
|
-
if (typeof storage.getStorageSync !== "function" || typeof storage.getStorageInfoSync !== "function" || typeof storage.removeStorageSync !== "function" || typeof storage.setStorageSync !== "function") throw new TypeError("全局 uni 对象未提供同步 Storage API。");
|
|
16
|
-
return storage;
|
|
9
|
+
const hasGlobalUniStorage = () => {
|
|
10
|
+
if (typeof uni === "undefined") return false;
|
|
11
|
+
if (uni === null || typeof uni.getStorageSync !== "function" || typeof uni.getStorageInfoSync !== "function" || typeof uni.removeStorageSync !== "function" || typeof uni.setStorageSync !== "function") throw new TypeError("The global uni object does not provide synchronous Storage APIs.");
|
|
12
|
+
return true;
|
|
17
13
|
};
|
|
18
14
|
/** 默认 JSON Codec;显式拒绝会被 JSON.stringify 静默丢弃的顶层值。 */
|
|
19
15
|
const jsonCodec = {
|
|
20
16
|
decode: (value) => JSON.parse(value),
|
|
21
17
|
encode: (value) => {
|
|
22
18
|
const encoded = JSON.stringify(value);
|
|
23
|
-
if (typeof encoded !== "string") throw new TypeError("
|
|
19
|
+
if (typeof encoded !== "string") throw new TypeError("The storage value cannot be serialized as JSON.");
|
|
24
20
|
return encoded;
|
|
25
21
|
}
|
|
26
22
|
};
|
|
@@ -29,7 +25,7 @@ const base64StorageCodec = {
|
|
|
29
25
|
decode: (value) => JSON.parse(decodeSecureBase64(value)),
|
|
30
26
|
encode: (value) => {
|
|
31
27
|
const encoded = JSON.stringify(value);
|
|
32
|
-
if (typeof encoded !== "string") throw new TypeError("
|
|
28
|
+
if (typeof encoded !== "string") throw new TypeError("The storage value cannot be serialized as JSON.");
|
|
33
29
|
return encodeSecureBase64(encoded);
|
|
34
30
|
}
|
|
35
31
|
};
|
|
@@ -38,30 +34,30 @@ let activeConfiguration;
|
|
|
38
34
|
/**
|
|
39
35
|
* 判断未知值是否为非数组对象记录。
|
|
40
36
|
*
|
|
41
|
-
* @param value - JSON.parse
|
|
37
|
+
* @param value - JSON.parse 返回的未知值
|
|
42
38
|
* @returns 值为非空、非数组对象时返回 `true`。
|
|
43
39
|
*/
|
|
44
40
|
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
45
41
|
/**
|
|
46
42
|
* 校验 Storage 业务键。
|
|
47
43
|
*
|
|
48
|
-
* @param key - 不含全局 Prefix
|
|
44
|
+
* @param key - 不含全局 Prefix 的业务键或业务键前缀
|
|
49
45
|
* @throws `TypeError` 当值不是非空字符串。
|
|
50
46
|
*/
|
|
51
47
|
const assertKey = (key) => {
|
|
52
|
-
if (typeof key !== "string" || key.length === 0) throw new TypeError("Storage
|
|
48
|
+
if (typeof key !== "string" || key.length === 0) throw new TypeError("Storage keys must be nonempty strings.");
|
|
53
49
|
};
|
|
54
50
|
/**
|
|
55
51
|
* 创建浏览器 Storage 后端。
|
|
56
52
|
*
|
|
57
53
|
* @remarks 平台对象在调用阶段读取,因此导入模块不会访问浏览器全局对象。
|
|
58
54
|
* @param kind - 选择 `localStorage` 或 `sessionStorage`。
|
|
59
|
-
* @returns
|
|
55
|
+
* @returns 统一的内部同步后端
|
|
60
56
|
* @throws `Error` 当所选 Storage 在当前环境不可用。
|
|
61
57
|
*/
|
|
62
58
|
const createWebStorageBackend = (kind) => {
|
|
63
|
-
const storage = kind === "local" ?
|
|
64
|
-
if (storage === void 0) throw new Error(
|
|
59
|
+
const storage = kind === "local" ? typeof localStorage === "undefined" ? void 0 : localStorage : typeof sessionStorage === "undefined" ? void 0 : sessionStorage;
|
|
60
|
+
if (storage === void 0) throw new Error(`The current runtime does not support ${kind}Storage.`);
|
|
65
61
|
return {
|
|
66
62
|
getItem: (key) => storage.getItem(key),
|
|
67
63
|
keys: () => {
|
|
@@ -84,91 +80,90 @@ const createWebStorageBackend = (kind) => {
|
|
|
84
80
|
* 把 uni-app 同步 Storage 适配为内部后端。
|
|
85
81
|
*
|
|
86
82
|
* @remarks uni-app 以空字符串同时表示“键缺失”和“真实空值”,因此空字符串需要结合键清单消除歧义。
|
|
87
|
-
* @
|
|
88
|
-
* @returns 统一的内部同步后端。
|
|
83
|
+
* @returns 统一的内部同步后端
|
|
89
84
|
*/
|
|
90
|
-
const createUniStorageBackend = (
|
|
85
|
+
const createUniStorageBackend = () => ({
|
|
91
86
|
getItem: (key) => {
|
|
92
|
-
const value =
|
|
87
|
+
const value = uni.getStorageSync(key);
|
|
93
88
|
if (value !== "") return value;
|
|
94
|
-
return
|
|
89
|
+
return uni.getStorageInfoSync().keys.includes(key) ? value : void 0;
|
|
95
90
|
},
|
|
96
|
-
keys: () => [...
|
|
91
|
+
keys: () => [...uni.getStorageInfoSync().keys],
|
|
97
92
|
removeItem: (key) => {
|
|
98
|
-
|
|
93
|
+
uni.removeStorageSync(key);
|
|
99
94
|
},
|
|
100
95
|
setItem: (key, value) => {
|
|
101
|
-
|
|
96
|
+
uni.setStorageSync(key, value);
|
|
102
97
|
}
|
|
103
98
|
});
|
|
104
99
|
/**
|
|
105
100
|
* 解析并校验版本化 Storage 包络。
|
|
106
101
|
*
|
|
107
|
-
* @param rawValue -
|
|
108
|
-
* @param key -
|
|
109
|
-
* @returns 当前 v3
|
|
102
|
+
* @param rawValue - 后端返回的原始值
|
|
103
|
+
* @param key - 用于错误定位的完整物理键
|
|
104
|
+
* @returns 当前 v3 包络
|
|
110
105
|
* @throws `TypeError` 当原始值不是字符串、JSON 损坏、版本不支持或字段类型非法。
|
|
111
106
|
*/
|
|
112
107
|
const parseStoredEnvelope = (rawValue, key) => {
|
|
113
|
-
if (typeof rawValue !== "string") throw new TypeError(`Storage
|
|
108
|
+
if (typeof rawValue !== "string") throw new TypeError(`Storage entry "${key}" is not a string.`);
|
|
114
109
|
try {
|
|
115
110
|
const parsed = JSON.parse(rawValue);
|
|
116
|
-
if (!isRecord(parsed) || parsed["version"] !== 3 || typeof parsed["data"] !== "string" || !(parsed["expiresAt"] === null || typeof parsed["expiresAt"] === "number" && Number.isFinite(parsed["expiresAt"]))) throw new TypeError("
|
|
111
|
+
if (!isRecord(parsed) || parsed["version"] !== 3 || typeof parsed["data"] !== "string" || !(parsed["expiresAt"] === null || typeof parsed["expiresAt"] === "number" && Number.isFinite(parsed["expiresAt"]))) throw new TypeError("Unsupported storage envelope.");
|
|
117
112
|
return {
|
|
118
113
|
data: parsed["data"],
|
|
119
114
|
expiresAt: parsed["expiresAt"],
|
|
120
115
|
version: 3
|
|
121
116
|
};
|
|
122
117
|
} catch (cause) {
|
|
123
|
-
throw new TypeError(`Storage
|
|
118
|
+
throw new TypeError(`Storage entry "${key}" is corrupted or unsupported.`, { cause });
|
|
124
119
|
}
|
|
125
120
|
};
|
|
126
121
|
/**
|
|
127
122
|
* 创建绑定命名空间、Codec 与时钟的 Storage Area。
|
|
128
123
|
*
|
|
129
124
|
* @param backendFactory - 每次操作时解析平台后端的工厂,保证导入安全并反映平台可用性。
|
|
130
|
-
* @param prefix -
|
|
131
|
-
* @param codec - 业务值与包络文本之间的 Codec
|
|
132
|
-
* @param now - TTL
|
|
133
|
-
* @returns 完整的命名空间 Storage
|
|
125
|
+
* @param prefix - 已校验的全局物理键前缀
|
|
126
|
+
* @param codec - 业务值与包络文本之间的 Codec
|
|
127
|
+
* @param now - TTL 计算使用的可注入时钟
|
|
128
|
+
* @returns 完整的命名空间 Storage 操作集合
|
|
134
129
|
*/
|
|
135
130
|
const createStorageArea = (backendFactory, prefix, codec, now) => {
|
|
136
131
|
/**
|
|
137
132
|
* 拼接物理键。
|
|
138
133
|
*
|
|
139
|
-
* @param key -
|
|
140
|
-
* @returns
|
|
134
|
+
* @param key - 已校验业务键
|
|
135
|
+
* @returns 带当前命名空间前缀的物理键
|
|
141
136
|
*/
|
|
142
137
|
const toStorageKey = (key) => `${prefix}${key}`;
|
|
143
138
|
/**
|
|
144
139
|
* 解析本次读写实际使用的 Codec。
|
|
145
140
|
*
|
|
146
141
|
* @param crypto - 单次 Base64 混淆开关;省略时沿用 Area 全局 Codec。
|
|
147
|
-
* @returns 本次操作使用的全局、JSON 或 Base64 Codec
|
|
142
|
+
* @returns 本次操作使用的全局、JSON 或 Base64 Codec
|
|
148
143
|
* @throws `TypeError` 当 JavaScript 调用方传入非布尔值。
|
|
149
144
|
*/
|
|
150
145
|
const resolveOperationCodec = (crypto) => {
|
|
151
146
|
if (crypto === void 0) return codec;
|
|
152
|
-
if (typeof crypto !== "boolean") throw new TypeError("Storage
|
|
147
|
+
if (typeof crypto !== "boolean") throw new TypeError("The per-operation Storage `crypto` option must be a boolean.");
|
|
153
148
|
return crypto ? base64StorageCodec : jsonCodec;
|
|
154
149
|
};
|
|
155
150
|
/**
|
|
156
151
|
* 枚举当前命名空间中的业务键。
|
|
157
152
|
*
|
|
158
|
-
* @param backend -
|
|
159
|
-
* @returns
|
|
153
|
+
* @param backend - 本次操作使用的后端
|
|
154
|
+
* @returns 已移除物理前缀、去重并排序的业务键
|
|
160
155
|
* @throws `TypeError` 当后端返回非字符串键。
|
|
161
156
|
*/
|
|
162
157
|
const listBusinessKeys = (backend) => {
|
|
163
158
|
const keys = backend.keys();
|
|
164
|
-
if (!Array.isArray(keys) || !keys.every((key) => typeof key === "string")) throw new TypeError("Storage
|
|
159
|
+
if (!Array.isArray(keys) || !keys.every((key) => typeof key === "string")) throw new TypeError("Keys returned by the Storage backend must be strings.");
|
|
165
160
|
return [...new Set(keys.filter((key) => key.startsWith(prefix)).map((key) => key.slice(prefix.length)))].sort();
|
|
166
161
|
};
|
|
167
162
|
/**
|
|
168
163
|
* 读取并处理单个包络。
|
|
169
164
|
*
|
|
170
|
-
* @param backend -
|
|
171
|
-
* @param key -
|
|
165
|
+
* @param backend - 本次操作使用的后端
|
|
166
|
+
* @param key - 业务键
|
|
172
167
|
* @returns 未过期包络;键缺失或已经过期时返回 `undefined`。
|
|
173
168
|
* @throws `TypeError` 当键或包络非法。
|
|
174
169
|
* @throws `RangeError` 当注入时钟返回非有限时间戳。
|
|
@@ -181,7 +176,7 @@ const createStorageArea = (backendFactory, prefix, codec, now) => {
|
|
|
181
176
|
const envelope = parseStoredEnvelope(rawValue, storageKey);
|
|
182
177
|
if (envelope.expiresAt === null) return envelope;
|
|
183
178
|
const timestamp = now();
|
|
184
|
-
if (!Number.isFinite(timestamp)) throw new RangeError("Storage
|
|
179
|
+
if (!Number.isFinite(timestamp)) throw new RangeError("The Storage clock must return a finite timestamp.");
|
|
185
180
|
if (timestamp < envelope.expiresAt) return envelope;
|
|
186
181
|
backend.removeItem(storageKey);
|
|
187
182
|
};
|
|
@@ -197,7 +192,7 @@ const createStorageArea = (backendFactory, prefix, codec, now) => {
|
|
|
197
192
|
try {
|
|
198
193
|
return resolveOperationCodec(options.crypto).decode(envelope.data);
|
|
199
194
|
} catch (cause) {
|
|
200
|
-
throw new TypeError(
|
|
195
|
+
throw new TypeError(`Unable to decode Storage entry "${toStorageKey(key)}".`, { cause });
|
|
201
196
|
}
|
|
202
197
|
},
|
|
203
198
|
has: (key) => readStoredEnvelope(backendFactory(), key) !== void 0,
|
|
@@ -222,20 +217,20 @@ const createStorageArea = (backendFactory, prefix, codec, now) => {
|
|
|
222
217
|
},
|
|
223
218
|
set(key, value, options = {}) {
|
|
224
219
|
assertKey(key);
|
|
225
|
-
if (value === void 0) throw new TypeError("
|
|
220
|
+
if (value === void 0) throw new TypeError("Cannot store top-level `undefined`; remove the key instead.");
|
|
226
221
|
let expiresAt = null;
|
|
227
222
|
if (options.ttlMs !== void 0) {
|
|
228
|
-
if (!Number.isFinite(options.ttlMs) || options.ttlMs <= 0) throw new RangeError("`ttlMs`
|
|
223
|
+
if (!Number.isFinite(options.ttlMs) || options.ttlMs <= 0) throw new RangeError("`ttlMs` must be a finite number greater than 0.");
|
|
229
224
|
const timestamp = now();
|
|
230
|
-
if (!Number.isFinite(timestamp) || !Number.isFinite(timestamp + options.ttlMs)) throw new RangeError("Storage
|
|
225
|
+
if (!Number.isFinite(timestamp) || !Number.isFinite(timestamp + options.ttlMs)) throw new RangeError("The Storage expiration time exceeds the supported timestamp range.");
|
|
231
226
|
expiresAt = timestamp + options.ttlMs;
|
|
232
227
|
}
|
|
233
228
|
let data;
|
|
234
229
|
try {
|
|
235
230
|
data = resolveOperationCodec(options.crypto).encode(value);
|
|
236
|
-
if (typeof data !== "string") throw new TypeError("Storage
|
|
231
|
+
if (typeof data !== "string") throw new TypeError("The Storage codec must return a string.");
|
|
237
232
|
} catch (cause) {
|
|
238
|
-
throw new TypeError("
|
|
233
|
+
throw new TypeError("Unable to encode the storage value.", { cause });
|
|
239
234
|
}
|
|
240
235
|
backendFactory().setItem(toStorageKey(key), JSON.stringify({
|
|
241
236
|
data,
|
|
@@ -248,30 +243,30 @@ const createStorageArea = (backendFactory, prefix, codec, now) => {
|
|
|
248
243
|
/**
|
|
249
244
|
* 获取已激活的全局 Storage 配置。
|
|
250
245
|
*
|
|
251
|
-
* @returns 显式配置或首次 Storage
|
|
246
|
+
* @returns 显式配置或首次 Storage 操作创建的默认配置
|
|
252
247
|
*/
|
|
253
248
|
const requireStorageConfiguration = () => {
|
|
254
249
|
if (activeConfiguration === void 0) configureStorage();
|
|
255
|
-
if (activeConfiguration === void 0) throw new Error("
|
|
250
|
+
if (activeConfiguration === void 0) throw new Error("Unable to initialize the Storage configuration.");
|
|
256
251
|
return activeConfiguration;
|
|
257
252
|
};
|
|
258
253
|
/**
|
|
259
254
|
* 创建稳定的公开 Storage 门面。
|
|
260
255
|
*
|
|
261
|
-
* @param select - 从激活配置选择 Local 或 Session
|
|
262
|
-
* @param name -
|
|
256
|
+
* @param select - 从激活配置选择 Local 或 Session 的函数
|
|
257
|
+
* @param name - 用于不可用错误的公开门面名称
|
|
263
258
|
* @returns 可安全导入、并在首次调用时解析默认或显式配置的稳定对象。
|
|
264
259
|
*/
|
|
265
260
|
const createStorageAreaProxy = (select, name) => {
|
|
266
261
|
/**
|
|
267
262
|
* 解析当前实际 Area。
|
|
268
263
|
*
|
|
269
|
-
* @returns 配置中的 Local 或 Session Area
|
|
264
|
+
* @returns 配置中的 Local 或 Session Area
|
|
270
265
|
* @throws `Error` 当 uni-app 模式请求 Session。
|
|
271
266
|
*/
|
|
272
267
|
const getArea = () => {
|
|
273
268
|
const area = select(requireStorageConfiguration());
|
|
274
|
-
if (area === void 0) throw new Error(
|
|
269
|
+
if (area === void 0) throw new Error(`${name} is not supported in uni-app.`);
|
|
275
270
|
return area;
|
|
276
271
|
};
|
|
277
272
|
return {
|
|
@@ -311,22 +306,22 @@ const Session = createStorageAreaProxy((configuration) => configuration.session,
|
|
|
311
306
|
*/
|
|
312
307
|
function configureStorage(options = {}) {
|
|
313
308
|
const prefix = options.prefix ?? "fast__";
|
|
314
|
-
if (typeof prefix !== "string" || prefix.length === 0) throw new TypeError("Storage
|
|
315
|
-
if (options.codec !== void 0 && options.crypto === true) throw new TypeError("Storage
|
|
309
|
+
if (typeof prefix !== "string" || prefix.length === 0) throw new TypeError("The Storage prefix must be a nonempty string.");
|
|
310
|
+
if (options.codec !== void 0 && options.crypto === true) throw new TypeError("Storage codec and crypto options cannot be used together.");
|
|
316
311
|
const codec = options.codec ?? (options.crypto === true ? base64StorageCodec : jsonCodec);
|
|
317
312
|
const now = options.now ?? Date.now;
|
|
318
313
|
if (activeConfiguration !== void 0) {
|
|
319
314
|
if (activeConfiguration.prefix === prefix && activeConfiguration.codec === codec && activeConfiguration.now === now) return;
|
|
320
|
-
throw new Error("Storage
|
|
315
|
+
throw new Error("Storage is already configured with different options.");
|
|
321
316
|
}
|
|
322
|
-
const
|
|
317
|
+
const usesUniStorage = hasGlobalUniStorage();
|
|
323
318
|
const configuration = {
|
|
324
319
|
codec,
|
|
325
|
-
local: createStorageArea(
|
|
320
|
+
local: createStorageArea(usesUniStorage ? () => createUniStorageBackend() : () => createWebStorageBackend("local"), prefix, codec, now),
|
|
326
321
|
now,
|
|
327
322
|
prefix
|
|
328
323
|
};
|
|
329
|
-
if (
|
|
324
|
+
if (!usesUniStorage) configuration.session = createStorageArea(() => createWebStorageBackend("session"), prefix, codec, now);
|
|
330
325
|
activeConfiguration = configuration;
|
|
331
326
|
}
|
|
332
327
|
/** 返回 Storage 是否已经显式配置,或由首次 Storage 操作激活默认配置。 */
|