Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | 3x 8x 3x 3x 3x 3x 3x 3x 5x 5x 10x 5x 3x 8x 8x 8x 8x 1x 8x 23x 23x 46x 23x 8x 17x 14x 1x 1x 1x 1x 14x 14x 5x 9x 8x 4x | import { isPlainObject, mapValues, range, shuffle } from 'lodash-uni'
import { base64UrlDecode, base64UrlEncode } from './base64'
import { isType } from './isType'
import { rot13 } from './rot13'
export type RawObjectData = Record<any, any>
export type RawListData<TRawObjectData extends RawObjectData = RawObjectData> =
TRawObjectData[]
export type RawData<TRawObjectData extends RawObjectData = RawObjectData> =
| TRawObjectData
| RawListData<TRawObjectData>
export type ElementOfRawData<TRawData extends RawData> =
TRawData extends RawData<infer X> ? X : never
export type KeyOfRawData<TRawData extends RawData> =
keyof ElementOfRawData<TRawData>
export type ValueOfRawData<TRawData extends RawData> =
ElementOfRawData<TRawData>[KeyOfRawData<TRawData>]
export type PackedData<TRawData extends RawData> = {
readonly _k: Array<KeyOfRawData<TRawData>>
readonly _v: Array<Array<ValueOfRawData<TRawData>>>
readonly _s: string
}
/**
* 数据打包器。
*/
export class DataPacker {
private static encodeIndexes(indexes: number[]): string {
return rot13(
base64UrlEncode(
`${Math.random().toString(36).slice(2)}.${indexes.join('.')}`,
),
)
}
private static decodeIndexes(value: string): number[] {
return base64UrlDecode(rot13(value)).split('.').slice(1).map(Number)
}
/**
* 打包数据。
*/
static pack<TRawObjectData extends RawData>(
rawData: TRawObjectData,
): PackedData<TRawObjectData> {
const notArray = !Array.isArray(rawData)
const rawList: RawListData = notArray ? [rawData] : (rawData as any)
const keys: Array<KeyOfRawData<TRawObjectData>> = rawList.length
? shuffle(Object.keys(rawList[0]) as any)
: []
const indexes: number[] = shuffle(range(0, keys.length))
const values = []
for (const rawItem of rawList) {
const item = []
for (let i = 0, len = indexes.length; i < len; i++) {
item[indexes[i]] = rawItem[keys[i]]
}
values.push(item)
}
return {
_k: keys,
_v: values,
_s: DataPacker.encodeIndexes(notArray ? [-1, ...indexes] : indexes),
}
}
/**
* 返回结果同 `pack()`,不过类型是原数据的类型。
*/
static packAsRawType<T>(rawData: T): T {
return DataPacker.pack(rawData as any) as any
}
/**
* 解包数据。
*/
static unpack<TRawObjectData extends RawData>(
packedData: PackedData<TRawObjectData>,
): RawData<TRawObjectData> {
const rawList: Array<RawListData<TRawObjectData>> = []
const indexes = DataPacker.decodeIndexes(packedData._s)
const notArray = indexes[0] === -1
if (notArray) {
indexes.shift()
}
for (const values of packedData._v) {
const item: ElementOfRawData<TRawObjectData> = {} as any
for (let i = 0, len = indexes.length; i < len; i++) {
item[packedData._k[i]] = values[indexes[i]]
}
rawList.push(item)
}
return (notArray ? rawList[0] : rawList) as any
}
/**
* 如果是打包后的数据,则解包后返回,否则直接返回。如果是对象,则递归尝试解包。
*
* @param value 数据
* @param depth 递归层级,默认:2
* @returns 返回结果数据
*/
static unpackIfNeeded(value: any, depth = 2): any {
if (isPlainObject(value)) {
// 兼容 v2 的 StructuredListTransformer 产生的数据
// https://github.com/fjc0k/vtils/blob/v2/packages/vtils/src/StructuredListTransformer.ts
if (value.__IS_PACKED_STRUCTURED_LIST__) {
value._k = value.keys
value._v = value.values
value._s = value.signature
delete value.__IS_PACKED_STRUCTURED_LIST__
}
if (isType<PackedData<RawObjectData>>(value)) {
if (value._k && value._v && value._s) {
return DataPacker.unpack(value)
}
if (depth > 0) {
return mapValues(value, v => DataPacker.unpackIfNeeded(v, depth - 1))
}
}
}
return value
}
}
|