JavaScripter writing XQuery: Formatting XQuery code

Martin Middel

Declarative Amsterdam, 7 November 2025
xquery.elliat.nl

A brief history of me


Started (professionally) writing JavaScript code around 2012

console.log('Here!')
document.querySelector('div').?????

                  node.apendChild(newChildNode);
              
if(something) {doSomething(); console.log('Did something!')}
                  else {
                  doNothing()
                  }

But that improved!

2013: Typechecking with TypeScript!


// Property 'apendChild' does
// not exist on type 'Node'.
// Did you mean 'log'?(2551)
node.apendChild(newChildNode);

2016: Autocomplete with Language Server Protocol

Step through debugging with Chrome (2017) and Firefox (2018)

2017: Automated formatting with Prettier

if (something) {
  doSomething();
  console.log("Did something!");
} else {
  doNothing();
}

It was starting to get good!

And then: XQuery

Felt like going back in time a bit...

child:p
idnex-of(('a', 'b'), 'a')
trace($var, 'I am here!')

if ($something) then (util:log('info', 'Did something!'), local:do-something()) else
    local:do-nothing()

I missed JS

Introducing!

prettier-plugin-XQuery


if ($something) then (util:log('info', 'Did something!'), local:do-something()) else
local:do-nothing()

<table>{
  for $i in 1 to xs:int($data?rows)
   return <tr>{for $j in 1 to xs:int($data?cols) return
<td>
<p>cell at {$i},{$j}</p></td>
   }</tr>
}</table>

Dialects?

πŸ§ͺ Exist-DB's update node syntax πŸ§ͺ


let $node := <root><a/></root>
return
    update insert <b/> into $node/a
		  

XSLT?

πŸ§ͺ


  <xsl:template match="Author">
    - <xsl:value-of select="1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27" />
  </xsl:template>
		    

Speed?

Filesize line count after formatting Prettify in ms
183B 4 ~10ms
6KB 161 ~34ms
24KB 641 170ms
94KB 2663 ~600ms

πŸ§ͺ XQuery 4? πŸ§ͺ

let $a :=
              ancestor-or-self::(div|section) otherwise
              descendant-or-self::(div|section)
              return $a => exists()

How?

  • Plugin for Prettier

  • Gunther Rademacher's REx parser generator

  • Some JS to 'amend' grammars for 'dialects'

  • Verifies correctness using QT3 / QT4 test set plus additional tests

Prettier

Makes code Prettier. Plugin available in about every IDE.

Parse code

Build tree, adding breakpoints

Output, breaking where needed

'A very very very long string' || ' That is sure to go over the limit'

const stringConcatExpression = join([
  leftHandSide,
  space,
  '||',
  break(indent(rightHandSide))
])
            

'A very very very long string' || ' That is sure to go over the limit'
                              ^  ^
                             /   '-  if break: newline+indent,
                          space      otherwise space
          
'A very very very long string' ||
  ' That is sure to go over the limit' 

πŸ§ͺDialectsπŸ§ͺ

Experimental. Not fully implemented yet

Amending grammars

  1. Take the XQ4 grammar
  2. Parse it
  3. Add new Rule to ExprSingle (for example)
  4. Add definition for that Rule
  5. Serialize to string
  6. Decide on formatting
const existDBMutations = [
	{
		where: 'ExprSingle',
		name: 'ExistDB_UpdateExpr',
		additionalRule: `ExistDB_UpdateExpr ::= 'update' (
  ExistDB_UpdateInsertExpr |
  ExistDB_UpdateReplaceExpr |
  ExistDB_UpdateDeleteExpr |
  ExistDB_UpdateRenameExpr |
  ExistDB_UpdateValueExpr
)`,
	},
];
            
ExprSingle ::= ExistDB_UpdateExpr | ( FLWORExpr | QuantifiedExpr | SwitchExpr | TypeswitchExpr | IfExpr | TryCatchExpr | OrExpr )
ExistDB_UpdateExpr ::= 'update' ( ExistDB_UpdateInsertExpr | ExistDB_UpdateReplaceExpr | ExistDB_UpdateDeleteExpr | ExistDB_UpdateRenameExpr | ExistDB_UpdateValueExpr )
ExistDB_UpdateInsertExpr ::= 'insert' Expr (
    'into' | 'following' | 'preceding'
  ) ExprSingle
ExistDB_UpdateReplaceExpr ::= 'replace' Expr 'with' ExprSingle
ExistDB_UpdateValueExpr ::= 'value' Expr 'with' ExprSingle
ExistDB_UpdateDeleteExpr ::= 'delete' Expr
ExistDB_UpdateRenameExpr ::= 'rename' Expr 'as' ExprSingle

Status

βœ“ XQuery 3.1

πŸ§ͺ XQuery 4.0

πŸ§ͺ ExistDB update node syntax

πŸ‘· Other Dialects

Sponsors?

πŸ‘· Embedded XQuery in XSLT

Sponsors?

That big file? Still huge, easier to read.

This took 250 ms to format πŸ‡

Why

Useful?

Available on NPM

prettier-plugin-xquery

Demo: xquery.elliat.nl

Q?

prettier-plugin-xquery
xquery.elliat.nl

DEMO