├── .github └── workflows │ └── release.yml ├── .gitignore ├── .scalafmt.conf ├── annotations └── src │ └── main │ └── scala │ └── eu │ └── swdev │ └── scala │ └── ts │ └── annotation │ └── adapt-annotations.scala ├── build.sbt ├── example └── angular │ ├── build.sbt │ ├── client │ └── src │ │ └── main │ │ └── scala │ │ └── CounterClient.scala │ ├── project │ ├── build.properties │ └── plugins.sbt │ ├── readme.md │ ├── server │ └── src │ │ └── main │ │ └── scala │ │ └── CounterServer.scala │ ├── shared │ └── src │ │ └── main │ │ └── scala │ │ └── CounterEndpoints.scala │ └── webapp │ ├── README.md │ ├── angular.json │ ├── browserslist │ ├── karma.conf.js │ ├── package-lock.json │ ├── package.json │ ├── proxy.conf.json │ ├── src │ ├── app │ │ ├── app.component.css │ │ ├── app.component.html │ │ ├── app.component.spec.ts │ │ ├── app.component.ts │ │ └── app.module.ts │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.css │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.spec.json │ └── tslint.json ├── explore ├── jest.config.mjs ├── module │ ├── index.d.ts │ ├── index.js │ ├── index.js.map │ └── package.json ├── package-lock.json ├── package.json ├── readme.md ├── src │ ├── app.ts │ ├── main │ │ ├── module │ │ │ ├── index.d.ts │ │ │ └── package.json │ │ └── scala │ │ │ ├── AdapterV1.scala │ │ │ └── scalajs.scala │ └── test │ │ └── ts │ │ ├── adapter.spec.ts │ │ ├── adt.spec.ts │ │ ├── array.spec.ts │ │ ├── class-with-inner-obj.spec.ts │ │ ├── iterator.spec.ts │ │ ├── non-exported-js-object.spec.ts │ │ ├── property.spec.ts │ │ ├── trait-methods.spec.ts │ │ └── util.ts ├── tsconfig.json └── tslint.json ├── generator └── src │ ├── main │ └── scala │ │ └── eu │ │ └── swdev │ │ └── scala │ │ └── ts │ │ ├── Adapter.scala │ │ ├── AdapterGenerator.scala │ │ ├── AdapterGeneratorMain.scala │ │ ├── AdapterTypeFormatter.scala │ │ ├── Adaption.scala │ │ ├── Analyzer.scala │ │ ├── DtsGeneratorMain.scala │ │ ├── Generator.scala │ │ ├── GeneratorMain.scala │ │ ├── Input.scala │ │ ├── Namespace.scala │ │ ├── NativeSymbolAnalyzer.scala │ │ ├── Output.scala │ │ ├── ReferencedSymbolsAnalyzer.scala │ │ ├── Result.scala │ │ ├── SealedTraitSubtypeAnalyzer.scala │ │ ├── SemSource.scala │ │ ├── TypeFormatter.scala │ │ ├── ValidationInfo.scala │ │ └── package.scala │ └── test │ ├── scala-2.13 │ └── eu │ │ └── swdev │ │ └── scala │ │ └── ts │ │ └── dts │ │ └── LiteralTypeTest.scala │ └── scala │ ├── eu │ └── swdev │ │ └── scala │ │ └── ts │ │ ├── AbstractAutoDetectingTest.scala │ │ ├── AdapterFunSuite.scala │ │ ├── DtsFunSuite.scala │ │ ├── FullNameTest.scala │ │ ├── GeneratorTest.scala │ │ ├── NativeSymbolAnalyzerTest.scala │ │ ├── ScalaMetaHelper.scala │ │ ├── adapter │ │ ├── ArrayTest.scala │ │ ├── ClassTest.scala │ │ ├── ListTest.scala │ │ ├── NestedClassTest.scala │ │ └── ObjectDefValVarTest.scala │ │ ├── auto │ │ ├── AutoDetectingTest.scala │ │ ├── PrimitiveTypes.scala │ │ ├── group-1-file-1.scala │ │ └── group-1-file-2.scala │ │ ├── dts │ │ ├── AbstractClassTest1.scala │ │ ├── AbstractClassTest2.scala │ │ ├── AccessorPairTest.scala │ │ ├── AccessorTest.scala │ │ ├── AdapterClassTest.scala │ │ ├── AdapterNestedClassTest.scala │ │ ├── AdapterV1.scala │ │ ├── Adt1Test.scala │ │ ├── Adt2Test.scala │ │ ├── Adt3Test.scala │ │ ├── AliasTest.scala │ │ ├── ApiReferenceTest.scala │ │ ├── ArrayTest.scala │ │ ├── ArrayTypeAliasTest.scala │ │ ├── BoundsTest.scala │ │ ├── BracketNotationTest.scala │ │ ├── ClassInheritanceTest.scala │ │ ├── ClassTest.scala │ │ ├── ClassWithInnerObjPropertyTest.scala │ │ ├── CtorParamExportTest.scala │ │ ├── DateTest.scala │ │ ├── DictionaryTest.scala │ │ ├── FunctionTest.scala │ │ ├── GenericClassTest.scala │ │ ├── GenericFunctionTest.scala │ │ ├── GenericUnionTest.scala │ │ ├── GlobalTest.scala │ │ ├── ImportNamespaceTest.scala │ │ ├── ImportTest.scala │ │ ├── InnerClassTest.scala │ │ ├── IteratorTest.scala │ │ ├── JSExportTest.scala │ │ ├── JsClassTest.scala │ │ ├── NativeSymbolTest.scala │ │ ├── NoneTest.scala │ │ ├── ObjectTest.scala │ │ ├── OuterTest.scala │ │ ├── PromiseLikeTest.scala │ │ ├── PromiseTest.scala │ │ ├── ReadOnlyArrayTest.scala │ │ ├── RegExpTest.scala │ │ ├── RootPackageClassTest.scala │ │ ├── RootPackageObjectTest.scala │ │ ├── SealedTraitAllMembersExportedTest.scala │ │ ├── SealedTraitHierarchyTest.scala │ │ ├── SealedTraitNoMembersExportedTest.scala │ │ ├── SealedTraitSomeMembersExportedTest.scala │ │ ├── SealedTraitUnexportedMembersTest.scala │ │ ├── SealedTraitWithoutMembersExportedTest.scala │ │ ├── StaticTest.scala │ │ ├── SymbolTest.scala │ │ ├── ThisFunctionTest.scala │ │ ├── TopLevelDefValVarTest.scala │ │ ├── TraitInheritanceTest1.scala │ │ ├── TraitInheritanceTest2.scala │ │ ├── TupleTest.scala │ │ ├── TypeAliasTest.scala │ │ ├── UndefOrTest.scala │ │ ├── UnionTest.scala │ │ └── VarArgsTest.scala │ │ └── tpe │ │ └── package.scala │ └── scala │ └── scalajs │ └── js │ ├── annotation │ └── stubs.scala │ ├── package.scala │ └── stubs.scala ├── project ├── build.properties └── plugins.sbt ├── readme.md ├── runtime └── src │ ├── main │ └── scala │ │ └── eu │ │ └── swdev │ │ └── scala │ │ └── ts │ │ ├── adapter │ │ ├── InteropConverter.scala │ │ ├── InteropIterable.scala │ │ └── package.scala │ │ └── tpe │ │ └── package.scala │ └── test │ └── scala │ └── eu │ └── swdev │ └── scala │ └── ts │ └── adapter │ ├── AsyncConverterTest.scala │ └── ConverterTest.scala └── sbt-scala-ts └── src ├── main └── scala │ ├── BuildInfo.scala │ └── ScalaTsPlugin.scala └── sbt-test ├── readme.md └── scala-ts ├── adapter ├── build.sbt ├── client │ ├── package-lock.json │ ├── package.json │ ├── src │ │ └── test │ │ │ └── ts │ │ │ ├── spec │ │ │ ├── date-adaption.spec.ts │ │ │ ├── nested-class.spec.ts │ │ │ ├── package-object.spec.ts │ │ │ ├── simple-class.spec.ts │ │ │ ├── util.spec.ts │ │ │ └── util.ts │ │ │ ├── tsconfig.json │ │ │ ├── ws-scala-2.12 │ │ │ ├── jest.config.mjs │ │ │ ├── mod │ │ │ │ └── scala-ts-mod.ts │ │ │ ├── package.json │ │ │ ├── spec │ │ │ └── tsconfig.json │ │ │ └── ws-scala-2.13 │ │ │ ├── jest.config.mjs │ │ │ ├── mod │ │ │ └── scala-ts-mod.ts │ │ │ ├── package.json │ │ │ ├── spec │ │ │ └── tsconfig.json │ └── tsconfig.json ├── project │ ├── build.properties │ ├── plugins.sbt │ └── project │ │ └── plugins.sbt ├── readme.md ├── shared │ └── src │ │ └── main │ │ └── scala │ │ ├── DateAdaption.scala │ │ ├── OuterClass.scala │ │ ├── SimpleClass.scala │ │ ├── Util.scala │ │ └── eu │ │ └── swdev │ │ └── scala │ │ └── ts │ │ └── adapter │ │ └── test │ │ └── package.scala └── test ├── dts ├── build.sbt ├── package-lock.json ├── package.json ├── project │ ├── build.properties │ ├── plugins.sbt │ └── project │ │ └── plugins.sbt ├── readme.md ├── src │ ├── main │ │ ├── scala-2.13 │ │ │ └── e2e │ │ │ │ ├── AdtTest.scala │ │ │ │ └── FunctionTest.scala │ │ └── scala │ │ │ └── e2e │ │ │ ├── Abstract.scala │ │ │ ├── Adapter1.scala │ │ │ ├── AdapterWithInnerClass.scala │ │ │ ├── BigIntInterop.scala │ │ │ ├── BracketNotation.scala │ │ │ ├── ClassWithStatics.scala │ │ │ ├── FromToRange.scala │ │ │ ├── Outer.scala │ │ │ ├── TraitInheritance1.scala │ │ │ ├── TraitInheritance2.scala │ │ │ ├── file1.scala │ │ │ └── root-package.scala │ └── test │ │ └── ts │ │ ├── spec │ │ ├── abstract.spec.ts │ │ ├── api-reference.spec.ts │ │ ├── bigint.spec.ts │ │ ├── bracket-notation.spec.ts │ │ ├── ctor-param-export.spec.ts │ │ ├── date.spec.ts │ │ ├── dictionary.spec.ts │ │ ├── global.spec.ts │ │ ├── import.spec.ts │ │ ├── iterable.spec.ts │ │ ├── iterator.spec.ts │ │ ├── js-class.spec.ts │ │ ├── nested-objects.spec.ts │ │ ├── promise.spec.ts │ │ ├── regexp.spec.ts │ │ ├── root-package.spec.ts │ │ ├── static.spec.ts │ │ ├── this-function.spec.ts │ │ ├── top-level-def-val-var.spec.ts │ │ ├── trait-inheritance.spec.ts │ │ ├── tuple.spec.ts │ │ ├── type-conversions.spec.ts │ │ ├── union.spec.ts │ │ └── varargs.spec.ts │ │ ├── tsconfig.json │ │ ├── ws-scala-2.12 │ │ ├── jest.config.mjs │ │ ├── mod │ │ │ └── scala-ts-mod.ts │ │ ├── package.json │ │ ├── spec │ │ └── tsconfig.json │ │ └── ws-scala-2.13 │ │ ├── jest.config.mjs │ │ ├── mod │ │ └── scala-ts-mod.ts │ │ ├── package.json │ │ ├── spec │ │ ├── spec-2.13 │ │ ├── function.spec.ts │ │ ├── object-adt.spec.ts │ │ ├── simple-adt.spec.ts │ │ └── util.ts │ │ └── tsconfig.json └── test ├── readme.md └── simple ├── build.sbt ├── project ├── build.properties ├── plugins.sbt └── project │ └── plugins.sbt ├── src └── main │ └── scala │ └── simple │ └── file1.scala └── test /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | branches: [master, main, 'feature/**'] 5 | tags: ["*"] 6 | jobs: 7 | publish: 8 | runs-on: ubuntu-20.04 9 | steps: 10 | - uses: actions/checkout@v3 11 | with: 12 | fetch-depth: 0 13 | - uses: actions/setup-java@v3 14 | with: 15 | distribution: temurin 16 | java-version: 8 17 | cache: sbt 18 | - run: sbt ci-release 19 | env: 20 | PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} 21 | PGP_SECRET: ${{ secrets.PGP_SECRET }} 22 | SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} 23 | SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | !.github 3 | target 4 | dist 5 | node_modules 6 | -------------------------------------------------------------------------------- /.scalafmt.conf: -------------------------------------------------------------------------------- 1 | maxColumn = 140 2 | align = most 3 | -------------------------------------------------------------------------------- /annotations/src/main/scala/eu/swdev/scala/ts/annotation/adapt-annotations.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.annotation 2 | 3 | import scala.annotation.Annotation 4 | 5 | /** 6 | * Indicates that adapter code should be generated and allows to override the default interoperation type. 7 | * 8 | * The interop type is the type that is exposed to the JavaScript side. It is either the type of parameters 9 | * or of returned values. ScalaTs chooses a default interop type if no interop type is specified. 10 | * 11 | * - When applied to a def, val, var then adapter code for accessing the definition is created; the interop 12 | * specifies the type of the returned value. 13 | * - When applied to a parameter of an adapted 'def' or constructor then the interop type specifies the type 14 | * of the exposed parameter. 15 | * 16 | * This annotation has no effect when applied on classes, objects, or traits. 17 | */ 18 | class Adapt extends Annotation { 19 | def this(interopType: String) = this() 20 | } 21 | 22 | /** 23 | * Indicates that adapter code for all members should be generated. 24 | * 25 | * Can be applied to classes, objects, and traits. 26 | */ 27 | class AdaptMembers extends Annotation 28 | 29 | /** 30 | * Indicates that adapter code for a constructor should be generated. 31 | * 32 | * Can be applied to classes. 33 | */ 34 | class AdaptConstructor extends Annotation 35 | 36 | /** 37 | * Implies [[AdaptMembers]] and [[AdaptConstructor]]. 38 | * 39 | * Can be applied to classes, objects, and traits. 40 | */ 41 | class AdaptAll extends Annotation 42 | 43 | -------------------------------------------------------------------------------- /example/angular/build.sbt: -------------------------------------------------------------------------------- 1 | ThisBuild / scalaVersion := "2.13.11" 2 | 3 | val shared = 4 | crossProject(JSPlatform, JVMPlatform) 5 | .crossType(CrossType.Pure) 6 | .settings( 7 | libraryDependencies ++= Seq( 8 | "org.endpoints4s" %%% "algebra" % "1.0.0", 9 | "org.endpoints4s" %%% "json-schema-generic" % "1.0.0", 10 | ) 11 | ) 12 | .jvmSettings( 13 | libraryDependencies += "org.scala-js" %% "scalajs-stubs" % "1.0.0" % "provided", 14 | ) 15 | .jsSettings( 16 | // the shared project contains classes (i.e. Counter and Increment) that are referenced in the exported API of the client project 17 | // -> semantic db information is required for these classes 18 | // -> configure the semanticdb compiler plugin 19 | ScalaTsPlugin.crossProject.jsSettings 20 | ) 21 | 22 | val sharedJS = shared.js 23 | val sharedJVM = shared.jvm 24 | 25 | val client = 26 | project 27 | .enablePlugins(ScalaTsPlugin) 28 | .settings( 29 | scalaTsModuleName := "scala-client", 30 | scalaTsConsiderFullCompileClassPath := true, 31 | libraryDependencies += "org.endpoints4s" %%% "xhr-client" % "1.0.0+sjs1", 32 | ) 33 | .dependsOn(sharedJS) 34 | 35 | val server = 36 | project 37 | .settings( 38 | libraryDependencies ++= Seq( 39 | "org.endpoints4s" %% "akka-http-server" % "1.0.0", 40 | ) 41 | ) 42 | .dependsOn(sharedJVM) 43 | 44 | lazy val root = project 45 | .in(file(".")) 46 | .aggregate(client, server, sharedJS, sharedJVM) 47 | .settings( 48 | name := "scala-ts-angular", 49 | publish := {}, 50 | publishLocal := {}, 51 | ) 52 | -------------------------------------------------------------------------------- /example/angular/client/src/main/scala/CounterClient.scala: -------------------------------------------------------------------------------- 1 | package org.test.client 2 | 3 | import endpoints4s.xhr 4 | import org.test.shared.{Counter, CounterEndpoints, Increment} 5 | 6 | import scala.scalajs.js 7 | import scala.scalajs.js.annotation.JSExportTopLevel 8 | 9 | /** 10 | * Defines an HTTP client for the endpoints described in the `CounterEndpoints` trait. 11 | * The derived HTTP client uses XMLHttpRequest to perform requests and returns 12 | * results in a `js.Thenable`. 13 | */ 14 | @JSExportTopLevel("CounterClient") 15 | object CounterClient extends js.Object { 16 | 17 | private object client 18 | extends CounterEndpoints 19 | with xhr.thenable.Endpoints 20 | with xhr.JsonEntitiesFromSchemas 21 | 22 | /** 23 | * Performs an XMLHttpRequest on the `currentValue` endpoint, and then 24 | * deserializes the JSON response as a `Counter`. 25 | */ 26 | def currentValue(): js.Thenable[Counter] = client.currentValue(()) 27 | 28 | /** 29 | * Serializes the `Increment` value into JSON and performs an XMLHttpRequest 30 | * on the `increment` endpoint. 31 | */ 32 | def increment(value: Int): js.Thenable[Unit] = client.increment(Increment(value)) 33 | } 34 | -------------------------------------------------------------------------------- /example/angular/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.9.3 -------------------------------------------------------------------------------- /example/angular/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("io.github.swachter" % "sbt-scala-ts" % "0.12.0") 2 | 3 | addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.1.1") 4 | addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.0.0") 5 | -------------------------------------------------------------------------------- /example/angular/readme.md: -------------------------------------------------------------------------------- 1 | ### Example Project: Angular with [endpoint4s](https://endpoints4s.github.io/) 2 | 3 | - A simple counter service is defined using endpoint4s. The example was copied from endpoint4s. 4 | - The definition is shared by the server and the client. 5 | - A Node module is generated that allows the Angular applicatioin to communicate with the server in a type safe manner. 6 | 7 | Generate the Node module that is used in the Angular application to access the server: 8 | 9 | ``` 10 | > sbt client/scalaTsFastOpt 11 | ``` 12 | 13 | Start the server via SBT: 14 | 15 | ``` 16 | > sbt server/run 17 | ``` 18 | 19 | In the webapp folder run: 20 | 21 | ``` 22 | > npm i 23 | > npm start 24 | ``` -------------------------------------------------------------------------------- /example/angular/server/src/main/scala/CounterServer.scala: -------------------------------------------------------------------------------- 1 | package org.test.server 2 | 3 | import java.util.concurrent.atomic.AtomicInteger 4 | 5 | import akka.http.scaladsl.server.Directives._ 6 | import akka.http.scaladsl.server.{HttpApp, Route} 7 | import endpoints4s.akkahttp.server 8 | import org.test.shared.{Counter, CounterEndpoints} 9 | 10 | /** 11 | * Defines Akka HTTP routes for the endpoints described in the `CounterEndpoints` trait. 12 | */ 13 | object CounterServer 14 | extends CounterEndpoints 15 | with server.Endpoints 16 | with server.JsonEntitiesFromSchemas { 17 | 18 | /** Simple implementation of an in-memory counter */ 19 | val counter = new AtomicInteger() 20 | 21 | // Implements the `currentValue` endpoint 22 | val currentValueRoute = currentValue.implementedBy(_ => Counter(counter.get)) 23 | 24 | // Implements the `increment` endpoint 25 | val incrementRoute = increment.implementedBy(inc => counter.addAndGet(inc.step)) 26 | 27 | val routes: Route = currentValueRoute ~ incrementRoute 28 | 29 | } 30 | 31 | object WebServer extends HttpApp { 32 | override protected def routes: Route = CounterServer.routes 33 | 34 | def main(args: Array[String]): Unit = startServer("localhost", 8000) 35 | } -------------------------------------------------------------------------------- /example/angular/shared/src/main/scala/CounterEndpoints.scala: -------------------------------------------------------------------------------- 1 | package org.test.shared 2 | 3 | import endpoints4s.{algebra, generic} 4 | 5 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 6 | 7 | /** 8 | * Defines the HTTP endpoints description of a web service implementing a counter. 9 | * This web service has two endpoints: one for getting the current value of the counter, 10 | * and one for incrementing it. 11 | */ 12 | trait CounterEndpoints extends algebra.Endpoints with algebra.JsonEntitiesFromSchemas with generic.JsonSchemas { 13 | 14 | /** 15 | * Get the counter current value. 16 | * Uses the HTTP verb “GET” and URL path “/current-value”. 17 | * The response entity is a JSON document representing the counter value. 18 | */ 19 | val currentValue: Endpoint[Unit, Counter] = endpoint(get(path / "current-value"), ok(jsonResponse[Counter])) 20 | 21 | /** 22 | * Increments the counter value. 23 | * Uses the HTTP verb “POST” and URL path “/increment”. 24 | * The request entity is a JSON document representing the increment to apply to the counter. 25 | * The response entity is empty. 26 | */ 27 | val increment: Endpoint[Increment, Unit] = endpoint(post(path / "increment", jsonRequest[Increment]), ok(emptyResponse)) 28 | 29 | // Generically derive the JSON schema of our `Counter` 30 | // and `Increment` case classes defined thereafter 31 | implicit lazy val counterSchema: JsonSchema[Counter] = genericJsonSchema 32 | implicit lazy val incrementSchema: JsonSchema[Increment] = genericJsonSchema 33 | 34 | } 35 | 36 | @JSExportTopLevel("Counter") 37 | @JSExportAll 38 | case class Counter(value: Int) 39 | @JSExportTopLevel("Increment") 40 | @JSExportAll 41 | case class Increment(step: Int) 42 | -------------------------------------------------------------------------------- /example/angular/webapp/README.md: -------------------------------------------------------------------------------- 1 | # Webapp 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 9.1.11. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /example/angular/webapp/browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /example/angular/webapp/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/webapp'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /example/angular/webapp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webapp", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve --proxy-config proxy.conf.json --open", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e" 11 | }, 12 | "type": "module", 13 | "private": true, 14 | "dependencies": { 15 | "@angular/animations": "~9.1.12", 16 | "@angular/common": "~9.1.12", 17 | "@angular/compiler": "~9.1.12", 18 | "@angular/core": "~9.1.12", 19 | "@angular/forms": "~9.1.12", 20 | "@angular/platform-browser": "~9.1.12", 21 | "@angular/platform-browser-dynamic": "~9.1.12", 22 | "@angular/router": "~9.1.12", 23 | "rxjs": "~6.5.4", 24 | "scala-client": "file:../client/target/scala-2.13", 25 | "tslib": "^1.10.0", 26 | "zone.js": "~0.10.2" 27 | }, 28 | "devDependencies": { 29 | "@angular-devkit/build-angular": "~0.901.11", 30 | "@angular/cli": "~9.1.11", 31 | "@angular/compiler-cli": "~9.1.12", 32 | "@types/node": "^12.11.1", 33 | "@types/jasmine": "~3.5.0", 34 | "@types/jasminewd2": "~2.0.3", 35 | "codelyzer": "^5.1.2", 36 | "jasmine-core": "~3.5.0", 37 | "jasmine-spec-reporter": "~4.2.1", 38 | "karma": "~5.0.0", 39 | "karma-chrome-launcher": "~3.1.0", 40 | "karma-coverage-istanbul-reporter": "~2.1.0", 41 | "karma-jasmine": "~3.0.1", 42 | "karma-jasmine-html-reporter": "^1.4.2", 43 | "protractor": "~7.0.0", 44 | "ts-node": "~8.3.0", 45 | "tslint": "~6.1.0", 46 | "typescript": "~3.8.3" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /example/angular/webapp/proxy.conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "*": { 3 | "target": "http://localhost:8000", 4 | "secure": false, 5 | "pathRewrite": { 6 | "^/posts": "" 7 | }, 8 | "changeOrigin": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /example/angular/webapp/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swachter/scala-ts/5ae7cf3d79213686157e2a38d0afcace7037335d/example/angular/webapp/src/app/app.component.css -------------------------------------------------------------------------------- /example/angular/webapp/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
current counter value: {{counterValue}}
4 |
5 | 6 |
7 | 8 |
9 | -------------------------------------------------------------------------------- /example/angular/webapp/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { AppComponent } from './app.component'; 3 | 4 | describe('AppComponent', () => { 5 | beforeEach(async(() => { 6 | TestBed.configureTestingModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | }).compileComponents(); 11 | })); 12 | 13 | it('should create the app', () => { 14 | const fixture = TestBed.createComponent(AppComponent); 15 | const app = fixture.componentInstance; 16 | expect(app).toBeTruthy(); 17 | }); 18 | 19 | it(`should have as title 'webapp'`, () => { 20 | const fixture = TestBed.createComponent(AppComponent); 21 | const app = fixture.componentInstance; 22 | expect(app.title).toEqual('webapp'); 23 | }); 24 | 25 | it('should render title', () => { 26 | const fixture = TestBed.createComponent(AppComponent); 27 | fixture.detectChanges(); 28 | const compiled = fixture.nativeElement; 29 | expect(compiled.querySelector('.content span').textContent).toContain('webapp app is running!'); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /example/angular/webapp/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core' 2 | import { CounterClient } from 'scala-client' 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | templateUrl: './app.component.html', 7 | styleUrls: ['./app.component.css'] 8 | }) 9 | export class AppComponent { 10 | title = 'webapp' 11 | counterValue: number 12 | 13 | constructor() { 14 | this.updateCurrentValue() 15 | } 16 | 17 | private updateCurrentValue(): void { 18 | CounterClient.currentValue().then(counter => this.counterValue = counter.value) 19 | } 20 | 21 | increment(): void { 22 | CounterClient.increment(1).then(_ => this.updateCurrentValue()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /example/angular/webapp/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | 4 | import { AppComponent } from './app.component'; 5 | 6 | @NgModule({ 7 | declarations: [ 8 | AppComponent 9 | ], 10 | imports: [ 11 | BrowserModule 12 | ], 13 | providers: [], 14 | bootstrap: [AppComponent] 15 | }) 16 | export class AppModule { } 17 | -------------------------------------------------------------------------------- /example/angular/webapp/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /example/angular/webapp/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /example/angular/webapp/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swachter/scala-ts/5ae7cf3d79213686157e2a38d0afcace7037335d/example/angular/webapp/src/favicon.ico -------------------------------------------------------------------------------- /example/angular/webapp/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Webapp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /example/angular/webapp/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /example/angular/webapp/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | -------------------------------------------------------------------------------- /example/angular/webapp/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /example/angular/webapp/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | keys(): string[]; 13 | (id: string): T; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting() 21 | ); 22 | // Then we find all the tests. 23 | const context = require.context('./', true, /\.spec\.ts$/); 24 | // And load the modules. 25 | context.keys().map(context); 26 | -------------------------------------------------------------------------------- /example/angular/webapp/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /example/angular/webapp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "es2015", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "lib": [ 15 | "es2018", 16 | "dom" 17 | ] 18 | }, 19 | "angularCompilerOptions": { 20 | "fullTemplateTypeCheck": true, 21 | "strictInjectionParameters": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/angular/webapp/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /example/angular/webapp/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rules": { 4 | "align": { 5 | "options": [ 6 | "parameters", 7 | "statements" 8 | ] 9 | }, 10 | "array-type": false, 11 | "arrow-return-shorthand": true, 12 | "curly": true, 13 | "deprecation": { 14 | "severity": "warning" 15 | }, 16 | "component-class-suffix": true, 17 | "contextual-lifecycle": true, 18 | "directive-class-suffix": true, 19 | "directive-selector": [ 20 | true, 21 | "attribute", 22 | "app", 23 | "camelCase" 24 | ], 25 | "component-selector": [ 26 | true, 27 | "element", 28 | "app", 29 | "kebab-case" 30 | ], 31 | "eofline": true, 32 | "import-blacklist": [ 33 | true, 34 | "rxjs/Rx" 35 | ], 36 | "import-spacing": true, 37 | "indent": { 38 | "options": [ 39 | "spaces" 40 | ] 41 | }, 42 | "max-classes-per-file": false, 43 | "max-line-length": [ 44 | true, 45 | 140 46 | ], 47 | "member-ordering": [ 48 | true, 49 | { 50 | "order": [ 51 | "static-field", 52 | "instance-field", 53 | "static-method", 54 | "instance-method" 55 | ] 56 | } 57 | ], 58 | "no-console": [ 59 | true, 60 | "debug", 61 | "info", 62 | "time", 63 | "timeEnd", 64 | "trace" 65 | ], 66 | "no-empty": false, 67 | "no-inferrable-types": [ 68 | true, 69 | "ignore-params" 70 | ], 71 | "no-non-null-assertion": true, 72 | "no-redundant-jsdoc": true, 73 | "no-switch-case-fall-through": true, 74 | "no-var-requires": false, 75 | "object-literal-key-quotes": [ 76 | true, 77 | "as-needed" 78 | ], 79 | "quotemark": [ 80 | true, 81 | "single" 82 | ], 83 | "semicolon": { 84 | "options": [ 85 | "always" 86 | ] 87 | }, 88 | "space-before-function-paren": { 89 | "options": { 90 | "anonymous": "never", 91 | "asyncArrow": "always", 92 | "constructor": "never", 93 | "method": "never", 94 | "named": "never" 95 | } 96 | }, 97 | "typedef-whitespace": { 98 | "options": [ 99 | { 100 | "call-signature": "nospace", 101 | "index-signature": "nospace", 102 | "parameter": "nospace", 103 | "property-declaration": "nospace", 104 | "variable-declaration": "nospace" 105 | }, 106 | { 107 | "call-signature": "onespace", 108 | "index-signature": "onespace", 109 | "parameter": "onespace", 110 | "property-declaration": "onespace", 111 | "variable-declaration": "onespace" 112 | } 113 | ] 114 | }, 115 | "variable-name": { 116 | "options": [ 117 | "ban-keywords", 118 | "check-format", 119 | "allow-pascal-case" 120 | ] 121 | }, 122 | "whitespace": { 123 | "options": [ 124 | "check-branch", 125 | "check-decl", 126 | "check-operator", 127 | "check-separator", 128 | "check-type", 129 | "check-typecast" 130 | ] 131 | }, 132 | "no-conflicting-lifecycle": true, 133 | "no-host-metadata-property": true, 134 | "no-input-rename": true, 135 | "no-inputs-metadata-property": true, 136 | "no-output-native": true, 137 | "no-output-on-prefix": true, 138 | "no-output-rename": true, 139 | "no-outputs-metadata-property": true, 140 | "template-banana-in-box": true, 141 | "template-no-negated-async": true, 142 | "use-lifecycle-interface": true, 143 | "use-pipe-transform-interface": true 144 | }, 145 | "rulesDirectory": [ 146 | "codelyzer" 147 | ] 148 | } -------------------------------------------------------------------------------- /explore/module/index.d.ts: -------------------------------------------------------------------------------- 1 | ../src/main/module/index.d.ts -------------------------------------------------------------------------------- /explore/module/index.js: -------------------------------------------------------------------------------- 1 | ../target/scala-2.13/explore-fastopt.js -------------------------------------------------------------------------------- /explore/module/index.js.map: -------------------------------------------------------------------------------- 1 | ../target/scala-2.13/explore-fastopt.js.map -------------------------------------------------------------------------------- /explore/module/package.json: -------------------------------------------------------------------------------- 1 | ../src/main/module/package.json -------------------------------------------------------------------------------- /explore/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "manual-dts", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "tsc && node dist/app.js", 8 | "test": "tsc && node --experimental-vm-modules node_modules/jest/bin/jest" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "devDependencies": { 13 | "@types/jest": "^25.2.3", 14 | "jest": "^26.0.1", 15 | "tslint": "^6.1.2", 16 | "typescript": "^3.8.3" 17 | }, 18 | "dependencies": { 19 | "@types/node": "^13.13.4", 20 | "from-scala": "file:module" 21 | }, 22 | "type": "module" 23 | } 24 | -------------------------------------------------------------------------------- /explore/readme.md: -------------------------------------------------------------------------------- 1 | Manual experiments for TypeScript <-> Scala interop 2 | === 3 | 4 | Scala sources are compiled into JavaScript containing an EcmaScript module. ScalaJS is configured to output an EcmaScript module by setting the corresponding `ModuleKind` in `build.sbt`: 5 | 6 | ``` 7 | scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.ESModule) } 8 | ``` 9 | 10 | The EcmaScript module in turn is augmented by a `package.json` and a hand crafted [TypeScript Declaration File](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html). The module is used by the TypeScript compiler and Node to compile and run the TypeScript application `app.ts`. 11 | 12 | Commands and Setup: 13 | --- 14 | 15 | Scala sources are compiled into JavaScript by: 16 | 17 | ``` 18 | > sbt explore/fastOptJS 19 | ``` 20 | 21 | The top-level `module` folder contains a couple of symbolic links: 22 | 23 | ``` 24 | index.d.ts -> ../src/main/module/index.d.ts 25 | index.js -> ../target/scala-2.13/explore-dts-fastopt.js 26 | index.js.map -> ../target/scala-2.13/explore-dts-fastopt.js.map 27 | package.json -> ../src/main/module/package.json 28 | ``` 29 | 30 | This folder represents a node module that contains the transpiled ScalaJS code and its meta data. In particular, the `package.json` file specifies that the module is an EcmaScript module named 'from-scala'. The 'from-scala' module has to be installed once as a local module by: 31 | 32 | ``` 33 | npm i ./module 34 | ``` 35 | 36 | Before running the test application or unit tests the necessary node modules have to be installed: 37 | 38 | ``` 39 | > npm i 40 | ``` 41 | 42 | Finally the TypeScript application `app.ts` can be compiled and run by: 43 | 44 | ``` 45 | > npm run start 46 | ``` 47 | 48 | Unit tests are run by: 49 | 50 | ``` 51 | npm t 52 | ``` 53 | -------------------------------------------------------------------------------- /explore/src/main/module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "from-scala", 3 | "main": "index.js", 4 | "version": "0.0.1", 5 | "type": "module" 6 | } 7 | -------------------------------------------------------------------------------- /explore/src/main/scala/AdapterV1.scala: -------------------------------------------------------------------------------- 1 | import scala.scalajs.js 2 | import scala.scalajs.js.annotation.{JSExport, JSExportAll, JSExportTopLevel} 3 | 4 | @JSExportTopLevel("AdapterV1") 5 | object AdapterV1 extends js.Object { 6 | 7 | @JSExportAll 8 | trait InstanceAdapter[D] { 9 | val $delegate: D 10 | } 11 | 12 | object x extends js.Object { 13 | 14 | @JSExportAll 15 | trait OuterV1 extends InstanceAdapter[_root_.x.OuterV1] { 16 | 17 | def x: Int = $delegate.x 18 | 19 | @JSExportAll 20 | trait MiddleV1 extends InstanceAdapter[_root_.x.OuterV1#MiddleV1] { 21 | 22 | def y: String = $delegate.y 23 | 24 | @JSExportAll 25 | trait InnerV1 extends InstanceAdapter[_root_.x.OuterV1#MiddleV1#InnerV1] { 26 | def z = $delegate.z 27 | } 28 | 29 | object InnerV1 extends js.Object { 30 | def newInstance(z: Boolean): _root_.x.OuterV1#MiddleV1#InnerV1 = new $delegate.InnerV1(z) 31 | def newAdapter(d: _root_.x.OuterV1#MiddleV1#InnerV1): InnerV1 = new InnerV1 { 32 | override val $delegate = d 33 | } 34 | } 35 | 36 | val innerV1 = InnerV1 37 | 38 | } 39 | 40 | object MiddleV1 extends js.Object { 41 | def newInstance(y: String): _root_.x.OuterV1#MiddleV1 = new $delegate.MiddleV1(y) 42 | def newAdapter(d: _root_.x.OuterV1#MiddleV1): MiddleV1 = new MiddleV1 { 43 | override val $delegate = d 44 | override def y = $delegate.y 45 | } 46 | } 47 | 48 | val middleV1 = MiddleV1 49 | 50 | } 51 | 52 | object OuterV1 extends js.Object { 53 | def newInstance(x: Int) = new _root_.x.OuterV1(x) 54 | def newAdapter(d: _root_.x.OuterV1): OuterV1 = new OuterV1 { 55 | override val $delegate = d 56 | override def x = $delegate.x 57 | } 58 | } 59 | 60 | val outerV1 = OuterV1 61 | 62 | } 63 | } 64 | 65 | package x { 66 | 67 | class OuterV1(val x: Int) { 68 | class MiddleV1(val y: String) { 69 | class InnerV1(val z: Boolean) { 70 | 71 | } 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /explore/src/test/ts/adapter.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from 'from-scala' 2 | import { assertNever } from './util' 3 | 4 | describe('adapter', function() { 5 | 6 | it('instantiate inner classes', function() { 7 | const outer = m.AdapterV1.x.OuterV1.newInstance(5) 8 | const outerAdapter = m.AdapterV1.x.OuterV1.newAdapter(outer) 9 | expect(outerAdapter.x).toBe(5) 10 | 11 | const middle = outerAdapter.middleV1.newInstance('abc') 12 | const middleAdapter = outerAdapter.middleV1.newAdapter(middle) 13 | expect(middleAdapter.y).toBe('abc') 14 | 15 | const inner = middleAdapter.innerV1.newInstance(true) 16 | const innerAdapter = middleAdapter.innerV1.newAdapter(inner) 17 | expect(innerAdapter.z).toBe(true) 18 | 19 | }); 20 | 21 | 22 | }); -------------------------------------------------------------------------------- /explore/src/test/ts/adt.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from 'from-scala' 2 | import { assertNever } from './util' 3 | 4 | describe('adt', function() { 5 | 6 | function checkByLiteralInt(adt: m.ADT, caseId: number): void { 7 | if (adt.literalTypedInt === 1) { 8 | expect(adt.caseId).toBe(1) 9 | } else if (adt.literalTypedInt === 2) { 10 | expect(adt.caseId).toBe(2) 11 | } else { 12 | assertNever(adt) 13 | } 14 | } 15 | 16 | function checkByLiteralString(adt: m.ADT, caseId: number): void { 17 | if (adt.literalTypedString === 'a') { 18 | expect(adt.caseId).toBe(1) 19 | } else if (adt.literalTypedString === 'b') { 20 | expect(adt.caseId).toBe(2) 21 | } else { 22 | assertNever(adt) 23 | } 24 | } 25 | 26 | function checkByLiteralBoolean(adt: m.ADT, caseId: number): void { 27 | if (adt.literalTypedBoolean === false) { 28 | expect(adt.caseId).toBe(1) 29 | } else if (adt.literalTypedBoolean === true) { 30 | expect(adt.caseId).toBe(2) 31 | } else { 32 | assertNever(adt) 33 | } 34 | } 35 | 36 | it('discriminate based on number', function() { 37 | checkByLiteralInt(new m.Case1(''), 1) 38 | checkByLiteralInt(new m.Case2(''), 2) 39 | }); 40 | 41 | it('discriminate based on string', function() { 42 | checkByLiteralString(new m.Case1(''), 1) 43 | checkByLiteralString(new m.Case2(''), 2) 44 | }); 45 | 46 | it('discriminate based on boolean', function() { 47 | checkByLiteralBoolean(new m.Case1(''), 1) 48 | checkByLiteralBoolean(new m.Case2(''), 2) 49 | }); 50 | 51 | 52 | }); -------------------------------------------------------------------------------- /explore/src/test/ts/array.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from 'from-scala' 2 | 3 | describe('array', function() { 4 | 5 | it('set / get vector', function() { 6 | const vec = [1, 2, 3] 7 | const mat = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 8 | const c = new m.ArrayAccess(vec, mat) 9 | 10 | expect(c.vector.length).toBe(vec.length) 11 | expect(c.matrix.length).toBe(mat.length) 12 | expect(c.matrix[0].length).toBe(mat[0].length) 13 | 14 | expect(c.vector).toStrictEqual(vec) 15 | expect(c.matrix).toStrictEqual(mat) 16 | 17 | const vec2 = [4] 18 | const mat2 = [[1]] 19 | c.vector = vec2 20 | c.matrix = mat2 21 | expect(c.vector).toStrictEqual(vec2) 22 | expect(c.matrix).toStrictEqual(mat2) 23 | }); 24 | 25 | }); -------------------------------------------------------------------------------- /explore/src/test/ts/class-with-inner-obj.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from 'from-scala' 2 | 3 | describe('class with inner obj', () => { 4 | 5 | it('inner object can be accessed', () => { 6 | const c = new m.ClassWithInnerObj() 7 | expect(c.x).toBe(1) 8 | // TODO uncomment after issue is fixed 9 | // cf. https://github.com/scala-js/scala-js/issues/4142 10 | //expect(c.innerObj.y).toBe(2) 11 | expect(c.innerObj).toBeUndefined 12 | }) 13 | 14 | }) -------------------------------------------------------------------------------- /explore/src/test/ts/iterator.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from 'from-scala' 2 | import { assertNever } from './util' 3 | 4 | describe('iterator', function() { 5 | 6 | it('discriminate based on number', function() { 7 | const range = new m.ToRange(0, 5) 8 | let sum = 0 9 | for (let n of range) { 10 | sum += n 11 | } 12 | expect(sum).toBe(15) 13 | }) 14 | 15 | }) 16 | 17 | -------------------------------------------------------------------------------- /explore/src/test/ts/non-exported-js-object.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from 'from-scala' 2 | 3 | describe('non-exported js.Object', function() { 4 | 5 | it('access js.Object member', function() { 6 | expect(m.nonExportedJsObject.name).toBe('nonExportedJsObject') 7 | }); 8 | 9 | it('access class derived from js.Object member', function() { 10 | expect(m.nonExportedJsClass().name).toBe('nonExportedJsClass') 11 | }); 12 | 13 | }); -------------------------------------------------------------------------------- /explore/src/test/ts/property.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from 'from-scala' 2 | 3 | describe('property', function() { 4 | 5 | it('access value via accessors and via property', function() { 6 | const i = new m.StdClass2() 7 | expect(i.value).toBe(5) 8 | i.value = 6 9 | expect(i.value).toBe(6) 10 | expect(i.valueProperty).toBe(6) 11 | i.valueProperty = 7 12 | expect(i.value).toBe(7) 13 | expect(i.valueProperty).toBe(7) 14 | }); 15 | 16 | it('array', () => { 17 | const i = new m.StdClass2() 18 | expect(i.numbers.length).toBe(5) 19 | i.numbers = [66, 67, 68] 20 | expect(i.numbers.length).toBe(3) 21 | expect(i.numbers[0]).toBe(66) 22 | expect(i.numbers[1]).toBe(67) 23 | expect(i.numbers[2]).toBe(68) 24 | }) 25 | 26 | it('option', () => { 27 | const i = new m.StdClass2() 28 | expect(i.option).toBe(5) 29 | i.option = undefined 30 | expect(i.option).toBeUndefined() 31 | i.option = 68 32 | expect(i.option).toBe(68) 33 | }) 34 | 35 | it('tuple', () => { 36 | const i = new m.StdClass2() 37 | expect(i.tuple).toStrictEqual(['abc', 1]) 38 | i.tuple = ['uvw', 2] 39 | expect(i.tuple).toStrictEqual(['uvw', 2]) 40 | }) 41 | 42 | }) -------------------------------------------------------------------------------- /explore/src/test/ts/trait-methods.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from 'from-scala' 2 | 3 | describe('trait methods', function() { 4 | 5 | it('simple', function() { 6 | const c = new m.ClassWithMethodsFromTraits() 7 | expect(c.base(2)).toBe(4) 8 | expect(c.middle(2)).toBe(6) 9 | }); 10 | 11 | }); -------------------------------------------------------------------------------- /explore/src/test/ts/util.ts: -------------------------------------------------------------------------------- 1 | export function assertNever(n: never): never { 2 | throw new Error('never case reached') 3 | } 4 | -------------------------------------------------------------------------------- /explore/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "jsRules": { 7 | }, 8 | "rules": { 9 | "no-console": false, 10 | "semicolon": false, 11 | }, 12 | "rulesDirectory": [] 13 | } 14 | -------------------------------------------------------------------------------- /generator/src/main/scala/eu/swdev/scala/ts/AdapterGeneratorMain.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | import java.io.File 4 | import java.nio.charset.StandardCharsets 5 | import java.nio.file.{Files, Paths} 6 | import java.util.regex.Pattern 7 | 8 | import eu.swdev.scala.ts 9 | 10 | import scala.meta.{Dialect, dialects} 11 | import scala.meta.internal.symtab.GlobalSymbolTable 12 | import scala.meta.io.{AbsolutePath, Classpath} 13 | import scala.util.control.NonFatal 14 | 15 | // this class is referenced in the ScalaTsPlugin when the generator is forked 16 | class AdapterGeneratorMain extends GeneratorMain 17 | 18 | /** 19 | * Main class that is started when the TypeScript declaration file generator is forked by the ScalaTsPlugin 20 | */ 21 | object AdapterGeneratorMain extends AdapterGeneratorMain { 22 | 23 | case class Config( 24 | adapterFile: File, 25 | adapterName: String, 26 | include: Pattern, 27 | exclude: Pattern, 28 | compileFullClasspath: List[File], 29 | validate: Boolean, 30 | ) { 31 | import Config._ 32 | 33 | def asEnvVars = Map( 34 | kAdapterFile -> adapterFile.toString, 35 | kAdapterName -> adapterName, 36 | kInclude -> include.pattern(), 37 | kExclude -> exclude.pattern(), 38 | kCompileFullClassPath -> compileFullClasspath.mkString(File.pathSeparator), 39 | kValidate -> String.valueOf(validate), 40 | ) 41 | } 42 | 43 | object Config { 44 | 45 | val kAdapterFile = "ADAPTER_FILE" 46 | val kAdapterName = "ADAPTER_NAME" 47 | val kInclude = "INCLUDE" 48 | val kExclude = "EXCLUDE" 49 | val kCompileFullClassPath = "COMPILE_FULL_CLASS_PATH" 50 | val kValidate = "VALIDATE" 51 | 52 | def fromEnvVars = Config( 53 | adapterFile = new File(System.getenv(kAdapterFile)), 54 | adapterName = System.getenv(kAdapterName), 55 | include = Pattern.compile(System.getenv(kInclude)), 56 | exclude = Pattern.compile(System.getenv(kExclude)), 57 | compileFullClasspath = System.getenv(kCompileFullClassPath).split(File.pathSeparatorChar).map(new File(_)).toList, 58 | validate = System.getenv(kValidate).toBoolean, 59 | ) 60 | 61 | } 62 | 63 | def main(args: Array[String]): Unit = { 64 | try { 65 | val config = Config.fromEnvVars 66 | val adapterPath = config.adapterFile.toPath 67 | 68 | val cp = config.compileFullClasspath.map(AbsolutePath(_)) 69 | val symTab = GlobalSymbolTable(Classpath(cp), true) 70 | 71 | val semSrcs = 72 | config.compileFullClasspath 73 | .filter(f => config.include.matcher(f.toString).find()) 74 | .filter(f => !config.exclude.matcher(f.toString).find()) 75 | .flatMap(SemSource.locate(_, dialect)) 76 | 77 | val inputs = Analyzer.analyze(semSrcs, symTab) 78 | 79 | def inputInfo = 80 | inputs.flattened 81 | .groupBy(_.getClass.getSimpleName) 82 | .toList 83 | .sortBy(_._1) 84 | .map { 85 | case (cn, lst) => s"$cn: ${lst.length}" 86 | } 87 | .mkString("{", ", ", "}") 88 | 89 | System.out.println(s"ScalaTs input : $inputInfo") 90 | 91 | val output = AdapterGenerator.generate(inputs, symTab, config.adapterName) 92 | 93 | System.out.println(s"ScalaTs output: $adapterPath") 94 | 95 | Files.createDirectories(adapterPath.getParent) 96 | Files.write(adapterPath, output.getBytes(StandardCharsets.UTF_8)) 97 | 98 | if (config.validate) { 99 | validate(semSrcs, symTab, inputs => AdapterGenerator.generate(inputs, symTab, config.adapterName)) 100 | } 101 | 102 | } catch { 103 | case NonFatal(e) => 104 | System.err.println("adapter creation failed") 105 | e.printStackTrace() 106 | System.exit(1) 107 | } 108 | 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /generator/src/main/scala/eu/swdev/scala/ts/Adaption.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | sealed trait Adaption { 4 | def fullName: FullName 5 | def simpleName: String = fullName.last 6 | def input: Input 7 | } 8 | 9 | object Adaption { 10 | 11 | sealed trait Method extends Adaption 12 | sealed trait DefValVar extends Method { 13 | def fullName: FullName = FullName(input.si) 14 | } 15 | 16 | case class Def(input: Input.Def) extends DefValVar 17 | case class Val(input: Input.Val) extends DefValVar 18 | case class Var(input: Input.Var) extends DefValVar 19 | 20 | // the newDelegate and newAdapter methods must be part of the adapter object of the class 21 | // -> construct the full name by adding "newDelegate" or "newAdapter" to the full name of the class 22 | 23 | case class NewDelegate(input: Input.Cls) extends Method { 24 | def fullName = FullName(input.si).member("newDelegate") 25 | } 26 | case class NewAdapter(input: Input.Cls) extends Method { 27 | def fullName = FullName(input.si).member("newAdapter") 28 | } 29 | 30 | case class Trait(input: Input.Cls) extends Adaption { 31 | def fullName: FullName = FullName(input.si) 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /generator/src/main/scala/eu/swdev/scala/ts/GeneratorMain.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | import scala.meta.{Dialect, dialects} 4 | import scala.meta.internal.symtab.SymbolTable 5 | 6 | class GeneratorMain { 7 | 8 | protected def dialect: Dialect = scala.util.Properties.versionNumberString match { 9 | case s if s.startsWith("2.12.") => dialects.Scala212 10 | case s if s.startsWith("2.13.") => dialects.Scala213 11 | case _ => dialects.Scala 12 | } 13 | 14 | protected def validate(semSrcs: List[SemSource], symTab: SymbolTable, generate: Inputs => String): Unit = { 15 | val infos = semSrcs.map(s => s -> ValidationInfo.dts(s)).collect { case (semSource, Some(dtsInfo)) => semSource -> dtsInfo } 16 | var failed = false 17 | def check(name: String, inputs: Inputs, expected: String): Unit = { 18 | val actual = generate(inputs).trim 19 | if (actual != expected) { 20 | System.err.println(s"$name: failed\n====== expected:\n$expected\n==== actual:\n$actual\n====") 21 | failed = true 22 | } else { 23 | System.out.println(s"$name: passed") 24 | } 25 | } 26 | infos.foreach { 27 | case (semSrc, ValidationInfo.Expected(expectedDts)) => 28 | val inputs = Analyzer.analyze(List(semSrc), symTab) 29 | check(s"file: ${semSrc.td.uri}", inputs, expectedDts) 30 | 31 | case (_, ValidationInfo.ExpectedAndGroup(expectedDts, group)) => 32 | val semSrcs = infos 33 | .collect { 34 | case (semSrc, ValidationInfo.Group(`group`)) => semSrc 35 | case (semSrc, ValidationInfo.ExpectedAndGroup(_, `group`)) => semSrc 36 | } 37 | val inputs = Analyzer.analyze(semSrcs, symTab) 38 | check(s"group: $group", inputs, expectedDts) 39 | 40 | case _ => 41 | } 42 | 43 | if (failed) { 44 | System.exit(1) 45 | } 46 | 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /generator/src/main/scala/eu/swdev/scala/ts/Result.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | trait Result { 4 | 5 | def openBlock(line: String): Unit 6 | 7 | def closeBlock(): Unit 8 | 9 | def addLine(line: String): Unit 10 | } 11 | 12 | object Result { 13 | 14 | class StringBuilderResult extends Result { 15 | var indent = 0 16 | def space = " " * indent 17 | 18 | val sb = new StringBuilder 19 | 20 | override def openBlock(line: String): Unit = { 21 | sb.append(s"$space$line {\n") 22 | indent += 1 23 | } 24 | 25 | override def closeBlock(): Unit = { 26 | indent -= 1 27 | sb.append(s"$space}\n") 28 | } 29 | 30 | override def addLine(line: String): Unit = sb.append(s"$space$line\n") 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /generator/src/main/scala/eu/swdev/scala/ts/SemSource.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | import java.io.File 4 | import java.nio.file.Path 5 | import scala.meta.common.Convert 6 | import scala.meta.inputs.Position 7 | import scala.meta.internal.semanticdb.SymbolInformation.Kind 8 | import scala.meta.internal.semanticdb.SymbolOccurrence.Role 9 | import scala.meta.{Dialect, Source} 10 | import scala.meta.internal.semanticdb.{Locator, SymbolInformation, SymbolOccurrence, TextDocument} 11 | import scala.meta.parsers.Parse 12 | import scala.meta.tokens.Tokens 13 | 14 | case class SemSource(td: TextDocument, source: Source, dialect: Dialect) { 15 | 16 | def symbolInfo(symbol: String): SymbolInformation = td.symbols.find(_.symbol == symbol).get 17 | 18 | def symbolInfo(pos: Position, kind: Kind): Option[SymbolInformation] = symbolInfos(pos, kind).headOption 19 | 20 | /** 21 | * Returns SymbolInformation instances that lie in the given range and or of the given kind. 22 | * 23 | * The returned sequence is ordered by start positions. 24 | */ 25 | def symbolInfos(pos: Position, kind: Kind): Seq[SymbolInformation] = { 26 | val symbolOccurrencesInRange = symbolOccurrences(pos, Role.DEFINITION) 27 | val matchingSymbolInformationsOfKind = symbolOccurrencesInRange 28 | .flatMap { 29 | case so => td.symbols.collect { 30 | case si if si.kind == kind && si.symbol == so.symbol => (si, so.range.get) 31 | } 32 | } 33 | val sortedByStartPosition = matchingSymbolInformationsOfKind 34 | .sortWith { 35 | case ((_, r1), (_, r2)) => r1.startLine < r2.startLine || r1.startLine == r2.startLine && r1.startCharacter < r2.startCharacter 36 | } 37 | sortedByStartPosition.map(_._1) 38 | } 39 | 40 | def symbolOccurrences(pos: Position, role: Role): Seq[SymbolOccurrence] = { 41 | td.occurrences.filter(so => so.range.map(pos.includes(_)).getOrElse(false) && so.role == role) 42 | } 43 | 44 | def tokens: Tokens = source.tokens(dialect) 45 | 46 | } 47 | 48 | object SemSource { 49 | 50 | def apply(td: TextDocument, dialect: Dialect): SemSource = { 51 | val parseSource = implicitly[Parse[Source]] 52 | val stringToInput = implicitly[Convert[String, scala.meta.inputs.Input]] 53 | val input = stringToInput.apply(td.text) 54 | val source = parseSource.apply(input, dialect).get 55 | SemSource(td, source, dialect) 56 | } 57 | 58 | /** 59 | * Locates SemSources in the given directory. 60 | * 61 | * The returned SemSources are sorted by the uri of their contained text document. 62 | */ 63 | def locate(dir: File, dialect: Dialect): List[SemSource] = locate(dir.toPath, dialect) 64 | 65 | /** 66 | * Locates SemSources in the given directory. 67 | * 68 | * The returned SemSources are sorted by the uri of their contained text document. 69 | */ 70 | def locate(dir: Path, dialect: Dialect): List[SemSource] = { 71 | val builder = List.newBuilder[SemSource] 72 | Locator(dir) { (_, tds) => 73 | tds.documents.foreach { td => 74 | val semSource = SemSource(td, dialect) 75 | builder += semSource 76 | } 77 | } 78 | builder.result().sortBy(_.td.uri) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /generator/src/main/scala/eu/swdev/scala/ts/ValidationInfo.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | import scala.meta.tokens.Token 4 | 5 | /** 6 | * Represents information that can be used to validate the TypeScript declaration file generation. 7 | * 8 | * The information is given in comments: A block comment that starts with ".d.ts:" or "adapter:" contains a 9 | * declaration file fragment or an adapter file fragment. 10 | * That fragment is either the result of processing the ScalaJS file that contains that comment or a group of ScalaJS files. 11 | * Groups of ScalaJS files can be formed by using an end of line comment that starts with "group:". 12 | * 13 | * Although being a test support type, the ValidationInfo type is defined in the main classes of the generator because 14 | * the ScalaTsPlugin depends on it to validate its generation result. 15 | * 16 | * In case that multiple ".d.ts:", "adapter:", or "group:" comments are given only the first is considered. 17 | */ 18 | sealed trait ValidationInfo 19 | 20 | object ValidationInfo { 21 | 22 | case class Expected(string: String) extends ValidationInfo 23 | case class Group(group: String) extends ValidationInfo 24 | case class ExpectedAndGroup(expected: String, group: String) extends ValidationInfo 25 | 26 | val groupMarker = "group:" 27 | val dtsMarker = ".d.ts:" 28 | val adapterMarker = "adapter:" 29 | 30 | def apply(semSrc: SemSource, expectedMarker: String): Option[ValidationInfo] = { 31 | val optFragment = semSrc.tokens.collectFirst { 32 | case t: Token.Comment if t.value.trim.startsWith(expectedMarker) => t.value.trim.substring(expectedMarker.length).trim 33 | } 34 | val optGroup = semSrc.tokens.collectFirst { 35 | case t: Token.Comment if t.value.trim.startsWith(groupMarker) => t.value.trim.substring(groupMarker.length).trim 36 | } 37 | (optFragment, optGroup) match { 38 | case (Some(fragment), Some(group)) => Some(ExpectedAndGroup(fragment, group)) 39 | case (Some(fragment), _) => Some(Expected(fragment)) 40 | case (_, Some(group)) => Some(Group(group)) 41 | case _ => None 42 | } 43 | } 44 | 45 | def dts(semSrc: SemSource) = apply(semSrc, dtsMarker) 46 | def adapter(semSrc: SemSource) = apply(semSrc, adapterMarker) 47 | } 48 | -------------------------------------------------------------------------------- /generator/src/test/scala-2.13/eu/swdev/scala/ts/dts/LiteralTypeTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.JSExportTopLevel 6 | 7 | class LiteralTypeTest extends DtsFunSuite { 8 | 9 | """ 10 | |export const litString: 'a' 11 | |export const litNumber: 1 12 | |export const litBoolean: true 13 | |""".check() 14 | 15 | } 16 | 17 | object LiteralTypeTest { 18 | 19 | @JSExportTopLevel("litString") 20 | val litString: "a" = "a" 21 | @JSExportTopLevel("litNumber") 22 | val litNumber: 1 = 1 23 | @JSExportTopLevel("litBoolean") 24 | val litBoolean: true = true 25 | 26 | } 27 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/AbstractAutoDetectingTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | import org.scalatest.funsuite.AnyFunSuite 4 | import org.scalatest.matchers.must.Matchers 5 | 6 | /** 7 | * Base class for tests that scan semantic db files and check for comments that start with a ".d.ts:" or "group:" mark. 8 | * 9 | * The package where the test class is located is the package where semantic db files are looked for. Subpackages 10 | * are also considered. If a semantic db file has a comment starting with ".d.ts:" then that comment specifies the 11 | * expected generated declaration file. 12 | * 13 | * Multiple files can be grouped and processed together resulting in a single declaration file. All files belonging 14 | * to the same group contain a comment that starts with "group:" followed by the same identifier. 15 | */ 16 | abstract class AbstractAutoDetectingTest extends AnyFunSuite with ScalaMetaHelper with Matchers { 17 | 18 | def dtsInfos(): List[(SemSource, ValidationInfo)] = { 19 | val relativeTestDir = basePath.relativize(testDirPath).toString 20 | locateSemSources(metaInfPath, dialect) 21 | .filter(_.td.uri.contains(relativeTestDir)) 22 | .map(s => s -> ValidationInfo.dts(s)) 23 | .collect { 24 | case (semSource, Some(dtsInfo)) => semSource -> dtsInfo 25 | } 26 | } 27 | 28 | val infos = dtsInfos() 29 | 30 | private def check(inputs: Inputs, expectedDts: String): Unit = { 31 | val generatedDts = Generator.generate(inputs, false, symTab, getClass.getClassLoader).trim 32 | generatedDts mustBe expectedDts 33 | } 34 | 35 | infos.foreach { 36 | 37 | case (semSrc, ValidationInfo.Expected(expectedDts)) => 38 | test(s"file: ${semSrc.td.uri}") { 39 | val inputs = Analyzer.analyze(List(semSrc), symTab) 40 | check(inputs, expectedDts) 41 | } 42 | 43 | case (_, ValidationInfo.ExpectedAndGroup(expectedDts, group)) => 44 | test(s"group: $group") { 45 | val semSrcs = infos 46 | .collect { 47 | case (semSrc, ValidationInfo.Group(`group`)) => semSrc 48 | case (semSrc, ValidationInfo.ExpectedAndGroup(_, `group`)) => semSrc 49 | } 50 | val inputs = Analyzer.analyze(semSrcs, symTab) 51 | check(inputs, expectedDts) 52 | } 53 | 54 | case _ => 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/AdapterFunSuite.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | import eu.swdev.scala.ts 4 | import org.scalatest.funsuite.AnyFunSuite 5 | import org.scalatest.matchers.must.Matchers 6 | 7 | trait AdapterFunSuite extends AnyFunSuite with ScalaMetaHelper with Matchers { self => 8 | 9 | implicit def strOps(str: String): StrOps = StrOps(str) 10 | 11 | case class StrOps(expectedAdapter: String) { 12 | 13 | /** 14 | * Creates a test that generates the adapter code for the given classes and checks if it matches the expected value. 15 | * 16 | * If no classes are given then the test class itself is used. 17 | * 18 | * Note that not only the given classes are considered when generating the adapter code but all 19 | * symbols that are defined in the corresponding files. 20 | */ 21 | def check(classes: Class[_]*): Unit = { 22 | test("adapter") { 23 | val is = inputs(classes: _*) 24 | val generatedAdapter = AdapterGenerator.generate(is, symTab, "Adapter").trim 25 | generatedAdapter mustBe expectedAdapter.stripMargin.trim 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/DtsFunSuite.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | import org.scalatest.funsuite.AnyFunSuite 4 | import org.scalatest.matchers.must.Matchers 5 | 6 | trait DtsFunSuite extends AnyFunSuite with ScalaMetaHelper with Matchers { self => 7 | 8 | implicit def strOps(str: String): StrOps = StrOps(str) 9 | 10 | case class StrOps(expectedDts: String) { 11 | 12 | /** 13 | * Creates a test that generates the type declaration file for this test class and checks if it matches the expected value. 14 | */ 15 | def check(addRootNamespace: Boolean = false): Unit = { 16 | test("dts") { 17 | val is = inputs() 18 | val generatedDts = Generator.generate(is, addRootNamespace, symTab, getClass.getClassLoader).trim 19 | generatedDts mustBe expectedDts.stripMargin.trim 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/FullNameTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | import org.scalatest.funsuite.AnyFunSuite 4 | import org.scalatest.matchers.must.Matchers 5 | 6 | class FullNameTest extends AnyFunSuite with Matchers { 7 | 8 | test("tail") { 9 | FullName.fromSymbol("dts/AccessorTest.").tail.map(_.str) mustBe Some("AccessorTest$") 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/GeneratorTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | import org.scalatest.funsuite.AnyFunSuite 4 | import org.scalatest.matchers.must.Matchers 5 | 6 | class GeneratorTest extends AnyFunSuite with Matchers { 7 | 8 | test("string escape") { 9 | TypeFormatter.escapeTypeScriptString("abc") mustBe "abc" 10 | TypeFormatter.escapeTypeScriptString("'") mustBe "\\'" 11 | TypeFormatter.escapeTypeScriptString("\"") mustBe "\\\"" 12 | TypeFormatter.escapeTypeScriptString("\n") mustBe "\\n" 13 | TypeFormatter.escapeTypeScriptString("\u00e4\u00f6\u00fc") mustBe "\\u00e4\\u00f6\\u00fc" 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/NativeSymbolAnalyzerTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | import org.scalatest.funsuite.AnyFunSuite 4 | import org.scalatest.matchers.must.Matchers 5 | 6 | import scala.scalajs.js 7 | import scala.scalajs.js.annotation.{JSGlobal, JSImport, JSName} 8 | 9 | class NativeSymbolAnalyzerTest extends AnyFunSuite with Matchers with ScalaMetaHelper { 10 | 11 | val na = new NativeSymbolAnalyzer(Map.empty, getClass.getClassLoader, symTab) 12 | 13 | def nativeSymbol(cls: Class[_]): Option[NativeSymbol] = { 14 | val sym = cls.getName.replace('.', '/').replace('$', '.') + "#" 15 | na.nativeSymbol(sym) 16 | } 17 | 18 | import NativeSymbolAnalyzerTest._ 19 | 20 | test("global without name") { 21 | nativeSymbol(classOf[GlobalWithoutName]) mustBe Some(NativeSymbol.Global("GlobalWithoutName", true)) 22 | } 23 | 24 | test("global with name") { 25 | nativeSymbol(classOf[GlobalWithName]) mustBe Some(NativeSymbol.Global("SomeName", false)) 26 | } 27 | 28 | test("import with name") { 29 | nativeSymbol(classOf[ImportWithName]) mustBe Some(NativeSymbol.ImportedName("SomeModule", "SomeName", false)) 30 | } 31 | 32 | test("import with default") { 33 | nativeSymbol(classOf[ImportWithDefault]) mustBe Some(NativeSymbol.ImportedName("SomeModule", "default", false)) 34 | } 35 | 36 | test("import with namespace") { 37 | nativeSymbol(classOf[ImportWithNamespace]) mustBe Some(NativeSymbol.ImportedNamespace("SomeModule", false)) 38 | } 39 | 40 | test("import with namespace / nested") { 41 | nativeSymbol(classOf[SomeModule.Nested]) mustBe Some( 42 | NativeSymbol.Inner("Nested", NativeSymbol.ImportedNamespace("SomeModule", true), true)) 43 | } 44 | 45 | test("import with namespace / nested2 / nested3") { 46 | nativeSymbol(classOf[SomeModule2.Nested2.Nested3]) mustBe Some( 47 | NativeSymbol.Inner( 48 | "Nested3", 49 | NativeSymbol.Inner( 50 | "Nested2", 51 | NativeSymbol.ImportedNamespace( 52 | "SomeModule2", 53 | true 54 | ), 55 | true 56 | ), 57 | false 58 | ) 59 | ) 60 | } 61 | 62 | } 63 | 64 | object NativeSymbolAnalyzerTest { 65 | 66 | @JSGlobal 67 | @js.native 68 | class GlobalWithoutName extends js.Object 69 | 70 | @JSGlobal("SomeName") 71 | @js.native 72 | class GlobalWithName 73 | 74 | @JSImport("SomeModule", "SomeName") 75 | @js.native 76 | class ImportWithName 77 | 78 | @JSImport("SomeModule", JSImport.Default) 79 | @js.native 80 | class ImportWithDefault 81 | 82 | @JSImport("SomeModule", JSImport.Namespace) 83 | @js.native 84 | class ImportWithNamespace 85 | 86 | @JSImport("SomeModule", JSImport.Namespace) 87 | object SomeModule extends js.Object { 88 | class Nested extends js.Object 89 | } 90 | 91 | @JSImport("SomeModule2", JSImport.Namespace) 92 | object SomeModule2 extends js.Object { 93 | object Nested2 extends js.Object { 94 | @JSName(js.Symbol.iterator) 95 | class Nested3 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/ScalaMetaHelper.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | import java.net.URLClassLoader 4 | import java.nio.file.{Path, Paths} 5 | 6 | import scala.collection.mutable 7 | import scala.meta.{Dialect, dialects} 8 | import scala.meta.internal.symtab.GlobalSymbolTable 9 | import scala.meta.io.{AbsolutePath, Classpath} 10 | 11 | trait ScalaMetaHelper { self => 12 | 13 | def dialect: Dialect = dialects.Scala 14 | 15 | val symTab = { 16 | def classLoaders(cl: ClassLoader): List[ClassLoader] = 17 | Option(cl).fold[List[ClassLoader]](Nil)(cl => cl :: classLoaders(cl.getParent)) 18 | val urls = classLoaders(getClass.getClassLoader).collect { 19 | case ucl: URLClassLoader => ucl.getURLs 20 | }.flatten 21 | 22 | val paths = urls.map(url => Paths.get(url.toURI).toAbsolutePath.toFile).map(AbsolutePath(_)) 23 | val cp = Classpath(paths) 24 | GlobalSymbolTable(cp, true) 25 | } 26 | 27 | val testDirPath: Path = { 28 | val clazz = getClass 29 | val url = clazz.getResource(s"${getClass.getSimpleName}.class") 30 | val uri = url.toURI 31 | Paths.get(uri).getParent 32 | } 33 | 34 | val basePath: Path = { 35 | val clazz = getClass 36 | var res = testDirPath 37 | var s = clazz.getName 38 | while (s.indexOf('.') > 0) { 39 | s = s.substring(s.indexOf('.') + 1) 40 | res = res.getParent 41 | } 42 | res 43 | } 44 | 45 | val metaInfPath: Path = basePath.resolve("META-INF") 46 | 47 | def locateSemSources(dir: Path, dialect: Dialect) = ScalaMetaHelper.locateSemSources(dir, dialect) 48 | 49 | /** 50 | * Analyzes semantic db files that contain symbols for the given classes. 51 | * 52 | * If no classes are given then the test class itself is used. 53 | * 54 | * @param classes 55 | * @return 56 | */ 57 | def inputs(classes: Class[_]*): Inputs = { 58 | val clss = if (classes.isEmpty) Seq(self.getClass) else classes 59 | val classSymbols = clss 60 | .map(_.getName.replace('.', '/')) 61 | .map { n => 62 | if (n.endsWith("$")) { 63 | // symbol of a Scala object class -> replace trailing '$' by a '.' 64 | s"${n.dropRight(1)}." 65 | } else { 66 | // symbol of a standard class -> append a '#' 67 | s"$n#" 68 | } 69 | } 70 | .toSet 71 | 72 | val semSources = locateSemSources(metaInfPath, dialect) 73 | .filter(_.td.symbols.map(_.symbol).exists(s => classSymbols.exists(cs => s.endsWith(cs)))) 74 | .sortBy(_.td.uri) 75 | 76 | Analyzer.analyze(semSources, symTab) 77 | } 78 | } 79 | 80 | object ScalaMetaHelper { 81 | 82 | def locateSemSources(dir: Path, dialect: Dialect): List[SemSource] = synchronized { 83 | map.getOrElseUpdate((dir, dialect), SemSource.locate(dir, dialect)) 84 | } 85 | 86 | // caches located SemSources during test runs 87 | private val map = mutable.Map.empty[(Path, Dialect), List[SemSource]] 88 | } 89 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/adapter/ArrayTest.scala: -------------------------------------------------------------------------------- 1 | package adapter 2 | 3 | import eu.swdev.scala.ts.AdapterFunSuite 4 | import eu.swdev.scala.ts.annotation.AdaptAll 5 | 6 | class ArrayTest extends AdapterFunSuite { 7 | 8 | """ 9 | |import scala.scalajs.js 10 | |import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 11 | |import eu.swdev.scala.ts.adapter._ 12 | |@JSExportTopLevel("Adapter") 13 | |object Adapter extends js.Object { 14 | | object adapter extends js.Object { 15 | | object ArrayTest extends js.Object { 16 | | def x = _root_.adapter.ArrayTest.x.$cnv[_root_.eu.swdev.scala.ts.tpe.ReadOnlyArray[Int]] 17 | | def x_=(value: _root_.eu.swdev.scala.ts.tpe.ReadOnlyArray[Int]) = _root_.adapter.ArrayTest.x = value.$cnv[_root_.scala.Array[Int]] 18 | | } 19 | | } 20 | |} 21 | |""".check() 22 | 23 | } 24 | 25 | @AdaptAll 26 | object ArrayTest { 27 | 28 | var x: Array[Int] = ??? 29 | } 30 | 31 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/adapter/ClassTest.scala: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import eu.swdev.scala.ts.AdapterFunSuite 4 | import eu.swdev.scala.ts.annotation.AdaptAll 5 | 6 | class ClassTest extends AdapterFunSuite { 7 | """ 8 | |import scala.scalajs.js 9 | |import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 10 | |import eu.swdev.scala.ts.adapter._ 11 | |@JSExportTopLevel("Adapter") 12 | |object Adapter extends js.Object { 13 | | @JSExportAll 14 | | trait InstanceAdapter[D] { 15 | | val $delegate: D 16 | | } 17 | | object test extends js.Object { 18 | | @JSExportAll 19 | | trait AdaptedClass extends InstanceAdapter[_root_.test.AdaptedClass] { 20 | | def sum = $delegate.sum.$cnv[Int] 21 | | def x = $delegate.x.$cnv[Int] 22 | | } 23 | | object AdaptedClass extends js.Object { 24 | | def newAdapter(delegate: _root_.test.AdaptedClass): AdaptedClass = new AdaptedClass { 25 | | override val $delegate = delegate 26 | | } 27 | | def newDelegate(x: Int, y: Int): _root_.test.AdaptedClass = new _root_.test.AdaptedClass(x.$cnv[Int], y.$cnv[Int]) 28 | | } 29 | | } 30 | |} 31 | |""".check() 32 | } 33 | 34 | @AdaptAll 35 | class AdaptedClass(val x: Int, y: Int) { 36 | 37 | def sum = x + y 38 | } -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/adapter/ListTest.scala: -------------------------------------------------------------------------------- 1 | package adapter 2 | 3 | import eu.swdev.scala.ts.AdapterFunSuite 4 | import eu.swdev.scala.ts.annotation.AdaptAll 5 | 6 | class ListTest extends AdapterFunSuite { 7 | 8 | """ 9 | |import scala.scalajs.js 10 | |import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 11 | |import eu.swdev.scala.ts.adapter._ 12 | |@JSExportTopLevel("Adapter") 13 | |object Adapter extends js.Object { 14 | | object adapter extends js.Object { 15 | | object ListTest extends js.Object { 16 | | def traverse[X](ol: _root_.scala.scalajs.js.Iterable[_root_.scala.scalajs.js.UndefOr[X]]) = _root_.adapter.ListTest.traverse(ol.$cnv[_root_.scala.List[_root_.scala.Option[X]]]).$cnv[_root_.scala.scalajs.js.UndefOr[_root_.scala.scalajs.js.Iterable[X]]] 17 | | } 18 | | } 19 | |} 20 | |""".check() 21 | 22 | } 23 | 24 | @AdaptAll 25 | object ListTest { 26 | 27 | def traverse[X](ol: List[Option[X]]): Option[List[X]] = ??? 28 | } -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/adapter/NestedClassTest.scala: -------------------------------------------------------------------------------- 1 | package adapter 2 | 3 | import eu.swdev.scala.ts.AdapterFunSuite 4 | import eu.swdev.scala.ts.annotation.AdaptAll 5 | 6 | class NestedClassTest extends AdapterFunSuite { 7 | 8 | """ 9 | |import scala.scalajs.js 10 | |import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 11 | |import eu.swdev.scala.ts.adapter._ 12 | |@JSExportTopLevel("Adapter") 13 | |object Adapter extends js.Object { 14 | | @JSExportAll 15 | | trait InstanceAdapter[D] { 16 | | val $delegate: D 17 | | } 18 | | object adapter extends js.Object { 19 | | @JSExportAll 20 | | trait OuterClass extends InstanceAdapter[_root_.adapter.OuterClass] { 21 | | def x = $delegate.x.$cnv[Int] 22 | | @JSExportAll 23 | | trait Inner extends InstanceAdapter[_root_.adapter.OuterClass#Inner] { 24 | | def y = $delegate.y.$cnv[String] 25 | | } 26 | | object Inner extends js.Object { 27 | | def newAdapter(delegate: _root_.adapter.OuterClass#Inner): Inner = new Inner { 28 | | override val $delegate = delegate 29 | | } 30 | | def newDelegate(y: String): _root_.adapter.OuterClass#Inner = new $delegate.Inner(y.$cnv[String]) 31 | | } 32 | | } 33 | | object OuterClass extends js.Object { 34 | | def newAdapter(delegate: _root_.adapter.OuterClass): OuterClass = new OuterClass { 35 | | override val $delegate = delegate 36 | | } 37 | | def newDelegate(x: Int): _root_.adapter.OuterClass = new _root_.adapter.OuterClass(x.$cnv[Int]) 38 | | } 39 | | } 40 | |} 41 | |""".check() 42 | 43 | } 44 | 45 | @AdaptAll 46 | class OuterClass(val x: Int) { 47 | @AdaptAll 48 | class Inner(val y: String) 49 | } 50 | 51 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/adapter/ObjectDefValVarTest.scala: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import eu.swdev.scala.ts.AdapterFunSuite 4 | import eu.swdev.scala.ts.annotation.AdaptAll 5 | 6 | class ObjectDefValVarTest extends AdapterFunSuite { 7 | """ 8 | |import scala.scalajs.js 9 | |import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 10 | |import eu.swdev.scala.ts.adapter._ 11 | |@JSExportTopLevel("Adapter") 12 | |object Adapter extends js.Object { 13 | | object test extends js.Object { 14 | | object ObjectDefValVarTest extends js.Object { 15 | | def method(x: Int) = _root_.test.ObjectDefValVarTest.method(x).$cnv[Boolean] 16 | | def value = _root_.test.ObjectDefValVarTest.value.$cnv[String] 17 | | def variable = _root_.test.ObjectDefValVarTest.variable.$cnv[Boolean] 18 | | def variable_=(value: Boolean) = _root_.test.ObjectDefValVarTest.variable = value.$cnv[Boolean] 19 | | } 20 | | } 21 | |} 22 | |""".check() 23 | } 24 | 25 | @AdaptAll 26 | object ObjectDefValVarTest { 27 | 28 | def method(x: Int): Boolean = ??? 29 | val value: String = ??? 30 | var variable: Boolean = ??? 31 | 32 | } -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/auto/AutoDetectingTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.auto 2 | 3 | import eu.swdev.scala.ts.AbstractAutoDetectingTest 4 | 5 | class AutoDetectingTest extends AbstractAutoDetectingTest 6 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/auto/PrimitiveTypes.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.auto 2 | 3 | import scala.scalajs.js 4 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 5 | 6 | /* .d.ts: 7 | 8 | export interface PrimitiveTypes$ { 9 | readonly string: string 10 | readonly int: number 11 | readonly double: number 12 | readonly byte: number 13 | readonly short: number 14 | readonly float: number 15 | readonly char: scala.Char 16 | readonly long: scala.Long 17 | readonly bigInt: bigint 18 | 'PrimitiveTypes$': never 19 | } 20 | export const PrimitiveTypes: PrimitiveTypes$ 21 | export namespace scala { 22 | interface Char { 23 | 'scala.Char': never 24 | } 25 | interface Long { 26 | 'scala.Long': never 27 | } 28 | } 29 | */ 30 | 31 | @JSExportTopLevel("PrimitiveTypes") 32 | @JSExportAll 33 | object PrimitiveTypes { 34 | 35 | val string: String = ??? 36 | val int: Int = ??? 37 | val double: Double = ??? 38 | val byte: Byte = ??? 39 | val short: Short = ??? 40 | val float: Float = ??? 41 | val char: Char = ??? 42 | val long: Long = ??? 43 | val bigInt: js.BigInt = ??? 44 | 45 | } 46 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/auto/group-1-file-1.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.auto 2 | 3 | import scala.scalajs.js.annotation.JSExportTopLevel 4 | 5 | /* .d.ts: 6 | 7 | export const fromFile1: string 8 | export const fromFile2: string 9 | 10 | */ 11 | 12 | // group: group-1 13 | 14 | object Grouped1 { 15 | 16 | @JSExportTopLevel("fromFile1") 17 | val x: String= ??? 18 | } -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/auto/group-1-file-2.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.auto 2 | 3 | import scala.scalajs.js.annotation.JSExportTopLevel 4 | 5 | // group: group-1 6 | 7 | object Grouped2 { 8 | 9 | @JSExportTopLevel("fromFile2") 10 | val x: String= ??? 11 | } -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/AbstractClassTest1.scala: -------------------------------------------------------------------------------- 1 | package dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 6 | 7 | class AbstractClassTest1 extends DtsFunSuite { 8 | 9 | """ 10 | |export interface Case1 extends dts.AbstractClassTest1.Base { 11 | | 'Case1': never 12 | |} 13 | |export class Case1 { 14 | | constructor(s: string) 15 | |} 16 | |export interface Case2 extends dts.AbstractClassTest1.Base { 17 | | 'Case2': never 18 | |} 19 | |export class Case2 { 20 | | constructor(i: number) 21 | |} 22 | |export namespace dts { 23 | | namespace AbstractClassTest1 { 24 | | interface Base { 25 | | readonly x: X 26 | | 'dts.AbstractClassTest1.Base': never 27 | | } 28 | | } 29 | |} 30 | |""".check() 31 | 32 | } 33 | 34 | object AbstractClassTest1 { 35 | 36 | @JSExportAll 37 | abstract class Base[X](val x: X) 38 | 39 | @JSExportTopLevel("Case1") 40 | class Case1(s: String) extends Base(s) 41 | @JSExportTopLevel("Case2") 42 | class Case2(i: Int) extends Base(i) 43 | } 44 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/AbstractClassTest2.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 7 | 8 | class AbstractClassTest2 extends DtsFunSuite { 9 | 10 | """ 11 | |export abstract class Base { 12 | | constructor(x: X) 13 | | readonly x: X 14 | | abstract size(): number 15 | |} 16 | |export class Case1 extends Base { 17 | | constructor(s: string) 18 | | size(): number 19 | |} 20 | |export class Case2 extends Base { 21 | | constructor(i: number) 22 | | size(): number 23 | |} 24 | |""".check() 25 | 26 | } 27 | 28 | object AbstractClassTest2 { 29 | 30 | @JSExportTopLevel("Base") 31 | abstract class Base[X](val x: X) extends js.Object { 32 | def size(): Int 33 | } 34 | 35 | @JSExportTopLevel("Case1") 36 | class Case1(s: String) extends Base(s) { 37 | override def size(): Int = s.length 38 | } 39 | @JSExportTopLevel("Case2") 40 | class Case2(i: Int) extends Base(i) { 41 | override def size(): Int = i 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/AccessorPairTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 6 | 7 | class AccessorPairTest extends DtsFunSuite { 8 | 9 | """ 10 | |export interface AccessorPairTest$ { 11 | | prop: string 12 | | 'AccessorPairTest$': never 13 | |} 14 | |export const AccessorPairTest: AccessorPairTest$ 15 | |""".check() 16 | 17 | } 18 | 19 | 20 | @JSExportTopLevel("AccessorPairTest") 21 | @JSExportAll 22 | object AccessorPairTest { 23 | def prop = Holder.x 24 | def prop_=(v: String) = Holder.x = v 25 | 26 | private object Holder { 27 | var x = "abc" 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/AccessorTest.scala: -------------------------------------------------------------------------------- 1 | package dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 6 | 7 | class AccessorTest extends DtsFunSuite { 8 | 9 | """ 10 | |export interface AccessorTest$ { 11 | | property: number 12 | | 'AccessorTest$': never 13 | |} 14 | |export const AccessorTest: AccessorTest$ 15 | |""".check() 16 | 17 | } 18 | 19 | @JSExportTopLevel("AccessorTest") 20 | @JSExportAll 21 | object AccessorTest { 22 | 23 | private var x = 1 24 | 25 | def property = x 26 | def property_=(v: Int): Unit = x = v 27 | 28 | } 29 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/AdapterClassTest.scala: -------------------------------------------------------------------------------- 1 | import eu.swdev.scala.ts.DtsFunSuite 2 | 3 | import scala.scalajs.js 4 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 5 | 6 | class AdapterClassTest extends DtsFunSuite { 7 | """ 8 | |export interface AdapterClassTest$ { 9 | | readonly x: _root_AdapterClassTest.x$ 10 | | 'AdapterClassTest$': never 11 | |} 12 | |export const AdapterClassTest: AdapterClassTest$ 13 | |export namespace AdapterClassTest { 14 | | interface InstanceAdapter { 15 | | readonly $delegate: D 16 | | 'AdapterClassTest.InstanceAdapter': never 17 | | } 18 | | interface x$ { 19 | | readonly SomeClass: _root_AdapterClassTest.x.SomeClass$ 20 | | 'AdapterClassTest.x$': never 21 | | } 22 | | namespace x { 23 | | interface SomeClass extends AdapterClassTest.InstanceAdapter<_root_x.SomeClass> { 24 | | readonly array: (number)[] 25 | | readonly sum: number 26 | | 'AdapterClassTest.x.SomeClass': never 27 | | } 28 | | interface SomeClass$ { 29 | | newInstance(array: (number)[]): _root_x.SomeClass 30 | | newAdapter(d: _root_x.SomeClass): AdapterClassTest.x.SomeClass 31 | | 'AdapterClassTest.x.SomeClass$': never 32 | | } 33 | | } 34 | |} 35 | |export namespace x { 36 | | interface SomeClass { 37 | | 'x.SomeClass': never 38 | | } 39 | |} 40 | |import _root_AdapterClassTest = AdapterClassTest 41 | |import _root_x = x 42 | |""".check(addRootNamespace = true) 43 | } 44 | 45 | package x { 46 | class SomeClass(val array: Array[Int]) { 47 | def sum: Int = ??? 48 | } 49 | } 50 | 51 | @JSExportTopLevel("AdapterClassTest") 52 | object AdapterClassTest extends js.Object { 53 | 54 | @JSExportAll 55 | trait InstanceAdapter[D] { 56 | val $delegate: D 57 | } 58 | 59 | object x extends js.Object { 60 | @JSExportAll 61 | trait SomeClass extends InstanceAdapter[_root_.x.SomeClass] { 62 | def array: js.Array[Int] = ??? 63 | def sum: Int = ??? 64 | } 65 | object SomeClass extends js.Object { 66 | def newInstance(array: js.Array[Int]): _root_.x.SomeClass = ??? 67 | def newAdapter(d: _root_.x.SomeClass): SomeClass = new SomeClass { 68 | override val $delegate = d 69 | } 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/AdapterNestedClassTest.scala: -------------------------------------------------------------------------------- 1 | import eu.swdev.scala.ts.DtsFunSuite 2 | 3 | import scala.scalajs.js 4 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 5 | 6 | class AdapterNestedClassTest extends DtsFunSuite { 7 | 8 | """ 9 | |export interface AdapterNestedClassTest$ { 10 | | readonly x: AdapterNestedClassTest.x$ 11 | | 'AdapterNestedClassTest$': never 12 | |} 13 | |export const AdapterNestedClassTest: AdapterNestedClassTest$ 14 | |export namespace AdapterNestedClassTest { 15 | | interface InstanceAdapter { 16 | | readonly $delegate: D 17 | | 'AdapterNestedClassTest.InstanceAdapter': never 18 | | } 19 | | interface x$ { 20 | | readonly Outer: AdapterNestedClassTest.x.Outer$ 21 | | 'AdapterNestedClassTest.x$': never 22 | | } 23 | | namespace x { 24 | | interface Outer extends AdapterNestedClassTest.InstanceAdapter { 25 | | outerMethod(): number 26 | | readonly Inner: AdapterNestedClassTest.x.Outer.Inner$ 27 | | 'AdapterNestedClassTest.x.Outer': never 28 | | } 29 | | interface Outer$ { 30 | | newInstance(x: number): x.Outer 31 | | newAdapter(d: x.Outer): AdapterNestedClassTest.x.Outer 32 | | 'AdapterNestedClassTest.x.Outer$': never 33 | | } 34 | | namespace Outer { 35 | | interface Inner extends AdapterNestedClassTest.InstanceAdapter { 36 | | innerMethod(): string 37 | | 'AdapterNestedClassTest.x.Outer.Inner': never 38 | | } 39 | | interface Inner$ { 40 | | newInstance(y: string): x.Outer.Inner 41 | | newAdapter(d: x.Outer.Inner): AdapterNestedClassTest.x.Outer.Inner 42 | | 'AdapterNestedClassTest.x.Outer.Inner$': never 43 | | } 44 | | } 45 | | } 46 | |} 47 | |export namespace x { 48 | | interface Outer { 49 | | 'x.Outer': never 50 | | } 51 | | namespace Outer { 52 | | interface Inner { 53 | | 'x.Outer.Inner': never 54 | | } 55 | | } 56 | |} 57 | |""".check() 58 | 59 | } 60 | 61 | package x { 62 | case class Outer(val x: Int) { 63 | def outerMethod() = 2 * x 64 | case class Inner(val y: String) { 65 | def innerMethod() = y.reverse 66 | } 67 | } 68 | } 69 | 70 | @JSExportTopLevel("AdapterNestedClassTest") 71 | object AdapterNestedClassTest extends js.Object { 72 | @JSExportAll 73 | trait InstanceAdapter[D] { 74 | val $delegate: D 75 | } 76 | 77 | object x extends js.Object { 78 | 79 | object Outer extends js.Object { 80 | def newInstance(x: Int) = new _root_.x.Outer(x) 81 | def newAdapter(d: _root_.x.Outer): Outer = new Outer { 82 | override val $delegate = d 83 | } 84 | } 85 | @JSExportAll 86 | trait Outer extends InstanceAdapter[_root_.x.Outer] { 87 | def outerMethod() = $delegate.outerMethod() 88 | object Inner extends js.Object { 89 | def newInstance(y: String): _root_.x.Outer#Inner = new $delegate.Inner(y) 90 | def newAdapter(d: _root_.x.Outer#Inner): Inner = new Inner { 91 | override val $delegate = d 92 | } 93 | 94 | } 95 | @JSExportAll 96 | trait Inner extends InstanceAdapter[_root_.x.Outer#Inner] { 97 | def innerMethod() = $delegate.innerMethod() 98 | } 99 | } 100 | 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/Adt1Test.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.JSExportTopLevel 6 | 7 | class Adt1Test extends DtsFunSuite { 8 | 9 | """ 10 | |export interface Adt1Case1 extends eu.swdev.scala.ts.dts.Adt1Test.Base { 11 | | 'Adt1Case1': never 12 | |} 13 | |export class Adt1Case1 { 14 | | constructor() 15 | |} 16 | |export interface Adt1Case2 extends eu.swdev.scala.ts.dts.Adt1Test.Base { 17 | | 'Adt1Case2': never 18 | |} 19 | |export class Adt1Case2 { 20 | | constructor() 21 | |} 22 | |export namespace eu { 23 | | namespace swdev { 24 | | namespace scala { 25 | | namespace ts { 26 | | namespace dts { 27 | | namespace Adt1Test { 28 | | interface Base { 29 | | 'eu.swdev.scala.ts.dts.Adt1Test.Base': never 30 | | } 31 | | type Base$u = Adt1Case1 | Adt1Case2 32 | | } 33 | | } 34 | | } 35 | | } 36 | | } 37 | |} 38 | |""".check() 39 | } 40 | 41 | object Adt1Test { 42 | 43 | sealed trait Base 44 | 45 | @JSExportTopLevel("Adt1Case1") 46 | class Case1 extends Base 47 | 48 | @JSExportTopLevel("Adt1Case2") 49 | class Case2 extends Base 50 | 51 | } 52 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/Adt2Test.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.JSExportTopLevel 6 | 7 | class Adt2Test extends DtsFunSuite { 8 | 9 | """ 10 | |export interface Adt2Case1 extends eu.swdev.scala.ts.dts.Adt2Test.Base { 11 | | 'Adt2Case1': never 12 | |} 13 | |export class Adt2Case1 { 14 | | constructor() 15 | |} 16 | |export interface Adt2Case2 extends eu.swdev.scala.ts.dts.Adt2Test.Base { 17 | | 'Adt2Case2': never 18 | |} 19 | |export class Adt2Case2 { 20 | | constructor() 21 | |} 22 | |export namespace eu { 23 | | namespace swdev { 24 | | namespace scala { 25 | | namespace ts { 26 | | namespace dts { 27 | | namespace Adt2Test { 28 | | interface Base { 29 | | 'eu.swdev.scala.ts.dts.Adt2Test.Base': never 30 | | } 31 | | type Base$u = Adt2Case1 | Adt2Case2 32 | | } 33 | | } 34 | | } 35 | | } 36 | | } 37 | |} 38 | |""".check() 39 | } 40 | 41 | object Adt2Test { 42 | 43 | sealed trait Base[X] 44 | 45 | @JSExportTopLevel("Adt2Case1") 46 | class Case1[Y] extends Base[Y] 47 | 48 | @JSExportTopLevel("Adt2Case2") 49 | class Case2 extends Base[Nothing] 50 | 51 | } 52 | 53 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/Adt3Test.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 6 | 7 | class Adt3Test extends DtsFunSuite { 8 | 9 | """ 10 | |export interface Adt3TestCase1$ extends eu.swdev.scala.ts.dts.Adt3Test.T { 11 | | readonly str: string 12 | | 'Adt3TestCase1$': never 13 | |} 14 | |export const Adt3TestCase1: Adt3TestCase1$ 15 | |export interface Adt3TestCase2$ extends eu.swdev.scala.ts.dts.Adt3Test.T { 16 | | readonly num: number 17 | | 'Adt3TestCase2$': never 18 | |} 19 | |export const Adt3TestCase2: Adt3TestCase2$ 20 | |export namespace eu { 21 | | namespace swdev { 22 | | namespace scala { 23 | | namespace ts { 24 | | namespace dts { 25 | | namespace Adt3Test { 26 | | interface T { 27 | | 'eu.swdev.scala.ts.dts.Adt3Test.T': never 28 | | } 29 | | type T$u = Adt3TestCase1$ | Adt3TestCase2$ 30 | | } 31 | | } 32 | | } 33 | | } 34 | | } 35 | |} 36 | |""".check() 37 | } 38 | 39 | object Adt3Test { 40 | 41 | sealed trait T 42 | 43 | @JSExportTopLevel("Adt3TestCase1") 44 | @JSExportAll 45 | object Case1 extends T { 46 | val str = "abc" 47 | } 48 | @JSExportTopLevel("Adt3TestCase2") 49 | @JSExportAll 50 | object Case2 extends T { 51 | val num = 555 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/AliasTest.scala: -------------------------------------------------------------------------------- 1 | package dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.JSExportTopLevel 6 | import scala.scalajs.js.| 7 | 8 | class AliasTest extends DtsFunSuite { 9 | 10 | """ 11 | |export function invert(v: dts.AliasTest.U): dts.AliasTest.U 12 | |export namespace dts { 13 | | namespace AliasTest { 14 | | type U = number | string | boolean 15 | | } 16 | |} 17 | |""".check() 18 | 19 | } 20 | 21 | object AliasTest { 22 | 23 | type U = Int | String | Boolean 24 | 25 | @JSExportTopLevel("invert") 26 | def invert(v: U): U = ??? 27 | } 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/ApiReferenceTest.scala: -------------------------------------------------------------------------------- 1 | package dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | import scala.scalajs.js.| 8 | 9 | class ApiReferenceTest extends DtsFunSuite { 10 | 11 | """ 12 | |export function someExportedMethod(in: dts.ApiReferenceTest.Input): dts.ApiReferenceTest.Output 13 | |export namespace dts { 14 | | namespace ApiReferenceTest { 15 | | interface In1 { 16 | | readonly i: number 17 | | 'dts.ApiReferenceTest.In1': never 18 | | } 19 | | type In2 = dts.ApiReferenceTest.In2$ 20 | | interface In2$ { 21 | | readonly s: string 22 | | 'dts.ApiReferenceTest.In2$': never 23 | | } 24 | | type Input = dts.ApiReferenceTest.In1 | dts.ApiReferenceTest.In2 25 | | interface Out1 { 26 | | readonly i: number 27 | | 'dts.ApiReferenceTest.Out1': never 28 | | } 29 | | interface Out2$ { 30 | | readonly s: string 31 | | 'dts.ApiReferenceTest.Out2$': never 32 | | } 33 | | type Output = dts.ApiReferenceTest.Out1 | dts.ApiReferenceTest.Out2$ 34 | | } 35 | |} 36 | |""".check() 37 | 38 | } 39 | 40 | object ApiReferenceTest { 41 | 42 | // types Input, Output, In1, In2, In2$, Out1, and Out2$ are exported 43 | // -> they are reference in the exported method 44 | 45 | type In2 = In2.type 46 | type Out2 = Out2.type // the Out2 type alias is not exported because it is not referenced 47 | 48 | type Input = In1 | In2 49 | type Output = Out1 | Out2.type 50 | 51 | @JSExportTopLevel("someExportedMethod") 52 | def someExportedMethod(in: Input): Output = ??? 53 | 54 | class Out1(val i: Int) extends js.Object 55 | 56 | object Out2 extends js.Object { 57 | val s = "abc" 58 | } 59 | 60 | class In1(val i: Int) extends js.Object 61 | 62 | object In2 extends js.Object { 63 | val s = "abc" 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/ArrayTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class ArrayTest extends DtsFunSuite { 9 | 10 | """ 11 | |export function vector(v: (number)[]): (number)[] 12 | |export function vectorGen(v: (X)[]): (X)[] 13 | |export function matrix(v: ((number)[])[]): ((number)[])[] 14 | |export function matrixGen(v: ((X)[])[]): ((X)[])[] 15 | |""".check() 16 | 17 | } 18 | 19 | object ArrayTest { 20 | 21 | @JSExportTopLevel("vector") 22 | def vector(v: js.Array[Int]) = v 23 | @JSExportTopLevel("vectorGen") 24 | def vectorGen[X](v: js.Array[X]) = v 25 | @JSExportTopLevel("matrix") 26 | def matrix(v: js.Array[js.Array[Int]]) = v 27 | @JSExportTopLevel("matrixGen") 28 | def matrixGen[X](v: js.Array[js.Array[X]]) = v 29 | 30 | } 31 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/ArrayTypeAliasTest.scala: -------------------------------------------------------------------------------- 1 | package dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | import eu.swdev.scala.ts.tpe.ReadOnlyArray 5 | 6 | import scala.scalajs.js 7 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 8 | 9 | class ArrayTypeAliasTest extends DtsFunSuite { 10 | 11 | """ 12 | |export class Example { 13 | | constructor() 14 | | foo(a: dts.Example.Elems): dts.Example.Elems 15 | |} 16 | |export namespace dts { 17 | | namespace Example { 18 | | type Elem = [string, any] 19 | | type Elems = (dts.Example.Elem)[] 20 | | } 21 | |} 22 | |""".check() 23 | 24 | } 25 | 26 | object Example { 27 | type Elem = js.Tuple2[String, js.Any] 28 | type Elems = js.Array[Elem] 29 | } 30 | 31 | @JSExportTopLevel("Example") 32 | @JSExportAll 33 | class Example() { 34 | 35 | import Example._ 36 | 37 | def foo(a: Elems) = a 38 | 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/BoundsTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class BoundsTest extends DtsFunSuite { 9 | 10 | """ 11 | |export function upperBound(t: T): void 12 | |export class UpperBound { 13 | | constructor() 14 | |} 15 | |""".check() 16 | 17 | } 18 | 19 | object BoundsTest { 20 | 21 | @JSExportTopLevel("upperBound") 22 | def upperBound[T <: js.Object](t: T): Unit = ??? 23 | 24 | @JSExportTopLevel("UpperBound") 25 | class UpperBound[T <: js.Object] 26 | } 27 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/BracketNotationTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.{JSExportTopLevel, JSName} 7 | 8 | class BracketNotationTest extends DtsFunSuite { 9 | 10 | """ 11 | |export interface BracketNotation$ { 12 | | readonly ['!x']: number 13 | | ['!y']: number 14 | | ['!z'](): number 15 | | 'BracketNotation$': never 16 | |} 17 | |export const BracketNotation: BracketNotation$ 18 | |""".check() 19 | 20 | } 21 | 22 | @JSExportTopLevel("BracketNotation") 23 | object BracketNotationTest extends js.Object { 24 | 25 | @JSName("!x") 26 | val x = 1 27 | 28 | @JSName("!y") 29 | var y = 1 30 | 31 | @JSName("!z") 32 | def z() = 1 33 | 34 | } 35 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/ClassInheritanceTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 6 | 7 | class ClassInheritanceTest extends DtsFunSuite { 8 | 9 | """ 10 | |export class A { 11 | | constructor(n: number) 12 | | readonly n: number 13 | |} 14 | |export class B extends A { 15 | | constructor(n: number, s: string) 16 | | readonly s: string 17 | |} 18 | |""".check() 19 | 20 | } 21 | 22 | object ClassInheritanceTest { 23 | 24 | @JSExportTopLevel("A") 25 | @JSExportAll 26 | class A(val n: Int) 27 | 28 | @JSExportTopLevel("B") 29 | @JSExportAll 30 | class B(n: Int, val s: String) extends A(n) 31 | 32 | } 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/ClassTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 6 | 7 | class ClassTest extends DtsFunSuite { 8 | 9 | """ 10 | |export class SomeClass { 11 | | constructor(s: string, i: number, b: boolean) 12 | | readonly s: string 13 | | i: number 14 | | doIt(): void 15 | |} 16 | |""".check() 17 | 18 | } 19 | 20 | @JSExportTopLevel("SomeClass") 21 | @JSExportAll 22 | case class SomeClass(s: String, var i: Int, private val b: Boolean) { 23 | 24 | def doIt() = () 25 | 26 | private def privateDef() = () 27 | private val privateVal = 1 28 | private var privateVar = 2 29 | 30 | } 31 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/ClassWithInnerObjPropertyTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 7 | 8 | class ClassWithInnerObjPropertyTest extends DtsFunSuite { 9 | 10 | """ 11 | |export interface AObj$ { 12 | | readonly outerV1: AObj.OuterV1 13 | | 'AObj$': never 14 | |} 15 | |export const AObj: AObj$ 16 | |export namespace eu { 17 | | namespace swdev { 18 | | namespace scala { 19 | | namespace ts { 20 | | namespace dts { 21 | | namespace AObj { 22 | | interface OuterV1 { 23 | | readonly Middle: eu.swdev.scala.ts.dts.AObj.OuterV1.Middle$ 24 | | 'eu.swdev.scala.ts.dts.AObj.OuterV1': never 25 | | } 26 | | namespace OuterV1 { 27 | | interface Middle$ { 28 | | readonly newAdapter: eu.swdev.scala.ts.dts.AObj.OuterV1.MiddleV1 29 | | 'eu.swdev.scala.ts.dts.AObj.OuterV1.Middle$': never 30 | | } 31 | | interface MiddleV1 { 32 | | 'eu.swdev.scala.ts.dts.AObj.OuterV1.MiddleV1': never 33 | | } 34 | | } 35 | | } 36 | | } 37 | | } 38 | | } 39 | | } 40 | |} 41 | |""".check() 42 | } 43 | 44 | @JSExportTopLevel("AObj") 45 | object AObj extends js.Object { 46 | 47 | @JSExportAll 48 | trait OuterV1 { 49 | 50 | @JSExportAll 51 | trait MiddleV1 52 | 53 | object Middle extends js.Object { 54 | def newAdapter: MiddleV1 = ??? 55 | } 56 | 57 | // val middle = Middle 58 | } 59 | 60 | val outerV1: OuterV1 = ??? 61 | // object OuterV1 extends js.Object { 62 | // def newAdapter: OuterV1 = ??? 63 | // } 64 | 65 | } 66 | 67 | //@JSExportTopLevel("OuterClass") 68 | //@JSExportAll 69 | //class OuterClassWithInheritedObject extends OuterTrait 70 | 71 | //@JSExportTopLevel("ClassWithInnerObjProperty") 72 | //@JSExportAll 73 | //class ClassWithInnerObjProperty { 74 | // 75 | // trait InnerObj 76 | // 77 | // object InnerObj extends js.Object { 78 | // val x = 1 79 | // } 80 | // 81 | // val innnerObj = InnerObj 82 | //} -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/CtorParamExportTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel} 6 | 7 | class CtorParamExportTest extends DtsFunSuite { 8 | 9 | """ 10 | |export class CtorParamClass { 11 | | constructor(x: number, z: number) 12 | | readonly x: number 13 | | y: number 14 | |} 15 | |""".check() 16 | 17 | } 18 | 19 | object CtorParamExportTest { 20 | 21 | @JSExportTopLevel("CtorParamClass") 22 | class C(@JSExport val x: Int, @JSExport("y") var z: Int) 23 | 24 | } 25 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/DateTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class DateTest extends DtsFunSuite { 9 | 10 | """ 11 | |export const date: Date 12 | |""".check() 13 | 14 | } 15 | 16 | object DateTest { 17 | @JSExportTopLevel("date") 18 | val date: js.Date = ??? 19 | } 20 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/DictionaryTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | import scala.scalajs.js.| 8 | 9 | class DictionaryTest extends DtsFunSuite { 10 | 11 | """ 12 | |export const dict1: { [key: string]: number } 13 | |export const dict2: { [key: string]: number | string } 14 | |""".check() 15 | 16 | } 17 | 18 | object DictionaryTest { 19 | @JSExportTopLevel("dict1") 20 | val dict1: js.Dictionary[Int] = ??? 21 | @JSExportTopLevel("dict2") 22 | val dict2: js.Dictionary[Int | String] = ??? 23 | } 24 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/FunctionTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class FunctionTest extends DtsFunSuite { 9 | 10 | """ 11 | |export function fun0(f: () => R): void 12 | |export function fun1(f: (p1: T1) => R): void 13 | |export function fun2(f: (p1: T1, p2: T2) => R): void 14 | |export function fun3(f: (p1: () => R, p2: (p1: T1) => R) => R): void 15 | |""".check() 16 | } 17 | 18 | object FunctionTest { 19 | @JSExportTopLevel("fun0") 20 | def fun0[R](f: js.Function0[R]) = () 21 | @JSExportTopLevel("fun1") 22 | def fun1[T1, R](f: js.Function1[T1, R]) = () 23 | @JSExportTopLevel("fun2") 24 | def fun2[T1, T2, R](f: js.Function2[T1, T2, R]) = () 25 | @JSExportTopLevel("fun3") 26 | def fun3[T1, R](f: js.Function2[js.Function0[R], js.Function1[T1, R], R]) = () 27 | } 28 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/GenericClassTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 6 | 7 | class GenericClassTest extends DtsFunSuite { 8 | 9 | """ 10 | |export class Box { 11 | | constructor(value: T) 12 | | readonly value: T 13 | | map(f: scala.Function1): Box 14 | |} 15 | |export function box(value: T): Box 16 | |export function unbox(b: Box): T 17 | |export namespace scala { 18 | | interface Function1 { 19 | | 'scala.Function1': never 20 | | } 21 | |} 22 | |""".check() 23 | 24 | } 25 | 26 | object GenericClassTest { 27 | 28 | @JSExportTopLevel("Box") 29 | @JSExportAll 30 | case class Box[T](value: T) { 31 | 32 | def map[X](f: T => X) = Box(f(value)) 33 | } 34 | 35 | @JSExportTopLevel("box") 36 | def box[T](value: T) = Box(value) 37 | 38 | @JSExportTopLevel("unbox") 39 | def unbox[T](b: Box[T]): T = b.value 40 | } 41 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/GenericFunctionTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.JSExportTopLevel 6 | 7 | class GenericFunctionTest extends DtsFunSuite { 8 | 9 | """ 10 | |export function some(t: T): scala.Some 11 | |export function option(t: T): scala.Option 12 | |export const none: scala.None$ 13 | |export namespace scala { 14 | | interface None$ extends scala.Option { 15 | | 'scala.None$': never 16 | | } 17 | | interface Option { 18 | | 'scala.Option': never 19 | | } 20 | | interface Some extends scala.Option { 21 | | 'scala.Some': never 22 | | } 23 | |} 24 | |""".check() 25 | 26 | } 27 | 28 | object GenericFunctionTest { 29 | 30 | @JSExportTopLevel("some") 31 | def some[T](t: T): Some[T] = Some(t) 32 | 33 | @JSExportTopLevel("option") 34 | def option[T](t: T): Option[T] = Some(t) 35 | 36 | @JSExportTopLevel("none") 37 | val none = None 38 | 39 | } 40 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/GenericUnionTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class GenericUnionTest extends DtsFunSuite { 9 | 10 | """ 11 | |export interface GenUnionCase1 extends eu.swdev.scala.ts.dts.GenericUnionTest.Base { 12 | | 'GenUnionCase1': never 13 | |} 14 | |export class GenUnionCase1 { 15 | | constructor() 16 | |} 17 | |export interface GenUnionCase2 extends eu.swdev.scala.ts.dts.GenericUnionTest.Base { 18 | | 'GenUnionCase2': never 19 | |} 20 | |export class GenUnionCase2 { 21 | | constructor() 22 | |} 23 | |export interface GenUnionCase3 extends eu.swdev.scala.ts.dts.GenericUnionTest.Base { 24 | | 'GenUnionCase3': never 25 | |} 26 | |export class GenUnionCase3 { 27 | | constructor() 28 | |} 29 | |export namespace eu { 30 | | namespace swdev { 31 | | namespace scala { 32 | | namespace ts { 33 | | namespace dts { 34 | | namespace GenericUnionTest { 35 | | interface Base { 36 | | 'eu.swdev.scala.ts.dts.GenericUnionTest.Base': never 37 | | } 38 | | type Base$u = GenUnionCase1 | GenUnionCase2 | GenUnionCase3<$M2_Y,T> 39 | | } 40 | | } 41 | | } 42 | | } 43 | | } 44 | |} 45 | |""".check() 46 | 47 | } 48 | 49 | object GenericUnionTest { 50 | 51 | sealed trait Base[T <: js.Object] 52 | 53 | @JSExportTopLevel("GenUnionCase1") 54 | class Case1[T <: js.Object] extends Base[T] 55 | @JSExportTopLevel("GenUnionCase2") 56 | class Case2[T <: js.Object, X] extends Base[T] 57 | @JSExportTopLevel("GenUnionCase3") 58 | class Case3[Y, T <: js.Object] extends Base[T] 59 | } 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/GlobalTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.{JSExportTopLevel, JSGlobal} 7 | 8 | class GlobalTest extends DtsFunSuite { 9 | 10 | """ 11 | |export const weakMap: WeakMap 12 | |export const weakSet: WeakSet 13 | |""".check() 14 | 15 | } 16 | 17 | object GlobalTest { 18 | 19 | @JSGlobal 20 | @js.native 21 | class WeakMap[K, V] 22 | 23 | @JSGlobal("WeakSet") 24 | @js.native 25 | class WeakSetRenamed[T] 26 | 27 | @JSExportTopLevel("weakMap") 28 | val map: WeakMap[String, String] = ??? 29 | 30 | @JSExportTopLevel("weakSet") 31 | val set: WeakSetRenamed[String] = ??? 32 | } 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/ImportNamespaceTest.scala: -------------------------------------------------------------------------------- 1 | package dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.{JSExportTopLevel, JSImport, JSName} 7 | 8 | class ImportNamespaceTest extends DtsFunSuite { 9 | 10 | """ 11 | |import * as $module from 'module' 12 | |export const namespaceImported: $module.ImportedClass 13 | |export const renamedNamespaceImported: $module.Renamed 14 | |""".check() 15 | 16 | } 17 | 18 | 19 | object ImportNamespaceTest extends js.Object { 20 | 21 | @JSImport("module", JSImport.Namespace) 22 | object ImportedNamespace extends js.Object { 23 | 24 | class ImportedClass 25 | 26 | @JSName("Renamed") 27 | class RenamedImportedClass 28 | 29 | } 30 | 31 | @JSExportTopLevel("namespaceImported") 32 | val namespaceImported: ImportedNamespace.ImportedClass = ??? 33 | 34 | @JSExportTopLevel("renamedNamespaceImported") 35 | val renamedNamespaceImported: ImportedNamespace.RenamedImportedClass = ??? 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/ImportTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.{JSExportTopLevel, JSGlobal, JSImport} 7 | 8 | class ImportTest extends DtsFunSuite { 9 | 10 | """ 11 | |import $random_ from 'random' 12 | |import * as $rxjs from 'rxjs' 13 | |export const observable: $rxjs.Observable 14 | |export const random: $random_ 15 | |""".check() 16 | 17 | } 18 | 19 | object ImportTest { 20 | 21 | @JSImport("rxjs", "Observable") 22 | @js.native 23 | class Observable[T] 24 | 25 | @JSImport("random", JSImport.Default) 26 | @js.native 27 | object Random 28 | 29 | @JSExportTopLevel("observable") 30 | val observable: Observable[String] = ??? 31 | 32 | @JSExportTopLevel("random") 33 | val random: Random.type = ??? 34 | } 35 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/InnerClassTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.JSExportTopLevel 6 | 7 | class InnerClassTest extends DtsFunSuite { 8 | 9 | """ 10 | |export const test: eu.swdev.scala.ts.dts.InnerClassTest.Outer.Inner 11 | |export namespace eu { 12 | | namespace swdev { 13 | | namespace scala { 14 | | namespace ts { 15 | | namespace dts { 16 | | namespace InnerClassTest { 17 | | namespace Outer { 18 | | interface Inner { 19 | | 'eu.swdev.scala.ts.dts.InnerClassTest.Outer.Inner': never 20 | | } 21 | | } 22 | | } 23 | | } 24 | | } 25 | | } 26 | | } 27 | |} 28 | |""".check() 29 | } 30 | 31 | object InnerClassTest { 32 | 33 | @JSExportTopLevel("test") 34 | val test: Outer#Inner = ??? 35 | 36 | class Outer { 37 | class Inner 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/IteratorTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class IteratorTest extends DtsFunSuite { 9 | 10 | """ 11 | |export const iterator: Iterator 12 | |export const iterable: Iterable 13 | |""".check() 14 | 15 | } 16 | 17 | object IteratorTest { 18 | @JSExportTopLevel("iterator") 19 | val x: js.Iterator[String] = ??? 20 | @JSExportTopLevel("iterable") 21 | val y: js.Iterable[Int] = ??? 22 | } 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/JSExportTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel} 6 | 7 | class JSExportTest extends DtsFunSuite { 8 | 9 | """ 10 | |export interface jsExportTest$ { 11 | | readonly x: number 12 | | readonly y: number 13 | | 'jsExportTest$': never 14 | |} 15 | |export const jsExportTest: jsExportTest$ 16 | |""".check() 17 | 18 | } 19 | 20 | @JSExportTopLevel("jsExportTest") 21 | object JSExportTest { 22 | 23 | @JSExport 24 | val x = 0 25 | @JSExport("y") 26 | val z = 0 27 | 28 | } 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/JsClassTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class JsClassTest extends DtsFunSuite { 9 | 10 | """ 11 | |export class JsClass { 12 | | constructor(str: string, num: number) 13 | | readonly str: string 14 | | num: number 15 | | setNum(n: number): void 16 | |} 17 | |""".check() 18 | 19 | } 20 | 21 | object JsClassTest { 22 | 23 | @JSExportTopLevel("JsClass") 24 | class JsClass(val str: String, var num: Int) extends js.Object { 25 | def setNum(n: Int): Unit = num = n 26 | } 27 | } 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/NativeSymbolTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel, JSName} 7 | 8 | class NativeSymbolTest extends DtsFunSuite { 9 | 10 | """ 11 | |export interface NativeSymbol$ { 12 | | readonly someSymbol: symbol 13 | | [Symbol.iterator](): Iterator 14 | | [NativeSymbol.someSymbol](x: number): number 15 | | 'NativeSymbol$': never 16 | |} 17 | |export const NativeSymbol: NativeSymbol$ 18 | |""".check() 19 | 20 | } 21 | 22 | @JSExportTopLevel("NativeSymbol") 23 | object NativeSymbolTest extends js.Object { 24 | 25 | val someSymbol: js.Symbol = ??? 26 | 27 | @JSName(js.Symbol.iterator) 28 | def iterator(): js.Iterator[Int] = ??? 29 | 30 | @JSName(someSymbol) 31 | def someMethod(x: Int): Int = x 32 | } 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/NoneTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.JSExportTopLevel 6 | 7 | class NoneTest extends DtsFunSuite { 8 | 9 | """ 10 | |export const none: scala.None$ 11 | |export namespace scala { 12 | | interface None$ { 13 | | 'scala.None$': never 14 | | } 15 | |} 16 | |""".check() 17 | 18 | } 19 | 20 | object NoneTest { 21 | 22 | @JSExportTopLevel("none") 23 | val none = None 24 | 25 | } 26 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/ObjectTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 7 | 8 | class ObjectTest extends DtsFunSuite { 9 | 10 | """ 11 | |export interface SomeObject$ { 12 | | doIt(): void 13 | | readonly x: number 14 | | y: number 15 | | readonly o: eu.swdev.scala.ts.dts.ObjectTest.o$ 16 | | 'SomeObject$': never 17 | |} 18 | |export const SomeObject: SomeObject$ 19 | |export namespace eu { 20 | | namespace swdev { 21 | | namespace scala { 22 | | namespace ts { 23 | | namespace dts { 24 | | namespace ObjectTest { 25 | | interface o$ { 26 | | readonly a: string 27 | | 'eu.swdev.scala.ts.dts.ObjectTest.o$': never 28 | | } 29 | | } 30 | | } 31 | | } 32 | | } 33 | | } 34 | |} 35 | |""".check() 36 | 37 | } 38 | 39 | @JSExportTopLevel("SomeObject") 40 | @JSExportAll 41 | object ObjectTest { 42 | 43 | def doIt() = () 44 | 45 | val x = 1 46 | var y = 2 47 | 48 | @JSExportAll 49 | object o { 50 | val a = "abc" 51 | } 52 | 53 | private val a = 0 54 | private var b = 1 55 | private def m = () 56 | 57 | } -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/OuterTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class OuterTest extends DtsFunSuite { 9 | 10 | """ 11 | |export class OuterClass { 12 | | constructor() 13 | | readonly midd: eu.swdev.scala.ts.dts.Outer.midd$ 14 | |} 15 | |export interface OuterObject$ { 16 | | readonly middle: eu.swdev.scala.ts.dts.Outer.middle$ 17 | | 'OuterObject$': never 18 | |} 19 | |export const OuterObject: OuterObject$ 20 | |export namespace eu { 21 | | namespace swdev { 22 | | namespace scala { 23 | | namespace ts { 24 | | namespace dts { 25 | | namespace Outer { 26 | | interface midd$ { 27 | | x: number 28 | | 'eu.swdev.scala.ts.dts.Outer.midd$': never 29 | | } 30 | | interface middle$ { 31 | | readonly innerMost: eu.swdev.scala.ts.dts.Outer.middle.innerMost$ 32 | | 'eu.swdev.scala.ts.dts.Outer.middle$': never 33 | | } 34 | | namespace middle { 35 | | interface innerMost$ { 36 | | x: number 37 | | 'eu.swdev.scala.ts.dts.Outer.middle.innerMost$': never 38 | | } 39 | | } 40 | | } 41 | | } 42 | | } 43 | | } 44 | | } 45 | |} 46 | |""".check() 47 | 48 | } 49 | 50 | 51 | @JSExportTopLevel("OuterClass") 52 | class Outer extends js.Object { 53 | object midd extends js.Object { 54 | // object innerMost extends js.Object { 55 | var x = 1 56 | // } 57 | } 58 | } 59 | 60 | @JSExportTopLevel("OuterObject") 61 | object Outer extends js.Object { 62 | object middle extends js.Object { 63 | object innerMost extends js.Object { 64 | var x = 1 65 | } 66 | } 67 | } 68 | 69 | 70 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/PromiseLikeTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class PromiseLikeTest extends DtsFunSuite { 9 | 10 | """ 11 | |export const promiseLike: PromiseLike 12 | |""".check() 13 | 14 | } 15 | 16 | object PromiseLikeTest { 17 | 18 | @JSExportTopLevel("promiseLike") 19 | val pl: js.Thenable[Int] = ??? 20 | } 21 | 22 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/PromiseTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class PromiseTest extends DtsFunSuite { 9 | 10 | """ 11 | |export const promise: Promise 12 | |""".check() 13 | 14 | } 15 | 16 | object PromiseTest { 17 | 18 | @JSExportTopLevel("promise") 19 | val promise: js.Promise[String] = ??? 20 | } 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/ReadOnlyArrayTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | import eu.swdev.scala.ts.tpe.ReadOnlyArray 5 | 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class ReadOnlyArrayTest extends DtsFunSuite { 9 | 10 | """ 11 | |export const readOnlyArray: ReadonlyArray 12 | |""".check() 13 | 14 | } 15 | 16 | object ReadOnlyArrayTest { 17 | 18 | @JSExportTopLevel("readOnlyArray") 19 | val readOnlyArray: ReadOnlyArray[Int] = ??? 20 | } 21 | 22 | 23 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/RegExpTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class RegExpTest extends DtsFunSuite { 9 | 10 | """ 11 | |export const regExp: RegExp 12 | |""".check() 13 | 14 | } 15 | 16 | object RegExpTest { 17 | @JSExportTopLevel("regExp") 18 | val regExp: js.RegExp = ??? 19 | } 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/RootPackageClassTest.scala: -------------------------------------------------------------------------------- 1 | import eu.swdev.scala.ts.DtsFunSuite 2 | 3 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 4 | 5 | class RootPackageClassTest extends DtsFunSuite { 6 | 7 | """ 8 | |export class RootPackageClass { 9 | | constructor() 10 | | readonly i: number 11 | |} 12 | |""".check() 13 | 14 | } 15 | 16 | @JSExportTopLevel("RootPackageClass") 17 | @JSExportAll 18 | class RootPackageClass { 19 | val i = 1 20 | } 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/RootPackageObjectTest.scala: -------------------------------------------------------------------------------- 1 | 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class RootPackageObjectTest extends DtsFunSuite { 9 | 10 | """ 11 | |export interface rootPackageObject$ { 12 | | readonly x: RootPackageObjectTest.x$ 13 | | 'rootPackageObject$': never 14 | |} 15 | |export const rootPackageObject: rootPackageObject$ 16 | |export namespace RootPackageObjectTest { 17 | | interface x$ { 18 | | readonly x: number 19 | | 'RootPackageObjectTest.x$': never 20 | | } 21 | |} 22 | |""".check() 23 | 24 | } 25 | 26 | @JSExportTopLevel("rootPackageObject") 27 | object RootPackageObjectTest extends js.Object { 28 | object x extends js.Object { 29 | val x = 1 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/SealedTraitAllMembersExportedTest.scala: -------------------------------------------------------------------------------- 1 | package dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.JSExportTopLevel 6 | 7 | class SealedTraitAllMembersExportedTest extends DtsFunSuite { 8 | 9 | """ 10 | |export interface Case1 extends dts.SealedTraitAllMembersExportedTest.Base { 11 | | 'Case1': never 12 | |} 13 | |export class Case1 { 14 | | constructor() 15 | |} 16 | |export interface Case2 extends dts.SealedTraitAllMembersExportedTest.Sub { 17 | | 'Case2': never 18 | |} 19 | |export class Case2 { 20 | | constructor() 21 | |} 22 | |export namespace dts { 23 | | namespace SealedTraitAllMembersExportedTest { 24 | | interface Base { 25 | | 'dts.SealedTraitAllMembersExportedTest.Base': never 26 | | } 27 | | type Base$u = Case1 | dts.SealedTraitAllMembersExportedTest.Sub$u 28 | | interface Sub extends dts.SealedTraitAllMembersExportedTest.Base { 29 | | 'dts.SealedTraitAllMembersExportedTest.Sub': never 30 | | } 31 | | type Sub$u = Case2 32 | | } 33 | |} 34 | |""".check() 35 | 36 | } 37 | 38 | object SealedTraitAllMembersExportedTest { 39 | 40 | sealed trait Base 41 | sealed trait Sub extends Base 42 | 43 | @JSExportTopLevel("Case1") 44 | class Case1 extends Base 45 | 46 | @JSExportTopLevel("Case2") 47 | class Case2 extends Sub 48 | } 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/SealedTraitHierarchyTest.scala: -------------------------------------------------------------------------------- 1 | package dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.JSExportTopLevel 6 | 7 | class SealedTraitHierarchyTest extends DtsFunSuite { 8 | 9 | """ 10 | |export interface Case1 extends dts.SealedTraitHierarchyTest.Base { 11 | | 'Case1': never 12 | |} 13 | |export class Case1 { 14 | | constructor() 15 | |} 16 | |export interface Case2 extends dts.SealedTraitHierarchyTest.Base { 17 | | 'Case2': never 18 | |} 19 | |export class Case2 { 20 | | constructor() 21 | |} 22 | |export interface Case3 extends dts.SealedTraitHierarchyTest.Middle { 23 | | 'Case3': never 24 | |} 25 | |export class Case3 { 26 | | constructor() 27 | |} 28 | |export interface Case4 extends dts.SealedTraitHierarchyTest.Middle { 29 | | 'Case4': never 30 | |} 31 | |export class Case4 { 32 | | constructor() 33 | |} 34 | |export interface Case5 extends dts.SealedTraitHierarchyTest.Middle { 35 | | 'Case5': never 36 | |} 37 | |export class Case5 { 38 | | constructor() 39 | |} 40 | |export namespace dts { 41 | | namespace SealedTraitHierarchyTest { 42 | | interface Base { 43 | | 'dts.SealedTraitHierarchyTest.Base': never 44 | | } 45 | | type Base$u = Case1 | Case2 | dts.SealedTraitHierarchyTest.Middle$u 46 | | interface Middle extends dts.SealedTraitHierarchyTest.Base { 47 | | 'dts.SealedTraitHierarchyTest.Middle': never 48 | | } 49 | | type Middle$u = Case3 | Case4 | Case5 50 | | } 51 | |} 52 | |""".check() 53 | 54 | } 55 | 56 | object SealedTraitHierarchyTest { 57 | 58 | sealed trait Base[X] 59 | 60 | sealed trait Middle[X, Y] extends Base[X] 61 | 62 | @JSExportTopLevel("Case1") 63 | class Case1[X] extends Base[X] 64 | 65 | @JSExportTopLevel("Case2") 66 | class Case2[X, Y] extends Base[X] 67 | 68 | @JSExportTopLevel("Case3") 69 | class Case3[X, Y] extends Middle[X, Y] 70 | 71 | @JSExportTopLevel("Case4") 72 | class Case4[X, Y, Z] extends Middle[X, Y] 73 | 74 | @JSExportTopLevel("Case5") 75 | class Case5[X, Y, Z] extends Middle[X, Y] 76 | 77 | } 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/SealedTraitNoMembersExportedTest.scala: -------------------------------------------------------------------------------- 1 | package dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | class SealedTraitNoMembersExportedTest extends DtsFunSuite { 6 | 7 | """ 8 | |""".check() 9 | 10 | } 11 | 12 | object SealedTraitNoMembersExportedTest { 13 | sealed trait Base 14 | sealed trait Sub extends Base 15 | 16 | class Case1 extends Base 17 | 18 | class Case2 extends Sub 19 | 20 | class Case3 extends Sub 21 | 22 | } 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/SealedTraitSomeMembersExportedTest.scala: -------------------------------------------------------------------------------- 1 | package dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.JSExportTopLevel 6 | 7 | class SealedTraitSomeMembersExportedTest extends DtsFunSuite { 8 | 9 | """ 10 | |export interface Case1 extends dts.SealedTraitSomeMembersExportedTest.Base { 11 | | 'Case1': never 12 | |} 13 | |export class Case1 { 14 | | constructor() 15 | |} 16 | |export interface Case2 extends dts.SealedTraitSomeMembersExportedTest.Sub { 17 | | 'Case2': never 18 | |} 19 | |export class Case2 { 20 | | constructor() 21 | |} 22 | |export namespace dts { 23 | | namespace SealedTraitSomeMembersExportedTest { 24 | | interface Base { 25 | | 'dts.SealedTraitSomeMembersExportedTest.Base': never 26 | | } 27 | | type Base$u = Case1 | dts.SealedTraitSomeMembersExportedTest.Sub$u 28 | | interface Case3 extends dts.SealedTraitSomeMembersExportedTest.Sub { 29 | | 'dts.SealedTraitSomeMembersExportedTest.Case3': never 30 | | } 31 | | interface Sub extends dts.SealedTraitSomeMembersExportedTest.Base { 32 | | 'dts.SealedTraitSomeMembersExportedTest.Sub': never 33 | | } 34 | | type Sub$u = Case2 | dts.SealedTraitSomeMembersExportedTest.Case3 35 | | } 36 | |} 37 | |""".check() 38 | 39 | } 40 | 41 | object SealedTraitSomeMembersExportedTest { 42 | sealed trait Base 43 | sealed trait Sub extends Base 44 | 45 | @JSExportTopLevel("Case1") 46 | class Case1 extends Base 47 | 48 | @JSExportTopLevel("Case2") 49 | class Case2 extends Sub 50 | 51 | class Case3 extends Sub 52 | 53 | } 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/SealedTraitUnexportedMembersTest.scala: -------------------------------------------------------------------------------- 1 | package dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.JSExportTopLevel 6 | 7 | class SealedTraitUnexportedMembersTest extends DtsFunSuite { 8 | 9 | """ 10 | |export interface Case1 extends dts.SealedTraitUnexportedMembersTest.Base { 11 | | 'Case1': never 12 | |} 13 | |export class Case1 { 14 | | constructor() 15 | |} 16 | |export namespace dts { 17 | | namespace SealedTraitUnexportedMembersTest { 18 | | interface Base { 19 | | 'dts.SealedTraitUnexportedMembersTest.Base': never 20 | | } 21 | | type Base$u = Case1 | dts.SealedTraitUnexportedMembersTest.Case2 | dts.SealedTraitUnexportedMembersTest.Case3$ 22 | | interface Case2 extends dts.SealedTraitUnexportedMembersTest.Base { 23 | | 'dts.SealedTraitUnexportedMembersTest.Case2': never 24 | | } 25 | | interface Case3$ extends dts.SealedTraitUnexportedMembersTest.Base { 26 | | 'dts.SealedTraitUnexportedMembersTest.Case3$': never 27 | | } 28 | | } 29 | |} 30 | |""".check() 31 | 32 | } 33 | 34 | object SealedTraitUnexportedMembersTest { 35 | 36 | sealed trait Base 37 | 38 | @JSExportTopLevel("Case1") 39 | class Case1 extends Base 40 | 41 | class Case2 extends Base 42 | 43 | object Case3 extends Base 44 | } 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/SealedTraitWithoutMembersExportedTest.scala: -------------------------------------------------------------------------------- 1 | package dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | class SealedTraitWithoutMembersExportedTest extends DtsFunSuite { 6 | 7 | """ 8 | |""".check() 9 | 10 | } 11 | 12 | object SealedTraitWithoutMembersExportedTest { 13 | 14 | sealed trait Base 15 | sealed trait Sub 16 | 17 | } -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/StaticTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.{JSExportStatic, JSExportTopLevel} 7 | 8 | class StaticTest extends DtsFunSuite { 9 | 10 | """ 11 | |export class ClassWitStatics { 12 | | static twice(x: number): number 13 | | static readonly str: string 14 | | static numero: number 15 | | static get x(): number 16 | | static set x(i: number) 17 | | constructor() 18 | |} 19 | |""".check() 20 | 21 | } 22 | 23 | object StaticTest { 24 | 25 | @JSExportTopLevel("ClassWitStatics") 26 | class ClassWitStatics extends js.Object 27 | 28 | object ClassWitStatics { 29 | 30 | @JSExportStatic 31 | def twice(x: Int) = 2 * x 32 | @JSExportStatic 33 | val str = "abc" 34 | @JSExportStatic("numero") 35 | var num = 55 36 | @JSExportStatic 37 | def x: Int = ??? 38 | @JSExportStatic 39 | def x_=(i: Int): Unit = ??? 40 | 41 | } 42 | 43 | } 44 | 45 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/SymbolTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class SymbolTest extends DtsFunSuite { 9 | 10 | """ 11 | |export const sym: symbol 12 | |""".check() 13 | 14 | } 15 | 16 | object SymbolTest { 17 | 18 | @JSExportTopLevel("sym") 19 | val sym: js.Symbol = ??? 20 | } 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/ThisFunctionTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.{ThisFunction1, ThisFunction2} 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class ThisFunctionTest extends DtsFunSuite { 9 | 10 | """ 11 | |export const thisFunction1: (this: void, p1: string) => number 12 | |export const thisFunction2: (this: void, p1: string, p2: boolean) => number 13 | |export function thisMethod(this: void, i: number): number 14 | |""".check() 15 | 16 | } 17 | 18 | object ThisFunctionTest { 19 | @JSExportTopLevel("thisFunction1") 20 | val f1: ThisFunction1[Unit, String, Int] = ??? 21 | @JSExportTopLevel("thisFunction2") 22 | val f2: ThisFunction2[Unit, String, Boolean, Int] = ??? 23 | @JSExportTopLevel("thisMethod") 24 | def f3(`this`: Unit, i: Int): Int = i 25 | } 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/TopLevelDefValVarTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.JSExportTopLevel 6 | 7 | class TopLevelDefValVarTest extends DtsFunSuite { 8 | 9 | """ 10 | |export const topLevelDefValVar_valString: string 11 | |export const topLevelDefValVar_valBoolean: boolean 12 | |export const topLevelDefValVar_valInt: number 13 | |export const topLevelDefValVar_valDouble: number 14 | |export let topLevelDefValVar_varString: string 15 | |export let topLevelDefValVar_varBoolean: boolean 16 | |export let topLevelDefValVar_varInt: number 17 | |export let topLevelDefValVar_varDouble: number 18 | |export function topLevelDefValVar_defUnit(): void 19 | |export function topLevelDefValVar_defNothing(): never 20 | |export function topLevelDefValVar_defDouble(n: number): number 21 | |""".check() 22 | 23 | } 24 | 25 | object TopLevelDefValVarTest { 26 | 27 | @JSExportTopLevel("topLevelDefValVar_valString") 28 | val valString = "abc"; 29 | @JSExportTopLevel("topLevelDefValVar_valBoolean") 30 | val valBoolean = true 31 | @JSExportTopLevel("topLevelDefValVar_valInt") 32 | val valInt = 1 33 | @JSExportTopLevel("topLevelDefValVar_valDouble") 34 | val valDouble = 1.0 35 | 36 | @JSExportTopLevel("topLevelDefValVar_varString") 37 | var varString = "abc"; 38 | @JSExportTopLevel("topLevelDefValVar_varBoolean") 39 | var varBoolean = true 40 | @JSExportTopLevel("topLevelDefValVar_varInt") 41 | var varInt = 1 42 | @JSExportTopLevel("topLevelDefValVar_varDouble") 43 | var varDouble = 1.0 44 | 45 | @JSExportTopLevel("topLevelDefValVar_defUnit") 46 | def unit() = () 47 | @JSExportTopLevel("topLevelDefValVar_defNothing") 48 | def nothing(): Nothing = throw new RuntimeException() 49 | @JSExportTopLevel("topLevelDefValVar_defDouble") 50 | def double(n: Double) = 2 * n 51 | 52 | } 53 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/TraitInheritanceTest1.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 6 | 7 | class TraitInheritanceTest1 extends DtsFunSuite { 8 | 9 | """ 10 | |export interface ClassWithInheritedMethods1 extends eu.swdev.scala.ts.dts.TraitInheritanceTest1.Middle { 11 | | 'ClassWithInheritedMethods1': never 12 | |} 13 | |export class ClassWithInheritedMethods1 { 14 | | constructor() 15 | |} 16 | |export namespace eu { 17 | | namespace swdev { 18 | | namespace scala { 19 | | namespace ts { 20 | | namespace dts { 21 | | namespace TraitInheritanceTest1 { 22 | | interface Base { 23 | | base(n: number): number 24 | | 'eu.swdev.scala.ts.dts.TraitInheritanceTest1.Base': never 25 | | } 26 | | interface Middle extends eu.swdev.scala.ts.dts.TraitInheritanceTest1.Base { 27 | | middle(n: number): number 28 | | 'eu.swdev.scala.ts.dts.TraitInheritanceTest1.Middle': never 29 | | } 30 | | } 31 | | } 32 | | } 33 | | } 34 | | } 35 | |} 36 | |""".check() 37 | 38 | } 39 | 40 | object TraitInheritanceTest1 { 41 | @JSExportAll 42 | trait Base { 43 | def base(n: Int) = 2*n 44 | } 45 | 46 | @JSExportAll 47 | trait Middle extends Base { 48 | def middle(n: Int) = 3*n 49 | } 50 | 51 | @JSExportTopLevel("ClassWithInheritedMethods1") 52 | class Cls extends Middle 53 | } 54 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/TraitInheritanceTest2.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class TraitInheritanceTest2 extends DtsFunSuite { 9 | 10 | """ 11 | |export interface ClassWithInheritedMethods2 extends eu.swdev.scala.ts.dts.TraitInheritanceTest2.Middle { 12 | | 'ClassWithInheritedMethods2': never 13 | |} 14 | |export class ClassWithInheritedMethods2 { 15 | | constructor() 16 | | middle(n: number): number 17 | | base(n: number): number 18 | |} 19 | |export namespace eu { 20 | | namespace swdev { 21 | | namespace scala { 22 | | namespace ts { 23 | | namespace dts { 24 | | namespace TraitInheritanceTest2 { 25 | | interface Base { 26 | | base(n: number): number 27 | | 'eu.swdev.scala.ts.dts.TraitInheritanceTest2.Base': never 28 | | } 29 | | interface Middle extends eu.swdev.scala.ts.dts.TraitInheritanceTest2.Base { 30 | | middle(n: number): number 31 | | 'eu.swdev.scala.ts.dts.TraitInheritanceTest2.Middle': never 32 | | } 33 | | } 34 | | } 35 | | } 36 | | } 37 | | } 38 | |} 39 | |""".check() 40 | 41 | } 42 | 43 | object TraitInheritanceTest2 { 44 | trait Base extends js.Object { 45 | def base(n: Int): Int 46 | } 47 | 48 | trait Middle extends Base { 49 | def middle(n: Int): Int 50 | } 51 | 52 | @JSExportTopLevel("ClassWithInheritedMethods2") 53 | class Cls extends Middle { 54 | override def middle(n: Int): Int = 3*n 55 | 56 | override def base(n: Int): Int = 2*n 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/TupleTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js 6 | import scala.scalajs.js.annotation.JSExportTopLevel 7 | 8 | class TupleTest extends DtsFunSuite { 9 | 10 | """ 11 | |export const tuple2: [string, number] 12 | |export const tuple3: [string, number, boolean] 13 | |""".check() 14 | } 15 | 16 | object TupleTest { 17 | @JSExportTopLevel("tuple2") 18 | val tuple2: js.Tuple2[String, Int] = ??? 19 | @JSExportTopLevel("tuple3") 20 | val tuple3: js.Tuple3[String, Int, Boolean] = ??? 21 | } 22 | 23 | 24 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/TypeAliasTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.JSExportTopLevel 6 | import scala.scalajs.js.| 7 | 8 | class TypeAliasTest extends DtsFunSuite { 9 | 10 | """ 11 | |export const valWithTypeAlias: eu.swdev.scala.ts.dts.TypeAliasTest.X 12 | |export namespace eu { 13 | | namespace swdev { 14 | | namespace scala { 15 | | namespace ts { 16 | | namespace dts { 17 | | namespace TypeAliasTest { 18 | | type X = string | number 19 | | } 20 | | } 21 | | } 22 | | } 23 | | } 24 | |} 25 | |""".check() 26 | 27 | } 28 | 29 | object TypeAliasTest { 30 | 31 | type X = String | Int 32 | 33 | @JSExportTopLevel("valWithTypeAlias") 34 | val alias: X = ??? 35 | } 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/UndefOrTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.UndefOr 6 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 7 | 8 | class UndefOrTest extends DtsFunSuite { 9 | 10 | """ 11 | |export function undefOrInt(u?: number): number | undefined 12 | |export function undefOrGeneric(u?: X): X | undefined 13 | |export class UndefOrClass { 14 | | constructor(x?: X, y?: X) 15 | | readonly x?: X 16 | | y?: X 17 | | method(p?: X): X | undefined 18 | |} 19 | |""".check() 20 | 21 | } 22 | 23 | object UndefOrTest { 24 | 25 | @JSExportTopLevel("undefOrInt") 26 | def undefOrInt(u: UndefOr[Int]) = u 27 | @JSExportTopLevel("undefOrGeneric") 28 | def undefOrGeneric[X](u: UndefOr[X]) = u 29 | 30 | @JSExportTopLevel("UndefOrClass") 31 | @JSExportAll 32 | case class UndefOrClass[X](x: UndefOr[X], var y: UndefOr[X]) { 33 | def method(p: UndefOr[X]) = p 34 | } 35 | 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/UnionTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.JSExportTopLevel 6 | import scala.scalajs.js.| 7 | 8 | class UnionTest extends DtsFunSuite { 9 | 10 | """ 11 | |export const stringOrBooleanOrInt: string | boolean | number 12 | |""".check() 13 | 14 | } 15 | 16 | object UnionTest { 17 | 18 | @JSExportTopLevel("stringOrBooleanOrInt") 19 | val x: String | Boolean | Int = ??? 20 | 21 | } 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/dts/VarArgsTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.dts 2 | 3 | import eu.swdev.scala.ts.DtsFunSuite 4 | 5 | import scala.scalajs.js.annotation.JSExportTopLevel 6 | 7 | class VarArgsTest extends DtsFunSuite { 8 | 9 | """ 10 | |export function sumVarArgs(...is: number[]): number 11 | |""".check() 12 | 13 | } 14 | 15 | object VarArgsTest { 16 | 17 | @JSExportTopLevel("sumVarArgs") 18 | def sum(is: Int*): Int = is.sum 19 | } 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /generator/src/test/scala/eu/swdev/scala/ts/tpe/package.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | package object tpe { 4 | 5 | type ReadOnlyArray[T] = scala.scalajs.js.Array[T] 6 | 7 | } 8 | -------------------------------------------------------------------------------- /generator/src/test/scala/scala/scalajs/js/annotation/stubs.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Scala.js (https://www.scala-js.org/) 3 | * 4 | * Copyright EPFL. 5 | * 6 | * Licensed under Apache License 2.0 7 | * (https://www.apache.org/licenses/LICENSE-2.0). 8 | * 9 | * See the NOTICE file distributed with this work for 10 | * additional information regarding copyright ownership. 11 | */ 12 | 13 | package scala.scalajs.js.annotation 14 | 15 | /** Marks the annotated class or object as imported from another JS module. 16 | * 17 | * Intuitively, this corresponds to ECMAScript import directives. See the 18 | * documentation of the various constructors. 19 | * 20 | * `@JSImport` is not compatible with the `jsDependencies` mechanism offered 21 | * by the Scala.js sbt plugin. You are responsible for resolving and/or 22 | * bundling the JavaScript modules that you are importing using other 23 | * mechanisms. 24 | */ 25 | class JSImport private () extends scala.annotation.StaticAnnotation { 26 | 27 | /** Named import of a member of the module. 28 | * 29 | * Intuitively, this corresponds to the following ECMAScript import 30 | * directive: 31 | * {{{ 32 | * import { as AnnotatedClassOrObject } from 33 | * }}} 34 | * 35 | * To import the default export of a module, use `JSImport.Default` as 36 | * `name`. 37 | */ 38 | def this(module: String, name: String) = this() 39 | 40 | /** Namespace import (import the module itself). 41 | * 42 | * The second parameter should be the singleton `JSImport.Namespace`. 43 | * 44 | * Intuitively, this corresponds to 45 | * {{{ 46 | * import * as AnnotatedObject from 47 | * }}} 48 | */ 49 | def this(module: String, name: JSImport.Namespace.type) = this() 50 | 51 | /** Named import of a member of the module, with a fallback on a global 52 | * variable. 53 | * 54 | * When linking with module support, this is equivalent to 55 | * `@JSImport(module, name)`. 56 | * 57 | * When linking without module support, this is equivalent to 58 | * `@JSGlobal(globalFallback)`. 59 | */ 60 | def this(module: String, name: String, globalFallback: String) = this() 61 | 62 | /** Namespace import (import the module itself), with a fallback on a global 63 | * variable. 64 | * 65 | * When linking with module support, this is equivalent to 66 | * `@JSImport(module, name)`. 67 | * 68 | * When linking without module support, this is equivalent to 69 | * `@JSGlobal(globalFallback)`. 70 | */ 71 | def this(module: String, name: JSImport.Namespace.type, 72 | globalFallback: String) = this() 73 | } 74 | 75 | object JSImport { 76 | /** Use as the `name` of a `JSImport` to use the default import. 77 | * 78 | * The actual value of this constant, the string `"default"`, is not 79 | * arbitrary. It is the name under which a default export is registered in 80 | * the ECMAScript 2015 specification. 81 | */ 82 | final val Default = "default" 83 | 84 | /** Use as the `name` of a `JSImport` to use a namespace import. 85 | * 86 | * Intuitively, it corresponds to `*` in an ECMAScript import: 87 | * {{{ 88 | * import * as AnnotatedObject from 89 | * }}} 90 | */ 91 | object Namespace 92 | } 93 | 94 | class JSGlobal extends scala.annotation.StaticAnnotation { 95 | def this(name: String) = this() 96 | } 97 | 98 | class JSName private () extends scala.annotation.StaticAnnotation { 99 | def this(name: String) = this() 100 | def this(symbol: scala.scalajs.js.Symbol) = this() 101 | } 102 | 103 | class JSExportStatic extends scala.annotation.StaticAnnotation { 104 | def this(name: String) = this() 105 | } 106 | -------------------------------------------------------------------------------- /generator/src/test/scala/scala/scalajs/js/package.scala: -------------------------------------------------------------------------------- 1 | package scala.scalajs 2 | 3 | import scala.annotation.unchecked.uncheckedVariance 4 | 5 | package object js { 6 | 7 | type UndefOr[+A] = (A @uncheckedVariance) | Unit 8 | 9 | class native extends scala.annotation.StaticAnnotation 10 | } 11 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version = 1.9.3 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | libraryDependencies += "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value 2 | 3 | addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.13.2") 4 | addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.0.0") 5 | addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.12") 6 | -------------------------------------------------------------------------------- /runtime/src/main/scala/eu/swdev/scala/ts/adapter/InteropIterable.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.adapter 2 | 3 | import scala.scalajs.js 4 | import scala.scalajs.js.JSConverters._ 5 | import scala.scalajs.js.annotation.JSName 6 | 7 | class InteropIterable[A, B](iter: Iterable[A], f: A => B) extends js.Iterable[B] { 8 | @JSName(js.Symbol.iterator) 9 | override def jsIterator(): js.Iterator[B] = iter.map(f).iterator.toJSIterator 10 | } 11 | -------------------------------------------------------------------------------- /runtime/src/main/scala/eu/swdev/scala/ts/adapter/package.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | package object adapter { 4 | 5 | /** 6 | * Captures the the type of the value that is converted. 7 | */ 8 | implicit class InteropFrom[F](val f: F) extends AnyVal { 9 | def $cnv[T](implicit ev: InteropConverter[F, T]): T = ev(f) 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /runtime/src/main/scala/eu/swdev/scala/ts/tpe/package.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | package object tpe { 4 | 5 | type ReadOnlyArray[T] = scala.scalajs.js.Array[T] 6 | 7 | } 8 | -------------------------------------------------------------------------------- /runtime/src/test/scala/eu/swdev/scala/ts/adapter/AsyncConverterTest.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.adapter 2 | 3 | import org.scalatest.funsuite.AsyncFunSuite 4 | import org.scalatest.matchers.must.Matchers 5 | 6 | import scala.concurrent.Future 7 | import scala.scalajs.js 8 | 9 | class AsyncConverterTest extends AsyncFunSuite with Matchers { 10 | 11 | implicit override def executionContext = scala.scalajs.concurrent.JSExecutionContext.queue 12 | 13 | test("Promise<->Future") { 14 | def method[X](a: Future[X]) = a 15 | val r: js.Promise[Int] = method(js.Promise.resolve[Int](1).$cnv/*.[Future[Int]]*/).$cnv 16 | r.toFuture.map(_ mustBe 1) 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/main/scala/BuildInfo.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts 2 | 3 | import java.util.Properties 4 | 5 | import sbt.internal.util.MessageOnlyException 6 | 7 | object BuildInfo { 8 | def version: String = props.getProperty("version") 9 | 10 | private lazy val props: Properties = { 11 | val props = new Properties() 12 | val path = "scala-ts.properties" 13 | val classloader = this.getClass.getClassLoader 14 | Option(classloader.getResourceAsStream(path)) match { 15 | case Some(stream) => props.load(stream) 16 | case None => throw new MessageOnlyException(s"can not determine ScalaTsPlugin version; missing resource: $path") 17 | } 18 | props 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/readme.md: -------------------------------------------------------------------------------- 1 | ### Test projects that use the ScalaTsPlugin 2 | 3 | Note: Node must be installed in order to test these projects. 4 | 5 | These projects are stand-alone projects that can be opened in an IDE and worked upon. In addition, each project contains a top-level `test` script file that configures a sequence of steps that is executed by the `scripted` task of the main build (cf. [Testing-sbt-plugins](https://www.scala-sbt.org/1.x/docs/Testing-sbt-plugins.html)). 6 | 7 | The plugin configuration of the `ScalaTsPlugin` in these projects is slightly complicated. The version number of the `ScalaTsPlugin` to use should match the version number of the current source state. The plugin configuration of the `ScalaTsPlugin` in `project/plugins.sbt` must distinguish two cases: 8 | * The project is tested by the `scripted` task: In this case, project files are copied into a temporary folder and no version can be derived from the current source state. The version number to use is specified by the `plugin.version` system property that is specified when running the `scripted` task. 9 | * The project is worked upon manually: In this case, the plugin version number is derived from the current source state. The derivation is done with the help of the [dynver](https://github.com/sbt/sbt-dynver) plugin. This plugin must be activated in `project/project/plugin.sbt` files in order to have the git version information available when configuring the `ScalaTsPlugin`. 10 | 11 | Projects that are cross built for different Scala versions output their generated node module in the cross target folders. Tests written in TypeScript use [NPM workspaces](https://docs.npmjs.com/cli/v7/using-npm/workspaces) corresponding to these Scala versions. Test specification code is shared between workspaces (using symlinks) and access to corresponding generated node module is given by a relative import of the `../mod/scala-ts-mod`. -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/build.sbt: -------------------------------------------------------------------------------- 1 | import scala.sys.process.Process 2 | 3 | val scala212 = "2.12.18" 4 | val scala213 = "2.13.11" 5 | val scala3 = "3.4.0-RC1-bin-SNAPSHOT" // "3.3.0" 6 | //val scala3 = "3.3.0" 7 | 8 | val scalaVersions = List(scala213, scala212) // TODO: Scala 3 not (yet) working 9 | 10 | ThisBuild / scalaVersion := scala213 11 | 12 | val npmInstall = taskKey[Unit]("Execute the 'npm install' command") 13 | 14 | lazy val shared = 15 | crossProject(JSPlatform, JVMPlatform) 16 | .crossType(CrossType.Pure) 17 | .settings( 18 | crossScalaVersions := scalaVersions, 19 | // add annotations dependency 20 | ScalaTsPlugin.crossProject.settings 21 | ) 22 | .jvmSettings( 23 | libraryDependencies += "org.scala-js" %% "scalajs-stubs" % "1.0.0" % "provided", 24 | ) 25 | .jsSettings( 26 | // adds semantic db settings 27 | ScalaTsPlugin.crossProject.jsSettings 28 | ) 29 | 30 | lazy val client = 31 | project 32 | .enablePlugins(ScalaTsPlugin) 33 | .dependsOn(shared.js) 34 | .settings( 35 | crossScalaVersions := scalaVersions, 36 | name := "adapter-cross", 37 | organization := "eu.swdev", 38 | scalaTsModuleName := { 39 | val scalaMajorMinor = CrossVersion.partialVersion(scalaVersion.value).map(t => s"${t._1}.${t._2}").get 40 | s"scala-$scalaMajorMinor-ts-mod" 41 | }, 42 | scalaTsValidate := true, 43 | scalaTsAdapterEnabled := true, 44 | (fastOptJS / crossTarget) := (Compile / crossTarget).value / "node_module", 45 | (fullOptJS / crossTarget) := (Compile / crossTarget).value / "node_module", 46 | //scalaTsChangeForkOptions := withDebugForkOptions(5005), 47 | npmInstall := Def 48 | .task { 49 | val scalaMajorMinor = CrossVersion.partialVersion(scalaVersion.value).map(t => s"${t._1}.${t._2}").get 50 | val cmd = Seq("npm", "i", "-w", s"ws-scala-$scalaMajorMinor") 51 | val r = ( 52 | Process(cmd, baseDirectory.value) ! 53 | ) 54 | val log = streams.value.log 55 | if (r != 0) { 56 | log.warn(s"Exit code of command '${cmd.mkString(" ")}' was non zero; maybe the error can be ignored - exitCode: $r") 57 | } 58 | baseDirectory.value 59 | } 60 | .dependsOn(scalaTsFastOpt) 61 | .value, 62 | test := Def 63 | .task { 64 | val scalaMajorMinor = CrossVersion.partialVersion(scalaVersion.value).map(t => s"${t._1}.${t._2}").get 65 | val r = ( 66 | Process(Seq("npm", "t", "-w", s"ws-scala-$scalaMajorMinor"), baseDirectory.value) ! 67 | ) 68 | if (r != 0) { 69 | throw new MessageOnlyException("e2e tests failed") 70 | } 71 | } 72 | .dependsOn(npmInstall) 73 | .value, 74 | cleanFiles += baseDirectory.value / "node_modules", 75 | cleanFiles ++= { 76 | val scalaMajorMinor = CrossVersion.partialVersion(scalaVersion.value).map(t => s"${t._1}.${t._2}").get 77 | val workspaceDir = baseDirectory.value / "src" / "test" / "ts" / s"ws-scala-$scalaMajorMinor" 78 | Seq(workspaceDir / "node_modules", workspaceDir / "dist") 79 | } 80 | ) 81 | 82 | lazy val root = project 83 | .in(file(".")) 84 | .aggregate(client, shared.js, shared.jvm) 85 | .settings( 86 | name := "adapter-cross", 87 | crossScalaVersions := Nil, 88 | // crossScalaVersions := scalaVersions, 89 | publish := {}, 90 | publishLocal := {}, 91 | ) 92 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-app", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "workspaces": [ "src/test/ts/ws-*" ], 7 | "scripts": { 8 | "clean": "rm -rf node_modules" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "type": "module" 13 | } 14 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/client/src/test/ts/spec/date-adaption.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('date access', function () { 4 | 5 | // class adapter 6 | const da = m.Adapter.t.DateAdaption 7 | 8 | it('as JavaScript date', function () { 9 | const d = new Date() 10 | da.date = d 11 | expect(da.date).toStrictEqual(d) 12 | }) 13 | 14 | it('as number', function () { 15 | const d = new Date().getTime() 16 | da.doubleDate = d 17 | expect(da.doubleDate).toBe(d) 18 | }) 19 | 20 | }) -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/client/src/test/ts/spec/nested-class.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | import { newAdapter } from './util' 3 | 4 | describe('nested class', function () { 5 | 6 | // class adapter 7 | const ca = m.Adapter.o.OuterClass 8 | 9 | it('two step construction', function () { 10 | const dOuter = ca.newDelegate(5) 11 | const aOuter = ca.newAdapter(dOuter) 12 | expect(aOuter.x).toBe(5) 13 | const dInner = aOuter.Inner.newDelegate('abc') 14 | const aInner = aOuter.Inner.newAdapter(dInner) 15 | expect(aInner.y).toBe('abc') 16 | }) 17 | 18 | it('combined construction', () => { 19 | const outer = newAdapter(ca, 1) 20 | expect(outer.x).toBe(1) 21 | const inner = newAdapter(outer.Inner, 'uvw') 22 | expect(inner.y).toBe('uvw') 23 | }) 24 | 25 | }) -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/client/src/test/ts/spec/package-object.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | import { newAdapter } from './util' 3 | 4 | describe('package object', function () { 5 | 6 | it('access method from package object', function () { 7 | expect(m.Adapter.eu.swdev.scala.ts.adapter.test.min([7, 6, 8])).toBe(6) 8 | }) 9 | 10 | }) -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/client/src/test/ts/spec/simple-class.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | import { newAdapter } from './util' 3 | 4 | describe('simple class', function () { 5 | 6 | // class adapter 7 | const sca = m.Adapter.x.y.SimpleClass 8 | 9 | it('access constructor var', function () { 10 | const d = sca.newDelegate([1, 2, 3]) 11 | const a = sca.newAdapter(d) 12 | expect(a.x).toStrictEqual([1, 2, 3]) 13 | expect(a.sum).toBe(6) 14 | a.x = [4, 5, 6] 15 | expect(a.x).toStrictEqual([4, 5, 6]) 16 | expect(a.sum).toBe(15) 17 | a.filter(n => n % 2 === 0) 18 | expect(a.sum).toBe(10) 19 | }) 20 | 21 | it('combine instance creation and adaption', () => { 22 | const c = newAdapter(sca, [1, 2, 3, 4, 5]) 23 | expect(c.sum).toBe(15) 24 | }) 25 | 26 | it('acceess method in companion object', () => { 27 | const d = sca.fromInt(7) 28 | const a = sca.newAdapter(d) 29 | expect(a.sum).toBe(7) 30 | }) 31 | 32 | }) -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/client/src/test/ts/spec/util.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('util', function() { 4 | 5 | it('sequence list of options', function() { 6 | expect(m.Adapter.x.Util.sequence([1, 2])).toStrictEqual([1, 2]) 7 | expect(m.Adapter.x.Util.sequence([1, undefined])).toBeUndefined 8 | expect(m.Adapter.x.Util.sequence([undefined, 2])).toBeUndefined 9 | expect(m.Adapter.x.Util.sequence([undefined, undefined])).toBeUndefined 10 | }) 11 | 12 | }) -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/client/src/test/ts/spec/util.ts: -------------------------------------------------------------------------------- 1 | // combine delegate and adapter creation 2 | export function newAdapter( 3 | a: { newDelegate: (...args: ARGS) => DELEGATE, newAdapter: (d: DELEGATE) => ADAPTER }, 4 | ...args: ARGS 5 | ): ADAPTER { 6 | return a.newAdapter(a.newDelegate(...args)) 7 | } 8 | 9 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/client/src/test/ts/ws-scala-2.12/mod/scala-ts-mod.ts: -------------------------------------------------------------------------------- 1 | export * from 'scala-2.12-ts-mod' 2 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/client/src/test/ts/ws-scala-2.12/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ws-scala-2.12", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "tsc && node --experimental-vm-modules ../../../../node_modules/jest/bin/jest" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "js-joda": "^1.11.0" 13 | }, 14 | "comment": "scala-ts-mod is configured as a devDependecy -> cf. comment of externalNpm in build.sbt", 15 | "devDependencies": { 16 | "@types/jest": "^29.5.3", 17 | "@types/node": "^16.11.7", 18 | "jest": "^29.6.2", 19 | "jest-environment-node": "^29.6.2", 20 | "scala-2.12-ts-mod": "file:./../../../../target/scala-2.12/node_module", 21 | "typescript": "^5.1.6" 22 | }, 23 | "type": "module" 24 | } 25 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/client/src/test/ts/ws-scala-2.12/spec: -------------------------------------------------------------------------------- 1 | ../spec -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/client/src/test/ts/ws-scala-2.12/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": [ 4 | "spec/*", 5 | "mod/*" 6 | ], 7 | "compilerOptions": { 8 | "outDir": "./dist" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/client/src/test/ts/ws-scala-2.13/mod/scala-ts-mod.ts: -------------------------------------------------------------------------------- 1 | export * from 'scala-2.13-ts-mod' 2 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/client/src/test/ts/ws-scala-2.13/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ws-scala-2.13", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "tsc && node --experimental-vm-modules ../../../../node_modules/jest/bin/jest" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "js-joda": "^1.11.0" 13 | }, 14 | "comment": "scala-ts-mod is configured as a devDependecy -> cf. comment of externalNpm in build.sbt", 15 | "devDependencies": { 16 | "@types/jest": "^29.5.3", 17 | "@types/node": "^16.11.7", 18 | "jest": "^29.6.2", 19 | "jest-environment-node": "^29.6.2", 20 | "scala-2.13-ts-mod": "file:../../../../target/scala-2.13/node_module", 21 | "typescript": "^5.1.6" 22 | }, 23 | "type": "module" 24 | } 25 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/client/src/test/ts/ws-scala-2.13/spec: -------------------------------------------------------------------------------- 1 | ../spec -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/client/src/test/ts/ws-scala-2.13/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": [ 4 | "spec/*", 5 | "mod/*" 6 | ], 7 | "compilerOptions": { 8 | "outDir": "./dist" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.9.3 2 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | import sbt.Defaults.sbtPluginExtra 2 | 3 | // complicated way of adding the scala-ts plugin 4 | // -> the pluginVersion is derived from the git based version using the dynver plugin 5 | // -> the logic corresponds to: addSbtPlugin("io.github.swachter" % "sbt-scala-ts" % pluginVersion) 6 | libraryDependencies += { 7 | val sbtV = (pluginCrossBuild / sbtBinaryVersion).value 8 | val scalaV = (update / scalaBinaryVersion).value 9 | val Version = """(\d+(?:\.\d+)*).*""".r 10 | val pluginVersion = sys.props.get("plugin.version").getOrElse(version.value) match { 11 | case Version(v) if isSnapshot.value => s"$v-SNAPSHOT" 12 | case v => v 13 | } 14 | val dependency = "io.github.swachter" % "sbt-scala-ts" % pluginVersion 15 | sbtPluginExtra(dependency, sbtV, scalaV) 16 | } 17 | 18 | addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.0.0") -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/project/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.0.1") 2 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/readme.md: -------------------------------------------------------------------------------- 1 | ### End-2-End of Adapter Generation 2 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/shared/src/main/scala/DateAdaption.scala: -------------------------------------------------------------------------------- 1 | package t 2 | 3 | import java.util.Date 4 | 5 | import eu.swdev.scala.ts.annotation.Adapt 6 | 7 | object DateAdaption { 8 | 9 | @Adapt 10 | var date: Date = new Date() 11 | 12 | @Adapt("Double") 13 | var doubleDate: Date = new Date() 14 | 15 | } 16 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/shared/src/main/scala/OuterClass.scala: -------------------------------------------------------------------------------- 1 | package o 2 | 3 | import eu.swdev.scala.ts.annotation.AdaptAll 4 | 5 | /* adapter: 6 | 7 | import scala.scalajs.js 8 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 9 | import eu.swdev.scala.ts.adapter._ 10 | @JSExportAll 11 | trait InstanceAdapter[D] { 12 | val $delegate: D 13 | } 14 | @JSExportTopLevel("Adapter") 15 | object Adapter extends js.Object { 16 | object o extends js.Object { 17 | @JSExportAll 18 | trait OuterClass extends InstanceAdapter[_root_.o.OuterClass] { 19 | def x = $delegate.x.$res 20 | @JSExportAll 21 | trait Inner extends InstanceAdapter[_root_.o.OuterClass#Inner] { 22 | def y = $delegate.y.$res 23 | } 24 | object nner extends js.Object { 25 | def newAdapter(delegate: $delegate.Inner): Inner = new Inner { 26 | override val $delegate = delegate 27 | } 28 | def newDelegate(y: String) = new $delegate.Inner(y.$cnv[String]) 29 | } 30 | } 31 | object OuterClass extends js.Object { 32 | def newAdapter(delegate: _root_.o.OuterClass): OuterClass = new OuterClass { 33 | override val $delegate = delegate 34 | } 35 | def newDelegate(x: Int) = new _root_.o.OuterClass(x.$cnv[Int]) 36 | } 37 | } 38 | } 39 | 40 | */ 41 | @AdaptAll 42 | class OuterClass(val x: Int) { 43 | @AdaptAll 44 | class Inner(val y: String) 45 | } 46 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/shared/src/main/scala/SimpleClass.scala: -------------------------------------------------------------------------------- 1 | package x.y 2 | 3 | import eu.swdev.scala.ts.annotation.{Adapt, AdaptAll} 4 | 5 | @AdaptAll 6 | class SimpleClass(var x: Array[Int]) { 7 | 8 | def sum = x.sum 9 | 10 | def filter(p: Int => Boolean) = x = x.filter(p) 11 | 12 | } 13 | 14 | object SimpleClass { 15 | 16 | @Adapt 17 | def fromInt(int: Int) = new SimpleClass(Array(int)) 18 | } 19 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/shared/src/main/scala/Util.scala: -------------------------------------------------------------------------------- 1 | package x 2 | 3 | import eu.swdev.scala.ts.annotation._ 4 | 5 | object Util { 6 | 7 | @Adapt("js.UndefOr[js.Array[X]]") 8 | def sequence[X](ol: List[Option[X]]): Option[List[X]] = ol.foldRight(Option(List.empty[X]))((o, a) => a.flatMap(l => o.map(_ :: l))) 9 | 10 | } 11 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/shared/src/main/scala/eu/swdev/scala/ts/adapter/test/package.scala: -------------------------------------------------------------------------------- 1 | package eu.swdev.scala.ts.adapter 2 | 3 | import eu.swdev.scala.ts.annotation.Adapt 4 | 5 | package object test { 6 | 7 | @Adapt 8 | def min(list: List[Double]): Double = list.min 9 | 10 | } 11 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/adapter/test: -------------------------------------------------------------------------------- 1 | > +test 2 | # $ pause 3 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/build.sbt: -------------------------------------------------------------------------------- 1 | import sbt.KeyRanks.APlusTask 2 | import scala.jdk.CollectionConverters._ 3 | import scala.sys.process.Process 4 | 5 | val scala212 = "2.12.18" 6 | val scala213 = "2.13.11" 7 | val scala3 = "3.4.0-RC1-bin-SNAPSHOT" // "3.3.0" 8 | //val scala3 = "3.3.0" 9 | 10 | val scalaVersions = List(scala213, scala212) // TODO: Scala 3 not (yet) working 11 | 12 | val npmInstall = taskKey[Unit]("Install npm packages.") 13 | 14 | ThisBuild / scalaVersion := scala213 15 | 16 | scalaTsFastOpt / logLevel := Level.Info 17 | 18 | lazy val root = (project in file(".")) 19 | .enablePlugins(ScalaTsPlugin, ScalablyTypedConverterExternalNpmPlugin) 20 | .settings( 21 | crossScalaVersions := scalaVersions, 22 | version := "0.0.1-SNAPSHOT", 23 | name := "dts-cross", 24 | organization := "eu.swdev", 25 | scalaTsModuleName := { 26 | val scalaMajorMinor = CrossVersion.partialVersion(scalaVersion.value).map(t => s"${t._1}.${t._2}").get 27 | s"scala-$scalaMajorMinor-ts-mod" 28 | }, 29 | scalaTsValidate := true, 30 | // enable adapter in order to include scala-ts-runtime library 31 | scalaTsAdapterEnabled := true, 32 | (fastOptJS / crossTarget) := (Compile / crossTarget).value / "node_module", 33 | (fullOptJS / crossTarget) := (Compile / crossTarget).value / "node_module", 34 | // scalaTsChangeForkOptions := withDebugForkOptions(5005), 35 | // the externalNpm task is executed by the ScalablyTypedConverterExternalNpmPlugin before the scala-ts module is generated 36 | // -> install dependencies; cf. https://scalablytyped.org/docs/plugin-no-bundler 37 | externalNpm := { 38 | val scalaMajorMinor = CrossVersion.partialVersion(scalaVersion.value).map(t => s"${t._1}.${t._2}").get 39 | val r = ( 40 | Process("npm" :: "i" :: "-w" :: s"ws-scala-$scalaMajorMinor" :: "--omit=dev" :: Nil, 41 | baseDirectory.value, 42 | /* "PATH" -> System.getenv("PATH") */ ) ! 43 | ) 44 | if (r != 0) { 45 | throw new MessageOnlyException("Could not install nondev dependencies") 46 | } 47 | baseDirectory.value 48 | }, 49 | npmInstall := Def 50 | .task { 51 | val scalaMajorMinor = CrossVersion.partialVersion(scalaVersion.value).map(t => s"${t._1}.${t._2}").get 52 | val cmd = Seq("npm", "i", "-w", s"ws-scala-$scalaMajorMinor") 53 | val r = ( 54 | Process(cmd, baseDirectory.value) ! 55 | ) 56 | val log = streams.value.log 57 | if (r != 0) { 58 | log.warn(s"Exit code of command '${cmd.mkString(" ")}' was non zero; maybe the error can be ignored - exitCode: $r") 59 | } 60 | baseDirectory.value 61 | } 62 | .dependsOn(scalaTsFastOpt) 63 | .value, 64 | test := Def 65 | .task { 66 | val scalaMajorMinor = CrossVersion.partialVersion(scalaVersion.value).map(t => s"${t._1}.${t._2}").get 67 | val r = ( 68 | Process(Seq("npm", "t", "-w", s"ws-scala-$scalaMajorMinor"), baseDirectory.value) ! 69 | ) 70 | if (r != 0) { 71 | throw new MessageOnlyException("e2e tests failed") 72 | } 73 | } 74 | .dependsOn(npmInstall) 75 | .value, 76 | cleanFiles += baseDirectory.value / "node_modules", 77 | cleanFiles ++= { 78 | val scalaMajorMinor = CrossVersion.partialVersion(scalaVersion.value).map(t => s"${t._1}.${t._2}").get 79 | val workspaceDir = baseDirectory.value / "src" / "test" / "ts" / s"ws-scala-$scalaMajorMinor" 80 | Seq(workspaceDir / "node_modules", workspaceDir / "dist") 81 | } 82 | // scalaTsChangeForkOptions := withDebugForkOptions(5005) 83 | ) 84 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-app", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "workspaces": [ "src/test/ts/ws-*" ], 7 | "scripts": { 8 | "clean": "rm -rf node_modules" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "---": "the js-joda dependency is added here because the scalablytyped plugin process package.json and adds a js-joda dependency to the ScalaJS project", 13 | "dependencies": { 14 | "js-joda": "^1.11.0" 15 | }, 16 | "type": "module" 17 | } 18 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.9.3 2 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | import sbt.Defaults.sbtPluginExtra 2 | 3 | // the ScalaTs plugin and the ScalablyTyped plugin both transitively depend on the ScalaJS plugin 4 | // -> set the necessary version here to overrule their version (TODO: validate that this is the correct way) 5 | addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.1.1") 6 | 7 | // complicated way of adding the scala-ts plugin 8 | // -> the pluginVersion is derived from the git based version using the dynver plugin 9 | // -> the logic corresponds to: addSbtPlugin("io.github.swachter" % "sbt-scala-ts" % pluginVersion) 10 | libraryDependencies += { 11 | val sbtV = (pluginCrossBuild / sbtBinaryVersion).value 12 | val scalaV = (update / scalaBinaryVersion).value 13 | val Version = """(\d+(?:\.\d+)*).*""".r 14 | val pluginVersion = sys.props.get("plugin.version").getOrElse(version.value) match { 15 | case Version(v) if isSnapshot.value => s"$v-SNAPSHOT" 16 | case v => v 17 | } 18 | val dependency = "io.github.swachter" % "sbt-scala-ts" % pluginVersion 19 | sbtPluginExtra(dependency, sbtV, scalaV) 20 | } 21 | 22 | addSbtPlugin("org.scalablytyped.converter" % "sbt-converter" % "1.0.0-beta42") 23 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/project/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.0.1") 2 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/readme.md: -------------------------------------------------------------------------------- 1 | ### End-2-End of TypeScript Declaration File Generation 2 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/main/scala-2.13/e2e/AdtTest.scala: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 4 | 5 | object SimpleAdt { 6 | 7 | sealed trait Adt 8 | 9 | @JSExportTopLevel("SimpleAdtCase1") 10 | @JSExportAll 11 | case class Case1(int: Int) extends Adt { 12 | val tpe: "i" = "i" 13 | } 14 | @JSExportTopLevel("SimpleAdtCase2") 15 | @JSExportAll 16 | case class Case2(str: String) extends Adt { 17 | val tpe: "s" = "s" 18 | } 19 | } 20 | 21 | object ObjectAdt { 22 | 23 | sealed trait Adt 24 | 25 | @JSExportTopLevel("ObjectAdtCase1") 26 | @JSExportAll 27 | object Case1 extends Adt { 28 | val tpe: 1 = 1 29 | val str = "abc" 30 | } 31 | 32 | @JSExportTopLevel("ObjectAdtCase2") 33 | @JSExportAll 34 | object Case2 extends Adt { 35 | val tpe: 2 = 2 36 | val num = 555 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/main/scala-2.13/e2e/FunctionTest.scala: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import scala.scalajs.js 4 | import scala.scalajs.js.annotation.JSExportTopLevel 5 | 6 | object FunctionTest { 7 | @JSExportTopLevel("fun0") 8 | def fun0[R](f: js.Function0[R]): R = f() 9 | @JSExportTopLevel("fun1") 10 | def fun1[T1, R](a: js.Array[T1], f: js.Function1[T1, js.Array[R]]): js.Array[R] = a.flatMap(f) 11 | @JSExportTopLevel("fun2") 12 | def fun2[T1, T2, R](a1: js.Array[T1], a2: js.Array[T2], f: js.Function2[T1, T2, R]): js.Array[R] = a1.zip(a2).map(f.tupled) 13 | } 14 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/main/scala/e2e/Abstract.scala: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import scala.scalajs.js 4 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 5 | 6 | /* .d.ts: 7 | 8 | 9 | */ 10 | 11 | object Abstract { 12 | 13 | // abstract classes can not be exported at the moment: https://github.com/scala-js/scala-js/issues/4117 14 | 15 | /* 16 | @JSExportTopLevel("AbstractBase") 17 | abstract class Base(val length: Int) extends js.Object { 18 | def area(): Double 19 | def color: String 20 | val dimensions: Int 21 | var name: String 22 | } 23 | 24 | @JSExportTopLevel("Square") 25 | class Square(length: Int) extends Base(length) { 26 | override def area(): Double = length * length 27 | override def color: String = "red" 28 | override val dimensions: Int = 2 29 | override var name: String = "square" 30 | } 31 | */ 32 | 33 | } 34 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/main/scala/e2e/Adapter1.scala: -------------------------------------------------------------------------------- 1 | import scala.scalajs.js 2 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 3 | import eu.swdev.scala.ts.adapter._ 4 | 5 | package x { 6 | package y { 7 | class SomeClass(val array: Array[Int]) { 8 | def sum: Int = array.sum 9 | } 10 | object SomeClass { 11 | def upper(s: String) = s.toUpperCase 12 | val x = 5 13 | var y = "abc" 14 | } 15 | } 16 | } 17 | 18 | @JSExportTopLevel("Adapter1") 19 | object Adapter1 extends js.Object { 20 | 21 | @JSExportAll 22 | trait InstanceAdapter[D] { 23 | val $delegate: D 24 | } 25 | 26 | object x extends js.Object { 27 | object y extends js.Object { 28 | @JSExportAll 29 | trait SomeClass extends InstanceAdapter[_root_.x.y.SomeClass] { 30 | def array = $delegate.array.$cnv[js.Array[Int]] 31 | def sum = $delegate.sum.$cnv[Int] 32 | } 33 | object SomeClass extends js.Object { 34 | def newInstance(array: js.Array[Int]) = new _root_.x.y.SomeClass(array.$cnv[Array[Int]]) 35 | def newAdapter(delegate: _root_.x.y.SomeClass) = new SomeClass { 36 | override val $delegate = delegate 37 | } 38 | // access object def 39 | def upper(s: String): String = _root_.x.y.SomeClass.upper(s).$cnv[String] 40 | // access object val 41 | def x = _root_.x.y.SomeClass.x.$cnv[Int] 42 | // access object var 43 | def y = _root_.x.y.SomeClass.y.$cnv[String] 44 | def y_=(v: String) = _root_.x.y.SomeClass.y = v.$cnv[String] 45 | } 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/main/scala/e2e/AdapterWithInnerClass.scala: -------------------------------------------------------------------------------- 1 | import scala.scalajs.js 2 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 3 | import eu.swdev.scala.ts.adapter._ 4 | 5 | package x { 6 | package y { 7 | case class Outer(val x: Int) { 8 | def outerMethod() = 2 * x 9 | case class Inner(val y: String) { 10 | def innerMethod() = y.reverse 11 | } 12 | } 13 | } 14 | } 15 | 16 | @JSExportTopLevel("AdapterWithInnerClass") 17 | object AdapterWithInnerClass extends js.Object { 18 | @JSExportAll 19 | trait InstanceAdapter[D] { 20 | val $delegate: D 21 | } 22 | 23 | object x extends js.Object { 24 | 25 | object y extends js.Object { 26 | object Outer extends js.Object { 27 | def newInstance(x: Int) = new _root_.x.y.Outer(x) 28 | def newAdapter(d: _root_.x.y.Outer) = new Outer { 29 | override val $delegate = d 30 | } 31 | } 32 | @JSExportAll 33 | trait Outer extends InstanceAdapter[_root_.x.y.Outer] { 34 | def outerMethod() = $delegate.outerMethod() 35 | object Inner { 36 | def newInstance(y: String) = new $delegate.Inner(y) 37 | def newAdapter(d: $delegate.Inner) = new Inner { 38 | override val $delegate = d 39 | } 40 | 41 | } 42 | @JSExportAll 43 | trait Inner extends InstanceAdapter[$delegate.Inner] { 44 | def innerMethod() = $delegate.innerMethod() 45 | } 46 | } 47 | } 48 | 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/main/scala/e2e/BigIntInterop.scala: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import scala.scalajs.js 4 | import scala.scalajs.js.annotation.JSExportTopLevel 5 | 6 | @JSExportTopLevel("BigIntInterop") 7 | object BigIntInterop extends js.Object { 8 | 9 | def string2BigInt(str: String): js.BigInt = js.BigInt(str) 10 | 11 | def bigInt2String(bigInt: js.BigInt): String = bigInt.toString() 12 | 13 | } 14 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/main/scala/e2e/BracketNotation.scala: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import scala.scalajs.js 4 | import scala.scalajs.js.annotation.{JSExportTopLevel, JSName} 5 | 6 | @JSExportTopLevel("BracketNotation") 7 | object BracketNotation extends js.Object { 8 | 9 | @JSName("!a") 10 | val a = 1 11 | 12 | @JSName("!b") 13 | var b = 1 14 | 15 | @JSName("!c") 16 | def c() = 1 17 | 18 | @JSName("!d") 19 | def d(n: Int) = n 20 | 21 | @JSName("!e") 22 | object o extends js.Object { 23 | @JSName("!f") 24 | val x = 1 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/main/scala/e2e/ClassWithStatics.scala: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import scala.scalajs.js 4 | import scala.scalajs.js.annotation.{JSExportStatic, JSExportTopLevel} 5 | 6 | /* .d.ts: 7 | 8 | export class ClassWitStatics { 9 | static twice(x: number): number 10 | static readonly str: string 11 | static numero: number 12 | static get x(): number 13 | static set x(i: number) 14 | constructor() 15 | } 16 | 17 | */ 18 | 19 | @JSExportTopLevel("ClassWitStatics") 20 | class ClassWitStatics extends js.Object 21 | 22 | object ClassWitStatics { 23 | 24 | @JSExportStatic 25 | def twice(x: Int) = 2 * x 26 | @JSExportStatic 27 | val str = "abc" 28 | @JSExportStatic("numero") 29 | var num = 55 30 | @JSExportStatic 31 | def x = _x 32 | @JSExportStatic 33 | def x_=(i: Int) = _x = i 34 | 35 | var _x = 0 36 | 37 | } 38 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/main/scala/e2e/FromToRange.scala: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import scala.scalajs.js 4 | import scala.scalajs.js.annotation.{JSExportTopLevel, JSName} 5 | import scala.scalajs.js.JSConverters._ 6 | 7 | @JSExportTopLevel("FromToRange") 8 | class FromToRange(from: Int, to: Int) extends js.Object { 9 | 10 | @JSName(js.Symbol.iterator) 11 | def iterator(): js.Iterator[Int] = (from to to).iterator.toJSIterator 12 | } 13 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/main/scala/e2e/Outer.scala: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import scala.scalajs.js 4 | import scala.scalajs.js.annotation.JSExportTopLevel 5 | 6 | @JSExportTopLevel("OuterClass") 7 | class Outer extends js.Object { 8 | object mid extends js.Object { 9 | // object innerMost1 extends js.Object { 10 | var x = 1 11 | // } 12 | } 13 | } 14 | 15 | @JSExportTopLevel("OuterObject") 16 | object Outer extends js.Object { 17 | object middle extends js.Object { 18 | object innerMost extends js.Object { 19 | var x = 1 20 | } 21 | } 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/main/scala/e2e/TraitInheritance1.scala: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel} 4 | 5 | /* .d.ts: 6 | 7 | export interface ClassWithInheritedMethods1 extends e2e.TraitInheritance1.Middle { 8 | 'ClassWithInheritedMethods1': never 9 | } 10 | export class ClassWithInheritedMethods1 { 11 | constructor() 12 | } 13 | export namespace e2e { 14 | namespace TraitInheritance1 { 15 | interface Base { 16 | base(n: number): number 17 | 'e2e.TraitInheritance1.Base': never 18 | } 19 | interface Middle extends e2e.TraitInheritance1.Base { 20 | middle(n: number): number 21 | 'e2e.TraitInheritance1.Middle': never 22 | } 23 | } 24 | } 25 | import _root_e2e = e2e 26 | 27 | */ 28 | 29 | object TraitInheritance1 { 30 | @JSExportAll 31 | trait Base { 32 | def base(n: Int) = 2*n 33 | } 34 | 35 | @JSExportAll 36 | trait Middle extends Base { 37 | def middle(n: Int) = 3*n 38 | } 39 | 40 | @JSExportTopLevel("ClassWithInheritedMethods1") 41 | class Cls extends Middle 42 | 43 | } 44 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/main/scala/e2e/TraitInheritance2.scala: -------------------------------------------------------------------------------- 1 | package e2e 2 | 3 | import scala.scalajs.js 4 | import scala.scalajs.js.annotation.JSExportTopLevel 5 | 6 | /* .d.ts: 7 | 8 | export interface ClassWithInheritedMethods2 extends e2e.TraitInheritance2.Middle { 9 | 'ClassWithInheritedMethods2': never 10 | } 11 | export class ClassWithInheritedMethods2 { 12 | constructor() 13 | middle(n: number): number 14 | base(n: number): number 15 | } 16 | export namespace e2e { 17 | namespace TraitInheritance2 { 18 | interface Base { 19 | base(n: number): number 20 | 'e2e.TraitInheritance2.Base': never 21 | } 22 | interface Middle extends e2e.TraitInheritance2.Base { 23 | middle(n: number): number 24 | 'e2e.TraitInheritance2.Middle': never 25 | } 26 | } 27 | } 28 | import _root_e2e = e2e 29 | 30 | */ 31 | 32 | object TraitInheritance2 { 33 | 34 | trait Base extends js.Object { 35 | def base(n: Int): Int 36 | } 37 | 38 | trait Middle extends Base { 39 | def middle(n: Int): Int 40 | } 41 | 42 | @JSExportTopLevel("ClassWithInheritedMethods2") 43 | class Cls extends Middle { 44 | override def middle(n: Int): Int = 3*n 45 | override def base(n: Int): Int = 2*n 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/main/scala/e2e/root-package.scala: -------------------------------------------------------------------------------- 1 | import scala.scalajs.js 2 | import scala.scalajs.js.annotation.JSExportTopLevel 3 | 4 | @JSExportTopLevel("RootPackageClass") 5 | class RootPackageClass extends js.Object { 6 | val i = 1 7 | } 8 | 9 | @JSExportTopLevel("RootPackageObject") 10 | object RootPackageObjectTest extends js.Object { 11 | val x = 1 12 | } 13 | 14 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/abstract.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('abstract', function() { 4 | 5 | it('simple', function() { 6 | const c1 = new m.AbstractTestCase1('abc') 7 | expect(c1.x).toBe('abc') 8 | const c2 = new m.AbstractTestCase2(55) 9 | expect(c2.x).toBe(55) 10 | 11 | }) 12 | 13 | }) -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/api-reference.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('api reference', function() { 4 | 5 | it('class-2-class', function() { 6 | expect.assertions(1) 7 | const o = m.convertInput2Output(m.createInput(0)) 8 | if ('i' in o) { 9 | expect(o.i).toBe(0) 10 | } 11 | }); 12 | 13 | it('class-2-class', function() { 14 | expect.assertions(1) 15 | const o = m.convertInput2Output(m.createInput(1)) 16 | if ('s' in o) { 17 | expect(o.s).toBe('abc') 18 | } 19 | }); 20 | 21 | 22 | }); -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/bigint.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('abstract', function() { 4 | 5 | it('simple', function() { 6 | const digits = 30 7 | const s1 = '9'.repeat(digits) 8 | const b1 = m.BigIntInterop.string2BigInt(s1) 9 | const b2 = b1 + 1n 10 | const s2 = m.BigIntInterop.bigInt2String(b2) 11 | const e2 = '1' + '0'.repeat(digits) 12 | expect(s2).toBe(e2) 13 | }) 14 | 15 | }) -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/bracket-notation.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('bracket notation', function() { 4 | 5 | it('simple', function() { 6 | expect(m.BracketNotation['!a']).toBe(1) 7 | expect(m.BracketNotation['!b']).toBe(1) 8 | m.BracketNotation['!b'] += 1 9 | expect(m.BracketNotation['!b']).toBe(2) 10 | expect(m.BracketNotation['!c']()).toBe(1) 11 | expect(m.BracketNotation['!d'](3)).toBe(3) 12 | expect(m.BracketNotation['!e']['!f']).toBe(1) 13 | }) 14 | 15 | }) -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/ctor-param-export.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('ctor param export', function() { 4 | 5 | it('simple', function() { 6 | const c = new m.CtorParamExport('abc', 'uvw') 7 | expect(c.x).toBe('abc') 8 | expect(c.y).toBe('uvw') 9 | }) 10 | 11 | }) -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/date.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('js.Date', function() { 4 | 5 | it('construct', function() { 6 | const d = new Date('2020-06-08') 7 | expect(m.fullYearOfDate(d)).toBe(2020) 8 | }); 9 | 10 | }); -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/dictionary.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('js.dictionary', function() { 4 | 5 | it('construct', function() { 6 | const d = { 'a': 1, 'b': 2, 'c': 3} 7 | expect(m.sumDict(d)).toBe(6) 8 | m.addToDict('d', 4, d) 9 | expect(m.sumDict(d)).toBe(10) 10 | }); 11 | 12 | }); -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/global.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('WeakMap', function() { 4 | 5 | it('construct', function() { 6 | const map = new WeakMap() 7 | const k1 = {} 8 | const k2 = {} 9 | m.setInWeakMap(k1, 'abc', map) 10 | m.setInWeakMap(k2, 'uvw', map) 11 | expect(map.get(k1)).toBe('abc') 12 | expect(map.get(k2)).toBe('uvw') 13 | }); 14 | 15 | }); -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/import.spec.ts: -------------------------------------------------------------------------------- 1 | import * as sm from '../mod/scala-ts-mod' 2 | import j from 'js-joda' 3 | 4 | describe('js-joda', function() { 5 | 6 | it('duration', function() { 7 | const nbDays1 = 1 8 | const ld1 = j.LocalDate.now() 9 | const ld2 = ld1.plusDays(nbDays1) 10 | const diff1 = ld1.until(ld2) 11 | expect(diff1.days()).toBe(nbDays1) 12 | const nbDays2 = 3 13 | const ld3 = sm.addDays(ld1, nbDays2) 14 | const diff2 = ld1.until(ld3) 15 | expect(diff2.days()).toBe(nbDays2) 16 | }); 17 | 18 | }); -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/iterable.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('iterable', function() { 4 | 5 | it('simple', function() { 6 | const range = new m.FromToRange(0, 4) 7 | let s = 0 8 | for (let n of range) { 9 | s += n 10 | } 11 | expect(s).toBe(10) 12 | }) 13 | 14 | }) -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/iterator.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('iterator', function() { 4 | 5 | 6 | it('sum', function() { 7 | expect(m.sumIterable([1, 2, 3, 4])).toBe(10) 8 | }); 9 | 10 | it('create dictionary', function() { 11 | const i = m.numberIterator(1) 12 | let n = i.next() 13 | expect(n.done).toBe(false) 14 | expect(n.value).toBe(0) 15 | n = i.next() 16 | expect(n.done).toBe(false) 17 | expect(n.value).toBe(1) 18 | n = i.next() 19 | expect(n.done).toBe(true) 20 | }); 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/js-class.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('js class', function() { 4 | 5 | it('construct', function() { 6 | const initialStr = 'abc' 7 | const initialNum = 5 8 | const c = new m.JsClass(initialStr, initialNum) 9 | expect(c.initialStr).toBe(initialStr) 10 | expect(c.num).toBe(initialNum) 11 | expect(c.str).toBe(initialStr) 12 | }); 13 | 14 | it('modify', function() { 15 | const initialStr = 'abc' 16 | const initialNum = 5 17 | const c = new m.JsClass(initialStr, initialNum) 18 | const s = initialStr + initialStr 19 | c.str = s 20 | expect(c.str).toBe(s) 21 | c.doubleNum() 22 | expect(c.num).toBe(2 * initialNum) 23 | c.num = initialNum 24 | expect(c.num).toBe(initialNum) 25 | }); 26 | 27 | }); -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/nested-objects.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('nested objects', function() { 4 | 5 | it('object/object/object', function() { 6 | expect(m.OuterObject.middle.innerMost.x).toBe(1) 7 | m.OuterObject.middle.innerMost.x += 1 8 | expect(m.OuterObject.middle.innerMost.x).toBe(2) 9 | }) 10 | 11 | it('class/object', function() { 12 | const c = new m.OuterClass() 13 | expect(c.mid.x).toBe(1) 14 | c.mid.x += 1 15 | expect(c.mid.x).toBe(2) 16 | }) 17 | 18 | }) -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/promise.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('Promise and PromiseLike', function() { 4 | 5 | function promise(t?: T): Promise { 6 | return new Promise((resolve, reject) => { 7 | process.nextTick(() => t ? resolve(t) : reject(t)) 8 | }) 9 | } 10 | 11 | it('map Promise', () => { 12 | expect.assertions(1) 13 | const p = promise(1) 14 | const q = m.mapPromise(p, x => 2*x) 15 | return expect(q).resolves.toBe(2) 16 | }); 17 | 18 | it('map Promise (neg)', () => { 19 | expect.assertions(1) 20 | const p = promise(1) 21 | const q = m.mapPromise(p, x => 2*x) 22 | return expect(q).resolves.not.toBe(3) 23 | }); 24 | 25 | it('map PromiseLike', () => { 26 | expect.assertions(1) 27 | const p = promise(1) 28 | const q = m.mapPromiseLike(p, x => 2*x) 29 | return expect(q).resolves.toBe(2) 30 | }); 31 | 32 | }); -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/regexp.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('js.dictionary', function() { 4 | 5 | it('construct', function() { 6 | const r = m.createRegExp('a+b+') 7 | expect(m.regExpMatches(r, 'ab')).toBeTruthy() 8 | expect(m.regExpMatches(r, 'ac')).toBeFalsy() 9 | }); 10 | 11 | }); -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/root-package.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('root-package', function() { 4 | 5 | it('class', function() { 6 | const c = new m.RootPackageClass() 7 | expect(c.i).toBe(1) 8 | }); 9 | 10 | it('object', function() { 11 | expect(m.RootPackageObject.x).toBe(1) 12 | }); 13 | 14 | }); -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/static.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('static', function() { 4 | 5 | it('simple', function() { 6 | expect(m.ClassWitStatics.twice(2)).toBe(4) 7 | expect(m.ClassWitStatics.str).toBe('abc') 8 | expect(m.ClassWitStatics.numero).toBe(55) 9 | m.ClassWitStatics.numero = 66 10 | expect(m.ClassWitStatics.numero).toBe(66) 11 | expect(m.ClassWitStatics.x).toBe(0) 12 | m.ClassWitStatics.x += 1 13 | expect(m.ClassWitStatics.x).toBe(1) 14 | }) 15 | 16 | }) -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/this-function.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('this function', function() { 4 | 5 | it('listener', function() { 6 | const n = new m.Notifier 7 | const l = new m.Listener 8 | const msg = 'message' 9 | let x: string = '' 10 | n.addListener(l.notifyFunction) 11 | n.addListener((s: string) => x = s) 12 | n.notify(msg) 13 | expect(l.s).toBe(msg) 14 | expect(x).toBe(msg) 15 | }); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/top-level-def-val-var.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('top level', function() { 4 | 5 | it('read val', function() { 6 | expect(m.immutable).toBe(5) 7 | }); 8 | 9 | it('read var', function() { 10 | expect(m.mutable).toBe('abc') 11 | }); 12 | 13 | it('write var', function() { 14 | const oldValue = m.mutable 15 | const newValue = oldValue + oldValue 16 | m.setMutable(newValue) 17 | expect(m.mutable).toBe(newValue) 18 | }); 19 | 20 | it('call function', function() { 21 | expect(m.multiply(2, 3)).toBe(6) 22 | }); 23 | 24 | }); -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/trait-inheritance.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('trait inheritance', function() { 4 | 5 | it('non js.Object', function() { 6 | const c = new m.ClassWithInheritedMethods1() 7 | expect(c.base(1)).toBe(2) 8 | expect(c.middle(2)).toBe(6) 9 | }) 10 | 11 | it('js.Object', function() { 12 | const c = new m.ClassWithInheritedMethods2() 13 | expect(c.base(1)).toBe(2) 14 | expect(c.middle(2)).toBe(6) 15 | }) 16 | 17 | }) -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/tuple.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('tuple', function() { 4 | 5 | it('tuple a function', function() { 6 | const f = (n1: number, n2: number) => n1 + n2 7 | const tf = m.tupleFunction(f) 8 | expect(tf([1, 2])).toBe(3) 9 | }); 10 | 11 | }); -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/type-conversions.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('type conversions in accessors', function() { 4 | 5 | const c = new m.TypeConversions() 6 | 7 | it('set / get array', function() { 8 | const mat = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 9 | 10 | c.matrix = mat 11 | expect(c.matrix).toStrictEqual(mat) 12 | 13 | // c.matrix stored a copy of mat -> changing mat does not change c.matrix 14 | mat[0][0] = 0 15 | expect(c.matrix).not.toStrictEqual(mat) 16 | 17 | // c.matrix returns a copy -> c.matrix itself is not modified 18 | c.matrix[0][0] = 0 19 | expect(c.matrix).not.toStrictEqual(mat) 20 | 21 | }); 22 | 23 | 24 | }); -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/union.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('union', function() { 4 | 5 | function invert(u: m.e2e.UnionTest.U) { 6 | return m.invert(u) 7 | } 8 | 9 | it('simple', function() { 10 | expect(m.invert(1)).toBe(-1) 11 | expect(m.invert('abc')).toBe('cba') 12 | expect(m.invert(true)).toBe(false) 13 | }); 14 | 15 | it('use union type alias', function() { 16 | expect(invert(5)).toBe(-5) 17 | }); 18 | 19 | }); 20 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/spec/varargs.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('varargs', function() { 4 | 5 | 6 | it('sum', function() { 7 | expect(m.sumVarArgs(1, 2, 3, 4)).toBe(10) 8 | }); 9 | 10 | it('create dictionary', function() { 11 | const d = m.createDictionary(['a', 1], ['b', 2], ['c', 3]) 12 | expect(d.a).toBe(1) 13 | expect(d.b).toBe(2) 14 | expect(d.c).toBe(3) 15 | }); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/ws-scala-2.12/mod/scala-ts-mod.ts: -------------------------------------------------------------------------------- 1 | export * from 'scala-2.12-ts-mod' 2 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/ws-scala-2.12/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ws-scala-2.12", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "tsc && node --experimental-vm-modules ../../../../node_modules/jest/bin/jest" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "js-joda": "^1.11.0" 13 | }, 14 | "comment": "scala-ts-mod is configured as a devDependecy -> cf. comment of externalNpm in build.sbt", 15 | "devDependencies": { 16 | "@types/jest": "^29.5.3", 17 | "@types/node": "^16.11.7", 18 | "jest": "^29.6.2", 19 | "jest-environment-node": "^29.6.2", 20 | "scala-2.12-ts-mod": "file:./../../../../target/scala-2.12/node_module", 21 | "typescript": "^5.1.6" 22 | }, 23 | "type": "module" 24 | } 25 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/ws-scala-2.12/spec: -------------------------------------------------------------------------------- 1 | ../spec -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/ws-scala-2.12/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": [ 4 | "spec/*", 5 | "mod/*" 6 | ], 7 | "compilerOptions": { 8 | "outDir": "./dist" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/ws-scala-2.13/mod/scala-ts-mod.ts: -------------------------------------------------------------------------------- 1 | export * from 'scala-2.13-ts-mod' 2 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/ws-scala-2.13/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ws-scala-2.13", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "tsc && node --experimental-vm-modules ../../../../node_modules/jest/bin/jest" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "js-joda": "^1.11.0" 13 | }, 14 | "comment": "scala-ts-mod is configured as a devDependecy -> cf. comment of externalNpm in build.sbt", 15 | "devDependencies": { 16 | "@types/jest": "^29.5.3", 17 | "@types/node": "^16.11.7", 18 | "jest": "^29.6.2", 19 | "jest-environment-node": "^29.6.2", 20 | "scala-2.13-ts-mod": "file:../../../../target/scala-2.13/node_module", 21 | "typescript": "^5.1.6" 22 | }, 23 | "type": "module" 24 | } 25 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/ws-scala-2.13/spec: -------------------------------------------------------------------------------- 1 | ../spec -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/ws-scala-2.13/spec-2.13/function.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | 3 | describe('function', function() { 4 | 5 | it('function0', function() { 6 | expect(m.fun0(() => 'a')).toBe('a') 7 | expect(m.fun0(() => 1)).toBe(1) 8 | }); 9 | 10 | it('function1', function() { 11 | // fun1 is a flatMap 12 | expect(m.fun1([1, 2, 3], n => new Array(n).fill(n))).toStrictEqual([1, 2, 2, 3, 3, 3]) 13 | }); 14 | 15 | it('function2', function() { 16 | // fun2 is a zipMap 17 | expect(m.fun2([1, 2, 3], ['a', 'b', 'c'], (n, s) => s.repeat(n))).toStrictEqual(['a', 'bb', 'ccc']) 18 | }); 19 | 20 | }); -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/ws-scala-2.13/spec-2.13/object-adt.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | import {assertNever} from './util' 3 | 4 | describe('object adt', function() { 5 | 6 | function match(adt: m.e2e.ObjectAdt.Adt$u): string | number { 7 | if (adt.tpe === 1) { 8 | return adt.str 9 | } else if (adt.tpe === 2) { 10 | return adt.num 11 | } else { 12 | return assertNever(adt) 13 | } 14 | } 15 | 16 | it('read val', function() { 17 | expect(match(m.ObjectAdtCase1)).toBe('abc') 18 | expect(match(m.ObjectAdtCase2)).toBe(555) 19 | }); 20 | 21 | }); -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/ws-scala-2.13/spec-2.13/simple-adt.spec.ts: -------------------------------------------------------------------------------- 1 | import * as m from '../mod/scala-ts-mod' 2 | import {assertNever} from './util' 3 | 4 | describe('simple adt', function() { 5 | 6 | function match(adt: m.e2e.SimpleAdt.Adt$u): string | number { 7 | if (adt.tpe === 's') { 8 | return adt.str 9 | } else if (adt.tpe === 'i') { 10 | return adt.int 11 | } else { 12 | return assertNever(adt) 13 | } 14 | } 15 | 16 | it('read val', function() { 17 | expect(match(new m.SimpleAdtCase1(5))).toBe(5) 18 | expect(match(new m.SimpleAdtCase2('x'))).toBe('x') 19 | }); 20 | 21 | }); -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/ws-scala-2.13/spec-2.13/util.ts: -------------------------------------------------------------------------------- 1 | export function assertNever(n: never): never { 2 | throw new Error('never case reached') 3 | } 4 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/src/test/ts/ws-scala-2.13/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": [ 4 | "spec/*", 5 | "spec-2.13/*", 6 | "mod/*" 7 | ], 8 | "compilerOptions": { 9 | "outDir": "./dist" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/dts/test: -------------------------------------------------------------------------------- 1 | > +test 2 | # $ pause 3 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/readme.md: -------------------------------------------------------------------------------- 1 | Projects that are cross built and checked for all supported Scala versions. -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/simple/build.sbt: -------------------------------------------------------------------------------- 1 | import eu.swdev.scala.ts.ScalaTsPlugin 2 | 3 | val scala212 = "2.12.18" 4 | val scala213 = "2.13.11" 5 | val scala3 = "3.4.0-RC1-bin-SNAPSHOT" // "3.3.0" 6 | //val scala3 = "3.3.0" 7 | 8 | val scalaVersions = List(scala3, scala213, scala212) 9 | 10 | ThisBuild / scalaVersion := scala3 11 | 12 | lazy val root = (project in file(".")) 13 | .enablePlugins(ScalaTsPlugin) 14 | .settings( 15 | crossScalaVersions := scalaVersions, 16 | scalaVersion := "2.13.11", 17 | version := "0.1.0", 18 | name := "simple-cross", 19 | scalaTsModuleName := "mod-name", 20 | // scalaTsChangeForkOptions := withDebugForkOptions(5006) 21 | ) 22 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/simple/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.9.3 2 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/simple/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | import sbt.Defaults.sbtPluginExtra 2 | 3 | // complicated way of adding the scala-ts plugin 4 | // -> the pluginVersion is derived from the git based version using the dynver plugin 5 | // -> the logic corresponds to: addSbtPlugin("io.github.swachter" % "sbt-scala-ts" % pluginVersion) 6 | libraryDependencies += { 7 | val sbtV = (pluginCrossBuild / sbtBinaryVersion).value 8 | val scalaV = (update / scalaBinaryVersion).value 9 | val Version = """(\d+(?:\.\d+)*).*""".r 10 | val pluginVersion = sys.props.get("plugin.version").getOrElse(version.value) match { 11 | case Version(v) if isSnapshot.value => s"$v-SNAPSHOT" 12 | case v => v 13 | } 14 | val dependency = "io.github.swachter" % "sbt-scala-ts" % pluginVersion 15 | sbtPluginExtra(dependency, sbtV, scalaV) 16 | } 17 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/simple/project/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.0.1") 2 | -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/simple/src/main/scala/simple/file1.scala: -------------------------------------------------------------------------------- 1 | package simple 2 | 3 | import scala.scalajs.js.annotation.JSExportTopLevel 4 | 5 | @JSExportTopLevel("Simple") 6 | case class Simple(int: Int, string: String, boolean: Boolean, double: Double) -------------------------------------------------------------------------------- /sbt-scala-ts/src/sbt-test/scala-ts/simple/test: -------------------------------------------------------------------------------- 1 | # check if the type mapping file gets created 2 | > +scalaTsFastOpt 3 | $ exists target/scala-2.12/simple-cross-fastopt.d.ts 4 | $ exists target/scala-2.12/package.json 5 | $ exists target/scala-2.12/simple-cross-fastopt.js 6 | $ exists target/scala-2.13/simple-cross-fastopt.d.ts 7 | $ exists target/scala-2.13/package.json 8 | $ exists target/scala-2.13/simple-cross-fastopt.js 9 | $ exists target/scala-3.4.0-RC1-bin-SNAPSHOT/simple-cross-fastopt.d.ts 10 | $ exists target/scala-3.4.0-RC1-bin-SNAPSHOT/package.json 11 | $ exists target/scala-3.4.0-RC1-bin-SNAPSHOT/simple-cross-fastopt.js 12 | # $ pause 13 | --------------------------------------------------------------------------------