sys-shim 0.0.1-7 → 0.0.1-9

Sign up to get free protection for your applications and to get access to all the features.
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-7",
5
+ "version": "0.0.1-9",
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
  }
package/readme.md CHANGED
@@ -42,9 +42,9 @@ new Sys('ws://127.0.0.1:10005?token=tokentokentoken').then(main => {
42
42
  })
43
43
  ```
44
44
 
45
- ### 方式三:使用脚手架模板开发(开发中)
45
+ ### 方式三:使用脚手架模板开发
46
46
 
47
- - 命令行
47
+ - [命令行](https://wll8.github.io/sys-shim-doc/docs/cli/sys-shim.html)
48
48
  - 服务
49
49
  - 界面
50
50
 
@@ -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,155 @@
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
+ let icon
62
+ try {
63
+ const res = new url.URL(iconPath)
64
+ icon = `${res.protocol}//${res.host}/favicon.ico`
65
+ const tempIcon = `${os.tmpdir()}/${filenamify(icon)}`
66
+ fs.writeFileSync(tempIcon, await download(icon))
67
+ return tempIcon
68
+ } catch (error) {
69
+ console.warn(`从 ${icon} 获取图标错误:`)
70
+ console.warn(String(error))
71
+ console.warn(`将使用默认图标`)
72
+ return `${pkgDir}/script/npm-pkg/shim/win/favicon.ico`
73
+ }
74
+ }
75
+ }
76
+
77
+ function zip(cfg) {
78
+ const zipBin = `${pkgDir}/script/npm-pkg/lib/WinRAR.exe`
79
+ const icon = cfg.icon
80
+ const out = cfg.out
81
+ const input = cfg.input
82
+ const unzip = cfg.unzip
83
+
84
+ /**
85
+ * Path 解压后运行
86
+ * Silent 解压对话框 1 隐藏 2 显示
87
+ * Overwrite 解压覆盖询问 0 询问 1 覆盖 2 跳过
88
+ * Update 更新 U 解压不存在的或较新的 F 只更新目标位置已存在的
89
+ * Shortcut 创建快捷方式
90
+ * D 桌面创建
91
+ * P 在开始菜单/程序中创建
92
+ * T 在启动菜单中创建
93
+ */
94
+ const comment = (() => {
95
+ const file = `${os.tmpdir()}/comment.txt`
96
+ const text = `
97
+ Path=${path.normalize(unzip)}
98
+ Setup=main
99
+ Silent=1
100
+ Overwrite=1
101
+ Update=U
102
+ Shortcut=D, main, , "sys-shim app", "${cfg.out}", favicon.ico
103
+ `.split(`\n`).map(item => item.trim()).join(`\n`).trim()
104
+ fs.writeFileSync(file, text)
105
+ return file
106
+ })()
107
+
108
+ /**
109
+ * a 添加压缩
110
+ * -r 递归
111
+ * -ep1 从名称中排除主文件夹
112
+ * -inul 关闭错误信息
113
+ * -y 假设全部的询问回应皆为“是”
114
+ * -sfx 创建自解压文件 默认为 Default.SFX 模块,修改示例 -sfxWinCon.SFX
115
+ * -iicon 指定自解压图标
116
+ * -iimg 指定自解压图片
117
+ * -m 设置压缩等级,-m0 为存储,-m5 为最优,默认 -m3 标准
118
+ * -p 使用密码,例如 -pMyPassWord
119
+ * -hp 使用密码,并加密文件名
120
+ * -z 从文件中读取注释
121
+ * -ibck 在后台运行 WinRAR
122
+ * -idv 显示详细输出
123
+ */
124
+ const outV = `${out}-${Date.now()}`
125
+ const cmd = `${zipBin} a -r -ep1 -y -ibck -sfx -iicon"${icon}" -z"${comment}" "${outV}" ${input}/*`
126
+ cp.execSync(cmd, {stdio: `inherit`})
127
+ }
128
+
129
+ function genFile(cfg) {
130
+ const newCfg = {
131
+ input: `${os.tmpdir()}/pack.temp`,
132
+ icon: `${os.tmpdir()}/pack.temp/favicon.ico`,
133
+ }
134
+ shelljs.rm(`-fr`, newCfg.input)
135
+ shelljs.cp(`-fr`, `${pkgDir}/template/pack`, newCfg.input)
136
+ shelljs.cp(`-f`, `${pkgDir}/script/npm-pkg/shim/win/main.exe`, newCfg.input)
137
+ shelljs.cp(`-f`, `${pkgDir}/script/npm-pkg/shim/win/favicon.ico`, newCfg.input)
138
+ shelljs.cp(`-f`, cfg.icon, `${newCfg.input}/favicon.ico`)
139
+ const newStr = simpleTemplate(fs.readFileSync(`${newCfg.input}/package.json`, `utf8`), {
140
+ page: determinePathType(cfg.input) === `url` ? cfg.input : `page.html`,
141
+ })
142
+ fs.writeFileSync(`${newCfg.input}/package.json`, newStr)
143
+ return newCfg
144
+ }
145
+
146
+
147
+ export async function fn(argv) {
148
+ const cfg = await parseArgv(argv)
149
+ const {input, icon} = genFile(cfg)
150
+ cfg.input = input
151
+ cfg.icon = icon
152
+ console.log(cfg)
153
+ await zip(cfg)
154
+
155
+ }
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,8 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const cp = require(`child_process`)
4
- const cwd = `${__dirname}/../npm-pkg/shim/win/`
5
- cp.execSync(`${cwd}/main.exe`, {
6
- cwd,
7
- stdio: `inherit`,
8
- })