XQueryX 3.1 to Javascript transpiler

Now, all browsers support async/await feature, so does Node.js. The Javascript arrays resulting from the XPath/XQuery parser can now be converted into Javascript functions.

To evaluate an expression, the context is passed as unique parameter to the Javascript function. Its body contains a sequence of instructions with a Reverse Polish Notation order: arguments and parameters are stacked before function calls. Path evaluations require if statements to stop when a step returns an empty sequence. Predicates are performed with inline functions to be called for each sequence item. Error management is implemented throwing Javascript exceptions.

For example,

concat('Hello ', PersonGivenName, '. We hope you like XForms!')

Becomes

ctx => {
  ctx.xqx_stringConstantExpr('Hello ');
  ctx.xqx_pathExpr();
  ctx.xqx_xpathAxis_child();
  ctx.xqx_nameTest("PersonGivenName");
  ctx.restoreContext();
  ctx.xs_string_1();
  ctx.xqx_stringConstantExpr('. We hope you like XForms!');
  ctx.fn_concat(3);
  return ctx;
};

This is optimized for Javascript interpreter own call stack and async/await use is reduced to minimal.

For example,

doc('r2d2.urdf.xml')/robot/joint[@name eq 'swivel']

Becomes

async ctx => {
  ctx.xqx_pathExpr();
  await ctx.xqx_filterExpr_async(async ctx => {
    ctx.xqx_stringConstantExpr('r2d2.urdf.xml');
    await ctx.fn_doc_1_async();
    return ctx;
  });
  if (ctx.item.isNotEmpty()) {
    ctx.xqx_xpathAxis_child();
    ctx.xqx_nameTest("robot");
    if (ctx.item.isNotEmpty()) {
      ctx.xqx_xpathAxis_child();
      ctx.xqx_nameTest("joint");
      if (ctx.item.isNotEmpty()) {
        ctx.xqx_predicateExpr(ctx => {
          ctx.xqx_pathExpr();
          ctx.xqx_xpathAxis_attribute();
          ctx.xqx_nameTest("name");
          ctx.restoreContext();
          ctx.atomize();
          ctx.xqx_stringConstantExpr('swivel');
          ctx.xqx_valueComp(Fleur.eqOp);
          return ctx;
        });
      }
    }
  }
  ctx.restoreContext();
  return ctx;
};

It is also enabling static optimization when generating the Javascript source. For example, atomizing and node sorting are not always necessary when calling a function. Instead of Javascript, with XSLT, a more sophisticated transpiler could be written to transform XQueryX to Javascript functions.

The fleur() Javascript function returns a type-explicit serialization which simulates an equivalent XQuery expression for the result of evaluation (more explicit than adaptative output).

For example,

fleur("xs:date('2021-05-21') - xs:date('2021-05-10')")

Returns

"xs:dayTimeDuration('P11D')"