Add existdb-openapi support for eXist 7.0+; retain atom-editor for 6.x compat#68
Open
joewiz wants to merge 2 commits into
Open
Add existdb-openapi support for eXist 7.0+; retain atom-editor for 6.x compat#68joewiz wants to merge 2 commits into
joewiz wants to merge 2 commits into
Conversation
6 tasks
76430e2 to
41be7d6
Compare
9ed576b to
7f39eed
Compare
…fallback)
Replaces the previous atom-editor-only backend with existdb-openapi's
language-service endpoints for eXist 7.0+, while preserving the bundled
atom-editor-support XAR as a backward-compatibility path for eXist 6.x.
## Server compatibility matrix
| eXist version | Path | Source |
|---|---|---|
| 7.0+ (recommended) | existdb-openapi /api/langservice/* + /api/query/* | Ships with eXist 7.0+; no install needed |
| 6.x (legacy) | Bundled atom-editor-support XAR + /apps/atom-editor/* | Prompted on first connect; basic features only |
Capability detection: server.ts calls `GET /api/langservice/capabilities`
at connect time. If the endpoint responds with `cursor.available === true`,
route through existdb-openapi. Otherwise check whether the bundled
atom-editor XAR is installed; prompt if missing.
## Backend wiring
- linting.ts: serverLint() POSTs to /api/langservice/diagnostics with
structured JSON response; handles multi-error diagnostics via
mapSeverity() (was: regex-parsing a single error from compile.xql).
- analyzed-document.ts: getCompletions/getHoverRemote/gotoDefinitionRemote
POST full query text to /api/langservice/{completions,hover,definition}.
Removed resolveImports/parseImports/getParameters/imports map/Import
interface (~120 lines of client-side import-resolution code).
- server.ts: capability detection via GET /api/langservice/capabilities.
- utils.ts: unchanged from upstream master (atom-editor XAR check retained).
Closes wolfgangmm#15 — request: and other built-in namespace prefixes no longer
trigger false XPST0081 errors, since lang:diagnostics resolves them
correctly (unlike the old util:compile-query path).
## Cursor-based query execution (7.0+ path)
Three-step cursor lifecycle against existdb-openapi's /api/query family:
1. POST /api/query → cursor:eval, returns { cursor, items, elapsed }
2. GET /api/query/{id}/results?start=…&count=… → cursor:fetch
3. DELETE /api/query/{id} → cursor:close
Legacy POST /apps/atom-editor/execute preserved as 6.x fallback.
Client (extension.ts): execute command handles both cursor-based (array
items) and legacy (string) results. New existdb.loadMoreResults command
fetches subsequent pages. Previous cursors automatically closed before
new queries.
Client (query-results-provider.ts): CursorState tracks active cursor,
total hits, fetched count, output mode. appendResults appends pages;
clearCursor resets state.
## New language service features
- Cross-module go-to-definition: handle "uri" field in definition response
for cross-module navigation. Maps database paths to workspace file URIs
using settings.path prefix.
- Semantic tokens provider: highlights function/variable declarations
using server-side lang:symbols, local fallback.
- Document formatting provider: XQuery formatting via Prettier +
prettier-plugin-xquery.
- Enhanced document symbols: server-side lang:symbols for richer outline
(return types, parameter types), local fallback.
- Find-references provider (Shift+F12).
- Signature help + rename symbol providers.
## Output format settings
- Settings (package.json): existdb.query.serializationMethod (default
"adaptive"; enum adaptive/xml/json/text), existdb.query.indent.
- Client: existdb.setOutputFormat quick-pick command; clickable status
bar item showing current method. getSerializationOptions auto-enables
highlight-matches: both when query contains ft:query/ft:search.
- Server: evalQuery/fetchResults accept optional serializationOptions;
options forwarded as query params on the cursor /results GET.
## module-load-path field name
Standardized on "module-load-path" across all langservice request bodies
to align with existdb-openapi's OpenAPI contract (matches the
XQueryContext.setModuleLoadPath() API name). Legacy atom-editor fallback
path unchanged since that endpoint isn't under our control.
## Tests
26 new tests covering the new endpoints and routing logic:
- test/capability-check.spec.ts (7 tests): GET /api/langservice/capabilities
probe semantics; routing of evalQuery vs legacy executeQuery.
- test/cursor-execution.spec.ts (10 tests): POST /api/query →
GET /api/query/{id}/results → DELETE /api/query/{id} cycle, output mode
detection, custom page size, error propagation, legacy executeQuery.
- test/serialization-options.spec.ts (10 tests): options pass-through
as query params on the GET, omission when undefined,
highlight-matches forwarding, Lucene ft:query/ft:search regex.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
xqlint produced false-positive warnings (wolfgangmm#67) and brought a stale, heavy dependency tree (~5 MB of transitive deps). After the previous commit deferred all diagnostics to the server-side lang:diagnostics endpoint, xqlint's only remaining role was producing a local AST for symbol lookup (hover / go-to-definition without a server roundtrip when the cursor is on a known local function/variable). eXide ships a REx-generated parser for the W3C XQuery 3.1 EBNF, plus an adapter that normalizes the parse tree to the same shape xqlint's JSONParseTreeHandler emitted — so the consumer surface in server/src/ast.ts (findNode, getAncestorOrSelf, getFunctionSignature) keeps working unchanged. The xqlint warnings are dropped entirely; errors continue to come from the server-side lang:diagnostics endpoint. Files added (copied verbatim from eXist-db/eXide src/parser/): - server/src/parser/XQueryParser.js (~1.1 MB, generated; XQ 3.1 grammar) - server/src/parser/adapter.js (xqlint-compat AST normalization) Both files have CommonJS exports, so plain require() works in Node. Bundle size after webpack tree-shake + minify is ~775 KB (the parser code minifies aggressively). Files removed: - server/src/xqlint.d.ts (no longer needed) Dependency removed: - server/package.json: drop "xqlint" (was github:eXistSolutions/xqlint#exist-syntax) Tests added (test/parser.spec.ts, 8 tests): - parseXQuery: trivial expression, function decl + call, invalid syntax (error reported without throwing), XQuery 3.1 features (FLWOR, type declarations, namespaces). - AST traversal: identifies the function call under the cursor, distinguishes calls by arity, returns null when cursor is not on a FunctionCall, handles multi-line input with position resolution across lines. Future: XQuery 4.0 parser (XQueryParser40.js, ~3 MB) is available in eXide and could be lazy-loaded when the source declares "4.0", but that's not needed for the langserver's current symbol-lookup use case. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7f39eed to
a0e2a74
Compare
Merged
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
existdb-openapi(formerlyexist-api) for language services: diagnostics, completions, hover, definition, references, symbols, and cursor-based query execution.atom-editor-supportXAR as the backward-compatibility path for eXist 6.x users — the langserver runtime-detects which one is available and routes accordingly.util:compile-query).cursor:eval/cursor:fetch/cursor:close— replaces legacyPOST /apps/atom-editor/executeon 7.0+; legacy path retained as fallback for 6.x.GET /api/langservice/capabilities— replaces the previous dummy-query probe.Closes #15 —
request:and other eXist-db built-in namespace prefixes no longer trigger falseXPST0081errors, sincelang:diagnosticsresolves them correctly (unlike the oldutil:compile-querypath).Server compatibility matrix
/api/langservice/*+/api/query/*atom-editor-supportXAR +/apps/atom-editor/*On 7.0+, the new features added in this PR (cursor pagination, signature help, rename, semantic tokens, find references, enhanced symbols) are fully available. On 6.x, only what
atom-editor-supporthistorically provided works; the new features are silently disabled.What changed
Capability detection (eXist 7.0+ vs 6.x)
server.tscallsGET /api/langservice/capabilitiesat connect time. If the endpoint responds withcursor.available === true, route through existdb-openapi. Otherwise check whether the bundled atom-editor XAR is installed; prompt if missing.Bundled XAR
resources/language-support-1.0.0.xar(intermediate scaffolding; no longer needed once existdb-openapi ships with eXist core).resources/atom-editor-1.1.0.xarfor 6.x backward compat.utils.tscheckServer()checks forhttp://exist-db.org/apps/atom-editor(unchanged from upstream master).Cursor-based query execution (7.0+ path)
Replaces the legacy
POST /apps/atom-editor/executewith a three-step cursor-based approach against existdb-openapi's/api/queryfamily:POST /api/querywith{query, …}— server-side maps tocursor:eval(...), returns{ cursor, items, elapsed }.GET /api/query/{id}/results?start=…&count=…— server-side maps tocursor:fetch(...), returns a page of items. Serialization options (method,indent,highlight-matches) ride along as additional query params.DELETE /api/query/{id}— server-side maps tocursor:close(...), releases server-side resources.server/src/analyzed-document.ts:evalQuery()POSTs/api/query, then auto-fetches the first page via the cursor results endpoint.fetchResults()andcloseCursor()support on-demand paging and cleanup.executeQuery()preserved as the 6.x fallback (POSTs/apps/atom-editor/execute).server/src/server.ts:GET /api/langservice/capabilities(replaces the dummyquery: '1'probe).executecommand routes to cursor-based or legacy path based on capability.fetchandcloseCursorcommands.client/src/extension.ts:existdb.loadMoreResultscommand fetches the next page from an open cursor.client/src/query-results-provider.ts:CursorStateinterface tracks active cursor, total hits, fetched count, output mode.appendResults()appends pages;clearCursor()resets state.Output format settings
Settings (
package.json):existdb.query.serializationMethod— defaultadaptive, enum:adaptive,xml,json,text.existdb.query.indent— defaulttrue, controls indentation of results.Client (
client/src/extension.ts):existdb.setOutputFormatcommand — quick pick: Adaptive, XML, JSON, Text (with checkmark on current).Adaptive).getSerializationOptions()builds options object from settings, auto-enableshighlight-matches: bothwhen query containsft:queryorft:search.executeandfetchcommands to server.Server:
evalQuery()andfetchResults()accept optionalserializationOptionsparameter./resultsGET.server/src/linting.tsserverLint(): POST to/api/langservice/diagnostics(was PUT tocompile.xql).mapSeverity()(was regex-parsing a single error message).server/src/analyzed-document.ts(besides cursor)getCompletions(): POST full query text to/api/langservice/completions(was GET with resolved imports as query params).getHoverRemote(): POST query + position to/api/langservice/hover(was GET with function signature).gotoDefinitionRemote(): POST query + position to/api/langservice/definition(was GET with signature + client-side file reading).resolveImports(),parseImports(),getParameters(),getOptions(),importsmap,Importinterface.server/src/server.tsgetCompletions()andtextDocumenttogetHover().lang:symbols, local fallback.prettier-plugin-xquery.lang:symbolsfor richer outline (return types, parameter types), local fallback.Tests
27 tests passing locally. Run with:
npm testtest/cursor-execution.spec.ts(10 tests):evalQuery: POST/api/query+ GET/api/query/{id}/resultstwo-step, output mode detection, custom page size, error propagation.fetchResults: GET withstart/countas query params, empty results.closeCursor: DELETE/api/query/{id}, response shape handling.executeQuerylegacy: atom-editor endpoint, form-encoded body.test/capability-check.spec.ts(7 tests):GET /api/langservice/capabilities: 200 with cursor available, 404, unreachable, missing cursor block, cursor.available=false.test/serialization-options.spec.ts(10 tests):ft:query/ft:searchregex detection (positive and negative cases).Local AST: eXide's REx-generated XQuery 3.1 parser
For local symbol lookup (so hover and go-to-definition can short-circuit a server roundtrip when the cursor is on a known local function/variable), the langserver builds an AST client-side. This PR swaps the previous xqlint dependency (which produced false-positive warnings, e.g. #67, and had a heavy transitive dep tree) for eXide's REx-generated parser — the same parser eXide uses, generated from the W3C XQuery 3.1 EBNF.
server/src/parser/XQueryParser.js(the generated 3.1 parser) andserver/src/parser/adapter.js(a normalization adapter that emits the same xqlint-shaped AST the existingserver/src/ast.tstraversals expect) are vendored into the langserver. The XQuery 4.0 parser (XQueryParser40.js) is available in eXide and could be added later if the langserver ever needs 4.0-specific local symbol lookup; for now the 3.1 parser covers all current use cases.Requirements
existdb-openapibuilt-in. No additional XAR install required for langserver features.atom-editor-supportXAR on first connect. Reduced feature set (no cursor, no semantic tokens, no references, no enhanced symbols).Test plan
/apps/existdb-openapi/api/langservice/capabilities.XPST0081error onrequest:get-parameter(VSCode objects to "request:" namespace prefix #15).[W03] Unused variablewarnings (false positive problem reports "unused variable" #67 — xqlint warnings removed).existdb.query.serializationMethod.ft:queryin query auto-enables highlight-matches.npm testpasses (27 tests).🤖 Generated with Claude Code