@build-script/package-tools 0.0.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.
Files changed (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +136 -0
  3. package/config/rig.json +6 -0
  4. package/lib/command-file-map.generated.d.ts +23 -0
  5. package/lib/command-file-map.generated.d.ts.map +1 -0
  6. package/lib/command-file-map.generated.js +27 -0
  7. package/lib/command-file-map.generated.js.map +1 -0
  8. package/lib/commands/detect-package-change.d.ts +14 -0
  9. package/lib/commands/detect-package-change.d.ts.map +1 -0
  10. package/lib/commands/detect-package-change.js +55 -0
  11. package/lib/commands/detect-package-change.js.map +1 -0
  12. package/lib/commands/monorepo-bump-version.d.ts +22 -0
  13. package/lib/commands/monorepo-bump-version.d.ts.map +1 -0
  14. package/lib/commands/monorepo-bump-version.js +121 -0
  15. package/lib/commands/monorepo-bump-version.js.map +1 -0
  16. package/lib/commands/monorepo-cnpm-sync.d.ts +8 -0
  17. package/lib/commands/monorepo-cnpm-sync.d.ts.map +1 -0
  18. package/lib/commands/monorepo-cnpm-sync.js +16 -0
  19. package/lib/commands/monorepo-cnpm-sync.js.map +1 -0
  20. package/lib/commands/monorepo-invalid.d.ts +8 -0
  21. package/lib/commands/monorepo-invalid.d.ts.map +1 -0
  22. package/lib/commands/monorepo-invalid.js +19 -0
  23. package/lib/commands/monorepo-invalid.js.map +1 -0
  24. package/lib/commands/monorepo-list.d.ts +22 -0
  25. package/lib/commands/monorepo-list.d.ts.map +1 -0
  26. package/lib/commands/monorepo-list.js +40 -0
  27. package/lib/commands/monorepo-list.js.map +1 -0
  28. package/lib/commands/monorepo-publish.d.ts +22 -0
  29. package/lib/commands/monorepo-publish.d.ts.map +1 -0
  30. package/lib/commands/monorepo-publish.js +178 -0
  31. package/lib/commands/monorepo-publish.js.map +1 -0
  32. package/lib/commands/monorepo-tsconfig.d.ts +14 -0
  33. package/lib/commands/monorepo-tsconfig.d.ts.map +1 -0
  34. package/lib/commands/monorepo-tsconfig.js +131 -0
  35. package/lib/commands/monorepo-tsconfig.js.map +1 -0
  36. package/lib/commands/monorepo-upgrade.d.ts +8 -0
  37. package/lib/commands/monorepo-upgrade.d.ts.map +1 -0
  38. package/lib/commands/monorepo-upgrade.js +110 -0
  39. package/lib/commands/monorepo-upgrade.js.map +1 -0
  40. package/lib/commands/run-if-version-mismatch.d.ts +23 -0
  41. package/lib/commands/run-if-version-mismatch.d.ts.map +1 -0
  42. package/lib/commands/run-if-version-mismatch.js +64 -0
  43. package/lib/commands/run-if-version-mismatch.js.map +1 -0
  44. package/lib/commands/sync-my-readme.d.ts +9 -0
  45. package/lib/commands/sync-my-readme.d.ts.map +1 -0
  46. package/lib/commands/sync-my-readme.js +51 -0
  47. package/lib/commands/sync-my-readme.js.map +1 -0
  48. package/lib/commands/test.d.ts +9 -0
  49. package/lib/commands/test.d.ts.map +1 -0
  50. package/lib/commands/test.js +16 -0
  51. package/lib/commands/test.js.map +1 -0
  52. package/lib/common/cache/escape-package-path.d.ts +2 -0
  53. package/lib/common/cache/escape-package-path.d.ts.map +1 -0
  54. package/lib/common/cache/escape-package-path.js +7 -0
  55. package/lib/common/cache/escape-package-path.js.map +1 -0
  56. package/lib/common/cache/native.npm.d.ts +50 -0
  57. package/lib/common/cache/native.npm.d.ts.map +1 -0
  58. package/lib/common/cache/native.npm.js +162 -0
  59. package/lib/common/cache/native.npm.js.map +1 -0
  60. package/lib/common/functions/cli.d.ts +85 -0
  61. package/lib/common/functions/cli.d.ts.map +1 -0
  62. package/lib/common/functions/cli.js +110 -0
  63. package/lib/common/functions/cli.js.map +1 -0
  64. package/lib/common/functions/global-lifecycle.d.ts +5 -0
  65. package/lib/common/functions/global-lifecycle.d.ts.map +1 -0
  66. package/lib/common/functions/global-lifecycle.js +34 -0
  67. package/lib/common/functions/global-lifecycle.js.map +1 -0
  68. package/lib/common/git/git.d.ts +12 -0
  69. package/lib/common/git/git.d.ts.map +1 -0
  70. package/lib/common/git/git.js +65 -0
  71. package/lib/common/git/git.js.map +1 -0
  72. package/lib/common/package-manager/constant.d.ts +2 -0
  73. package/lib/common/package-manager/constant.d.ts.map +1 -0
  74. package/lib/common/package-manager/constant.js +2 -0
  75. package/lib/common/package-manager/constant.js.map +1 -0
  76. package/lib/common/package-manager/driver.abstract.d.ts +41 -0
  77. package/lib/common/package-manager/driver.abstract.d.ts.map +1 -0
  78. package/lib/common/package-manager/driver.abstract.js +138 -0
  79. package/lib/common/package-manager/driver.abstract.js.map +1 -0
  80. package/lib/common/package-manager/driver.npm.d.ts +7 -0
  81. package/lib/common/package-manager/driver.npm.d.ts.map +1 -0
  82. package/lib/common/package-manager/driver.npm.js +11 -0
  83. package/lib/common/package-manager/driver.npm.js.map +1 -0
  84. package/lib/common/package-manager/driver.pnpm.d.ts +7 -0
  85. package/lib/common/package-manager/driver.pnpm.d.ts.map +1 -0
  86. package/lib/common/package-manager/driver.pnpm.js +83 -0
  87. package/lib/common/package-manager/driver.pnpm.js.map +1 -0
  88. package/lib/common/package-manager/functions.d.ts +13 -0
  89. package/lib/common/package-manager/functions.d.ts.map +1 -0
  90. package/lib/common/package-manager/functions.js +95 -0
  91. package/lib/common/package-manager/functions.js.map +1 -0
  92. package/lib/common/package-manager/package-json.d.ts +5 -0
  93. package/lib/common/package-manager/package-json.d.ts.map +1 -0
  94. package/lib/common/package-manager/package-json.js +50 -0
  95. package/lib/common/package-manager/package-json.js.map +1 -0
  96. package/lib/common/package-manager/package-manager.d.ts +5 -0
  97. package/lib/common/package-manager/package-manager.d.ts.map +1 -0
  98. package/lib/common/package-manager/package-manager.js +27 -0
  99. package/lib/common/package-manager/package-manager.js.map +1 -0
  100. package/lib/common/package-manager/proxy.d.ts +5 -0
  101. package/lib/common/package-manager/proxy.d.ts.map +1 -0
  102. package/lib/common/package-manager/proxy.js +116 -0
  103. package/lib/common/package-manager/proxy.js.map +1 -0
  104. package/lib/common/shared-jobs/cnpm-sync.d.ts +4 -0
  105. package/lib/common/shared-jobs/cnpm-sync.d.ts.map +1 -0
  106. package/lib/common/shared-jobs/cnpm-sync.js +52 -0
  107. package/lib/common/shared-jobs/cnpm-sync.js.map +1 -0
  108. package/lib/common/shared-jobs/detect-change-job.d.ts +12 -0
  109. package/lib/common/shared-jobs/detect-change-job.d.ts.map +1 -0
  110. package/lib/common/shared-jobs/detect-change-job.js +52 -0
  111. package/lib/common/shared-jobs/detect-change-job.js.map +1 -0
  112. package/lib/common/shared-jobs/publish-package-version-job.d.ts +4 -0
  113. package/lib/common/shared-jobs/publish-package-version-job.d.ts.map +1 -0
  114. package/lib/common/shared-jobs/publish-package-version-job.js +40 -0
  115. package/lib/common/shared-jobs/publish-package-version-job.js.map +1 -0
  116. package/lib/common/taball/decompress.d.ts +2 -0
  117. package/lib/common/taball/decompress.d.ts.map +1 -0
  118. package/lib/common/taball/decompress.js +39 -0
  119. package/lib/common/taball/decompress.js.map +1 -0
  120. package/lib/common/taball/file-download.d.ts +15 -0
  121. package/lib/common/taball/file-download.d.ts.map +1 -0
  122. package/lib/common/taball/file-download.js +137 -0
  123. package/lib/common/taball/file-download.js.map +1 -0
  124. package/lib/common/temp-work-folder.d.ts +20 -0
  125. package/lib/common/temp-work-folder.d.ts.map +1 -0
  126. package/lib/common/temp-work-folder.js +68 -0
  127. package/lib/common/temp-work-folder.js.map +1 -0
  128. package/lib/common/version.generated.d.ts +12 -0
  129. package/lib/common/version.generated.d.ts.map +1 -0
  130. package/lib/common/version.generated.js +17 -0
  131. package/lib/common/version.generated.js.map +1 -0
  132. package/lib/main.d.ts +2 -0
  133. package/lib/main.d.ts.map +1 -0
  134. package/lib/main.js +115 -0
  135. package/lib/main.js.map +1 -0
  136. package/lib/tsconfig.tsbuildinfo +1 -0
  137. package/load.js +12 -0
  138. package/package.json +59 -0
  139. package/src/command-file-map.generated.ts +28 -0
  140. package/src/command-file-map.generator.ts +23 -0
  141. package/src/commands/detect-package-change.ts +57 -0
  142. package/src/commands/monorepo-bump-version.ts +152 -0
  143. package/src/commands/monorepo-cnpm-sync.ts +19 -0
  144. package/src/commands/monorepo-invalid.ts +22 -0
  145. package/src/commands/monorepo-list.ts +46 -0
  146. package/src/commands/monorepo-publish.ts +227 -0
  147. package/src/commands/monorepo-tsconfig.ts +156 -0
  148. package/src/commands/monorepo-upgrade.ts +131 -0
  149. package/src/commands/run-if-version-mismatch.ts +78 -0
  150. package/src/commands/sync-my-readme.ts +56 -0
  151. package/src/commands/test.ts +18 -0
  152. package/src/common/cache/escape-package-path.ts +6 -0
  153. package/src/common/cache/native.npm.ts +206 -0
  154. package/src/common/functions/cli.ts +145 -0
  155. package/src/common/functions/global-lifecycle.ts +40 -0
  156. package/src/common/git/git.ts +75 -0
  157. package/src/common/package-manager/constant.ts +1 -0
  158. package/src/common/package-manager/driver.abstract.ts +162 -0
  159. package/src/common/package-manager/driver.npm.ts +13 -0
  160. package/src/common/package-manager/driver.pnpm.ts +113 -0
  161. package/src/common/package-manager/functions.ts +117 -0
  162. package/src/common/package-manager/package-json.ts +56 -0
  163. package/src/common/package-manager/package-manager.ts +46 -0
  164. package/src/common/package-manager/proxy.ts +129 -0
  165. package/src/common/shared-jobs/cnpm-sync.ts +57 -0
  166. package/src/common/shared-jobs/detect-change-job.ts +76 -0
  167. package/src/common/shared-jobs/publish-package-version-job.ts +46 -0
  168. package/src/common/taball/decompress.ts +41 -0
  169. package/src/common/taball/file-download.ts +166 -0
  170. package/src/common/temp-work-folder.ts +80 -0
  171. package/src/common/version.generated.ts +18 -0
  172. package/src/common/version.generator.ts +15 -0
  173. package/src/global.d.ts +17 -0
  174. package/src/main.ts +144 -0
  175. package/src/tsconfig.json +11 -0
@@ -0,0 +1,131 @@
1
+ import type { IPackageInfo } from '@build-script/monorepo-lib';
2
+ import { loadJsonFile, writeJsonFileBack } from '@idlebox/json-edit';
3
+ import { logger } from '@idlebox/logger';
4
+ import { resolve } from 'node:path';
5
+ import { argv, CommandDefine } from '../common/functions/cli.js';
6
+ import { PackageManagerUsageKind } from '../common/package-manager/driver.abstract.js';
7
+ import { resolveNpm, splitAliasVersion, splitPackageSpecSimple } from '../common/package-manager/functions.js';
8
+ import { createPackageManager } from '../common/package-manager/package-manager.js';
9
+
10
+ export class Command extends CommandDefine {
11
+ protected override _usage = '';
12
+ protected override _description = '更新monorepo中各个项目的所有依赖版本';
13
+ protected override _help = '被更新的包必须没有或者用^作为前缀';
14
+ }
15
+
16
+ export async function main() {
17
+ const dryRun = argv.flag('--dry') > 0;
18
+ const skipUpdate = argv.flag('--skip-update') > 0;
19
+
20
+ const packageManager = await createPackageManager(PackageManagerUsageKind.Read);
21
+ const projects = await packageManager.workspace.listPackages();
22
+
23
+ logger.log('Collecting local project versions:');
24
+ const alldeps: Record<string, string> = {};
25
+ for (const project of projects) {
26
+ const myDeps = { ...project.packageJson.dependencies, ...project.packageJson.devDependencies };
27
+ Object.assign(alldeps, filterDependencyToUpgrade(myDeps));
28
+
29
+ const size = Object.keys(myDeps).length;
30
+ logger.log(` * ${project.name} - ${size} dep${size > 1 ? 's' : ''}`);
31
+ }
32
+
33
+ logger.log('Resolving npm registry:');
34
+ const map = await resolveNpm(new Map(Object.entries(alldeps)));
35
+
36
+ logger.log('Write changed files:');
37
+ let hasSomeChange = 0;
38
+ for (const project of projects) {
39
+ const packageJson = await loadJsonFile(resolve(project.absolute, 'package.json'));
40
+
41
+ let numChange = 0;
42
+ numChange += update(project, packageJson.dependencies, map);
43
+ numChange += update(project, packageJson.devDependencies, map);
44
+
45
+ if (dryRun) {
46
+ logger.log(` * ${project.name} - ${numChange} change${numChange > 1 ? 's' : ''}`);
47
+ continue;
48
+ }
49
+
50
+ const changed = await writeJsonFileBack(packageJson);
51
+
52
+ if (changed) {
53
+ logger.log(` * ${project.name} - ${numChange} change${numChange > 1 ? 's' : ''}`);
54
+ }
55
+ hasSomeChange += numChange;
56
+ }
57
+
58
+ if (dryRun) {
59
+ logger.log('dry-run: quit now.');
60
+ return;
61
+ }
62
+
63
+ if (hasSomeChange === 0) {
64
+ logger.log('OHHHH! No update!');
65
+ return;
66
+ }
67
+
68
+ logger.log('Delete temp file(s):');
69
+
70
+ if (skipUpdate) {
71
+ logger.warn(`You should run "${packageManager.binary} update" now`);
72
+ return;
73
+ }
74
+
75
+ await packageManager.install();
76
+ }
77
+
78
+ /**
79
+ * @param target 被更新的dependencies对象
80
+ * @param map 解析后的版本号表
81
+ */
82
+ function update(project: IPackageInfo, target: Record<string, string>, map: Map<string, string>) {
83
+ let changed = 0;
84
+ logger.log(`updating: ${project.name}`);
85
+ if (!target) return changed;
86
+ for (const [name, currVer] of Object.entries(target)) {
87
+ if (currVer.startsWith('workspace:')) continue;
88
+
89
+ let newVer = map.get(name);
90
+
91
+ if (currVer.startsWith('npm:')) {
92
+ // package alias
93
+ const [alias] = splitPackageSpecSimple(currVer.substring(4));
94
+ newVer = map.get(alias);
95
+ if (!newVer) {
96
+ // console.log(' - no version [%s] current [%s]', item, target[item]);
97
+ continue;
98
+ }
99
+ newVer = `npm:${alias}@${newVer}`;
100
+ }
101
+
102
+ if (currVer === newVer) continue;
103
+
104
+ if (newVer) {
105
+ console.log(' - update package [%s] from [%s] to [%s]', name, currVer, newVer);
106
+ target[name] = newVer;
107
+ } else {
108
+ // console.log(' - no version [%s] current [%s]', item, target[item]);
109
+ continue;
110
+ }
111
+
112
+ changed++;
113
+ }
114
+ return changed;
115
+ }
116
+
117
+ function filterDependencyToUpgrade(map: Record<string, string>) {
118
+ const clone: Record<string, string> = {};
119
+ for (const [name, version] of Object.entries(map)) {
120
+ if (version === '*' || version === '') {
121
+ continue;
122
+ }
123
+
124
+ const [alias, ver] = splitAliasVersion(version);
125
+
126
+ if (ver) {
127
+ clone[alias || name] = ver;
128
+ }
129
+ }
130
+ return clone;
131
+ }
@@ -0,0 +1,78 @@
1
+ import type { IArgsReaderApi } from '@idlebox/args';
2
+ import { logger } from '@idlebox/logger';
3
+ import { checkChildProcessResult } from '@idlebox/node';
4
+ import { execa } from 'execa';
5
+ import { lt } from 'semver';
6
+ import { CacheMode } from '../common/cache/native.npm.js';
7
+ import { CommandDefine, distTagInput, pArgS, pDesc } from '../common/functions/cli.js';
8
+ import { PackageManagerUsageKind } from '../common/package-manager/driver.abstract.js';
9
+ import { createPackageManager } from '../common/package-manager/package-manager.js';
10
+
11
+ process.env.COREPACK_ENABLE_STRICT = '0';
12
+
13
+ export class Command extends CommandDefine {
14
+ protected override _usage = `${pArgS('--no-cache')} ${pArgS('--flush')} \x1B[38;5;9m--\x1B[0m command to run`;
15
+ protected override _description = '如果版本号改变,则运行命令';
16
+ protected override _help = `${pDesc('如果package.json中的version与npm上的版本(latest)不一致,则运行命令')}
17
+ 注意: 命令行中的"--"是必须的
18
+ `;
19
+ protected override _arguments = {
20
+ '--no-cache': { flag: true, description: '禁用缓存' },
21
+ '--flush': { flag: true, description: '程序成功退出时自动删除npm缓存' },
22
+ '--newer': { flag: true, description: '只有在本地版本号大于远程版本号时才运行(默认只要不同就运行)' },
23
+ };
24
+ }
25
+ export async function main(argv: IArgsReaderApi) {
26
+ const noCache = argv.flag('--no-cache') > 0;
27
+ const flushCache = argv.flag('--flush') > 0;
28
+ const onlyNewer = argv.flag('--newer') > 0;
29
+
30
+ const commands = argv.unused();
31
+ if (commands.length === 0 || !process.argv.includes('--')) {
32
+ logger.error(
33
+ '参数中必须包含"--",并且后面跟随要运行的命令。\n 示例: run-if-version-mismatch --quiet -- pnpm publish',
34
+ );
35
+ return 22;
36
+ }
37
+ logger.debug('即将运行命令: %s', commands.join(' '));
38
+
39
+ const packageManager = await createPackageManager(PackageManagerUsageKind.Read);
40
+
41
+ const packagePath = await packageManager.workspace.getNearestPackage(process.cwd());
42
+ logger.log('工作目录: %s', packagePath);
43
+
44
+ const packageJson = await packageManager.loadPackageJson();
45
+ logger.log('包名: %s', packageJson.name);
46
+
47
+ const cache = await packageManager.createCacheHandler();
48
+ const pkg = await cache.fetchVersion(packageJson.name, distTagInput, noCache ? CacheMode.ForceNew : CacheMode.Normal);
49
+ const rversion = pkg?.version;
50
+ logger.log('远程版本: %s', rversion);
51
+
52
+ if (rversion) {
53
+ if (rversion === packageJson.version) {
54
+ logger.log('本地版本 (%s) === 远程版本 (%s),无需操作,直接退出。', packageJson.version, rversion);
55
+ return 0;
56
+ }
57
+ if (onlyNewer && lt(packageJson.version, rversion)) {
58
+ logger.log('本地版本 (%s) < 远程版本 (%s),无需操作,直接退出。', packageJson.version, rversion);
59
+ return 0;
60
+ }
61
+ }
62
+
63
+ logger.log('本地版本 (%s) !== 远程版本 (%s),开始执行命令!', packageJson.version, rversion);
64
+ const r = await execa(commands[0], commands.slice(1), {
65
+ cwd: packagePath,
66
+ stdout: 'inherit',
67
+ stderr: 'inherit',
68
+ });
69
+
70
+ checkChildProcessResult(r);
71
+
72
+ if (flushCache) {
73
+ logger.log('刷新npm缓存...');
74
+ await cache.deleteMetadata(packageJson.name);
75
+ }
76
+
77
+ return 0;
78
+ }
@@ -0,0 +1,56 @@
1
+ import { findUpUntilSync, writeFileIfChangeSync } from '@idlebox/node';
2
+ import { execaNode } from 'execa';
3
+ import { readFileSync } from 'node:fs';
4
+ import { CommandDefine } from '../common/functions/cli.js';
5
+
6
+ export class Command extends CommandDefine {
7
+ protected override _usage = '';
8
+ protected override _description = '内部开发命令';
9
+ protected override _help = '';
10
+ public override isHidden = true;
11
+ }
12
+
13
+ export async function main() {
14
+ const result = await execaNode(process.argv[1], ['--help'], { all: true, encoding: 'utf8', stdio: 'pipe' });
15
+
16
+ const usageText = result.all.trim().replace(/\u001b.+?m/gu, '');
17
+
18
+ const readmeFile = findUpUntilSync({ file: 'README.md', from: import.meta.dirname });
19
+ if (!readmeFile) {
20
+ throw new Error('README.md not found');
21
+ }
22
+
23
+ const content = readFileSync(readmeFile, { encoding: 'utf8' }).split('\n');
24
+
25
+ const output_lines = [];
26
+ const start = '```text id="usage"';
27
+ const end = '```';
28
+
29
+ let found_start = false;
30
+ let found_end = false;
31
+ for (const line of content) {
32
+ if (!found_start && line === start) {
33
+ output_lines.push(line);
34
+ output_lines.push(usageText);
35
+ found_start = true;
36
+ } else if (found_start && !found_end) {
37
+ if (line === end) {
38
+ output_lines.push(line);
39
+ found_end = true;
40
+ }
41
+ } else {
42
+ output_lines.push(line);
43
+ }
44
+ }
45
+
46
+ if (!found_start || !found_end) {
47
+ throw new Error(`Cannot find usage section in ${readmeFile}`);
48
+ }
49
+
50
+ const ch = writeFileIfChangeSync(readmeFile, output_lines.join('\n'));
51
+ if (ch) {
52
+ console.log(`Updated ${readmeFile}`);
53
+ } else {
54
+ console.log(`No changes made to ${readmeFile}`);
55
+ }
56
+ }
@@ -0,0 +1,18 @@
1
+ import { CommandDefine } from '../common/functions/cli.js';
2
+ import { PackageManagerUsageKind } from '../common/package-manager/driver.abstract.js';
3
+ import { createPackageManager } from '../common/package-manager/package-manager.js';
4
+
5
+ export class Command extends CommandDefine {
6
+ protected override _usage = '测试参数';
7
+ protected override _description = '测试命令';
8
+ protected override _help = '没有帮助信息';
9
+ public override isHidden = true;
10
+ }
11
+
12
+ export async function main() {
13
+ const pm = await createPackageManager(PackageManagerUsageKind.Read);
14
+ const cache = await pm.createCacheHandler();
15
+
16
+ const r = await cache.downloadTarball('react-dom', 'latest');
17
+ console.log(r);
18
+ }
@@ -0,0 +1,6 @@
1
+ export function escapePackageNameToFilename(name: string) {
2
+ if (name.startsWith('@')) {
3
+ return name.slice(1).replace('/', '__');
4
+ }
5
+ return name;
6
+ }
@@ -0,0 +1,206 @@
1
+ import { sleep, type IPackageJson } from '@idlebox/common';
2
+ import { logger } from '@idlebox/logger';
3
+ import { get as cacheGet, rm as cacheRm } from 'cacache';
4
+ import { rm } from 'node:fs/promises';
5
+ import { createRequire } from 'node:module';
6
+ import { resolve } from 'node:path';
7
+ import { json as npmFetchJson } from 'npm-registry-fetch';
8
+ import { DEFAULT_NPM_REGISTRY } from '../package-manager/constant.js';
9
+ import type { IPackageManager } from '../package-manager/package-manager.js';
10
+ import { getProxyValue } from '../package-manager/proxy.js';
11
+ import { downloadFileCached } from '../taball/file-download.js';
12
+ import { self_package_name, self_package_repository, self_package_version } from '../version.generated.js';
13
+ import { escapePackageNameToFilename } from './escape-package-path.js';
14
+
15
+ export interface IRegistryMetadata {
16
+ _attachments: any;
17
+ _id: string;
18
+ _rev: string;
19
+ author: IPackageJson['author'];
20
+ description: string;
21
+ 'dist-tags': Record<string, string>;
22
+ license: string;
23
+ maintainers: IPackageJson['author'][];
24
+ name: string;
25
+ readme: string;
26
+ time: {
27
+ created: string;
28
+ modified: string;
29
+ [version: string]: string;
30
+ };
31
+ versions: Record<string, IPackageJson>;
32
+ bugs: IPackageJson['bugs'];
33
+ contributors: IPackageJson['contributors'];
34
+ homepage: string;
35
+ keywords: string[];
36
+ repository: IPackageJson['repository'];
37
+ _source_registry_name: string;
38
+ }
39
+
40
+ export class NpmCacheHandler {
41
+ constructor(
42
+ private readonly pm: IPackageManager,
43
+ private readonly registry: string,
44
+ public readonly path: string,
45
+ ) {}
46
+
47
+ deleteMetadata(name: string) {
48
+ return deleteNpmCache(this.path, name, this.registry);
49
+ }
50
+
51
+ async fetchMetadata(name: string, cacheMode = CacheMode.Normal) {
52
+ const registry = await this.pm.getNpmRegistry();
53
+ return fetchNpmWithCache(this.path, name, registry, { mode: cacheMode });
54
+ }
55
+
56
+ async fetchVersion(name: string, distTag = 'latest', cacheMode = CacheMode.Normal) {
57
+ const json = await this.fetchMetadata(name, cacheMode);
58
+ if (!json) {
59
+ return;
60
+ }
61
+ const version = getVersion(json, distTag);
62
+ if (!version) {
63
+ logger.warn(` ! 找不到版本信息(${name}@${distTag})`);
64
+ return;
65
+ }
66
+ return version;
67
+ }
68
+
69
+ private getTarballFile(name: string, tag: string) {
70
+ const es = escapePackageNameToFilename(name);
71
+ return resolve(this.path, `../package-tools/${es}-${tag}.tgz`);
72
+ }
73
+
74
+ public async downloadTarball(name: string, distTag: string) {
75
+ const r = await this.fetchVersion(name, distTag);
76
+ if (!r) {
77
+ throw new Error(`无此版本: ${name} = ${distTag}`);
78
+ }
79
+ return await downloadFileCached(r.dist.tarball, this.getTarballFile(name, distTag));
80
+ }
81
+
82
+ public deleteTarball(name: string, distTag: string) {
83
+ return rm(this.getTarballFile(name, distTag), { force: true });
84
+ }
85
+ }
86
+
87
+ function getVersion(json: any, distTag: string): IPackageJson | undefined {
88
+ if (!json.versions) {
89
+ return undefined;
90
+ }
91
+ const v = json?.['dist-tags']?.[distTag];
92
+ if (!v) {
93
+ return json.versions[distTag];
94
+ }
95
+ return json.versions[v];
96
+ }
97
+
98
+ // type NpmLog = Exclude<FetchOptions['log'], undefined>;
99
+
100
+ export enum CacheMode {
101
+ Normal = 'normal',
102
+ ForceNew = 'force-renew',
103
+ Offline = 'offline',
104
+ }
105
+
106
+ interface IMyOpts {
107
+ mode?: CacheMode;
108
+ maxRetry?: number;
109
+ }
110
+ const defOpt: Required<IMyOpts> = {
111
+ mode: CacheMode.Normal,
112
+ maxRetry: 3,
113
+ };
114
+
115
+ export async function fetchNpmWithCache(path: string, name: string, registry: string, _options?: IMyOpts) {
116
+ logger.debug(` * npm-registry-fetch: ${registry} :: ${name}`);
117
+
118
+ const options: Required<IMyOpts> = Object.assign({}, defOpt, _options);
119
+
120
+ let try_cnt = 0;
121
+ let retry = options.maxRetry;
122
+ let retry_timeout = 500;
123
+ let json: IRegistryMetadata | undefined;
124
+
125
+ while (true) {
126
+ try_cnt++;
127
+ retry--;
128
+ try {
129
+ const proxy = getProxyValue(registry);
130
+ json = (await npmFetchJson(name, {
131
+ cache: path,
132
+ registry: registry,
133
+ fetchRetries: 0,
134
+ noProxy: false,
135
+ preferOnline: options.mode === CacheMode.ForceNew,
136
+ offline: options.mode === CacheMode.Offline,
137
+ preferOffline: options.mode === CacheMode.Normal,
138
+ proxy: proxy,
139
+ timeout: 5000,
140
+ userAgent: `${self_package_name}(${self_package_version}) GongT(${self_package_repository})`,
141
+ })) as any;
142
+ break;
143
+ } catch (e: any) {
144
+ if (!e || !e.message) {
145
+ console.dir(e);
146
+ throw new Error('npm fetch throw unexpected thing');
147
+ }
148
+ if (e.statusCode === 404) {
149
+ logger.verbose('registry say 404, return empty.');
150
+ return undefined;
151
+ }
152
+ if (e.code === 'ECONNRESET') retry++;
153
+
154
+ if (retry <= 0) throw e;
155
+
156
+ retry_timeout = (retry_timeout / 1000) * 1.2;
157
+ if (retry_timeout > 15000) retry_timeout = 15000;
158
+ logger.error(`failed fetch npm registry: ${e.message}, retry in ${(retry_timeout / 1000).toFixed(1)} seconds...`);
159
+ await sleep(retry_timeout);
160
+ }
161
+ }
162
+
163
+ if (!json) {
164
+ logger.error('[!!] NPM cache structure changed!');
165
+ process.exit(1);
166
+ }
167
+
168
+ return json;
169
+ }
170
+
171
+ async function deleteNpmCache(path: string, name: string, registry?: string) {
172
+ const require = createRequire(import.meta.url);
173
+ const cacheKey = require('make-fetch-happen/lib/cache/key.js');
174
+ const registries = new Set([DEFAULT_NPM_REGISTRY, 'https://registry.npmmirror.com/']);
175
+ if (registry) {
176
+ if (!registry.endsWith('/')) {
177
+ registry += '/';
178
+ }
179
+ registries.add(registry);
180
+ }
181
+
182
+ let deleted = false;
183
+ logger.debug(` - delete cache: ${name}`);
184
+ let i = registries.size;
185
+ for (const registry of registries.values()) {
186
+ logger.debug(` │ ${registry}${name}`);
187
+ const cid = cacheKey({ url: `${registry}${name}` });
188
+
189
+ i--;
190
+ const tc = i > 0 ? '├' : '└';
191
+
192
+ const info = await cacheGet.info(path, cid);
193
+ // console.log(info);
194
+ await cacheRm.content(path, cid);
195
+ // @types/cacache 最后一个参数丢失
196
+ await (cacheRm.entry as any)(path, cid, { removeFully: true });
197
+ if (info) {
198
+ logger.debug(` ${tc} deleted! ${cid}`);
199
+ deleted = true;
200
+ } else {
201
+ logger.debug(` ${tc} not exists: ${cid}`);
202
+ }
203
+ }
204
+
205
+ return deleted;
206
+ }
@@ -0,0 +1,145 @@
1
+ import { createArgsReader } from '@idlebox/args';
2
+
3
+ export const CSI = '\x1b[';
4
+
5
+ export class DieError extends Error {
6
+ constructor(msg: string) {
7
+ super(msg);
8
+ this.stack = this.message;
9
+ }
10
+ }
11
+ function die(msg: string) {
12
+ throw new DieError(msg);
13
+ }
14
+
15
+ export const argv = createArgsReader(process.argv.slice(2));
16
+
17
+ type ArgDefine = {
18
+ flag: boolean;
19
+ description: string;
20
+ };
21
+ const common_args = {
22
+ quiet: { flag: true, description: '减少输出' },
23
+ registry: { flag: false, description: 'npm服务器,默认从.npmrc读取(必须有schema://)' },
24
+ 'dist-tag': { flag: false, description: '需要从服务器读取时使用的tag,默认为"latest"' },
25
+ package: { flag: false, description: '实际操作前,更改当前目录(此文件夹应包含package.json)' },
26
+ json: { flag: true, description: '输出json格式(部分命令支持)' },
27
+ help: { flag: true, description: '显示帮助信息' },
28
+ };
29
+ type CommonArgs = keyof typeof common_args;
30
+ const all_common_args = Object.keys(common_args) as ReadonlyArray<CommonArgs>;
31
+
32
+ export abstract class CommandDefine {
33
+ /**
34
+ * 紧接在命令后面的参数
35
+ */
36
+ protected abstract readonly _usage: string;
37
+ /**
38
+ * usage后面的简短说明
39
+ */
40
+ protected abstract readonly _description: string;
41
+ /**
42
+ * 多行详细帮助信息
43
+ */
44
+ protected abstract readonly _help: string;
45
+ /**
46
+ * 独特命令行参数
47
+ */
48
+ protected readonly _arguments?: Record<string, ArgDefine>;
49
+ /**
50
+ * 通用命令行参数
51
+ */
52
+ protected readonly _commonArgs?: readonly CommonArgs[];
53
+
54
+ public readonly isHidden: boolean = false;
55
+
56
+ get help() {
57
+ let r = this._help;
58
+ if (this._arguments) {
59
+ const opts = formatOptions(this._arguments);
60
+ if (r) r += '\n';
61
+ r += opts;
62
+ }
63
+ return r;
64
+ }
65
+
66
+ get usage() {
67
+ return this._usage;
68
+ }
69
+ get description() {
70
+ return this._description;
71
+ }
72
+ get commonArgs() {
73
+ return this._commonArgs;
74
+ }
75
+ }
76
+
77
+ export const isVerbose = argv.flag('--verbose') > 0;
78
+ export const isQuiet = argv.flag(['--silent', '-s', '--quiet']) > 0;
79
+ export const isJsonOutput = argv.flag('--json') > 0;
80
+ export const isHelp = argv.flag(['--help', '-h']) > 0;
81
+ export const distTagInput = argv.single('--dist-tag') || 'latest';
82
+ export const registryInput = argv.single('--registry') || 'detect';
83
+ export const isDebugMode = argv.flag('--debug') > 0;
84
+
85
+ if (isVerbose && isQuiet) {
86
+ die('不能同时使用 --verbose 和 --quiet');
87
+ }
88
+
89
+ export function pArgS(s: string) {
90
+ return `\x1B[3;38;5;14m${s}\x1B[0m`;
91
+ }
92
+ export function pDesc(s: string) {
93
+ return `\x1B[3;2m${s}\x1B[0m`;
94
+ }
95
+ export function pCmd(s: string) {
96
+ return `\x1B[38;5;10m${s}\x1B[0m`;
97
+ }
98
+
99
+ export const mainCliController = {
100
+ command: undefined as CommandDefine | undefined,
101
+ setCommand(cmd: CommandDefine) {
102
+ this.command = cmd;
103
+ },
104
+ };
105
+
106
+ export function printCommonOptions() {
107
+ process.stderr.write('\x1B[2m通用参数\x1B[0m:\n');
108
+
109
+ const whitelist = mainCliController.command?.commonArgs ?? all_common_args;
110
+ const clone_common: Record<string, ArgDefine> = {};
111
+ for (const key of whitelist) {
112
+ clone_common[key] = common_args[key];
113
+ }
114
+
115
+ process.stderr.write(formatOptions(clone_common, { color: 3, indent: ' ' }));
116
+ }
117
+
118
+ interface IFormatOptions {
119
+ color?: number;
120
+ indent?: string;
121
+ }
122
+ export function formatOptions(args: Record<string, ArgDefine>, { color, indent }: IFormatOptions = {}) {
123
+ let r = '';
124
+ if (!color) color = 14;
125
+ if (!indent) indent = '';
126
+
127
+ for (const [name, { description, flag }] of Object.entries(args)) {
128
+ const names = name.split(',').map((n) => {
129
+ n = n.trim();
130
+ if (!n.startsWith('-')) {
131
+ if (n.length > 1) {
132
+ n = `--${n}`;
133
+ } else {
134
+ n = `-${n}`;
135
+ }
136
+ }
137
+ return n;
138
+ });
139
+
140
+ const flag_suffix = flag ? '' : ' <value>';
141
+
142
+ r += `${indent}\x1B[38;5;${color}m${names.join(', ')}${flag_suffix}\x1B[0m: ${description}\n`;
143
+ }
144
+ return r;
145
+ }
@@ -0,0 +1,40 @@
1
+ import { ensureDisposeGlobal } from '@idlebox/common';
2
+
3
+ export let isApplicationShuttingDown = false;
4
+
5
+ export function shutdown(code: number) {
6
+ if (isApplicationShuttingDown) {
7
+ process.exitCode = code || process.exitCode;
8
+ return;
9
+ }
10
+ isApplicationShuttingDown = true;
11
+ ensureDisposeGlobal().finally(() => {
12
+ process.exit(code || process.exitCode);
13
+ });
14
+ }
15
+
16
+ export let shutdownExtraErase = 0;
17
+
18
+ export function registerShutdownHandlers() {
19
+ process.on('unhandledRejection', (reason, promise) => {
20
+ console.error('got unhandledRejection: %s', reason);
21
+ console.error(promise);
22
+ shutdown(1);
23
+ });
24
+
25
+ process.on('SIGINT', () => {
26
+ console.error('\ngot SIGINT');
27
+ shutdownExtraErase += 2;
28
+ shutdown(0);
29
+ });
30
+
31
+ process.on('SIGTERM', () => {
32
+ console.error('\ngot SIGTERM');
33
+ shutdownExtraErase += 2;
34
+ shutdown(0);
35
+ });
36
+
37
+ process.on('beforeExit', (code) => {
38
+ shutdown(code);
39
+ });
40
+ }