Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .mdl/defs/actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ if [[ "$CI_PULL_REQUEST_VAL" != "false" ]]; then
exit 0
fi

SYSTEM=$(uname -s | tr '[:upper:]' '[:lower:]')
PROJECT_ROOT="${sys.project-root}"
DIST_DIR="${action.build-sjs.dist-dir}"
PUBLISH_DIR="${PROJECT_ROOT}/npm-publish"
Expand All @@ -193,7 +194,11 @@ mkdir -p "$PUBLISH_DIR"
cp "${DIST_DIR}"/* "$PUBLISH_DIR"/
cp "${PROJECT_ROOT}/json-sick-scala/npm-template/"* "$PUBLISH_DIR"/

sed -i "s/VERSION_PLACEHOLDER/$VERSION/g" "$PUBLISH_DIR/package.json"
if [[ "${SYSTEM}" == "darwin" ]]; then
sed -i '' "s/VERSION_PLACEHOLDER/$VERSION/g" "$PUBLISH_DIR/package.json"
else
sed -i "s/VERSION_PLACEHOLDER/$VERSION/g" "$PUBLISH_DIR/package.json"
fi

cd "$PUBLISH_DIR"

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package izumi.sick.eba.cursor

import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel}

@JSExportTopLevel("ArrayCursor")
@JSExportAll
class ArrayCursorJs(cursor: ArrayCursor) extends SickCursorJs(cursor.asInstanceOf[SickCursor]) {

def left: ArrayCursorJs = {
new ArrayCursorJs(cursor.left)
}

def right: ArrayCursorJs = {
new ArrayCursorJs(cursor.right)
}

def value: SickCursorJs = downIndex(cursor.index)

def downIndex(index: Int): SickCursorJs = {
new SickCursorJs(cursor.downIndex(index))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package izumi.sick.eba.cursor

import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel}

@JSExportTopLevel("ObjectCursor")
@JSExportAll
class ObjectCursorJs(cursor: ObjectCursor) extends TopCursorJs(cursor.asInstanceOf[TopCursor])
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package izumi.sick.eba.cursor

import scala.scalajs.js
import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel}
import scala.scalajs.js.JSConverters._

@JSExportTopLevel("SickCursor")
@JSExportAll
class SickCursorJs(cursor: SickCursor) {
def downField(field: String): ObjectCursorJs = {
new ObjectCursorJs(cursor.downField(field))
}

def downArray: ArrayCursorJs = {
new ArrayCursorJs(cursor.downArray)
}

def asNul: js.UndefOr[Null] = cursor.asNul.orUndefined

def asBool: js.UndefOr[Boolean] = cursor.asBool.orUndefined

def asByte: js.UndefOr[Byte] = cursor.asByte.orUndefined

def asShort: js.UndefOr[Short] = cursor.asShort.orUndefined

def asInt: js.UndefOr[Int] = cursor.asInt.orUndefined

def asLong: js.UndefOr[Long] = cursor.asLong.orUndefined

def asBigInt: js.UndefOr[js.BigInt] = cursor.asBigInt.map(v => js.BigInt(v.toString)).orUndefined

def asFloat: js.UndefOr[Float] = cursor.asFloat.orUndefined

def asDouble: js.UndefOr[Double] = cursor.asDouble.orUndefined

def asString: js.UndefOr[String] = cursor.asString.orUndefined
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package izumi.sick.eba.cursor

import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel}

import scala.scalajs.js
import scala.scalajs.js.JSConverters.*

@JSExportTopLevel("TopCursor")
@JSExportAll
class TopCursorJs(cursor: TopCursor) extends SickCursorJs(cursor.asInstanceOf[SickCursor]) {
def query(request: String): ObjectCursorJs = {
new ObjectCursorJs(cursor.query(request))
}

def getValues: js.Map[String, ObjectCursorJs] = {
cursor.getValues.view.mapValues(new ObjectCursorJs(_)).toMap.toJSMap
}

def readKey(index: Int): ObjectCursorJs = {
new ObjectCursorJs(cursor.readKey(index))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package izumi.sick.jsapi
import io.circe.Json
import izumi.sick.SICK
import izumi.sick.eba.SICKSettings
import izumi.sick.eba.reader.EagerEBAReader
import izumi.sick.eba.cursor.TopCursorJs
import izumi.sick.eba.reader.{EagerEBAReader, IncrementalEBAReader}
import izumi.sick.eba.writer.EBAWriter
import izumi.sick.model.{SICKWriterParameters, TableWriteStrategy}
import izumi.sick.sickcirce.CirceTraverser.*
Expand Down Expand Up @@ -84,4 +85,17 @@ object SickJsAPI {
val bytes = res._1.toArrayUnsafe()
bytesToUint8Array(bytes)
}

/**
* Accepts an instance of `Uint8Array` and the rootId, returns a cursor to navigate through the structure
*
* `{ data: { a: 2, b: { c: 3 } } }`
* `const cursor = sickCursorFromUint8Array(uint8Array, "data")`
* `cursor.downField("b").downField("c").asInt`
*/
@JSExportTopLevel("sickCursorFromUint8Array")
def sickCursorFromUint8Array(uint8Array: Uint8Array, rootId: String): TopCursorJs = {
val ebaReader = IncrementalEBAReader.openBytes(uint8ArrayToBytes(uint8Array), eagerOffsets = false)
new TopCursorJs(ebaReader.getCursor(rootId))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ class JsApiTest extends AnyWordSpec {
val circeJson = io.circe.scalajs.convertJsToJson(jsAny).toTry.get
assert(circeJson == Json.obj("root1" -> Json.obj("a" -> Json.fromInt(2)), "root2" -> Json.obj("b" -> Json.fromInt(3))))
}

locally {
val uint8Array = SickJsAPI.encodeObjsToSickUint8Array(js.Dictionary("data" -> js.Dynamic.literal(a = 1, b = 2, c = 3)))
val cursor = SickJsAPI.sickCursorFromUint8Array(uint8Array, "data")
assert(cursor.downField("a").asInt.toOption.contains(1))
assert(cursor.downField("b").asInt.toOption.contains(2))
assert(cursor.downField("c").asInt.toOption.contains(3))
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package izumi.sick.eba.cursor

import izumi.sick.eba.reader.IncrementalEBAReader
import izumi.sick.model.Ref
import izumi.sick.model.RefKind.TArr

class ArrayCursor(val ref: Ref, val ebaReader: IncrementalEBAReader, val index: Int = 0) extends SickCursor {
private val length = ebaReader.arrTable.readElem(ref.ref).length

def left: ArrayCursor = {
if (index == 0) throw new ArrayIndexOutOfBoundsException("Can not move left: Index is on first element")
else new ArrayCursor(ref, ebaReader, index - 1)
}

def right: ArrayCursor = {
if (index == length - 1) throw new ArrayIndexOutOfBoundsException(s"Can not move right: Index is on last element")
else new ArrayCursor(ref, ebaReader, index + 1)
}

def value: SickCursor = downIndex(index)

def downIndex(index: Int): SickCursor = {
val newRef = ebaReader.readArrayElementRef(ref, index)
newRef.kind match {
case TArr => new ArrayCursor(newRef, ebaReader)
case _ => new ObjectCursor(newRef, ebaReader)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package izumi.sick.eba.cursor

import izumi.sick.eba.reader.IncrementalEBAReader
import izumi.sick.model.Ref

class ObjectCursor(override val ref: Ref, override val ebaReader: IncrementalEBAReader) extends TopCursor(ref, ebaReader)
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package izumi.sick.eba.cursor

import izumi.sick.eba.reader.IncrementalEBAReader
import izumi.sick.model.RefKind.*
import izumi.sick.model.{Ref, RefKind}

abstract class SickCursor {
def ref: Ref
def ebaReader: IncrementalEBAReader

def downField(field: String): ObjectCursor = {
if (ref.kind != TArr) {
val newRef = ebaReader.readObjectFieldRef(ref, field)
new ObjectCursor(newRef, ebaReader)
} else throw new IllegalArgumentException("Ref has an array kind")
}

def downArray: ArrayCursor = {
if (ref.kind == TArr) {
new ArrayCursor(ref, ebaReader)
} else throw new IllegalArgumentException("Ref is not an array kind")
}

def asObjectCursor: ObjectCursor = {
this.asInstanceOf[ObjectCursor]
}

def asNul: Option[Null] = {
if (ref.kind == TNul) Some(null)
else None
}

def asBool: Option[Boolean] = {
if (ref.kind == TBit) Some(ref.ref == 1)
else None
}

def asByte: Option[Byte] = {
if (ref.kind == TByte) Some(ref.ref.toByte)
else None
}

def asShort: Option[Short] = {
ref.kind match {
case RefKind.TByte => Some(ref.ref.toShort)
case RefKind.TShort => Some(ref.ref.toShort)
case _ => None
}
}

def asInt: Option[Int] = {
ref.kind match {
case RefKind.TByte => Some(ref.ref.toInt)
case RefKind.TShort => Some(ref.ref.toInt)
case RefKind.TInt => Some(ebaReader.intTable.readElem(ref.ref))
case _ => None
}
}

def asLong: Option[Long] = {
ref.kind match {
case RefKind.TByte => Some(ref.ref.toLong)
case RefKind.TShort => Some(ref.ref.toLong)
case RefKind.TInt => Some(ebaReader.intTable.readElem(ref.ref).toLong)
case RefKind.TLng => Some(ebaReader.longTable.readElem(ref.ref))
case _ => None
}
}

def asBigInt: Option[BigInt] = {
ref.kind match {
case RefKind.TByte => Some(BigInt.apply(ref.ref.toLong))
case RefKind.TShort => Some(BigInt.apply(ref.ref.toLong))
case RefKind.TInt =>
Some(BigInt.apply(ebaReader.intTable.readElem(ref.ref).toLong))
case RefKind.TLng => Some(BigInt.apply(ebaReader.longTable.readElem(ref.ref)))
case RefKind.TBigInt => Some(ebaReader.bigIntTable.readElem(ref.ref))
case _ => None
}
}

def asFloat: Option[Float] = {
ref.kind match {
case RefKind.TByte => Some(ref.ref.toFloat)
case RefKind.TShort => Some(ref.ref.toFloat)
case RefKind.TInt => Some(ebaReader.intTable.readElem(ref.ref).toFloat)
case RefKind.TLng => Some(ebaReader.longTable.readElem(ref.ref).toFloat)
case RefKind.TFlt => Some(ebaReader.floatTable.readElem(ref.ref))
case _ => None
}
}

def asDouble: Option[Double] = {
ref.kind match {
case RefKind.TByte => Some(ref.ref.toDouble)
case RefKind.TShort => Some(ref.ref.toDouble)
case RefKind.TInt => Some(ebaReader.intTable.readElem(ref.ref).toDouble)
case RefKind.TLng => Some(ebaReader.longTable.readElem(ref.ref).toDouble)
case RefKind.TFlt => Some(ebaReader.floatTable.readElem(ref.ref).toDouble)
case RefKind.TDbl => Some(ebaReader.doubleTable.readElem(ref.ref))
case _ => None
}
}

def asBigDec: Option[BigDecimal] = {
ref.kind match {
case RefKind.TByte => Some(BigDecimal.apply(ref.ref.toLong))
case RefKind.TShort => Some(BigDecimal.apply(ref.ref.toLong))
case RefKind.TInt =>
Some(BigDecimal.apply(ebaReader.intTable.readElem(ref.ref).toLong))
case RefKind.TLng =>
Some(BigDecimal.apply(ebaReader.longTable.readElem(ref.ref)))
case RefKind.TFlt =>
Some(BigDecimal.apply(ebaReader.floatTable.readElem(ref.ref).toDouble))
case RefKind.TDbl =>
Some(BigDecimal.apply(ebaReader.doubleTable.readElem(ref.ref)))
case RefKind.TBigDec => Some(ebaReader.bigDecTable.readElem(ref.ref))
case _ => None
}
}

def asString: Option[String] = {
if (ref.kind == TStr) Some(ebaReader.strTable.readElem(ref.ref))
else None
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package izumi.sick.eba.cursor

import izumi.sick.eba.reader.IncrementalEBAReader
import izumi.sick.model.Ref
import izumi.sick.model.RefKind.TObj

class TopCursor(val ref: Ref, val ebaReader: IncrementalEBAReader) extends SickCursor {
def query(request: String): ObjectCursor = {
new ObjectCursor(ebaReader.queryRef(ref, request)._1, ebaReader)
}

def getReferences: Map[String, Ref] = {
if (ref.kind == TObj) ebaReader.objTable.readElem(ref.ref).iterator.toMap
else throw new RuntimeException(s"Can not get references for kind ${ref.kind}")
}

def getValues: Map[String, ObjectCursor] = {
getReferences.view.mapValues(ref =>
new ObjectCursor(ref, ebaReader)
).toMap
}

def readKey(index: Int): ObjectCursor = {
if (ref.kind == TObj) new ObjectCursor(ebaReader.objTable.readElem(ref.ref).readKey(index)._2, ebaReader)
else throw new RuntimeException(s"Can not read key for kind ${ref.kind}")
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package izumi.sick.eba.reader

import izumi.sick.eba.cursor.TopCursor
import izumi.sick.eba.reader.incremental.{IncrementalJValue, IncrementalTableFixed, IncrementalTableVar, OneObjTable}
import izumi.sick.eba.writer.codecs.EBACodecs.{DebugTableName, IntCodec, RefCodec, ShortCodec}
import izumi.sick.eba.{EBAStructure, SICKSettings}
Expand Down Expand Up @@ -115,12 +116,23 @@ class IncrementalEBAReader(
val roots: collection.Map[String, Ref],
) extends AutoCloseable {

def getCursor(ref: Ref): TopCursor = {
new TopCursor(ref, this)
}

def getCursor(rootId: String): TopCursor = {
getRoot(rootId) match {
case Some(ref) => new TopCursor(ref, this)
case None => throw new NoSuchElementException(s"Root with id $rootId was not found")
}
}

def getRoot(id: String): Option[Ref] = {
roots.get(id)
}

def query(ref: Ref, path: String): IncrementalJValue = {
query(ref, path.split(".").toList)
query(ref, path.split('.').toList)
}

def query(ref: Ref, parts: List[String]): IncrementalJValue = {
Expand All @@ -137,7 +149,7 @@ class IncrementalEBAReader(
}

def query(jObj: IncrementalJValue.JObj, path: String): IncrementalJValue = {
query(jObj, path.split(".").toList)
query(jObj, path.split('.').toList)
}

def query(jObj: IncrementalJValue.JObj, parts: List[String]): IncrementalJValue = {
Expand All @@ -151,7 +163,7 @@ class IncrementalEBAReader(
}

def queryRef(ref: Ref, path: String): (Ref, Seq[String]) = {
val parts = path.split(".").toList
val parts = path.split('.').toList
(queryRef(ref, parts), parts)
}

Expand Down
Loading