react-native-update-cli 2.7.2 → 2.8.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.
- package/cli.json +0 -1
- package/lib/bundle.js +22 -7
- package/package.json +26 -24
- package/src/bundle.ts +19 -9
- package/lib/esm/api..mjs +0 -183
- package/lib/esm/app..mjs +0 -130
- package/lib/esm/bundle..mjs +0 -823
- package/lib/esm/exports..mjs +0 -11
- package/lib/esm/index..mjs +0 -122
- package/lib/esm/install..mjs +0 -18
- package/lib/esm/locales/en..mjs +0 -131
- package/lib/esm/locales/zh..mjs +0 -130
- package/lib/esm/module-manager..mjs +0 -109
- package/lib/esm/modules/app-module..mjs +0 -213
- package/lib/esm/modules/bundle-module..mjs +0 -178
- package/lib/esm/modules/index..mjs +0 -17
- package/lib/esm/modules/package-module..mjs +0 -6
- package/lib/esm/modules/user-module..mjs +0 -351
- package/lib/esm/modules/version-module..mjs +0 -6
- package/lib/esm/package..mjs +0 -316
- package/lib/esm/provider..mjs +0 -293
- package/lib/esm/types..mjs +0 -1
- package/lib/esm/user..mjs +0 -36
- package/lib/esm/utils/add-gitignore..mjs +0 -32
- package/lib/esm/utils/app-info-parser/aab..mjs +0 -215
- package/lib/esm/utils/app-info-parser/apk..mjs +0 -75
- package/lib/esm/utils/app-info-parser/app..mjs +0 -3
- package/lib/esm/utils/app-info-parser/index..mjs +0 -44
- package/lib/esm/utils/app-info-parser/ipa..mjs +0 -73
- package/lib/esm/utils/app-info-parser/resource-finder..mjs +0 -401
- package/lib/esm/utils/app-info-parser/utils..mjs +0 -121
- package/lib/esm/utils/app-info-parser/xml-parser/binary..mjs +0 -569
- package/lib/esm/utils/app-info-parser/xml-parser/manifest..mjs +0 -200
- package/lib/esm/utils/app-info-parser/zip..mjs +0 -65
- package/lib/esm/utils/check-lockfile..mjs +0 -78
- package/lib/esm/utils/check-plugin..mjs +0 -25
- package/lib/esm/utils/constants..mjs +0 -19
- package/lib/esm/utils/dep-versions..mjs +0 -33
- package/lib/esm/utils/git..mjs +0 -43
- package/lib/esm/utils/http-helper..mjs +0 -70
- package/lib/esm/utils/i18n..mjs +0 -23
- package/lib/esm/utils/index..mjs +0 -316
- package/lib/esm/utils/latest-version/cli..mjs +0 -294
- package/lib/esm/utils/latest-version/index..mjs +0 -238
- package/lib/esm/utils/plugin-config..mjs +0 -23
- package/lib/esm/versions..mjs +0 -290
package/lib/esm/utils/index..mjs
DELETED
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
import os from "os";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import chalk from "chalk";
|
|
4
|
-
import { satisfies } from "compare-versions";
|
|
5
|
-
import fs from "fs-extra";
|
|
6
|
-
import pkg from "../../package.json";
|
|
7
|
-
import latestVersion from "./latest-version";
|
|
8
|
-
import AppInfoParser from "./app-info-parser";
|
|
9
|
-
import { checkPlugins } from "./check-plugin";
|
|
10
|
-
import { read } from "read";
|
|
11
|
-
import { IS_CRESC, tempDir } from "./constants";
|
|
12
|
-
import { depVersions } from "./dep-versions";
|
|
13
|
-
import { t } from "./i18n";
|
|
14
|
-
export async function question(query, password) {
|
|
15
|
-
if (NO_INTERACTIVE) {
|
|
16
|
-
return '';
|
|
17
|
-
}
|
|
18
|
-
return read({
|
|
19
|
-
prompt: query,
|
|
20
|
-
silent: password,
|
|
21
|
-
replace: password ? '*' : undefined
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
export function translateOptions(options) {
|
|
25
|
-
const ret = {};
|
|
26
|
-
for(const key in options){
|
|
27
|
-
const v = options[key];
|
|
28
|
-
if (typeof v === 'string') {
|
|
29
|
-
ret[key] = v.replace(/\$\{(\w+)\}/g, (v, n)=>options[n] || process.env[n] || v);
|
|
30
|
-
} else {
|
|
31
|
-
ret[key] = v;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return ret;
|
|
35
|
-
}
|
|
36
|
-
export async function getApkInfo(fn) {
|
|
37
|
-
const appInfoParser = new AppInfoParser(fn);
|
|
38
|
-
const bundleFile = await appInfoParser.parser.getEntry(/assets\/index.android.bundle/);
|
|
39
|
-
if (!bundleFile) {
|
|
40
|
-
throw new Error(t('bundleNotFound', {
|
|
41
|
-
packageType: 'apk',
|
|
42
|
-
entryFile: 'index.android.bundle'
|
|
43
|
-
}));
|
|
44
|
-
}
|
|
45
|
-
const updateJsonFile = await appInfoParser.parser.getEntry(/res\/raw\/update.json/);
|
|
46
|
-
let appCredential = {};
|
|
47
|
-
if (updateJsonFile) {
|
|
48
|
-
appCredential = JSON.parse(updateJsonFile.toString()).android;
|
|
49
|
-
}
|
|
50
|
-
const { versionName, application } = await appInfoParser.parse();
|
|
51
|
-
let buildTime = 0;
|
|
52
|
-
if (Array.isArray(application.metaData)) {
|
|
53
|
-
for (const meta of application.metaData){
|
|
54
|
-
if (meta.name === 'pushy_build_time') {
|
|
55
|
-
buildTime = meta.value[0];
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
if (buildTime == 0) {
|
|
60
|
-
throw new Error(t('buildTimeNotFound'));
|
|
61
|
-
}
|
|
62
|
-
return {
|
|
63
|
-
versionName,
|
|
64
|
-
buildTime,
|
|
65
|
-
...appCredential
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
export async function getAppInfo(fn) {
|
|
69
|
-
const appInfoParser = new AppInfoParser(fn);
|
|
70
|
-
const bundleFile = await appInfoParser.parser.getEntryFromHarmonyApp(/rawfile\/bundle.harmony.js/);
|
|
71
|
-
if (!bundleFile) {
|
|
72
|
-
throw new Error(t('bundleNotFound', {
|
|
73
|
-
packageType: 'app',
|
|
74
|
-
entryFile: 'bundle.harmony.js'
|
|
75
|
-
}));
|
|
76
|
-
}
|
|
77
|
-
const updateJsonFile = await appInfoParser.parser.getEntryFromHarmonyApp(/rawfile\/update.json/);
|
|
78
|
-
let appCredential = {};
|
|
79
|
-
if (updateJsonFile) {
|
|
80
|
-
appCredential = JSON.parse(updateJsonFile.toString()).harmony;
|
|
81
|
-
}
|
|
82
|
-
const metaJsonFile = await appInfoParser.parser.getEntryFromHarmonyApp(/rawfile\/meta.json/);
|
|
83
|
-
let metaData = {};
|
|
84
|
-
if (metaJsonFile) {
|
|
85
|
-
metaData = JSON.parse(metaJsonFile.toString());
|
|
86
|
-
}
|
|
87
|
-
const { versionName, pushy_build_time } = metaData;
|
|
88
|
-
let buildTime = 0;
|
|
89
|
-
if (pushy_build_time) {
|
|
90
|
-
buildTime = pushy_build_time;
|
|
91
|
-
}
|
|
92
|
-
if (buildTime == 0) {
|
|
93
|
-
throw new Error(t('buildTimeNotFound'));
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
versionName,
|
|
97
|
-
buildTime,
|
|
98
|
-
...appCredential
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
export async function getIpaInfo(fn) {
|
|
102
|
-
const appInfoParser = new AppInfoParser(fn);
|
|
103
|
-
const bundleFile = await appInfoParser.parser.getEntry(/payload\/.+?\.app\/main.jsbundle/);
|
|
104
|
-
if (!bundleFile) {
|
|
105
|
-
throw new Error(t('bundleNotFound', {
|
|
106
|
-
packageType: 'ipa',
|
|
107
|
-
entryFile: 'main.jsbundle'
|
|
108
|
-
}));
|
|
109
|
-
}
|
|
110
|
-
const updateJsonFile = await appInfoParser.parser.getEntry(/payload\/.+?\.app\/assets\/update.json/);
|
|
111
|
-
let appCredential = {};
|
|
112
|
-
if (updateJsonFile) {
|
|
113
|
-
appCredential = JSON.parse(updateJsonFile.toString()).ios;
|
|
114
|
-
}
|
|
115
|
-
const { CFBundleShortVersionString: versionName } = await appInfoParser.parse();
|
|
116
|
-
let buildTimeTxtBuffer = await appInfoParser.parser.getEntry(/payload\/.+?\.app\/pushy_build_time.txt/);
|
|
117
|
-
if (!buildTimeTxtBuffer) {
|
|
118
|
-
// Not in root bundle when use `use_frameworks`
|
|
119
|
-
buildTimeTxtBuffer = await appInfoParser.parser.getEntry(/payload\/.+?\.app\/frameworks\/react_native_update.framework\/pushy_build_time.txt/);
|
|
120
|
-
}
|
|
121
|
-
if (!buildTimeTxtBuffer) {
|
|
122
|
-
throw new Error(t('buildTimeNotFound'));
|
|
123
|
-
}
|
|
124
|
-
const buildTime = buildTimeTxtBuffer.toString().replace('\n', '');
|
|
125
|
-
return {
|
|
126
|
-
versionName,
|
|
127
|
-
buildTime,
|
|
128
|
-
...appCredential
|
|
129
|
-
};
|
|
130
|
-
}
|
|
131
|
-
export async function getAabInfo(fn) {
|
|
132
|
-
const protobuf = require('protobufjs');
|
|
133
|
-
const root = await protobuf.load(path.join(__dirname, '../../proto/Resources.proto'));
|
|
134
|
-
const XmlNode = root.lookupType('aapt.pb.XmlNode');
|
|
135
|
-
const buffer = await readZipEntry(fn, 'base/manifest/AndroidManifest.xml');
|
|
136
|
-
const message = XmlNode.decode(buffer);
|
|
137
|
-
const object = XmlNode.toObject(message, {
|
|
138
|
-
enums: String,
|
|
139
|
-
longs: String,
|
|
140
|
-
bytes: String,
|
|
141
|
-
defaults: true,
|
|
142
|
-
arrays: true
|
|
143
|
-
});
|
|
144
|
-
const manifestElement = object.element;
|
|
145
|
-
if (manifestElement.name !== 'manifest') {
|
|
146
|
-
throw new Error('Invalid manifest');
|
|
147
|
-
}
|
|
148
|
-
let versionName = '';
|
|
149
|
-
for (const attr of manifestElement.attribute){
|
|
150
|
-
if (attr.name === 'versionName') {
|
|
151
|
-
versionName = attr.value;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
let buildTime = 0;
|
|
155
|
-
const appCredential = {};
|
|
156
|
-
// Find application node
|
|
157
|
-
const applicationNode = manifestElement.child.find((c)=>c.element && c.element.name === 'application');
|
|
158
|
-
if (applicationNode) {
|
|
159
|
-
const metaDataNodes = applicationNode.element.child.filter((c)=>c.element && c.element.name === 'meta-data');
|
|
160
|
-
for (const meta of metaDataNodes){
|
|
161
|
-
let name = '';
|
|
162
|
-
let value = '';
|
|
163
|
-
let resourceId = 0;
|
|
164
|
-
for (const attr of meta.element.attribute){
|
|
165
|
-
if (attr.name === 'name') {
|
|
166
|
-
name = attr.value;
|
|
167
|
-
}
|
|
168
|
-
if (attr.name === 'value') {
|
|
169
|
-
var _attr_compiledItem_ref, _attr_compiledItem, _attr_compiledItem_prim, _attr_compiledItem1;
|
|
170
|
-
value = attr.value;
|
|
171
|
-
if ((_attr_compiledItem = attr.compiledItem) == null ? void 0 : (_attr_compiledItem_ref = _attr_compiledItem.ref) == null ? void 0 : _attr_compiledItem_ref.id) {
|
|
172
|
-
resourceId = attr.compiledItem.ref.id;
|
|
173
|
-
} else if ((_attr_compiledItem1 = attr.compiledItem) == null ? void 0 : (_attr_compiledItem_prim = _attr_compiledItem1.prim) == null ? void 0 : _attr_compiledItem_prim.intDecimalValue) {
|
|
174
|
-
value = attr.compiledItem.prim.intDecimalValue.toString();
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
if (name === 'pushy_build_time') {
|
|
179
|
-
if (resourceId > 0) {
|
|
180
|
-
const resolvedValue = await resolveResource(fn, resourceId, root);
|
|
181
|
-
if (resolvedValue) {
|
|
182
|
-
value = resolvedValue;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
buildTime = Number(value);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
if (buildTime === 0) {
|
|
190
|
-
throw new Error(t('buildTimeNotFound'));
|
|
191
|
-
}
|
|
192
|
-
return {
|
|
193
|
-
versionName,
|
|
194
|
-
buildTime,
|
|
195
|
-
...appCredential
|
|
196
|
-
};
|
|
197
|
-
}
|
|
198
|
-
async function readZipEntry(fn, entryName) {
|
|
199
|
-
const yauzl = require('yauzl');
|
|
200
|
-
return new Promise((resolve, reject)=>{
|
|
201
|
-
yauzl.open(fn, {
|
|
202
|
-
lazyEntries: true
|
|
203
|
-
}, (err, zipfile)=>{
|
|
204
|
-
if (err) return reject(err);
|
|
205
|
-
let found = false;
|
|
206
|
-
zipfile.readEntry();
|
|
207
|
-
zipfile.on('entry', (entry)=>{
|
|
208
|
-
if (entry.fileName === entryName) {
|
|
209
|
-
found = true;
|
|
210
|
-
zipfile.openReadStream(entry, (err, readStream)=>{
|
|
211
|
-
if (err) return reject(err);
|
|
212
|
-
const chunks = [];
|
|
213
|
-
readStream.on('data', (chunk)=>chunks.push(chunk));
|
|
214
|
-
readStream.on('end', ()=>resolve(Buffer.concat(chunks)));
|
|
215
|
-
readStream.on('error', reject);
|
|
216
|
-
});
|
|
217
|
-
} else {
|
|
218
|
-
zipfile.readEntry();
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
zipfile.on('end', ()=>{
|
|
222
|
-
if (!found) reject(new Error(`${entryName} not found in AAB`));
|
|
223
|
-
});
|
|
224
|
-
zipfile.on('error', reject);
|
|
225
|
-
});
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
async function resolveResource(fn, resourceId, root) {
|
|
229
|
-
const pkgId = resourceId >> 24 & 0xff;
|
|
230
|
-
const typeId = resourceId >> 16 & 0xff;
|
|
231
|
-
const entryId = resourceId & 0xffff;
|
|
232
|
-
try {
|
|
233
|
-
const buffer = await readZipEntry(fn, 'base/resources.pb');
|
|
234
|
-
const ResourceTable = root.lookupType('aapt.pb.ResourceTable');
|
|
235
|
-
const message = ResourceTable.decode(buffer);
|
|
236
|
-
const object = ResourceTable.toObject(message, {
|
|
237
|
-
enums: String,
|
|
238
|
-
longs: String,
|
|
239
|
-
bytes: String,
|
|
240
|
-
defaults: true,
|
|
241
|
-
arrays: true
|
|
242
|
-
});
|
|
243
|
-
// Find package
|
|
244
|
-
const pkg = object.package.find((p)=>p.packageId === pkgId);
|
|
245
|
-
if (!pkg) return null;
|
|
246
|
-
// Find type
|
|
247
|
-
const type = pkg.type.find((t)=>t.typeId === typeId);
|
|
248
|
-
if (!type) return null;
|
|
249
|
-
// Find entry
|
|
250
|
-
const entry = type.entry.find((e)=>e.entryId === entryId);
|
|
251
|
-
if (!entry) return null;
|
|
252
|
-
// Get value from configValue
|
|
253
|
-
if (entry.configValue && entry.configValue.length > 0) {
|
|
254
|
-
var _val_item;
|
|
255
|
-
const val = entry.configValue[0].value;
|
|
256
|
-
if ((_val_item = val.item) == null ? void 0 : _val_item.str) {
|
|
257
|
-
return val.item.str.value;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
} catch (e) {
|
|
261
|
-
console.warn('Failed to resolve resource:', e);
|
|
262
|
-
}
|
|
263
|
-
return null;
|
|
264
|
-
}
|
|
265
|
-
const localDir = path.resolve(os.homedir(), tempDir);
|
|
266
|
-
fs.ensureDirSync(localDir);
|
|
267
|
-
export function saveToLocal(originPath, destName) {
|
|
268
|
-
// TODO
|
|
269
|
-
// const destPath = path.join(localDir, destName);
|
|
270
|
-
// fs.ensureDirSync(path.dirname(destPath));
|
|
271
|
-
// fs.copyFileSync(originPath, destPath);
|
|
272
|
-
}
|
|
273
|
-
async function getLatestVersion(pkgNames) {
|
|
274
|
-
return latestVersion(pkgNames, {
|
|
275
|
-
// useCache: true,
|
|
276
|
-
requestOptions: {
|
|
277
|
-
timeout: 2000
|
|
278
|
-
}
|
|
279
|
-
}).then((pkgs)=>pkgs.map((pkg)=>pkg.latest)).catch(()=>[]);
|
|
280
|
-
}
|
|
281
|
-
export async function printVersionCommand() {
|
|
282
|
-
let [latestRnuCliVersion, latestRnuVersion] = await getLatestVersion([
|
|
283
|
-
'react-native-update-cli',
|
|
284
|
-
'react-native-update'
|
|
285
|
-
]);
|
|
286
|
-
latestRnuCliVersion = latestRnuCliVersion ? ` ${t('latestVersionTag', {
|
|
287
|
-
version: chalk.green(latestRnuCliVersion)
|
|
288
|
-
})}` : '';
|
|
289
|
-
console.log(`react-native-update-cli: ${pkg.version}${latestRnuCliVersion}`);
|
|
290
|
-
const rnuVersion = depVersions['react-native-update'];
|
|
291
|
-
if (rnuVersion) {
|
|
292
|
-
latestRnuVersion = latestRnuVersion ? ` ${t('latestVersionTag', {
|
|
293
|
-
version: chalk.green(latestRnuVersion)
|
|
294
|
-
})}` : '';
|
|
295
|
-
console.log(`react-native-update: ${rnuVersion}${latestRnuVersion}`);
|
|
296
|
-
if (IS_CRESC) {
|
|
297
|
-
if (satisfies(rnuVersion, '<10.27.0')) {
|
|
298
|
-
console.error('Unsupported version, please update to the latest version: npm i react-native-update@latest');
|
|
299
|
-
process.exit(1);
|
|
300
|
-
}
|
|
301
|
-
} else {
|
|
302
|
-
if (satisfies(rnuVersion, '<8.5.2')) {
|
|
303
|
-
console.warn(`当前版本已不再支持,请至少升级到 v8 的最新小版本后重新打包(代码无需改动): npm i react-native-update@8 .
|
|
304
|
-
如有使用安装 apk 的功能,请注意添加所需权限 https://pushy.reactnative.cn/docs/api#async-function-downloadandinstallapkurl`);
|
|
305
|
-
} else if (satisfies(rnuVersion, '9.0.0 - 9.2.1')) {
|
|
306
|
-
console.warn(`当前版本已不再支持,请至少升级到 v9 的最新小版本后重新打包(代码无需改动,可直接热更): npm i react-native-update@9 .
|
|
307
|
-
如有使用安装 apk 的功能,请注意添加所需权限 https://pushy.reactnative.cn/docs/api#async-function-downloadandinstallapkurl`);
|
|
308
|
-
} else if (satisfies(rnuVersion, '10.0.0 - 10.17.0')) {
|
|
309
|
-
console.warn('当前版本已不再支持,请升级到 v10 的最新小版本(代码无需改动,可直接热更): npm i react-native-update@10');
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
} else {
|
|
313
|
-
console.log(t('rnuVersionNotFound'));
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
export { checkPlugins };
|
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "fs";
|
|
2
|
-
import { dirname } from "path";
|
|
3
|
-
import { blue, bold, cyan, gray, green, italic, magenta, red, reset, strip, underline, yellow } from "@colors/colors/safe";
|
|
4
|
-
import semverDiff from "semver/functions/diff";
|
|
5
|
-
import semverMajor from "semver/functions/major";
|
|
6
|
-
import latestVersion from ".";
|
|
7
|
-
const colorizeDiff = (from, to)=>{
|
|
8
|
-
const toParts = to.split('.');
|
|
9
|
-
const diffIndex = from.split('.').findIndex((part, i)=>part !== toParts[i]);
|
|
10
|
-
if (diffIndex !== -1) {
|
|
11
|
-
let color = magenta;
|
|
12
|
-
if (toParts[0] !== '0') {
|
|
13
|
-
color = diffIndex === 0 ? red : diffIndex === 1 ? cyan : green;
|
|
14
|
-
}
|
|
15
|
-
const start = toParts.slice(0, diffIndex).join('.');
|
|
16
|
-
const mid = diffIndex === 0 ? '' : '.';
|
|
17
|
-
const end = color(toParts.slice(diffIndex).join('.'));
|
|
18
|
-
return `${start}${mid}${end}`;
|
|
19
|
-
}
|
|
20
|
-
return to;
|
|
21
|
-
};
|
|
22
|
-
const columnCellRenderer = (column, row)=>{
|
|
23
|
-
let text = row[column.attrName];
|
|
24
|
-
const gap = text.length < column.maxLength ? ' '.repeat(column.maxLength - text.length) : '';
|
|
25
|
-
switch(column.attrName){
|
|
26
|
-
case 'name':
|
|
27
|
-
text = yellow(text);
|
|
28
|
-
break;
|
|
29
|
-
case 'installed':
|
|
30
|
-
case 'separator':
|
|
31
|
-
text = blue(text);
|
|
32
|
-
break;
|
|
33
|
-
case 'location':
|
|
34
|
-
case 'tagOrRange':
|
|
35
|
-
text = gray(text);
|
|
36
|
-
break;
|
|
37
|
-
case 'wanted':
|
|
38
|
-
text = colorizeDiff(row.installed, text);
|
|
39
|
-
break;
|
|
40
|
-
case 'latest':
|
|
41
|
-
if (text !== row.wanted) {
|
|
42
|
-
text = colorizeDiff(row.installed, text);
|
|
43
|
-
}
|
|
44
|
-
break;
|
|
45
|
-
default:
|
|
46
|
-
break;
|
|
47
|
-
}
|
|
48
|
-
return column.align === 'right' ? `${gap}${text}` : `${text}${gap}`;
|
|
49
|
-
};
|
|
50
|
-
const columnHeaderRenderer = (column)=>{
|
|
51
|
-
const text = column.label;
|
|
52
|
-
const gap = text.length < column.maxLength ? ' '.repeat(column.maxLength - text.length) : '';
|
|
53
|
-
return column.align === 'right' ? `${gap}${underline(text)}` : `${underline(text)}${gap}`;
|
|
54
|
-
};
|
|
55
|
-
const drawBox = (lines, color = yellow, horizontalPadding = 3)=>{
|
|
56
|
-
const maxLineWidth = lines.reduce((max, row)=>Math.max(max, strip(row).length), 0);
|
|
57
|
-
console.log(color(`┌${'─'.repeat(maxLineWidth + horizontalPadding * 2)}┐`));
|
|
58
|
-
lines.forEach((row)=>{
|
|
59
|
-
const padding = ' '.repeat(horizontalPadding);
|
|
60
|
-
const fullRow = `${row}${' '.repeat(maxLineWidth - strip(row).length)}`;
|
|
61
|
-
console.log(`${color('│')}${padding}${reset(fullRow)}${padding}${color('│')}`);
|
|
62
|
-
});
|
|
63
|
-
console.log(color(`└${'─'.repeat(maxLineWidth + horizontalPadding * 2)}┘`));
|
|
64
|
-
};
|
|
65
|
-
const getTableColumns = (rows)=>{
|
|
66
|
-
const columns = [
|
|
67
|
-
{
|
|
68
|
-
label: 'Package',
|
|
69
|
-
attrName: 'name',
|
|
70
|
-
align: 'left',
|
|
71
|
-
maxLength: 0,
|
|
72
|
-
items: []
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
label: 'Location',
|
|
76
|
-
attrName: 'location',
|
|
77
|
-
align: 'left',
|
|
78
|
-
maxLength: 0,
|
|
79
|
-
items: []
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
label: 'Installed',
|
|
83
|
-
attrName: 'installed',
|
|
84
|
-
align: 'right',
|
|
85
|
-
maxLength: 0,
|
|
86
|
-
items: []
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
label: '',
|
|
90
|
-
attrName: 'separator',
|
|
91
|
-
align: 'center',
|
|
92
|
-
maxLength: 0,
|
|
93
|
-
items: []
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
label: 'Range',
|
|
97
|
-
attrName: 'tagOrRange',
|
|
98
|
-
align: 'right',
|
|
99
|
-
maxLength: 0,
|
|
100
|
-
items: []
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
label: '',
|
|
104
|
-
attrName: 'separator',
|
|
105
|
-
align: 'center',
|
|
106
|
-
maxLength: 0,
|
|
107
|
-
items: []
|
|
108
|
-
},
|
|
109
|
-
{
|
|
110
|
-
label: 'Wanted',
|
|
111
|
-
attrName: 'wanted',
|
|
112
|
-
align: 'right',
|
|
113
|
-
maxLength: 0,
|
|
114
|
-
items: []
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
label: 'Latest',
|
|
118
|
-
attrName: 'latest',
|
|
119
|
-
align: 'right',
|
|
120
|
-
maxLength: 0,
|
|
121
|
-
items: []
|
|
122
|
-
}
|
|
123
|
-
];
|
|
124
|
-
rows.forEach((row)=>{
|
|
125
|
-
columns.forEach((column)=>{
|
|
126
|
-
column.maxLength = Math.max(column.label.length, column.maxLength, row[column.attrName].length || 0);
|
|
127
|
-
});
|
|
128
|
-
});
|
|
129
|
-
return columns;
|
|
130
|
-
};
|
|
131
|
-
const getTableRows = (updates)=>{
|
|
132
|
-
return updates.reduce((all, pkg)=>{
|
|
133
|
-
const { name, latest, local, globalNpm, globalYarn, wantedTagOrRange, updatesAvailable } = pkg;
|
|
134
|
-
const getGroup = (a, b)=>{
|
|
135
|
-
if (b && semverMajor(b) === 0) {
|
|
136
|
-
return 'majorVersionZero';
|
|
137
|
-
} else if (a && b) {
|
|
138
|
-
var _semverDiff;
|
|
139
|
-
const releaseType = (_semverDiff = semverDiff(a, b)) != null ? _semverDiff : '';
|
|
140
|
-
if ([
|
|
141
|
-
'major',
|
|
142
|
-
'premajor',
|
|
143
|
-
'prerelease'
|
|
144
|
-
].includes(releaseType)) {
|
|
145
|
-
return 'major';
|
|
146
|
-
} else if ([
|
|
147
|
-
'minor',
|
|
148
|
-
'preminor'
|
|
149
|
-
].includes(releaseType)) {
|
|
150
|
-
return 'minor';
|
|
151
|
-
} else if ([
|
|
152
|
-
'patch',
|
|
153
|
-
'prepatch'
|
|
154
|
-
].includes(releaseType)) {
|
|
155
|
-
return 'patch';
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
return 'unknown';
|
|
159
|
-
};
|
|
160
|
-
const add = (group, location, installed, wanted)=>all.push({
|
|
161
|
-
name: ' ' + name,
|
|
162
|
-
location,
|
|
163
|
-
installed: installed != null ? installed : 'unknown',
|
|
164
|
-
latest: latest != null ? latest : 'unknown',
|
|
165
|
-
tagOrRange: wantedTagOrRange != null ? wantedTagOrRange : 'unknown',
|
|
166
|
-
separator: '→',
|
|
167
|
-
wanted: wanted != null ? wanted : 'unknown',
|
|
168
|
-
group
|
|
169
|
-
});
|
|
170
|
-
if (updatesAvailable) {
|
|
171
|
-
if (updatesAvailable.local) {
|
|
172
|
-
add(getGroup(local, updatesAvailable.local), 'local', local, updatesAvailable.local);
|
|
173
|
-
}
|
|
174
|
-
if (updatesAvailable.globalNpm) {
|
|
175
|
-
add(getGroup(globalNpm, updatesAvailable.globalNpm), 'NPM global', globalNpm, updatesAvailable.globalNpm);
|
|
176
|
-
}
|
|
177
|
-
if (updatesAvailable.globalYarn) {
|
|
178
|
-
add(getGroup(globalYarn, updatesAvailable.globalYarn), 'YARN global', globalYarn, updatesAvailable.globalYarn);
|
|
179
|
-
}
|
|
180
|
-
} else {
|
|
181
|
-
if (local && local !== latest) {
|
|
182
|
-
add(getGroup(local, latest), 'local', local, pkg.wanted);
|
|
183
|
-
}
|
|
184
|
-
if (globalNpm && globalNpm !== latest) {
|
|
185
|
-
add(getGroup(globalNpm, latest), 'NPM global', globalNpm, pkg.wanted);
|
|
186
|
-
}
|
|
187
|
-
if (globalYarn && globalYarn !== latest) {
|
|
188
|
-
add(getGroup(globalYarn, latest), 'YARN global', globalYarn, pkg.wanted);
|
|
189
|
-
}
|
|
190
|
-
if (!local && !globalNpm && !globalYarn) {
|
|
191
|
-
add('unknown', 'unknown', 'unknown', pkg.wanted);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
return all;
|
|
195
|
-
}, []);
|
|
196
|
-
};
|
|
197
|
-
const displayTable = (latestVersionPackages)=>{
|
|
198
|
-
const updates = latestVersionPackages.filter((pkg)=>pkg.updatesAvailable);
|
|
199
|
-
if (updates.length) {
|
|
200
|
-
const rows = getTableRows(updates);
|
|
201
|
-
const hasUpdates = rows.some((row)=>row.installed !== 'unknown');
|
|
202
|
-
const columns = getTableColumns(rows);
|
|
203
|
-
const columnGap = 2;
|
|
204
|
-
const getGroupLines = (groupType, color, title, description)=>{
|
|
205
|
-
const items = rows.filter((row)=>row.group === groupType).sort((a, b)=>a.name > b.name ? 1 : -1);
|
|
206
|
-
return !items.length ? [] : [
|
|
207
|
-
'',
|
|
208
|
-
color(`${bold(title)} ${italic(`(${description})`)}`),
|
|
209
|
-
...items.map((row)=>columns.map((column)=>columnCellRenderer(column, row)).join(' '.repeat(columnGap)))
|
|
210
|
-
];
|
|
211
|
-
};
|
|
212
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
213
|
-
drawBox([
|
|
214
|
-
'',
|
|
215
|
-
hasUpdates ? yellow('Important updates are available.') : undefined,
|
|
216
|
-
hasUpdates ? '' : undefined,
|
|
217
|
-
columns.map(columnHeaderRenderer).join(' '.repeat(columnGap)),
|
|
218
|
-
...getGroupLines('patch', green, 'Patch', 'backwards-compatible bug fixes'),
|
|
219
|
-
...getGroupLines('minor', cyan, 'Minor', 'backwards-compatible features'),
|
|
220
|
-
...getGroupLines('major', red, 'Major', 'potentially breaking API changes'),
|
|
221
|
-
...getGroupLines('majorVersionZero', magenta, 'Major version zero', 'not stable, anything may change'),
|
|
222
|
-
...getGroupLines('unknown', blue, 'Missing', 'not installed'),
|
|
223
|
-
''
|
|
224
|
-
].filter((line)=>line !== undefined));
|
|
225
|
-
} else {
|
|
226
|
-
console.log(green('🎉 Packages are up-to-date'));
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
const checkVersions = async (packages, skipMissing, options = {
|
|
230
|
-
useCache: true
|
|
231
|
-
})=>{
|
|
232
|
-
const ora = (await import("ora")).default;
|
|
233
|
-
const spinner = ora({
|
|
234
|
-
text: cyan('Checking versions...')
|
|
235
|
-
});
|
|
236
|
-
spinner.start();
|
|
237
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
238
|
-
// @ts-ignore
|
|
239
|
-
let latestVersionPackages = await latestVersion(packages, options);
|
|
240
|
-
if (skipMissing) {
|
|
241
|
-
latestVersionPackages = latestVersionPackages.filter((pkg)=>{
|
|
242
|
-
var _pkg_local, _ref;
|
|
243
|
-
return (_ref = (_pkg_local = pkg.local) != null ? _pkg_local : pkg.globalNpm) != null ? _ref : pkg.globalYarn;
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
spinner.stop();
|
|
247
|
-
displayTable(latestVersionPackages);
|
|
248
|
-
};
|
|
249
|
-
void (async ()=>{
|
|
250
|
-
let args = process.argv.slice(2);
|
|
251
|
-
const skipMissing = args.includes('--skip-missing');
|
|
252
|
-
// Remove any options from the arguments
|
|
253
|
-
args = args.filter((arg)=>!arg.startsWith('-'));
|
|
254
|
-
// If argument is a package.json file
|
|
255
|
-
if (args.length === 1 && args[0].endsWith('package.json')) {
|
|
256
|
-
if (existsSync(args[0])) {
|
|
257
|
-
process.chdir(dirname(args[0]));
|
|
258
|
-
await checkVersions(JSON.parse(readFileSync(args[0]).toString()), skipMissing);
|
|
259
|
-
} else {
|
|
260
|
-
console.log(cyan('No package.json file were found'));
|
|
261
|
-
}
|
|
262
|
-
} else {
|
|
263
|
-
// Check if a local package.json file exists
|
|
264
|
-
let localPkgJson;
|
|
265
|
-
if (existsSync('package.json')) {
|
|
266
|
-
localPkgJson = JSON.parse(readFileSync('package.json').toString());
|
|
267
|
-
}
|
|
268
|
-
// Check given arguments
|
|
269
|
-
if (args.length) {
|
|
270
|
-
// Map arguments with any range that could be found in local package.json
|
|
271
|
-
args = args.map((arg)=>{
|
|
272
|
-
var _localPkgJson_dependencies, _localPkgJson_devDependencies, _localPkgJson_peerDependencies;
|
|
273
|
-
if (localPkgJson == null ? void 0 : (_localPkgJson_dependencies = localPkgJson.dependencies) == null ? void 0 : _localPkgJson_dependencies[arg]) {
|
|
274
|
-
var _localPkgJson_dependencies1;
|
|
275
|
-
return `${arg}@${(_localPkgJson_dependencies1 = localPkgJson.dependencies) == null ? void 0 : _localPkgJson_dependencies1[arg]}`;
|
|
276
|
-
}
|
|
277
|
-
if (localPkgJson == null ? void 0 : (_localPkgJson_devDependencies = localPkgJson.devDependencies) == null ? void 0 : _localPkgJson_devDependencies[arg]) {
|
|
278
|
-
var _localPkgJson_devDependencies1;
|
|
279
|
-
return `${arg}@${(_localPkgJson_devDependencies1 = localPkgJson.devDependencies) == null ? void 0 : _localPkgJson_devDependencies1[arg]}`;
|
|
280
|
-
}
|
|
281
|
-
if (localPkgJson == null ? void 0 : (_localPkgJson_peerDependencies = localPkgJson.peerDependencies) == null ? void 0 : _localPkgJson_peerDependencies[arg]) {
|
|
282
|
-
var _localPkgJson_peerDependencies1;
|
|
283
|
-
return `${arg}@${(_localPkgJson_peerDependencies1 = localPkgJson.peerDependencies) == null ? void 0 : _localPkgJson_peerDependencies1[arg]}`;
|
|
284
|
-
}
|
|
285
|
-
return arg;
|
|
286
|
-
});
|
|
287
|
-
await checkVersions(args, skipMissing);
|
|
288
|
-
} else if (localPkgJson) {
|
|
289
|
-
await checkVersions(localPkgJson, skipMissing);
|
|
290
|
-
} else {
|
|
291
|
-
console.log(cyan('No packages were found'));
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
})();
|