This is an automated email from the ASF dual-hosted git repository.

hdalsania pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/daffodil-vscode.git


The following commit(s) were added to refs/heads/main by this push:
     new 52ddf25b Added support for Daffodil 4.1.0 and 4.2.0, including support 
for Scala 3.3.7
52ddf25b is described below

commit 52ddf25bae02f9015f66d0ab9d0e8a95247609bb
Author: Hitesh Dalsania <[email protected]>
AuthorDate: Mon Jul 27 23:09:46 2026 -0400

    Added support for Daffodil 4.1.0 and 4.2.0, including support for Scala 
3.3.7
    
    update daffodilDebug.ts
    
    Added error handling
---
 CHANGELOG.md                                       |   7 +
 README.md                                          |  16 +++
 build.sbt                                          |   2 +-
 .../org.apache.daffodil.debugger.dap/Parse.scala   | 142 +++++++++++++++++++--
 .../org.apache.daffodil.debugger/ParseSuite.scala  |   4 +
 package.json                                       |  10 +-
 src/adapter/daffodilDebug.ts                       | 127 +++++++++++++++++-
 src/daffodilDebugger/daffodilJars.ts               |  20 ++-
 src/launchWizard/launchWizard.ts                   |  26 +++-
 src/launchWizard/script.js                         |  23 +++-
 src/tests/suite/daffodilDebugger.test.ts           |   8 +-
 src/tests/suite/version.test.ts                    |  27 ++++
 src/utils.ts                                       |   2 +-
 13 files changed, 385 insertions(+), 29 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0b9b2d84..f54067b3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,6 +26,13 @@
 
 This file outlines the release notes and known issues for the 
"daffodil-vscode" extension.
 
