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

jeremyyao 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 ae5a5e3  Document DFDL relevant items in src/language and 
src/language/providers/utils.ts
ae5a5e3 is described below

commit ae5a5e3a10b80778ef91237be66139430b246433
Author: Jeremy Yao <[email protected]>
AuthorDate: Wed Jan 7 20:00:13 2026 -0500

    Document DFDL relevant items in src/language and 
src/language/providers/utils.ts
    
    Closes #1487
    Closes #1494
---
 src/language/dfdl.ts                     |  45 +++
 src/language/index.ts                    |  15 +
 src/language/intellisense-development.md |  75 +++--
 src/language/providers/utils.ts          | 469 ++++++++++++++++++++++++++++++-
 4 files changed, 578 insertions(+), 26 deletions(-)

diff --git a/src/language/dfdl.ts b/src/language/dfdl.ts
index f940ee1..366211a 100644
--- a/src/language/dfdl.ts
+++ b/src/language/dfdl.ts
@@ -15,6 +15,21 @@
  * limitations under the License.
  */
 
+/**
+ * DFDL (Data Format Description Language) Language Support Module
+ *
+ * This module provides comprehensive language support for DFDL schemas 
including:
+ * - Semantic tokenization and syntax highlighting for XML and XPath 
expressions
+ * - Completion providers for DFDL elements, attributes, and attribute values
+ * - Hover providers showing documentation for DFDL constructs
+ * - Auto-closing of XML tags
+ * - Diagnostic reporting for XPath expressions and DFDL schema validation
+ * - Integration with the DFDL Language Server Protocol (LSP) implementation
+ *
+ * DFDL is used to describe the structure of binary and text data formats,
+ * allowing parsers to convert between data and XML representations.
+ */
+
 import * as vscode from 'vscode'
 import * as fs from 'fs'
 import { getElementCompletionProvider } from './providers/elementCompletion'
@@ -24,7 +39,24 @@ import { getAttributeValueCompletionProvider } from 
'./providers/attributeValueC
 import { getCloseElementSlashProvider } from './providers/closeElementSlash'
 import { getAttributeHoverProvider } from './providers/attributeHover'
 
+/**
+ * Activates DFDL language features and registers all language service 
providers.
+ *
+ * This is the main entry point that wires up the extension's language 
features by calling
+ * VS Code registration APIs (e.g., `registerCompletionItemProvider`, 
`registerHoverProvider`).
+ * It connects the provider implementations to VS Code specifically for the 
DFDL language.
+ *
+ * The activation process:
+ * 1. Loads the DFDL General Format schema for element completion data
+ * 2. Registers completion providers for elements, attributes, and attribute 
values
+ * 3. Registers providers for auto-closing tags (both regular and self-closing)
+ * 4. Registers hover provider for showing attribute documentation
+ *
+ * @param context - VS Code extension context for managing subscriptions and 
resources
+ */
 export function activate(context: vscode.ExtensionContext) {
+  // Load the DFDL General Format schema file which contains
+  // the structure definitions used for element completion suggestions
   let dfdlFormat = fs
     .readFileSync(
       context.asAbsolutePath(
@@ -33,12 +65,25 @@ export function activate(context: vscode.ExtensionContext) {
     )
     .toLocaleString()
 
+  // Register all language service providers with VS Code
+  // Each provider will be automatically disposed when the extension 
deactivates
   context.subscriptions.push(
+    // Suggests child elements / element tags based on DFDL schema structure
     getElementCompletionProvider(dfdlFormat),
+
+    // Suggests attribute names when typing inside an element tag
     getAttributeCompletionProvider(),
+
+    // Provides completion suggestions for attribute values (e.g., enumerated 
values, booleans)
     getAttributeValueCompletionProvider(),
+
+    // Automatically inserts closing tags when user types '>' after an opening 
tag
     getCloseElementProvider(),
+
+    // Handles self-closing tags when user types '/' (creates '<element/>' 
syntax)
     getCloseElementSlashProvider(),
+
+    // Shows documentation and available values when hovering over attributes
     getAttributeHoverProvider()
   )
 }
diff --git a/src/language/index.ts b/src/language/index.ts
index b21d310..c5819cf 100644
--- a/src/language/index.ts
+++ b/src/language/index.ts
@@ -14,5 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+/**
+ * Language services module for DFDL (Data Format Description Language) and 
TDML (Test Data Markup Language).
+ *
+ * This module serves as the main entry point for language support features 
including:
+ * - Language server initialization and management
+ * - Semantic tokenization and syntax highlighting
+ * - Completion providers for elements, attributes, and XPath expressions
+ * - Hover providers for documentation
+ * - Diagnostics and validation
+ */
+
+// Export DFDL language services including lexer, providers, and language 
server setup
 export * as dfdl from './dfdl'
+
+// Export TDML language services for test data markup language support
 export * as tdml from './tdml'
diff --git a/src/language/intellisense-development.md 
b/src/language/intellisense-development.md
index bd27782..e94d71d 100644
--- a/src/language/intellisense-development.md
+++ b/src/language/intellisense-development.md
@@ -17,7 +17,7 @@
 
 # Intellisense
 
-This document contains an overview of how intellisense works as well as a 
general view of the architecture of the code.
+This document contains an overview of how Intellisense works, as well as a 
general view of the architecture of the code.
 
 ## Table of Contents
 
