sys-shim 0.0.1-6 → 0.0.1-8

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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "sys-shim",
3
3
  "private": false,
4
4
  "type": "module",
5
- "version": "0.0.1-6",
5
+ "version": "0.0.1-8",
6
6
  "main": "./script/npm-pkg/node/main.min.cjs",
7
7
  "module": "./script/npm-pkg/node/main.min.mjs",
8
8
  "browser": {
@@ -10,9 +10,14 @@
10
10
  "./script/npm-pkg/node/main.min.mjs": "./script/npm-pkg/browser/main.esm.min.js"
11
11
  },
12
12
  "bin": {
13
- "sys-shim": "./script/bin/sys-shim.cjs"
13
+ "sys-shim": "./script/npm-pkg/bin/index.mjs"
14
14
  },
15
15
  "files": [
16
+ "./src/proxy-deep.js",
17
+ "./src/util.js",
18
+ "./template",
19
+ "./script/npm-pkg/bin",
20
+ "./script/npm-pkg/lib",
16
21
  "./script/npm-pkg/shim",
17
22
  "./script/npm-pkg/test",
18
23
  "./script/npm-pkg/node/main.min.cjs",
@@ -21,6 +26,7 @@
21
26
  "./script/npm-pkg/browser/main.esm.min.js"
22
27
  ],
23
28
  "scripts": {
29
+ "sys-shim": "node ./script/npm-pkg/bin/index.mjs",
24
30
  "lint": "eslint ./ --format unix",
25
31
  "lint-fix": "eslint ./ --fix --format unix",
26
32
  "dev": "run-p vite run.shim",
@@ -49,9 +55,15 @@
49
55
  "proxy-deep": "^3.1.1",
50
56
  "rollup": "^4.17.2",
51
57
  "rpc-websockets": "^7.6.0",
52
- "shx": "^0.3.4",
53
58
  "sys-shim": "link:",
54
59
  "vite": "^5.0.0",
55
60
  "vue": "^3.3.8"
61
+ },
62
+ "dependencies": {
63
+ "shx": "^0.3.4",
64
+ "download": "^8.0.0",
65
+ "filenamify": "^6.0.0",
66
+ "minimist": "^1.2.8",
67
+ "shelljs": "^0.8.5"
56
68
  }
