From 78b0c199dead85f03e955409892cedf82bab4765 Mon Sep 17 00:00:00 2001 From: Louis Lambeau Date: Fri, 6 Jan 2023 23:15:45 +0100 Subject: [PATCH] Typescript generator. --- lib/finitio/typescript.rb | 20 ++++++ lib/finitio/typescript/ad_type.rb | 9 +++ lib/finitio/typescript/alias_type.rb | 9 +++ lib/finitio/typescript/any_type.rb | 9 +++ lib/finitio/typescript/builtin_type.rb | 32 ++++++++++ lib/finitio/typescript/hash_based_type.rb | 35 +++++++++++ lib/finitio/typescript/high_order_type.rb | 11 ++++ lib/finitio/typescript/proxy_type.rb | 13 ++++ lib/finitio/typescript/rel_based_type.rb | 9 +++ lib/finitio/typescript/seq_type.rb | 10 +++ lib/finitio/typescript/set_type.rb | 10 +++ lib/finitio/typescript/struct_type.rb | 10 +++ lib/finitio/typescript/sub_type.rb | 9 +++ lib/finitio/typescript/system.rb | 10 +++ lib/finitio/typescript/type.rb | 11 ++++ lib/finitio/typescript/union_type.rb | 21 +++++++ spec/spec_helper.rb | 5 ++ spec/typescript/test_ad_type.rb | 15 +++++ spec/typescript/test_alias_type.rb | 15 +++++ spec/typescript/test_any_type.rb | 11 ++++ spec/typescript/test_builtin_type.rb | 51 ++++++++++++++++ spec/typescript/test_multi_relation_type.rb | 39 ++++++++++++ spec/typescript/test_multi_tuple_type.rb | 39 ++++++++++++ spec/typescript/test_recursive_type.rb | 48 +++++++++++++++ spec/typescript/test_relation_type.rb | 19 ++++++ spec/typescript/test_seq_type.rb | 15 +++++ spec/typescript/test_set_type.rb | 15 +++++ spec/typescript/test_struct_type.rb | 15 +++++ spec/typescript/test_sub_type.rb | 15 +++++ spec/typescript/test_system.rb | 68 +++++++++++++++++++++ spec/typescript/test_tuple_type.rb | 18 ++++++ spec/typescript/test_union_type.rb | 67 ++++++++++++++++++++ tasks/test.rake | 2 +- 33 files changed, 684 insertions(+), 1 deletion(-) create mode 100644 lib/finitio/typescript.rb create mode 100644 lib/finitio/typescript/ad_type.rb create mode 100644 lib/finitio/typescript/alias_type.rb create mode 100644 lib/finitio/typescript/any_type.rb create mode 100644 lib/finitio/typescript/builtin_type.rb create mode 100644 lib/finitio/typescript/hash_based_type.rb create mode 100644 lib/finitio/typescript/high_order_type.rb create mode 100644 lib/finitio/typescript/proxy_type.rb create mode 100644 lib/finitio/typescript/rel_based_type.rb create mode 100644 lib/finitio/typescript/seq_type.rb create mode 100644 lib/finitio/typescript/set_type.rb create mode 100644 lib/finitio/typescript/struct_type.rb create mode 100644 lib/finitio/typescript/sub_type.rb create mode 100644 lib/finitio/typescript/system.rb create mode 100644 lib/finitio/typescript/type.rb create mode 100644 lib/finitio/typescript/union_type.rb create mode 100644 spec/typescript/test_ad_type.rb create mode 100644 spec/typescript/test_alias_type.rb create mode 100644 spec/typescript/test_any_type.rb create mode 100644 spec/typescript/test_builtin_type.rb create mode 100644 spec/typescript/test_multi_relation_type.rb create mode 100644 spec/typescript/test_multi_tuple_type.rb create mode 100644 spec/typescript/test_recursive_type.rb create mode 100644 spec/typescript/test_relation_type.rb create mode 100644 spec/typescript/test_seq_type.rb create mode 100644 spec/typescript/test_set_type.rb create mode 100644 spec/typescript/test_struct_type.rb create mode 100644 spec/typescript/test_sub_type.rb create mode 100644 spec/typescript/test_system.rb create mode 100644 spec/typescript/test_tuple_type.rb create mode 100644 spec/typescript/test_union_type.rb diff --git a/lib/finitio/typescript.rb b/lib/finitio/typescript.rb new file mode 100644 index 0000000..87e761d --- /dev/null +++ b/lib/finitio/typescript.rb @@ -0,0 +1,20 @@ +module Finitio + module Typescript + class Error < Finitio::Error; end + end # module Typescript +end # module Finitio +require_relative 'typescript/type' +require_relative 'typescript/ad_type' +require_relative 'typescript/any_type' +require_relative 'typescript/alias_type' +require_relative 'typescript/builtin_type' +require_relative 'typescript/hash_based_type' +require_relative 'typescript/high_order_type' +require_relative 'typescript/rel_based_type' +require_relative 'typescript/seq_type' +require_relative 'typescript/set_type' +require_relative 'typescript/struct_type' +require_relative 'typescript/sub_type' +require_relative 'typescript/union_type' +require_relative 'typescript/proxy_type' +require_relative 'typescript/system' diff --git a/lib/finitio/typescript/ad_type.rb b/lib/finitio/typescript/ad_type.rb new file mode 100644 index 0000000..7861acf --- /dev/null +++ b/lib/finitio/typescript/ad_type.rb @@ -0,0 +1,9 @@ +module Finitio + class AdType + + def to_typescript(*args, &bl) + contracts.map{|c| c.infotype.ts_name || c.infotype.to_typescript(*args, &bl) }.join('|') + end + + end # class AdType +end # module Finitio diff --git a/lib/finitio/typescript/alias_type.rb b/lib/finitio/typescript/alias_type.rb new file mode 100644 index 0000000..f08ac6a --- /dev/null +++ b/lib/finitio/typescript/alias_type.rb @@ -0,0 +1,9 @@ +module Finitio + class AliasType + + def to_typescript(*args, &bl) + target.ts_name || target.to_typescript + end + + end # class AliasType +end # module Finitio diff --git a/lib/finitio/typescript/any_type.rb b/lib/finitio/typescript/any_type.rb new file mode 100644 index 0000000..2d7a8b3 --- /dev/null +++ b/lib/finitio/typescript/any_type.rb @@ -0,0 +1,9 @@ +module Finitio + class AnyType + + def to_typescript(*args, &bl) + "any" + end + + end # class AnyType +end # module Finitio diff --git a/lib/finitio/typescript/builtin_type.rb b/lib/finitio/typescript/builtin_type.rb new file mode 100644 index 0000000..fb98516 --- /dev/null +++ b/lib/finitio/typescript/builtin_type.rb @@ -0,0 +1,32 @@ +module Finitio + module Typescript + + BUILTIN_MAPPING = { + NilClass => "null", + String => "string", + Integer => "number", + Fixnum => "number", + Bignum => "number", + Float => "number", + Numeric => "number", + TrueClass => "boolean", + FalseClass => "boolean", + Object => "any", + DateTime => "Date", + Date => "Date" + } + + end + class BuiltinType + + def to_typescript(*args, &bl) + mapped = Typescript::BUILTIN_MAPPING[ruby_type] + if mapped + mapped + else + raise Typescript::Error, "Unable to map #{ruby_type} to json-schema" + end + end + + end # class BuiltinType +end # module Finitio diff --git a/lib/finitio/typescript/hash_based_type.rb b/lib/finitio/typescript/hash_based_type.rb new file mode 100644 index 0000000..4e8228d --- /dev/null +++ b/lib/finitio/typescript/hash_based_type.rb @@ -0,0 +1,35 @@ +module Finitio + module HashBasedType + + def to_typescript(*args, &bl) + defs = [] + + attrs = heading.inject([]) do |ps,a| + separator = a.required? ? ": " : "?: " + type = if a.type.is_a?(UnionType) + a.type.to_typescript + ## TODO @llambeau @blambeau why do we assign default names to inline types anyway? + elsif a.type.name && a.type.name[0] == '{' + a.type.to_typescript + else + a.type.ts_name || a.type.to_typescript + end + ps + ["#{a.name}#{separator}#{type}"] + end + + defs << "{ #{attrs.join(', ')} }" unless attrs.empty? + + if heading.allow_extra? + extra = if heading.allow_extra.is_a?(Finitio::AliasType) + heading.allow_extra.ts_name + else + heading.allow_extra.to_typescript(*args, &bl) + end + defs << "{ [key: string]: #{extra} }" + end + + defs.join(' & ') + end + + end # module HashBasedType +end # module UnionType diff --git a/lib/finitio/typescript/high_order_type.rb b/lib/finitio/typescript/high_order_type.rb new file mode 100644 index 0000000..87d3c73 --- /dev/null +++ b/lib/finitio/typescript/high_order_type.rb @@ -0,0 +1,11 @@ +module Finitio + class HighOrderType < Type + def to_typescript(*args, &bl) + defn.ts_name || defn.to_typescript(*args, &bl) + end + + def ts_name + "#{super}<#{vars.join(', ')}>" if super + end + end # class HighOrderType +end # module Finitio diff --git a/lib/finitio/typescript/proxy_type.rb b/lib/finitio/typescript/proxy_type.rb new file mode 100644 index 0000000..f89d985 --- /dev/null +++ b/lib/finitio/typescript/proxy_type.rb @@ -0,0 +1,13 @@ +module Finitio + class ProxyType + + def to_typescript(*args, &bl) + @target_name + end + + def ts_name + @target_name + end + + end # module ProxyType +end # module UnionType diff --git a/lib/finitio/typescript/rel_based_type.rb b/lib/finitio/typescript/rel_based_type.rb new file mode 100644 index 0000000..a378c4d --- /dev/null +++ b/lib/finitio/typescript/rel_based_type.rb @@ -0,0 +1,9 @@ +module Finitio + module RelBasedType + + def to_typescript(*args, &bl) + "Set<#{tuple_type.to_typescript(*args, &bl)}>" + end + + end # module RelBasedType +end # module Finitio diff --git a/lib/finitio/typescript/seq_type.rb b/lib/finitio/typescript/seq_type.rb new file mode 100644 index 0000000..7b457f2 --- /dev/null +++ b/lib/finitio/typescript/seq_type.rb @@ -0,0 +1,10 @@ +module Finitio + class SeqType + + def to_typescript(*args, &bl) + type_ts = elm_type.ts_name || elm_type.to_typescript(*args, &bl) + "Array<#{type_ts}>" + end + + end # class SeqType +end # module Finitio diff --git a/lib/finitio/typescript/set_type.rb b/lib/finitio/typescript/set_type.rb new file mode 100644 index 0000000..7b780ff --- /dev/null +++ b/lib/finitio/typescript/set_type.rb @@ -0,0 +1,10 @@ +module Finitio + class SetType + + def to_typescript(*args, &bl) + type = elm_type.to_typescript(*args, &bl) + "Set<#{type}>" + end + + end # class SetType +end # module Finitio diff --git a/lib/finitio/typescript/struct_type.rb b/lib/finitio/typescript/struct_type.rb new file mode 100644 index 0000000..f935277 --- /dev/null +++ b/lib/finitio/typescript/struct_type.rb @@ -0,0 +1,10 @@ +module Finitio + class StructType + + def to_typescript(*args, &bl) + elms = component_types.map{|c| c.to_typescript(*args, &bl) } + "[#{elms.join(', ')}]" + end + + end # class StructType +end # module Finitio diff --git a/lib/finitio/typescript/sub_type.rb b/lib/finitio/typescript/sub_type.rb new file mode 100644 index 0000000..726f1db --- /dev/null +++ b/lib/finitio/typescript/sub_type.rb @@ -0,0 +1,9 @@ +module Finitio + class SubType + + def to_typescript(*args, &bl) + super_type.ts_name + end + + end # class SubType +end # module Finitio diff --git a/lib/finitio/typescript/system.rb b/lib/finitio/typescript/system.rb new file mode 100644 index 0000000..a565b57 --- /dev/null +++ b/lib/finitio/typescript/system.rb @@ -0,0 +1,10 @@ +module Finitio + class System + def to_typescript(*args, &bl) + ts = types.map do |name, t| + "export type #{t.ts_name} = #{t.to_typescript(*args, &bl)}" + end + ts.join("\n") + end + end # class AdType +end # module Finitio diff --git a/lib/finitio/typescript/type.rb b/lib/finitio/typescript/type.rb new file mode 100644 index 0000000..a267bbd --- /dev/null +++ b/lib/finitio/typescript/type.rb @@ -0,0 +1,11 @@ +module Finitio + class Type + + TS_TYPE_UNALLOWED_CHARS = /[^<>a-zA-Z_$]/.freeze + + def ts_name + @name.gsub(TS_TYPE_UNALLOWED_CHARS, '') if @name + end + + end # class Type +end # module Finitio diff --git a/lib/finitio/typescript/union_type.rb b/lib/finitio/typescript/union_type.rb new file mode 100644 index 0000000..fce0523 --- /dev/null +++ b/lib/finitio/typescript/union_type.rb @@ -0,0 +1,21 @@ +module Finitio + class UnionType + + FALSE_TYPE = BuiltinType.new(TrueClass) + + TRUE_TYPE = BuiltinType.new(FalseClass) + + BOOLEAN_TYPE = UnionType.new([TRUE_TYPE, FALSE_TYPE]) + + def to_typescript(*args, &bl) + return 'boolean' if self == BOOLEAN_TYPE + if candidates.size == 1 + c = candidates.first + c.ts_name || c.to_typescript(*args, &bl) + else + candidates.map{|c| c.ts_name || c.to_typescript(*args, &bl) }.join('|') + end + end + + end # class UnionType +end # module Finitio diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 4e2c3d3..f0260c8 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -4,6 +4,7 @@ require 'finitio/syntax' require 'finitio/generation' require 'finitio/json_schema' +require 'finitio/typescript' require 'coveralls' Coveralls.wear! @@ -74,6 +75,10 @@ def stringType @stringType ||= Finitio::BuiltinType.new(String, "stringType") end + def namespacedStringType + @stringType ||= Finitio::BuiltinType.new(String, "Namespace.String") + end + def byte_full @byte_full ||= Finitio::Constraint.new(->(i){ i>=0 && i<=255 }, :byte) end diff --git a/spec/typescript/test_ad_type.rb b/spec/typescript/test_ad_type.rb new file mode 100644 index 0000000..b21879b --- /dev/null +++ b/spec/typescript/test_ad_type.rb @@ -0,0 +1,15 @@ +module Finitio + module Typescript + describe "AdType" do + + let(:type) { + type = AdType.new(Color, [rgb_contract, hex_contract]) + } + + it 'works as expected' do + expect(type.to_typescript).to eql("intType|stringType") + end + + end + end +end diff --git a/spec/typescript/test_alias_type.rb b/spec/typescript/test_alias_type.rb new file mode 100644 index 0000000..6201bbe --- /dev/null +++ b/spec/typescript/test_alias_type.rb @@ -0,0 +1,15 @@ +module Finitio + module Typescript + describe "AliasType" do + + let(:alias_type) { + AliasType.new(anyType, "X") + } + + it 'works as expected' do + expect(alias_type.to_typescript).to eql('any') + end + + end + end +end diff --git a/spec/typescript/test_any_type.rb b/spec/typescript/test_any_type.rb new file mode 100644 index 0000000..3e7f63a --- /dev/null +++ b/spec/typescript/test_any_type.rb @@ -0,0 +1,11 @@ +module Finitio + module Typescript + describe "AnyType" do + + it 'works as expected' do + expect(anyType.to_typescript).to eql('any') + end + + end + end +end diff --git a/spec/typescript/test_builtin_type.rb b/spec/typescript/test_builtin_type.rb new file mode 100644 index 0000000..2bddee7 --- /dev/null +++ b/spec/typescript/test_builtin_type.rb @@ -0,0 +1,51 @@ +module Finitio + module Typescript + describe 'BuiltinType' do + + let(:builtin_type) { + BuiltinType.new(ruby_type) + } + + subject { + builtin_type.to_typescript + } + + context 'with NilClass' do + let(:ruby_type){ NilClass } + + it 'works' do + expect(subject).to eql('null') + end + end + + context 'with String' do + let(:ruby_type){ String } + + it 'works' do + expect(subject).to eql('string') + end + end + + [Fixnum, Bignum, Integer].each do |rt| + context 'with #{rt}' do + let(:ruby_type){ rt } + + it 'works' do + expect(subject).to eql('number') + end + end + end + + [Float, Numeric].each do |rt| + context 'with #{rt}' do + let(:ruby_type){ rt } + + it 'works' do + expect(subject).to eql('number') + end + end + end + + end + end +end diff --git a/spec/typescript/test_multi_relation_type.rb b/spec/typescript/test_multi_relation_type.rb new file mode 100644 index 0000000..f0238fa --- /dev/null +++ b/spec/typescript/test_multi_relation_type.rb @@ -0,0 +1,39 @@ +module Finitio + module Typescript + describe "MultiRelationType" do + + context 'with a true allow extra and some optional attribute' do + let(:heading){ + Heading.new([ + Attribute.new(:a, anyType), + Attribute.new(:b, anyType, false), + ], allow_extra: true) + } + + let(:multi_relation_type) { + MultiRelationType.new(heading) + } + + it 'works as expected' do + expect(multi_relation_type.to_typescript).to eql("Set<{ a: any, b?: any } & { [key: string]: any }>") + end + end + + context 'with a allow extra requiring Strings' do + let(:heading){ + Heading.new([ + ], allow_extra: BuiltinType.new(String)) + } + + let(:multi_relation_type) { + MultiRelationType.new(heading) + } + + it 'works as expected' do + expect(multi_relation_type.to_typescript).to eql("Set<{ [key: string]: string }>") + end + end + + end + end +end diff --git a/spec/typescript/test_multi_tuple_type.rb b/spec/typescript/test_multi_tuple_type.rb new file mode 100644 index 0000000..311e50b --- /dev/null +++ b/spec/typescript/test_multi_tuple_type.rb @@ -0,0 +1,39 @@ +module Finitio + module Typescript + describe "MultiTupleType" do + + context 'with a true allow extra and some optional attribute' do + let(:heading){ + Heading.new([ + Attribute.new(:a, anyType), + Attribute.new(:b, anyType, false), + ], allow_extra: true) + } + + let(:multi_tuple_type) { + MultiTupleType.new(heading) + } + + it 'works as expected' do + expect(multi_tuple_type.to_typescript).to eql("{ a: any, b?: any } & { [key: string]: any }") + end + end + + context 'with a allow extra requiring Strings' do + let(:heading){ + Heading.new([ + ], allow_extra: BuiltinType.new(String)) + } + + let(:multi_tuple_type) { + MultiTupleType.new(heading) + } + + it 'works as expected' do + expect(multi_tuple_type.to_typescript).to eql("{ [key: string]: string }") + end + end + + end + end +end diff --git a/spec/typescript/test_recursive_type.rb b/spec/typescript/test_recursive_type.rb new file mode 100644 index 0000000..34a0914 --- /dev/null +++ b/spec/typescript/test_recursive_type.rb @@ -0,0 +1,48 @@ +require 'spec_helper' +module Finitio + module Typescript + describe "A recursive type" do + + let(:system){ + ::Finitio.system <<-FIO + Tree = { + children : [Tree] + } + FIO + } + + let(:type) { + system['Tree'] + } + + xit 'works as expected' do + expect(type.to_typescript).to eql({ + type: "object", + properties: { + children: { + type: "array", + items: { + type: "object", + properties: { + children: { + type: "array", + items: "object" + } + }, + required: [ + :children + ], + additionalProperties: false + } + } + }, + required: [ + :children + ], + additionalProperties: false + }) + end + + end + end +end diff --git a/spec/typescript/test_relation_type.rb b/spec/typescript/test_relation_type.rb new file mode 100644 index 0000000..2abbbdb --- /dev/null +++ b/spec/typescript/test_relation_type.rb @@ -0,0 +1,19 @@ +module Finitio + module Typescript + describe "RelationType" do + + let(:heading){ + Heading.new([Attribute.new(:a, anyType)]) + } + + let(:tuple_type) { + RelationType.new(heading) + } + + it 'works as expected' do + expect(tuple_type.to_typescript).to eql("Set<{ a: any }>") + end + + end + end +end diff --git a/spec/typescript/test_seq_type.rb b/spec/typescript/test_seq_type.rb new file mode 100644 index 0000000..96df73c --- /dev/null +++ b/spec/typescript/test_seq_type.rb @@ -0,0 +1,15 @@ +module Finitio + module Typescript + describe "SeqType" do + + let(:type) { + SeqType.new(BuiltinType.new(String)) + } + + it 'works as expected' do + expect(type.to_typescript).to eql('Array') + end + + end + end +end diff --git a/spec/typescript/test_set_type.rb b/spec/typescript/test_set_type.rb new file mode 100644 index 0000000..0242567 --- /dev/null +++ b/spec/typescript/test_set_type.rb @@ -0,0 +1,15 @@ +module Finitio + module Typescript + describe "SetType" do + + let(:type) { + SetType.new(BuiltinType.new(String)) + } + + it 'works as expected' do + expect(type.to_typescript).to eql('Set') + end + + end + end +end diff --git a/spec/typescript/test_struct_type.rb b/spec/typescript/test_struct_type.rb new file mode 100644 index 0000000..fbcb1d6 --- /dev/null +++ b/spec/typescript/test_struct_type.rb @@ -0,0 +1,15 @@ +module Finitio + module Typescript + describe "StructType" do + + let(:type) { + StructType.new([anyType, BuiltinType.new(String)]) + } + + it 'works as expected' do + expect(type.to_typescript).to eql('[any, string]') + end + + end + end +end diff --git a/spec/typescript/test_sub_type.rb b/spec/typescript/test_sub_type.rb new file mode 100644 index 0000000..f4020dc --- /dev/null +++ b/spec/typescript/test_sub_type.rb @@ -0,0 +1,15 @@ +module Finitio + module Typescript + describe "SubType" do + + let(:type) { + byte + } + + it 'skips constraints (for now)' do + expect(byte.to_typescript).to eql("intType") + end + + end + end +end diff --git a/spec/typescript/test_system.rb b/spec/typescript/test_system.rb new file mode 100644 index 0000000..d858a7b --- /dev/null +++ b/spec/typescript/test_system.rb @@ -0,0 +1,68 @@ +module Finitio + module Typescript + describe "System" do + let(:system){ System.new } + + before do + system.add_type(intType) + system.add_type(byte) + system.add_type(namespacedStringType) + end + + # it 'works as expected' do + # expected = <<~TS.strip + # export type intType = number + # export type Byte = number + # export type NamespaceString = string + # TS + # expect(system.to_typescript).to eql(expected) + # end + + it 'converts unsafe type names to safe typescript type names' do + system = Finitio.system(<<~FIO) + @import finitio/data + + UUID = String(s | s s.strip.size > 0) + URL = String + + JSONApi.Links = { + self: URL + ...: URL + } + + JSONApi.Entity = { + id: UUID + type: String + attributes: T + links: JSONApi.Links + } + + JSONApi.Relationship = { + links : Links + data : JSONApi.Entity + } + + Person.Attributes.Full = { + name: String + dob: DateTime|Nil + inline: { + meta: String + } + } + Person = JSONApi.Entity + FIO + + expected = <<~TS.strip + export type UUID = String + export type URL = String + export type JSONApiLinks = { self: URL } & { [key: string]: URL } + export type JSONApiEntity = { id: UUID, type: String, attributes: T, links: JSONApiLinks } + export type JSONApiRelationship = { links: Links, data: JSONApiEntity } + export type PersonAttributesFull = { name: String, dob: DateTime|Nil, inline: { meta: String } } + export type Person = JSONApiEntity + TS + expect(system.to_typescript).to eql(expected) + end + end + end +end diff --git a/spec/typescript/test_tuple_type.rb b/spec/typescript/test_tuple_type.rb new file mode 100644 index 0000000..1c3cae4 --- /dev/null +++ b/spec/typescript/test_tuple_type.rb @@ -0,0 +1,18 @@ +module Finitio + module Typescript + describe "TupleType" do + + let(:heading){ + Heading.new([Attribute.new(:a, anyType)]) + } + + let(:tuple_type) { + TupleType.new(heading) + } + + it 'works as expected' do + expect(tuple_type.to_typescript).to eql("{ a: any }") + end + end + end +end diff --git a/spec/typescript/test_union_type.rb b/spec/typescript/test_union_type.rb new file mode 100644 index 0000000..9426147 --- /dev/null +++ b/spec/typescript/test_union_type.rb @@ -0,0 +1,67 @@ +module Finitio + module Typescript + describe "UnionType" do + + let(:string_type) { + BuiltinType.new(String) + } + + let(:int_type) { + BuiltinType.new(Integer) + } + + let(:true_type) { + BuiltinType.new(TrueClass) + } + + let(:false_type) { + BuiltinType.new(FalseClass) + } + + let(:nil_type) { + BuiltinType.new(NilClass) + } + + context 'when used with a single type' do + let(:union_type) { + UnionType.new([string_type]) + } + + it 'works as expected' do + expect(union_type.to_typescript).to eql("string") + end + end + + context 'when used with two types' do + let(:union_type) { + UnionType.new([string_type, int_type]) + } + + it 'works as expected' do + expect(union_type.to_typescript).to eql("string|number") + end + end + + context 'when used with a |Nil' do + let(:union_type) { + UnionType.new([string_type, int_type, nil_type]) + } + + it 'works as expected' do + expect(union_type.to_typescript).to eql("string|number|null") + end + end + + context 'when used with a TrueClass|FalseClass' do + let(:union_type) { + UnionType.new([true_type, false_type]) + } + + it 'works as expected' do + expect(union_type.to_typescript).to eql("boolean") + end + end + + end + end +end diff --git a/tasks/test.rake b/tasks/test.rake index 8654e0e..fa5e477 100644 --- a/tasks/test.rake +++ b/tasks/test.rake @@ -28,4 +28,4 @@ namespace :test do task :all => [ :unit, :cucumber ] end -task :test => :'test:all' \ No newline at end of file +task :test => :'test:all'