react-native-update-cli 2.8.5 → 2.9.0

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 (106) hide show
  1. package/lib/api.d.ts +18 -0
  2. package/lib/app.d.ts +38 -0
  3. package/lib/app.js +5 -4
  4. package/lib/bundle-pack.d.ts +1 -0
  5. package/lib/bundle-pack.js +104 -0
  6. package/lib/bundle-runner.d.ts +20 -0
  7. package/lib/bundle-runner.js +404 -0
  8. package/lib/bundle.d.ts +6 -0
  9. package/lib/bundle.js +73 -471
  10. package/lib/diff.d.ts +13 -0
  11. package/lib/diff.js +144 -123
  12. package/lib/exports.d.ts +12 -0
  13. package/lib/index.d.ts +5 -0
  14. package/lib/index.js +5 -13
  15. package/lib/install.d.ts +4 -0
  16. package/lib/locales/en.d.ts +137 -0
  17. package/lib/locales/zh.d.ts +136 -0
  18. package/lib/module-manager.d.ts +20 -0
  19. package/lib/module-manager.js +3 -9
  20. package/lib/modules/app-module.d.ts +2 -0
  21. package/lib/modules/app-module.js +84 -44
  22. package/lib/modules/bundle-module.d.ts +2 -0
  23. package/lib/modules/bundle-module.js +7 -8
  24. package/lib/modules/index.d.ts +6 -0
  25. package/lib/modules/package-module.d.ts +2 -0
  26. package/lib/modules/user-module.d.ts +2 -0
  27. package/lib/modules/user-module.js +55 -44
  28. package/lib/modules/version-module.d.ts +2 -0
  29. package/lib/package.d.ts +58 -0
  30. package/lib/package.js +103 -139
  31. package/lib/provider.d.ts +26 -0
  32. package/lib/provider.js +115 -217
  33. package/lib/types.d.ts +120 -0
  34. package/lib/user.d.ts +8 -0
  35. package/lib/utils/add-gitignore.d.ts +1 -0
  36. package/lib/utils/app-info-parser/aab.d.ts +22 -0
  37. package/lib/utils/app-info-parser/aab.js +0 -4
  38. package/lib/utils/app-info-parser/apk.d.ts +14 -0
  39. package/lib/utils/app-info-parser/apk.js +6 -4
  40. package/lib/utils/app-info-parser/app.d.ts +4 -0
  41. package/lib/utils/app-info-parser/app.js +3 -0
  42. package/lib/utils/app-info-parser/index.d.ts +16 -0
  43. package/lib/utils/app-info-parser/index.js +2 -0
  44. package/lib/utils/app-info-parser/ipa.d.ts +14 -0
  45. package/lib/utils/app-info-parser/ipa.js +1 -1
  46. package/lib/utils/app-info-parser/resource-finder.d.ts +49 -0
  47. package/lib/utils/app-info-parser/utils.d.ts +31 -0
  48. package/lib/utils/app-info-parser/utils.js +1 -0
  49. package/lib/utils/app-info-parser/xml-parser/binary.d.ts +56 -0
  50. package/lib/utils/app-info-parser/xml-parser/manifest.d.ts +10 -0
  51. package/lib/utils/app-info-parser/zip.d.ts +18 -0
  52. package/lib/utils/app-info-parser/zip.js +7 -9
  53. package/lib/utils/check-lockfile.d.ts +1 -0
  54. package/lib/utils/check-plugin.d.ts +7 -0
  55. package/lib/utils/command-result.d.ts +3 -0
  56. package/lib/utils/command-result.js +35 -0
  57. package/lib/utils/constants.d.ts +9 -0
  58. package/lib/utils/dep-versions.d.ts +1 -0
  59. package/lib/utils/git.d.ts +8 -0
  60. package/lib/utils/http-helper.d.ts +4 -0
  61. package/lib/utils/i18n.d.ts +12 -0
  62. package/lib/utils/index.d.ts +22 -0
  63. package/lib/utils/index.js +52 -22
  64. package/lib/utils/latest-version/cli.d.ts +1 -0
  65. package/lib/utils/latest-version/cli.js +24 -60
  66. package/lib/utils/latest-version/index.d.ts +146 -0
  67. package/lib/utils/latest-version/index.js +22 -22
  68. package/lib/utils/options.d.ts +4 -0
  69. package/lib/utils/options.js +63 -0
  70. package/lib/utils/plugin-config.d.ts +9 -0
  71. package/lib/utils/zip-entries.d.ts +3 -0
  72. package/lib/versions.d.ts +43 -0
  73. package/lib/workflow-runner.d.ts +2 -0
  74. package/lib/workflow-runner.js +25 -0
  75. package/package.json +20 -5
  76. package/src/api.ts +1 -1
  77. package/src/app.ts +20 -11
  78. package/src/bundle-pack.ts +51 -0
  79. package/src/bundle-runner.ts +463 -0
  80. package/src/bundle.ts +184 -571
  81. package/src/diff.ts +208 -174
  82. package/src/index.ts +15 -17
  83. package/src/module-manager.ts +15 -15
  84. package/src/modules/app-module.ts +120 -48
  85. package/src/modules/bundle-module.ts +21 -11
  86. package/src/modules/package-module.ts +0 -1
  87. package/src/modules/user-module.ts +117 -58
  88. package/src/package.ts +158 -138
  89. package/src/provider.ts +164 -240
  90. package/src/types.ts +13 -8
  91. package/src/utils/app-info-parser/aab.ts +0 -7
  92. package/src/utils/app-info-parser/apk.ts +9 -6
  93. package/src/utils/app-info-parser/app.ts +5 -1
  94. package/src/utils/app-info-parser/index.ts +11 -6
  95. package/src/utils/app-info-parser/ipa.ts +1 -1
  96. package/src/utils/app-info-parser/utils.ts +3 -0
  97. package/src/utils/app-info-parser/xml-parser/manifest.ts +3 -1
  98. package/src/utils/app-info-parser/zip.ts +12 -14
  99. package/src/utils/command-result.ts +24 -0
  100. package/src/utils/index.ts +138 -39
  101. package/src/utils/latest-version/cli.ts +22 -20
  102. package/src/utils/latest-version/index.ts +20 -20
  103. package/src/utils/options.ts +56 -0
  104. package/src/utils/zip-entries.ts +1 -1
  105. package/src/workflow-runner.ts +24 -0
  106. package/index.js +0 -1
