Comments (12)
would you be interested in trying to fix it?
I first want to get #489 over the finish line.
from chimney.
I don't really know the value of vector and can't find it. I assume it's a Vector[io.moia.food.food.Meal.Color] where the To type is gotten by index. Is there a way to get that? I could then try to use the derived code and debug further.
vector
is not printed but it's Vector[Any]
where all runtime data is stored (basically all withFieldConst
/withFieldComputed
/... values). If e.g you took
given Transformer[Color, food.Meal.Color] = Transformer
.define[Color, food.Meal.Color]
.withCoproductInstance[Color.Yellow.type](_ => food.Meal.Color.COLOR_YELLOW)
.withCoproductInstance[Color.Red.type](_ => food.Meal.Color.COLOR_RED)
.withCoproductInstance[Color.orange.type](_ => food.Meal.Color.COLOR_ORANGE)
.withCoproductInstance[Color.pink.type](_ => food.Meal.Color.COLOR_PINK)
.withCoproductInstance[Color.Blue.type](_ => food.Meal.Color.COLOR_BLUE)
.buildTransformer
and did this:
given Transformer[Color, food.Meal.Color] =
val foo = Transformer
.define[Color, food.Meal.Color]
.withCoproductInstance[Color.Yellow.type](_ => food.Meal.Color.COLOR_YELLOW)
.withCoproductInstance[Color.Red.type](_ => food.Meal.Color.COLOR_RED)
.withCoproductInstance[Color.orange.type](_ => food.Meal.Color.COLOR_ORANGE)
.withCoproductInstance[Color.pink.type](_ => food.Meal.Color.COLOR_PINK)
.withCoproductInstance[Color.Blue.type](_ => food.Meal.Color.COLOR_BLUE)
println(foo.runtimeData)
foo.buildTransformer
you'd see its content.
from chimney.
I looked at this yesterday and it seems that the issue is not with the pattern match case catching incorrect values but with incorrect runtimeData
being used in the rhs there. E.g.:
//> using dep "io.scalaland::chimney:0.8.5"
import io.scalaland.chimney.dsl.*
import io.scalaland.chimney.Transformer
sealed trait Color
object Color {
case object orange extends Color
case object pink extends Color
}
sealed trait Target
object Target {
case class Impl(value: String) extends Target
}
@main def main() =
val writer: Transformer[Color, Target] = Transformer
.define[Color, Target]
.withCoproductInstance[Color.orange.type](_ => Target.Impl("orange"))
.withCoproductInstance[Color.pink.type](_ => Target.Impl("pink"))
.enableMacrosLogging
.buildTransformer
writer.transform(Color.pink)
when running this with -Xprint:inlining
, we get (I trimmed some of the types for readability):
val writer: io.scalaland.chimney.Transformer[Color, Target] =
{
val TransformerDefinition_this: io.scalaland.chimney.dsl.TransformerDefinition[...]
= io.scalaland.chimney.Transformer.define[Color, Target]
val TransformerDefinition_this:
io.scalaland.chimney.dsl.TransformerDefinition[...]
=
io.scalaland.chimney.internal.runtime.WithRuntimeDataStore.update[ // idx: 0, orange
...
](TransformerDefinition_this,
{
def $anonfun(_$1: Color.orange.type): Target =
Target.Impl.apply("orange")
closure($anonfun)
}
).asInstanceOf[...]
{
val TransformerDefinition_this:
io.scalaland.chimney.dsl.TransformerDefinition[...]
=
io.scalaland.chimney.internal.runtime.WithRuntimeDataStore.
update[...](TransformerDefinition_this, // idx: 1, pink
{
def $anonfun(_$2: Color.pink.type): Target =
Target.Impl.apply("pink")
closure($anonfun)
}
).asInstanceOf[...].enableMacrosLogging
{
val vector$macro$1: Vector[Any] =
TransformerDefinition_this.runtimeData
{
{
(vector$macro$1:Vector[Any] @unchecked match
{
case _ => ()
}
)
()
}
{
final class $anon() extends Object(), io.scalaland.chimney.
Transformer[Color, Target] {
def transform(src: Color): Target =
{
val color$macro$1: Color = src
color$macro$1:Color @unchecked match
{
case orange$macro$2 @ Color.orange =>
val orange$macro$1: Color.orange.type =
orange$macro$2
{
orange$macro$1:Color.orange.type @unchecked
match
{
case _ => ()
}
()
}
vector$macro$1.apply(1).asInstanceOf[ // idx 1: pink for type orange
Color => Target].apply(
orange$macro$1.asInstanceOf[Color])
case pink$macro$2 @ Color.pink =>
val pink$macro$1: Color.pink.type = pink$macro$2
{
pink$macro$1:Color.pink.type @unchecked match
{
case _ => ()
}
()
}
vector$macro$1.apply(0).asInstanceOf[ // idx: 0, orange, for type pink
Color => Target].apply(
pink$macro$1.asInstanceOf[Color])
}
}
}
new $anon():io.scalaland.chimney.Transformer[Color, Target]
}
}
}:io.scalaland.chimney.Transformer[Color, Target]
}
}
This can also be replicated in tests, however changing the order of withCoproductInstance
will "fix" the issue, so I imagine that is why it was not discovered there. I have not managed to fix this yet, unfortunately
from chimney.
@jchyb I believe that it a bug in pattern matching on Scala 3 after all. (Or in detecting case objects).
I compared:
- type level representations of config
- coproductOverrides
in
- Scala 2.13 - https://scastie.scala-lang.org/IDPfJJBLRBmoNhmnrGseQg
- Scala 3 - https://scastie.scala-lang.org/5oxrmiI8QkGMENM0qzo5qg
They are correct - runtime values are prepended so that what is in Vector[Any]
corresponds with the position with type-level-list of overrides (rename is an exception but in everything else prepends both on type-level and on value-level).
val writer: Transformer[Color, Target] = Transformer
.define[Color, Target]
.withCoproductInstance[Color.orange.type](_ => Target.Impl("orange")) // last but one override -> idx = 1
.withCoproductInstance[Color.pink.type](_ => Target.Impl("pink")) // last override -> idx = 0
.enableMacrosLogging
.buildTransformer
What changes is the order of case
clauses in a pattern matching - at first Chimney generates them from CoproductInstance overrides - in the order it found them in a config, so it's deterministic - and then fill the remaining subtypes by matching names.
You can see that failing example has orange
as the first case
and working one has pink
as the first case
. Pass orange
and the outcome reverses.
(I had a much longer comment but I accidentally refreshed and it all got removed :| )
I was certain that I test for these, but apparently the test was not detailed enough. :/
EDIT:
I tried to dig around, I refactored the code a bit, to eliminate leaky abstraction and imprecise methods names to make the code easier to read, but was not successful. Unfortunately, Ident.unapply
returns String
instead of a symbol, so I have to guess what exactly goes into it when compiler constructs an ADT that is not throwing :/
EDIT2:
I modified the first test of SealedHierarchySpec
(colors1.Red: colors1.Color).transformInto[colors2.Color] ==> colors2.Red
(colors1.Green: colors1.Color).transformInto[colors2.Color] ==> colors2.Green
(colors1.Blue: colors1.Color).transformInto[colors2.Color] ==> colors2.Blue
(colors1.Red: colors1.Color)
.into[colors2.Color]
.withCoproductInstance[colors1.Red.type](_ => colors2.Red)
.withCoproductInstance[colors1.Blue.type](_ => colors2.Blue)
.transform ==> colors2.Red
(colors1.Blue: colors1.Color)
.into[colors2.Color]
.withCoproductInstance[colors1.Red.type](_ => colors2.Red)
.withCoproductInstance[colors1.Blue.type](_ => colors2.Blue)
.transform ==> colors2.Blue
(colors1.Green: colors1.Color)
.into[colors2.Color]
.withCoproductInstance[colors1.Red.type](_ => colors2.Red)
.withCoproductInstance[colors1.Blue.type](_ => colors2.Blue)
.transform ==> colors2.Green
it... passed. So I tried one more thing. I changed all names to PascalCase:
import io.scalaland.chimney.dsl.*
import io.scalaland.chimney.Transformer
sealed trait Color
object Color {
case object Orange extends Color
case object Pink extends Color
}
sealed trait Target
object Target {
case class Impl(value: String) extends Target
}
val testDupa = Transformer
.define[Color, Target]
.withCoproductInstance[Color.Orange.type](_ => Target.Impl("orange")) // 1
.withCoproductInstance[Color.Pink.type](_ => Target.Impl("pink")) // 0
.enableMacrosLogging
val testDupa2 = Transformer
.define[Color, Target]
.withCoproductInstance[Color.Pink.type](_ => Target.Impl("pink")) // 1
.withCoproductInstance[Color.Orange.type](_ => Target.Impl("orange")) // 0
.enableMacrosLogging
val writer: Transformer[Color, Target] = testDupa // orange -> 1, pink -> 0
.buildTransformer
scala.util.Try(writer.transform(Color.Pink))
val writer2: Transformer[Color, Target] = testDupa2 // pink -> 1, orange -> 0
.buildTransformer
scala.util.Try(writer2.transform(Color.Pink))
scala.util.Try(writer2.transform(Color.Orange))
I tried to skip withCoproductInstance but match it against virtually the same sealed hierarchy - also with lowercase names.
It fails in exactly the same way.
This explains why no other tests detected it. This only fails for a combination of:
- Scala 3
- sealed trait
- with case objects with lowercased names
😱
from chimney.
Reported as scala/scala3#20350
from chimney.
Thank you for the report!
As I wrote in #480, I don't have much time on my hand so I am not sure when I'll be able to look at the reproduction.
If you wanted to investivate further in the meantime
-
it could be interesting to take a look at the generated code, to see if handwritten version would have the same issue
-
it's very curious , if
clean
andcompile
can change the outcome, as it suggest it might be something about Zink and/or classloader. I started observing many issues ever since I updated Scala 3 to 3.3.3 - on 3.3.1 code was compiling fine, but after update I get a lot of broken classpath exceptions, and I have tocompile
sometimes 3 times or more before it works. I was thinking it might be an artifact of some weird changes to build.sbt I attempted a few days ago, but maybe it's related to the Scala 3 update. I see you have 3.3.3 as well. What would happen if you downgrade to 3.3.1?
from chimney.
The erroneous derived transformer looks like:
[info] || {
[info] || final class $anon() extends io.scalaland.chimney.Transformer[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color, io.moia.food.food.Meal.Color] {
[info] || def transform(src: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color): io.moia.food.food.Meal.Color = {
[info] || val color: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color = src
[info] || (color: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color @scala.unchecked) match {
[info] || case pink @ io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.pink =>
[info] || val pink: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.pink.type = pink
[info] || {
[info] || (pink: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.pink @scala.unchecked) match {
[info] || case _ =>
[info] || ()
[info] || }
[info] || ()
[info] || }
[info] || vector.apply(1).asInstanceOf[scala.Function1[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color, io.moia.food.food.Meal.Color]].apply(pink.asInstanceOf[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color])
[info] || case red @ io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Red =>
[info] || val red: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Red.type = red
[info] || {
[info] || (red: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Red @scala.unchecked) match {
[info] || case _ =>
[info] || ()
[info] || }
[info] || ()
[info] || }
[info] || vector.apply(3).asInstanceOf[scala.Function1[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color, io.moia.food.food.Meal.Color]].apply(red.asInstanceOf[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color])
[info] || case yellow @ io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Yellow =>
[info] || val yellow: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Yellow.type = yellow
[info] || {
[info] || (yellow: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Yellow @scala.unchecked) match {
[info] || case _ =>
[info] || ()
[info] || }
[info] || ()
[info] || }
[info] || vector.apply(4).asInstanceOf[scala.Function1[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color, io.moia.food.food.Meal.Color]].apply(yellow.asInstanceOf[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color])
[info] || case blue @ io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Blue =>
[info] || val blue: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Blue.type = blue
[info] || {
[info] || (blue: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Blue @scala.unchecked) match {
[info] || case _ =>
[info] || ()
[info] || }
[info] || ()
[info] || }
[info] || vector.apply(0).asInstanceOf[scala.Function1[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color, io.moia.food.food.Meal.Color]].apply(blue.asInstanceOf[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color])
[info] || case orange @ io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.orange =>
[info] || val orange: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.orange.type = orange
[info] || {
[info] || (orange: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.orange @scala.unchecked) match {
[info] || case _ =>
[info] || ()
[info] || }
[info] || ()
[info] || }
[info] || vector.apply(2).asInstanceOf[scala.Function1[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color, io.moia.food.food.Meal.Color]].apply(orange.asInstanceOf[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color])
[info] || }
[info] || }
[info] || }
[info] ||
[info] || (new $anon(): io.scalaland.chimney.Transformer[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color, io.moia.food.food.Meal.Color])
[info] || }
The enum one:
[info] || {
[info] || final class $anon() extends io.scalaland.chimney.Transformer[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color, io.moia.food.food.Meal.Color] {
[info] || def transform(src: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color): io.moia.food.food.Meal.Color = {
[info] || val color: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color = src
[info] || (color: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color @scala.unchecked) match {
[info] || case blue: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Blue.type =>
[info] || val blue: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Blue.type = blue
[info] || {
[info] || (blue: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Blue @scala.unchecked) match {
[info] || case _ =>
[info] || ()
[info] || }
[info] || ()
[info] || }
[info] || vector.apply(0).asInstanceOf[scala.Function1[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color, io.moia.food.food.Meal.Color]].apply(blue.asInstanceOf[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color])
[info] || case yellow: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Yellow.type =>
[info] || val yellow: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Yellow.type = yellow
[info] || {
[info] || (yellow: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Yellow @scala.unchecked) match {
[info] || case _ =>
[info] || ()
[info] || }
[info] || ()
[info] || }
[info] || vector.apply(4).asInstanceOf[scala.Function1[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color, io.moia.food.food.Meal.Color]].apply(yellow.asInstanceOf[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color])
[info] || case red: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Red.type =>
[info] || val red: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Red.type = red
[info] || {
[info] || (red: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.Red @scala.unchecked) match {
[info] || case _ =>
[info] || ()
[info] || }
[info] || ()
[info] || }
[info] || vector.apply(3).asInstanceOf[scala.Function1[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color, io.moia.food.food.Meal.Color]].apply(red.asInstanceOf[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color])
[info] || case pink: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.pink.type =>
[info] || val pink: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.pink.type = pink
[info] || {
[info] || (pink: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.pink @scala.unchecked) match {
[info] || case _ =>
[info] || ()
[info] || }
[info] || ()
[info] || }
[info] || vector.apply(1).asInstanceOf[scala.Function1[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color, io.moia.food.food.Meal.Color]].apply(pink.asInstanceOf[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color])
[info] || case orange: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.orange.type =>
[info] || val orange: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.orange.type = orange
[info] || {
[info] || (orange: io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color.orange @scala.unchecked) match {
[info] || case _ =>
[info] || ()
[info] || }
[info] || ()
[info] || }
[info] || vector.apply(2).asInstanceOf[scala.Function1[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color, io.moia.food.food.Meal.Color]].apply(orange.asInstanceOf[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color])
[info] || }
[info] || }
[info] || }
[info] ||
[info] || (new $anon(): io.scalaland.chimney.Transformer[io.moia.protos.teleproto.ProtocolBuffersRoundTripTest.Color, io.moia.food.food.Meal.Color])
[info] || }
Ignoring all the boilerplate, the only difference is the colon :
instead of an @
in each case
of the pattern match.
I don't really know the value of vector
and can't find it. I assume it's a Vector[io.moia.food.food.Meal.Color]
where the To
type is gotten by index. Is there a way to get that? I could then try to use the derived code and debug further.
from chimney.
Using Scala 3.3.1 the problem still exists. Also on Scala 3.4. (Although I found another issue with ScalaPB: scalapb/ScalaPB#1662)
from chimney.
I minimised the example even further in https://github.com/moia-oss/teleproto/blob/chimney2/src/test/scala/io/moia/protos/teleproto/ProtocolBuffersRoundTripTest.scala.
I found another difference: It's not only the :
but also the .type
in the same line.
The ClassCastException
is thrown by the @unchecked
annotation as documented here:
https://www.scala-lang.org/api/current/scala/unchecked.html. I don't really understand why it's not thrown in the enum
variant.
from chimney.
I must be a corner-case that should be fixed in https://github.com/scalalandio/chimney/blob/master/chimney-macro-commons/src/main/scala-3/io/scalaland/chimney/internal/compiletime/ExprPromisesPlatform.scala#L125 which wasn't triggered by any of the tests we have.
I reproduced the issue with Scastie, and my guess is that:
case pink @ Playground.Color.pink =>
val pink: Playground.Color.pink.type = pink
must be catching all values (basically being treated as case pink =>
), and then this exception is justified. I am not sure though why it happens and why none of our tests are not having this issue (we explicitly test matching of every value of an enum/sealed trait to make sure it doesn't happen).
Perhaps @jchyb would know something?
from chimney.
@jchyb thank you for figuring it out!
If that's the case then either:
- there is a bug in how indices are calculated in https://github.com/scalalandio/chimney/blob/master/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/Configurations.scala#L291 or
- there is bug in how configs are matched against values in https://github.com/scalalandio/chimney/blob/master/chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformSealedHierarchyToSealedHierarchyRuleModule.scala#L60
So to fix it we'd have to:
- create reproduction in https://github.com/scalalandio/chimney/blob/master/chimney/src/test/scala/io/scalaland/chimney/IssuesSpec.scala
- it might be a good idea to come up with several similar cases, e.g. with
withCoproductInstant
,withCoproductInstantPartial
, maybe also something similar for case classes and fields - the Scastie code might be a good starting point
- it might be a good idea to come up with several similar cases, e.g. with
- use
enableMacrosLogging
to figure out which part of the code maps indices incorrectly - fix it and verify that tests are passing
@saeltz would you be interested in trying to fix it?
from chimney.
Since there is nothing we can do do fix this, and the only solution I can see is fixing it in the compiler, I'll close it now.
from chimney.
Related Issues (20)
- Unexpected arity mismatch when mixing Tuple with `enableOptionDefaultsToNone` HOT 6
- Improve ReadTheDocs/MkDocs configuration
- Scary compiler error when providing Int const instead of Long HOT 3
- Compilation of partial transformation fails when there are fields named both `is{Name}` and `{name}` HOT 2
- Silent invalid behavior of `withFieldConst` when field name starts with "set" HOT 6
- [PartialTransformer] Field Option[Field].None to Proto3.Fields.Default
- Automatic Coproduct Rename from/to Protobuf GeneratedEnum HOT 8
- Can't transform coproduct - Java Enum to Sealed trait HOT 24
- Cannot transform Scala class to Java class HOT 5
- Chimney stabilization into 1.0.0
- Exclude macro generated code from WartRemover checks HOT 16
- Fix Overrides for Subtypes matching
- Support seamless transformation of protobuf oneof types HOT 4
- Compiler bugs: known, relevant and unresolved/undocumented
- Support transformation to and from Java primitives
- Test more Scala CLI snippets for output (printed results)
- Support runtime-defined enums
- Rewrite Patchers as a special case of multiple case classes mapping
- Refactor internals to NOT rely on RuntimeDataStore
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from chimney.