@@ -2,103 +2,134 @@ export type PrereleaseId = string | number;
2
2
3
3
export type PreRelease = PrereleaseId [ ] ;
4
4
5
-
6
- function comparePreReleases (
7
- a : PreRelease ,
8
- b : PreRelease
9
- ) : number {
10
- const len = Math . min ( a . length , b . length ) ;
11
- for ( let i = 0 ; i < len ; i ++ ) {
12
- const aPart = a [ i ] ;
13
- const bPart = b [ i ] ;
14
- if ( aPart === bPart ) continue ;
15
- if ( typeof aPart === 'number' && typeof bPart === 'number' ) {
16
- return aPart - bPart ;
17
- }
18
- if ( typeof aPart === 'string' && typeof bPart === 'string' ) {
19
- return aPart . localeCompare ( bPart ) ;
20
- }
21
- // According to 11.4.3, numeric identifiers always have lower precedence than non-numeric identifiers.
22
- // So if `a` is a string, it has higher precedence than `b`.
23
- return typeof aPart === 'string' ? 1 : - 1 ;
5
+ // Compare pre-release identifiers according to the semver spec (https://semver.org/#spec-item-11).
6
+ function comparePreReleases ( a : PreRelease , b : PreRelease ) : number {
7
+ const len = Math . min ( a . length , b . length ) ;
8
+ for ( let i = 0 ; i < len ; i ++ ) {
9
+ const aPart = a [ i ] ;
10
+ const bPart = b [ i ] ;
11
+ if ( aPart === bPart ) continue ;
12
+ if ( typeof aPart === 'number' && typeof bPart === 'number' ) {
13
+ return aPart - bPart ;
14
+ }
15
+ if ( typeof aPart === 'string' && typeof bPart === 'string' ) {
16
+ return aPart . localeCompare ( bPart ) ;
24
17
}
25
- // See rule 11.4.4 in the semver spec.
26
- return a . length - b . length ;
18
+ // According to item 11.4.3, numeric identifiers always have lower precedence than non-numeric identifiers.
19
+ // So if `a` is a string, it has higher precedence than `b`.
20
+ return typeof aPart === 'string' ? 1 : - 1 ;
21
+ }
22
+ // See rule 11.4.4 in the semver spec.
23
+ return a . length - b . length ;
27
24
}
28
25
29
- // We don't use these, so I'm not going to parse it to spec.
26
+ // We don't use these, and they don't matter for version ordering, so I'm not going to parse it to spec.
30
27
export type BuildInfo = string ;
31
28
29
+ // This is exported for tests.
32
30
export class SemanticVersion {
33
- major : number ;
34
- minor : number ;
35
- patch : number ;
36
- preRelease : PreRelease | null ;
37
- buildInfo : BuildInfo | null ;
38
-
39
- constructor (
40
- major : number ,
41
- minor : number ,
42
- patch : number ,
43
- preRelease : PreRelease | null = null ,
44
- buildInfo : BuildInfo | null = null
45
- ) {
46
- this . major = major ;
47
- this . minor = minor ;
48
- this . patch = patch ;
49
- this . preRelease = preRelease ;
50
- this . buildInfo = buildInfo ;
31
+ major : number ;
32
+ minor : number ;
33
+ patch : number ;
34
+ preRelease : PreRelease | null ;
35
+ buildInfo : BuildInfo | null ;
36
+
37
+ constructor (
38
+ major : number ,
39
+ minor : number ,
40
+ patch : number ,
41
+ preRelease : PreRelease | null = null ,
42
+ buildInfo : BuildInfo | null = null
43
+ ) {
44
+ this . major = major ;
45
+ this . minor = minor ;
46
+ this . patch = patch ;
47
+ this . preRelease = preRelease ;
48
+ this . buildInfo = buildInfo ;
49
+ }
50
+
51
+ toString ( ) : string {
52
+ let versionString = `${ this . major } .${ this . minor } .${ this . patch } ` ;
53
+ if ( this . preRelease ) {
54
+ versionString += `-${ this . preRelease . join ( '.' ) } ` ;
51
55
}
52
-
53
- toString ( ) : string {
54
- let versionString = `${ this . major } .${ this . minor } .${ this . patch } ` ;
55
- if ( this . preRelease ) {
56
- versionString += `-${ this . preRelease . join ( '.' ) } ` ;
57
- }
58
- if ( this . buildInfo ) {
59
- versionString += `+${ this . buildInfo } ` ;
60
- }
61
- return versionString ;
56
+ if ( this . buildInfo ) {
57
+ versionString += `+${ this . buildInfo } ` ;
62
58
}
59
+ return versionString ;
60
+ }
63
61
64
- compare ( other : SemanticVersion ) : number {
65
- if ( this . major !== other . major ) {
66
- return this . major - other . major ;
67
- }
68
- if ( this . minor !== other . minor ) {
69
- return this . minor - other . minor ;
70
- }
71
- if ( this . patch !== other . patch ) {
72
- return this . patch - other . patch ;
73
- }
74
- if ( this . preRelease && other . preRelease ) {
75
- return comparePreReleases ( this . preRelease , other . preRelease ) ;
76
- }
77
- if ( this . preRelease ) {
78
- return - 1 ; // The version without a pre-release is greater.
79
- }
80
- if ( other . preRelease ) {
81
- return - 1 ; // Since we don't have a pre-release, this version is greater.
82
- }
83
- return 0 ; // versions are equal
62
+ compare ( other : SemanticVersion ) : number {
63
+ if ( this . major !== other . major ) {
64
+ return this . major - other . major ;
65
+ }
66
+ if ( this . minor !== other . minor ) {
67
+ return this . minor - other . minor ;
68
+ }
69
+ if ( this . patch !== other . patch ) {
70
+ return this . patch - other . patch ;
71
+ }
72
+ if ( this . preRelease && other . preRelease ) {
73
+ return comparePreReleases ( this . preRelease , other . preRelease ) ;
74
+ }
75
+ if ( this . preRelease ) {
76
+ return - 1 ; // The version without a pre-release is greater.
84
77
}
78
+ if ( other . preRelease ) {
79
+ return - 1 ; // Since we don't have a pre-release, this version is greater.
80
+ }
81
+ return 0 ; // versions are equal
82
+ }
83
+
84
+ clone ( ) : SemanticVersion {
85
+ return new SemanticVersion (
86
+ this . major ,
87
+ this . minor ,
88
+ this . patch ,
89
+ this . preRelease ? [ ...this . preRelease ] : null ,
90
+ this . buildInfo
91
+ ) ;
92
+ }
85
93
86
- static parseVersionString ( version : string ) : SemanticVersion {
87
- const regex = / ^ ( 0 | [ 1 - 9 ] \d * ) \. ( 0 | [ 1 - 9 ] \d * ) \. ( 0 | [ 1 - 9 ] \d * ) (?: - ( [ \d a - z A - Z - ] + (?: \. [ \d a - z A - Z - ] + ) * ) ) ? (?: \+ ( [ \d a - z A - Z - ] + (?: \. [ \d a - z A - Z - ] + ) * ) ) ? $ / ;
88
- const match = version . match ( regex ) ;
89
- if ( ! match ) {
90
- throw new Error ( `Invalid version string: ${ version } ` ) ;
91
- }
92
-
93
- const major = parseInt ( match [ 1 ] , 10 ) ;
94
- const minor = parseInt ( match [ 2 ] , 10 ) ;
95
- const patch = parseInt ( match [ 3 ] , 10 ) ;
96
- const preRelease = match [ 4 ] ? match [ 4 ] . split ( '.' ) . map ( id => isNaN ( Number ( id ) ) ? id : Number ( id ) ) : null ;
97
- const buildInfo = match [ 5 ] || null ;
98
-
99
- return new SemanticVersion ( major , minor , patch , preRelease , buildInfo ) ;
94
+ static parseVersionString ( version : string ) : SemanticVersion {
95
+ const regex =
96
+ / ^ ( 0 | [ 1 - 9 ] \d * ) \. ( 0 | [ 1 - 9 ] \d * ) \. ( 0 | [ 1 - 9 ] \d * ) (?: - ( [ \d a - z A - Z - ] + (?: \. [ \d a - z A - Z - ] + ) * ) ) ? (?: \+ ( [ \d a - z A - Z - ] + (?: \. [ \d a - z A - Z - ] + ) * ) ) ? $ / ;
97
+ const match = version . match ( regex ) ;
98
+ if ( ! match ) {
99
+ throw new Error ( `Invalid version string: ${ version } ` ) ;
100
100
}
101
+
102
+ const major = parseInt ( match [ 1 ] , 10 ) ;
103
+ const minor = parseInt ( match [ 2 ] , 10 ) ;
104
+ const patch = parseInt ( match [ 3 ] , 10 ) ;
105
+ const preRelease = match [ 4 ]
106
+ ? match [ 4 ] . split ( '.' ) . map ( id => ( isNaN ( Number ( id ) ) ? id : Number ( id ) ) )
107
+ : null ;
108
+ const buildInfo = match [ 5 ] || null ;
109
+
110
+ return new SemanticVersion ( major , minor , patch , preRelease , buildInfo ) ;
111
+ }
101
112
}
102
113
103
114
// The SDK depends on some module information that was not generated before this version.
104
- export const MINIMUM_CLI_VERSION : SemanticVersion = new SemanticVersion ( 1 , 1 , 2 ) ;
115
+ export const _MINIMUM_CLI_VERSION : SemanticVersion = new SemanticVersion (
116
+ 1 ,
117
+ 1 ,
118
+ 2
119
+ ) ;
120
+
121
+ export function ensureMinimumVersionOrThrow ( versionString ?: string ) : void {
122
+ if ( versionString === undefined ) {
123
+ throw new Error ( versionErrorMessage ( versionString ) ) ;
124
+ }
125
+ const version = SemanticVersion . parseVersionString ( versionString ) ;
126
+ if ( version . compare ( _MINIMUM_CLI_VERSION ) < 0 ) {
127
+ throw new Error ( versionErrorMessage ( versionString ) ) ;
128
+ }
129
+ }
130
+
131
+ function versionErrorMessage ( incompatibleVersion ?: string ) : string {
132
+ const badVersion =
133
+ incompatibleVersion === undefined ? 'unknown' : incompatibleVersion ;
134
+ return `Module code was generated with an incompatible version of the spacetimedb cli (${ incompatibleVersion } ). Update the cli version to at least ${ _MINIMUM_CLI_VERSION . toString ( ) } and regenerate the bindings. You can upgrade to the latest cli version by running: spacetime version upgrade` ;
135
+ }
0 commit comments