From 8a5bd0275b9d2153fa5c00502c4931f96824797e Mon Sep 17 00:00:00 2001 From: Troy Sornson Date: Tue, 27 May 2025 22:51:16 -0600 Subject: [PATCH 1/4] Add type restrictions to json --- src/json/any.cr | 14 +++++++------- src/json/builder.cr | 6 +++--- src/json/from_json.cr | 20 ++++++++++---------- src/json/lexer.cr | 4 ++-- src/json/lexer/string_based.cr | 4 ++-- src/json/pull_parser.cr | 10 +++++----- src/json/to_json.cr | 2 +- 7 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/json/any.cr b/src/json/any.cr index 61a4118ee932..3d9cd8f9ef8d 100644 --- a/src/json/any.cr +++ b/src/json/any.cr @@ -21,7 +21,7 @@ struct JSON::Any alias Type = Nil | Bool | Int64 | Float64 | String | Array(JSON::Any) | Hash(String, JSON::Any) # Reads a `JSON::Any` value from the given pull parser. - def self.new(pull : JSON::PullParser) + def self.new(pull : JSON::PullParser) : self case pull.kind when .null? new pull.read_null @@ -58,13 +58,13 @@ struct JSON::Any end # :ditto: - def self.new(raw : Int) + def self.new(raw : Int) : self # FIXME: Workaround for https://github.com/crystal-lang/crystal/issues/11645 new(raw.to_i64) end # :ditto: - def self.new(raw : Float) + def self.new(raw : Float) : self # FIXME: Workaround for https://github.com/crystal-lang/crystal/issues/11645 new(raw.to_f64) end @@ -130,7 +130,7 @@ struct JSON::Any # Traverses the depth of a structure and returns the value. # Returns `nil` if not found. - def dig?(index_or_key : String | Int, *subkeys) : JSON::Any? + def dig?(index_or_key : String | Int, *subkeys : Int | String) : JSON::Any? self[index_or_key]?.try &.dig?(*subkeys) end @@ -145,7 +145,7 @@ struct JSON::Any end # Traverses the depth of a structure and returns the value, otherwise raises. - def dig(index_or_key : String | Int, *subkeys) : JSON::Any + def dig(index_or_key : String | Int, *subkeys : Int | String) : JSON::Any self[index_or_key].dig(*subkeys) end @@ -305,7 +305,7 @@ struct JSON::Any def_hash raw # :nodoc: - def to_json(json : JSON::Builder) + def to_json(json : JSON::Builder) : Nil raw.to_json(json) end @@ -319,7 +319,7 @@ struct JSON::Any end # Returns a new JSON::Any instance with the `raw` value `clone`ed. - def clone + def clone : JSON::Any JSON::Any.new(raw.clone) end end diff --git a/src/json/builder.cr b/src/json/builder.cr index c1dc2c39c8e8..719622503b34 100644 --- a/src/json/builder.cr +++ b/src/json/builder.cr @@ -277,7 +277,7 @@ class JSON::Builder # Writes an object's field and value. # The field's name is first converted to a `String` by invoking # `to_s` on it. - def field(name, value) + def field(name : String | Int32, value) : Nil string(name) value.to_json(self) end @@ -296,7 +296,7 @@ class JSON::Builder end # Sets the indent *string*. - def indent=(string : String) + def indent=(string : String) : String? if string.empty? @indent = nil else @@ -305,7 +305,7 @@ class JSON::Builder end # Sets the indent *level* (number of spaces). - def indent=(level : Int) + def indent=(level : Int) : String? if level < 0 @indent = nil else diff --git a/src/json/from_json.cr b/src/json/from_json.cr index 92edf0472c77..c2e3aa3db44c 100644 --- a/src/json/from_json.cr +++ b/src/json/from_json.cr @@ -8,7 +8,7 @@ # Int32.from_json("1") # => 1 # Array(Int32).from_json("[1, 2, 3]") # => [1, 2, 3] # ``` -def Object.from_json(string_or_io) +def Object.from_json(string_or_io : String | IO) : Object parser = JSON::PullParser.new(string_or_io) new parser end @@ -21,7 +21,7 @@ end # ``` # Int32.from_json(%({"main": 1}), root: "main") # => 1 # ``` -def Object.from_json(string_or_io, root : String) +def Object.from_json(string_or_io : String | IO, root : String) : Object parser = JSON::PullParser.new(string_or_io) parser.on_key!(root) do new parser @@ -116,11 +116,11 @@ module Iterator(T) end end -def Nil.new(pull : JSON::PullParser) +def Nil.new(pull : JSON::PullParser) : Nil pull.read_null end -def Bool.new(pull : JSON::PullParser) +def Bool.new(pull : JSON::PullParser) : Bool pull.read_bool end @@ -157,7 +157,7 @@ end end {% end %} -def Float32.new(pull : JSON::PullParser) +def Float32.new(pull : JSON::PullParser) : Float32 case pull.kind when .int? value = pull.int_value.to_f32 @@ -172,7 +172,7 @@ def Float32.from_json_object_key?(key : String) : Float32? key.to_f32? end -def Float64.new(pull : JSON::PullParser) +def Float64.new(pull : JSON::PullParser) : Float64 case pull.kind when .int? value = pull.int_value.to_f @@ -187,11 +187,11 @@ def Float64.from_json_object_key?(key : String) : Float64? key.to_f64? end -def String.new(pull : JSON::PullParser) +def String.new(pull : JSON::PullParser) : String pull.read_string end -def Path.new(pull : JSON::PullParser) +def Path.new(pull : JSON::PullParser) : Path new(pull.read_string) end @@ -315,7 +315,7 @@ end # See `#to_json` for reference. # # Raises `JSON::ParseException` if the deserialization fails. -def Enum.new(pull : JSON::PullParser) +def Enum.new(pull : JSON::PullParser) : self {% if @type.annotation(Flags) %} value = {{ @type }}::None pull.read_array do @@ -470,7 +470,7 @@ end # time value. # # See `#to_json` for reference. -def Time.new(pull : JSON::PullParser) +def Time.new(pull : JSON::PullParser) : Time Time::Format::ISO_8601_DATE_TIME.parse(pull.read_string) end diff --git a/src/json/lexer.cr b/src/json/lexer.cr index 3e61179b9844..664a98c99aea 100644 --- a/src/json/lexer.cr +++ b/src/json/lexer.cr @@ -1,11 +1,11 @@ require "string_pool" abstract class JSON::Lexer - def self.new(string : String) + def self.new(string : String) : self StringBased.new(string) end - def self.new(io : IO) + def self.new(io : IO) : self IOBased.new(io) end diff --git a/src/json/lexer/string_based.cr b/src/json/lexer/string_based.cr index 5696bc6f78b2..32c7f0e40d5c 100644 --- a/src/json/lexer/string_based.cr +++ b/src/json/lexer/string_based.cr @@ -50,11 +50,11 @@ class JSON::Lexer::StringBased < JSON::Lexer @reader.pos end - def string_range(start_pos, end_pos) : String + def string_range(start_pos : Int, end_pos : Int) : String @reader.string.byte_slice(start_pos, end_pos - start_pos) end - def slice_range(start_pos, end_pos) : Bytes + def slice_range(start_pos : Int, end_pos : Int) : Bytes @reader.string.to_slice[start_pos, end_pos - start_pos] end diff --git a/src/json/pull_parser.cr b/src/json/pull_parser.cr index a4c5b4797bd4..4b07ac442cb4 100644 --- a/src/json/pull_parser.cr +++ b/src/json/pull_parser.cr @@ -137,13 +137,13 @@ class JSON::PullParser end # Reads the beginning of an array. - def read_begin_array + def read_begin_array : JSON::PullParser::Kind expect_kind :begin_array read_next end # Reads the end of an array. - def read_end_array + def read_end_array : JSON::PullParser::Kind expect_kind :end_array read_next end @@ -163,13 +163,13 @@ class JSON::PullParser end # Reads the beginning of an object. - def read_begin_object + def read_begin_object : JSON::PullParser::Kind expect_kind :begin_object read_next end # Reads the end of an object. - def read_end_object + def read_end_object : JSON::PullParser::Kind expect_kind :end_object read_next end @@ -268,7 +268,7 @@ class JSON::PullParser # Reads the new value and fill the a JSONĀ builder with it. # # Use this method with a `JSON::Builder` to read a JSON while building another one. - def read_raw(json) : Nil + def read_raw(json : JSON::Builder) : Nil case @kind when .null? read_next diff --git a/src/json/to_json.cr b/src/json/to_json.cr index 7e52b5663786..529d99c34f48 100644 --- a/src/json/to_json.cr +++ b/src/json/to_json.cr @@ -215,7 +215,7 @@ struct Enum # # `ValueConverter.to_json` offers a different serialization strategy based on the # member value. - def to_json(json : JSON::Builder) + def to_json(json : JSON::Builder) : Nil {% if @type.annotation(Flags) %} json.array do each do |member, _value| From eb754b0964f604882ede9cd054eefa144991686f Mon Sep 17 00:00:00 2001 From: Troy Sornson Date: Tue, 27 May 2025 22:57:40 -0600 Subject: [PATCH 2/4] Flatten long union types --- src/json/builder.cr | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/json/builder.cr b/src/json/builder.cr index 719622503b34..004385184540 100644 --- a/src/json/builder.cr +++ b/src/json/builder.cr @@ -110,7 +110,7 @@ class JSON::Builder # ``` # # This method can also be used to write the name of an object field. - def string(value) : Nil + def string(value : _) : Nil string do |io| value.to_s(io) end @@ -277,7 +277,7 @@ class JSON::Builder # Writes an object's field and value. # The field's name is first converted to a `String` by invoking # `to_s` on it. - def field(name : String | Int32, value) : Nil + def field(name : String | Int32, value : _) : Nil string(name) value.to_json(self) end @@ -291,7 +291,7 @@ class JSON::Builder end # Flushes the underlying `IO`. - def flush + def flush : IO? @io.flush end From 2a818d9663142dc2dfeb380c87fce307a0d5227c Mon Sep 17 00:00:00 2001 From: Troy Sornson Date: Thu, 29 May 2025 19:56:42 -0600 Subject: [PATCH 3/4] Review comments --- src/json/any.cr | 8 ++++---- src/json/builder.cr | 4 ++-- src/json/from_json.cr | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/json/any.cr b/src/json/any.cr index 3d9cd8f9ef8d..bf0425b5fa01 100644 --- a/src/json/any.cr +++ b/src/json/any.cr @@ -130,12 +130,12 @@ struct JSON::Any # Traverses the depth of a structure and returns the value. # Returns `nil` if not found. - def dig?(index_or_key : String | Int, *subkeys : Int | String) : JSON::Any? + def dig?(index_or_key : Int | String, *subkeys : Int | String) : JSON::Any? self[index_or_key]?.try &.dig?(*subkeys) end # :nodoc: - def dig?(index_or_key : String | Int) : JSON::Any? + def dig?(index_or_key : Int | String) : JSON::Any? case @raw when Hash, Array self[index_or_key]? @@ -145,12 +145,12 @@ struct JSON::Any end # Traverses the depth of a structure and returns the value, otherwise raises. - def dig(index_or_key : String | Int, *subkeys : Int | String) : JSON::Any + def dig(index_or_key : Int | String, *subkeys : Int | String) : JSON::Any self[index_or_key].dig(*subkeys) end # :nodoc: - def dig(index_or_key : String | Int) : JSON::Any + def dig(index_or_key : Int | String) : JSON::Any self[index_or_key] end diff --git a/src/json/builder.cr b/src/json/builder.cr index 004385184540..0012fde2583f 100644 --- a/src/json/builder.cr +++ b/src/json/builder.cr @@ -277,7 +277,7 @@ class JSON::Builder # Writes an object's field and value. # The field's name is first converted to a `String` by invoking # `to_s` on it. - def field(name : String | Int32, value : _) : Nil + def field(name : _, value : _) : Nil string(name) value.to_json(self) end @@ -291,7 +291,7 @@ class JSON::Builder end # Flushes the underlying `IO`. - def flush : IO? + def flush : Nil @io.flush end diff --git a/src/json/from_json.cr b/src/json/from_json.cr index c2e3aa3db44c..5e682067068d 100644 --- a/src/json/from_json.cr +++ b/src/json/from_json.cr @@ -116,11 +116,11 @@ module Iterator(T) end end -def Nil.new(pull : JSON::PullParser) : Nil +def Nil.new(pull : JSON::PullParser) : self pull.read_null end -def Bool.new(pull : JSON::PullParser) : Bool +def Bool.new(pull : JSON::PullParser) : self pull.read_bool end @@ -172,7 +172,7 @@ def Float32.from_json_object_key?(key : String) : Float32? key.to_f32? end -def Float64.new(pull : JSON::PullParser) : Float64 +def Float64.new(pull : JSON::PullParser) : self case pull.kind when .int? value = pull.int_value.to_f @@ -187,11 +187,11 @@ def Float64.from_json_object_key?(key : String) : Float64? key.to_f64? end -def String.new(pull : JSON::PullParser) : String +def String.new(pull : JSON::PullParser) : self pull.read_string end -def Path.new(pull : JSON::PullParser) : Path +def Path.new(pull : JSON::PullParser) : self new(pull.read_string) end @@ -470,7 +470,7 @@ end # time value. # # See `#to_json` for reference. -def Time.new(pull : JSON::PullParser) : Time +def Time.new(pull : JSON::PullParser) : self Time::Format::ISO_8601_DATE_TIME.parse(pull.read_string) end From 004666d6a74d6627df0f4a8018592233a8cdff07 Mon Sep 17 00:00:00 2001 From: Troy Sornson Date: Thu, 29 May 2025 19:59:42 -0600 Subject: [PATCH 4/4] Update missed constructor --- src/json/from_json.cr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/json/from_json.cr b/src/json/from_json.cr index 5e682067068d..179b55b4b274 100644 --- a/src/json/from_json.cr +++ b/src/json/from_json.cr @@ -157,7 +157,7 @@ end end {% end %} -def Float32.new(pull : JSON::PullParser) : Float32 +def Float32.new(pull : JSON::PullParser) : self case pull.kind when .int? value = pull.int_value.to_f32