xshell 1.3.44 → 1.3.46

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/builder.d.ts CHANGED
@@ -60,6 +60,9 @@ type Assets = {
60
60
  productions?: (string | AssetOption)[];
61
61
  devs?: (string | AssetOption)[];
62
62
  };
63
+ /** 从 tsconfig.json 中解析 paths 配置为 resolve alias
64
+ 文件不存在或无 paths alias 配置时返回 null */
65
+ export declare function get_resolve_alias(fpd_root: string): Promise<Record<string, string> | null>;
63
66
  export interface BundlerOptions {
64
67
  dependencies?: DependencyId[];
65
68
  source_map?: boolean;
@@ -153,7 +156,7 @@ export declare class Bundler {
153
156
  - expose?: `false` 入口模块所有导出的属性赋值到全局对象 globalThis 上
154
157
  - single_chunk?: `true` 输出为单个文件,将依赖也打包到其中,不要生成多个 chunk
155
158
  - dynamic_import?: `true` 对于 await import('...') 要不要打包外部模块到输出文件中
156
- - resolve_alias?: 配置 resolve alias
159
+ - resolve_alias?: 配置 resolve alias,会自动从项目 tsconfig.json 的 paths 中读取,用户配置作为覆盖
157
160
  - resolve_fallback?: 配置 resolve fallback
158
161
  - assets_stats?: `true` 打印输出的文件信息
159
162
  - analyzer?: `false` 启用 WebpackBundleAnalyzer 插件分析构建产物大小
package/builder.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { fileURLToPath } from 'node:url';
2
2
  import { not_empty } from "./prototype.js";
3
3
  import { noprint } from "./process.js";
4
- import { Lock, filter_values } from "./utils.js";
5
- import { fcopy, fmkdir, fwrite, print_info, ramdisk } from "./file.js";
4
+ import { Lock, check, filter_values } from "./utils.js";
5
+ import { fcopy, fmkdir, fwrite, print_info, ramdisk, fread_lines } from "./file.js";
6
6
  import { path } from "./path.js";
7
7
  const get_target = (production) => production ? 'production' : 'development';
8
8
  function get_react_js(production, src, map) {
@@ -112,6 +112,51 @@ function get_vendor_asset_out(asset) {
112
112
  ? `vendors/${asset}`
113
113
  : asset.out || asset.src;
114
114
  }
115
+ /** get_resolve_alias 的缓存,null 表示文件不存在或无 paths 配置 */
116
+ const resolve_alias_cache = new Map();
117
+ /** 从 tsconfig.json 中解析 paths 配置为 resolve alias
118
+ 文件不存在或无 paths alias 配置时返回 null */
119
+ export async function get_resolve_alias(fpd_root) {
120
+ const cached = resolve_alias_cache.get(fpd_root);
121
+ if (cached !== undefined)
122
+ return cached;
123
+ const fp = `${fpd_root}tsconfig.json`;
124
+ let lines;
125
+ try {
126
+ lines = await fread_lines(fp);
127
+ }
128
+ catch (error) {
129
+ if (error.code === 'ENOENT') {
130
+ resolve_alias_cache.set(fpd_root, null);
131
+ return null;
132
+ }
133
+ throw error;
134
+ }
135
+ // 移除 // 行注释
136
+ const { compilerOptions } = JSON.parse(lines
137
+ .filter(line => !line.trimStart().startsWith('//'))
138
+ .join_lines());
139
+ const paths = compilerOptions?.paths;
140
+ if (!paths) {
141
+ resolve_alias_cache.set(fpd_root, null);
142
+ return null;
143
+ }
144
+ const result = Object.fromEntries(Object.entries(paths).map(([key, values]) => {
145
+ // 检查 value 数组只有一项
146
+ check(values.length === 1, `paths 的 value 数组必须只有一项: ${key}`);
147
+ const value = values[0];
148
+ // key 和 value 都以 /* 结尾时,去掉 *
149
+ if (key.endsWith('/*') && value.endsWith('/*'))
150
+ return [
151
+ key.slice(0, -1),
152
+ fpd_root + value.slice(0, -1).strip_if_start('./')
153
+ ];
154
+ else // 是某个具体文件
155
+ return [key, fpd_root + value.strip_if_start('./')];
156
+ }));
157
+ resolve_alias_cache.set(fpd_root, result);
158
+ return result;
159
+ }
115
160
  export class Bundler {
116
161
  name;
117
162
  target;
@@ -177,7 +222,7 @@ export class Bundler {
177
222
  - expose?: `false` 入口模块所有导出的属性赋值到全局对象 globalThis 上
178
223
  - single_chunk?: `true` 输出为单个文件,将依赖也打包到其中,不要生成多个 chunk
179
224
  - dynamic_import?: `true` 对于 await import('...') 要不要打包外部模块到输出文件中
180
- - resolve_alias?: 配置 resolve alias
225
+ - resolve_alias?: 配置 resolve alias,会自动从项目 tsconfig.json 的 paths 中读取,用户配置作为覆盖
181
226
  - resolve_fallback?: 配置 resolve fallback
182
227
  - assets_stats?: `true` 打印输出的文件信息
183
228
  - analyzer?: `false` 启用 WebpackBundleAnalyzer 插件分析构建产物大小
@@ -201,6 +246,7 @@ export class Bundler {
201
246
  throw new Error('expose 和 commonjs2 不能同时启用');
202
247
  }
203
248
  async build(print = true) {
249
+ const { fpd_root } = this;
204
250
  if (!this.lcompiler)
205
251
  await (this.lcompiler = new Lock()).request(async () => {
206
252
  const { default: Webpack } = await import('webpack');
@@ -232,7 +278,7 @@ export class Bundler {
232
278
  name: this.name,
233
279
  mode: get_target(this.production),
234
280
  devtool: this.source_map ? 'source-map' : false,
235
- context: this.fpd_root,
281
+ context: fpd_root,
236
282
  entry: this.entry,
237
283
  experiments: {
238
284
  outputModule: output_module,
@@ -286,7 +332,10 @@ export class Bundler {
286
332
  extensionAlias: {
287
333
  '.js': ['.js', '.ts', '.tsx']
288
334
  },
289
- ...this.resolve_alias ? { alias: this.resolve_alias } : {},
335
+ alias: filter_values({
336
+ ...await get_resolve_alias(fpd_root),
337
+ ...this.resolve_alias
338
+ }),
290
339
  // modules: [
291
340
  // '',
292
341
  // ],
@@ -319,7 +368,7 @@ export class Bundler {
319
368
  loader: get_loader('ts-loader'),
320
369
  // https://github.com/TypeStrong/ts-loader
321
370
  options: {
322
- configFile: `${this.fpd_root}tsconfig.json`,
371
+ configFile: `${fpd_root}tsconfig.json`,
323
372
  onlyCompileBundledFiles: true,
324
373
  transpileOnly: !this.dts,
325
374
  compilerOptions: {
@@ -438,7 +487,7 @@ export class Bundler {
438
487
  },
439
488
  stats: {
440
489
  colors: true,
441
- context: this.fpd_root,
490
+ context: fpd_root,
442
491
  entrypoints: false,
443
492
  errors: true,
444
493
  errorDetails: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xshell",
3
- "version": "1.3.44",
3
+ "version": "1.3.46",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "bin": {
package/tsconfig.json CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  "compilerOptions": {
7
7
  // --- module
8
- "module": "ESNext", // none, CommonJS, amd, system, umd, es6, es2015, ESNext
8
+ "module": "ESNext",
9
9
  "moduleResolution": "Bundler",
10
10
  "allowSyntheticDefaultImports": true,
11
11
  "esModuleInterop": false,
@@ -57,7 +57,7 @@
57
57
  "noImplicitOverride": true,
58
58
  "noUnusedLocals": false,
59
59
  "noUnusedParameters": false,
60
- "skipLibCheck": true,
60
+ "skipLibCheck": true
61
61
  }
62
62
  }
63
63
 
package/xlint.js CHANGED
@@ -5,7 +5,7 @@ import TSParser from '@typescript-eslint/parser';
5
5
  import ts_plugin from '@typescript-eslint/eslint-plugin';
6
6
  import react_plugin from 'eslint-plugin-react';
7
7
  import stylistic_plugin from '@stylistic/eslint-plugin';
8
- import { check } from "./utils.js";
8
+ import { array_equals, check } from "./utils.js";
9
9
  import { path } from "./path.js";
10
10
  // 用 ast explorer 选 esprima 来看
11
11
  // 或者 https://explorer.eslint.org/
@@ -703,18 +703,6 @@ export const xlint_plugin = {
703
703
  'Program:exit'() {
704
704
  if (need_fix_source || imports.length <= 1)
705
705
  return;
706
- const { sourceCode: source } = context;
707
- const { body } = source.ast;
708
- const first = imports[0].node;
709
- const ifirst = body.indexOf(first);
710
- if (body.indexOf(imports.last.node, ifirst + 1) - ifirst !== imports.length - 1) {
711
- context.report({
712
- // @ts-ignore
713
- message: 'import 语句不连续,中间有其他语句,无法自动排序修复,需手动修复',
714
- node: first
715
- });
716
- return;
717
- }
718
706
  // 检查顺序并修复: 样式 xxx.sass < nodejs builtin < package < alias < subpath
719
707
  // 如果为样式,则放前面,其他的就按照数组来
720
708
  let imports_ = imports.toSorted((a, b) => {
@@ -724,40 +712,47 @@ export const xlint_plugin = {
724
712
  return a.ialias - b.ialias;
725
713
  return imtypes.indexOf(a.type) - imtypes.indexOf(b.type);
726
714
  });
727
- for (let i = 0; i < imports.length; i++) {
728
- let im = imports[i];
729
- let im_ = imports_[i];
730
- if (im.node === im_.node)
731
- continue;
715
+ if (array_equals(imports, imports_))
716
+ return;
717
+ const { sourceCode: source } = context;
718
+ const { body } = source.ast;
719
+ const first = imports[0].node;
720
+ const ifirst = body.indexOf(first);
721
+ if (body.indexOf(imports.last.node, ifirst + 1) - ifirst !== imports.length - 1) {
732
722
  context.report({
733
723
  // @ts-ignore
734
- message: `第 ${i} import 顺序不对`,
735
- node: im.node,
736
- fix(fixer) {
737
- let _start = Number.MAX_SAFE_INTEGER, _end = 0;
738
- let type;
739
- // 收集所有排序后的 import 文本
740
- const texts = imports_.map((im, i) => {
741
- const [start, end] = get_range_with_comments(source, im.node);
742
- if (start < _start)
743
- _start = start;
744
- if (end > _end)
745
- _end = end;
746
- let text = source.text.slice(start, end);
747
- // 分组之间空一行
748
- if (im.type !== type) {
749
- if (type)
750
- text = '\n' + text;
751
- type = im.type;
752
- }
753
- return text;
754
- });
755
- // 一次性替换所有 import
756
- return fixer.replaceTextRange([_start, _end], texts.join_lines(false));
757
- }
724
+ message: 'import 顺序不对,且 import 语句不连续,中间有其他语句,无法自动排序修复,需手动修复',
725
+ node: first
758
726
  });
759
- break;
727
+ return;
760
728
  }
729
+ context.report({
730
+ // @ts-ignore
731
+ message: 'import 顺序不对',
732
+ node: imports[0].node,
733
+ fix(fixer) {
734
+ let _start = Number.MAX_SAFE_INTEGER, _end = 0;
735
+ let type;
736
+ // 收集所有排序后的 import 文本
737
+ const texts = imports_.map((im, i) => {
738
+ const [start, end] = get_range_with_comments(source, im.node);
739
+ if (start < _start)
740
+ _start = start;
741
+ if (end > _end)
742
+ _end = end;
743
+ let text = source.text.slice(start, end);
744
+ // 分组之间空一行
745
+ if (im.type !== type) {
746
+ if (type)
747
+ text = '\n' + text;
748
+ type = im.type;
749
+ }
750
+ return text;
751
+ });
752
+ // 一次性替换所有 import
753
+ return fixer.replaceTextRange([_start, _end], texts.join_lines(false));
754
+ }
755
+ });
761
756
  }
762
757
  };
763
758
  }