57
69
  }
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+
3
+ import cp from 'node:child_process'
4
+ import fs from 'node:fs'
5
+ import path from 'node:path'
6
+ import { fileURLToPath } from 'node:url'
7
+ import process from 'node:process'
8
+ import minimist from 'minimist'
9
+ import {fn as pack} from './pack.mjs'
10
+
11
+ const __filename = fileURLToPath(import.meta.url)
12
+ const __dirname = path.dirname(__filename)
13
+
14
+ const cwd = `${__dirname}/../shim/win`
15
+ const argv = minimist(process.argv.slice(2))
16
+ const argv0 = argv._[0]
17
+
18
+ new Promise(async () => {
19
+ if(argv0 === `pack`) {
20
+ await pack(argv)
21
+ } else {
22
+ cp.execSync(`${cwd}/main.exe`, {
23
+ cwd,
24
+ stdio: `inherit`,
25
+ })
26
+ }
27
+ })
@@ -0,0 +1,152 @@
1
+ import cp from 'node:child_process'
2
+ import fs from 'node:fs'
3
+ import path from 'node:path'
4
+ import url from 'node:url'
5
+ import os from 'node:os'
6
+ import filenamify from 'filenamify'
7
+ import download from 'download'
8
+ import shelljs from 'shelljs'
9
+ import {
10
+ simpleTemplate,
11
+ } from '../../../src/util.js'
12
+ import process from 'node:process'
13
+
14
+ const __filename = url.fileURLToPath(import.meta.url)
15
+ const __dirname = path.dirname(__filename)
16
+ const pkgDir = path.join(__dirname, `../../../`)
17
+
18
+ function determinePathType(filePath) {
19
+ if((/^(http:\/\/|https:\/\/).+/i).test(filePath)) {
20
+ return `url`
21
+ } else if (path.isAbsolute(filePath)) {
22
+ return `abs`
23
+ } else if (filePath.startsWith(`./`) || filePath.startsWith(`../`)) {
24
+ return `relative`
25
+ } else {
26
+ return `sys`
27
+ }
28
+ }
29
+
30
+
31
+ /**
32
+ * 获取默认配置
33
+ */
34
+ async function parseArgv(argv) {
35
+ const cfg = {
36
+ input: ``,
37
+ icon: ``,
38
+ out: ``,
39
+ unzip: ``,
40
+ password: ``,
41
+ ...argv,
42
+ }
43
+ if(determinePathType(argv.input) === `url`) {
44
+ cfg.icon = cfg.icon || await getIcon(`${cfg.input}/favicon.ico`)
45
+ cfg.out = cfg.out || filenamify(cfg.input)
46
+ } else {
47
+ cfg.icon = cfg.icon || await getIcon(`${cfg.input}/favicon.ico`)
48
+ cfg.out = cfg.out || path.parse(cfg.input).name
49
+ }
50
+ cfg.unzip = argv.unzip || `sys-shim-app/${cfg.out}`
51
+ return cfg
52
+ }
53
+
54
+ /**
55
+ * 如果不存在 icon 则返回默认 icon
56
+ */
57
+ async function getIcon(iconPath) {
58
+ if(fs.existsSync(iconPath)) {
59
+ return iconPath
60
+ } else {
61
+ try {
62
+ const res = new url.URL(iconPath)
63
+ const icon = `${res.protocol}//${res.host}/favicon.ico`
64
+ const tempIcon = `${os.tmpdir()}/${filenamify(icon)}`
65
+ fs.writeFileSync(tempIcon, await download(icon))
66
+ return tempIcon
67
+ } catch (error) {
68
+ console.warn(`从 ${iconPath} 获取图标错误,将使用默认图标`, error)
69
+ return `${pkgDir}/script/npm-pkg/shim/win/favicon.ico`
70
+ }
71
+ }
72
+ }
73
+
74
+ function zip(cfg) {
75
+ const zipBin = `${pkgDir}/script/npm-pkg/lib/WinRAR.exe`
76
+ const icon = cfg.icon
77
+ const out = cfg.out
78
+ const input = cfg.input
79
+ const unzip = cfg.unzip
80
+
81
+ /**
82
+ * Path 解压后运行
83
+ * Silent 解压对话框 1 隐藏 2 显示
84
+ * Overwrite 解压覆盖询问 0 询问 1 覆盖 2 跳过
85
+ * Update 更新 U 解压不存在的或较新的 F 只更新目标位置已存在的
86
+ * Shortcut 创建快捷方式
87
+ * D 桌面创建
88
+ * P 在开始菜单/程序中创建
89
+ * T 在启动菜单中创建
90
+ */
91
+ const comment = (() => {
92
+ const file = `${os.tmpdir()}/comment.txt`
93
+ const text = `
94
+ Path=${path.normalize(unzip)}
95
+ Setup=main
96
+ Silent=1
97
+ Overwrite=1
98
+ Update=U
99
+ Shortcut=D, main, , "sys-shim app", "${cfg.out}", favicon.ico
100
+ `.split(`\n`).map(item => item.trim()).join(`\n`).trim()
101
+ fs.writeFileSync(file, text)
102
+ return file
103
+ })()
104
+
105
+ /**
106
+ * a 添加压缩
107
+ * -r 递归
108
+ * -ep1 从名称中排除主文件夹
109
+ * -inul 关闭错误信息
110
+ * -y 假设全部的询问回应皆为“是”
111
+ * -sfx 创建自解压文件 默认为 Default.SFX 模块,修改示例 -sfxWinCon.SFX
112
+ * -iicon 指定自解压图标
113
+ * -iimg 指定自解压图片
114
+ * -m 设置压缩等级,-m0 为存储,-m5 为最优,默认 -m3 标准
115
+ * -p 使用密码,例如 -pMyPassWord
116
+ * -hp 使用密码,并加密文件名
117
+ * -z 从文件中读取注释
118
+ * -ibck 在后台运行 WinRAR
119
+ * -idv 显示详细输出
120
+ */
121
+ const outV = `${out}-${Date.now()}`
122
+ const cmd = `${zipBin} a -r -ep1 -y -ibck -sfx -iicon"${icon}" -z"${comment}" "${outV}" ${input}/*`
123
+ cp.execSync(cmd, {stdio: `inherit`})
124
+ }
125
+
126
+ function genFile(cfg) {
127
+ const newCfg = {
128
+ input: `${os.tmpdir()}/pack.temp`,
129
+ icon: `${os.tmpdir()}/pack.temp/favicon.ico`,
130
+ }
131
+ shelljs.rm(`-fr`, newCfg.input)
132
+ shelljs.cp(`-fr`, `${pkgDir}/template/pack`, newCfg.input)
133
+ shelljs.cp(`-f`, `${pkgDir}/script/npm-pkg/shim/win/main.exe`, newCfg.input)
134
+ shelljs.cp(`-f`, `${pkgDir}/script/npm-pkg/shim/win/favicon.ico`, newCfg.input)
135
+ shelljs.cp(`-f`, cfg.icon, `${newCfg.input}/favicon.ico`)
136
+ const newStr = simpleTemplate(fs.readFileSync(`${newCfg.input}/package.json`, `utf8`), {
137
+ page: determinePathType(cfg.input) === `url` ? cfg.input : `page.html`,
138
+ })
139
+ fs.writeFileSync(`${newCfg.input}/package.json`, newStr)
140
+ return newCfg
141
+ }
142
+
143
+
144
+ export async function fn(argv) {
145
+ const cfg = await parseArgv(argv)
146
+ const {input, icon} = genFile(cfg)
147
+ cfg.input = input
148
+ cfg.icon = icon
149
+ console.log(cfg)
150
+ await zip(cfg)
151
+
152
+ }
Binary file
Binary file
Binary file
@@ -0,0 +1,104 @@
1
+ 'use strict'
2
+
3
+ function parsePath(text) {
4
+ return text.split(`.`)
5
+ }
6
+
7
+ function push(arr, el) {
8
+ const newArr = arr.slice()
9
+ newArr.push(el)
10
+ return newArr
11
+ }
12
+
13
+ // names of the traps that can be registered with ES6's Proxy object
14
+ const trapNames = [
15
+ `apply`,
16
+ `construct`,
17
+ `defineProperty`,
18
+ `deleteProperty`,
19
+ `enumerate`,
20
+ `get`,
21
+ `getOwnPropertyDescriptor`,
22
+ `getPrototypeOf`,
23
+ `has`,
24
+ `isExtensible`,
25
+ `ownKeys`,
26
+ `preventExtensions`,
27
+ `set`,
28
+ `setPrototypeOf`,
29
+ ]
30
+
31
+ // a list of paramer indexes that indicate that the a recieves a key at that parameter
32
+ // this information will be used to update the path accordingly
33
+ const keys = {
34
+ get: 1,
35
+ set: 1,
36
+ deleteProperty: 1,
37
+ has: 1,
38
+ defineProperty: 1,
39
+ getOwnPropertyDescriptor: 1,
40
+ }
41
+
42
+ export function DeepProxy(rootTarget, traps, options) {
43
+
44
+ let path = []
45
+ let _userData = {}
46
+
47
+ if (options !== undefined && typeof options.path !== `undefined`) {
48
+ path = parsePath(options.path)
49
+ }
50
+ if (options !== undefined && typeof options.userData !== `undefined`) {
51
+ _userData = options.userData
52
+ }
53
+
54
+ function createProxy(target, path, userData = {}) {
55
+
56
+ // avoid creating a new object between two traps
57
+ const context = { rootTarget, path }
58
+ Object.assign(context, _userData, userData)
59
+
60
+ const realTraps = {}
61
+
62
+ for (const trapName of trapNames) {
63
+ const keyParamIdx = keys[trapName]
64
+ , trap = traps[trapName]
65
+
66
+ if (typeof trap !== `undefined`) {
67
+
68
+ if (typeof keyParamIdx !== `undefined`) {
69
+
70
+ realTraps[trapName] = function () {
71
+
72
+ const key = arguments[keyParamIdx]
73
+
74
+ // update context for this trap
75
+ context.nest = function (nestedTarget, { userData = {} } = {}) {
76
+ if (nestedTarget === undefined)
77
+ nestedTarget = rootTarget
78
+ return createProxy(nestedTarget, push(path, key), userData)
79
+ }
80
+ return trap.apply(context, arguments)
81
+ }
82
+ } else {
83
+
84
+ realTraps[trapName] = function () {
85
+
86
+ // update context for this trap
87
+ context.nest = function (nestedTarget, { userData = {} } = {}) {
88
+ if (nestedTarget === undefined)
89
+ nestedTarget = {}
90
+ return createProxy(nestedTarget, path, userData)
91
+ }
92
+
93
+ return trap.apply(context, arguments)
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ return new Proxy(target, realTraps)
100
+ }
101
+
102
+ return createProxy(rootTarget, path)
103
+
104
+ }
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
+
@@ -1,6 +0,0 @@
1
- const cp = require(`node:child_process`)
2
- const cwd = `${__dirname}/../npm-pkg/shim/win/`
3
- cp.execSync(`${cwd}/main.exe`, {
4
- cwd,
5
- stdio: `inherit`,
6
- })