Skip to content

Commit

Permalink
Added doctrine facade
Browse files Browse the repository at this point in the history
  • Loading branch information
viktor-podzigun committed Aug 29, 2021
1 parent 1f5386b commit 5c9e905
Show file tree
Hide file tree
Showing 10 changed files with 756 additions and 5 deletions.
111 changes: 111 additions & 0 deletions codegen/src/main/scala/scommons/doctrine/Doctrine.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package scommons.doctrine

import scommons.doctrine.DoctrineType._
import scommons.doctrine.raw.{DoctrineNativeType => NativeType, DoctrineNativeTypeName => TypeName, _}

import scala.scalajs.js
import scala.util.{Failure, Success, Try}

/**
* Doctrine is a JSDoc parser.
*
* @see https://www.npmjs.com/package/doctrine
*/
object Doctrine {

private[doctrine] var native = DoctrineNative

def parse(jsDoc: String): DoctrineAnnotation = {
val res = native.parse(jsDoc)

DoctrineAnnotation(
description = res.description,
tags = res.tags.map { tag =>
val tagErrors = tag.errors.map(_.toList).getOrElse(Nil)
val (maybeType, allErrors) = tag.`type`.toOption match {
case None => (None, tagErrors)
case Some(t) =>
Try(toDoctrineType(t)) match {
case Success(value) => (Some(value), tagErrors)
case Failure(ex) => (None, s"$ex" :: tagErrors)
}
}

DoctrineTag(
title = tag.title,
description = tag.description,
`type` = maybeType,
name = tag.name.toOption,
kind = tag.kind.toOption,
errors = allErrors
)
}.toList
)
}

private[doctrine] def toDoctrineType(t: NativeType): DoctrineType = t.`type` match {
case TypeName.AllLiteral => AllLiteral
case TypeName.ArrayType => new ArrayType(
elements = toTypeList(t.elements)
)
case n@TypeName.FieldType => FieldType(
key = getOrThrow(t.key, s"$n without key"),
value = toTypeOpt(t.value)
)
case n@TypeName.FunctionType => new FunctionType(
`this` = getOrThrow(t.`this`.map(toDoctrineType), s"$n without `this`"),
`new` = getOrThrow(t.`new`.map(toDoctrineType), s"$n without `new`"),
params = toTypeList(t.params),
result = toTypeList(t.result)
)
case n@TypeName.NameExpression => NameExpression(
name = getOrThrow(t.name, s"$n without name")
)
case n@TypeName.NonNullableType => NonNullableType(
prefix = getOrThrow(t.prefix, s"$n without prefix"),
expression = getOrThrow(t.expression.map(toDoctrineType), s"$n without expression")
)
case TypeName.NullableLiteral => NullableLiteral
case n@TypeName.NullableType => NullableType(
prefix = getOrThrow(t.prefix, s"$n without prefix"),
expression = getOrThrow(t.expression.map(toDoctrineType), s"$n without expression")
)
case TypeName.NullLiteral => NullLiteral
case n@TypeName.OptionalType => OptionalType(
expression = getOrThrow(t.expression.map(toDoctrineType), s"$n without expression")
)
case n@TypeName.ParameterType => ParameterType(
name = getOrThrow(t.name, s"$n without name"),
expression = getOrThrow(t.expression.map(toDoctrineType), s"$n without expression")
)
case TypeName.RecordType => RecordType(
fields = toTypeList(t.fields)
)
case TypeName.RestType => RestType(
expression = toTypeOpt(t.expression)
)
case n@TypeName.TypeApplication => TypeApplication(
expression = getOrThrow(t.expression.map(toDoctrineType), s"$n without expression"),
applications = toTypeList(t.applications)
)
case TypeName.UndefinedLiteral => UndefinedLiteral
case TypeName.UnionType => UnionType(
elements = toTypeList(t.elements)
)
case TypeName.VoidLiteral => VoidLiteral
case typeName =>
throw new IllegalStateException(s"Unknown Tag type: $typeName")
}

private def getOrThrow[T](maybeValue: js.UndefOr[T], error: => String): T = {
maybeValue.getOrElse(throw new IllegalStateException(error))
}

private def toTypeList(maybeArray: js.UndefOr[js.Array[NativeType]]): List[DoctrineType] = {
maybeArray.map(_.toList).getOrElse(Nil).map(toDoctrineType)
}

private def toTypeOpt(maybeType: js.UndefOr[NativeType]): Option[DoctrineType] = {
maybeType.map(toDoctrineType).toOption
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package scommons.doctrine

case class DoctrineAnnotation(description: String, tags: List[DoctrineTag])
8 changes: 8 additions & 0 deletions codegen/src/main/scala/scommons/doctrine/DoctrineTag.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package scommons.doctrine

case class DoctrineTag(title: String,
description: String,
`type`: Option[DoctrineType],
name: Option[String],
kind: Option[String],
errors: List[String])
44 changes: 44 additions & 0 deletions codegen/src/main/scala/scommons/doctrine/DoctrineType.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package scommons.doctrine

sealed trait DoctrineType

object DoctrineType {

case object AllLiteral extends DoctrineType

case class ArrayType(elements: List[DoctrineType]) extends DoctrineType

case class FieldType(key: String, value: Option[DoctrineType]) extends DoctrineType

case class FunctionType(`this`: DoctrineType,
`new`: DoctrineType,
params: List[DoctrineType],
result: List[DoctrineType]) extends DoctrineType

case class NameExpression(name: String) extends DoctrineType

case class NonNullableType(prefix: Boolean, expression: DoctrineType) extends DoctrineType

case object NullableLiteral extends DoctrineType

case class NullableType(prefix: Boolean, expression: DoctrineType) extends DoctrineType

case object NullLiteral extends DoctrineType

case class OptionalType(expression: DoctrineType) extends DoctrineType

case class ParameterType(name: String, expression: DoctrineType) extends DoctrineType

case class RecordType(fields: List[DoctrineType]) extends DoctrineType

case class RestType(expression: Option[DoctrineType]) extends DoctrineType

case class TypeApplication(expression: DoctrineType,
applications: List[DoctrineType]) extends DoctrineType

case object UndefinedLiteral extends DoctrineType

case class UnionType(elements: List[DoctrineType]) extends DoctrineType

case object VoidLiteral extends DoctrineType
}
82 changes: 82 additions & 0 deletions codegen/src/main/scala/scommons/doctrine/raw/DoctrineNative.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package scommons.doctrine.raw

import scala.scalajs.js
import scala.scalajs.js.annotation.JSImport

/**
* Doctrine is a JSDoc parser.
*
* @see https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/doctrine/index.d.ts
*/
@js.native
@JSImport("doctrine", JSImport.Default)
object DoctrineNative extends js.Object {

def parse(jsDoc: String): DoctrineNativeAnnotation = js.native
}

@js.native
trait DoctrineNativeAnnotation extends js.Object {

def description: String
def tags: js.Array[DoctrineNativeTag]
}

@js.native
trait DoctrineNativeTag extends js.Object {

def title: String
def description: String
def `type`: js.UndefOr[DoctrineNativeType]
def name: js.UndefOr[String]
def kind: js.UndefOr[String]
def errors: js.UndefOr[js.Array[String]]
}

@js.native
trait DoctrineNativeType extends js.Object {

def `type`: DoctrineNativeTypeName

def elements: js.UndefOr[js.Array[DoctrineNativeType]]

def key: js.UndefOr[String]
def value: js.UndefOr[DoctrineNativeType]

def `this`: js.UndefOr[DoctrineNativeType]
def `new`: js.UndefOr[DoctrineNativeType]
def params: js.UndefOr[js.Array[DoctrineNativeType]]
def result: js.UndefOr[js.Array[DoctrineNativeType]]

def name: js.UndefOr[String]

def prefix: js.UndefOr[Boolean]
def expression: js.UndefOr[DoctrineNativeType]

def fields: js.UndefOr[js.Array[DoctrineNativeType]]
def applications: js.UndefOr[js.Array[DoctrineNativeType]]
}

@js.native
sealed trait DoctrineNativeTypeName extends js.Object

object DoctrineNativeTypeName {

val AllLiteral: DoctrineNativeTypeName = "AllLiteral".asInstanceOf[DoctrineNativeTypeName]
val ArrayType: DoctrineNativeTypeName = "ArrayType".asInstanceOf[DoctrineNativeTypeName]
val FieldType: DoctrineNativeTypeName = "FieldType".asInstanceOf[DoctrineNativeTypeName]
val FunctionType: DoctrineNativeTypeName = "FunctionType".asInstanceOf[DoctrineNativeTypeName]
val NameExpression: DoctrineNativeTypeName = "NameExpression".asInstanceOf[DoctrineNativeTypeName]
val NonNullableType: DoctrineNativeTypeName = "NonNullableType".asInstanceOf[DoctrineNativeTypeName]
val NullableLiteral: DoctrineNativeTypeName = "NullableLiteral".asInstanceOf[DoctrineNativeTypeName]
val NullableType: DoctrineNativeTypeName = "NullableType".asInstanceOf[DoctrineNativeTypeName]
val NullLiteral: DoctrineNativeTypeName = "NullLiteral".asInstanceOf[DoctrineNativeTypeName]
val OptionalType: DoctrineNativeTypeName = "OptionalType".asInstanceOf[DoctrineNativeTypeName]
val ParameterType: DoctrineNativeTypeName = "ParameterType".asInstanceOf[DoctrineNativeTypeName]
val RecordType: DoctrineNativeTypeName = "RecordType".asInstanceOf[DoctrineNativeTypeName]
val RestType: DoctrineNativeTypeName = "RestType".asInstanceOf[DoctrineNativeTypeName]
val TypeApplication: DoctrineNativeTypeName = "TypeApplication".asInstanceOf[DoctrineNativeTypeName]
val UndefinedLiteral: DoctrineNativeTypeName = "UndefinedLiteral".asInstanceOf[DoctrineNativeTypeName]
val UnionType: DoctrineNativeTypeName = "UnionType".asInstanceOf[DoctrineNativeTypeName]
val VoidLiteral: DoctrineNativeTypeName = "VoidLiteral".asInstanceOf[DoctrineNativeTypeName]
}
Loading

0 comments on commit 5c9e905

Please sign in to comment.