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
80 changes: 48 additions & 32 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import org.scalajs.linker.interface.Report

import scala.sys.process._

ThisBuild / scalaVersion := "2.13.10"
ThisBuild / scalaVersion := "2.13.17"
ThisBuild / description := "Salesforce Apex outline parser with type definitions"
ThisBuild / organization := "io.github.apex-dev-tools"
ThisBuild / organizationHomepage := Some(url("https://github.com/apex-dev-tools/outline-parser"))
Expand All @@ -18,16 +18,17 @@ ThisBuild / developers := List(
url("https://github.com/apex-dev-tools")
)
)
ThisBuild / versionScheme := Some("strict")
ThisBuild / sonatypeCredentialHost := "s01.oss.sonatype.org"
ThisBuild / sonatypeRepository := "https://s01.oss.sonatype.org/service/local"
ThisBuild / versionScheme := Some("strict")
ThisBuild / resolvers += Resolver.mavenLocal
ThisBuild / resolvers ++= Resolver.sonatypeOssRepos("releases")
ThisBuild / resolvers ++= Resolver.sonatypeOssRepos("snapshots")
ThisBuild / resolvers += Resolver.sonatypeCentralSnapshots

lazy val build = taskKey[File]("Build artifacts")
lazy val pack = inputKey[Unit]("Publish specific local version")
lazy val Dev = config("dev") extend Compile
// Java 17 development with Java 8 runtime compatibility
ThisBuild / javacOptions ++= Seq("-source", "8", "-target", "8")

lazy val build = taskKey[File]("Build artifacts")
lazy val pack = inputKey[Unit]("Publish specific local version")
lazy val npmInstall = taskKey[Unit]("Install Node modules for Scala.js tasks")
lazy val Dev = config("dev") extend Compile