@@ -43,15 +43,16 @@ This document contains an overview of how intellisense 
works as well as a genera
         - [Intellisense Data Files (intellisense 
subdirectory)](#intellisense-data-files-intellisense-subdirectory)
           - [attributeItems.ts](#attributeitemsts)
           - [attributeValueItems.ts](#attributevalueitemsts)
+        - [src/language/dfdl.ts](#srclanguagedfdlts)
     - [TDML](#tdml)
 
 ### General Intellisense Concepts
 
 #### Providers
 
-Providers in the VS Code API are extension points that let you plug specific 
language or editor features into the editor’s pipeline (e.g., completions, 
hovers, formatting). Proviers are implemented and then registered in the code 
which gets then gets called depending on the situation the provider activates.
+Providers in the VS Code API are extension points that let you plug specific 
language or editor features into the editor’s pipeline (e.g., completions, 
hovers, formatting). Providers are implemented and then registered in the code, 
which then gets called depending on the situation in which the provider 
activates.
 
-Many providers exist. Relevant ones that are used extensively in the code 
pertaining to IntelliSense functionality include `completionItemProvider` which 
provide code suggestions and `hoverProvider` which provider hover information. 
More information can be found at 
<https://code.visualstudio.com/api/references/vscode-api>.
+Many providers exist. Relevant ones that are used extensively in the code 
about IntelliSense functionality include `completionItemProvider`, which 
provides code suggestions, and `hoverProvider`, which provides hover 
information. For more information, visit 
<https://code.visualstudio.com/api/references/vscode-api>.
 
 #### Registration
 
@@ -63,11 +64,11 @@ This section focuses on the `dfdl` Intellisense 
implementation.
 
 #### High-level dfdl Intellisense Overview
 
-This section providers a high-level view of the architecture of all relevant 
code items pertaining to the `dfdl` IntelliSense functionality.
+This section provides a high-level view of the architecture of all relevant 
code items about the `dfdl` IntelliSense functionality.
 
 ##### Provider Registration (Start Here)
 
-`src/language/dfdl.ts` is the starting point. It wires up the extension’s 
language features by calling VS Code registration APIs (e.g., 
`registerCompletionItemProvider`, `registerHoverProvider`, and similar) that 
are then customized as functions that provide customized provider functinoality.
+`src/language/dfdl.ts` is the starting point. It wires up the extension’s 
language features by calling VS Code registration APIs (e.g., 
`registerCompletionItemProvider`, `registerHoverProvider`, and similar) that 
are then customized as functions that provide customized provider functionality.
 
 In other words, `dfdl.ts` connects the provider implementations to VS Code for 
the DFDL language.
 
@@ -75,25 +76,21 @@ In other words, `dfdl.ts` connects the provider 
implementations to VS Code for t
 
 Autocompletion logic is split into multiple provider modules under 
`src/language/providers/`, each handling different completion scenarios.
 
-- `elementCompletion.ts` -- suggests child elements / element tags.
+- `elementCompletion.ts` -- suggests child elements/element tags.
 - `attributeCompletion.ts` -- suggests attribute names when inside an element.
 - `attributeValueCompletion.ts` -- provides completion suggestions for 
attribute values (e.g., enumerated values).
 - `closeElement.ts`, `closeElementSlash.ts` -- completions for closing tags 
and slash completions.
 - `attributeHover.ts` -- hover provider that shows attribute 
documentation/available attributes.
 
-It should be noted that there are many `registerCompletionItemProvider` calls. 
The implemented `completionItemProvider`s each contain logic to determine 
whether or not it the provider is relevant to a given situation or not.
+It should be noted that there are many `registerCompletionItemProvider` calls. 
The implemented `completionItemProvider`s each contain logic to determine 
whether or not the provider is relevant to a given situation.
 
 ##### Helpers + Vocabulary
 
-`src/language/providers/utils.ts` and 
`src/language/providers/intellisense/commonItems.ts` contain shared helpers for 
constructing CompletionItem objects, and context parsing utilities used by many 
providers. For `src/language/providers/intellisense/commonItems.ts` and tracing 
through usage, it's used by `attributeCompletion.ts` and `elementCompletion.ts`.
-
-`src/rootCompletion/utils.ts` contains utilities used for root-level 
completion logic (common completion primitives).
-
-The code relies on project classes like schemaData (found under 
src/classes/schemaData.ts) and other "model" classes to know DFDL vocabulary 
(elements, attributes, properties). Those model classes hold the authoritative 
lists that the providers consult when building suggestions.
+`src/language/providers/utils.ts` contains shared helpers for constructing 
CompletionItem objects, and context parsing utilities used by many providers. 
It also contains utilities used for root-level completion logic (common 
completion primitives).
 
 ##### Context Parsing
 
-Providers do lightweight parsing of the current document and cursor context 
(often using a small tokenizer / utility functions) to determine whether the 
cursor is:
+Providers do lightweight parsing of the current document and cursor context 
(often using a small tokenizer/utility functions) to determine whether the 
cursor is:
 
 - inside an element start tag
 - inside attribute name or value
@@ -104,7 +101,7 @@ This context detection guides which provider runs and how 
it filters suggestions
 
 ##### Namespace / Prefix Handling
 
-The code is able to determine the current element's namespace and the 
suggestions are able to insert the correct namespace or omit the namespace 
accordinly for attribute and element suggestions
+The code can determine the current element's namespace, and the suggestions 
can insert the correct namespace or omit the namespace accordingly for 
attribute and element suggestions.
 
 ##### Completions Construction
 
@@ -119,7 +116,7 @@ Some items use resolveCompletionItem logic if additional 
data must be computed a
 
 ##### Hover / Documentation
 
-`attributeHover.ts` forms hover messages (Markdown strings) describing 
attributes available on a tag, DFDL property documentation, etc. Hover resolves 
current element context then gathers attribute docs and returns a 
`vscode.Hover` object.
+`attributeHover.ts` forms hover messages (Markdown strings) describing 
attributes available on a tag, DFDL property documentation, etc. Hover resolves 
the current element context, then gathers attribute docs and returns a 
`vscode.Hover` object.
 
 Hover tooltips can be found under `attributeHoverValues()` in 
`attributeHoverItems.ts`.
 
@@ -137,7 +134,7 @@ Hover tooltips can be found under `attributeHoverValues()` 
in `attributeHoverIte
 
 **Key Functionality:**
 
-- Provides context-aware attribute suggestions based on current XML element 
type
+- Provides context-aware attribute suggestions based on the current XML 
element type
 - Suggests valid DFDL attributes for DFDL-specific elements
 - Suggests XSD attributes for XML Schema elements
 - Filters out already-present attributes to avoid duplicates
@@ -149,7 +146,7 @@ Hover tooltips can be found under `attributeHoverValues()` 
in `attributeHoverIte
 - `getAttributeCompletionProvider()`: DFDL document provider
 - `getTDMLAttributeCompletionProvider()`: TDML document provider
 - `getDefinedTypes()`: Scans for xs:simpleType and xs:complexType declarations
-- `prunedDuplicateAttributes()`: Removes attributes already present on element
+- `prunedDuplicateAttributes()`: Removes attributes already present on the 
element
 
 **Trigger:** Space (` `) or newline (`\n`)
 
@@ -197,8 +194,8 @@ Hover tooltips can be found under `attributeHoverValues()` 
in `attributeHoverIte
 **Attribute Categories:**
 
 - XSD Core Attributes (name, ref, type, minOccurs, maxOccurs)
-- DFDL Length Properties (dfdl:length, dfdl:lengthKind, dfdl:lengthUnits)
-- DFDL Encoding Properties (dfdl:encoding, dfdl:encodingErrorPolicy)
+- DFDL Length Properties (dfdl: length, dfdl:lengthKind, dfdl:lengthUnits)
+- DFDL Encoding Properties (dfdl: encoding, dfdl:encodingErrorPolicy)
 - DFDL Text/Binary Representation
 - DFDL Separators/Delimiters
 - DFDL Calendar/Date
@@ -240,6 +237,46 @@ Hover tooltips can be found under `attributeHoverValues()` 
in `attributeHoverIte
 - `noChoiceAttributes`: List of attributes without predefined choices
 - `attributeValues(attributeName, startPos, additionalTypes)`: Inserts 
appropriate snippet at cursor
 
+##### src/language/dfdl.ts
+
+**Purpose:** The central registration file for all DFDL language features.
+
+**Key Functionality:**
+
+- **Starting Point:** It is executed during extension activation and registers 
the completion and hover providers with VS Code. This file is the “entry point” 
for Language features. If you want to add providers, this is the place to 
update.
+- **Central Rgistration Point:**It imports provider modules (element, 
attribute, attributeValue, closeElement, attributeHover, etc.) and registers 
them with appropriate trigger characters (e.g., `<`, `:`, `"`, `=`, `/`, 
`whitespace`).
+- **Wiring:**It does not perform completion logic itself — rather it wires VS 
Code events to the exported provider objects/functions in the provider modules.
+- **DFDL Language Provider:**When VS Code triggers a provider callback for the 
DFDL language, the registered provider function from the corresponding module 
is invoked.
+
+##### src\language\providers\utils.ts
+
+**Purpose:** Central utility module providing common functions used across all 
completion and hover providers.
+
+**Key Functionality:**
+
+- **Position & Context Detection:** Functions to determine cursor position 
within XML documents, identify element types, and detect XPath contexts
+- **Element & Attribute Parsing:** Extract element names, attributes, and 
ranges from document text
+- **XML Navigation:** Working with XML DOM structures using xml2js, finding 
nearest open tags, parent elements
+- **Completion Item Creation:** Building VS Code completion items with 
appropriate styling and documentation
+- **Context Detection:** Functions to determine if cursor is within quotes, 
braces, XPath expressions, or after specific characters
+- **Namespace Handling:** Detecting and managing XML namespace prefixes (xs:, 
dfdl:, etc.)
+
+**Key Classes:**
+
+- `XmlItem`: Encapsulates parsed XML element information (name, namespace, 
attributes)
+
+**Key Functions:**
+
+- `nearestOpen()`: Finds the nearest unclosed XML element at the cursor 
position
+- `checkTagOpen()`: Determines if a tag is open at a given position with 
attribute discovery
+- `cursorWithinQuotes()`: Detects if the cursor is inside attribute value 
quotes
+- `getNsPrefix()`: Retrieves namespace prefix for schema elements
+- `createCompletionItem()`: Creates VS Code completion items from intellisense 
data
+
+**Provider Checks:**
+
+If you look at the structure of the `dfdl.ts`, it registers multiple 
providers. There are checks to determine whether or not a certain provider's 
autocomplete suggestions apply to the situation. This file's helper functions 
provide a check criterion.
+
 ### TDML
 
 This section focuses on the `tdml` Intellisense implementation. It should be 
noted that the functionality is currently unused.
diff --git a/src/language/providers/utils.ts b/src/language/providers/utils.ts
index 5304f8a..be8318b 100644
--- a/src/language/providers/utils.ts
+++ b/src/language/providers/utils.ts
@@ -15,13 +15,35 @@
  * limitations under the License.
  */
 
+/**
+ * Utility Functions for Language Service Providers
+ *
+ * This module provides common utility functions used across all completion 
and hover providers
+ * for DFDL and TDML language support. Key functionality includes:
+ *
+ * - Position and context detection: Determining cursor context within XML 
documents
+ * - Element and attribute parsing: Extracting names and ranges from document 
text
+ * - XML parsing and navigation: Working with XML DOM structures
+ * - Completion item creation: Building VS Code completion items with 
appropriate styling
+ * - XPath detection: Identifying when cursor is within an XPath expression
+ *
+ * These utilities are shared between DFDL and TDML providers to ensure 
consistent behavior
+ * and reduce code duplication.
+ */
+
 import * as vscode from 'vscode'
 import { isXPath } from '../semantics/dfdlExt'
 import { xml2js } from 'xml-js'
 
+// Regular expression to match XML schema elements with optional namespace 
prefixes
+// Matches patterns like: <schema>, </schema>, <xs:schema>, <xsd:schema>
 const schemaPrefixRegEx = new RegExp('</?(|[^ ]+:)schema')
 
-//List of high level dfdl element items
+/**
+ * List of high-level DFDL schema element names.
+ * These are the primary structural elements that can appear in a DFDL schema.
+ * Used for element completion suggestions and validation.
+ */
 const items = [
   'element',
   'sequence',
@@ -50,52 +72,85 @@ const items = [
   'import',
 ]
 
+/**
+ * Represents an XML element with its name, namespace, and attributes.
+ * Used to encapsulate parsed XML element information for provider logic.
+ */
 export class XmlItem {
   private _itemName: string = 'none'
   private _itemNS: string = 'none'
   private _itemAttributes: string[] = []
 
+  /** Gets the XML element name (e.g., "element", "sequence") */
   public get itemName() {
     return this._itemName
   }
 
+  /** Sets the XML element name */
   public set itemName(name: string) {
     this._itemName = name
   }
 
+  /** Gets the namespace prefix (e.g., "xs", "dfdl") */
   public get itemNS() {
     return this._itemNS
   }
 
+  /** Sets the namespace prefix */
   public set itemNS(nameSpace: string) {
     this._itemNS = nameSpace
   }
 
+  /** Sets the list of attribute names for this element */
   public set itemAttributes(attributeNames: string[]) {
     this._itemAttributes = attributeNames
   }
 
+  /** Gets the list of attribute names for this element */
   public get itemAttributes() {
     return this._itemAttributes
   }
 }
 
+/**
+ * Returns the list of high-level DFDL element names.
+ * @returns Array of element name strings
+ */
 export function getItems() {
   return items
 }
 
+/**
+ * Retrieves the namespace prefix used for XML Schema elements in the document.
+ * Looks at the beginning of the document to find schema declarations.
+ *
+ * @param document - The VS Code text document
+ * @returns The namespace prefix (e.g., "xs", "xsd") or default empty string
+ */
 export function getSchemaNsPrefix(document: vscode.TextDocument) {
   const pos = new vscode.Position(0, 0)
   return getNsPrefix(document, pos)
 }
 
-// default namespace in the event that a namespace was not found
+/**
+ * Default namespace prefix when no explicit prefix is found.
+ * Empty string represents the default (unprefixed) namespace.
+ */
 export const defaultXsdNsPrefix = ''
 
-// dfdl namespace for dfdl format element in non dfdl tags
+/**
+ * DFDL namespace prefix used for DFDL-specific format elements
+ * in otherwise standard XML Schema elements.
+ */
 export const dfdlDefaultPrefix = 'dfdl:'
 
-// Function to insert snippet to active editor
+/**
+ * Inserts a snippet into the active text editor at the specified position.
+ * Used to programmatically insert text templates with tab stops and 
placeholders.
+ *
+ * @param snippetString - The snippet text with VS Code snippet syntax ($1, 
$2, etc.)
+ * @param backpos - The position where the snippet should be inserted
+ */
 export function insertSnippet(snippetString: string, backpos: vscode.Position) 
{
   vscode.window.activeTextEditor?.insertSnippet(
     new vscode.SnippetString(snippetString),
@@ -103,6 +158,16 @@ export function insertSnippet(snippetString: string, 
backpos: vscode.Position) {
   )
 }
 
+/**
+ * Counts the number of lines from the current position back to the opening 
tag of a specified element.
+ * Searches backwards through the document to find the nearest opening tag 
that matches the given tag name.
+ * Skips closing tags and self-closing tags.
+ *
+ * @param document - The VS Code text document
+ * @param position - The current cursor position
+ * @param tag - The element tag name to search for (without namespace prefix)
+ * @returns The number of lines between the position and the opening tag, or 
-1 if not found
+ */
 export function lineCount(
   document: vscode.TextDocument,
   position: vscode.Position,
@@ -112,12 +177,14 @@ export function lineCount(
   let lineCount = 0
   let nsPrefix = getNsPrefix(document, position)
 
+  // Search backwards through the document
   while (lineNum !== 0) {
     --lineNum
     ++lineCount
 
     const triggerText = document.lineAt(lineNum).text
 
+    // Check if this line contains the opening tag (not a closing tag or 
self-closing tag)
     if (
       triggerText.includes('<' + nsPrefix + tag) &&
       !triggerText.includes('</' + nsPrefix + tag) &&
@@ -129,16 +196,27 @@ export function lineCount(
   return lineCount
 }
 
+/**
+ * Finds the nearest open (unclosed) XML element at the cursor position.
+ * Searches through the list of known DFDL elements to determine which element
+ * the cursor is currently inside of. This is used to provide context-aware 
completions.
+ *
+ * @param document - The VS Code text document
+ * @param position - The current cursor position
+ * @returns XmlItem containing the element name, namespace, and attributes, or 
empty XmlItem if none found
+ */
 export function nearestOpen(
   document: vscode.TextDocument,
   position: vscode.Position
 ) {
   let xmlItem = new XmlItem()
+  // Early return for empty document
   if (document.lineCount === 1 && position.character === 0) {
     return xmlItem
   }
   const nsPrefix = getNsPrefix(document, position)
 
+  // Check each known DFDL element to see if the cursor is inside it
   for (let i = 0; i < items.length; ++i) {
     let [isTagOpen, isDfdlNs, attributeNames] = checkTagOpen(
       document,
@@ -147,6 +225,7 @@ export function nearestOpen(
       items[i]
     )
     if (isTagOpen) {
+      // Set the appropriate namespace (DFDL-specific or schema default)
       if (isDfdlNs) {
         xmlItem.itemNS = 'dfdl:'
       } else {
@@ -160,6 +239,44 @@ export function nearestOpen(
   return xmlItem
 }
 
+/**
+ * Finds the nearest matching opening tag for a set of known "items" relative 
to a given document position.
+ *
+ * The function searches backwards from a provided starting line/column to 
locate an opening tag that matches
+ * one of the known items (the `items` array referenced in the implementation) 
with the requested namespace prefix.
+ * It returns a tuple describing the found tag name (without namespace 
prefix), the line index where it was found,
+ * and the character index of the tag's opening '<' on that line.
+ *
+ * Search behavior:
+ * - If the trigger line contains multiple items and the start position lies 
inside the same line's tag range,
+ *   the function searches backward within the trigger line for the previous 
'<' and attempts to match a tag there.
+ * - Otherwise, the function walks upward line-by-line from `startLine` 
(adjusting if `startLine` equals the
+ *   trigger line and the cursor is exactly at a '<' or the trigger line is 
blank), skipping self-closing tags (`/>`),
+ *   and checking each line for an opening tag that matches one of the known 
items.
+ * - Before checking a line it ignores lines containing closing-tag syntax 
(`</`) unless the cursor is within
+ *   the tag's inner content and both opening and closing tags appear on the 
same line; in that case the
+ *   function may return that tag if the cursor lies between the `>` and `</`.
+ * - The namespace prefix is recalculated from the document/position during 
the upward search (via `getNsPrefix`).
+ *
+ * Edge cases & return value:
+ * - If a match is found, returns `[itemName, lineIndex, charIndex]` where:
+ *     - itemName is the matched item string (without the namespace prefix),
+ *     - lineIndex is a 0-based line number where the opening '<' appears,
+ *     - charIndex is the 0-based character index of that opening '<' on the 
line.
+ * - If no matching opening tag is found, returns `['none', 0, 0]`.
+ *
+ * Notes:
+ * - The function depends on external helpers and data: `items` (array of 
valid tag names),
+ *   `getItemsOnLineCount(text)`, and `getNsPrefix(document, position)`.
+ * - Indices and positions are zero-based (compatible with 
`vscode.TextDocument` / `vscode.Position`).
+ *
+ * @param document - The TextDocument in which to search.
+ * @param position - The trigger Position (usually the cursor position) used 
for namespace inference and context.
+ * @param nsPrefix - The current namespace prefix to use when matching tags 
(may be recalculated during search).
+ * @param startLine - The 0-based line index from which to begin the backward 
search.
+ * @param startPos - The 0-based character index on `startLine` from which to 
begin searching (used for same-line logic).
+ * @returns A tuple of `[matchedItemName, lineIndex, charIndex]`, or `['none', 
0, 0]` if nothing is found.
+ */
 export function nearestTag(
   document: vscode.TextDocument,
   position: vscode.Position,
@@ -241,6 +358,43 @@ export function nearestTag(
   return ['none', 0, 0]
 }
 
+/**
+ * Determines whether the XML/DFDL start tag for a given namespace prefix and 
tag name
+ * is currently "open" at the provided document position, and returns any 
attribute
+ * names found on that open tag.
+ *
+ * The function inspects the current and preceding lines to locate the nearest 
opening
+ * tag that matches "<{nsPrefix}{tag}" (falls back to "dfdl:" prefix if 
necessary).
+ * It handles both single-line tags and multi-line start tags:
+ * - For single-line tags it verifies the cursor position falls within the 
tag's
+ *   attribute region (between the start '<...' and the closing '>' if 
present).
+ * - For multi-line tags (start tag is present but its '>' is not on the same 
line),
+ *   it defers to checkMultiLineTag to determine openness across multiple 
lines.
+ *
+ * Behavior summary:
+ * - Scans backward when the current line contains few XML items to find the 
line
+ *   that actually contains the tag start.
+ * - Detects and normalizes a DFDL-specific 'dfdl:' prefix when the provided 
prefix
+ *   does not match but a 'dfdl:' occurrence is found.
+ * - If the tag is considered open at the given position, collects attribute 
names
+ *   by calling getAttributeNames(document, position, nsPrefix, tag).
+ *
+ * Notes and side effects:
+ * - The nsPrefix parameter is reassigned locally if a 'dfdl:' fallback is 
detected;
+ *   this does not mutate any caller-owned object but affects subsequent 
internal checks.
+ * - Relies on helper functions getItemsOnLineCount, getAttributeNames and
+ *   checkMultiLineTag as well as vscode.TextDocument.lineAt for text access.
+ * - Returns quickly if the tag cannot be located or the position is outside 
the tag.
+ *
+ * @param document - The vscode.TextDocument to inspect.
+ * @param position - The vscode.Position (cursor) used to determine whether 
the tag is open.
+ * @param nsPrefix - Expected namespace prefix (e.g. "dfdl:" or custom prefix) 
to match before the tag name.
+ * @param tag - The tag name to search for (without angle brackets or prefix).
+ * @returns A tuple containing:
+ *   - [0] boolean: true if the specified start tag is open at the given 
position, false otherwise.
+ *   - [1] boolean: true if a 'dfdl:' prefix was detected/used instead of the 
provided nsPrefix.
+ *   - [2] string[]: array of attribute names found on the open tag (empty if 
tag not open).
+ */
 export function checkTagOpen(
   document: vscode.TextDocument,
   position: vscode.Position,
@@ -351,6 +505,43 @@ export function checkTagOpen(
   )
 }
 
+/**
+ * Determine the namespace prefix to use for a given item name.
+ *
+ * Uses a set of string-matching rules (checked in order) to compute the
+ * prefix. If no rule matches, the provided `nsPrefix` is returned unchanged.
+ *
+ * @param item - The item name to evaluate. Matching is case-sensitive.
+ * @param nsPrefix - The default namespace prefix to return when no rule 
applies.
+ *
+ * @returns The computed prefix. Possible values include:
+ * - the original `nsPrefix` (default)
+ * - `'dfdl:'` for certain DFDL-related items
+ * - `'?'` specifically for `"xml version"`
+ * - `''` (empty string) for fully-qualified DFDL element names
+ *
+ * @remarks
+ * Rules (applied in order; later rules override earlier ones):
+ * 1. Default: return `nsPrefix`.
+ * 2. If `item` is one of `'assert'`, `'discriminator'`, `'defineFormat'`, 
`'format'`,
+ *    or if `item` contains `'Variable'` or `'scape'`, set prefix to `'dfdl:'`.
+ * 3. If `item === 'xml version'`, set prefix to `'?'`.
+ * 4. If `item` is one of `'dfdl:element'`, `'dfdl:sequence'`, 
`'dfdl:simpleType'`,
+ *    or `'dfdl:format'`, set prefix to the empty string `''`.
+ *
+ * Note that because rules are evaluated sequentially, a later rule can 
override
+ * an earlier one. For example, `'dfdl:format'` will result in `''` even though
+ * it contains `'format'` and would match the earlier `'format'` rule.
+ *
+ * @example
+ * getItemPrefix('assert', 'ns:') // returns 'dfdl:'
+ * @example
+ * getItemPrefix('xml version', 'ns:') // returns '?'
+ * @example
+ * getItemPrefix('dfdl:element', 'ns:') // returns ''
+ * @example
+ * getItemPrefix('otherItem', 'ns:') // returns 'ns:'
+ */
 export function getItemPrefix(item: string, nsPrefix: string) {
   let itemPrefix = nsPrefix
 
@@ -380,6 +571,43 @@ export function getItemPrefix(item: string, nsPrefix: 
string) {
   return itemPrefix
 }
 
+/**
+ * Determine whether the cursor is located within a multi-line opening tag for 
a given namespaced tag,
+ * and collect attribute names if the opening tag spans multiple lines.
+ *
+ * The function:
+ * - Treats the tag as a DFDL tag if nsPrefix === 'dfdl:' (the returned 
isDfdlTag will be true).
+ * - Immediately returns [false, isDfdlTag, []] when more than one item exists 
on the current line (itemsOnLine > 1).
+ * - If the current line is blank, searches upward until a non-blank line is 
found.
+ * - If the cursor appears after a closing tag ("</...") or on a self-closing 
tag ("/>") on that line, returns false.
+ * - Searches upward from the non-blank line to find an opening tag that 
matches "<" + nsPrefix + tag.
+ * - When an opening tag line is found, concatenates following lines until a 
'>' is encountered (or document end).
+ * - If both the opening tag and the '>' are present in the concatenated text, 
calls getAttributeNames(...) to
+ *   collect attribute names and returns [true, isDfdlTag, attributeNames].
+ * - Otherwise returns [false, isDfdlTag, []].
+ *
+ * Notes and edge cases:
+ * - tagPos and tagLine are accepted by the signature but are not used by the 
function logic.
+ * - The search upward stops at the top of the document (openTagLine > 0) and 
the forward search for '>' stops
+ *   at document.lineCount.
+ * - The function never mutates the provided TextDocument or Position; it only 
reads lines.
+ * - getAttributeNames is invoked only when an opening tag and a closing '>' 
for the start tag are found;
+ *   attributeNames is an empty array otherwise.
+ *
+ * @param document - The vscode.TextDocument to inspect.
+ * @param position - The current cursor position within the document.
+ * @param itemsOnLine - Number of syntactic items on the current line; if > 1 
the function exits early.
+ * @param nsPrefix - Namespace prefix string (e.g. "dfdl:" or ""), used when 
matching the tag name.
+ * @param tagPos - (Unused) numeric position of the tag in the original call 
site; preserved for compatibility.
+ * @param tagLine - (Unused) original line index of the tag; preserved for 
compatibility.
+ * @param tag - The tag name (without prefix) to search for (e.g. "sequence", 
"element").
+ * @param isDfdlTag - Optional input flag; when nsPrefix === "dfdl:" this will 
be set to true and returned.
+ *
+ * @returns A tuple:
+ *   - [0] boolean: true when a multi-line opening tag for the given 
namespaced tag was found and closed with '>',
+ *   - [1] boolean: isDfdlTag flag indicating whether the tag is a DFDL tag,
+ *   - [2] string[]: an array of attribute names extracted from the multi-line 
tag (empty if none or not multi-line).
+ */
 export function checkMultiLineTag(
   document: vscode.TextDocument,
   position: vscode.Position,
@@ -460,6 +688,26 @@ export function checkMultiLineTag(
 }
 
 //returns an empty value or a prefix plus a colon
+/**
+ * Get the XML namespace prefix used for the XSD/schema in the given document 
at or above the supplied position.
+ *
+ * Scans lines starting from the top of the document down to the line of 
`position` (inclusive) and returns the
+ * first capture group produced by `schemaPrefixRegEx`. The captured value may 
be an empty string or a prefix
+ * including a trailing colon (e.g. "xsd:"). If no matching schema declaration 
is found (or if `position.line`
+ * is 0), the function returns `defaultXsdNsPrefix`.
+ *
+ * @param document - The VS Code text document to search for a schema 
namespace prefix.
+ * @param position - The position whose line number is used as the inclusive 
upper bound for the search.
+ * @returns The namespace prefix string (possibly empty or including a colon) 
if found; otherwise `defaultXsdNsPrefix`.
+ *
+ * @remarks
+ * - This function relies on the module-level `schemaPrefixRegEx` to identify 
schema prefix declarations
+ *   and on `defaultXsdNsPrefix` as the fallback value.
+ * - The search proceeds from the start of the document to the given line and 
returns the first match encountered.
+ *
+ * @example
+ * // If a line near the top contains 
'xmlns:xsd="http://www.w3.org/2001/XMLSchema";', this may return 'xsd:'.
+ */
 export function getNsPrefix(
   document: vscode.TextDocument,
   position: vscode.Position
@@ -482,6 +730,41 @@ export function getNsPrefix(
   return defaultXsdNsPrefix
 }
 
+/**
+ * Collects the attribute names of an XML/HTML tag located at the given 
position in a VS Code text document.
+ *
+ * The function handles both single-line tags and tags that span multiple 
lines. If the tag at the
+ * supplied position is not a complete single-line tag, the function searches 
upward to find the
+ * opening tag line and then reads forward until it encounters a line 
containing `>` to assemble the
+ * full tag text. The assembled text is parsed and the attribute names are 
returned as a unique list.
+ *
+ * @param document - The vscode.TextDocument to read lines from.
+ * @param position - The vscode.Position indicating the starting line to 
inspect.
+ * @param nsPrefix - Namespace prefix expected before the tag name (e.g. 
`"ns:"` or `""`).
+ * @param tag - The tag name to locate (without angle brackets).
+ * @returns An array of unique attribute names found on the tag. Returns an 
empty array if no attributes are found or the tag cannot be parsed.
+ *
+ * @remarks
+ * - The search for the opening tag moves upward from the provided position 
until a line containing the
+ *   prefixed tag is found or the start of the document is reached.
+ * - Once the opening tag line is found, subsequent lines are appended until a 
closing `>` is encountered,
+ *   producing a single string that is parsed to extract attributes.
+ * - The function uses a parser to extract attributes and returns the 
attribute keys; duplicate names are
+ *   de-duplicated.
+ *
+ * @example
+ * // Single-line tag
+ * // <ns:tag attr1="a" attr2="b">
+ * // getAttributeNames(document, position, "ns:", "tag") -> ["attr1", "attr2"]
+ *
+ * @example
+ * // Multi-line tag
+ * // <ns:tag
+ * //   attr1="a"
+ * //   attr2="b"
+ * // >
+ * // getAttributeNames(document, position, "ns:", "tag") -> ["attr1", "attr2"]
+ */
 export function getAttributeNames(
   document: vscode.TextDocument,
   position: vscode.Position,
@@ -543,6 +826,44 @@ export function getAttributeNames(
   return attributeNames
 }
 
+/**
+ * Count opening tag-like items on a single line of text.
+ *
+ * Scans the provided line for '<' ... '>' pairs and counts occurrences that
+ * look like opening tags. The function ignores known non-opening constructs
+ * such as explicit closing tags, HTML/XML comments, and certain bracketed
+ * constructs. If an unmatched '<' (without a corresponding '>') is found,
+ * it is counted as one item and scanning stops.
+ *
+ * Special-case:
+ * - If the input contains the substring "schema" but does not contain
+ *   "schemaLocation", the function immediately returns 1.
+ *
+ * Excluded from counting (examples):
+ * - Constructs containing "</" (closing tags)
+ * - Comment markers "<!--" or "-->"
+ * - Constructs beginning with "<[" or "<!["
+ *
+ * @param triggerText - The line of text to analyze (expected to be a string).
+ * @returns The number of opening tag-like items found on the line 
(non-negative integer).
+ *
+ * @remarks
+ * - The function performs a simple, single-line scan and does not validate
+ *   tag names or nesting structure.
+ * - Time complexity is linear in the length of the input string.
+ *
+ * @example
+ * // returns 2
+ * getItemsOnLineCount("<a><b>");
+ *
+ * @example
+ * // returns 1
+ * getItemsOnLineCount("<a></a>");
+ *
+ * @example
+ * // returns 1 (special-case for "schema")
+ * getItemsOnLineCount("schema");
+ */
 export function getItemsOnLineCount(triggerText: String) {
   let itemsOnLine = 0
   let nextPos = 0
@@ -582,7 +903,19 @@ export function getItemsOnLineCount(triggerText: String) {
   return itemsOnLine
 }
 
-//Determines if the current curser is in XPath and dfdl intellisense should be 
turned off
+/**
+ * Determines if the cursor is currently positioned within an XPath expression.
+ * When the cursor is in XPath, DFDL element/attribute intellisense should be 
disabled
+ * and XPath-specific completion should be active instead.
+ *
+ * This is used to prevent DFDL completions from showing when the user is 
typing
+ * XPath expressions in attributes like dfdl:inputValueCalc, 
dfdl:outputValueCalc,
+ * dfdl:test, etc.
+ *
+ * @param document - The VS Code text document
+ * @param position - The cursor position to check
+ * @returns true if the cursor is within an XPath expression, false otherwise
+ */
 export function isInXPath(
   document: vscode.TextDocument,
   position: vscode.Position
@@ -590,6 +923,18 @@ export function isInXPath(
   return isXPath(position)
 }
 
+/**
+ * Verifies whether the character immediately before the cursor position is NOT
+ * the expected trigger character for a completion provider.
+ *
+ * This is used by completion providers to ensure they were actually triggered
+ * by the correct character and not by some other mechanism (like manual 
invocation).
+ *
+ * @param document - The VS Code text document
+ * @param position - The current cursor position
+ * @param triggerChar - The expected trigger character (e.g., '<', '>', '/', ' 
', '=')
+ * @returns true if the character before the cursor is NOT the trigger 
character, false otherwise
+ */
 export function isNotTriggerChar(
   document: vscode.TextDocument,
   position: vscode.Position,
@@ -605,6 +950,16 @@ export function isNotTriggerChar(
   }
 }
 
+/**
+ * Checks if the given trigger character indicates the end of an XML tag.
+ * Tag end characters are '/' (for self-closing tags) and '>' (for closing 
tags).
+ *
+ * This is used to determine when NOT to provide element name completions,
+ * since element names only make sense at the beginning of tags, not at the 
end.
+ *
+ * @param trigChar - The trigger character to check (typically from 
CompletionContext)
+ * @returns true if the character is '/' or '>', false otherwise
+ */
 export function isTagEndTrigger(trigChar: string | undefined) {
   if (trigChar == '/' || trigChar == '>') {
     return true
@@ -613,6 +968,18 @@ export function isTagEndTrigger(trigChar: string | 
undefined) {
   }
 }
 
+/**
+ * Determines if the cursor is positioned immediately after an equals sign (=).
+ * This typically indicates the user is about to enter an attribute value.
+ *
+ * Used to suppress certain completion providers (like element completion) when
+ * the user is in an attribute value context and should see attribute value
+ * completions instead.
+ *
+ * @param document - The VS Code text document
+ * @param position - The current cursor position
+ * @returns true if the cursor is directly after an '=' character, false 
otherwise
+ */
 export function cursorAfterEquals(
   document: vscode.TextDocument,
   position: vscode.Position
@@ -631,6 +998,24 @@ export function cursorAfterEquals(
   return false
 }
 
+/**
+ * Determines if the cursor is currently positioned within quoted attribute 
value text.
+ * Handles both single quotes (') and double quotes ("), and works across 
multiple lines
+ * for attribute values that span multiple lines.
+ *
+ * The function searches backwards to find the opening quote (preceded by '=') 
and forwards
+ * to find the closing quote, then checks if the cursor position falls within 
that range.
+ *
+ * This is crucial for:
+ * - Enabling attribute value completion providers
+ * - Disabling element/attribute name completion when inside values
+ * - Detecting XPath expressions within attribute values
+ *
+ * @param document - The VS Code text document
+ * @param position - The current cursor position
+ * @returns true if the cursor is inside a quoted attribute value (between 
opening and closing quotes),
+ *          false otherwise
+ */
 export function cursorWithinQuotes(
   document: vscode.TextDocument,
   position: vscode.Position
@@ -638,9 +1023,11 @@ export function cursorWithinQuotes(
   const quoteChar: string[] = ["'", '"']
   let startLine = position.line
 
+  // Check both single and double quotes
   for (let i = 0; i < quoteChar.length; ++i) {
     let currentText = document.lineAt(startLine).text
 
+    // If line contains '<' but no quotes, we're not in an attribute value
     if (
       currentText.includes('<') &&
       !currentText.includes("'") &&
@@ -652,6 +1039,7 @@ export function cursorWithinQuotes(
     if (currentText.includes(quoteChar[i])) {
       let textBeforeTrigger = currentText.substring(0, position.character)
 
+      // Check if cursor is before an attribute assignment
       if (
         currentText.indexOf('=' + quoteChar[i]) > position.character &&
         textBeforeTrigger.trim() == ''
@@ -663,6 +1051,7 @@ export function cursorWithinQuotes(
       let quoteStartPos = -1
       let equalStartPos = -1
 
+      // Search backwards for the opening quote (preceded by '=')
       while (
         (equalStartPos = textBeforeTrigger.lastIndexOf('=' + quoteChar[i])) ===
         -1
@@ -677,6 +1066,7 @@ export function cursorWithinQuotes(
       let quoteEndLine = quoteStartLine
       let quoteEndPos = -1
 
+      // Search forwards for the closing quote
       if (quoteStartPos > -1) {
         while (
           quoteEndLine < document.lineCount &&
@@ -688,6 +1078,7 @@ export function cursorWithinQuotes(
           currentText = document.lineAt(++quoteEndLine).text
         }
 
+        // Verify the opening quote is preceded by '=' and check if cursor is 
within the quoted range
         if (
           quoteEndPos > -1 &&
           currentText.indexOf('=', quoteStartPos - 1) === quoteStartPos - 1
@@ -713,6 +1104,24 @@ export function cursorWithinQuotes(
   return false
 }
 
+/**
+ * Determines if the cursor is currently positioned within curly braces { }.
+ * Curly braces in DFDL are used for expression language contexts, where
+ * different completion rules apply.
+ *
+ * The function searches backwards to find the opening brace '{' and forwards
+ * to find the closing brace '}', handling multi-line expressions. If the 
cursor
+ * falls within this range, the function returns true.
+ *
+ * This is used to:
+ * - Disable XML element/attribute completion inside DFDL expressions
+ * - Enable expression-specific completion (variables, functions, operators)
+ * - Properly scope completion providers
+ *
+ * @param document - The VS Code text document
+ * @param position - The current cursor position
+ * @returns true if the cursor is inside a pair of curly braces, false 
otherwise
+ */
 export function cursorWithinBraces(
   document: vscode.TextDocument,
   position: vscode.Position
@@ -722,6 +1131,7 @@ export function cursorWithinBraces(
   let braceStartLine = startLine
   let braceStartPos = -1
 
+  // Search backwards for opening brace '{'
   while (
     braceStartLine > 0 &&
     (braceStartPos = currentText.indexOf('{')) === -1
@@ -732,6 +1142,7 @@ export function cursorWithinBraces(
   let braceEndPos = -1
 
   if (braceStartPos > -1) {
+    // Search forwards for closing brace '}'
     while (
       braceEndLine < document.lineCount &&
       (braceEndPos = currentText.indexOf('}')) === -1
@@ -739,6 +1150,7 @@ export function cursorWithinBraces(
       currentText = document.lineAt(++braceEndLine).text
     }
 
+    // Check if cursor position falls within the brace range
     if (braceEndPos > -1) {
       if (
         (position.line > braceStartLine && position.line < braceEndLine) ||
@@ -759,6 +1171,22 @@ export function cursorWithinBraces(
   return false
 }
 
+/**
+ * Checks if there is an unclosed (open) curly brace in the current context.
+ * This detects when a curly brace expression is incomplete and missing its
+ * matching closing/opening brace.
+ *
+ * The function checks two scenarios:
+ * 1. If current line has '{', search forward for matching '}' - if not found, 
brace is open
+ * 2. If current line has '}', search backward for matching '{' - if not 
found, brace is open
+ *
+ * This is used to disable certain completion providers when braces are 
unbalanced,
+ * as the expression context is ambiguous or malformed.
+ *
+ * @param document - The VS Code text document
+ * @param position - The current cursor position
+ * @returns true if there is an unclosed brace, false if braces are balanced
+ */
 export function checkBraceOpen(
   document: vscode.TextDocument,
   position: vscode.Position
@@ -766,28 +1194,52 @@ export function checkBraceOpen(
   let lineNum = position.line
   let triggerText = document.lineAt(lineNum).text
 
+  // If line contains opening brace, check if it has a closing brace
   if (triggerText.includes('{')) {
     while (!triggerText.includes('}') && lineNum < document.lineCount) {
       triggerText = document.lineAt(++lineNum).text
     }
 
     if (!triggerText.includes('}')) {
-      return true
+      return true // Opening brace without closing brace
     }
   }
 
+  // If line contains closing brace, check if it has an opening brace
   if (triggerText.includes('}')) {
     while (!triggerText.includes('{') && lineNum > 0) {
       triggerText = document.lineAt(--lineNum).text
     }
 
     if (!triggerText.includes('{')) {
-      return true
+      return true // Closing brace without opening brace
     }
   }
   return false
 }
 
+/**
+ * Creates a VS Code completion item from intellisense data.
+ * Constructs a completion item with appropriate snippet text, documentation,
+ * and optional prefix values.
+ *
+ * The function:
+ * - Creates a CompletionItem with the item name as the label
+ * - Sets the insert text as a snippet (supporting tab stops like $1, $2, etc.)
+ * - Optionally prepends a prefix value (e.g., namespace prefix)
+ * - Attaches markdown documentation if provided
+ *
+ * Some items (like dfdl:choiceBranchKey, dfdl:simpleType) are excluded from
+ * receiving the prefix value as they have special formatting requirements.
+ *
+ * @param e - The intellisense item data containing:
+ *            - item: The display name/label
+ *            - snippetString: The VS Code snippet syntax to insert
+ *            - markdownString: Optional documentation in markdown format
+ * @param preVal - Prefix value to prepend to the snippet (e.g., attribute 
spacing)
+ * @param nsPrefix - The namespace prefix (e.g., 'xs:', 'dfdl:')
+ * @returns A configured VS Code CompletionItem ready to be shown to the user
+ */
 export function createCompletionItem(
   e:
     | {
@@ -805,6 +1257,7 @@ export function createCompletionItem(
 ) {
   const completionItem = new vscode.CompletionItem(e.item)
 
+  // Items that should not receive the prefix value
   const noPreVals = [
     'dfdl:choiceBranchKey=',
     'dfdl:representation',
@@ -814,6 +1267,7 @@ export function createCompletionItem(
     'restriction',
   ]
 
+  // Apply prefix value unless item is in the exclusion list
   if (preVal !== '' && !noPreVals.includes(e.item)) {
     completionItem.insertText = new vscode.SnippetString(
       preVal + e.snippetString
@@ -822,6 +1276,7 @@ export function createCompletionItem(
     completionItem.insertText = new vscode.SnippetString(e.snippetString)
   }
 
+  // Attach documentation if provided
   if (e.markdownString) {
     completionItem.documentation = new vscode.MarkdownString(e.markdownString)
   }

Reply via email to