Modernize eXide: CM6 editor, REx parser, REST API, LSP integration#778
Modernize eXide: CM6 editor, REx parser, REST API, LSP integration#778joewiz wants to merge 55 commits intoeXist-db:developfrom
Conversation
Replace eXide's bundled xqlint parser with a REx-generated parser built from the W3C XQuery 3.1 + Update 3.0 + Full Text 1.0 EBNF grammar. Includes adapter layer, static analysis, and comprehensive tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Migrate from Ace to CM6 with full language support, syntax highlighting, autocompletion, and keybinding infrastructure. Includes editor-utils shim layer and CM6 bundling script. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bundle Prettier with plugins via esbuild. Replaces xqlint CodeFormatter with multi-language formatting support. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace jQuery AJAX with fetch, jQuery UI dialogs with native <dialog> via dialog-utils.js, and AG Grid with vanilla HTML tables. Remove all jQuery/AG Grid CSS themes and scripts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace 15+ legacy XQuery modules with a Roaster-based OpenAPI REST API. Endpoints for storage, query execution, packages, authentication, templates, search, admin, sync, and editor operations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
569033d to
c226471
Compare
Comprehensive UI overhaul including redesigned toolbar, status bar with mode selector, native dialog system, tab overflow controls, filterable outline panel, dark mode with system theme detection, keyboard shortcuts dialog, and responsive layout improvements. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CM6 autocompletion with LSP-aware function completions, semantic highlighting via CM6 decorations, hover tooltips, function documentation, and language helpers for JSON, Less, Markdown, JavaScript, CSS, and XML. Remove dead Ace-era code (ace-modes.js, popup.js, splitter.js). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cypress E2E tests for autocomplete, diagnostics, outline, query execution, preferences, formatting, and more. Remaining frontend updates: layout, find/replace, menus, directory browser, drag-and-drop, history, and monitoring panel. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Editor features: - Matching tag highlight for XML/HTML (open/close tag partner) - XML/HTML scope breadcrumb in status bar (XPath at cursor) - XML Rename Element with multi-cursor (both tags updated) - XPath signatures with positional predicates in outline - Navigation flash on all jump-to actions (gotoLine, gotoSymbol, gotoDefinition, outline click, rename element) - Selection match highlighting, Cmd+D multi-select - Diagnostics panel (Cmd+Shift+D), autocomplete-on-type preference - Dynamic namespace registry from server, local hover fallback - Deferred splash screen, bracket matching restyled blue - Dialog focus on primary action button instead of close × - Enable multiple selections for multi-cursor operations - Unprefixed default namespace completion (conc → fn:concat) - Preserve namespace prefix on completion acceptance - Fix duplicate outline entries for self-closing XML elements - Fix JS gotoSymbol when outline not yet populated exist-next compatibility: - controller.xq, auth.xqm: xs:dayTimeDuration cast - admin.xqm: dynamic file module detection via util:eval - sync.xqm: dynamic file:sync() via util:eval - packages.xqm: fix collection-to-package resolution - query.xqm: make lsp:* import optional - compileError: parse line/column from message when lsp returns line 0 CI: - Skip autocomplete/outline tests when lsp:* unavailable - Move LSP-dependent Cypress tests to lsp/ subdirectory - Add 4 Cypress tests for prefix/unprefixed completion scenarios Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
POST /api/query/references with {query, line, column, base} returns
all references to the symbol at position. Uses dynamic function-lookup
for lsp:references (gracefully returns empty when unavailable).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
940e50f to
00bafd0
Compare
eXide Desktop wraps eXide's web UI in a native desktop application via Tauri v2. In dev mode, it loads from the local eXist-db server; in production, it bundles the web build. - src-tauri/: Rust entry point, Tauri config, default icons - npm run dev:desktop: opens native window against localhost:8080 - npm run build:desktop: produces .dmg/.exe/.AppImage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add tauri-plugin-fs and tauri-plugin-dialog (Rust + JS) - Register plugins in lib.rs, enable permissions in capabilities - Add src/desktop-bridge.js: detects Tauri runtime and exposes readDir, readFile, writeFile, pickFolder, pickFile, pickSaveFile - No-op in browser mode (eXide.desktop.isDesktop = false) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| - name: Build frontend Using node.js ${{ matrix.node-version }} and build EXPath Package | ||
| run: npm run build | ||
|
|
||
| - name: Download Roaster dependency |
There was a problem hiding this comment.
I would recommend using gh cli, and download both latest release and the min version as per expath-pkg.xml in a matrix
There was a problem hiding this comment.
[This response was co-authored with Claude Code. -Joe]
Done in commits ea7d771–1ddca80: replaced curl with gh release download (using the built-in GITHUB_TOKEN) for the Roaster dependency. The existing release/latest Docker matrix covers the most important cases — testing against the specific semver-min from expath-pkg.xml (6.1.0) would require an old Docker image that predates the Roaster/lsp:* dependencies this PR needs. Happy to add that as a separate matrix entry once we settle on the minimum version the full feature set requires.
| * #error-status. We need to wait for that to settle before testing. | ||
| */ | ||
| function waitForInitialLoad() { | ||
| cy.get('.path', { timeout: 10000 }).should('contain', 'untitled-1') |
There was a problem hiding this comment.
random timeouts are usually an anti pattern, is there something we can put on a named route, so we can wait on a request and its response?
There was a problem hiding this comment.
[This response was co-authored with Claude Code. -Joe]
Line 22 is already cy.wait('@compile', { timeout: 10000 }) — a named intercept alias set up in beforeEach via cy.intercept('POST', '**/api/query/compile').as('compile'). The remaining cy.wait(50) at line 30 is waiting for a browser MutationObserver microtask to fire after writing to #error-status, which can't be replaced with a network route. It's a minimal delay for a synchronous DOM write, not a timing guess.
| const el = win.document.getElementById('error-status') | ||
| el.textContent = '' | ||
| }) | ||
| cy.wait(50) |
There was a problem hiding this comment.
[This response was co-authored with Claude Code. -Joe]
Same as above — this is the MutationObserver microtask wait (50ms), not a network timing guess.
| cy.loginXHR('admin', '') | ||
| cy.visit('/eXide/index.html') | ||
| cy.reload(true) | ||
| cy.get('.path', { timeout: 10000 }).should('contain', 'untitled-1') |
There was a problem hiding this comment.
[This response was co-authored with Claude Code. -Joe]
These lines are cy.visit() and cy.get('.path').should('contain', 'untitled-1') — no cy.wait() here. The numeric waits that were the real issue (lines 95/100/135/163/168/195/200) have been replaced with cy.intercept('POST', '**/api/query/completions').as('completions') + cy.wait('@completions') in commit 24ef119.
| cy.reload(true) | ||
| cy.get('.path', { timeout: 10000 }).should('contain', 'untitled-1') | ||
| // Wait longer for login to propagate | ||
| cy.get('#user', { timeout: 15000 }).should('not.have.text', 'Login') |
There was a problem hiding this comment.
[This response was co-authored with Claude Code. -Joe]
These lines are cy.visit() and cy.get('.path').should('contain', 'untitled-1') — no cy.wait() here. The numeric waits that were the real issue (lines 95/100/135/163/168/195/200) have been replaced with cy.intercept('POST', '**/api/query/completions').as('completions') + cy.wait('@completions') in commit 24ef119.
There was a problem hiding this comment.
is this covered in our tests?
There was a problem hiding this comment.
[This response was co-authored with Claude Code. -Joe]
Not yet — the deployment dialog involves a multi-step UI (selecting server, entering credentials, triggering package install) that's harder to automate without a test server with the public repo accessible. Tracked in the future test gaps list.
There was a problem hiding this comment.
lol for a moment I was wondering why we had a dungeons and dragons file
There was a problem hiding this comment.
[This response was co-authored with Claude Code. -Joe]
dnd.js is for Drag and Drop, not Dungeons and Dragons — though XQuery dungeon crawling is admittedly an underexplored genre.
There was a problem hiding this comment.
[This response was co-authored with Claude Code. -Joe]
Removed in commit ea7d771. The .class file is a compiled Java binary for the REx parser generator — it shouldn't have been in version control. generate-parser.js now compiles it from REx.java on demand via javac if the class file is absent.
There was a problem hiding this comment.
Why do we store and commit binaries and java here?
There was a problem hiding this comment.
[This response was co-authored with Claude Code. -Joe]
REx.java is the source for the REx parser generator (by Gunther Rademacher, bottlecaps.de), included for transparency and reproducible builds — the site hosts the tool but isn't always reachable. The compiled REx.class has been removed from git (commit ea7d771); npm run generate-parser now compiles it on first use via javac. The .java source stays so contributors can inspect and rebuild without depending on an external download.
| @@ -0,0 +1,6 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <package xmlns="http://expath.org/ns/pkg" name="http://exist-db.org/apps/eXide" abbrev="eXide" version="3.5.5" spec="1.0"> | |||
There was a problem hiding this comment.
3.5.5 this should likely by 3.6.0 or 4.0.0
There was a problem hiding this comment.
[This response was co-authored with Claude Code. -Joe]
Bumped to 3.6.0 in commit a23c9cf. This is a significant feature release but preserves installation compatibility with the existing expath-pkg / repo:install flow, so a minor version bump feels right.
eXide Desktop wraps eXide's web UI in a native desktop application via Tauri v2. Connects to a running eXist-db server for full functionality (query execution, LSP, file management). Features: - Native macOS/Windows/Linux desktop app - Custom app icon: colorful glass marbles on wood (Gemini design) - Filesystem and dialog Tauri plugins for future local file access - Desktop bridge JS module (detects Tauri, exposes native APIs) - Release build navigates to eXist-db server URL (configurable via EXIDE_SERVER env var, defaults to localhost:8080) - Dev mode loads from localhost:8080 with hot reload - build-desktop.js: XHTML→HTML5 conversion for WebKit compatibility - Injects eXide.configuration defaults for standalone rendering Build: - npm run dev:desktop — development with hot reload - npm run build:desktop — produces .app/.dmg/.exe/.AppImage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On startup, shows a connection dialog where users can enter an eXist-db server URL. Saves recent servers in localStorage. Clicking Connect navigates directly to the server. - Tauri store plugin for persistent preferences - connect.html: sleek dark-themed connection UI with recent servers - Defaults to localhost:8080/exist/apps/eXide - EXIDE_SERVER env var skips the dialog for automated setups Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
duncdrum
left a comment
There was a problem hiding this comment.
I m starting to be a bit concerned about a mix of Java, Rust, Js,… it adds quite a bit of complexity.
That being said love tauri.
Should be build on ci though.
| "clean": "node scripts/build.js clean", | ||
| "xqlint": "cd support/xqlint && node r.js -o build.js && cd ../..", | ||
| "cypress": "cypress run" | ||
| "test": "node --test test/parser-test.js test/visitor-test.js test/utils-test.js test/static-analysis-test.js test/snippet-test.js test/parser-registry-test.js test/xq40-syntax-test.js", |
There was a problem hiding this comment.
I think node --test should suffice here
There was a problem hiding this comment.
[This response was co-authored with Claude Code. -Joe]
Done in commit 1ddca80: simplified to node --test. Node 20+ auto-discovers *-test.js files in test/.
Full native menu bar matching eXide's web menus: - eXide Desktop: About, Preferences (Cmd+,), Hide, Quit - File: New XQuery (Cmd+N), New (Cmd+Shift+N), Open, Save, Close (Cmd+W) - Edit: Undo/Redo, Cut/Copy/Paste, Find/Replace, Format, Toggle Comment - View: Toggle Collections, Results, Dark Mode - Navigate: Command Palette, Go to Definition (F3), Find References (Shift+F3), Go to Symbol, Go to Line, Function Doc, Diagnostics - Run: Run Query (Cmd+Enter), Launch Application - XQuery: Expand Selection, Rename, Extract Function/Variable - App: Launch, Deploy, Download, Synchronize - Window: Minimize, Maximize, Fullscreen, Next/Prev Tab - Help: Keyboard Shortcuts, About eXide Menu events execute JS in the webview via window.eval(). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
File > Open Local Folder opens a native macOS folder picker, then displays a LOCAL tab in the west panel with a browsable file tree (pre-loaded 3 levels deep from Rust). Folders expand/collapse on click. Architecture: since Tauri's JS IPC isn't available on server-loaded pages, all filesystem I/O is done Rust-side. The directory tree is serialized as JSON and injected via window.eval() into the eXide page. Known limitations (future work): - File opening on double-click not yet implemented (needs a mechanism for JS to request file content from Rust without IPC) - LOCAL tab styling needs polish to match COLLECTIONS/OUTLINE - Deep directories beyond 3 levels aren't pre-loaded Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Clicking a file in the local filesystem pane now opens it in the editor. Uses a Tauri custom URI scheme protocol (localfs://read/path) so the webview can fetch local file contents without IPC. Rust serves the file content with appropriate MIME types. The JS creates a new editor tab with the file content and correct syntax mode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Local files: update tab label to show filename instead of untitled-N - Connect page: test server reachability with 8-second timeout before navigating. Shows Cancel button during connection, Retry on failure. Handles unreachable servers gracefully. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Client-side WebSocket transport (src/ws-transport.js) providing: - Persistent bidirectional connection to eXist-db - JSON-RPC message framing (compatible with LSP protocol) - Request/response with callbacks for hover, completions, etc. - Server-push notifications for diagnostics, monitoring events - Auto-reconnect with exponential backoff - Auto-connect deriving WebSocket URL from page location - Graceful fallback when WebSocket unavailable API: eXide.ws.connect(), .send(), .notify(), .on(), .off() Designed for use with eXist-db's WebSocket support (PR #6145). Phase 1 target: real-time monitoring (replace HTTP polling). Phase 2: LSP over WebSocket (push diagnostics, incremental edits). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Auto-connect to ws://host/exist/ws on eXide startup - Monitor: try WebSocket streaming before falling back to HTTP polling (listens for exist/metrics, exist/queryStarted, exist/queryEnded) - LSP hover: use WebSocket request/response when connected, HTTP fallback when not - WebSocket URL derived from page location using monex's pattern (rootContext + "/ws") Requires eXist-db with WebSocket support (PR #6145). Graceful fallback to HTTP when WebSocket unavailable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Ignore plain-text "ping" keepalive messages from eXist-db WebSocket (server sends "ping" not JSON, was causing parse errors) - Add 5 Cypress tests: auto-connect, endpoint connection, ping handling, API surface, graceful fallback Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ncoding Autocomplete was doubling namespace prefixes (e.g. repo:repo:deploy) when the user typed a prefixed name like "repo:" — the nsPart logic now checks whether the server result already includes the prefix before prepending it. Storage API calls in eXide.js and directory.js used encodeURIComponent on full paths, encoding slashes as %2F and causing 400 errors. Fixed by using the existing apiPath() helper that encodes each segment individually. Also replaced fixed cy.wait() sleeps in monitor and websocket specs with assertion-based retries, cutting suite time by ~2 minutes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…al/fetch
Replaces the old XQueryServlet + session.xq flow and the WebSocket streaming
approach with a cursor-based architecture using the new lsp:eval/lsp:fetch/
lsp:close functions from the exist-lsp package.
How it works:
- POST /api/query calls lsp:eval() → stores result sequence in Caffeine cache,
returns cursor ID + item count + elapsed time
- GET /api/query/{id}/results?start=N&count=M calls lsp:fetch() → serializes
only the requested page, includes documentURI and nodeId per item
- DELETE /api/query/{id} calls lsp:close() → releases the cursor
- Cursors auto-expire after 5 minutes of inactivity
This restores the key qualities of the old flow:
- Lazy serialization (only viewed page is serialized)
- No client-side buffering (results stay on server)
- Pagination (identical UX with next/previous/first/last)
- Document links (documentURI field for clickable result badges)
Also adds:
- Cancel button in toolbar (visible during execution)
- Timing display bar below results navbar
- WebSocket eval transport (ws-eval.js) for future progress/cancel support
- exist-lsp package dependency in expath-pkg.xml
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cancel button now aborts the in-flight HTTP request and attempts to kill the server-side query via the admin API. If the query contains update expressions (update, insert, delete, replace, rename), a confirmation dialog warns about potential database inconsistency before cancelling. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The side-effect detection regex now covers: - XQUF: update, insert, delete, replace, rename - xmldb: store, remove, create-collection, copy, move, rename - sm: chmod, chown, chgrp, add-account, remove-account - file: write, delete, move, mkdirs, serialize Also hides cancel button and shows "Query cancelled." message after cancel completes, and adds explanatory comments about the client-side vs server-side cancel behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Serialization mode, indent, and highlight-matches settings from eXide's results toolbar are now sent with each page fetch request. Changing these settings re-fetches the current page with new serialization — no query re-execution needed. The results endpoint accepts all W3C serialization parameters as query string params (method, indent, omit-xml-declaration, encoding, etc.) plus eXist's highlight-matches. Falls back gracefully to 3-arity lsp:fetch if the 4-arity overload isn't available yet. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New Cypress tests: - Pagination: next/previous/first/last with 25-item result set - Large result set: 10,000 items renders only 10 in DOM - Serialization mode change: re-fetches page without re-executing - Indent toggle: re-fetches page with new indent setting Also fixes toggle button change event dispatch — programmatic checkbox.checked changes now fire the change event so cursor re-fetch listeners trigger correctly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…pe, and selection match New test files: - goto_references_spec.cy.js (4 tests): F3 go-to-definition jumps to declaration, Cmd/Ctrl adds clickable class, findReferences opens QuickPicker, Escape closes QuickPicker - tag_scope_selection_spec.cy.js (6 tests): tag matching CSS defined, XML scope breadcrumb shows XPath, XQuery scope shows function context, scope hidden outside named context, selection match highlights occurrences, highlights clear when selection clears Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Displays phase-level timing from lsp:eval: Compile, Eval, Total, Items. Falls back to simple Elapsed display if the timing map isn't available (e.g., older exist-lsp without the timing breakdown). Also passes timing map through query.xqm execute endpoint. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ground Generated from the x.svg in dashboard/resources/images at 16x16, 32x32, and 48x48. Added favicon link to src-tauri/connect.html (the only page template that was missing it). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The lsp:* functions have been consolidated into the exist-api package (http://exist-db.org/pkg/api) which provides a unified platform API for eXist-db. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Used by Node.js test scripts to verify the /ws/eval endpoint protocol (eval, cancel, progress messages) outside of the browser. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This is a major feature release: CM6 editor, REx parser, Roaster REST API, LSP integration, WebSocket monitoring, and Prettier formatting. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The LGPL header was accidentally dropped when syncing the schema from eXist-db/exist. Restored from the upstream source. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Before: before() and after() in file_save_spec each duplicated the same XQuery cleanup request. Now both call cy.cleanupTestFiles(), and other specs that create /db files can reuse it without duplication. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…omplete_spec cy.wait(300/200/500) was used as a proxy for "completions API response arrived". Now each test that accepts a completion intercepts POST /api/query/completions and waits on the named alias, making timing deterministic rather than guessed. Also converts leftover var → const in the filter test. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
REx.class is a compiled Java binary — it shouldn't be in version control. REx.java (the source, by Gunther Rademacher, bottlecaps.de) stays committed for transparency and reproducible builds. generate-parser.js now compiles REx.java via javac if the class file is absent, so the workflow is unchanged: run `npm run generate-parser` and it just works. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Run `npm test` (node --test) before building — catches JS regressions early - Validate OpenAPI schema with @redocly/cli before deploying - Replace curl with `gh release download` for the Roaster dependency, using the built-in GITHUB_TOKEN so no secrets are needed - Simplify package.json test script to `node --test` (file discovery is automatic for the *-test.js naming convention used in test/) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
a9ce2ba to
1ddca80
Compare
Previously, "Copy all displayed results to clipboard" concatenated items without any separator. Now each item is joined with a newline, making the pasted output readable when the query returns multiple items. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously, changing the number-of-results dropdown only updated the internal variable without refreshing the display. Now it resets to page 1 and re-fetches with the new page size immediately. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The Indent and Highlight Matches buttons previously used identical colors for both hover and active states. Active buttons now show a solid blue background with white text (dark mode: semi-opaque blue), making it clear at a glance whether the option is on or off. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously, clicking an already-open menu header would close it and immediately re-open it. Now clicking an open menu header closes it, consistent with standard menubar behaviour. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
xmldb:copy-collection() returns the destination path as a string. The copy action was returning this string alongside the status map, producing a 2-item sequence that roaster cannot serialize as JSON (err:SERE0023). Wrap the for loop in let $_ := to discard the return value and return only the status map. Fixes the Cypress DB manager copy test and makes copy/paste of collections and resources functional. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replacing cy.wait(300) with cy.wait('@Completions') waits for the
network response but not for CM6's internal state to settle. By
the time acceptCompletion() or {enter} ran, the popup had been
dismissed. Replace with li[aria-selected="true"].click() which
interacts directly with the visible popup item before it can close.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
eXide previously used its own /api/query endpoints. Route all query calls to exist-api instead — cookie auth works because both apps share the org.exist.login cookie domain (fixed in exist-api's cookieAuth spec). eXide.js changes: - POST/DELETE/GET URLs: api/query → ../exist-api/api/query - Request body: base → module-load-path - POST response: data.id → data.cursor, data.count → data.items - GET results: data.items (wrapped) → data (plain array) Version bumped to 4.0.0 to signal the new exist-api dependency, which is already declared in expath-pkg.xml. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
query_execution_spec.cy.js: two tests verifying eXide renders adaptive output correctly — xs:string is double-quoted, xs:integer is bare. adaptive_serialization_spec.cy.js: 16 UI-level tests covering all major XDM atomic types drawn from XQTS ser/method-adaptive.xml test cases: xs:integer, xs:decimal, xs:double, xs:float, xs:boolean, xs:string (with internal quote doubling), xs:anyURI, xs:untypedAtomic, xs:dateTime, xs:date, xs:time, xs:duration, xs:base64Binary, xs:hexBinary, xs:QName. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
A comprehensive modernization of eXide, replacing legacy dependencies with modern alternatives and adding LSP-powered language intelligence. This consolidates work from multiple prior PRs (#774, #777) into a single reviewable PR with grouped commits.
Commits (grouped for review)
1. Replace xqlint parser with REx-generated XQuery 3.1 parser
REx-generated parser from W3C EBNF grammar (XQuery 3.1 + Update 3.0 + Full Text 1.0). Adapter layer preserves the existing visitor infrastructure. Includes unit tests for parser, visitors, and static analysis.
2. Replace Ace editor with CodeMirror 6
Full migration from Ace to CM6 with language support, syntax highlighting, keybinding infrastructure, and editor-utils compatibility layer.
3. Add Prettier-based code formatting
Multi-language formatting via Prettier + plugins (XQuery, XML, HTML, CSS, Less, Markdown), bundled with esbuild. Replaces xqlint's CodeFormatter.
4. Remove jQuery, jQuery UI, and AG Grid dependencies
All AJAX calls use fetch, dialogs use native
<dialog>via dialog-utils.js, DOM manipulation uses vanilla JS. AG Grid replaced with vanilla HTML tables.5. Add OpenAPI/Roaster REST API and remove legacy XQuery modules
Replace 15+ legacy XQuery modules with a Roaster-based OpenAPI REST API. All backend operations (storage, query, packages, auth, sync, search, admin) handled through typed JSON endpoints.
6. Redesign UI
Toolbar, status bar with mode selector, native dialog system, tab overflow controls, filterable outline panel, dark mode with proper syntax highlighting (One Dark palette via CSS classHighlighter), system theme detection, keyboard shortcuts dialog, monitoring panel, and responsive layout.
7. Add CM6 autocomplete, semantic highlighting, and multi-language helpers
CM6 autocompletion with LSP-aware function completions (prefixed and unprefixed default namespace), semantic highlighting via decorations, hover tooltips with AST fallback, go-to-definition (same-file and cross-module), multi-cursor rename, and language helpers for JSON, Less, Markdown, JavaScript, CSS, and XML. Native HTML tag/attribute, CSS property/value, and JavaScript local variable completions via CM6 language packs.
8. Add Cypress integration tests and remaining frontend updates
E2E tests for autocomplete, diagnostics, outline, query execution, preferences, formatting, and more (172+ tests). Remaining frontend updates: layout, find/replace, menus, directory browser, drag-and-drop, build scripts, login page.
9. Add tag matching, exist-next compat, and CI fixes
10. Add Find All References
11. WebSocket transport and monitoring
ws-transport.js) for real-time LSP and monitoring push12. Server-side cursor query execution
Replaces the old XQueryServlet + session.xq flow with a cursor-based architecture using
lsp:eval/lsp:fetch/lsp:closefrom the exist-lsp package.Before:
After:
Key properties:
documentURIandnodeIdavailable per result itemThis follows the same pattern used by SQL clients (server-side cursors), BaseX GUI (in-process result references), and eXist's own Java admin client (XML-RPC result handles).
Cursor store cache policy
Results are held in a Caffeine cache with configurable eviction:
cursor.maximumSizecursor.expireAfterAccesscursor.maximumWeightConfiguration via
exist.xmlmodule parameters:13. Query cancellation
What it does:
AbortController.abort()drops the HTTP connectionsystem:kill-running-xquery()(admin only)Risks — cancelling state-modifying queries can leave the database inconsistent:
insert/delete/replace/rename)update value,update insert)xmldb:store()/xmldb:remove()sm:chmod()/sm:chown()file:write()/file:delete()Mitigations:
xmldb:*,sm:*,file:*mutations14. Results toolbar and menubar polish
Temporary workarounds (remove after upstream merges)
xquery version "4.0"code with a user-friendly message. Remove once prettier-plugin-xquery adds 4.0 support.Known limitations
lsp:eval/lsp:fetch/lsp:closeare eXist-specific IDE support functions in the exist-lsp package. Reviewers are invited to weigh in on whether this scope is appropriate or if a separate package would be preferred.Requirements
Test plan
npm run build && xst package install local build/eXide-3.5.5.xar --force)npm test— 178 tests)autocomplete_spec(11),diagnostics_panel_spec(5),error_status_spec(8),native_autocomplete_spec(7)goto_references_spec(F3 jump + clickable class)goto_references_spec(QuickPicker opens + Escape closes)autocomplete_speccovers prefixed, unprefixed,fn:,repo:, variable completionslayout_spec(dark mode layout)prettier_format_spec(4 tests)outline_navigation_spec(12 tests)tag_scope_selection_spec(CSS defined, XML/XQuery scope, selection match)query_execution_spec"paginates results with next/previous buttons"1 to 10000) —query_execution_spec"handles large result sets" (10 DOM nodes for 10K items)query_execution_spec"re-fetches page when serialization mode changes without re-executing"query_execution_spec"re-fetches page when indent toggle changes"query_execution_speccancel button tests (existence, visibility)monitor_spec"shows running query and allows killing it" (flaky timing)🤖 Generated with Claude Code