@@ -5784,14 +5784,15 @@ function makeParserClass (Parser) {
5784
5784
let target = this . ctx
5785
5785
let finalKey = kv . key . pop ( )
5786
5786
for ( let kw of kv . key ) {
5787
- if ( hasKey ( target , kw ) && ( ! isTable ( target [ kw ] ) || target [ kw ] [ _declared ] ) ) {
5787
+ if ( hasKey ( target , kw ) && ! isTable ( target [ kw ] ) ) {
5788
5788
throw this . error ( new TomlError ( "Can't redefine existing key" ) )
5789
5789
}
5790
5790
target = target [ kw ] = target [ kw ] || Table ( )
5791
5791
}
5792
5792
if ( hasKey ( target , finalKey ) ) {
5793
5793
throw this . error ( new TomlError ( "Can't redefine existing key" ) )
5794
5794
}
5795
+ target [ _declared ] = true
5795
5796
// unbox our numbers
5796
5797
if ( isInteger ( kv . value ) || isFloat ( kv . value ) ) {
5797
5798
target [ finalKey ] = kv . value . valueOf ( )
@@ -5849,6 +5850,8 @@ function makeParserClass (Parser) {
5849
5850
do {
5850
5851
if ( this . char === Parser . END || this . char === CTRL_J ) {
5851
5852
return this . return ( )
5853
+ } else if ( this . char === CHAR_DEL || ( this . char <= CTRL_CHAR_BOUNDARY && this . char !== CTRL_I ) ) {
5854
+ throw this . errorControlCharIn ( 'comments' )
5852
5855
}
5853
5856
} while ( this . nextChar ( ) )
5854
5857
}
@@ -6062,7 +6065,7 @@ function makeParserClass (Parser) {
6062
6065
} else if ( this . atEndOfLine ( ) ) {
6063
6066
throw this . error ( new TomlError ( 'Unterminated string' ) )
6064
6067
} else if ( this . char === CHAR_DEL || ( this . char <= CTRL_CHAR_BOUNDARY && this . char !== CTRL_I ) ) {
6065
- throw this . errorControlCharInString ( )
6068
+ throw this . errorControlCharIn ( 'strings' )
6066
6069
} else {
6067
6070
this . consume ( )
6068
6071
}
@@ -6091,7 +6094,7 @@ function makeParserClass (Parser) {
6091
6094
} else if ( this . char === Parser . END ) {
6092
6095
throw this . error ( new TomlError ( 'Unterminated multi-line string' ) )
6093
6096
} else if ( this . char === CHAR_DEL || ( this . char <= CTRL_CHAR_BOUNDARY && this . char !== CTRL_I && this . char !== CTRL_J && this . char !== CTRL_M ) ) {
6094
- throw this . errorControlCharInString ( )
6097
+ throw this . errorControlCharIn ( 'strings' )
6095
6098
} else {
6096
6099
this . consume ( )
6097
6100
}
@@ -6107,12 +6110,28 @@ function makeParserClass (Parser) {
6107
6110
}
6108
6111
parseLiteralMultiEnd2 ( ) {
6109
6112
if ( this . char === CHAR_APOS ) {
6110
- return this . return ( )
6113
+ return this . next ( this . parseLiteralMultiEnd3 )
6111
6114
} else {
6112
6115
this . state . buf += "''"
6113
6116
return this . goto ( this . parseLiteralMultiStringContent )
6114
6117
}
6115
6118
}
6119
+ parseLiteralMultiEnd3 ( ) {
6120
+ if ( this . char === CHAR_APOS ) {
6121
+ this . state . buf += "'"
6122
+ return this . next ( this . parseLiteralMultiEnd4 )
6123
+ } else {
6124
+ return this . returnNow ( )
6125
+ }
6126
+ }
6127
+ parseLiteralMultiEnd4 ( ) {
6128
+ if ( this . char === CHAR_APOS ) {
6129
+ this . state . buf += "'"
6130
+ return this . return ( )
6131
+ } else {
6132
+ return this . returnNow ( )
6133
+ }
6134
+ }
6116
6135
6117
6136
/* STRINGS double quoted */
6118
6137
parseDoubleString ( ) {
@@ -6131,7 +6150,7 @@ function makeParserClass (Parser) {
6131
6150
} else if ( this . atEndOfLine ( ) ) {
6132
6151
throw this . error ( new TomlError ( 'Unterminated string' ) )
6133
6152
} else if ( this . char === CHAR_DEL || ( this . char <= CTRL_CHAR_BOUNDARY && this . char !== CTRL_I ) ) {
6134
- throw this . errorControlCharInString ( )
6153
+ throw this . errorControlCharIn ( 'strings' )
6135
6154
} else {
6136
6155
this . consume ( )
6137
6156
}
@@ -6166,20 +6185,20 @@ function makeParserClass (Parser) {
6166
6185
} else if ( this . char === Parser . END ) {
6167
6186
throw this . error ( new TomlError ( 'Unterminated multi-line string' ) )
6168
6187
} else if ( this . char === CHAR_DEL || ( this . char <= CTRL_CHAR_BOUNDARY && this . char !== CTRL_I && this . char !== CTRL_J && this . char !== CTRL_M ) ) {
6169
- throw this . errorControlCharInString ( )
6188
+ throw this . errorControlCharIn ( 'strings' )
6170
6189
} else {
6171
6190
this . consume ( )
6172
6191
}
6173
6192
} while ( this . nextChar ( ) )
6174
6193
}
6175
- errorControlCharInString ( ) {
6194
+ errorControlCharIn ( type ) {
6176
6195
let displayCode = '\\u00'
6177
6196
if ( this . char < 16 ) {
6178
6197
displayCode += '0'
6179
6198
}
6180
6199
displayCode += this . char . toString ( 16 )
6181
6200
6182
- return this . error ( new TomlError ( `Control characters (codes < 0x1f and 0x7f) are not allowed in strings , use ${ displayCode } instead` ) )
6201
+ return this . error ( new TomlError ( `Control characters (codes < 0x1f and 0x7f) are not allowed in ${ type } , use ${ displayCode } instead` ) )
6183
6202
}
6184
6203
recordMultiEscapeReplacement ( replacement ) {
6185
6204
this . state . buf += replacement
@@ -6195,12 +6214,28 @@ function makeParserClass (Parser) {
6195
6214
}
6196
6215
parseMultiEnd2 ( ) {
6197
6216
if ( this . char === CHAR_QUOT ) {
6198
- return this . return ( )
6217
+ return this . next ( this . parseMultiEnd3 )
6199
6218
} else {
6200
6219
this . state . buf += '""'
6201
6220
return this . goto ( this . parseMultiStringContent )
6202
6221
}
6203
6222
}
6223
+ parseMultiEnd3 ( ) {
6224
+ if ( this . char === CHAR_QUOT ) {
6225
+ this . state . buf += '"'
6226
+ return this . next ( this . parseMultiEnd4 )
6227
+ } else {
6228
+ return this . returnNow ( )
6229
+ }
6230
+ }
6231
+ parseMultiEnd4 ( ) {
6232
+ if ( this . char === CHAR_QUOT ) {
6233
+ this . state . buf += '"'
6234
+ return this . return ( )
6235
+ } else {
6236
+ return this . returnNow ( )
6237
+ }
6238
+ }
6204
6239
parseMultiEscape ( ) {
6205
6240
if ( this . char === CTRL_M || this . char === CTRL_J ) {
6206
6241
return this . next ( this . parseMultiTrim )
@@ -6762,13 +6797,7 @@ function makeParserClass (Parser) {
6762
6797
}
6763
6798
}
6764
6799
recordInlineListValue ( value ) {
6765
- if ( this . state . resultArr ) {
6766
- const listType = this . state . resultArr [ _contentType ]
6767
- const valueType = tomlType ( value )
6768
- if ( listType !== valueType ) {
6769
- throw this . error ( new TomlError ( `Inline lists must be a single type, not a mix of ${ listType } and ${ valueType } ` ) )
6770
- }
6771
- } else {
6800
+ if ( ! this . state . resultArr ) {
6772
6801
this . state . resultArr = InlineList ( tomlType ( value ) )
6773
6802
}
6774
6803
if ( isFloat ( value ) || isInteger ( value ) ) {
@@ -6831,13 +6860,26 @@ function makeParserClass (Parser) {
6831
6860
} else if ( this . char === Parser . END || this . char === CHAR_NUM || this . char === CTRL_J || this . char === CTRL_M ) {
6832
6861
throw this . error ( new TomlError ( 'Unterminated inline array' ) )
6833
6862
} else if ( this . char === CHAR_COMMA ) {
6834
- return this . next ( this . parseInlineTable )
6863
+ return this . next ( this . parseInlineTablePostComma )
6835
6864
} else if ( this . char === CHAR_RCUB ) {
6836
6865
return this . goto ( this . parseInlineTable )
6837
6866
} else {
6838
6867
throw this . error ( new TomlError ( 'Invalid character, expected whitespace, comma (,) or close bracket (])' ) )
6839
6868
}
6840
6869
}
6870
+ parseInlineTablePostComma ( ) {
6871
+ if ( this . char === CHAR_SP || this . char === CTRL_I ) {
6872
+ return null
6873
+ } else if ( this . char === Parser . END || this . char === CHAR_NUM || this . char === CTRL_J || this . char === CTRL_M ) {
6874
+ throw this . error ( new TomlError ( 'Unterminated inline array' ) )
6875
+ } else if ( this . char === CHAR_COMMA ) {
6876
+ throw this . error ( new TomlError ( 'Empty elements in inline tables are not permitted' ) )
6877
+ } else if ( this . char === CHAR_RCUB ) {
6878
+ throw this . error ( new TomlError ( 'Trailing commas in inline tables are not permitted' ) )
6879
+ } else {
6880
+ return this . goto ( this . parseInlineTable )
6881
+ }
6882
+ }
6841
6883
}
6842
6884
return TOMLParser
6843
6885
}
@@ -7075,10 +7117,6 @@ function typeError (type) {
7075
7117
return new Error ( 'Can only stringify objects, not ' + type )
7076
7118
}
7077
7119
7078
- function arrayOneTypeError ( ) {
7079
- return new Error ( "Array values can't have mixed types" )
7080
- }
7081
-
7082
7120
function getInlineKeys ( obj ) {
7083
7121
return Object . keys ( obj ) . filter ( key => isInline ( obj [ key ] ) )
7084
7122
}
@@ -7100,20 +7138,20 @@ function toJSON (obj) {
7100
7138
7101
7139
function stringifyObject ( prefix , indent , obj ) {
7102
7140
obj = toJSON ( obj )
7103
- var inlineKeys
7104
- var complexKeys
7141
+ let inlineKeys
7142
+ let complexKeys
7105
7143
inlineKeys = getInlineKeys ( obj )
7106
7144
complexKeys = getComplexKeys ( obj )
7107
- var result = [ ]
7108
- var inlineIndent = indent || ''
7145
+ const result = [ ]
7146
+ const inlineIndent = indent || ''
7109
7147
inlineKeys . forEach ( key => {
7110
7148
var type = tomlType ( obj [ key ] )
7111
7149
if ( type !== 'undefined' && type !== 'null' ) {
7112
7150
result . push ( inlineIndent + stringifyKey ( key ) + ' = ' + stringifyAnyInline ( obj [ key ] , true ) )
7113
7151
}
7114
7152
} )
7115
7153
if ( result . length > 0 ) result . push ( '' )
7116
- var complexIndent = prefix && inlineKeys . length > 0 ? indent + ' ' : ''
7154
+ const complexIndent = prefix && inlineKeys . length > 0 ? indent + ' ' : ''
7117
7155
complexKeys . forEach ( key => {
7118
7156
result . push ( stringifyComplex ( prefix , complexIndent , key , obj [ key ] ) )
7119
7157
} )
@@ -7165,7 +7203,7 @@ function tomlType (value) {
7165
7203
}
7166
7204
7167
7205
function stringifyKey ( key ) {
7168
- var keyStr = String ( key )
7206
+ const keyStr = String ( key )
7169
7207
if ( / ^ [ - A - Z a - z 0 - 9 _ ] + $ / . test ( keyStr ) ) {
7170
7208
return keyStr
7171
7209
} else {
@@ -7261,9 +7299,7 @@ function stringifyFloat (value) {
7261
7299
} else if ( Object . is ( value , - 0 ) ) {
7262
7300
return '-0.0'
7263
7301
}
7264
- var chunks = String ( value ) . split ( '.' )
7265
- var int = chunks [ 0 ]
7266
- var dec = chunks [ 1 ] || 0
7302
+ const [ int , dec ] = String ( value ) . split ( '.' )
7267
7303
return stringifyInteger ( int ) + '.' + dec
7268
7304
}
7269
7305
@@ -7275,29 +7311,10 @@ function stringifyDatetime (value) {
7275
7311
return value . toISOString ( )
7276
7312
}
7277
7313
7278
- function isNumber ( type ) {
7279
- return type === 'float' || type === 'integer'
7280
- }
7281
- function arrayType ( values ) {
7282
- var contentType = tomlType ( values [ 0 ] )
7283
- if ( values . every ( _ => tomlType ( _ ) === contentType ) ) return contentType
7284
- // mixed integer/float, emit as floats
7285
- if ( values . every ( _ => isNumber ( tomlType ( _ ) ) ) ) return 'float'
7286
- return 'mixed'
7287
- }
7288
- function validateArray ( values ) {
7289
- const type = arrayType ( values )
7290
- if ( type === 'mixed' ) {
7291
- throw arrayOneTypeError ( )
7292
- }
7293
- return type
7294
- }
7295
-
7296
7314
function stringifyInlineArray ( values ) {
7297
7315
values = toJSON ( values )
7298
- const type = validateArray ( values )
7299
- var result = '['
7300
- var stringified = values . map ( _ => stringifyInline ( _ , type ) )
7316
+ let result = '['
7317
+ const stringified = values . map ( _ => stringifyInline ( _ ) )
7301
7318
if ( stringified . join ( ', ' ) . length > 60 || / \n / . test ( stringified ) ) {
7302
7319
result += '\n ' + stringified . join ( ',\n ' ) + '\n'
7303
7320
} else {
@@ -7308,15 +7325,15 @@ function stringifyInlineArray (values) {
7308
7325
7309
7326
function stringifyInlineTable ( value ) {
7310
7327
value = toJSON ( value )
7311
- var result = [ ]
7328
+ const result = [ ]
7312
7329
Object . keys ( value ) . forEach ( key => {
7313
7330
result . push ( stringifyKey ( key ) + ' = ' + stringifyAnyInline ( value [ key ] , false ) )
7314
7331
} )
7315
7332
return '{ ' + result . join ( ', ' ) + ( result . length > 0 ? ' ' : '' ) + '}'
7316
7333
}
7317
7334
7318
7335
function stringifyComplex ( prefix , indent , key , value ) {
7319
- var valueType = tomlType ( value )
7336
+ const valueType = tomlType ( value )
7320
7337
/* istanbul ignore else */
7321
7338
if ( valueType === 'array' ) {
7322
7339
return stringifyArrayOfTables ( prefix , indent , key , value )
@@ -7329,12 +7346,11 @@ function stringifyComplex (prefix, indent, key, value) {
7329
7346
7330
7347
function stringifyArrayOfTables ( prefix , indent , key , values ) {
7331
7348
values = toJSON ( values )
7332
- validateArray ( values )
7333
- var firstValueType = tomlType ( values [ 0 ] )
7349
+ const firstValueType = tomlType ( values [ 0 ] )
7334
7350
/* istanbul ignore if */
7335
7351
if ( firstValueType !== 'table' ) throw typeError ( firstValueType )
7336
- var fullKey = prefix + stringifyKey ( key )
7337
- var result = ''
7352
+ const fullKey = prefix + stringifyKey ( key )
7353
+ let result = ''
7338
7354
values . forEach ( table => {
7339
7355
if ( result . length > 0 ) result += '\n'
7340
7356
result += indent + '[[' + fullKey + ']]\n'
@@ -7344,8 +7360,8 @@ function stringifyArrayOfTables (prefix, indent, key, values) {
7344
7360
}
7345
7361
7346
7362
function stringifyComplexTable ( prefix , indent , key , value ) {
7347
- var fullKey = prefix + stringifyKey ( key )
7348
- var result = ''
7363
+ const fullKey = prefix + stringifyKey ( key )
7364
+ let result = ''
7349
7365
if ( getInlineKeys ( value ) . length > 0 ) {
7350
7366
result += indent + '[' + fullKey + ']\n'
7351
7367
}
0 commit comments