1010 * Maxprograms - initial API and implementation
1111 *******************************************************************************/
1212
13+ import { ValidationResult } from "../grammar/Grammar" ;
1314import { XMLUtils } from "../XMLUtils" ;
1415import { SimpleType } from "./SimpleType" ;
15- import { ValidationResult } from "../grammar/Grammar" ;
1616
1717export class BuiltinTypes {
1818 private static types : Map < string , SimpleType > = new Map ( ) ;
@@ -28,7 +28,7 @@ export class BuiltinTypes {
2828 // Base types
2929 this . createType ( "anyType" , xsNamespace , ( ) => ValidationResult . success ( ) ) ;
3030 this . createType ( "anySimpleType" , xsNamespace , ( ) => ValidationResult . success ( ) ) ;
31-
31+
3232 // String types
3333 this . createType ( "string" , xsNamespace , this . validateString ) ;
3434 this . createType ( "normalizedString" , xsNamespace , this . validateNormalizedString ) ;
@@ -40,7 +40,7 @@ export class BuiltinTypes {
4040 this . createType ( "IDREF" , xsNamespace , this . validateIDREF ) ;
4141 this . createType ( "ENTITY" , xsNamespace , BuiltinTypes . validateNCName ) ;
4242 this . createType ( "NMTOKEN" , xsNamespace , this . validateNMTOKEN ) ;
43-
43+
4444 // Numeric types
4545 this . createType ( "decimal" , xsNamespace , this . validateDecimal ) ;
4646 this . createType ( "integer" , xsNamespace , BuiltinTypes . validateInteger ) ;
@@ -58,7 +58,7 @@ export class BuiltinTypes {
5858 this . createType ( "unsignedByte" , xsNamespace , this . validateUnsignedByte ) ;
5959 this . createType ( "float" , xsNamespace , this . validateFloat ) ;
6060 this . createType ( "double" , xsNamespace , this . validateDouble ) ;
61-
61+
6262 // Date/time types
6363 this . createType ( "duration" , xsNamespace , this . validateDuration ) ;
6464 this . createType ( "dateTime" , xsNamespace , this . validateDateTime ) ;
@@ -69,7 +69,7 @@ export class BuiltinTypes {
6969 this . createType ( "gMonthDay" , xsNamespace , this . validateGMonthDay ) ;
7070 this . createType ( "gDay" , xsNamespace , this . validateGDay ) ;
7171 this . createType ( "gMonth" , xsNamespace , this . validateGMonth ) ;
72-
72+
7373 // Other types
7474 this . createType ( "boolean" , xsNamespace , this . validateBoolean ) ;
7575 this . createType ( "base64Binary" , xsNamespace , this . validateBase64Binary ) ;
@@ -121,19 +121,36 @@ export class BuiltinTypes {
121121 if ( ! normalized . isValid ) {
122122 return normalized ;
123123 }
124-
124+
125125 if ( value !== value . trim ( ) || / \s { 2 , } / . test ( value ) ) {
126126 return ValidationResult . error ( "token cannot have leading/trailing whitespace or consecutive spaces" ) ;
127127 }
128128 return ValidationResult . success ( ) ;
129129 }
130130
131131 private static validateLanguage ( value : string ) : ValidationResult {
132- // RFC 3066 language codes
133- const pattern = / ^ [ a - z A - Z ] { 1 , 8 } ( - [ a - z A - Z 0 - 9 ] { 1 , 8 } ) * $ / ;
134- if ( ! pattern . test ( value ) ) {
132+ // RFC 3066 language codes - use iterative checks to avoid regex backtracking issues
133+ if ( ! value ) {
135134 return ValidationResult . error ( "Invalid language code format" ) ;
136135 }
136+
137+ const segments : string [ ] = value . split ( '-' ) ;
138+ if ( segments . length === 0 ) {
139+ return ValidationResult . error ( "Invalid language code format" ) ;
140+ }
141+
142+ const primaryTag : string = segments [ 0 ] ;
143+ if ( ! / ^ [ a - z A - Z ] { 1 , 8 } $ / . test ( primaryTag ) ) {
144+ return ValidationResult . error ( "Invalid language code format" ) ;
145+ }
146+
147+ for ( let i = 1 ; i < segments . length ; i ++ ) {
148+ const subTag : string = segments [ i ] ;
149+ if ( ! / ^ [ a - z A - Z 0 - 9 ] { 1 , 8 } $ / . test ( subTag ) ) {
150+ return ValidationResult . error ( "Invalid language code format" ) ;
151+ }
152+ }
153+
137154 return ValidationResult . success ( ) ;
138155 }
139156
@@ -152,7 +169,7 @@ export class BuiltinTypes {
152169 if ( ! nameResult . isValid ) {
153170 return nameResult ;
154171 }
155-
172+
156173 if ( value . includes ( ':' ) ) {
157174 return ValidationResult . error ( "NCName cannot contain colon" ) ;
158175 }
@@ -198,7 +215,7 @@ export class BuiltinTypes {
198215 if ( ! intResult . isValid ) {
199216 return intResult ;
200217 }
201-
218+
202219 const num = parseInt ( value , 10 ) ;
203220 if ( num > 0 ) {
204221 return ValidationResult . error ( "nonPositiveInteger must be <= 0" ) ;
@@ -211,7 +228,7 @@ export class BuiltinTypes {
211228 if ( ! intResult . isValid ) {
212229 return intResult ;
213230 }
214-
231+
215232 const num = parseInt ( value , 10 ) ;
216233 if ( num >= 0 ) {
217234 return ValidationResult . error ( "negativeInteger must be < 0" ) ;
@@ -224,7 +241,7 @@ export class BuiltinTypes {
224241 if ( ! intResult . isValid ) {
225242 return intResult ;
226243 }
227-
244+
228245 const num = parseInt ( value , 10 ) ;
229246 if ( num < - 9223372036854775808 || num > 9223372036854775807 ) {
230247 return ValidationResult . error ( "long value out of range" ) ;
@@ -237,7 +254,7 @@ export class BuiltinTypes {
237254 if ( ! intResult . isValid ) {
238255 return intResult ;
239256 }
240-
257+
241258 const num = parseInt ( value , 10 ) ;
242259 if ( num < - 2147483648 || num > 2147483647 ) {
243260 return ValidationResult . error ( "int value out of range" ) ;
@@ -250,7 +267,7 @@ export class BuiltinTypes {
250267 if ( ! intResult . isValid ) {
251268 return intResult ;
252269 }
253-
270+
254271 const num = parseInt ( value , 10 ) ;
255272 if ( num < - 32768 || num > 32767 ) {
256273 return ValidationResult . error ( "short value out of range" ) ;
@@ -263,7 +280,7 @@ export class BuiltinTypes {
263280 if ( ! intResult . isValid ) {
264281 return intResult ;
265282 }
266-
283+
267284 const num = parseInt ( value , 10 ) ;
268285 if ( num < - 128 || num > 127 ) {
269286 return ValidationResult . error ( "byte value out of range" ) ;
@@ -276,7 +293,7 @@ export class BuiltinTypes {
276293 if ( ! intResult . isValid ) {
277294 return intResult ;
278295 }
279-
296+
280297 const num = parseInt ( value , 10 ) ;
281298 if ( num < 0 ) {
282299 return ValidationResult . error ( "nonNegativeInteger must be >= 0" ) ;
@@ -289,7 +306,7 @@ export class BuiltinTypes {
289306 if ( ! intResult . isValid ) {
290307 return intResult ;
291308 }
292-
309+
293310 const num = parseInt ( value , 10 ) ;
294311 if ( num <= 0 ) {
295312 return ValidationResult . error ( "positiveInteger must be > 0" ) ;
@@ -302,7 +319,7 @@ export class BuiltinTypes {
302319 if ( ! nonNegResult . isValid ) {
303320 return nonNegResult ;
304321 }
305-
322+
306323 const num = parseInt ( value , 10 ) ;
307324 if ( num > 18446744073709551615 ) {
308325 return ValidationResult . error ( "unsignedLong value out of range" ) ;
@@ -315,7 +332,7 @@ export class BuiltinTypes {
315332 if ( ! nonNegResult . isValid ) {
316333 return nonNegResult ;
317334 }
318-
335+
319336 const num = parseInt ( value , 10 ) ;
320337 if ( num > 4294967295 ) {
321338 return ValidationResult . error ( "unsignedInt value out of range" ) ;
@@ -328,7 +345,7 @@ export class BuiltinTypes {
328345 if ( ! nonNegResult . isValid ) {
329346 return nonNegResult ;
330347 }
331-
348+
332349 const num = parseInt ( value , 10 ) ;
333350 if ( num > 65535 ) {
334351 return ValidationResult . error ( "unsignedShort value out of range" ) ;
@@ -341,7 +358,7 @@ export class BuiltinTypes {
341358 if ( ! nonNegResult . isValid ) {
342359 return nonNegResult ;
343360 }
344-
361+
345362 const num = parseInt ( value , 10 ) ;
346363 if ( num > 255 ) {
347364 return ValidationResult . error ( "unsignedByte value out of range" ) ;
@@ -353,7 +370,7 @@ export class BuiltinTypes {
353370 if ( value === "INF" || value === "-INF" || value === "NaN" ) {
354371 return ValidationResult . success ( ) ;
355372 }
356-
373+
357374 const num = parseFloat ( value ) ;
358375 if ( isNaN ( num ) ) {
359376 return ValidationResult . error ( "Invalid float format" ) ;
@@ -492,14 +509,14 @@ export class BuiltinTypes {
492509 if ( parts . length > 2 ) {
493510 return ValidationResult . error ( "QName can have at most one colon" ) ;
494511 }
495-
512+
496513 for ( const part of parts ) {
497514 const ncNameResult = BuiltinTypes . validateNCName ( part ) ;
498515 if ( ! ncNameResult . isValid ) {
499516 return ValidationResult . error ( "Invalid QName: " + ncNameResult . errors [ 0 ] . message ) ;
500517 }
501518 }
502-
519+
503520 return ValidationResult . success ( ) ;
504521 }
505522}
0 commit comments