Created
March 21, 2017 09:38
-
-
Save sjrd/ef8bb7c52be1451b3a3b9bab6a187549 to your computer and use it in GitHub Desktop.
scalafix rewrites for Scala.js: migrate facades to using @jsglobal, new in Scala.js 0.6.15
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package scalafix.rewrite | |
import scala.collection.immutable.Seq | |
import scala.meta._ | |
import scala.meta.contrib._ | |
import scalafix.util.Patch | |
import scalafix.util.TokenPatch._ | |
import scalafix.util.TreePatch.AddGlobalImport | |
import scalafix.util.TreePatch.Rename | |
import org.scalameta.logger | |
object ScalaJSRewrites { | |
// Symbols copy pasted from mirror.database | |
val nativeSymbol = Symbol("_root_.scala.scalajs.js.package.native#") | |
val globalScopeSymbol = | |
Symbol("_root_.scala.scalajs.js.annotation.JSGlobalScope#`<init>`()V.") | |
val globalScopeParentSymbol = | |
Symbol("_root_.scala.scalajs.js.GlobalScope#") | |
val jsImportSymbol = Symbol( | |
"_root_.scala.scalajs.js.annotation.JSImport#`<init>`(Ljava/lang/String;Ljava/lang/String;)V.") | |
private object ClassOrObject { | |
def unapply(arg: Tree): Option[(Seq[Mod], Seq[Ctor.Call])] = arg match { | |
case Defn.Class(mods, _, _, _, Template(_, parents, _, _)) => | |
Option(mods -> parents) | |
case Defn.Object(mods, _, Template(_, parents, _, _)) => | |
Option(mods -> parents) | |
case _ => None | |
} | |
} | |
val DemandJSGlobal: Rewrite[Mirror] = Rewrite[Mirror] { ctx => | |
import ctx._ | |
implicit val mirror = ctx.mirror | |
object JSNative { | |
def unapply(mods: Seq[Mod]): Option[(Mod, Option[Name])] = | |
mods.collectFirst { | |
case native @ Mod.Annot(ref: Ref) if ref.symbol == nativeSymbol => | |
native -> mods.collectFirst { | |
case Mod.Annot( | |
Term.Apply(jsName @ Ctor.Ref.Name("JSName"), _)) => | |
jsName | |
} | |
} | |
} | |
// https://github.com/scala-js/scala-js/pull/2794#issuecomment-284982025 | |
def skipRewrite(mods: Seq[Mod], parents: Seq[Ctor.Call]): Boolean = { | |
def hasInvalidAnnot: Boolean = | |
mods.exists(_.exists { | |
case ref: Ref => | |
ref.symbol == jsImportSymbol || | |
ref.symbol == globalScopeSymbol | |
case _ => false | |
}) | |
def hasGlobalScopeParent: Boolean = | |
parents.exists(_.exists { | |
case ref: Ref => ref.symbol == globalScopeParentSymbol | |
case _ => false | |
}) | |
hasInvalidAnnot || hasGlobalScopeParent | |
} | |
val patchB = Seq.newBuilder[Patch] | |
new Traverser { | |
override def apply(tree: Tree): Unit = tree match { | |
case ClassOrObject(mods, parents) => | |
if (skipRewrite(mods, parents)) Unit // do nothing | |
else { | |
mods match { | |
case JSNative(_, Some(jsName)) => | |
patchB += Rename(jsName, q"JSGlobal") | |
case JSNative(native, None) => | |
patchB += AddRight(native.tokens.last, " @JSGlobal") | |
case _ => | |
} | |
} | |
case _ => super.apply(tree) | |
} | |
}.apply(tree) | |
val patches = patchB.result() | |
if (patches.nonEmpty && config.imports.organize) { | |
AddGlobalImport(importer"scala.scalajs.js.annotation.JSGlobal") +: patches | |
} else { | |
patches | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment