xshell 1.0.132 → 1.0.134

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/apps.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
1
  import type { Readable } from 'stream';
3
2
  import type OSS from 'ali-oss';
4
3
  import { type CallOptions } from './process.js';
package/builder.d.ts CHANGED
@@ -1,6 +1,58 @@
1
1
  import Webpack from 'webpack';
2
2
  import { Lock } from './utils.js';
3
+ /** target web 时的 npm 包依赖管理
4
+ 有 productions 但无 devs 时,大部分情况是相同配置,因此在 dev 模式下会用 productions
5
+ 也可以手动设置 [ ] 禁用 fallback */
6
+ export interface Dependency {
7
+ /** 项目隐含的子依赖 */
8
+ dependencies?: string[];
9
+ /** 开发环境依赖的 .js 文件 */
10
+ devs?: string[];
11
+ /** 生产环境依赖的 .js 文件 */
12
+ productions?: string[];
13
+ /** 需要直接复制到输出目录的资源 */
14
+ assets?: {
15
+ productions: string[];
16
+ devs?: string[];
17
+ };
18
+ /** .map 代码映射 */
19
+ maps?: {
20
+ productions?: string[];
21
+ devs?: string[];
22
+ };
23
+ }
24
+ type DependencyId = 'react' | 'react-dom' | 'lodash' | 'jquery' | 'xterm' | 'swiper' | 'dayjs' | 'antd' | 'antd-icons' | 'vscode-oniguruma' | 'antd-plots' | 'gridstack' | 'quill' | 'monaco' | 'echarts';
25
+ export interface HtmlBuildOptions {
26
+ title: string;
27
+ device_viewport?: boolean;
28
+ /** 也会在 copy_files 中一并被复制 */
29
+ fp_icon?: string;
30
+ dependencies?: DependencyId[];
31
+ fp_manifest?: string;
32
+ /** 额外需要加载的脚本 */
33
+ scripts?: {
34
+ /** 在 index.js 之前加载 */
35
+ before?: string[];
36
+ /** 在 index.js 之后加载 */
37
+ after?: string[];
38
+ };
39
+ /** 额外需要加载的 module 脚本, 在 index.js 之前 */
40
+ mscripts?: string[];
41
+ heads?: string[];
42
+ notice?: boolean;
43
+ }
44
+ interface AssetOption {
45
+ /** 相对 fpd_root 的路径 */
46
+ src: string;
47
+ /** 默认为 {fpd_out}/ 加上 srcs 中的路径 */
48
+ out?: string;
49
+ }
50
+ type Assets = {
51
+ productions?: (string | AssetOption)[];
52
+ devs?: (string | AssetOption)[];
53
+ };
3
54
  export interface BundlerOptions {
55
+ dependencies?: DependencyId[];
4
56
  source_map?: boolean;
5
57
  production?: boolean;
6
58
  external_dayjs?: boolean;
@@ -16,15 +68,23 @@ export interface BundlerOptions {
16
68
  cache_version?: string;
17
69
  single_chunk?: boolean;
18
70
  exclude_modules?: RegExp;
71
+ assets?: Assets;
19
72
  license?: {
20
73
  ignores?: string[];
21
74
  };
75
+ htmls?: Record<string, HtmlBuildOptions>;
22
76
  }
23
77
  export declare class Bundler {
24
78
  name: string;
25
79
  fpd_root: string;
26
- config: Webpack.Configuration;
80
+ production: boolean;
81
+ fpd_out: string;
82
+ source_map: boolean;
83
+ dependencies: DependencyId[];
27
84
  analyzer: boolean;
85
+ config: Webpack.Configuration;
86
+ htmls?: Record<string, HtmlBuildOptions>;
87
+ assets?: Assets;
28
88
  license?: {
29
89
  ignores?: string[];
30
90
  };
@@ -41,6 +101,11 @@ export declare class Bundler {
41
101
  - globals?: 全局变量定义
42
102
  - external_dayjs?: `false` 配置 dayjs 为 external 来配合 antd 使用, 减小一点体积
43
103
  - externals?: 配置外部模块
104
+ - htmls?: 配置要生成的 html, 比如 { 'index.html', { title: '文件', ... } }
105
+ - assets?: 项目中需要直接复制到输出目录的资源,有 productions 但无 devs 时 (是同一套),
106
+ 在 dev 模式下会用 productions 中的资源,如果不需要 productions 资源, devs 可以设置为 [ ],
107
+ 每一项是 string 或者 { src: '...', out: '...' },路径相对于 fpd_root 和 fpd_out
108
+ - local_loaders?: `true` true 时使用项目 node_modules/ 中的 loader; false 时使用 D:/0/ 下面的
44
109
  - commonjs2?: `false` 打包为 commonjs2 (.cjs) 的文件
45
110
  - single_chunk?: `true` 输出为单个文件,将依赖也打包到其中,不要生成多个 chunk
46
111
  - dynamic_import?: `true` 对于 await import('...') 要不要打包外部模块到输出文件中
@@ -53,8 +118,37 @@ export declare class Bundler {
53
118
  - production?: `true` webpack mode 设置为 'production'
54
119
  - sass?: 传入 sass 实例避免 webpack 重复加载 .cjs 版本
55
120
  - license?: 使用 license-webpack-plugin 构建 ThirdPartyNotice.txt */
56
- constructor(name: string, target: 'web' | 'nodejs', fpd_root: string, fpd_out: string, fpdt_cache: string, entry: Record<string, string>, { source_map, globals, external_dayjs, externals, commonjs2, single_chunk, dynamic_import, resolve_alias, assets_stats, analyzer, dts, exclude_modules, cache_version, production, sass, license, }?: BundlerOptions);
121
+ constructor(name: string, target: 'web' | 'nodejs', fpd_root: string, fpd_out: string, fpdt_cache: string, entry: Record<string, string>, { source_map, globals, external_dayjs, externals, htmls, assets, commonjs2, single_chunk, dynamic_import, resolve_alias, assets_stats, analyzer, dts, exclude_modules, cache_version, production, sass, dependencies, license, }?: BundlerOptions);
57
122
  build(print?: boolean): Promise<void>;
58
123
  close(): Promise<void>;
59
124
  build_and_close(print?: boolean): Promise<void>;
125
+ build_htmls(print?: {
126
+ info: boolean;
127
+ files: boolean;
128
+ }): Promise<void>;
129
+ resolve_dependencies(dependency_ids?: DependencyId[], resolveds?: Set<DependencyId>): Set<DependencyId>;
130
+ /** 解析依赖的文件
131
+ - dependencies: 依赖 id
132
+ - assets: false 时只包括在 script 标签加载的文件; true 时包括 assets, maps 等 */
133
+ resolve_dependency_files(_dependencies: DependencyId[], assets: boolean, { production, source_map }?: {
134
+ production?: boolean;
135
+ source_map?: boolean;
136
+ }): string[];
137
+ copy_files({ dependencies, production, assets, fpd_root, fpd_out, print }?: {
138
+ dependencies?: DependencyId[];
139
+ production?: boolean;
140
+ assets?: Assets;
141
+ fpd_root?: string;
142
+ fpd_out?: string;
143
+ print?: {
144
+ info: boolean;
145
+ files: boolean;
146
+ };
147
+ }): Promise<void>;
148
+ /** 为空时返回空数组 */
149
+ resolve_config(config: {
150
+ productions?: string[];
151
+ devs?: string[];
152
+ } | Assets | undefined, production: boolean): (string | AssetOption)[];
60
153
  }
154
+ export {};
package/builder.js CHANGED
@@ -1,11 +1,110 @@
1
1
  import { fileURLToPath } from 'url';
2
2
  import Webpack from 'webpack';
3
- import { Lock, Timer, filter_values } from './utils.js';
3
+ import { noprint } from './process.js';
4
+ import { Lock, Timer, assert, filter_values, not_empty } from './utils.js';
5
+ import { fcopy, fmkdir, fwrite } from './file.js';
6
+ import { path } from './path.js';
7
+ const monaco_files = [
8
+ 'loader.js',
9
+ 'editor/editor.main.js',
10
+ 'editor/editor.main.css',
11
+ 'editor/editor.main.nls.js',
12
+ 'editor/editor.main.nls.zh-cn.js',
13
+ 'base/common/worker/simpleWorker.nls.js',
14
+ 'base/worker/workerMain.js',
15
+ 'base/browser/ui/codicons/codicon/codicon.ttf',
16
+ ...['python', 'javascript', 'typescript', 'css', 'html', 'cpp', 'sql', 'scss', 'shell'].map(language => `basic-languages/${language}/${language}.js`),
17
+ ];
18
+ const dependencies = {
19
+ react: {
20
+ productions: ['react/umd/react.production.min.js'],
21
+ devs: ['react/umd/react.development.js'],
22
+ },
23
+ 'react-dom': {
24
+ dependencies: ['react'],
25
+ productions: ['react-dom/umd/react-dom.production.min.js'],
26
+ devs: ['react-dom/umd/react-dom.development.js'],
27
+ },
28
+ lodash: {
29
+ productions: ['lodash/lodash.min.js'],
30
+ devs: ['lodash/lodash.js'],
31
+ },
32
+ jquery: {
33
+ productions: ['jquery/dist/jquery.min.js']
34
+ },
35
+ xterm: {
36
+ productions: ['@xterm/xterm/lib/xterm.js'],
37
+ maps: {
38
+ productions: ['@xterm/xterm/lib/xterm.js.map'],
39
+ }
40
+ },
41
+ swiper: {
42
+ productions: ['swiper/swiper-bundle.min.js']
43
+ },
44
+ dayjs: {
45
+ productions: ['dayjs/dayjs.min.js'],
46
+ },
47
+ antd: {
48
+ dependencies: ['dayjs', 'react', 'react-dom'],
49
+ productions: ['antd/dist/antd.min.js'],
50
+ devs: ['antd/dist/antd.js'],
51
+ maps: {
52
+ productions: ['antd/dist/antd.min.js.map'],
53
+ devs: ['antd/dist/antd.js.map'],
54
+ }
55
+ },
56
+ 'antd-icons': {
57
+ dependencies: ['antd'],
58
+ productions: ['@ant-design/icons/dist/index.umd.min.js'],
59
+ devs: ['@ant-design/icons/dist/index.umd.js']
60
+ },
61
+ 'vscode-oniguruma': {
62
+ assets: {
63
+ productions: ['vscode-oniguruma/release/onig.wasm']
64
+ }
65
+ },
66
+ 'antd-plots': {
67
+ productions: ['@ant-design/plots/dist/plots.min.js'],
68
+ maps: {
69
+ productions: ['@ant-design/plots/dist/plots.min.js.map']
70
+ }
71
+ },
72
+ gridstack: {
73
+ productions: ['gridstack/dist/gridstack-all.js'],
74
+ maps: {
75
+ productions: ['gridstack/dist/gridstack-all.js.map']
76
+ }
77
+ },
78
+ quill: {
79
+ productions: ['react-quill/dist/react-quill.js']
80
+ },
81
+ monaco: {
82
+ assets: {
83
+ productions: monaco_files.map(fp => `monaco-editor/min/vs/${fp}`),
84
+ devs: monaco_files.map(fp => `monaco-editor/dev/vs/${fp}`)
85
+ },
86
+ maps: {
87
+ productions: monaco_files.filter(fp => fp.endsWith('.js') && !fp.startsWith('basic-languages/') && !fp.startsWith('language/'))
88
+ .map(fp => `monaco-editor/min-maps/vs/${fp}.map`),
89
+ devs: monaco_files.filter(fp => fp.endsWith('.js') && !fp.startsWith('basic-languages/') && !fp.startsWith('language/'))
90
+ .map(fp => `monaco-editor/dev/vs/${fp}.map`),
91
+ }
92
+ },
93
+ echarts: {
94
+ productions: ['echarts/dist/echarts.js']
95
+ }
96
+ };
4
97
  export class Bundler {
5
98
  name;
6
99
  fpd_root;
7
- config;
100
+ production;
101
+ fpd_out;
102
+ source_map;
103
+ dependencies = [];
8
104
  analyzer;
105
+ config;
106
+ htmls;
107
+ assets;
9
108
  license;
10
109
  lcompiler;
11
110
  /** 通过 webpack 从入口文件打包所有依赖生成单个 index.{mjs,cjs} 文件
@@ -20,6 +119,11 @@ export class Bundler {
20
119
  - globals?: 全局变量定义
21
120
  - external_dayjs?: `false` 配置 dayjs 为 external 来配合 antd 使用, 减小一点体积
22
121
  - externals?: 配置外部模块
122
+ - htmls?: 配置要生成的 html, 比如 { 'index.html', { title: '文件', ... } }
123
+ - assets?: 项目中需要直接复制到输出目录的资源,有 productions 但无 devs 时 (是同一套),
124
+ 在 dev 模式下会用 productions 中的资源,如果不需要 productions 资源, devs 可以设置为 [ ],
125
+ 每一项是 string 或者 { src: '...', out: '...' },路径相对于 fpd_root 和 fpd_out
126
+ - local_loaders?: `true` true 时使用项目 node_modules/ 中的 loader; false 时使用 D:/0/ 下面的
23
127
  - commonjs2?: `false` 打包为 commonjs2 (.cjs) 的文件
24
128
  - single_chunk?: `true` 输出为单个文件,将依赖也打包到其中,不要生成多个 chunk
25
129
  - dynamic_import?: `true` 对于 await import('...') 要不要打包外部模块到输出文件中
@@ -32,9 +136,19 @@ export class Bundler {
32
136
  - production?: `true` webpack mode 设置为 'production'
33
137
  - sass?: 传入 sass 实例避免 webpack 重复加载 .cjs 版本
34
138
  - license?: 使用 license-webpack-plugin 构建 ThirdPartyNotice.txt */
35
- constructor(name, target, fpd_root, fpd_out, fpdt_cache, entry, { source_map = true, globals, external_dayjs = false, externals, commonjs2 = false, single_chunk = true, dynamic_import = true, resolve_alias, assets_stats = true, analyzer = false, dts = false, exclude_modules, cache_version, production = true, sass, license, } = {}) {
139
+ constructor(name, target, fpd_root, fpd_out, fpdt_cache, entry, { source_map = true, globals, external_dayjs = false, externals, htmls, assets, commonjs2 = false, single_chunk = true, dynamic_import = true, resolve_alias, assets_stats = true, analyzer = false, dts = false, exclude_modules, cache_version, production = true, sass, dependencies, license, } = {}) {
36
140
  this.name = name;
37
141
  this.analyzer = analyzer;
142
+ this.production = production;
143
+ this.fpd_root = fpd_root;
144
+ this.fpd_out = fpd_out;
145
+ this.source_map = source_map;
146
+ this.htmls = htmls;
147
+ this.assets = assets;
148
+ if (dependencies) {
149
+ assert(target === 'web');
150
+ this.dependencies = dependencies;
151
+ }
38
152
  this.license = license;
39
153
  // let smp = new SpeedMeasurePlugin()
40
154
  // const config: Webpack.Configuration = smp.wrap({
@@ -330,5 +444,97 @@ export class Bundler {
330
444
  await this.build(print);
331
445
  await this.close();
332
446
  }
447
+ async build_htmls(print = { info: true, files: false }) {
448
+ await Promise.all(Object.entries(this.htmls).map(async ([fp_html, { device_viewport: device_width = false, fp_icon, fp_manifest, dependencies: _dependencies = this.dependencies, title, scripts, mscripts, notice = false, heads, }]) => {
449
+ const html = '<!doctype html>\n' +
450
+ '<html>\n' +
451
+ ' <head>\n' +
452
+ ` <title>${title}</title>\n` +
453
+ " <meta charset='utf-8' />\n" +
454
+ (heads ? heads.map(head => ` ${head}`).join_lines() : '') +
455
+ (device_width ? " <meta name='viewport' content='width=device-width, initial-scale=1.0' />\n" : '') +
456
+ (fp_icon ? ` <link rel='icon' href='${fp_icon}' />\n` : '') +
457
+ (fp_manifest ? ` <link rel='manifest' href='${fp_manifest}' />\n` : '') +
458
+ this.resolve_dependency_files(_dependencies, false, { production: this.production }).map(fp => ` <script src='./vendors/${fp}' defer></script>`).join_lines() +
459
+ (scripts?.before ? scripts.before.map(fp => ` <script src='${fp}' defer></script>`).join_lines() : '') +
460
+ (mscripts ? mscripts.map(fp => ` <script src='${fp}' type='module'></script>`).join_lines() : '') +
461
+ " <script src='./index.js' type='module'></script>\n" +
462
+ (scripts?.after ? scripts.after.map(fp => ` <script src='${fp}' defer></script>`).join_lines() : '') +
463
+ ' </head>\n' +
464
+ ' <body>\n' +
465
+ " <div class='root'>\n" +
466
+ (notice ?
467
+ ' <h2>正在加载 ··· (最多需要十秒钟)</h2>\n' +
468
+ ' <h2>如果一直停留在此页面请按 f12 或右键 > 检查,打开开发者工具查看底部控制台报错,并尝试更换浏览器或将浏览器更新到最新版本,同时检查网络连接情况</h2>\n'
469
+ : '') +
470
+ ' </div>\n' +
471
+ ' </body>\n' +
472
+ '</html>\n';
473
+ await fwrite(`${this.fpd_out}${fp_html}`, html, noprint);
474
+ if (print.files)
475
+ console.log(`已构建 ${fp_html}`);
476
+ }));
477
+ if (print.info)
478
+ console.log('htmls 已构建完成');
479
+ }
480
+ resolve_dependencies(dependency_ids = this.dependencies, resolveds = new Set()) {
481
+ dependency_ids.forEach(id => {
482
+ if (!resolveds.has(id)) {
483
+ const dependency_ids_ = dependencies[id].dependencies;
484
+ if (dependency_ids_)
485
+ this.resolve_dependencies(dependency_ids_, resolveds);
486
+ resolveds.add(id);
487
+ }
488
+ });
489
+ return resolveds;
490
+ }
491
+ /** 解析依赖的文件
492
+ - dependencies: 依赖 id
493
+ - assets: false 时只包括在 script 标签加载的文件; true 时包括 assets, maps 等 */
494
+ resolve_dependency_files(_dependencies, assets, { production = this.production, source_map = this.source_map } = {}) {
495
+ return this.resolve_dependencies(_dependencies).map(id => {
496
+ const dependency = dependencies[id];
497
+ const { assets: _assets, maps } = dependency;
498
+ return [
499
+ ...assets ? this.resolve_config(_assets, production) : [],
500
+ ...assets && source_map ? this.resolve_config(maps, production) : [],
501
+ ...this.resolve_config(dependency, production)
502
+ ];
503
+ }).flat();
504
+ }
505
+ async copy_files({ dependencies = this.dependencies, production = this.production, assets = this.assets, fpd_root = this.fpd_root, fpd_out = this.fpd_out, print = { info: true, files: false } } = {}) {
506
+ if (print.info)
507
+ console.log(`复制项目文件及依赖到输出目录`);
508
+ if (dependencies)
509
+ await fmkdir(`${fpd_out}vendors/`, { print: false });
510
+ await Promise.all([
511
+ ...this.resolve_dependency_files(dependencies, true, { production })
512
+ .map(async (fp) => fcopy(`${fpd_root}node_modules/${fp}`, `${fpd_out}vendors/${fp}`, { print: print.files })),
513
+ ...this.resolve_config(assets, production)
514
+ .map(async (asset) => {
515
+ let src, out;
516
+ if (typeof asset === 'string')
517
+ src = out = asset;
518
+ else
519
+ ({ src, out } = asset);
520
+ fcopy(`${fpd_root}${src}`, `${fpd_out}${out}`, { print: print.files });
521
+ }),
522
+ ...this.htmls ? Object.entries(this.htmls).map(async ([fp_html, { fp_icon, fp_manifest, scripts, mscripts }]) => Promise.all([
523
+ fp_icon,
524
+ fp_manifest,
525
+ ...(scripts?.before || []),
526
+ ...(scripts?.after || []),
527
+ ...(mscripts || [])
528
+ ].filter(not_empty)
529
+ .map(fp => fcopy(path.resolve(`${fpd_root}${fp_html}`.fdir, fp), path.resolve(`${fpd_out}${fp_html}`.fdir, fp), { print: print.files })))) : []
530
+ ]);
531
+ }
532
+ /** 为空时返回空数组 */
533
+ resolve_config(config, production) {
534
+ return config
535
+ ? (production ? config.productions : config.devs || config.productions) ||
536
+ []
537
+ : [];
538
+ }
333
539
  }
334
540
  //# sourceMappingURL=builder.js.map
package/file.d.ts CHANGED
@@ -1,6 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- /// <reference types="node" resolution-mode="require"/>
3
- /// <reference types="node" resolution-mode="require"/>
4
1
  import { promises as fsp, default as fs } from 'fs';
5
2
  type FileHandle = fsp.FileHandle & {
6
3
  fp: string;
@@ -42,6 +39,7 @@ export declare function fread(fp: string, { dir, encoding, print }?: {
42
39
  encoding?: Encoding;
43
40
  print?: boolean;
44
41
  }): Promise<string>;
42
+ /** 读取文件,划分为行,并去掉最后一个 \n 之后的 '' */
45
43
  export declare function fread_lines(fp: string, options?: {
46
44
  dir?: string;
47
45
  encoding?: Encoding;
package/file.js CHANGED
@@ -49,6 +49,7 @@ export async function fread(fp, { dir, encoding = 'utf-8', print = true } = {})
49
49
  .decode(await fsp.readFile(fp));
50
50
  }
51
51
  }
52
+ /** 读取文件,划分为行,并去掉最后一个 \n 之后的 '' */
52
53
  export async function fread_lines(fp, options = {}) {
53
54
  return (await fread(fp, options))
54
55
  .split_lines();
package/git.d.ts CHANGED
@@ -5,9 +5,10 @@ export declare class Git {
5
5
  constructor(cwd: string);
6
6
  static init(cwd: string, print?: boolean): Promise<Git>;
7
7
  static clone(repo: string, fpd: string): Promise<void>;
8
- call(args?: any[], { color, print }?: {
8
+ call(args?: any[], { color, print, printers }?: {
9
9
  color?: boolean;
10
10
  print?: CallOptions['print'];
11
+ printers?: CallOptions['printers'];
11
12
  }): Promise<import("./process.js").CallResult<string>>;
12
13
  get_branch(): Promise<string>;
13
14
  /** - print: `true` */
@@ -42,3 +43,11 @@ export declare class Git {
42
43
  message: string;
43
44
  }>;
44
45
  }
46
+ export interface GitVersionInfo {
47
+ version: string;
48
+ branch: string;
49
+ time: string;
50
+ hash: string;
51
+ commiter: string;
52
+ message: string;
53
+ }
package/git.js CHANGED
@@ -1,4 +1,4 @@
1
- import { call } from './process.js';
1
+ import { call, print_no_command } from './process.js';
2
2
  import { fread, fmkdir } from './file.js';
3
3
  export class Git {
4
4
  static exe = 'git';
@@ -15,7 +15,7 @@ export class Git {
15
15
  await fmkdir(fpd);
16
16
  await new this(fpd).call(['clone', repo, '.']);
17
17
  }
18
- async call(args = [], { color = true, print } = {}) {
18
+ async call(args = [], { color = true, print, printers } = {}) {
19
19
  return call(Git.exe, [
20
20
  ...color ? [] : [
21
21
  '-c', 'color.status=false',
@@ -26,6 +26,7 @@ export class Git {
26
26
  ], {
27
27
  cwd: this.cwd,
28
28
  print,
29
+ printers
29
30
  });
30
31
  }
31
32
  async get_branch() {
@@ -93,32 +94,12 @@ export class Git {
93
94
  await this._checkout(branch);
94
95
  else {
95
96
  console.log(`创建分支 ${branch}`);
96
- await this.call(['checkout', '-b', branch], { print: { command: false, code: false, stdout: true, stderr: true } });
97
+ await this.call(['checkout', '-b', branch], print_no_command);
97
98
  }
98
99
  }
99
100
  }
100
101
  async _checkout(branch) {
101
- try {
102
- const { stdout, stderr } = await this.call(['checkout', branch], { print: false });
103
- if (stdout)
104
- console.log(stdout.trimEnd());
105
- console.log(/Already on '.*'\n/.test(stderr) ?
106
- `已经在 ${branch} 分支了`
107
- : /Switched to branch '.*'/.test(stderr) ?
108
- `已切换到 ${branch} 分支`
109
- :
110
- stderr.trimEnd());
111
- }
112
- catch (error) {
113
- if (error.result) {
114
- const { stdout, stderr } = error.result;
115
- if (stdout)
116
- console.log(stdout);
117
- if (stderr)
118
- console.log(stderr);
119
- }
120
- throw error;
121
- }
102
+ await this.call(['checkout', branch], print_no_command);
122
103
  }
123
104
  async get_version_info(version) {
124
105
  const branch = await this.get_branch();
@@ -1,9 +1,9 @@
1
1
  import { I18N } from './index.js';
2
2
  export declare let i18n: I18N;
3
3
  declare const t: (text: string, options?: {
4
- [key: string]: any;
5
4
  language?: import("./index.js").Language;
6
5
  context?: string;
7
6
  count?: number;
7
+ [key: string]: any;
8
8
  }) => string, language: import("./index.js").Language;
9
9
  export { t, language };
@@ -1,3 +1,4 @@
1
+ import { PluginItem } from '@babel/core';
1
2
  export declare let unmarkeds: any[];
2
3
  export declare function Checker({ filepath }: {
3
4
  filepath: any;
@@ -27,7 +27,7 @@ declare const DEFAULT_CONFIG: {
27
27
  context: boolean;
28
28
  contextFallback: boolean;
29
29
  contextSeparator: string;
30
- plural(language: string, ns: string, key: string, options: any /** Config */): boolean;
30
+ plural(language: string, ns: string, key: string, options: any /** Config */): language is "en";
31
31
  pluralFallback: boolean;
32
32
  pluralSeparator: string;
33
33
  interpolation: {
package/net.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- /// <reference types="node" resolution-mode="require"/>
3
1
  import { type Readable } from 'stream';
4
2
  import type { FormData } from 'undici';
5
3
  import type { WebSocket, CloseEvent, ErrorEvent } from 'ws';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xshell",
3
- "version": "1.0.132",
3
+ "version": "1.0.134",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "bin": {
@@ -56,9 +56,9 @@
56
56
  "@svgr/webpack": "^8.1.0",
57
57
  "@types/sass-loader": "^8.0.8",
58
58
  "@types/ws": "^8.5.10",
59
- "@typescript-eslint/eslint-plugin": "^7.13.0",
60
- "@typescript-eslint/parser": "^7.13.0",
61
- "@typescript-eslint/utils": "^7.13.0",
59
+ "@typescript-eslint/eslint-plugin": "^7.13.1",
60
+ "@typescript-eslint/parser": "^7.13.1",
61
+ "@typescript-eslint/utils": "^7.13.1",
62
62
  "@xterm/addon-fit": "^0.10.0",
63
63
  "@xterm/addon-web-links": "^0.11.0",
64
64
  "@xterm/addon-webgl": "^0.18.0",
@@ -74,14 +74,14 @@
74
74
  "commander": "^12.1.0",
75
75
  "css-loader": "^7.1.2",
76
76
  "emoji-regex": "^10.3.0",
77
- "eslint": "^9.4.0",
77
+ "eslint": "^9.5.0",
78
78
  "eslint-plugin-import": "^2.29.1",
79
- "eslint-plugin-react": "^7.34.2",
79
+ "eslint-plugin-react": "^7.34.3",
80
80
  "gulp-sort": "^2.0.0",
81
81
  "hash-string": "^1.0.0",
82
82
  "https-proxy-agent": "^7.0.4",
83
83
  "i18next": "^23.11.5",
84
- "i18next-scanner": "^4.4.0",
84
+ "i18next-scanner": "^4.5.0",
85
85
  "koa": "^2.15.3",
86
86
  "koa-compress": "^5.1.1",
87
87
  "license-webpack-plugin": "^4.0.2",
@@ -93,7 +93,7 @@
93
93
  "react-i18next": "^14.1.2",
94
94
  "react-object-model": "^1.2.6",
95
95
  "resolve-path": "^1.4.0",
96
- "sass": "^1.77.5",
96
+ "sass": "^1.77.6",
97
97
  "sass-loader": "^14.2.1",
98
98
  "source-map-loader": "^5.0.0",
99
99
  "strip-ansi": "^7.1.0",
@@ -102,14 +102,14 @@
102
102
  "tough-cookie": "^4.1.4",
103
103
  "ts-loader": "^9.5.1",
104
104
  "tslib": "^2.6.3",
105
- "typescript": "^5.4.5",
105
+ "typescript": "^5.5.2",
106
106
  "ua-parser-js": "^2.0.0-beta.3",
107
- "undici": "^6.18.2",
107
+ "undici": "^6.19.2",
108
108
  "vinyl": "^3.0.0",
109
109
  "vinyl-fs": "^4.0.0",
110
- "webpack": "^5.92.0",
110
+ "webpack": "^5.92.1",
111
111
  "webpack-bundle-analyzer": "^4.10.2",
112
- "ws": "^8.17.0"
112
+ "ws": "^8.17.1"
113
113
  },
114
114
  "devDependencies": {
115
115
  "@babel/types": "^7.24.7",
@@ -125,7 +125,7 @@
125
125
  "@types/koa-compress": "^4.0.6",
126
126
  "@types/lodash": "^4.17.5",
127
127
  "@types/mime-types": "^2.1.4",
128
- "@types/node": "^20.14.2",
128
+ "@types/node": "^20.14.7",
129
129
  "@types/react": "^18.3.3",
130
130
  "@types/through2": "^2.0.41",
131
131
  "@types/tough-cookie": "^4.0.5",
package/path.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
1
  import { default as npath, type FormatInputPathObject } from 'path';
3
2
  export declare function to_fp(str: string): string;
4
3
  /** Normalize a string path, reducing '..' and '.' parts.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,40 @@
1
+ if (!Promise.withResolvers)
2
+ Promise.withResolvers = function PromiseWithResolvers() {
3
+ let resolve, reject;
4
+ let promise = new Promise((_resolve, _reject) => {
5
+ resolve = _resolve;
6
+ reject = _reject;
7
+ });
8
+ return { promise, resolve, reject };
9
+ };
10
+ if (!Array.prototype.toReversed)
11
+ Object.defineProperty(Array.prototype, 'toReversed', {
12
+ configurable: true,
13
+ writable: true,
14
+ enumerable: false,
15
+ value: function toReversed() {
16
+ return [...this].reverse();
17
+ }
18
+ });
19
+ if (!Array.prototype.toSpliced)
20
+ Object.defineProperty(Array.prototype, 'toSpliced', {
21
+ configurable: true,
22
+ writable: true,
23
+ enumerable: false,
24
+ value: function toSpliced(...args) {
25
+ const copy = [...this];
26
+ copy.splice(...args);
27
+ return copy;
28
+ }
29
+ });
30
+ if (!Array.prototype.at)
31
+ Object.defineProperty(Array.prototype, 'at', {
32
+ configurable: true,
33
+ writable: true,
34
+ enumerable: false,
35
+ value: function at(index) {
36
+ return index >= 0 ? this[index] : this[index + this.length];
37
+ }
38
+ });
39
+ export {};
40
+ //# sourceMappingURL=polyfill.browser.js.map
package/process.d.ts CHANGED
@@ -1,6 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- /// <reference types="node" resolution-mode="require"/>
3
- /// <reference types="node" resolution-mode="require"/>
4
1
  import { type ChildProcess } from 'child_process';
5
2
  import './prototype.js';
6
3
  import { Encoding } from './file.js';
@@ -11,6 +8,14 @@ export declare const username: string;
11
8
  export declare const noprint: {
12
9
  readonly print: false;
13
10
  };
11
+ export declare const print_no_command: {
12
+ readonly print: {
13
+ readonly command: false;
14
+ readonly code: false;
15
+ readonly stdout: true;
16
+ readonly stderr: true;
17
+ };
18
+ };
14
19
  interface StartOptions {
15
20
  /** `继承当前工作目录 process.cwd()` 子进程的工作目录 `inherit the cwd` cwd of the child process. */
16
21
  cwd?: string;
@@ -57,6 +62,10 @@ export declare function start_nodejs(js: string, args?: string[], options?: Star
57
62
  export interface CallOptions extends StartOptions {
58
63
  throw_code?: boolean;
59
64
  input?: string;
65
+ printers?: {
66
+ stdout?: (chunk: string) => void;
67
+ stderr?: (chunk: string) => void;
68
+ };
60
69
  }
61
70
  export interface CallResult<TOutput extends string | Buffer = string> {
62
71
  pid: number;
@@ -109,7 +118,9 @@ export interface CallNodeJsOptions extends CallOptions {
109
118
  - print?: `true` print 选项,支持设置细项 print option (with details)
110
119
  - stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理 when 'ignore' then ignore stdio processing
111
120
  - detached?: `false` 是否断开和 child 的关系 (ignore stdio, unref) whether to break the connection with child (ignore stdio, unref)
112
- - throw_code?: `true` code 不为 0 时是否抛出异常 whether to throw Error when code is not 0 */
121
+ - throw_code?: `true` code 不为 0 时是否抛出异常
122
+ - inspect?: nodejs debugger port
123
+ - break?: break at first line */
113
124
  export declare function call_nodejs(js: string, args?: string[], { inspect, break: _break, ...options }?: CallNodeJsOptions): Promise<CallResult<string>>;
114
125
  export interface TermOptions {
115
126
  /** `process.cwd()` */
package/process.js CHANGED
@@ -7,6 +7,7 @@ export const exe_nodejs = process.execPath.fp;
7
7
  export const platform = os.platform();
8
8
  export const username = os.userInfo().username;
9
9
  export const noprint = { print: false };
10
+ export const print_no_command = { print: { command: false, code: false, stdout: true, stderr: true } };
10
11
  /** start process
11
12
  - exe: .exe 路径或文件名 (建议使用完整路径,跳过 path 搜索,性能更高) path or filename (full path is recommanded to skip path searching for better perf)
12
13
  - args: `[]` 参数列表 arguments list
@@ -86,7 +87,7 @@ export async function start_nodejs(js, args = [], options) {
86
87
  return start(exe_nodejs, [js, ...args], options);
87
88
  }
88
89
  export async function call(exe, args = [], options = {}) {
89
- const { encoding = 'utf-8', throw_code = true, input, } = options;
90
+ const { encoding = 'utf-8', throw_code = true, input, printers } = options;
90
91
  let { stdio = 'pipe', print = true } = options;
91
92
  if (typeof print === 'boolean')
92
93
  print = {
@@ -126,7 +127,10 @@ export async function call(exe, args = [], options = {}) {
126
127
  if (stdio[1] === 'pipe')
127
128
  for await (const chunk of child.stdout) {
128
129
  if (encoding !== 'binary' && print.stdout)
129
- process.stdout.write(chunk);
130
+ if (printers?.stdout)
131
+ printers.stdout(chunk);
132
+ else
133
+ process.stdout.write(chunk);
130
134
  stdouts.push(chunk);
131
135
  }
132
136
  })(),
@@ -134,7 +138,10 @@ export async function call(exe, args = [], options = {}) {
134
138
  if (stdio[2] === 'pipe')
135
139
  for await (const chunk of child.stderr) {
136
140
  if (encoding !== 'binary' && print.stderr)
137
- process.stderr.write(chunk);
141
+ if (printers?.stderr)
142
+ printers.stderr(chunk);
143
+ else
144
+ process.stderr.write(chunk);
138
145
  stderrs.push(chunk);
139
146
  }
140
147
  })()
@@ -176,7 +183,9 @@ export async function call(exe, args = [], options = {}) {
176
183
  - print?: `true` print 选项,支持设置细项 print option (with details)
177
184
  - stdio?: `'pipe'` 设置为 'ignore' 时忽略 stdio 处理 when 'ignore' then ignore stdio processing
178
185
  - detached?: `false` 是否断开和 child 的关系 (ignore stdio, unref) whether to break the connection with child (ignore stdio, unref)
179
- - throw_code?: `true` code 不为 0 时是否抛出异常 whether to throw Error when code is not 0 */
186
+ - throw_code?: `true` code 不为 0 时是否抛出异常
187
+ - inspect?: nodejs debugger port
188
+ - break?: break at first line */
180
189
  export async function call_nodejs(js, args = [], { inspect, break: _break, ...options } = {}) {
181
190
  return call(exe_nodejs, [
182
191
  ...inspect ? [`--inspect${_break ? '-brk' : ''}=localhost:${inspect}`] : [],
@@ -53,6 +53,8 @@ declare global {
53
53
  }
54
54
  ```
55
55
 
56
+ 为空时返回 { }
57
+
56
58
  - preservations?: `''` 保留的正则表达式字符
57
59
  - flags?: `''` 正则匹配选项
58
60
  - pattern_placeholder?: `/\{.*?\}/g`
@@ -147,6 +149,9 @@ declare global {
147
149
  interface Error {
148
150
  toJSON(this: Error): string;
149
151
  }
152
+ interface Set<T> {
153
+ map<TResult>(mapfn: (value: T, index: number) => TResult): TResult[];
154
+ }
150
155
  }
151
156
  export declare const emoji_regex: RegExp;
152
157
  export declare function to_method_property_descriptors(methods: {
@@ -454,6 +454,11 @@ Object.defineProperties(Error.prototype, to_method_property_descriptors({
454
454
  .map(name => [name, this[name]]));
455
455
  }
456
456
  }));
457
+ Object.defineProperties(Set.prototype, to_method_property_descriptors({
458
+ map(mapfn) {
459
+ return Array.from(this, mapfn);
460
+ }
461
+ }));
457
462
  export function to_json(obj, replacer) {
458
463
  return JSON.stringify(obj, replacer, 4) + '\n';
459
464
  }
package/prototype.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
1
  declare global {
3
2
  var my_prototype_defined: boolean;
4
3
  interface String {
@@ -54,6 +53,8 @@ declare global {
54
53
  }
55
54
  ```
56
55
 
56
+ 为空时返回 { }
57
+
57
58
  - preservations?: `''` 保留的正则表达式字符
58
59
  - flags?: `''` 正则匹配选项
59
60
  - pattern_placeholder?: `/\{.*?\}/g` */
@@ -178,6 +179,9 @@ declare global {
178
179
  interface Error {
179
180
  toJSON(this: Error): string;
180
181
  }
182
+ interface Set<T> {
183
+ map<TResult>(mapfn: (value: T, index: number) => TResult): TResult[];
184
+ }
181
185
  }
182
186
  import chalk from 'chalk';
183
187
  export declare const emoji_regex: RegExp;
package/prototype.js CHANGED
@@ -507,6 +507,11 @@ if (!globalThis.my_prototype_defined) {
507
507
  .map(name => [name, this[name]]));
508
508
  }
509
509
  }));
510
+ Object.defineProperties(Set.prototype, to_method_property_descriptors({
511
+ map(mapfn) {
512
+ return Array.from(this, mapfn);
513
+ }
514
+ }));
510
515
  }
511
516
  export function to_json(obj, replacer) {
512
517
  return JSON.stringify(obj, replacer, 4) + '\n';
package/server.d.ts CHANGED
@@ -1,7 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- /// <reference types="node" resolution-mode="require"/>
3
- /// <reference types="node" resolution-mode="require"/>
4
- /// <reference types="node" resolution-mode="require"/>
5
1
  import { type Server as HttpServer, type IncomingHttpHeaders, type IncomingMessage } from 'http';
6
2
  import { type Http2SecureServer, type IncomingHttpHeaders as IncomingHttp2Headers } from 'http2';
7
3
  import type { Duplex } from 'stream';
@@ -5,4 +5,4 @@ export declare let toaster: {
5
5
  toast(message: string): Promise<void>;
6
6
  show(): Promise<void>;
7
7
  };
8
- export declare const toast: (message: string) => Promise<void>;
8
+ export declare const toast: (typeof toaster)["toast"];
@@ -3,6 +3,9 @@ export declare const noop: () => void;
3
3
  export declare const not_empty: (value: any) => boolean;
4
4
  export declare function assert(assertion: any, message?: string): never | void;
5
5
  export declare function log<T>(obj: T): T;
6
+ /** 数组或 iterable 去重(可按 selector 去重),重复值保留最后出现的那个
7
+ - selector?: 可以是 key (string) 或 (obj: any) => any */
8
+ export declare function unique<TObj>(iterable: TObj[] | Iterable<TObj>, selector?: string | ((obj: TObj) => any)): TObj[];
6
9
  /** 生成 0, 1, ..., n - 1 (不包括 n) 的数组,支持传入 generator 函数,通过 index 生成各个元素
7
10
  @example seq(10, i => `item-${i}`) */
8
11
  export declare function seq<T = number>(n: number, generator?: (index: number) => T): T[];
package/utils.browser.js CHANGED
@@ -12,6 +12,17 @@ export function log(obj) {
12
12
  console.log(obj);
13
13
  return obj;
14
14
  }
15
+ /** 数组或 iterable 去重(可按 selector 去重),重复值保留最后出现的那个
16
+ - selector?: 可以是 key (string) 或 (obj: any) => any */
17
+ export function unique(iterable, selector) {
18
+ if (!selector)
19
+ return [...new Set(iterable)];
20
+ let map = new Map();
21
+ const is_str_selector = typeof selector === 'string';
22
+ for (const x of iterable)
23
+ map.set(is_str_selector ? x[selector] : selector(x), x);
24
+ return [...map.values()];
25
+ }
15
26
  /** 生成 0, 1, ..., n - 1 (不包括 n) 的数组,支持传入 generator 函数,通过 index 生成各个元素
16
27
  @example seq(10, i => `item-${i}`) */
17
28
  export function seq(n, generator) {
@@ -216,12 +227,16 @@ export function concat(arrays) {
216
227
  export function delta2str(delta) {
217
228
  if (delta < 1)
218
229
  return '0 ms';
219
- // [1, 1000) ms
220
- if (delta < 1000)
230
+ // [1, 100) ms
231
+ if (delta < 100)
221
232
  return `${delta.toFixed(0)} ms`;
222
- // 1.1 s
223
- if (1000 <= delta && delta < 1000 * 60)
233
+ // [100, 1000) ms
234
+ // 0.8 s
235
+ if (delta <= 950)
224
236
  return `${(delta / 1000).toFixed(1)} s`;
237
+ // 3 s
238
+ if (delta < 1000 * 60)
239
+ return `${(delta / 1000).toFixed()} s`;
225
240
  // 1 min 12 s [1 min 0s, 60 min)
226
241
  const seconds = Math.trunc(delta / 1000);
227
242
  if (seconds < 60 * 60)
package/utils.d.ts CHANGED
@@ -1,7 +1,3 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
- /// <reference types="node" resolution-mode="require"/>
3
- /// <reference types="node" resolution-mode="require"/>
4
- /// <reference types="node" resolution-mode="require"/>
5
1
  import { Writable, Transform, type Readable, type Duplex, type TransformCallback } from 'stream';
6
2
  import util from 'util';
7
3
  import type { TimerOptions } from 'timers';
package/utils.js CHANGED
@@ -150,12 +150,16 @@ export function typed_array_to_buffer(view) {
150
150
  export function delta2str(delta) {
151
151
  if (delta < 1)
152
152
  return '0 ms';
153
- // [1, 1000) ms
154
- if (delta < 1000)
153
+ // [1, 100) ms
154
+ if (delta < 100)
155
155
  return `${delta.toFixed(0)} ms`;
156
- // 1.1 s
157
- if (1000 <= delta && delta < 1000 * 60)
156
+ // [100, 1000) ms
157
+ // 0.8 s
158
+ if (delta <= 950)
158
159
  return `${(delta / 1000).toFixed(1)} s`;
160
+ // 3 s
161
+ if (delta < 1000 * 60)
162
+ return `${(delta / 1000).toFixed()} s`;
159
163
  // 1 min 12 s [1 min 0s, 60 min)
160
164
  const seconds = Math.trunc(delta / 1000);
161
165
  if (seconds < 60 * 60)