1
+ import chalk from 'chalk' ;
2
+ import urllib from 'urllib' ;
3
+ import assert from 'assert' ;
4
+ import semver from 'semver' ;
5
+ import { NpmCheckUpdateConfig , UpgradeInfo } from './types' ;
6
+ import debug from 'debug' ;
7
+ const helperDebug = debug ( 'npmcheckupdate#helper' ) ;
8
+
9
+ export async function checkUpdate ( option : Pick < NpmCheckUpdateConfig , 'unpkgUrl' | 'upgradePolicy' > & {
10
+ pkgName : string ;
11
+ pkgVersion : string ;
12
+ pkgBaseDir : string ;
13
+ } ) {
14
+ const { unpkgUrl, upgradePolicy, pkgVersion, pkgName, pkgBaseDir } = option ;
15
+
16
+ let distTag : string | undefined ;
17
+ let remoteVersionPatterns : string ;
18
+ const [ major , minor ] = pkgVersion . split ( '.' ) ;
19
+ if ( upgradePolicy === 'major' ) {
20
+ remoteVersionPatterns = '*' ;
21
+ } else if ( upgradePolicy === 'minor' ) {
22
+ remoteVersionPatterns = `${ major } .*` ;
23
+ } else if ( upgradePolicy === 'patch' ) {
24
+ remoteVersionPatterns = `${ major } .${ minor } .*` ;
25
+ } else {
26
+ distTag = upgradePolicy ;
27
+ remoteVersionPatterns = upgradePolicy ;
28
+ }
29
+
30
+ // request unpkg to get version info
31
+ let remoteVersion : string ;
32
+ const unpkgHost = unpkgUrl . endsWith ( '/' ) ? unpkgUrl : `${ unpkgUrl } /` ;
33
+ const remoteUrl = `${ unpkgHost } ${ pkgName } @${ remoteVersionPatterns } /package.json` ;
34
+ try {
35
+ const { data } = await urllib . request ( remoteUrl , {
36
+ dataType : 'json' ,
37
+ } ) ;
38
+
39
+ assert ( data . version , 'Invalid package.json, not found version info' ) ;
40
+ remoteVersion = data . version ;
41
+ } catch ( e ) {
42
+ helperDebug ( `Request ${ remoteUrl } failed with error: ` + e . message ) ;
43
+ return undefined ;
44
+ }
45
+
46
+ // check whether need to update
47
+ const result = semver . compare ( remoteVersion , pkgVersion ) ;
48
+ if ( result > 0 ) {
49
+ return {
50
+ distTag,
51
+ upgradePolicy,
52
+ pkgName,
53
+ pkgVersion,
54
+ pkgBaseDir,
55
+ targetVersion : remoteVersion ,
56
+ } ;
57
+ }
58
+
59
+ return undefined ;
60
+ }
61
+
62
+ export function displayUpgradeInfo ( upgradeInfo : UpgradeInfo ) {
63
+ // update contents
64
+ const contents = [
65
+ `Update available ${ chalk . gray ( upgradeInfo . pkgVersion ) } → ${ chalk . greenBright ( upgradeInfo . targetVersion ) } ` ,
66
+ `Run ${ chalk . blueBright ( `npm i -g ${ upgradeInfo . pkgName } @${ upgradeInfo . distTag || upgradeInfo . targetVersion } ` ) } to update` ,
67
+ ] ;
68
+
69
+ const removeColor = c => c . replace ( / \x1B \[ \d + m / g, '' ) ;
70
+ const maxLen = contents . map ( removeColor )
71
+ . sort ( ( a , b ) => a . length - b . length )
72
+ . pop ( ) . length ;
73
+
74
+ // show content
75
+ const distanceLen = 2 ;
76
+ const displayContents : string [ ] = [ ] ;
77
+ const contentLen = maxLen + distanceLen * 2 ;
78
+ displayContents . push ( '┌' + '─' . repeat ( contentLen ) + '┐' ) ;
79
+ displayContents . push ( '│' + ' ' . repeat ( contentLen ) + '│' ) ;
80
+ displayContents . push ( '│' + ' ' . repeat ( contentLen ) + '│' ) ;
81
+
82
+ contents . forEach ( c => {
83
+ const realContentLen = removeColor ( c ) . length ;
84
+ const leftSpace = ' ' . repeat ( distanceLen + ( maxLen - realContentLen ) / 2 ) ;
85
+ const rightSpace = ' ' . repeat ( contentLen - leftSpace . length - realContentLen ) ;
86
+ displayContents . push ( '│' + leftSpace + c + rightSpace + '│' ) ;
87
+ } ) ;
88
+
89
+ displayContents . push ( '│' + ' ' . repeat ( contentLen ) + '│' ) ;
90
+ displayContents . push ( '│' + ' ' . repeat ( contentLen ) + '│' ) ;
91
+ displayContents . push ( '└' + '─' . repeat ( contentLen ) + '┘' ) ;
92
+ console . info ( `\n\n${ displayContents . map ( c => ` ${ c } ` ) . join ( '\n' ) } \n\n` ) ;
93
+ }
0 commit comments