sys-shim 0.0.1-10

Sign up to get free protection for your applications and to get access to all the features.
package/src/util.js ADDED
@@ -0,0 +1,386 @@
1
+ import { DeepProxy } from './proxy-deep.js'
2
+ const KEYS_MAP = new Map()
3
+ export function get([key]) {
4
+ return KEYS_MAP.get(key) || key
5
+ }
6
+
7
+ /**
8
+ * 获取 `/**` 中 `*` 号的数量
9
+ * @param {*} inputStr
10
+ * @returns
11
+ */
12
+ export function getCodeLine(inputStr) {
13
+ // 使用正则表达式匹配以 `/` 开头,后面跟着连续的 `*` 号的模式,使用贪婪匹配
14
+ const pattern = /\/\*{1,}/g
15
+ const matches = inputStr.match(pattern)
16
+
17
+ // 如果没有匹配到任何 '/**',返回0或者其他默认值
18
+ if (!matches) {
19
+ return 0
20
+ }
21
+
22
+ // 初始化最大 '**' 数量和对应的 '/**' 字符串
23
+ let maxAsterisks = 0
24
+ let maxAsterisksMatch = ``
25
+
26
+ // 遍历所有匹配结果,找出包含最多 '*' 号的那一个
27
+ for (const match of matches) {
28
+ const asterisksCount = match.length - 1 // 减去前面的 '/'
29
+ if (asterisksCount > maxAsterisks) {
30
+ maxAsterisks = asterisksCount
31
+ maxAsterisksMatch = match
32
+ }
33
+ }
34
+
35
+ // 返回最多的 '*' 号数量
36
+ return maxAsterisks
37
+ }
38
+
39
+ export function deepProxy({
40
+ keys = [`then`, `catch`],
41
+ cb = (records) => {
42
+ return new Promise(async (res, rej) => {
43
+ // 模拟异步操作
44
+ setTimeout(() => {
45
+ res(records)
46
+ }, Math.random() * 1000)
47
+ })
48
+ },
49
+ } = {}) {
50
+ keys.forEach(key => {
51
+ let _val = Symbol(key)
52
+ KEYS_MAP.set(key, _val)
53
+ KEYS_MAP.set(_val, key)
54
+ })
55
+ function getRecords(context = {}) {
56
+ return context.records || []
57
+ }
58
+ // 代理处理程序
59
+ const handler = {
60
+ get(target, key, receiver) {
61
+ let records = getRecords(this)
62
+ if (keys.includes(key)) {
63
+ let promise = cb(records)
64
+ records.hackRun = true // 已运行过
65
+ return promise[key].bind(promise)
66
+ } else {
67
+ records.push({ type: `get`, key: get([key]) })
68
+ let newTarget = function () { }
69
+ return this.nest(newTarget, { userData: { records } })
70
+ }
71
+ },
72
+ apply(target, thisArg, args) {
73
+ let records = getRecords(this)
74
+ setTimeout(() => {
75
+ let recordsEnd = getRecords(this)
76
+ !recordsEnd.hackRun && cb(recordsEnd)
77
+ }, 0)
78
+ const key = records[records.length - 1].key
79
+ records[records.length - 1] = { type: `apply`, key, arg: args }
80
+ let newTarget = function () { }
81
+ return this.nest(newTarget, { userData: { records } })
82
+ },
83
+ construct(target, args) {
84
+ let records = getRecords(this)
85
+ records.push({ type: `construct`, arg: args })
86
+ let newTarget = function () { }
87
+ return this.nest(newTarget, { userData: { records } })
88
+ },
89
+ defineProperty(target, key, args) {
90
+ let records = getRecords(this)
91
+ records.push({ type: `defineProperty`, key, arg: args })
92
+ let newTarget = function () { }
93
+ return this.nest(newTarget, { userData: { records } })
94
+ },
95
+ deleteProperty(target, key) {
96
+ let records = getRecords(this)
97
+ records.push({ type: `deleteProperty`, key })
98
+ let newTarget = function () { }
99
+ return this.nest(newTarget, { userData: { records } })
100
+
101
+ },
102
+ set(target, key, value) {
103
+ let records = getRecords(this)
104
+ records.push({ type: `set`, key, arg: value })
105
+ let newTarget = function () { }
106
+ return this.nest(newTarget, { userData: { records } })
107
+ },
108
+ getOwnPropertyDescriptor(target, prop) {
109
+ let records = getRecords(this)
110
+ records.push({ type: `getOwnPropertyDescriptor`, key: prop })
111
+ let newTarget = function () { }
112
+ return { configurable: true, enumerable: true, value: this.nest(newTarget) }
113
+ },
114
+ getPrototypeOf(target) {
115
+ let records = getRecords(this)
116
+ records.push({ type: `getPrototypeOf` })
117
+ let newTarget = function () { }
118
+ return this.nest(newTarget, { userData: { records } })
119
+ },
120
+ has(target, prop) {
121
+ let records = getRecords(this)
122
+ records.push({ type: `has`, key: prop })
123
+ return true
124
+ },
125
+ isExtensible(target) {
126
+ let records = getRecords(this)
127
+ records.push({ type: `isExtensible` })
128
+ return true
129
+ },
130
+ setPrototypeOf(target, prototype) {
131
+ let records = getRecords(this)
132
+ records.push({ type: `setPrototypeOf`, arg: prototype })
133
+ return true
134
+ },
135
+ ownKeys(target) {
136
+ let records = getRecords(this)
137
+ records.push({ type: `ownKeys` })
138
+ return Reflect.ownKeys(target)
139
+ },
140
+ preventExtensions(target) {
141
+ let records = getRecords(this)
142
+ records.push({ type: `preventExtensions` })
143
+ Object.preventExtensions(target)
144
+ return true
145
+ },
146
+ }
147
+
148
+ // 返回初始对象的代理
149
+ return new DeepProxy({}, handler)
150
+ }
151
+
152
+ export function binaryArrayToBuffer(binaryArray) {
153
+ let buffer = new ArrayBuffer(binaryArray.length)
154
+ let view = new Uint8Array(buffer)
155
+ for (let i = 0; i < binaryArray.length; i++) {
156
+ view[i] = binaryArray[i]
157
+ }
158
+ return buffer
159
+ }
160
+
161
+ /**
162
+ * 删除左边空格
163
+ * @param {*} str
164
+ * @returns
165
+ */
166
+ export function removeLeft(str) {
167
+ const lines = str.split(`\n`)
168
+ // 获取应该删除的空白符数量
169
+ const minSpaceNum = lines.filter(item => item.trim())
170
+ .map(item => item.match(/(^\s+)?/)[0].length)
171
+ .sort((a, b) => a - b)[0]
172
+ // 删除空白符
173
+ const newStr = lines
174
+ .map(item => item.slice(minSpaceNum))
175
+ .join(`\n`)
176
+ return newStr
177
+ }
178
+
179
+ /**
180
+ * 简单的模板功能
181
+ * @param {*} template
182
+ * @param {*} data
183
+ * @returns
184
+ */
185
+ export function simpleTemplate(template, data) {
186
+ return template.replace(/#\{(\w+)\}/g, (match, key, pos) => {
187
+ const lineStr = getLineContainingChar(template, pos)
188
+ const spaceNum = getMinSpaceNum(lineStr)
189
+ const val = data[key] || ``
190
+ const newVal = addSpace(val, {num: spaceNum})
191
+ return newVal
192
+ })
193
+ }
194
+
195
+ /**
196
+ * 返回字符所在位置的整行文本
197
+ * @param {*} text
198
+ * @param {*} charPosition
199
+ * @returns
200
+ */
201
+ export function getLineContainingChar(text, charPosition) {
202
+ // 将多行文本分割成行数组
203
+ const lines = text.split(`\n`)
204
+
205
+ // 遍历行数组,找到包含给定字符位置的行
206
+ for (let i = 0; i < lines.length; i++) {
207
+ // 计算当前行的字符位置
208
+ const lineLength = lines[i].length
209
+ if (charPosition < lineLength) {
210
+ // 如果字符位置在当前行内,返回该行
211
+ return lines[i]
212
+ } else {
213
+ // 否则,减去当前行的长度,继续检查下一行
214
+ charPosition -= lineLength + 1 // +1 是为了减去换行符
215
+ }
216
+ }
217
+
218
+ // 如果没有找到包含给定字符位置的行,返回null或适当的错误信息
219
+ return null
220
+ }
221
+
222
+ /**
223
+ * 获取最小空白符数量
224
+ * @param {*} str
225
+ * @returns
226
+ */
227
+ export function getMinSpaceNum(str) {
228
+ const lines = str.split(`\n`)
229
+ const minSpaceNum = lines.filter(item => item.trim())
230
+ .map(item => item.match(/(^\s+)?/)[0].length)
231
+ .sort((a, b) => a - b)[0]
232
+ return minSpaceNum
233
+ }
234
+
235
+ /**
236
+ * 添加空白符
237
+ * @param {*} str
238
+ * @param {*} opt
239
+ * @returns
240
+ */
241
+ export function addSpace(str, opt = {}) {
242
+ opt = {
243
+ num: 0, // 字符符数量
244
+ space: ` `,
245
+ skip: 0, // 要跳过设置的索引
246
+ ...opt,
247
+ }
248
+ const lines = str.split(`\n`)
249
+ const newStr = lines
250
+ .map((item, index) => index <= opt.skip ? item : opt.space.repeat(opt.num) + item)
251
+ .join(`\n`)
252
+ return newStr
253
+ }
254
+
255
+ /**
256
+ * 获取 uuid
257
+ * @returns
258
+ */
259
+ export function getUuid () {
260
+ if (typeof crypto === `object`) {
261
+ if (typeof crypto.randomUUID === `function`) {
262
+ return crypto.randomUUID()
263
+ }
264
+ if (typeof crypto.getRandomValues === `function` && typeof Uint8Array === `function`) {
265
+ const callback = (c) => {
266
+ const num = Number(c)
267
+ return (num ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (num / 4)))).toString(16)
268
+ }
269
+ return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, callback)
270
+ }
271
+ }
272
+ let timestamp = new Date().getTime()
273
+ let perforNow = (typeof performance !== `undefined` && performance.now && performance.now() * 1000) || 0
274
+ return `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g, (c) => {
275
+ let random = Math.random() * 16
276
+ if (timestamp > 0) {
277
+ random = (timestamp + random) % 16 | 0
278
+ timestamp = Math.floor(timestamp / 16)
279
+ } else {
280
+ random = (perforNow + random) % 16 | 0
281
+ perforNow = Math.floor(perforNow / 16)
282
+ }
283
+ return (c === `x` ? random : (random & 0x3) | 0x8).toString(16)
284
+ })
285
+ }
286
+
287
+ export function isUTF8MultiByteStart(byte) {
288
+ // 如果字节的高位为11,则是多字节字符的起始字节
289
+ return (byte & 0xC0) === 0xC0
290
+ }
291
+
292
+ export function isUTF8MultiByteContinuation(byte) {
293
+ // 如果字节的高位为10,则是多字节字符的延续字节
294
+ return (byte & 0xC0) === 0x80
295
+ }
296
+
297
+
298
+ /**
299
+ * 根据字节长度分割字符串
300
+ * @param {*} param0
301
+ * @returns
302
+ */
303
+ export function sliceStringByBytes({lib, str, sliceLength}) {
304
+ const uint8Array = lib.encoder.encode(str)
305
+ let slices = []
306
+ let start = 0
307
+
308
+ while (start < uint8Array.length) {
309
+ let end = start + sliceLength
310
+ if (end > uint8Array.length) {
311
+ end = uint8Array.length
312
+ } else {
313
+ // 确保不在多字节字符中间断开
314
+ while (end > start && isUTF8MultiByteContinuation(uint8Array[end - 1])) {
315
+ end--
316
+ }
317
+ // 如果我们在多字节字符的起始处中止,则再次前移
318
+ if (end > start && isUTF8MultiByteStart(uint8Array[end - 1])) {
319
+ end--
320
+ }
321
+ }
322
+
323
+ const slice = uint8Array.subarray(start, end)
324
+ slices.push(lib.decoder.decode(slice))
325
+ start = end // 设置下次分片的起始位置
326
+ }
327
+
328
+ return slices
329
+ }
330
+
331
+ export function isType(data, type = undefined) { // 判断数据是否为 type, 或返回 type
332
+ const dataType = Object.prototype.toString.call(data).match(/\s(.+)]/)[1].toLowerCase()
333
+ return type ? (dataType === type.toLowerCase()) : dataType
334
+ }
335
+
336
+ /**
337
+ * 判断是否为空值
338
+ * @param {*} value 要判断的值
339
+ */
340
+ export function isEmpty(value) {
341
+ return [NaN, null, undefined, ``, [], {}].some((emptyItem) =>
342
+ typeof value === `string` && value
343
+ ? false
344
+ : JSON.stringify(value) === JSON.stringify(emptyItem),
345
+ )
346
+ }
347
+
348
+ /**
349
+ * 删除空值
350
+ * @param {object} obj 要处理的数据
351
+ */
352
+ export function removeEmpty(obj) {
353
+ return JSON.parse(JSON.stringify(obj), (key, value) => {
354
+ if (isEmpty(value) === false && Array.isArray(value)) {
355
+ value = value.filter((v) => !isEmpty(v))
356
+ }
357
+ return isEmpty(value) ? undefined : value
358
+ })
359
+ }
360
+
361
+ /**
362
+ * 函数缓存器,相同参数只会执行一次
363
+ * @param {*} fn
364
+ * @returns
365
+ */
366
+ export function memoize(fn) {
367
+ const cache = new Map() // 使用Map来存储缓存结果
368
+
369
+ function memoized(...args) {
370
+ const key = JSON.stringify(args) // 将参数转换为字符串作为缓存的键
371
+ if (cache.has(key)) {
372
+ return cache.get(key) // 如果缓存中已存在,直接返回缓存的结果
373
+ }
374
+
375
+ const result = fn.apply(this, args) // 否则,调用函数并存储结果
376
+ cache.set(key, result)
377
+ return result
378
+ }
379
+
380
+ // 添加一个方法来清除缓存
381
+ memoized.clearCache = function() {
382
+ cache.clear()
383
+ }
384
+
385
+ return memoized
386
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "browserArguments": "--disable-web-security --allow-running-insecure-content",
3
+ "page": "#{page}"
4
+ }
@@ -0,0 +1,5 @@
1
+ document.addEventListener(`DOMContentLoaded`, async () => {
2
+ new window.Sys().then(async main => {
3
+ window.sys = main
4
+ })
5
+ })
@@ -0,0 +1,6 @@
1
+ 直接通过 url 生成程序。
2
+
3
+ ``` sh
4
+ sys-shim pack --input [url]
5
+ ```
6
+