xshell 1.2.89 → 1.3.1

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/utils.common.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t } from "./i18n/instance.js";
2
- import { ident, is_key_type, noop, not_empty, select, to_snake_case } from "./prototype.common.js";
2
+ import { is_key_type, noop, not_empty, select, to_snake_case } from "./prototype.common.js";
3
3
  import { platform } from "./platform.common.js";
4
4
  export async function delay(milliseconds, options) {
5
5
  return platform.delay(milliseconds, options);
@@ -70,14 +70,14 @@ export function sort_keys(obj) {
70
70
  }
71
71
  /** 比较 1.10.02 这种版本号
72
72
  - l, r: 两个版本号字符串
73
- - loose?: 宽松模式,允许两个版本号格式(位数)不一致 */
73
+ - loose?: `false` 宽松模式,允许两个版本号格式(位数)不一致 */
74
74
  export function vercmp(l, r, loose = false) {
75
75
  const lparts = l.split('.').map(x => Number(x));
76
76
  const rparts = r.split('.').map(x => Number(x));
77
77
  if (!loose && lparts.length !== rparts.length)
78
78
  throw new Error('传入 vercmp 的两个版本号格式不一致');
79
- let minlen = Math.min(lparts.length, rparts.length);
80
- for (let i = 0; i < minlen; i++) {
79
+ const minlen = Math.min(lparts.length, rparts.length);
80
+ for (let i = 0; i < minlen; ++i) {
81
81
  const l = lparts[i];
82
82
  const r = rparts[i];
83
83
  check(!isNaN(l) && !isNaN(r), '传入 vercmp 的版本非法');
@@ -184,9 +184,9 @@ export function buffer_equals(left, right) {
184
184
  - milliseconds: 限时毫秒数
185
185
  - action?: 要等待运行的任务, async function 或 promise
186
186
  - on_timeout?: 超时后调用的函数
187
- - 如果传入了 on_timeout 参数: 调用 on_timeout,然后 timeout 函数正常返回 null
188
- - 如果没传入 on_timeout 参数: 抛出 TimeoutError
189
- - print?: 打印已超时任务的错误 */
187
+ - 若传: 调用 on_timeout,参数为 TimeoutError,然后 timeout 函数正常返回 null
188
+ - 若不传: 抛出 TimeoutError
189
+ - print?: `true` 打印已超时任务的错误 */
190
190
  export async function timeout(milliseconds, action, on_timeout, print = true) {
191
191
  const error = new TimeoutError();
192
192
  return new Promise((resolve, reject) => {
@@ -197,7 +197,7 @@ export async function timeout(milliseconds, action, on_timeout, print = true) {
197
197
  if (!done)
198
198
  if (on_timeout)
199
199
  try {
200
- await on_timeout();
200
+ await on_timeout(error);
201
201
  resolve(null);
202
202
  }
203
203
  catch (error) {
@@ -252,34 +252,42 @@ export async function poll(duration, times, action) {
252
252
  return null;
253
253
  }
254
254
  /** 模糊过滤字符串列表或对象列表,常用于根据用户输入补全或搜索过滤
255
- 如果有完全匹配的,只返回那一项的数组
255
+ 如果有完全匹配关键词的,只返回完全匹配关键词的候选项
256
256
  - query: 查询字符串,要求为全小写
257
- - list: 要过滤的列表
258
- - list_lower?: 要过滤的列表对应的全小写字符串列表形式,传入时可复用缓存,加快搜索速度 */
259
- export function fuzzyfilter(query, list, mapper = ident, list_lower, single_char_startswith = false) {
257
+ - items: TItem[], 要过滤的列表
258
+ - keywords: string[][] 每个 item 对应一个全小写字符串的关键词数组,用于实际筛选匹配 */
259
+ export function fuzzyfilter(query, items, keywords, single_char_startswith = false) {
260
260
  if (!query)
261
- return list;
262
- if (is_key_type(mapper))
263
- mapper = select(mapper);
264
- mapper ??= ident;
265
- list_lower ??= list.map(item => mapper(item).toLowerCase());
261
+ return items;
262
+ if (!items.length)
263
+ return [];
266
264
  const query_lower = query.toLowerCase();
267
- let ifullmatch;
268
- if ((ifullmatch = list_lower.indexOf(query_lower)) !== -1)
269
- return [list[ifullmatch]];
265
+ let fullmatches = [];
266
+ keywords.forEach((words, index) => {
267
+ if (words.includes(query_lower))
268
+ fullmatches.push(items[index]);
269
+ });
270
+ if (fullmatches.length)
271
+ return fullmatches;
270
272
  if (single_char_startswith && query.length === 1) {
271
273
  const c = query[0];
272
- return list.filter((_, i) => list_lower[i].startsWith(c));
274
+ return items.filter((_, i) => keywords[i].some(x => x.startsWith(c)));
273
275
  }
274
- return list.filter((_, i) => {
275
- const str_lower = list_lower[i];
276
- let j = 0;
277
- for (const c of query_lower) {
278
- j = str_lower.indexOf(c, j) + 1;
279
- if (!j) // 找不到则 j === 0
280
- return false;
276
+ return items.filter((_, i) => {
277
+ for (const str_lower of keywords[i]) {
278
+ let j = 0;
279
+ let not_found = false;
280
+ for (const c of query_lower) {
281
+ j = str_lower.indexOf(c, j) + 1;
282
+ if (!j) { // 找不到则 j === 0
283
+ not_found = true;
284
+ break;
285
+ }
286
+ }
287
+ if (!not_found)
288
+ return true;
281
289
  }
282
- return true;
290
+ return false;
283
291
  });
284
292
  }
285
293
  export function get(obj, keypath) {
@@ -326,16 +334,16 @@ export const date_format = 'YYYY.MM.DD';
326
334
  /** 默认时间格式 */
327
335
  export const time_format = 'HH:mm:ss';
328
336
  export class Timer {
329
- started = new Date().getTime();
330
- ended;
337
+ started = Date.now();
338
+ ended = 0;
331
339
  /** 停止秒表,保存读数 */
332
340
  stop() {
333
- this.ended = new Date().getTime();
341
+ this.ended = Date.now();
334
342
  }
335
343
  /** 如果秒表未停止,获取当前秒表读数;
336
344
  如果秒表已停止,获取停止时的秒表读数; */
337
345
  get() {
338
- return (this.ended || new Date().getTime()) - this.started;
346
+ return (this.ended || Date.now()) - this.started;
339
347
  }
340
348
  /** 获取时间表示字符串,如 1.2 s
341
349
  - parenthesis?: `true` 字符串前后加上括号,如 (1.2 s) */
@@ -351,8 +359,8 @@ export class Timer {
351
359
  }
352
360
  /** 重置 started */
353
361
  reset() {
354
- this.started = new Date().getTime();
355
- this.ended = null;
362
+ this.started = Date.now();
363
+ this.ended = 0;
356
364
  }
357
365
  get_and_reset() {
358
366
  const result = this.get();
@@ -388,6 +396,33 @@ export function defer(initial) {
388
396
  reject: noop
389
397
  });
390
398
  }
399
+ /** 有 settled 状态的 defer */
400
+ // eslint-disable-next-line @typescript-eslint/promise-function-async
401
+ export function defer2(initial) {
402
+ if (initial === undefined) {
403
+ let settled = false;
404
+ let { promise, resolve, reject } = Promise.withResolvers();
405
+ return Object.assign(promise, {
406
+ resolve(value) {
407
+ settled = true;
408
+ resolve(value);
409
+ },
410
+ reject(error) {
411
+ settled = true;
412
+ reject(error);
413
+ },
414
+ get settled() {
415
+ return settled;
416
+ }
417
+ });
418
+ }
419
+ else
420
+ return Object.assign(Promise.resolve(initial), {
421
+ resolve: noop,
422
+ reject: noop,
423
+ settled: true
424
+ });
425
+ }
391
426
  /** @example
392
427
  let lock = new Lock(redis)
393
428
 
@@ -522,4 +557,36 @@ export function tomorrow(date) {
522
557
  export function to_csv_field(str) {
523
558
  return /[,"\n\r]/.test(str) ? str.replaceAll('"', '""').quote('double') : str;
524
559
  }
560
+ /** 设置 error.message 同时更新 error.stack */
561
+ export function set_error_message(error, message) {
562
+ error.message = message;
563
+ error.stack = `${error.name}: ${message}\n` +
564
+ error.stack.slice_from('\n', { optional: true });
565
+ return error;
566
+ }
567
+ /** 比较两个数组中的元素完全相同,数组元素用引用比较 */
568
+ export function array_equals(a, b) {
569
+ if (!a && !b)
570
+ return true;
571
+ if (a && !b || !a && b)
572
+ return false;
573
+ return a.every((x, i) => x === b[i]);
574
+ }
575
+ export function nowstr(with_date = false) {
576
+ const date = new Date();
577
+ return with_date ? date.to_str() : date.to_time_str();
578
+ }
579
+ /** 面向对象的 timeout, callback 在后的 timeout */
580
+ export function set_timeout(delay, callback) {
581
+ let ret = {
582
+ ref: setTimeout(callback, delay),
583
+ clear() {
584
+ if (!ret.ref)
585
+ return;
586
+ clearTimeout(ret.ref);
587
+ ret.ref = null;
588
+ }
589
+ };
590
+ return ret;
591
+ }
525
592
  //# sourceMappingURL=utils.common.js.map
package/utils.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Writable, Transform, type Readable, type Duplex, type TransformCallback } from 'stream';
2
- import util from 'util';
1
+ import { Writable, Transform, type Readable, type Duplex, type TransformCallback } from 'node:stream';
2
+ import util from 'node:util';
3
3
  import './prototype.ts';
4
4
  import './platform.ts';
5
5
  export * from './utils.common.ts';
package/utils.js CHANGED
@@ -1,6 +1,6 @@
1
- import { Stream, Writable, Transform } from 'stream';
2
- import util from 'util';
3
- import ncrypto from 'crypto';
1
+ import { Stream, Writable, Transform } from 'node:stream';
2
+ import util from 'node:util';
3
+ import ncrypto from 'node:crypto';
4
4
  import "./prototype.js";
5
5
  import "./platform.js";
6
6
  import { assert, decode, defer, delay } from "./utils.common.js";
@@ -40,7 +40,13 @@ export async function schedule_everyday(hour, action) {
40
40
  // 等时间到
41
41
  await delay(target.getTime() - now.getTime());
42
42
  for (;;) {
43
- await action();
43
+ try {
44
+ await action();
45
+ }
46
+ catch (error) {
47
+ // 往上抛没什么意义,打印个日志算了
48
+ console.error(error);
49
+ }
44
50
  // 等一天
45
51
  await delay(1000 * 60 * 60 * 24);
46
52
  }
package/i18n/utils.d.ts DELETED
@@ -1 +0,0 @@
1
- export declare function try_load_dict(fp_dict: string): Promise<any>;
package/i18n/utils.js DELETED
@@ -1,11 +0,0 @@
1
- import { fread_json } from "../file.js";
2
- export async function try_load_dict(fp_dict) {
3
- try {
4
- return await fread_json(fp_dict, { print: false });
5
- }
6
- catch {
7
- // console.error('未找到或解析错误,跳过加载:' + modpath)
8
- return {};
9
- }
10
- }
11
- //# sourceMappingURL=utils.js.map