@@ -27,7 +27,39 @@ export function getCookies(cookies: string, exclusions?: string[]): Record<strin
2727 return ! isEmpty ( result ) ? result : null ;
2828}
2929
30+ function getSecureCrypto ( ) : Crypto | null {
31+ const { crypto } = globalThis ;
32+ if ( ! crypto || typeof crypto . getRandomValues !== "function" ) {
33+ return null ;
34+ }
35+
36+ return crypto ;
37+ }
38+
39+ function toHex ( bytes : Uint8Array , start : number , length : number ) : string {
40+ let result = "" ;
41+ for ( let index = start ; index < start + length ; index ++ ) {
42+ result += bytes [ index ] . toString ( 16 ) . padStart ( 2 , "0" ) ;
43+ }
44+
45+ return result ;
46+ }
47+
3048export function guid ( ) : string {
49+ const crypto = getSecureCrypto ( ) ;
50+ if ( crypto ) {
51+ if ( typeof crypto . randomUUID === "function" ) {
52+ return crypto . randomUUID ( ) ;
53+ }
54+
55+ const bytes = new Uint8Array ( 16 ) ;
56+ crypto . getRandomValues ( bytes ) ;
57+ bytes [ 6 ] = ( bytes [ 6 ] & 0x0f ) | 0x40 ;
58+ bytes [ 8 ] = ( bytes [ 8 ] & 0x3f ) | 0x80 ;
59+
60+ return `${ toHex ( bytes , 0 , 4 ) } -${ toHex ( bytes , 4 , 2 ) } -${ toHex ( bytes , 6 , 2 ) } -${ toHex ( bytes , 8 , 2 ) } -${ toHex ( bytes , 10 , 6 ) } ` ;
61+ }
62+
3163 function s4 ( ) {
3264 return Math . floor ( ( 1 + Math . random ( ) ) * 0x10000 )
3365 . toString ( 16 )
@@ -37,15 +69,101 @@ export function guid(): string {
3769 return s4 ( ) + s4 ( ) + "-" + s4 ( ) + "-" + s4 ( ) + "-" + s4 ( ) + "-" + s4 ( ) + s4 ( ) + s4 ( ) ;
3870}
3971
72+ function isDigitCode ( code : number ) : boolean {
73+ return code >= 48 && code <= 57 ;
74+ }
75+
76+ function isVersionIdentifierCode ( code : number ) : boolean {
77+ return isDigitCode ( code ) || ( code >= 65 && code <= 90 ) || ( code >= 97 && code <= 122 ) || code === 45 ;
78+ }
79+
80+ function readDigits ( input : string , start : number ) : number {
81+ let index = start ;
82+ while ( index < input . length && isDigitCode ( input . charCodeAt ( index ) ) ) {
83+ index ++ ;
84+ }
85+
86+ return index > start ? index : - 1 ;
87+ }
88+
89+ function readVersionIdentifiers ( input : string , start : number ) : number {
90+ let index = start ;
91+ while ( index < input . length ) {
92+ const segmentStart = index ;
93+ while ( index < input . length && isVersionIdentifierCode ( input . charCodeAt ( index ) ) ) {
94+ index ++ ;
95+ }
96+
97+ if ( index === segmentStart ) {
98+ return - 1 ;
99+ }
100+
101+ if ( input [ index ] !== "." ) {
102+ return index ;
103+ }
104+
105+ index ++ ;
106+ }
107+
108+ return index ;
109+ }
110+
40111export function parseVersion ( source : string ) : string | null {
41112 if ( ! source ) {
42113 return null ;
43114 }
44115
45- const versionRegex = / ( v ? ( ( \d + ) \. ( \d + ) ( \. ( \d + ) ) ? ) (?: - ( [ \d A - Z a - z - ] + (?: \. [ \d A - Z a - z - ] + ) * ) ) ? (?: \+ ( [ \d A - Z a - z - ] + (?: \. [ \d A - Z a - z - ] + ) * ) ) ? ) / ;
46- const matches = versionRegex . exec ( source ) ;
47- if ( matches && matches . length > 0 ) {
48- return matches [ 0 ] ;
116+ for ( let index = 0 ; index < source . length ; ) {
117+ const start = index ;
118+ let cursor = index ;
119+
120+ if ( source [ cursor ] === "v" ) {
121+ if ( ! isDigitCode ( source . charCodeAt ( cursor + 1 ) ) ) {
122+ index ++ ;
123+ continue ;
124+ }
125+
126+ cursor ++ ;
127+ } else if ( ! isDigitCode ( source . charCodeAt ( cursor ) ) ) {
128+ index ++ ;
129+ continue ;
130+ }
131+
132+ const majorEnd = readDigits ( source , cursor ) ;
133+ if ( source [ majorEnd ] !== "." ) {
134+ index = majorEnd ;
135+ continue ;
136+ }
137+
138+ const minorEnd = readDigits ( source , majorEnd + 1 ) ;
139+ if ( minorEnd === - 1 ) {
140+ index = majorEnd + 1 ;
141+ continue ;
142+ }
143+
144+ let end = minorEnd ;
145+ if ( source [ end ] === "." ) {
146+ const patchEnd = readDigits ( source , end + 1 ) ;
147+ if ( patchEnd !== - 1 ) {
148+ end = patchEnd ;
149+ }
150+ }
151+
152+ if ( source [ end ] === "-" ) {
153+ const preReleaseEnd = readVersionIdentifiers ( source , end + 1 ) ;
154+ if ( preReleaseEnd !== - 1 ) {
155+ end = preReleaseEnd ;
156+ }
157+ }
158+
159+ if ( source [ end ] === "+" ) {
160+ const buildEnd = readVersionIdentifiers ( source , end + 1 ) ;
161+ if ( buildEnd !== - 1 ) {
162+ end = buildEnd ;
163+ }
164+ }
165+
166+ return source . slice ( start , end ) ;
49167 }
50168
51169 return null ;
@@ -73,6 +191,14 @@ export function parseQueryString(query: string, exclusions?: string[]): Record<s
73191}
74192
75193export function randomNumber ( ) : number {
194+ const crypto = getSecureCrypto ( ) ;
195+ if ( crypto ) {
196+ const values = new Uint32Array ( 2 ) ;
197+ crypto . getRandomValues ( values ) ;
198+
199+ return ( values [ 0 ] & 0x1fffff ) * 0x100000000 + values [ 1 ] ;
200+ }
201+
76202 return Math . floor ( Math . random ( ) * 9007199254740992 ) ;
77203}
78204
@@ -86,16 +212,15 @@ export function isMatch(input: string | undefined, patterns: string[], ignoreCas
86212 return false ;
87213 }
88214
89- const trim = / ^ [ \s \uFEFF \xA0 ] + | [ \s \uFEFF \xA0 ] + $ / g;
90- input = ( ignoreCase ? input . toLowerCase ( ) : input ) . replace ( trim , "" ) ;
215+ input = ( ignoreCase ? input . toLowerCase ( ) : input ) . trim ( ) ;
91216
92217 return ( patterns || [ ] ) . some ( ( pattern ) => {
93218 if ( typeof pattern !== "string" ) {
94219 return false ;
95220 }
96221
97222 if ( pattern ) {
98- pattern = ( ignoreCase ? pattern . toLowerCase ( ) : pattern ) . replace ( trim , "" ) ;
223+ pattern = ( ignoreCase ? pattern . toLowerCase ( ) : pattern ) . trim ( ) ;
99224 }
100225
101226 if ( ! pattern ) {
0 commit comments