Skip to content

Commit 317b19f

Browse files
committed
Predictable module names (fixes #469)
add `stShortModuleNames` (for sbt plugin) and `--shortModuleNames` for CLI which reverts to old behaviour. Note that the old behaviour is deprecated
1 parent d05bf63 commit 317b19f

File tree

270 files changed

+921
-854
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

270 files changed

+921
-854
lines changed

cli/src/main/scala/org/scalablytyped/converter/cli/Main.scala

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,19 @@ object Main {
3232
}
3333

3434
val DefaultOptions = ConversionOptions(
35-
useScalaJsDomTypes = true,
36-
outputPackage = Name.typings,
37-
enableScalaJsDefined = Selection.All,
38-
flavour = Flavour.Normal,
39-
ignored = SortedSet("typescript"),
40-
stdLibs = SortedSet("es6"),
41-
expandTypeMappings = EnabledTypeMappingExpansion.DefaultSelection,
42-
versions = Versions(Versions.Scala3, Versions.ScalaJs1),
43-
organization = "org.scalablytyped",
44-
enableReactTreeShaking = Selection.None,
45-
enableLongApplyMethod = false,
46-
privateWithin = None,
35+
useScalaJsDomTypes = true,
36+
outputPackage = Name.typings,
37+
enableScalaJsDefined = Selection.All,
38+
flavour = Flavour.Normal,
39+
ignored = SortedSet("typescript"),
40+
stdLibs = SortedSet("es6"),
41+
expandTypeMappings = EnabledTypeMappingExpansion.DefaultSelection,
42+
versions = Versions(Versions.Scala3, Versions.ScalaJs1),
43+
organization = "org.scalablytyped",
44+
enableReactTreeShaking = Selection.None,
45+
enableLongApplyMethod = false,
46+
privateWithin = None,
47+
useDeprecatedModuleNames = false,
4748
)
4849

4950
case class Config(
@@ -166,6 +167,11 @@ object Main {
166167
opt[Boolean]("enableLongApplyMethod")
167168
.action((x, c) => c.mapConversion(_.copy(enableLongApplyMethod = x)))
168169
.text(s"Enables long apply methods, instead of implicit ops builders"),
170+
opt[Boolean]("shortModuleNames")
171+
.action((x, c) => c.mapConversion(_.copy(useDeprecatedModuleNames = x)))
172+
.text(
173+
s"Enables short module names. This used to be the default, and is now deprecated since it's so difficult to navigate",
174+
),
169175
arg[Seq[TsIdentLibrary]]("libs")
170176
.text("Libraries you want to convert from node_modules")
171177
.unbounded()
@@ -263,11 +269,12 @@ object Main {
263269
)
264270
.next(
265271
new Phase2ToScalaJs(
266-
pedantic = false,
267-
scalaVersion = conversion.versions.scala,
268-
enableScalaJsDefined = conversion.enableScalaJsDefined,
269-
outputPkg = conversion.outputPackage,
270-
flavour = conversion.flavourImpl,
272+
pedantic = false,
273+
scalaVersion = conversion.versions.scala,
274+
enableScalaJsDefined = conversion.enableScalaJsDefined,
275+
outputPkg = conversion.outputPackage,
276+
flavour = conversion.flavourImpl,
277+
useDeprecatedModuleNames = conversion.useDeprecatedModuleNames,
271278
),
272279
"scala.js",
273280
)

importer-portable/src/main/scala/org/scalablytyped/converter/internal/importer/AdaptiveNamingImport.scala

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ final class AdaptiveNamingImport(private val rewrites: Map[IArray[TsIdent], Qual
2727

2828
object AdaptiveNamingImport {
2929
def apply(
30-
outputPkg: Name,
31-
libraryName: TsIdentLibrary,
32-
library: TsParsedFile,
33-
depsRewrites: IArray[AdaptiveNamingImport],
34-
cleanIllegalNames: CleanIllegalNames,
30+
outputPkg: Name,
31+
libraryName: TsIdentLibrary,
32+
library: TsParsedFile,
33+
depsRewrites: IArray[AdaptiveNamingImport],
34+
cleanIllegalNames: CleanIllegalNames,
35+
useDeprecatedModuleNames: Boolean,
3536
): AdaptiveNamingImport = {
3637
val allReferences: IArray[IArray[TsIdent]] =
3738
TsTreeTraverse
@@ -60,9 +61,15 @@ object AdaptiveNamingImport {
6061
case IArray.Empty => ()
6162
case whole @ IArray.initLast(parent, current) =>
6263
val parentTranslated = registeredReferences(parent)
63-
val variants = variantsFor(current, parent.exists(_.isInstanceOf[TsIdentModule]), illegalNames)
64-
var continue = true
65-
val iter = variants.iterator
64+
val variants = variantsFor(
65+
current,
66+
parent.exists(_.isInstanceOf[TsIdentModule]),
67+
parent.collectFirst { case x: TsIdentLibrary => x },
68+
illegalNames,
69+
useDeprecatedModuleNames,
70+
)
71+
var continue = true
72+
val iter = variants.iterator
6673
while (continue && iter.hasNext) {
6774
val currentVariant = iter.next()
6875
val possibleQname = QualifiedName(parentTranslated.parts :+ Name.necessaryRewrite(Name(currentVariant)))
@@ -88,7 +95,13 @@ object AdaptiveNamingImport {
8895
new AdaptiveNamingImport(registeredReferences.toMap)
8996
}
9097

91-
def variantsFor(tsIdent: TsIdent, hasModuleParent: Boolean, illegalNames: Set[String]): Stream[String] = {
98+
def variantsFor(
99+
tsIdent: TsIdent,
100+
hasModuleParent: Boolean,
101+
inLib: Option[TsIdentLibrary],
102+
illegalNames: Set[String],
103+
useDeprecatedModuleNames: Boolean,
104+
): Stream[String] = {
92105
val base = tsIdent match {
93106
case TsIdent.namespaced => Stream(Name.namespaced.unescaped)
94107
case TsIdent.Apply => Stream(Name.APPLY.unescaped)
@@ -100,7 +113,7 @@ object AdaptiveNamingImport {
100113
/* todo: We should look up what the augmented module is called and reuse it. I don't care enough to do it now */
101114
nameVariants(joinCamelCase(m.scopeOpt.toList ++ m.fragments)).map(_ + "AugmentingMod")
102115

103-
case m: TsIdentModule =>
116+
case m: TsIdentModule if useDeprecatedModuleNames =>
104117
val increasingLength: Stream[List[String]] = {
105118
val (libraryBits, moduleBits) =
106119
m match {
@@ -122,15 +135,28 @@ object AdaptiveNamingImport {
122135

123136
preferCamelCase.flatMap(frags => nameVariants(addMod(joinCamelCase(frags))))
124137

125-
case library: TsIdentLibrary =>
126-
nameVariants(toCamelCase(library.value))
138+
case m: TsIdentModule =>
139+
val shortenedFragments = {
140+
inLib match {
141+
case Some(TsIdentLibrarySimple(value)) if m.fragments.head == value =>
142+
m.fragments.drop(1)
143+
case Some(TsIdentLibraryScoped(scope, name)) if m.scopeOpt.contains(scope) && m.fragments.head == name =>
144+
m.fragments.drop(1)
145+
case _ =>
146+
m.fragments
147+
}
148+
}
149+
Stream(addMod(joinCamelCase(shortenedFragments.map(toCamelCase))))
127150

128-
case _: TsIdentImport => sys.error("unexpected")
151+
case library: TsIdentLibrary => variantsForLibName(library)
152+
case _: TsIdentImport => sys.error("unexpected")
129153
}
130154

131155
base #::: base.map(_ + "_") #::: base.map(_ + "__")
132156
}
133157

158+
def variantsForLibName(library: TsIdentLibrary) =
159+
nameVariants(toCamelCase(library.value))
134160
private def addMod(str: String) = str match {
135161
case "" => Name.mod.unescaped
136162
case nonEmpty => nonEmpty + "Mod"

importer-portable/src/main/scala/org/scalablytyped/converter/internal/importer/ConversionOptions.scala

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,19 @@ import org.scalablytyped.converter.internal.ts.TsIdentLibrary
1010
import scala.collection.immutable.SortedSet
1111

1212
case class ConversionOptions(
13-
useScalaJsDomTypes: Boolean,
14-
flavour: Flavour,
15-
outputPackage: Name,
16-
enableScalaJsDefined: Selection[TsIdentLibrary],
17-
stdLibs: SortedSet[String],
18-
expandTypeMappings: Selection[TsIdentLibrary],
19-
ignored: SortedSet[String],
20-
versions: Versions,
21-
organization: String,
22-
enableReactTreeShaking: Selection[Name],
23-
enableLongApplyMethod: Boolean,
24-
privateWithin: Option[Name],
13+
useScalaJsDomTypes: Boolean,
14+
flavour: Flavour,
15+
outputPackage: Name,
16+
enableScalaJsDefined: Selection[TsIdentLibrary],
17+
stdLibs: SortedSet[String],
18+
expandTypeMappings: Selection[TsIdentLibrary],
19+
ignored: SortedSet[String],
20+
versions: Versions,
21+
organization: String,
22+
enableReactTreeShaking: Selection[Name],
23+
enableLongApplyMethod: Boolean,
24+
privateWithin: Option[Name],
25+
useDeprecatedModuleNames: Boolean,
2526
) {
2627
val ignoredLibs: Set[TsIdentLibrary] =
2728
ignored.map(TsIdentLibrary.apply)

importer-portable/src/main/scala/org/scalablytyped/converter/internal/importer/ImportName.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ object ImportName {
1515
Name.necessaryRewrite(Name(i.value))
1616

1717
def apply(i: TsIdentLibrary): Name =
18-
Name.necessaryRewrite(Name(AdaptiveNamingImport.variantsFor(i, hasModuleParent = false, Set()).head))
18+
Name.necessaryRewrite(Name(AdaptiveNamingImport.variantsForLibName(i).head))
1919

2020
object withJsNameAnnotation {
2121
def apply(original: TsIdentSimple): (Name, Option[Annotation.JsName]) = {

importer-portable/src/main/scala/org/scalablytyped/converter/internal/importer/Phase2ToScalaJs.scala

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ import scala.collection.immutable.SortedSet
2727
* Then the phase itself implements a bunch of scala.js limitations, like ensuring no methods erase to the same signature
2828
*/
2929
class Phase2ToScalaJs(
30-
pedantic: Boolean,
31-
scalaVersion: Versions.Scala,
32-
enableScalaJsDefined: Selection[TsIdentLibrary],
33-
outputPkg: Name,
34-
flavour: FlavourImpl,
30+
pedantic: Boolean,
31+
useDeprecatedModuleNames: Boolean,
32+
scalaVersion: Versions.Scala,
33+
enableScalaJsDefined: Selection[TsIdentLibrary],
34+
outputPkg: Name,
35+
flavour: FlavourImpl,
3536
) extends Phase[LibTsSource, LibTs, LibScalaJs] {
3637

3738
override def apply(
@@ -90,6 +91,7 @@ class Phase2ToScalaJs(
9091
tsLibrary.parsed,
9192
scalaDeps.mapToIArray { case (_, v) => v.names },
9293
cleanIllegalNames,
94+
useDeprecatedModuleNames,
9395
)
9496

9597
val importType = new ImportType(new StdNames(outputPkg))

importer/src/main/scala/org/scalablytyped/converter/internal/importer/Ci.scala

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,11 @@ object Ci {
113113
else Versions.Scala3,
114114
Versions.ScalaJs1,
115115
),
116-
organization = organization,
117-
enableReactTreeShaking = Selection.None,
118-
enableLongApplyMethod = false,
119-
privateWithin = None,
116+
organization = organization,
117+
enableReactTreeShaking = Selection.None,
118+
enableLongApplyMethod = false,
119+
privateWithin = None,
120+
useDeprecatedModuleNames = false,
120121
),
121122
wantedLibs = wantedLibNames,
122123
offline = flags contains "-offline",
@@ -272,10 +273,11 @@ class Ci(config: Ci.Config, paths: Ci.Paths, pool: ForkJoinPool, ec: ExecutionCo
272273
.next(
273274
new Phase2ToScalaJs(
274275
config.pedantic,
275-
scalaVersion = config.conversion.versions.scala,
276-
enableScalaJsDefined = config.conversion.enableScalaJsDefined,
277-
outputPkg = config.conversion.outputPackage,
278-
flavour = config.conversion.flavourImpl,
276+
scalaVersion = config.conversion.versions.scala,
277+
enableScalaJsDefined = config.conversion.enableScalaJsDefined,
278+
outputPkg = config.conversion.outputPackage,
279+
flavour = config.conversion.flavourImpl,
280+
useDeprecatedModuleNames = config.conversion.useDeprecatedModuleNames,
279281
),
280282
"scala.js",
281283
)

importer/src/test/scala/org/scalablytyped/converter/internal/importer/ImporterHarness.scala

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,11 @@ trait ImporterHarness extends AnyFunSuite {
8989
.next(
9090
new Phase2ToScalaJs(
9191
pedantic,
92-
scalaVersion = version.scala,
93-
enableScalaJsDefined = Selection.All,
94-
outputPkg = flavour.outputPkg,
95-
flavour = flavour,
92+
scalaVersion = version.scala,
93+
enableScalaJsDefined = Selection.All,
94+
outputPkg = flavour.outputPkg,
95+
flavour = flavour,
96+
useDeprecatedModuleNames = false,
9697
),
9798
"scala.js",
9899
)

sbt-converter/src/main/scala/org/scalablytyped/converter/internal/ImportTypings.scala

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,12 @@ object ImportTypings {
9393
)
9494
.next(
9595
new Phase2ToScalaJs(
96-
pedantic = false,
97-
scalaVersion = input.conversion.versions.scala,
98-
enableScalaJsDefined = input.conversion.enableScalaJsDefined,
99-
outputPkg = input.conversion.outputPackage,
100-
flavour = input.conversion.flavourImpl,
96+
pedantic = false,
97+
scalaVersion = input.conversion.versions.scala,
98+
enableScalaJsDefined = input.conversion.enableScalaJsDefined,
99+
outputPkg = input.conversion.outputPackage,
100+
flavour = input.conversion.flavourImpl,
101+
useDeprecatedModuleNames = input.conversion.useDeprecatedModuleNames,
101102
),
102103
"scala.js",
103104
)

sbt-converter/src/main/scala/org/scalablytyped/converter/internal/ImportTypingsGenSources.scala

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,12 @@ object ImportTypingsGenSources {
7676
)
7777
.next(
7878
new Phase2ToScalaJs(
79-
pedantic = false,
80-
scalaVersion = input.conversion.versions.scala,
81-
enableScalaJsDefined = input.conversion.enableScalaJsDefined,
82-
outputPkg = conversion.outputPackage,
83-
flavour = input.conversion.flavourImpl,
79+
pedantic = false,
80+
scalaVersion = input.conversion.versions.scala,
81+
enableScalaJsDefined = input.conversion.enableScalaJsDefined,
82+
outputPkg = conversion.outputPackage,
83+
flavour = input.conversion.flavourImpl,
84+
useDeprecatedModuleNames = input.conversion.useDeprecatedModuleNames,
8485
),
8586
"scala.js",
8687
)
@@ -155,18 +156,19 @@ object ImportTypingsGenSources {
155156
val outputName = Name.typings
156157

157158
val conversion = ConversionOptions(
158-
useScalaJsDomTypes = true,
159-
flavour = Flavour.Slinky,
160-
outputPackage = outputName,
161-
enableScalaJsDefined = Selection.All,
162-
stdLibs = SortedSet("es5", "dom"),
163-
expandTypeMappings = EnabledTypeMappingExpansion.DefaultSelection,
164-
ignored = SortedSet(),
165-
versions = Versions(Versions.Scala213, Versions.ScalaJs1),
166-
organization = "org.scalablytyped",
167-
enableReactTreeShaking = Selection.None,
168-
enableLongApplyMethod = false,
169-
privateWithin = None,
159+
useScalaJsDomTypes = true,
160+
flavour = Flavour.Slinky,
161+
outputPackage = outputName,
162+
enableScalaJsDefined = Selection.All,
163+
stdLibs = SortedSet("es5", "dom"),
164+
expandTypeMappings = EnabledTypeMappingExpansion.DefaultSelection,
165+
ignored = SortedSet(),
166+
versions = Versions(Versions.Scala213, Versions.ScalaJs1),
167+
organization = "org.scalablytyped",
168+
enableReactTreeShaking = Selection.None,
169+
enableLongApplyMethod = false,
170+
privateWithin = None,
171+
useDeprecatedModuleNames = false,
170172
)
171173

172174
println(

sbt-converter/src/main/scala/org/scalablytyped/converter/plugin/ScalablyTypedPluginBase.scala

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,11 @@ object ScalablyTypedPluginBase extends AutoPlugin {
4747
"If a given library is enabled, the react flavour will pick *longest* module names instead of shortest.",
4848
)
4949
val stEnableLongApplyMethod = settingKey[Boolean]("long apply methods instead of implicit ops builders")
50-
val stPrivateWithin = settingKey[Option[String]]("generate all top-level things private to the given package")
51-
val stIncludeDev = settingKey[Boolean]("generate facades for dev dependencies as well")
50+
val stShortModuleNames = settingKey[Boolean](
51+
"Enables short module names. This used to be the default, and is now deprecated since it's so difficult to navigate",
52+
)
53+
val stPrivateWithin = settingKey[Option[String]]("generate all top-level things private to the given package")
54+
val stIncludeDev = settingKey[Boolean]("generate facades for dev dependencies as well")
5255
}
5356

5457
override def requires = JvmPlugin && PlatformDepsPlugin
@@ -71,6 +74,7 @@ object ScalablyTypedPluginBase extends AutoPlugin {
7174
stEnableLongApplyMethod := false,
7275
stPrivateWithin := None,
7376
stIncludeDev := false,
77+
stShortModuleNames := false,
7478
stConversionOptions := {
7579
val versions = Versions(
7680
Versions.Scala(scalaVersion = (Compile / Keys.scalaVersion).value),
@@ -85,18 +89,19 @@ object ScalablyTypedPluginBase extends AutoPlugin {
8589
}
8690

8791
ConversionOptions(
88-
useScalaJsDomTypes = stUseScalaJsDom.value,
89-
flavour = stFlavour.value,
90-
outputPackage = outputPackage,
91-
enableScalaJsDefined = stEnableScalaJsDefined.value.map(TsIdentLibrary.apply),
92-
stdLibs = SortedSet.empty ++ stStdlib.value,
93-
expandTypeMappings = stInternalExpandTypeMappings.value.map(TsIdentLibrary.apply),
94-
ignored = stIgnore.value.to[Set].sorted,
95-
versions = versions,
96-
organization = organization,
97-
enableReactTreeShaking = stReactEnableTreeShaking.value.map(name => ImportName(TsIdentLibrary(name))),
98-
enableLongApplyMethod = stEnableLongApplyMethod.value,
99-
privateWithin = stPrivateWithin.value.map(Name.apply),
92+
useScalaJsDomTypes = stUseScalaJsDom.value,
93+
flavour = stFlavour.value,
94+
outputPackage = outputPackage,
95+
enableScalaJsDefined = stEnableScalaJsDefined.value.map(TsIdentLibrary.apply),
96+
stdLibs = SortedSet.empty ++ stStdlib.value,
97+
expandTypeMappings = stInternalExpandTypeMappings.value.map(TsIdentLibrary.apply),
98+
ignored = stIgnore.value.to[Set].sorted,
99+
versions = versions,
100+
organization = organization,
101+
enableReactTreeShaking = stReactEnableTreeShaking.value.map(name => ImportName(TsIdentLibrary(name))),
102+
enableLongApplyMethod = stEnableLongApplyMethod.value,
103+
privateWithin = stPrivateWithin.value.map(Name.apply),
104+
useDeprecatedModuleNames = stShortModuleNames.value,
100105
)
101106
},
102107
)

0 commit comments

Comments
 (0)