@@ -15,7 +15,9 @@ export class ManifestParser {
15
15
 
16
16
  private collapseAttributes(element: any) {
17
17
  const collapsed: Record<string, any> = Object.create(null);
18
- for (const attr of Array.from(element.attributes)) {
18
+ for (const attr of Array.from(
19
+ element.attributes as Array<{ name: string; typedValue: { value: any } }>,
20
+ )) {
19
21
  collapsed[attr.name] = attr.typedValue.value;
20
22
  }
21
23
  return collapsed;
@@ -1,19 +1,16 @@
1
- import { decodeNullUnicode } from './utils';
2
1
  import path from 'path';
2
+ import { decodeNullUnicode } from './utils';
3
3
 
4
4
  const Unzip = require('isomorphic-unzip');
5
5
 
6
6
  import { enumZipEntries, readEntry } from '../zip-entries';
7
7
 
8
8
  export class Zip {
9
- file: string;
9
+ file: string | File;
10
10
  unzip: any;
11
11
 
12
- constructor(file: string) {
13
- if (typeof file !== 'string') {
14
- throw new Error('Param error: [file] must be file path in Node.');
15
- }
16
- this.file = path.resolve(file);
12
+ constructor(file: string | File) {
13
+ this.file = typeof file === 'string' ? path.resolve(file) : file;
17
14
  this.unzip = new Unzip(this.file);
18
15
  }
19
16
 
@@ -56,16 +53,17 @@ export class Zip {
56
53
  });
57
54
  }
58
55
 
59
- async getEntryFromHarmonyApp(regex: RegExp) {
56
+ async getEntryFromHarmonyApp(
57
+ regex: RegExp,
58
+ ): Promise<Buffer | Blob | undefined> {
60
59
  try {
61
60
  let originSource: Buffer | Blob | undefined;
62
- await enumZipEntries(this.file, (entry: any, zipFile: any) => {
61
+ if (typeof this.file !== 'string') {
62
+ throw new Error('Param error: [file] must be file path in Node.');
63
+ }
64
+ await enumZipEntries(this.file, async (entry, zipFile) => {
63
65
  if (regex.test(entry.fileName)) {
64
- return readEntry(entry, zipFile).then(
65
- (value: Buffer | Blob | undefined) => {
66
- originSource = value;
67
- },
68
- );
66
+ originSource = await readEntry(entry, zipFile);
69
67
  }
70
68
  });
71
69
  return originSource;
@@ -0,0 +1,24 @@
1
+ import type { CommandResult } from '../types';
2
+
3
+ export function toErrorMessage(error: unknown, fallback: string): string {
4
+ return error instanceof Error ? error.message : fallback;
5
+ }
6
+
7
+ export async function runAsCommandResult<T>(
8
+ task: () => Promise<T>,
9
+ fallbackError: string,
10
+ mapSuccess?: (result: T) => unknown,
11
+ ): Promise<CommandResult> {
12
+ try {
13
+ const result = await task();
14
+ return {
15
+ success: true,
16
+ data: mapSuccess ? mapSuccess(result) : result,
17
+ };
18
+ } catch (error) {
19
+ return {
20
+ success: false,
21
+ error: toErrorMessage(error, fallbackError),
22
+ };
23
+ }
24
+ }
@@ -3,6 +3,8 @@ import path from 'path';
3
3
  import chalk from 'chalk';
4
4
  import { satisfies } from 'compare-versions';
5
5
  import fs from 'fs-extra';
6
+ import type { Root as ProtobufRoot } from 'protobufjs';
7
+ import { type Entry as YauzlEntry, open as openZipFile } from 'yauzl';
6
8
  import pkg from '../../package.json';
7
9
  import latestVersion from '../utils/latest-version';
8
10
  import AppInfoParser from './app-info-parser';
@@ -13,6 +15,77 @@ import { IS_CRESC, tempDir } from './constants';
13
15
  import { depVersions } from './dep-versions';
14
16
  import { t } from './i18n';
15
17
 
18
+ type ApkMetaEntry = {
19
+ name?: string;
20
+ value?: string | number | Array<string | number>;
21
+ };
22
+
23
+ type ParsedApkInfo = {
24
+ versionName: string;
25
+ application: {
26
+ metaData?: ApkMetaEntry[];
27
+ };
28
+ };
29
+
30
+ type ParsedIpaInfo = {
31
+ CFBundleShortVersionString: string;
32
+ };
33
+
34
+ type ParsedAppMetaInfo = {
35
+ versionName?: string;
36
+ pushy_build_time?: number | string;
37
+ };
38
+
39
+ type AabXmlAttr = {
40
+ name: string;
41
+ value: string;
42
+ compiledItem?: {
43
+ ref?: {
44
+ id?: number;
45
+ };
46
+ prim?: {
47
+ intDecimalValue?: number;
48
+ };
49
+ };
50
+ };
51
+
52
+ type AabXmlElement = {
53
+ name: string;
54
+ attribute: AabXmlAttr[];
55
+ child: Array<{ element?: AabXmlElement }>;
56
+ };
57
+
58
+ type AabXmlNodeObject = {
59
+ element: AabXmlElement;
60
+ };
61
+
62
+ type AabResourceEntry = {
63
+ entryId: number;
64
+ configValue?: Array<{
65
+ value?: {
66
+ item?: {
67
+ str?: {
68
+ value?: string;
69
+ };
70
+ };
71
+ };
72
+ }>;
73
+ };
74
+
75
+ type AabResourceType = {
76
+ typeId: number;
77
+ entry: AabResourceEntry[];
78
+ };
79
+
80
+ type AabResourcePackage = {
81
+ packageId: number;
82
+ type: AabResourceType[];
83
+ };
84
+
85
+ type AabResourceTableObject = {
86
+ package: AabResourcePackage[];
87
+ };
88
+
16
89
  export async function question(query: string, password?: boolean) {
17
90
  if (NO_INTERACTIVE) {
18
91
  return '';
@@ -24,20 +97,29 @@ export async function question(query: string, password?: boolean) {
24
97
  });
25
98
  }
26
99
 
27
- export function translateOptions(options: Record<string, string>) {
28
- const ret: Record<string, string> = {};
100
+ export function translateOptions<T extends Record<string, unknown>>(
101
+ options: T,
102
+ ): T & Record<string, unknown> {
103
+ const ret: Record<string, unknown> = {};
29
104
  for (const key in options) {
30
- const v = options[key];
31
- if (typeof v === 'string') {
32
- ret[key] = v.replace(
33
- /\$\{(\w+)\}/g,
34
- (v, n) => options[n] || process.env[n] || v,
35
- );
105
+ const value = options[key];
106
+ if (typeof value === 'string') {
107
+ ret[key] = value.replace(/\$\{(\w+)\}/g, (placeholder, name) => {
108
+ const replacement = options[name] ?? process.env[name];
109
+ if (
110
+ typeof replacement === 'string' ||
111
+ typeof replacement === 'number' ||
112
+ typeof replacement === 'boolean'
113
+ ) {
114
+ return String(replacement);
115
+ }
116
+ return placeholder;
117
+ });
36
118
  } else {
37
- ret[key] = v;
119
+ ret[key] = value;
38
120
  }
39
121
  }
40
- return ret;
122
+ return ret as T & Record<string, unknown>;
41
123
  }
42
124
 
43
125
  export async function getApkInfo(fn: string) {
@@ -60,12 +142,18 @@ export async function getApkInfo(fn: string) {
60
142
  if (updateJsonFile) {
61
143
  appCredential = JSON.parse(updateJsonFile.toString()).android;
62
144
  }
63
- const { versionName, application } = await appInfoParser.parse();
145
+ const { versionName, application } =
146
+ await appInfoParser.parse<ParsedApkInfo>();
64
147
  let buildTime = 0;
65
148
  if (Array.isArray(application.metaData)) {
66
149
  for (const meta of application.metaData) {
67
150
  if (meta.name === 'pushy_build_time') {
68
- buildTime = meta.value[0];
151
+ if (Array.isArray(meta.value)) {
152
+ const firstValue = meta.value[0];
153
+ buildTime = Number(firstValue);
154
+ } else if (meta.value !== undefined) {
155
+ buildTime = Number(meta.value);
156
+ }
69
157
  }
70
158
  }
71
159
  }
@@ -96,14 +184,14 @@ export async function getAppInfo(fn: string) {
96
184
  }
97
185
  const metaJsonFile =
98
186
  await appInfoParser.parser.getEntryFromHarmonyApp(/rawfile\/meta.json/);
99
- let metaData: Record<string, any> = {};
187
+ let metaData: ParsedAppMetaInfo = {};
100
188
  if (metaJsonFile) {
101
- metaData = JSON.parse(metaJsonFile.toString());
189
+ metaData = JSON.parse(metaJsonFile.toString()) as ParsedAppMetaInfo;
102
190
  }
103
191
  const { versionName, pushy_build_time } = metaData;
104
192
  let buildTime = 0;
105
193
  if (pushy_build_time) {
106
- buildTime = pushy_build_time;
194
+ buildTime = Number(pushy_build_time);
107
195
  }
108
196
  if (buildTime == 0) {
109
197
  throw new Error(t('buildTimeNotFound'));
@@ -132,7 +220,7 @@ export async function getIpaInfo(fn: string) {
132
220
  appCredential = JSON.parse(updateJsonFile.toString()).ios;
133
221
  }
134
222
  const { CFBundleShortVersionString: versionName } =
135
- await appInfoParser.parse();
223
+ await appInfoParser.parse<ParsedIpaInfo>();
136
224
  let buildTimeTxtBuffer = await appInfoParser.parser.getEntry(
137
225
  /payload\/.+?\.app\/pushy_build_time.txt/,
138
226
  );
@@ -150,7 +238,7 @@ export async function getIpaInfo(fn: string) {
150
238
  }
151
239
 
152
240
  export async function getAabInfo(fn: string) {
153
- const protobuf = require('protobufjs');
241
+ const protobuf = require('protobufjs') as typeof import('protobufjs');
154
242
  const root = await protobuf.load(
155
243
  path.join(__dirname, '../../proto/Resources.proto'),
156
244
  );
@@ -165,7 +253,7 @@ export async function getAabInfo(fn: string) {
165
253
  bytes: String,
166
254
  defaults: true,
167
255
  arrays: true,
168
- });
256
+ }) as AabXmlNodeObject;
169
257
 
170
258
  const manifestElement = object.element;
171
259
  if (manifestElement.name !== 'manifest') {
@@ -184,18 +272,23 @@ export async function getAabInfo(fn: string) {
184
272
 
185
273
  // Find application node
186
274
  const applicationNode = manifestElement.child.find(
187
- (c: any) => c.element && c.element.name === 'application',
275
+ (child) => child.element?.name === 'application',
188
276
  );
189
- if (applicationNode) {
190
- const metaDataNodes = applicationNode.element.child.filter(
191
- (c: any) => c.element && c.element.name === 'meta-data',
277
+ const applicationElement = applicationNode?.element;
278
+ if (applicationElement) {
279
+ const metaDataNodes = applicationElement.child.filter(
280
+ (child) => child.element?.name === 'meta-data',
192
281
  );
193
282
  for (const meta of metaDataNodes) {
194
283
  let name = '';
195
284
  let value = '';
196
285
  let resourceId = 0;
197
286
 
198
- for (const attr of meta.element.attribute) {
287
+ const metaElement = meta.element;
288
+ if (!metaElement) {
289
+ continue;
290
+ }
291
+ for (const attr of metaElement.attribute) {
199
292
  if (attr.name === 'name') {
200
293
  name = attr.value;
201
294
  }
@@ -229,19 +322,24 @@ export async function getAabInfo(fn: string) {
229
322
  }
230
323
 
231
324
  async function readZipEntry(fn: string, entryName: string): Promise<Buffer> {
232
- const yauzl = require('yauzl');
233
325
  return new Promise((resolve, reject) => {
234
- yauzl.open(fn, { lazyEntries: true }, (err: any, zipfile: any) => {
235
- if (err) return reject(err);
326
+ openZipFile(fn, { lazyEntries: true }, (err, zipfile) => {
327
+ if (err || !zipfile) {
328
+ reject(err ?? new Error('Failed to open zip file'));
329
+ return;
330
+ }
236
331
  let found = false;
237
332
  zipfile.readEntry();
238
- zipfile.on('entry', (entry: any) => {
333
+ zipfile.on('entry', (entry: YauzlEntry) => {
239
334
  if (entry.fileName === entryName) {
240
335
  found = true;
241
- zipfile.openReadStream(entry, (err: any, readStream: any) => {
242
- if (err) return reject(err);
243
- const chunks: any[] = [];
244
- readStream.on('data', (chunk: any) => chunks.push(chunk));
336
+ zipfile.openReadStream(entry, (streamError, readStream) => {
337
+ if (streamError || !readStream) {
338
+ reject(streamError ?? new Error('Failed to read zip entry'));
339
+ return;
340
+ }
341
+ const chunks: Buffer[] = [];
342
+ readStream.on('data', (chunk: Buffer) => chunks.push(chunk));
245
343
  readStream.on('end', () => resolve(Buffer.concat(chunks)));
246
344
  readStream.on('error', reject);
247
345
  });
@@ -260,7 +358,7 @@ async function readZipEntry(fn: string, entryName: string): Promise<Buffer> {
260
358
  async function resolveResource(
261
359
  fn: string,
262
360
  resourceId: number,
263
- root: any,
361
+ root: ProtobufRoot,
264
362
  ): Promise<string | null> {
265
363
  const pkgId = (resourceId >> 24) & 0xff;
266
364
  const typeId = (resourceId >> 16) & 0xff;
@@ -276,25 +374,26 @@ async function resolveResource(
276
374
  bytes: String,
277
375
  defaults: true,
278
376
  arrays: true,
279
- });
377
+ }) as AabResourceTableObject;
280
378
 
281
379
  // Find package
282
- const pkg = object.package.find((p: any) => p.packageId === pkgId);
380
+ const pkg = object.package.find((pkgItem) => pkgItem.packageId === pkgId);
283
381
  if (!pkg) return null;
284
382
 
285
383
  // Find type
286
- const type = pkg.type.find((t: any) => t.typeId === typeId);
384
+ const type = pkg.type.find((typeItem) => typeItem.typeId === typeId);
287
385
  if (!type) return null;
288
386
 
289
387
  // Find entry
290
- const entry = type.entry.find((e: any) => e.entryId === entryId);
388
+ const entry = type.entry.find((entryItem) => entryItem.entryId === entryId);
291
389
  if (!entry) return null;
292
390
 
293
391
  // Get value from configValue
294
392
  if (entry.configValue && entry.configValue.length > 0) {
295
- const val = entry.configValue[0].value;
296
- if (val.item?.str) {
297
- return val.item.str.value;
393
+ const val = entry.configValue[0]?.value;
394
+ const stringValue = val?.item?.str?.value;
395
+ if (typeof stringValue === 'string') {
396
+ return stringValue;
298
397
  }
299
398
  }
300
399
  } catch (e) {
@@ -122,13 +122,13 @@ const drawBox = (
122
122
  );
123
123
 
124
124
  console.log(color(`┌${'─'.repeat(maxLineWidth + horizontalPadding * 2)}┐`));
125
- lines.forEach((row) => {
125
+ for (const row of lines) {
126
126
  const padding = ' '.repeat(horizontalPadding);
127
127
  const fullRow = `${row}${' '.repeat(maxLineWidth - strip(row).length)}`;
128
128
  console.log(
129
129
  `${color('│')}${padding}${reset(fullRow)}${padding}${color('│')}`,
130
130
  );
131
- });
131
+ }
132
132
  console.log(color(`└${'─'.repeat(maxLineWidth + horizontalPadding * 2)}┘`));
133
133
  };
134
134
 
@@ -191,15 +191,15 @@ const getTableColumns = (rows: TableRow[]): TableColumn[] => {
191
191
  items: [],
192
192
  },
193
193
  ];
194
- rows.forEach((row) => {
195
- columns.forEach((column) => {
194
+ for (const row of rows) {
195
+ for (const column of columns) {
196
196
  column.maxLength = Math.max(
197
197
  column.label.length,
198
198
  column.maxLength,
199
199
  row[column.attrName].length || 0,
200
200
  );
201
- });
202
- });
201
+ }
202
+ }
203
203
  return columns;
204
204
  };
205
205
 
@@ -217,13 +217,16 @@ const getTableRows = (updates: LatestVersionPackage[]): TableRow[] => {
217
217
  const getGroup = (a?: string, b?: string): TableRowGroup => {
218
218
  if (b && semverMajor(b) === 0) {
219
219
  return 'majorVersionZero';
220
- } else if (a && b) {
220
+ }
221
+ if (a && b) {
221
222
  const releaseType = semverDiff(a, b) ?? '';
222
223
  if (['major', 'premajor', 'prerelease'].includes(releaseType)) {
223
224
  return 'major';
224
- } else if (['minor', 'preminor'].includes(releaseType)) {
225
+ }
226
+ if (['minor', 'preminor'].includes(releaseType)) {
225
227
  return 'minor';
226
- } else if (['patch', 'prepatch'].includes(releaseType)) {
228
+ }
229
+ if (['patch', 'prepatch'].includes(releaseType)) {
227
230
  return 'patch';
228
231
  }
229
232
  }
@@ -236,7 +239,7 @@ const getTableRows = (updates: LatestVersionPackage[]): TableRow[] => {
236
239
  wanted?: string,
237
240
  ) =>
238
241
  all.push({
239
- name: ' ' + name,
242
+ name: ` ${name}`,
240
243
  location,
241
244
  installed: installed ?? 'unknown',
242
245
  latest: latest ?? 'unknown',
@@ -368,21 +371,20 @@ const checkVersions = async (
368
371
  skipMissing: boolean,
369
372
  options: LatestVersionOptions = { useCache: true },
370
373
  ): Promise<void> => {
371
- const ora = (await import('ora')).default;
372
- const spinner = ora({ text: cyan('Checking versions...') });
373
- spinner.start();
374
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
375
- // @ts-ignore
376
- let latestVersionPackages: LatestVersionPackage[] = await latestVersion(
377
- packages,
378
- options,
379
- );
374
+ console.log(cyan('Checking versions...'));
375
+ let latestVersionPackages: LatestVersionPackage[];
376
+ if (typeof packages === 'string') {
377
+ latestVersionPackages = [await latestVersion(packages, options)];
378
+ } else if (Array.isArray(packages)) {
379
+ latestVersionPackages = await latestVersion(packages, options);
380
+ } else {
381
+ latestVersionPackages = await latestVersion(packages, options);
382
+ }
380
383
  if (skipMissing) {
381
384
  latestVersionPackages = latestVersionPackages.filter(
382
385
  (pkg) => pkg.local ?? pkg.globalNpm ?? pkg.globalYarn,
383
386
  );
384
387
  }
385
- spinner.stop();
386
388
  displayTable(latestVersionPackages);
387
389
  };
388
390
 
@@ -363,7 +363,8 @@ const getInstalledVersion = (
363
363
  if (location === 'globalNpm') {
364
364
  return require(join(npm.packages, pkgName, 'package.json'))
365
365
  ?.version as string;
366
- } else if (location === 'globalYarn') {
366
+ }
367
+ if (location === 'globalYarn') {
367
368
  // Make sure package is globally installed by Yarn
368
369
  const yarnGlobalPkg = require(
369
370
  pathResolve(yarn.packages, '..', 'package.json'),
@@ -373,25 +374,24 @@ const getInstalledVersion = (
373
374
  }
374
375
  return require(join(yarn.packages, pkgName, 'package.json'))
375
376
  ?.version as string;
376
- } else {
377
- /**
378
- * Compute the local paths manually as require.resolve() and require.resolve.paths()
379
- * cannot be trusted anymore.
380
- * @see https://github.com/nodejs/node/issues/33460
381
- * @see https://github.com/nodejs/loaders/issues/26
382
- */
383
- const { root } = parse(process.cwd());
384
- let path = process.cwd();
385
- const localPaths = [join(path, 'node_modules')];
386
- while (path !== root) {
387
- path = dirname(path);
388
- localPaths.push(join(path, 'node_modules'));
389
- }
390
- for (const localPath of localPaths) {
391
- const pkgPath = join(localPath, pkgName, 'package.json');
392
- if (existsSync(pkgPath)) {
393
- return require(pkgPath)?.version as string;
394
- }
377
+ }
378
+ /**
379
+ * Compute the local paths manually as require.resolve() and require.resolve.paths()
380
+ * cannot be trusted anymore.
381
+ * @see https://github.com/nodejs/node/issues/33460
382
+ * @see https://github.com/nodejs/loaders/issues/26
383
+ */
384
+ const { root } = parse(process.cwd());
385
+ let path = process.cwd();
386
+ const localPaths = [join(path, 'node_modules')];
387
+ while (path !== root) {
388
+ path = dirname(path);
389
+ localPaths.push(join(path, 'node_modules'));
390
+ }
391
+ for (const localPath of localPaths) {
392
+ const pkgPath = join(localPath, pkgName, 'package.json');
393
+ if (existsSync(pkgPath)) {
394
+ return require(pkgPath)?.version as string;
395
395
  }
396
396
  }
397
397
  return undefined;
@@ -0,0 +1,56 @@
1
+ export function getBooleanOption(
2
+ options: Record<string, unknown>,
3
+ key: string,
4
+ fallback = false,
5
+ ): boolean {
6
+ const value = options[key];
7
+ if (typeof value === 'boolean') {
8
+ return value;
9
+ }
10
+ if (typeof value === 'string') {
11
+ return value.toLowerCase() === 'true';
12
+ }
13
+ if (typeof value === 'number') {
14
+ return value !== 0;
15
+ }
16
+ return fallback;
17
+ }
18
+
19
+ export function getStringOption(
20
+ options: Record<string, unknown>,
21
+ key: string,
22
+ fallback = '',
23
+ ): string {
24
+ const value = options[key];
25
+ if (typeof value === 'string') {
26
+ return value;
27
+ }
28
+ if (typeof value === 'number' || typeof value === 'boolean') {
29
+ return String(value);
30
+ }
31
+ return fallback;
32
+ }
33
+
34
+ export function getOptionalStringOption(
35
+ options: Record<string, unknown>,
36
+ key: string,
37
+ ): string | undefined {
38
+ const value = options[key];
39
+ if (typeof value === 'string') {
40
+ return value || undefined;
41
+ }
42
+ if (typeof value === 'number' || typeof value === 'boolean') {
43
+ return String(value);
44
+ }
45
+ return undefined;
46
+ }
47
+
48
+ export function toObjectState<T extends Record<string, unknown>>(
49
+ value: unknown,
50
+ fallback: T,
51
+ ): T {
52
+ if (value && typeof value === 'object') {
53
+ return value as T;
54
+ }
55
+ return fallback;
56
+ }
@@ -34,7 +34,7 @@ export async function enumZipEntries(
34
34
  entry: Entry,
35
35
  zipFile: YauzlZipFile,
36
36
  nestedPath?: string,
37
- ) => Promise<any>,
37
+ ) => Promise<any> | undefined,
38
38
  nestedPath = '',
39
39
  ) {
40
40
  return new Promise((resolve, reject) => {
@@ -0,0 +1,24 @@
1
+ import type { CommandContext, CustomWorkflow } from './types';
2
+
3
+ export async function runWorkflow(
4
+ workflowName: string,
5
+ workflow: CustomWorkflow,
6
+ context: CommandContext,
7
+ ): Promise<unknown> {
8
+ if (workflow.validate && !workflow.validate(context)) {
9
+ throw new Error(`Workflow '${workflowName}' validation failed`);
10
+ }
11
+
12
+ let previousResult: unknown;
13
+ for (const step of workflow.steps) {
14
+ if (step.condition && !step.condition(context)) {
15
+ console.log(`Skipping step '${step.name}' due to condition`);
16
+ continue;
17
+ }
18
+
19
+ console.log(`Executing step '${step.name}'`);
20
+ previousResult = await step.execute(context, previousResult);
21
+ }
22
+
23
+ return previousResult;
24
+ }
package/index.js DELETED
@@ -1 +0,0 @@
1
- module.exports = require('./lib');