A new version of WebClient-Core was added to project The Inbox: http://source.squeak.org/inbox/WebClient-Core-tpr.135.mcz
==================== Summary ====================
Name: WebClient-Core-tpr.135 Author: tpr Time: 29 October 2023, 5:55:50.903884 pm UUID: 04c4b5e6-fe5a-4d04-b6d1-1b3e25a0d85c Ancestors: WebClient-Core-tpr.134
A proposal to convert WebUtils to use Json instead of the older internal code. - divert #jsonEncode: to use Json render: - divert #jsonDecode: to use Json readFrom and check at the end for potential single-atom issue - divert #jsonFromString to String parseAsJson - remove all the theoretically now-unused methods. Relies upon JSON-ul.57
NB: we also seem to have some json related code deep in monticello classes. Maybe they should be looked at.
=============== Diff against WebClient-Core-tpr.134 ===============
Item was removed: - ----- Method: WebUtils class>>jsonArray:on: (in category 'json-encode') ----- - jsonArray: anArray on: stream - "Encodes an array" - - stream nextPut: $[. - anArray - do:[:each| self jsonObj: each on: stream] - separatedBy:[stream nextPutAll:', ']. - stream nextPut:$]. - !
Item was removed: - ----- Method: WebUtils class>>jsonArrayFrom: (in category 'json-decode') ----- - jsonArrayFrom: stream - "Decodes a JSON [value, *] array from the stream" - - | ch result | - (ch := stream next) = $[ ifFalse:[^self error: 'JSON Array expected']. - stream skipSeparators. - stream peek = $] ifTrue:[stream next. ^#()]. - result := WriteStream on: (Array new: 10). - ["Decode the next value" - stream skipSeparators. - result nextPut: (self jsonDecode: stream). - stream skipSeparators. - (ch := stream next) = $]] whileFalse:[ - ch = $, ifFalse:[^self error: 'Comma expected']. - ]. - - ^result contents!
Item was removed: - ----- Method: WebUtils class>>jsonChar:on: (in category 'json-encode') ----- - jsonChar: aCharacter on: stream - "Writes a single encoded character" - - | ascii | - ascii := aCharacter asciiValue. - - ascii < 32 ifTrue:["Control character" - ascii caseOf: { - [13] -> [^stream nextPutAll: '\r']. - [12] -> [^stream nextPutAll: '\f']. - [10] -> [^stream nextPutAll: '\n']. - [9] -> [^stream nextPutAll: '\t']. - [8] -> [^stream nextPutAll: '\b']. - } otherwise:[ - ^stream nextPutAll: '\u'; nextPutAll: - ((ascii printStringBase: 16) padded: #left to: 4 with: $0) - ]. - ]. - - (ascii >= 32 and:[ascii <=127]) ifTrue:["Ascii character" - (ascii = 34 or:[ascii = 92 or:[ascii = 47]]) ifTrue:[stream nextPut: $]. - ^stream nextPut: aCharacter - ]. - - "Encode other characters (control chars, accents, umlauts, unicode)" - stream nextPutAll: - '\u', (((ascii bitAnd: 16rFFFF) printStringBase: 16) padded: #left to: 4 with: $0). - !
Item was removed: - ----- Method: WebUtils class>>jsonCharFrom: (in category 'json-decode') ----- - jsonCharFrom: stream - "Decodes a backslash-escaped character" - - | ch | - ^(ch := stream next) caseOf: { - [$u] -> [Unicode value: - (Integer readFrom: (stream next: 4) readStream base: 16)]. - [$r] -> [Character cr]. - [$n] -> [Character lf]. - [$t] -> [Character tab]. - [$b] -> [Character backspace]. - [$f] -> [Character newPage]. - } otherwise:[ch]. - !
Item was changed: ----- Method: WebUtils class>>jsonDecode: (in category 'json-decode') ----- jsonDecode: stream + "Decodes an arbitrary JSON encoded value from the given stream. + Checks the stream atEnd in order to catch some mildly obscure single-atom input errors" - "Decodes an arbitrary JSON encoded value from the given stream"
+ | parser result | + parser := Json new. + result := parser readFrom: stream. + stream atEnd ifFalse: [ parser invalid: 'Unexpected data at end of input' ]. + ^result! - stream skipSeparators. - ^stream peek caseOf: { - [$"] -> [self jsonStringFrom: stream]. - [$t] -> [self jsonTrueFrom: stream]. - [$f] -> [self jsonFalseFrom: stream]. - [$n] -> [self jsonNullFrom: stream]. - [${] -> [self jsonMapFrom: stream]. - [$[] -> [self jsonArrayFrom: stream]. - } otherwise:[self jsonNumberFrom: stream]. - !
Item was changed: ----- Method: WebUtils class>>jsonEncode: (in category 'json-encode') ----- jsonEncode: anObject "Encode the given object as JSON"
+ ^Json render: anObject! - ^String streamContents:[:s| self jsonObj: anObject on: s]!
Item was removed: - ----- Method: WebUtils class>>jsonFalseFrom: (in category 'json-decode') ----- - jsonFalseFrom: stream - "Decodes 'false' from aStream" - - ((stream next: 5) = 'false' - and:[stream atEnd or:[stream peek isAlphaNumeric not]]) - ifFalse:[^self error: 'Expected ''false''']. - ^false!
Item was removed: - ----- Method: WebUtils class>>jsonFloatSignificand:exp10: (in category 'json-decode') ----- - jsonFloatSignificand: value exp10: exponent - "Take care to convert to nearest Float" - ^self jsonFloatSignificand: value exp10: exponent scale: (10 raisedTo: exponent abs)!
Item was removed: - ----- Method: WebUtils class>>jsonFloatSignificand:exp10:scale: (in category 'json-decode') ----- - jsonFloatSignificand: value exp10: exponent scale: scale - "Take care to convert to nearest Float" - "self assert: scale = (10 raisedTo: exponent abs)." - ^(value isAnExactFloat and: ["scale isAnExactFloat" - exponent between: -22 and: 22 - "(1 to: 100) detect: [:i | (10 raisedTo: i) isAnExactFloat not]"]) - ifTrue: [exponent >= 0 - ifTrue: [value asExactFloat * scale asExactFloat] - ifFalse: [value asExactFloat / scale asExactFloat]] - ifFalse: [exponent >= 0 - ifTrue: [(value * scale) asFloat] - ifFalse: [(Fraction numerator: value denominator: scale) asFloat]]!
Item was changed: ----- Method: WebUtils class>>jsonFromString: (in category 'json-decode') ----- jsonFromString: aString
+ ^aString parseAsJson! - ^ self jsonDecode: aString readStream!
Item was removed: - ----- Method: WebUtils class>>jsonMap:on: (in category 'json-encode') ----- - jsonMap: aDictionary on: stream - "Encodes a dictionary" - - stream nextPut: ${. - "Sorting keys ensures deterministic order" - aDictionary keys asArray sort do:[:key| - self jsonString: key on: stream. - stream nextPutAll:': '. - self jsonObj: (aDictionary at: key) on: stream. - ] separatedBy:[stream nextPutAll: ', ']. - stream nextPut: $}.!
Item was removed: - ----- Method: WebUtils class>>jsonMapFrom: (in category 'json-decode') ----- - jsonMapFrom: stream - "Decodes a JSON {key:value, *} object from the stream" - - | map ch key value | - map := Dictionary new. - (ch := stream next) = ${ ifFalse:[^self error: 'JSON Object expected']. - stream skipSeparators. - stream peek = $} ifTrue:[^map]. - - ["Decode the next key:value pair" - stream skipSeparators. - key := self jsonStringFrom: stream. - stream skipSeparators. - stream next = $: ifFalse:[^self error: 'Key-value pair expected']. - value := self jsonDecode: stream. - map at: key put: value. - stream skipSeparators. - (ch := stream next) = $}] whileFalse:[ - ch = $, ifFalse:[^self error: 'Comma expected']. - ]. - - ^map!
Item was removed: - ----- Method: WebUtils class>>jsonNullFrom: (in category 'json-decode') ----- - jsonNullFrom: stream - "Decodes 'null' from aStream" - - ((stream next: 4) = 'null' - and:[stream atEnd or:[stream peek isAlphaNumeric not]]) - ifFalse:[^self error: 'Expected ''null''']. - ^nil!
Item was removed: - ----- Method: WebUtils class>>jsonNumber:on: (in category 'json-encode') ----- - jsonNumber: aNumber on: stream - "Encodes a number" - - | value | - value := aNumber. - value isInteger ifFalse:[value := aNumber asFloat]. - stream print: aNumber. - !
Item was removed: - ----- Method: WebUtils class>>jsonNumberFrom: (in category 'json-decode') ----- - jsonNumberFrom: stream - "Decodes a JSON number from the stream" - - | ascii ch integer fraction scale sign expSign exponent exp value beFloat | - integer := fraction := exponent := exp := 0. sign := scale := expSign := 1. - ascii := stream next asciiValue. - ascii = 45 "$- asciiValue" ifTrue:[ - sign := -1. - ascii := stream next asciiValue. - ]. - "JSON requires at least one digit" - (ascii >= 48 and:[ascii <= 57]) ifFalse:[^self error: 'Digit expected']. - - "Read the integer part" - integer := ascii - 48. - [ch := stream next ifNil:[^integer * sign]. - ascii := ch asciiValue. - ascii >= 48 and:[ascii <= 57]] whileTrue:[ - integer := (integer * 10) + (ascii - 48). - ]. - - (beFloat := ascii = 46) "$. asciiValue" ifTrue:[ - "Read the fraction part" - [ch := stream next ifNil: - [value := integer * scale + fraction * sign. - ^self jsonFloatSignificand: value exp10: exponent scale: scale]. - ascii := ch asciiValue. - ascii >= 48 and:[ascii <= 57]] whileTrue:[ - fraction := (fraction * 10) + (ascii - 48). - exponent := exponent - 1. - scale := scale * 10. - ]. - value := integer * scale + fraction * sign. - ] ifFalse:[value := integer * sign]. - (ascii = 69 "$E asciiValue" or:[ascii = 101 "$e asciiValue"]) ifTrue:[ - "Read exponent" - ascii := stream next asciiValue. - ascii = 45 "$- asciiValue" ifTrue:[ - expSign := -1. - ascii := stream next asciiValue. - ] ifFalse:[ascii = 43 "$+ asciiValue" ifTrue:[ascii := stream next asciiValue]]. - exp := ascii - 48. - [ch := stream next ifNil: - [exponent := exp * expSign + exponent. - (beFloat or: [expSign = -1]) ifTrue: [^self jsonFloatSignificand: value exp10: exponent]. - ^value * (10 raisedTo: exponent)]. - ascii := ch asciiValue. - ascii >= 48 and:[ascii <= 57]] whileTrue:[ - exp := (exp * 10) + (ascii - 48). - ]. - exponent := exp * expSign + exponent - ]. - - "Skip back before last character since number might be part of a sequence - like 1, 2, 3, 4, etc (which would eat the trailing comma)" - ch isAlphaNumeric ifTrue:[^self error: 'Delimiter expected']. - stream skip: -1. - - (beFloat or: [expSign = -1]) ifTrue: [^self jsonFloatSignificand: value exp10: exponent]. - ^value * (10 raisedTo: exponent)!
Item was removed: - ----- Method: WebUtils class>>jsonObj:on: (in category 'json-encode') ----- - jsonObj: anObject on: stream - "Encode a generic object" - - anObject isString ifTrue:[^self jsonString: anObject on: stream]. - anObject isNumber ifTrue:[^self jsonNumber: anObject on: stream]. - anObject == nil ifTrue:[^stream nextPutAll: 'null']. - anObject == true ifTrue:[^stream nextPutAll: 'true']. - anObject == false ifTrue:[^stream nextPutAll: 'false']. - anObject isArray ifTrue:[^self jsonArray: anObject on: stream]. - anObject isDictionary ifTrue:[^self jsonMap: anObject on: stream]. - - self error: 'Cannot encode: ', anObject!
Item was removed: - ----- Method: WebUtils class>>jsonString:on: (in category 'json-encode') ----- - jsonString: aString on: stream - "Encodes a string" - - stream nextPut: $". - aString do:[:ch| self jsonChar: ch on: stream]. - stream nextPut: $". - !
Item was removed: - ----- Method: WebUtils class>>jsonStringFrom: (in category 'json-decode') ----- - jsonStringFrom: stream - "Decodes a JSON encoded string" - - | ch result | - (ch := stream next) = $" - ifFalse:[^self error: 'String expected']. - result := WriteStream on: (String new: 20). - [(ch := stream next) == nil] whileFalse:[ - ch = $" ifTrue:[^result contents]. - ch = $\ ifTrue:[ch := self jsonCharFrom: stream]. - result nextPut: ch. - ]. - ^self error: 'Unterminated string'!
Item was removed: - ----- Method: WebUtils class>>jsonTrueFrom: (in category 'json-decode') ----- - jsonTrueFrom: stream - "Decodes 'true' from aStream" - - ((stream next: 4) = 'true' - and:[stream atEnd or:[stream peek isAlphaNumeric not]]) - ifFalse:[^self error: 'Expected ''true''']. - ^true!
squeak-dev@lists.squeakfoundation.org