// Don't publish root
publish / skip := true
Expand All @@ -43,7 +44,7 @@ lazy val parser = crossProject(JSPlatform, JVMPlatform)
scalacOptions += "-deprecation",
libraryDependencies ++= Seq(
"org.scalatest" %%% "scalatest" % "3.2.9" % Test,
"io.github.apex-dev-tools" %%% "apex-ls" % "4.3.1" % Test
"io.github.apex-dev-tools" %%% "apex-ls" % "6.0.2" % Test
)
)
.jvmSettings(
Expand All @@ -55,10 +56,14 @@ lazy val parser = crossProject(JSPlatform, JVMPlatform)
)
)
.jsSettings(
build := buildJs(Compile / fullLinkJS).value,
Dev / build := buildJs(Compile / fastLinkJS).value,
build := buildJs(Compile / fullLinkJS).value,
Dev / build := buildJs(Compile / fastLinkJS).value,
Test / parallelExecution := false,
npmInstall := syncNodeModules.value,
Test / test := (Test / test).dependsOn(npmInstall).value,
Test / testOnly := (Test / testOnly).dependsOn(npmInstall).evaluated,
Test / testQuick := (Test / testQuick).dependsOn(npmInstall).evaluated,
libraryDependencies ++= Seq("net.exoego" %%% "scala-js-nodejs-v14" % "0.12.0"),
Test / parallelExecution := false,
scalaJSUseMainModuleInitializer := false,
scalaJSLinkerConfig ~= {
_.withModuleKind(ModuleKind.CommonJSModule)
Expand All @@ -82,34 +87,45 @@ lazy val buildJVM = Def.task {
}

def buildJs(jsTask: TaskKey[Attributed[Report]]): Def.Initialize[Task[File]] = Def.task {
def exec: (String, File) => Unit = run(streams.value.log)(_, _)

// Depends on scalaJS fast/full linker output
val t = jsTask.value
jsTask.value

val targetDir = crossTarget.value
val targetFile = (jsTask / scalaJSLinkerOutputDirectory).value / "main.js"
val npmDir = baseDirectory.value / "npm"

val files: Map[File, File] = Map(
// Update target with NPM modules (for testing)
npmDir / "package.json" -> targetDir / "package.json"
)
syncNodeModules.value

IO.copy(files, CopyOptions().withOverwrite(true))
targetFile
}

// Install modules in NPM
exec("npm ci", npmDir)
def syncNodeModules: Def.Initialize[Task[Unit]] = Def.task {
val log = streams.value.log
val npmDir = baseDirectory.value / "npm"
val targetDir = crossTarget.value
val lockFile = npmDir / "package-lock.json"
val nodeDir = npmDir / "node_modules"
val exec = run(log)(_, _)
val needInstall =
!nodeDir.exists() || (lockFile.exists() && lockFile.lastModified() > nodeDir.lastModified())

if (needInstall) {
exec("npm ci", npmDir)
}

// Update target with NPM modules (for testing)
IO.delete(targetDir / "node_modules")
IO.copyDirectory(
npmDir / "node_modules",
targetDir / "node_modules",
CopyOptions().withOverwrite(true)
)
val packageJson = npmDir / "package.json"
if (packageJson.exists()) {
IO.copyFile(packageJson, targetDir / "package.json")
}
if (lockFile.exists()) {
IO.copyFile(lockFile, targetDir / "package-lock.json")
}

targetFile
IO.delete(targetDir / "node_modules")
if (nodeDir.exists()) {
IO.copyDirectory(nodeDir, targetDir / "node_modules", CopyOptions().withOverwrite(true))
} else {
log.warn("npm node_modules directory not found after installation")
}
}

// Command to do a local release under a specific version
Expand Down
15 changes: 8 additions & 7 deletions js/npm/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion js/npm/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@apexdevtools/outline-parser",
"dependencies": {
"@apexdevtools/apex-parser": "^3.3.0"
"@apexdevtools/apex-parser": "^4.3.1"
},
"engines": {
"node": ">=14.0.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,20 @@ object AntlrOps {

implicit class ContextOps[X <: ParserRuleContext](context: X) {
def location: Location = {
// ANTLR uses [start, end) convention with exclusive end positions
// We don't calculate byte offsets here as that would be too expensive
// The comparison code will ignore byte offsets for ANTLR-generated locations

// Handle UndefOr[Token] in ScalaJS - context.stop might be undefined
val stopToken = context.stop.toOption.getOrElse(context.start)

Location(
context.start.line,
context.start.charPositionInLine,
context.start.startIndex,
context.stop.line,
context.stop.charPositionInLine + context.stop.text.length,
context.stop.stopIndex
0, // byte offset not calculated
stopToken.line,
stopToken.charPositionInLine + stopToken.text.length,
0 // byte offset not calculated
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@ object AntlrOps {

implicit class ContextOps(context: ParserRuleContext) {
def location: Location = {
// ANTLR uses [start, end) convention with exclusive end positions
// We don't calculate byte offsets here as that would be too expensive
// The comparison code will ignore byte offsets for ANTLR-generated locations
Location(
context.start.getLine,
context.start.getCharPositionInLine,
context.start.getStartIndex,
0, // byte offset not calculated
context.stop.getLine,
context.stop.getCharPositionInLine + context.stop.getText.length,
context.stop.getStopIndex
0 // byte offset not calculated
)
}
}
Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version = 1.8.0
sbt.version = 1.12.8
8 changes: 4 additions & 4 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.12.0")
addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.2.0")
addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.11")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.0")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.20.2")
addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.3.2")
addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.11.2")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.6")
41 changes: 29 additions & 12 deletions shared/src/main/scala/com/financialforce/oparser/Buffer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,31 @@ import com.financialforce.types.base.Location

class Buffer(backing: String) {

private var startLine = 0
private var startLineOffset = 0
private var endLine = 0
private var endLineOffset = 0
private var startCharOffset = 0
private var endCharOffset = 0
private var startByteOffset = 0
private var endByteOffset = 0
private var capturing = false
private var startLine = 0
private var startLineOffset = 0
private var endLine = 0
private var endLineOffset = 0
private var startCharOffset = 0
private var endCharOffset = 0
private var startByteOffset = 0
private var endByteOffset = 0
private var lastCharByteLength = 1
private var capturing = false

private val emptyString = ""

def captured(): (String, Location) = {
(
if (capturing) backing.substring(startCharOffset, endCharOffset + 1)
else emptyString,
Location(startLine, startLineOffset, startByteOffset, endLine, endLineOffset, endByteOffset)
Location(
startLine,
startLineOffset,
startByteOffset,
endLine,
endLineOffset + 1,
endByteOffset + lastCharByteLength
)
)
}

Expand All @@ -36,10 +44,18 @@ class Buffer(backing: String) {
endLineOffset = 0
startByteOffset = 0
endByteOffset = 0
lastCharByteLength = 1
capturing = false
}

def append(byteOffset: Int, charOffset: Int, line: Int, lineOffset: Int): Unit = {
def append(
byteOffset: Int,
charOffset: Int,
line: Int,
lineOffset: Int,
charByteLength: Int,
charCount: Int = 1
): Unit = {
if (!capturing) {
capturing = true
startByteOffset = byteOffset
Expand All @@ -48,9 +64,10 @@ class Buffer(backing: String) {
startLineOffset = lineOffset
}
endByteOffset = byteOffset
endCharOffset = charOffset
endCharOffset = charOffset + charCount - 1 // For surrogate pairs, this will be charOffset + 1
endLine = line
endLineOffset = lineOffset
lastCharByteLength = charByteLength
}

}
Loading
Loading