+## 1.6.0
+  ### Debugger:
+  - Updated Scala 3 debugger compatibility for Apache Daffodil 4.x runtimes.
+    - Added support for Daffodil 4.0.0, 4.1.0, and 4.2.0 infoset runtime API 
shapes.
+    - Added runtime compatibility regression coverage for infoset walker API 
detection on Scala 3.
+    - Aligned Scala 3 target to 3.3.7 based on Daffodil release notes guidance.
+
 ## 1.5.0
   ### Debugger:
   - Added support for multiple versions of the Daffodil parser (i.e., Daffodil 
3.10.0, 3.11.0, and 4.0.0). 
diff --git a/README.md b/README.md
index cc62780c..928ad40a 100644
--- a/README.md
+++ b/README.md
@@ -61,6 +61,22 @@ The Data Editor component can be configured to run alongside 
and open the design
 * [Install Java Runtime 8 or 
greater](https://docs.oracle.com/goldengate/1212/gg-winux/GDRAD/java.htm#BGBFJHAB)
 * On Linux, glibc 2.31 or greater is required
 
+# Debugger Compatibility
+
+The debugger backend is built for multiple Scala and Daffodil versions so the 
extension can support a wider range of parser runtimes.
+
+| Debugger target | Scala version | Daffodil dependency |
+| --- | --- | --- |
+| `debugger2_12` | 2.12.20 | 3.10.0 |
+| `debugger` | 2.13.18 | 3.11.0 |
+| `debugger3` | 3.3.8 | 4.0.0, 4.1.0, 4.2.0 |
+
+Notes:
+
+* The Scala 3 debugger target requires Java 17 or later.
+* Daffodil 4.x runtime API differences are handled in the debugger backend so 
infoset serialization remains compatible with Daffodil 4.0.0, 4.1.0, and 4.2.0.
+* For Daffodil library and CLI release information, see [Apache Daffodil 
Library and CLI](https://daffodil.apache.org/libraryAndCLI/).
+
 # Getting Help
 
 If additional help or guidance on using Apache Daffodilâ„¢, Apache Daffodilâ„¢ 
Extension for Visual Studio Code, or DFDL development in general is needed, 
please engage with the Daffodil user and developer communities on [mailing 
lists](https://daffodil.apache.org/community/) 
(https://daffodil.apache.org/community/) and/or review the [list 
archives](https://lists.apache.org/[email protected]) 
(https://lists.apache.org/[email protected]).
diff --git a/build.sbt b/build.sbt
index 619a9e3d..b0787ba2 100644
--- a/build.sbt
+++ b/build.sbt
@@ -247,7 +247,7 @@ def getPlatformSpecificLibraries(scalaBinaryVersion: 
String) =
       )
     case "3" =>
       Seq(
-        "org.apache.daffodil" %% "daffodil-core" % "4.0.0" % "provided,test"
+        "org.apache.daffodil" %% "daffodil-core" % "4.2.0" % "provided,test"
       )
   }
 
diff --git 
a/debugger/src/main/scala/org.apache.daffodil.debugger.dap/Parse.scala 
b/debugger/src/main/scala/org.apache.daffodil.debugger.dap/Parse.scala
index f559f9b0..c6777f85 100644
--- a/debugger/src/main/scala/org.apache.daffodil.debugger.dap/Parse.scala
+++ b/debugger/src/main/scala/org.apache.daffodil.debugger.dap/Parse.scala
@@ -33,7 +33,7 @@ import java.net.URI
 import java.nio.file._
 import org.apache.commons.io.FileUtils
 import org.apache.daffodil.debugger.dap.{BuildInfo => DAPBuildInfo}
-import org.apache.daffodil.runtime1.infoset.{DIDocument, DIElement, 
InfosetWalker}
+import org.apache.daffodil.runtime1.infoset.{DIDocument, DIElement}
 import org.apache.daffodil.runtime1.processors._
 import org.apache.daffodil.runtime1.processors.dfa.DFADelimiter
 import org.apache.daffodil.runtime1.processors.parsers._
@@ -1245,18 +1245,140 @@ object Parse {
 
     private def infosetToString(format: String, ie: DIElement): String = {
       val bos = new java.io.ByteArrayOutputStream()
-
-      val iw = InfosetWalker(
-        ie.asInstanceOf[DIElement],
-        Support.getInfosetOutputter(format, bos),
-        walkHidden = false,
-        ignoreBlocks = true,
-        releaseUnneededInfoset = false
-      )
-      iw.walk(lastWalk = true)
+      val outputter = Support.getInfosetOutputter(format, bos)
+
+      // Daffodil runtime walker APIs differ across 4.x releases.
+      // Use reflection to support older InfosetWalker companion, newer 
streaming walker class APIs, and
+      // finally a non-streaming constructor fallback.
+      val walker = createInfosetWalker(ie, outputter)
+      val walkMethod = walker.getClass.getMethod("walk", classOf[Boolean])
+      walkMethod.invoke(walker, Boolean.box(true))
       bos.toString("UTF-8")
     }
 
+    private def createInfosetWalker(ie: DIElement, outputter: AnyRef): AnyRef 
= {
+      createInfosetWalkerFromCompanion(ie, outputter)
+        .orElse(createInfosetWalkerFromStreamingClass(ie, outputter))
+        .orElse(createInfosetWalkerFromCtor(ie, outputter))
+        .getOrElse {
+          throw new IllegalStateException(
+            "Unable to create infoset walker. Unsupported Daffodil runtime API 
for infoset serialization."
+          )
+        }
+    }
+
+    def isCompatibleRuntimeForInfosetSerialization(): Boolean =
+      hasCompatibleInfosetWalkerCompanionApi() || 
hasCompatibleStreamingInfosetWalkerApi() || hasCompatibleNonStreamingCtorApi()
+
+    private def hasCompatibleInfosetWalkerCompanionApi(): Boolean =
+      Try {
+        val companion = 
Class.forName("org.apache.daffodil.runtime1.infoset.InfosetWalker$")
+        companion
+          .getMethods
+          .filter(m => m.getName == "apply")
+          .exists(m => isCompatibleApplyMethod(m, classOf[DIElement], None))
+      }.getOrElse(false)
+
+    private def hasCompatibleStreamingInfosetWalkerApi(): Boolean =
+      Try {
+        val clazz = 
Class.forName("org.apache.daffodil.runtime1.infoset.StreamingInfosetWalker")
+        clazz
+          .getMethods
+          .filter(m => m.getName == "apply")
+          .exists(m => isCompatibleApplyMethod(m, classOf[DIElement], None))
+      }.getOrElse(false)
+
+    private def hasCompatibleNonStreamingCtorApi(): Boolean =
+      Try {
+        val clazz = 
Class.forName("org.apache.daffodil.runtime1.infoset.NonStreamingInfosetWalker")
+        clazz.getConstructors.exists(_.getParameterCount == 2)
+      }.getOrElse(false)
+
+    private def createInfosetWalkerFromCompanion(ie: DIElement, outputter: 
AnyRef): Option[AnyRef] =
+      Try {
+        val companion = 
Class.forName("org.apache.daffodil.runtime1.infoset.InfosetWalker$")
+        val module = companion.getField("MODULE$").get(null)
+        val maybeMethod = companion
+          .getMethods
+          .filter(m => m.getName == "apply")
+          .find(m => isCompatibleApplyMethod(m, ie.getClass, 
Some(outputter.getClass)))
+
+        val method = maybeMethod.getOrElse(
+          throw new NoSuchMethodException(
+            "InfosetWalker$.apply(...) with expected first five parameters was 
not found"
+          )
+        )
+
+        val args = new Array[AnyRef](method.getParameterCount)
+        args(0) = ie
+        args(1) = outputter
+        args(2) = Boolean.box(false)
+        args(3) = Boolean.box(true)
+        args(4) = Boolean.box(false)
+
+        (5 until method.getParameterCount).foreach { i =>
+          val defaultMethodName = s"apply$$default$$${i + 1}"
+          val defaultValue = 
companion.getMethod(defaultMethodName).invoke(module)
+          args(i) = defaultValue.asInstanceOf[AnyRef]
+        }
+
+        method.invoke(module, args: _*).asInstanceOf[AnyRef]
+      }.toOption
+
+    private def createInfosetWalkerFromStreamingClass(ie: DIElement, 
outputter: AnyRef): Option[AnyRef] =
+      Try {
+        val clazz = 
Class.forName("org.apache.daffodil.runtime1.infoset.StreamingInfosetWalker")
+        val maybeApply = clazz
+          .getMethods
+          .filter(m => m.getName == "apply")
+          .find(m => isCompatibleApplyMethod(m, ie.getClass, 
Some(outputter.getClass)))
+
+        val method = maybeApply.getOrElse(
+          throw new NoSuchMethodException(
+            "StreamingInfosetWalker.apply(...) with expected first five 
parameters was not found"
+          )
+        )
+
+        val args = new Array[AnyRef](method.getParameterCount)
+        args(0) = ie
+        args(1) = outputter
+        args(2) = Boolean.box(false)
+        args(3) = Boolean.box(true)
+        args(4) = Boolean.box(false)
+
+        (5 until method.getParameterCount).foreach { i =>
+          val defaultMethodName = s"apply$$default$$${i + 1}"
+          val defaultValue = clazz.getMethod(defaultMethodName).invoke(null)
+          args(i) = defaultValue.asInstanceOf[AnyRef]
+        }
+
+        method.invoke(null, args: _*).asInstanceOf[AnyRef]
+      }.toOption
+
+    private def createInfosetWalkerFromCtor(ie: DIElement, outputter: AnyRef): 
Option[AnyRef] =
+      Try {
+        val clazz = 
Class.forName("org.apache.daffodil.runtime1.infoset.NonStreamingInfosetWalker")
+        val ctor = clazz.getConstructors.find(_.getParameterCount == 
2).getOrElse(
+          throw new 
NoSuchMethodException("NonStreamingInfosetWalker(DIElement, InfosetOutputter)")
+        )
+
+        ctor.newInstance(ie, outputter).asInstanceOf[AnyRef]
+      }.toOption
+
+    private def isCompatibleApplyMethod(
+        method: java.lang.reflect.Method,
+        rootClass: Class[?],
+        outputterClass: Option[Class[?]]
+    ): Boolean = {
+      val pts = method.getParameterTypes
+      pts.length >= 5 &&
+      pts(0).isAssignableFrom(rootClass) &&
+      outputterClass.fold(!pts(1).isPrimitive)(cls => 
pts(1).isAssignableFrom(cls)) &&
+      pts(2) == java.lang.Boolean.TYPE &&
+      pts(3) == java.lang.Boolean.TYPE &&
+      pts(4) == java.lang.Boolean.TYPE
+    }
+
   }
 
   /** Behavior of a stepping debugger that can be running or stopped. */
diff --git 
a/debugger/src/test/scala/org.apache.daffodil.debugger/ParseSuite.scala 
b/debugger/src/test/scala/org.apache.daffodil.debugger/ParseSuite.scala
index 7102e7c3..ecf53834 100644
--- a/debugger/src/test/scala/org.apache.daffodil.debugger/ParseSuite.scala
+++ b/debugger/src/test/scala/org.apache.daffodil.debugger/ParseSuite.scala
@@ -169,6 +169,10 @@ class ParseSuite extends FunSuite {
     )
   }
 
+  test("Infoset walker runtime API is compatible") {
+    
assertEquals(Parse.InfosetEvent.isCompatibleRuntimeForInfosetSerialization(), 
true)
+  }
+
   def buildJson(): Unit = {
     schema.addProperty("path", schemaPath)
 
diff --git a/package.json b/package.json
index d11a6ebf..d0e77be3 100644
--- a/package.json
+++ b/package.json
@@ -718,7 +718,7 @@
                 "properties": {
                   "daffodilVersion": {
                     "type": "string",
-                    "default": "3.11.0",
+                    "default": "4.2.0",
                     "description": "Daffodil version to use."
                   },
                   "timeout": {
@@ -755,7 +755,7 @@
                   }
                 },
                 "default": {
-                  "daffodilVersion": "3.11.0",
+                  "daffodilVersion": "4.2.0",
                   "timeout": "10s",
                   "logging": {
                     "level": "INFO",
@@ -801,7 +801,7 @@
               }
             },
             "dfdlDebugger": {
-              "daffodilVersion": "3.11.0",
+              "daffodilVersion": "4.2.0",
               "timeout": "10s",
               "logging": {
                 "level": "INFO",
@@ -849,7 +849,7 @@
                 }
               },
               "dfdlDebugger": {
-                "daffodilVersion": "3.11.0",
+                "daffodilVersion": "4.2.0",
                 "timeout": "10s",
                 "logging": {
                   "level": "INFO",
@@ -973,7 +973,7 @@
             "type": "object",
             "description": "Configuration for debugger. Settings are 
daffodilVersion, timeout and logging (level and file)",
             "default": {
-              "daffodilVersion": "3.11.0",
+              "daffodilVersion": "4.2.0",
               "timeout": "10s",
               "logging": {
                 "level": "INFO",
diff --git a/src/adapter/daffodilDebug.ts b/src/adapter/daffodilDebug.ts
index ec098cb5..87c7a310 100644
--- a/src/adapter/daffodilDebug.ts
+++ b/src/adapter/daffodilDebug.ts
@@ -24,7 +24,8 @@ import {
   Breakpoint,
 } from '@vscode/debugadapter'
 import { DebugProtocol } from '@vscode/debugprotocol'
-import { basename } from 'path'
+import * as fs from 'fs'
+import * as path from 'path'
 import {
   DaffodilRuntime,
   IDaffodilBreakpoint,
@@ -51,6 +52,12 @@ interface ILaunchRequestArguments extends 
DebugProtocol.LaunchRequestArguments {
   trace?: boolean
   /** run without debugging */
   noDebug?: boolean
+  /** debugger-specific settings used by the external Scala backend */
+  dfdlDebugger?: {
+    logging?: {
+      file?: string
+    }
+  }
 }
 
 export class DaffodilDebugSession extends LoggingDebugSession {
@@ -75,6 +82,11 @@ export class DaffodilDebugSession extends 
LoggingDebugSession {
   private _showHex = false
   private _useInvalidatedEvent = false
 
+  private _debuggerLogFilePath: string | undefined
+  private _debuggerLogWatcher: fs.FSWatcher | undefined
+  private _debuggerLogOffset = 0
+  private _debuggerLogRemainder = ''
+
   /**
    * Creates a new debug adapter that is used for one debug session.
    * We configure the default implementation of a debug adapter here.
@@ -141,6 +153,7 @@ export class DaffodilDebugSession extends 
LoggingDebugSession {
       this.sendEvent(e)
     })
     this._runtime.on('end', () => {
+      this.stopDebuggerLogStreaming()
       this.sendEvent(new TerminatedEvent())
     })
   }
@@ -243,6 +256,8 @@ export class DaffodilDebugSession extends 
LoggingDebugSession {
       false
     )
 
+    this.startDebuggerLogStreaming(args)
+
     // wait until configuration has finished (and configurationDoneRequest has 
been called)
     await this._configurationDone.wait(1000)
 
@@ -252,6 +267,24 @@ export class DaffodilDebugSession extends 
LoggingDebugSession {
     this.sendResponse(response)
   }
 
+  protected disconnectRequest(
+    response: DebugProtocol.DisconnectResponse,
+    args: DebugProtocol.DisconnectArguments,
+    request?: DebugProtocol.Request
+  ): void {
+    this.stopDebuggerLogStreaming()
+    super.disconnectRequest(response, args, request)
+  }
+
+  protected terminateRequest(
+    response: DebugProtocol.TerminateResponse,
+    args: DebugProtocol.TerminateArguments,
+    request?: DebugProtocol.Request
+  ): void {
+    this.stopDebuggerLogStreaming()
+    super.terminateRequest(response, args, request)
+  }
+
   protected async setBreakPointsRequest(
     response: DebugProtocol.SetBreakpointsResponse,
     args: DebugProtocol.SetBreakpointsArguments
@@ -775,9 +808,99 @@ export class DaffodilDebugSession extends 
LoggingDebugSession {
 
   //---- helpers
 
+  private startDebuggerLogStreaming(args: ILaunchRequestArguments): void {
+    const configuredLogFile = args.dfdlDebugger?.logging?.file?.trim()
+
+    if (!configuredLogFile || configuredLogFile.includes('${')) {
+      return
+    }
+
+    this.stopDebuggerLogStreaming()
+
+    try {
+      fs.mkdirSync(path.dirname(configuredLogFile), { recursive: true })
+      if (!fs.existsSync(configuredLogFile)) {
+        fs.writeFileSync(configuredLogFile, '')
+      }
+
+      this._debuggerLogFilePath = configuredLogFile
+      this._debuggerLogOffset = fs.statSync(configuredLogFile).size
+
+      this._debuggerLogWatcher = fs.watch(configuredLogFile, (eventType) => {
+        if (eventType === 'change') {
+          this.readDebuggerLogDelta()
+        }
+      })
+    } catch (error) {
+      this.sendEvent(
+        new OutputEvent(
+          `Unable to stream debugger log file '${configuredLogFile}': 
${error}\n`
+        )
+      )
+      this.stopDebuggerLogStreaming()
+    }
+  }
+
+  private stopDebuggerLogStreaming(): void {
+    if (this._debuggerLogWatcher) {
+      this._debuggerLogWatcher.close()
+      this._debuggerLogWatcher = undefined
+    }
+
+    this._debuggerLogFilePath = undefined
+    this._debuggerLogOffset = 0
+    this._debuggerLogRemainder = ''
+  }
+
+  private readDebuggerLogDelta(): void {
+    if (!this._debuggerLogFilePath) {
+      return
+    }
+
+    try {
+      const stats = fs.statSync(this._debuggerLogFilePath)
+
+      if (stats.size < this._debuggerLogOffset) {
+        this._debuggerLogOffset = 0
+        this._debuggerLogRemainder = ''
+      }
+
+      if (stats.size === this._debuggerLogOffset) {
+        return
+      }
+
+      const chunkLength = stats.size - this._debuggerLogOffset
+      const buffer = Buffer.alloc(chunkLength)
+      const fd = fs.openSync(this._debuggerLogFilePath, 'r')
+
+      try {
+        fs.readSync(fd, buffer, 0, chunkLength, this._debuggerLogOffset)
+      } finally {
+        fs.closeSync(fd)
+      }
+
+      this._debuggerLogOffset = stats.size
+      this.emitDebuggerLogChunk(buffer.toString('utf8'))
+    } catch {
+      // Ignore transient file access errors while the backend is writing.
+    }
+  }
+
+  private emitDebuggerLogChunk(chunk: string): void {
+    const combined = this._debuggerLogRemainder + chunk
+    const lines = combined.split(/\r?\n/)
+    this._debuggerLogRemainder = lines.pop() ?? ''
+
+    for (const line of lines) {
+      if (line.length > 0) {
+        this.sendEvent(new OutputEvent(`[daffodil-debugger] ${line}\n`))
+      }
+    }
+  }
+
   private createSource(filePath: string): Source {
     return new Source(
-      basename(filePath),
+      path.basename(filePath),
       this.convertDebuggerPathToClient(filePath),
       undefined,
       undefined,
diff --git a/src/daffodilDebugger/daffodilJars.ts 
b/src/daffodilDebugger/daffodilJars.ts
index e6cee07e..0b89873a 100644
--- a/src/daffodilDebugger/daffodilJars.ts
+++ b/src/daffodilDebugger/daffodilJars.ts
@@ -56,7 +56,7 @@ export async function checkIfDaffodilJarsNeeded(
   // If not a valid daffodil version provided and it doesn't exist already in 
cache then throw error
   if (!(await checkIfValidDaffodilVersion(daffodilVersion))) {
     throw new Error(
-      'Invalid Daffodil Version provided. Make sure 
dfdlDebugger.daffodilVersion is a valid version of Daffodil'
+      'Unsupported or Invalid Daffodil Version provided. Make sure 
dfdlDebugger.daffodilVersion is a valid version of Daffodil'
     )
   }
 
@@ -65,6 +65,15 @@ export async function checkIfDaffodilJarsNeeded(
   return await downloadAndExtractToGlobalStorage(context, daffodilVersion)
 }
 
+const allowedDaffodilVersions = [
+  '3.9.0',
+  '3.10.0',
+  '3.11.0',
+  '4.0.0',
+  '4.1.0',
+  '4.2.0',
+]
+
 // Helper function to get the list of valid Daffodil versions
 async function getValidDaffodilVersions(): Promise<string[]> {
   const url = 'https://daffodil.apache.org/doap.rdf'
@@ -91,8 +100,13 @@ async function getValidDaffodilVersions(): 
Promise<string[]> {
 // Helper function to check if the given daffodil version is a valid version 
or not
 const checkIfValidDaffodilVersion = async (
   daffodilVersion: string
-): Promise<boolean> =>
-  (await getValidDaffodilVersions()).includes(daffodilVersion)
+): Promise<boolean> => {
+  const validVersions = await getValidDaffodilVersions()
+  return (
+    allowedDaffodilVersions.includes(daffodilVersion) &&
+    validVersions.includes(daffodilVersion)
+  )
+}
 
 export async function downloadAndExtractToGlobalStorage(
   context: vscode.ExtensionContext,
diff --git a/src/launchWizard/launchWizard.ts b/src/launchWizard/launchWizard.ts
index 63ff2a19..b1515c2c 100644
--- a/src/launchWizard/launchWizard.ts
+++ b/src/launchWizard/launchWizard.ts
@@ -26,6 +26,28 @@ import * as path from 'path'
 
 let launchWizard: LaunchWizard | undefined
 
+export const DEFAULT_DAFFODIL_VERSION = '4.2.0'
+export const SUPPORTED_DAFFODIL_VERSIONS = [
+  '3.9.0',
+  '3.10.0',
+  '3.11.0',
+  '4.0.0',
+  '4.1.0',
+  '4.2.0',
+]
+
+export function getDaffodilVersionOptions(selectedVersion?: string): string {
+  const effectiveVersion =
+    selectedVersion && SUPPORTED_DAFFODIL_VERSIONS.includes(selectedVersion)
+      ? selectedVersion
+      : DEFAULT_DAFFODIL_VERSION
+
+  return SUPPORTED_DAFFODIL_VERSIONS.map((version) => {
+    const isSelected = version === effectiveVersion
+    return `<option value="${version}"${isSelected ? ' selected' : 
''}>${version}</option>`
+  }).join('')
+}
+
 const defaultConf = getConfig({
   name: 'Wizard Config',
   request: 'launch',
@@ -662,7 +684,9 @@ class LaunchWizard {
         <input class="file-input" value="${defaultValues.debugServer}" 
id="debugServer"/>
 
         <p id="dfdlDaffodilVersionLabel" style="margin-top: 10px;" 
class="setting-description">Version (Daffodil Version):</p>
-        <input class="file-input" value="${dfdlDebugger.daffodilVersion}" 
id="dfdlDaffodilVersion">
+        <select class="file-input" style="width: 200px;" 
id="dfdlDaffodilVersion">
+          ${getDaffodilVersionOptions(dfdlDebugger.daffodilVersion)}
+        </select>
 
         <p id="dfdlDebuggerTimeoutLabel" style="margin-top: 10px;" 
class="setting-description">Timeout (should end with s, m or h):</p>
         <input class="file-input" value="${dfdlDebugger.timeout}" 
id="dfdlDebuggerTimeout">
diff --git a/src/launchWizard/script.js b/src/launchWizard/script.js
index 366ae663..e2bcf707 100644
--- a/src/launchWizard/script.js
+++ b/src/launchWizard/script.js
@@ -17,6 +17,15 @@
 
 // Retrieve vscode api - Doing this multiple times causes issues with the 
scripts
 const vscode = acquireVsCodeApi()
+const SUPPORTED_DAFFODIL_VERSIONS = [
+  '3.9.0',
+  '3.10.0',
+  '3.11.0',
+  '4.0.0',
+  '4.1.0',
+  '4.2.0',
+]
+const DEFAULT_DAFFODIL_VERSION = '4.2.0'
 
 // Function to get config index
 function getConfigIndex() {
@@ -681,8 +690,18 @@ async function updateConfigValues(config) {
   document.getElementById('dataEditorLogLevel').value =
     config.dataEditor.logging.level
 
-  document.getElementById('dfdlDaffodilVersion').value =
-    config.dfdlDebugger.daffodilVersion
+  const dfdlDaffodilVersionSelect = document.getElementById(
+    'dfdlDaffodilVersion'
+  )
+  if (dfdlDaffodilVersionSelect) {
+    const currentVersion =
+      config.dfdlDebugger?.daffodilVersion &&
+      SUPPORTED_DAFFODIL_VERSIONS.includes(config.dfdlDebugger.daffodilVersion)
+        ? config.dfdlDebugger.daffodilVersion
+        : DEFAULT_DAFFODIL_VERSION
+
+    dfdlDaffodilVersionSelect.value = currentVersion
+  }
   document.getElementById('dfdlDebuggerTimeout').value =
     config.dfdlDebugger.timeout
   document.getElementById('dfdlDebuggerLogFile').value =
diff --git a/src/tests/suite/daffodilDebugger.test.ts 
b/src/tests/suite/daffodilDebugger.test.ts
index bf3b3855..eaf2b317 100644
--- a/src/tests/suite/daffodilDebugger.test.ts
+++ b/src/tests/suite/daffodilDebugger.test.ts
@@ -120,13 +120,13 @@ async function getDaffodilVersionsToTest(): 
Promise<Array<string>> {
   const isAtLeastJdk17: boolean = parseFloat(javaHome?.version ?? '0') >= 17
 
   const dfdlVersions = ['3.10.0', '3.11.0']
-  if (isAtLeastJdk17) dfdlVersions.push('4.0.0')
+  if (isAtLeastJdk17) dfdlVersions.push('4.0.0', '4.1.0', '4.2.0')
   return dfdlVersions
 }
 
 /**
  * Populates the array of debugger configs with all debugger configs. If JDK 
>= 17 there
- * should be 6 and if JDK < 17 there should be 4. Each version of the debugger 
has two
+ * should be 10 and if JDK < 17 there should be 4. Each version of the 
debugger has two
  * configs, one for XML and one for JSON.
  */
 async function getDebuggerConfigs() {
@@ -198,11 +198,11 @@ async function checkDebug(
 
 /**
  * This function adds a number of tests to the suite for connecting to the 
debuggers.
- * Since we have 3 different versions of the debugger, each needs to be 
connected to
+ * Since we have multiple versions of the debugger, each needs to be connected 
to
  * twice. Once for outputting XML and one for outputting JSON. Not sure if 
this is
  * a common way to add tests to a test suite but it seemed better and more 
efficient
  * than making a single separate test for each combination of the debugger 
plus infoset
- * format. Especially since two of the combinations can only be ran if the JDK 
version
+ * format. Especially since some of the combinations can only be ran if the 
JDK version
  * being used is >= 17.
  */
 async function addDebuggerRunningTests(
diff --git a/src/tests/suite/version.test.ts b/src/tests/suite/version.test.ts
index b6cd9b6a..a628173a 100644
--- a/src/tests/suite/version.test.ts
+++ b/src/tests/suite/version.test.ts
@@ -20,6 +20,10 @@ import * as fs from 'fs'
 import * as path from 'path'
 import { PROJECT_ROOT } from './common'
 import { parse as jsoncParse } from 'jsonc-parser'
+import {
+  DEFAULT_DAFFODIL_VERSION,
+  getDaffodilVersionOptions,
+} from '../../launchWizard/launchWizard'
 
 suite('Daffodil Version', () => {
   const versionFile = path.join(PROJECT_ROOT, 'src/version.ts')
@@ -40,5 +44,28 @@ suite('Daffodil Version', () => {
       const version = require('../../version').LIB_VERSION
       assert.strictEqual(version, packageMapped.version)
     })
+
+    test('launch wizard exposes the supported Daffodil version options', () => 
{
+      const options = getDaffodilVersionOptions('4.1.0')
+
+      assert.ok(options.includes('value="3.9.0"'))
+      assert.ok(options.includes('value="3.10.0"'))
+      assert.ok(options.includes('value="3.11.0"'))
+      assert.ok(options.includes('value="4.0.0"'))
+      assert.ok(options.includes('value="4.1.0"'))
+      assert.ok(options.includes('value="4.2.0"'))
+      assert.ok(options.includes('selected'))
+      assert.ok(options.includes('>4.1.0<'))
+    })
+
+    test('launch wizard defaults the Daffodil version to 4.2.0', () => {
+      assert.strictEqual(DEFAULT_DAFFODIL_VERSION, '4.2.0')
+      assert.ok(
+        getDaffodilVersionOptions(undefined).includes('value="4.2.0" selected')
+      )
+      assert.ok(
+        getDaffodilVersionOptions('9.9.9').includes('value="4.2.0" selected')
+      )
+    })
   })
 })
diff --git a/src/utils.ts b/src/utils.ts
index ca66f66d..b3f0e630 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -190,7 +190,7 @@ export function getConfig(jsonArgs: object): 
vscode.DebugConfiguration {
       },
     }),
     dfdlDebugger: defaultConf.get('dfdlDebugger', {
-      daffodilVersion: '3.11.0',
+      daffodilVersion: '4.2.0',
       timeout: '10s',
       logging: {
         level: 'INFO',

Reply via email to