1
1
import React , { Component , Fragment } from "react" ;
2
2
import PropTypes from "prop-types" ;
3
- import { Link } from "react-router-dom" ;
3
+ import { Link , withRouter } from "react-router-dom" ;
4
+ import { match as matchSemver } from "semver-match" ;
4
5
5
6
import { formatPackageString } from "../../utils/string" ;
6
7
import { getInstance as api } from "../../services/ApiManager" ;
7
8
8
- export default class Package extends Component {
9
+ class Package extends Component {
9
10
static propTypes = {
10
- match : PropTypes . object . isRequired
11
+ match : PropTypes . object . isRequired ,
12
+ history : PropTypes . object . isRequired
11
13
} ;
12
14
constructor ( props ) {
13
15
super ( props ) ;
@@ -17,9 +19,15 @@ export default class Package extends Component {
17
19
state : "loading"
18
20
} ;
19
21
async componentDidMount ( ) {
20
- const { scope, name } = this . props . match . params ;
21
- this . loadInfos ( scope , name ) ;
22
+ const { scope, name, version } = this . props . match . params ;
23
+ this . loadInfos ( scope , name , version ) ;
22
24
}
25
+ /**
26
+ * Once the container is mounted, we have to track for changes in the router
27
+ * to relaunch xhr to npm-registry, since componentDidMount won't be re-triggered
28
+ * That way, we trigger this.loadInfos with fresh props from the router
29
+ * @param {Object } newProps
30
+ */
23
31
componentWillReceiveProps ( newProps ) {
24
32
const { scope, name, version } = this . props . match . params ;
25
33
const {
@@ -28,17 +36,60 @@ export default class Package extends Component {
28
36
version : newVersion
29
37
} = newProps . match . params ;
30
38
if ( scope !== newScope || name !== newName || version !== newVersion ) {
31
- this . loadInfos ( newScope , newName ) ;
39
+ this . loadInfos ( newScope , newName , newVersion ) ;
40
+ }
41
+ }
42
+ /**
43
+ * Redirect a final version is matched
44
+ * Returns the matched versions if matched (and redirects the router).
45
+ * If no need to redirect, returns false.
46
+ * @param {String } scope
47
+ * @param {String } name
48
+ * @param {String } range
49
+ * @param {Array } versions
50
+ * @param {Object } distTags
51
+ * @return {Boolean|String }
52
+ */
53
+ redirectUntilMatchVersion ( scope , name , range , versions = [ ] , distTags = { } ) {
54
+ if ( typeof range !== "undefined" ) {
55
+ const matchedVersion = matchSemver ( range , versions , distTags ) || "latest" ;
56
+ console . log ( { range, versions, distTags, matchedVersion } ) ;
57
+ if (
58
+ matchedVersion &&
59
+ matchedVersion !== this . props . match . params . version
60
+ ) {
61
+ this . props . history . replace (
62
+ `/package/${ formatPackageString ( { scope, name } ) } @${ matchedVersion } `
63
+ ) ;
64
+ }
65
+ return matchedVersion ;
32
66
}
67
+ return false ;
33
68
}
34
- async loadInfos ( scope , name ) {
69
+ /**
70
+ * Loads infos from the npm registry.
71
+ * @param {String } scope
72
+ * @param {String } name
73
+ * @param {String } range
74
+ */
75
+ async loadInfos ( scope , name , range ) {
35
76
this . setState ( { state : "loading" } ) ;
36
77
try {
37
78
const { data : packageInfos } = await api ( ) . packageInfos (
38
79
formatPackageString ( { scope, name } )
39
80
) ;
40
81
console . log ( packageInfos . name , { packageInfos } ) ;
41
- this . setState ( { packageInfos, state : "loaded" } ) ;
82
+ const matched = this . redirectUntilMatchVersion (
83
+ scope ,
84
+ name ,
85
+ range ,
86
+ Object . keys ( packageInfos . versions ) ,
87
+ packageInfos [ "dist-tags" ]
88
+ ) ;
89
+ if ( matched ) {
90
+ console . log ( "matched" , matched ) ;
91
+ this . setState ( { packageInfos, state : "loaded" } ) ;
92
+ }
42
93
} catch ( e ) {
43
94
console . error ( e ) ;
44
95
this . setState ( { packageInfos : null , state : "error" } ) ;
@@ -80,3 +131,8 @@ export default class Package extends Component {
80
131
) ;
81
132
}
82
133
}
134
+
135
+ /**
136
+ * Gives access to history/location/match in props from the router - https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/withRouter.md
137
+ */
138
+ export default withRouter ( Package ) ;
0 commit comments