Repository: FontoXML/fontoxpath
Pull request #612 (2023-10-19 07:06:39)

Bump @babel/traverse from 7.22.20 to 7.23.2
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.22.20 to 7.23.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/babel/babel/releases"><code>@​babel/traverse</code>'s releases</a>.</em></p>
<blockquote>
<h2>v7.23.2 (2023-10-11)</h2>
<p><strong>NOTE</strong>: This release also re-publishes <code>@babel/core</code>, even if it does not appear in the linked release commit.</p>
<p>Thanks <a href="https://github.com/jimmydief"><code>@​jimmydief</code></a> for your first PR!</p>
<h4>:bug: Bug Fix</h4>
<ul>
<li><code>babel-traverse</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/16033">#16033</a> Only evaluate own String/Number/Math methods (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
<li><code>babel-preset-typescript</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/16022">#16022</a> Rewrite <code>.tsx</code> extension when using <code>rewriteImportExtensions</code> (<a href="https://github.com/jimmydief"><code>@​jimmydief</code></a>)</li>
</ul>
</li>
<li><code>babel-helpers</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/16017">#16017</a> Fix: fallback to typeof when toString is applied to incompatible object (<a href="https://github.com/JLHwung"><code>@​JLHwung</code></a>)</li>
</ul>
</li>
<li><code>babel-helpers</code>, <code>babel-plugin-transform-modules-commonjs</code>, <code>babel-runtime-corejs2</code>, <code>babel-runtime-corejs3</code>, <code>babel-runtime</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/16025">#16025</a> Avoid override mistake in namespace imports (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
</ul>
<h4>Committers: 5</h4>
<ul>
<li>Babel Bot (<a href="https://github.com/babel-bot"><code>@​babel-bot</code></a>)</li>
<li>Huáng Jùnliàng (<a href="https://github.com/JLHwung"><code>@​JLHwung</code></a>)</li>
<li>James Diefenderfer (<a href="https://github.com/jimmydief"><code>@​jimmydief</code></a>)</li>
<li>Nicolò Ribaudo (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
<li><a href="https://github.com/liuxingbaoyu"><code>@​liuxingbaoyu</code></a></li>
</ul>
<h2>v7.23.1 (2023-09-25)</h2>
<p>Re-publishing <code>@babel/helpers</code> due to a publishing error in 7.23.0.</p>
<h2>v7.23.0 (2023-09-25)</h2>
<p>Thanks <a href="https://github.com/lorenzoferre"><code>@​lorenzoferre</code></a> and <a href="https://github.com/RajShukla1"><code>@​RajShukla1</code></a> for your first PRs!</p>
<h4>:rocket: New Feature</h4>
<ul>
<li><code>babel-plugin-proposal-import-wasm-source</code>, <code>babel-plugin-syntax-import-source</code>, <code>babel-plugin-transform-dynamic-import</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15870">#15870</a> Support transforming <code>import source</code> for wasm (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
<li><code>babel-helper-module-transforms</code>, <code>babel-helpers</code>, <code>babel-plugin-proposal-import-defer</code>, <code>babel-plugin-syntax-import-defer</code>, <code>babel-plugin-transform-modules-commonjs</code>, <code>babel-runtime-corejs2</code>, <code>babel-runtime-corejs3</code>, <code>babel-runtime</code>, <code>babel-standalone</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15878">#15878</a> Implement <code>import defer</code> proposal transform support (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
<li><code>babel-generator</code>, <code>babel-parser</code>, <code>babel-types</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15845">#15845</a> Implement <code>import defer</code> parsing support (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
<li><a href="https://redirect.github.com/babel/babel/pull/15829">#15829</a> Add parsing support for the &quot;source phase imports&quot; proposal (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
<li><code>babel-generator</code>, <code>babel-helper-module-transforms</code>, <code>babel-parser</code>, <code>babel-plugin-transform-dynamic-import</code>, <code>babel-plugin-transform-modules-amd</code>, <code>babel-plugin-transform-modules-commonjs</code>, <code>babel-plugin-transform-modules-systemjs</code>, <code>babel-traverse</code>, <code>babel-types</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15682">#15682</a> Add <code>createImportExpressions</code> parser option (<a href="https://github.com/JLHwung"><code>@​JLHwung</code></a>)</li>
</ul>
</li>
<li><code>babel-standalone</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15671">#15671</a> Pass through nonce to the transformed script element (<a href="https://github.com/JLHwung"><code>@​JLHwung</code></a>)</li>
</ul>
</li>
<li><code>babel-helper-function-name</code>, <code>babel-helper-member-expression-to-functions</code>, <code>babel-helpers</code>, <code>babel-parser</code>, <code>babel-plugin-proposal-destructuring-private</code>, <code>babel-plugin-proposal-optional-chaining-assign</code>, <code>babel-plugin-syntax-optional-chaining-assign</code>, <code>babel-plugin-transform-destructuring</code>, <code>babel-plugin-transform-optional-chaining</code>, <code>babel-runtime-corejs2</code>, <code>babel-runtime-corejs3</code>, <code>babel-runtime</code>, <code>babel-standalone</code>, <code>babel-types</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15751">#15751</a> Add support for optional chain in assignments (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
<li><code>babel-helpers</code>, <code>babel-plugin-proposal-decorators</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15895">#15895</a> Implement the &quot;decorator metadata&quot; proposal (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
<li><code>babel-traverse</code>, <code>babel-types</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15893">#15893</a> Add <code>t.buildUndefinedNode</code> (<a href="https://github.com/liuxingbaoyu"><code>@​liuxingbaoyu</code></a>)</li>
</ul>
</li>
<li><code>babel-preset-typescript</code></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/babel/babel/blob/main/CHANGELOG.md"><code>@​babel/traverse</code>'s changelog</a>.</em></p>
<blockquote>
<h2>v7.23.2 (2023-10-11)</h2>
<h4>:bug: Bug Fix</h4>
<ul>
<li><code>babel-traverse</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/16033">#16033</a> Only evaluate own String/Number/Math methods (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
<li><code>babel-preset-typescript</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/16022">#16022</a> Rewrite <code>.tsx</code> extension when using <code>rewriteImportExtensions</code> (<a href="https://github.com/jimmydief"><code>@​jimmydief</code></a>)</li>
</ul>
</li>
<li><code>babel-helpers</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/16017">#16017</a> Fix: fallback to typeof when toString is applied to incompatible object (<a href="https://github.com/JLHwung"><code>@​JLHwung</code></a>)</li>
</ul>
</li>
<li><code>babel-helpers</code>, <code>babel-plugin-transform-modules-commonjs</code>, <code>babel-runtime-corejs2</code>, <code>babel-runtime-corejs3</code>, <code>babel-runtime</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/16025">#16025</a> Avoid override mistake in namespace imports (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
</ul>
<h2>v7.23.0 (2023-09-25)</h2>
<h4>:rocket: New Feature</h4>
<ul>
<li><code>babel-plugin-proposal-import-wasm-source</code>, <code>babel-plugin-syntax-import-source</code>, <code>babel-plugin-transform-dynamic-import</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15870">#15870</a> Support transforming <code>import source</code> for wasm (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
<li><code>babel-helper-module-transforms</code>, <code>babel-helpers</code>, <code>babel-plugin-proposal-import-defer</code>, <code>babel-plugin-syntax-import-defer</code>, <code>babel-plugin-transform-modules-commonjs</code>, <code>babel-runtime-corejs2</code>, <code>babel-runtime-corejs3</code>, <code>babel-runtime</code>, <code>babel-standalone</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15878">#15878</a> Implement <code>import defer</code> proposal transform support (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
<li><code>babel-generator</code>, <code>babel-parser</code>, <code>babel-types</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15845">#15845</a> Implement <code>import defer</code> parsing support (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
<li><a href="https://redirect.github.com/babel/babel/pull/15829">#15829</a> Add parsing support for the &quot;source phase imports&quot; proposal (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
<li><code>babel-generator</code>, <code>babel-helper-module-transforms</code>, <code>babel-parser</code>, <code>babel-plugin-transform-dynamic-import</code>, <code>babel-plugin-transform-modules-amd</code>, <code>babel-plugin-transform-modules-commonjs</code>, <code>babel-plugin-transform-modules-systemjs</code>, <code>babel-traverse</code>, <code>babel-types</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15682">#15682</a> Add <code>createImportExpressions</code> parser option (<a href="https://github.com/JLHwung"><code>@​JLHwung</code></a>)</li>
</ul>
</li>
<li><code>babel-standalone</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15671">#15671</a> Pass through nonce to the transformed script element (<a href="https://github.com/JLHwung"><code>@​JLHwung</code></a>)</li>
</ul>
</li>
<li><code>babel-helper-function-name</code>, <code>babel-helper-member-expression-to-functions</code>, <code>babel-helpers</code>, <code>babel-parser</code>, <code>babel-plugin-proposal-destructuring-private</code>, <code>babel-plugin-proposal-optional-chaining-assign</code>, <code>babel-plugin-syntax-optional-chaining-assign</code>, <code>babel-plugin-transform-destructuring</code>, <code>babel-plugin-transform-optional-chaining</code>, <code>babel-runtime-corejs2</code>, <code>babel-runtime-corejs3</code>, <code>babel-runtime</code>, <code>babel-standalone</code>, <code>babel-types</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15751">#15751</a> Add support for optional chain in assignments (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
<li><code>babel-helpers</code>, <code>babel-plugin-proposal-decorators</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15895">#15895</a> Implement the &quot;decorator metadata&quot; proposal (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
<li><code>babel-traverse</code>, <code>babel-types</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15893">#15893</a> Add <code>t.buildUndefinedNode</code> (<a href="https://github.com/liuxingbaoyu"><code>@​liuxingbaoyu</code></a>)</li>
</ul>
</li>
<li><code>babel-preset-typescript</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15913">#15913</a> Add <code>rewriteImportExtensions</code> option to TS preset (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
<li><code>babel-parser</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15896">#15896</a> Allow TS tuples to have both labeled and unlabeled elements (<a href="https://github.com/yukukotani"><code>@​yukukotani</code></a>)</li>
</ul>
</li>
</ul>
<h4>:bug: Bug Fix</h4>
<ul>
<li><code>babel-plugin-transform-block-scoping</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15962">#15962</a> fix: <code>transform-block-scoping</code> captures the variables of the method in the loop (<a href="https://github.com/liuxingbaoyu"><code>@​liuxingbaoyu</code></a>)</li>
</ul>
</li>
</ul>
<h4>:nail_care: Polish</h4>
<ul>
<li><code>babel-traverse</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15797">#15797</a> Expand evaluation of global built-ins in <code>@babel/traverse</code> (<a href="https://github.com/lorenzoferre"><code>@​lorenzoferre</code></a>)</li>
</ul>
</li>
<li><code>babel-plugin-proposal-explicit-resource-management</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15985">#15985</a> Improve source maps for blocks with <code>using</code> declarations (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
</ul>
<h4>:microscope: Output optimization</h4>
<ul>
<li><code>babel-core</code>, <code>babel-helper-module-transforms</code>, <code>babel-plugin-transform-async-to-generator</code>, <code>babel-plugin-transform-classes</code>, <code>babel-plugin-transform-dynamic-import</code>, <code>babel-plugin-transform-function-name</code>, <code>babel-plugin-transform-modules-amd</code>, <code>babel-plugin-transform-modules-commonjs</code>, <code>babel-plugin-transform-modules-umd</code>, <code>babel-plugin-transform-parameters</code>, <code>babel-plugin-transform-react-constant-elements</code>, <code>babel-plugin-transform-react-inline-elements</code>, <code>babel-plugin-transform-runtime</code>, <code>babel-plugin-transform-typescript</code>, <code>babel-preset-env</code>
<ul>
<li><a href="https://redirect.github.com/babel/babel/pull/15984">#15984</a> Inline <code>exports.XXX =</code> update in simple variable declarations (<a href="https://github.com/nicolo-ribaudo"><code>@​nicolo-ribaudo</code></a>)</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/babel/babel/commit/b4b9942a6cde0685c222eb3412347880aae40ad5"><code>b4b9942</code></a> v7.23.2</li>
<li><a href="https://github.com/babel/babel/commit/b13376b346946e3f62fc0848c1d2a23223314c82"><code>b13376b</code></a> Only evaluate own String/Number/Math methods (<a href="https://github.com/babel/babel/tree/HEAD/packages/babel-traverse/issues/16033">#16033</a>)</li>
<li><a href="https://github.com/babel/babel/commit/ca58ec15cb6dde6812c36997477e44880bec0bba"><code>ca58ec1</code></a> v7.23.0</li>
<li><a href="https://github.com/babel/babel/commit/0f333dafcf470f1970083e4e695ced6aec8bead0"><code>0f333da</code></a> Add <code>createImportExpressions</code> parser option (<a href="https://github.com/babel/babel/tree/HEAD/packages/babel-traverse/issues/15682">#15682</a>)</li>
<li><a href="https://github.com/babel/babel/commit/3744545649fdc21688a2f3c97e1e39dbebff0d21"><code>3744545</code></a> Fix linting</li>
<li><a href="https://github.com/babel/babel/commit/c7e6806e2194deb36c330f543409c792592b22d4"><code>c7e6806</code></a> Add <code>t.buildUndefinedNode</code> (<a href="https://github.com/babel/babel/tree/HEAD/packages/babel-traverse/issues/15893">#15893</a>)</li>
<li><a href="https://github.com/babel/babel/commit/38ee8b4dd693f1e2bd00107bbc1167ce84736ea0"><code>38ee8b4</code></a> Expand evaluation of global built-ins in <code>@babel/traverse</code> (<a href="https://github.com/babel/babel/tree/HEAD/packages/babel-traverse/issues/15797">#15797</a>)</li>
<li>See full diff in <a href="https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@babel/traverse&package-manager=npm_and_yarn&previous-version=7.22.20&new-version=7.23.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

You can trigger a rebase of this PR by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/FontoXML/fontoxpath/network/alerts).

</details>

> **Note**
> Automatic rebases have been disabled on this pull request as it has been open for over 30 days.


bundlemon[bot]: <!-- bundlemon -->
## BundleMon

  
  
  
  
  
  
  
<details>
<summary>Unchanged files (2)</summary>

Status | Path | Size | Limits
:------------: | ------------ | :------------: | :------------:
:white_check_mark: | fontoxpath.esm.js<br/> | 77.61KB | -
:white_check_mark: | fontoxpath.js<br/> | 77.52KB | -
</details>



No change in files bundle size

Final result: :white_check_mark:

[View report in BundleMon website ➡️](https://app.bundlemon.dev/projects/6437c8f89a7cb205c434db8d/reports/6530d5d1d141061b425fd19c)

---
<p align="center"><a href="https://app.bundlemon.dev/projects/6437c8f89a7cb205c434db8d/reports?branch=dependabot%2Fnpm_and_yarn%2Fbabel%2Ftraverse-7.23.2&resolution=all" target="_blank" rel="noreferrer noopener">Current branch size history</a> | <a href="https://app.bundlemon.dev/projects/6437c8f89a7cb205c434db8d/reports?branch=master&resolution=days" target="_blank" rel="noreferrer noopener">Target branch size history</a></p>
coveralls: 
[![Coverage Status](https://coveralls.io/builds/63397743/badge)](https://coveralls.io/builds/63397743)

coverage: 91.58%. remained the same when pulling **27e0e55ea9315d0b9d2eca0666b4e0a2afb92edb on dependabot/npm_and_yarn/babel/traverse-7.23.2** into **dd07d62fd1dea7c171d208f63ac0aa9d38b70719 on master**.


Patch:
diff --git a/LICENSE.md b/LICENSE.md
index 6c89137c..fd39b98f 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2017 Fonto Group BV
+Copyright (c) 2017 Fonto Group BV, Martin Middel
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/package-lock.json b/package-lock.json
index c4ab928c..ce5a5b9e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
 	"name": "fontoxpath",
-	"version": "3.30.2",
+	"version": "3.32.0",
 	"lockfileVersion": 2,
 	"requires": true,
 	"packages": {
 		"": {
 			"name": "fontoxpath",
-			"version": "3.30.2",
+			"version": "3.32.0",
 			"license": "MIT",
 			"dependencies": {
 				"prsc": "4.0.0",
@@ -212,12 +212,12 @@
 			}
 		},
 		"node_modules/@babel/generator": {
-			"version": "7.22.15",
-			"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz",
-			"integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==",
+			"version": "7.23.0",
+			"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
+			"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
 			"dev": true,
 			"dependencies": {
-				"@babel/types": "^7.22.15",
+				"@babel/types": "^7.23.0",
 				"@jridgewell/gen-mapping": "^0.3.2",
 				"@jridgewell/trace-mapping": "^0.3.17",
 				"jsesc": "^2.5.1"
@@ -273,13 +273,13 @@
 			}
 		},
 		"node_modules/@babel/helper-function-name": {
-			"version": "7.22.5",
-			"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
-			"integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
+			"version": "7.23.0",
+			"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+			"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
 			"dev": true,
 			"dependencies": {
-				"@babel/template": "^7.22.5",
-				"@babel/types": "^7.22.5"
+				"@babel/template": "^7.22.15",
+				"@babel/types": "^7.23.0"
 			},
 			"engines": {
 				"node": ">=6.9.0"
@@ -479,9 +479,9 @@
 			}
 		},
 		"node_modules/@babel/parser": {
-			"version": "7.22.16",
-			"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz",
-			"integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==",
+			"version": "7.23.0",
+			"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
+			"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
 			"dev": true,
 			"bin": {
 				"parser": "bin/babel-parser.js"
@@ -517,19 +517,19 @@
 			}
 		},
 		"node_modules/@babel/traverse": {
-			"version": "7.22.20",
-			"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.20.tgz",
-			"integrity": "sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==",
+			"version": "7.23.2",
+			"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
+			"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
 			"dev": true,
 			"dependencies": {
 				"@babel/code-frame": "^7.22.13",
-				"@babel/generator": "^7.22.15",
+				"@babel/generator": "^7.23.0",
 				"@babel/helper-environment-visitor": "^7.22.20",
-				"@babel/helper-function-name": "^7.22.5",
+				"@babel/helper-function-name": "^7.23.0",
 				"@babel/helper-hoist-variables": "^7.22.5",
 				"@babel/helper-split-export-declaration": "^7.22.6",
-				"@babel/parser": "^7.22.16",
-				"@babel/types": "^7.22.19",
+				"@babel/parser": "^7.23.0",
+				"@babel/types": "^7.23.0",
 				"debug": "^4.1.0",
 				"globals": "^11.1.0"
 			},
@@ -547,13 +547,13 @@
 			}
 		},
 		"node_modules/@babel/types": {
-			"version": "7.22.19",
-			"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.19.tgz",
-			"integrity": "sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg==",
+			"version": "7.23.0",
+			"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
+			"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
 			"dev": true,
 			"dependencies": {
 				"@babel/helper-string-parser": "^7.22.5",
-				"@babel/helper-validator-identifier": "^7.22.19",
+				"@babel/helper-validator-identifier": "^7.22.20",
 				"to-fast-properties": "^2.0.0"
 			},
 			"engines": {
@@ -1528,16 +1528,16 @@
 			"dev": true
 		},
 		"node_modules/@typescript-eslint/eslint-plugin": {
-			"version": "6.7.2",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.2.tgz",
-			"integrity": "sha512-ooaHxlmSgZTM6CHYAFRlifqh1OAr3PAQEwi7lhYhaegbnXrnh7CDcHmc3+ihhbQC7H0i4JF0psI5ehzkF6Yl6Q==",
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.16.0.tgz",
+			"integrity": "sha512-O5f7Kv5o4dLWQtPX4ywPPa+v9G+1q1x8mz0Kr0pXUtKsevo+gIJHLkGc8RxaZWtP8RrhwhSNIWThnW42K9/0rQ==",
 			"dev": true,
 			"dependencies": {
 				"@eslint-community/regexpp": "^4.5.1",
-				"@typescript-eslint/scope-manager": "6.7.2",
-				"@typescript-eslint/type-utils": "6.7.2",
-				"@typescript-eslint/utils": "6.7.2",
-				"@typescript-eslint/visitor-keys": "6.7.2",
+				"@typescript-eslint/scope-manager": "6.16.0",
+				"@typescript-eslint/type-utils": "6.16.0",
+				"@typescript-eslint/utils": "6.16.0",
+				"@typescript-eslint/visitor-keys": "6.16.0",
 				"debug": "^4.3.4",
 				"graphemer": "^1.4.0",
 				"ignore": "^5.2.4",
@@ -1583,16 +1583,140 @@
 				"typescript": "*"
 			}
 		},
+		"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": {
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz",
+			"integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==",
+			"dev": true,
+			"dependencies": {
+				"@typescript-eslint/types": "6.16.0",
+				"@typescript-eslint/visitor-keys": "6.16.0"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": {
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz",
+			"integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==",
+			"dev": true,
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": {
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz",
+			"integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==",
+			"dev": true,
+			"dependencies": {
+				"@typescript-eslint/types": "6.16.0",
+				"@typescript-eslint/visitor-keys": "6.16.0",
+				"debug": "^4.3.4",
+				"globby": "^11.1.0",
+				"is-glob": "^4.0.3",
+				"minimatch": "9.0.3",
+				"semver": "^7.5.4",
+				"ts-api-utils": "^1.0.1"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependenciesMeta": {
+				"typescript": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": {
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.16.0.tgz",
+			"integrity": "sha512-T83QPKrBm6n//q9mv7oiSvy/Xq/7Hyw9SzSEhMHJwznEmQayfBM87+oAlkNAMEO7/MjIwKyOHgBJbxB0s7gx2A==",
+			"dev": true,
+			"dependencies": {
+				"@eslint-community/eslint-utils": "^4.4.0",
+				"@types/json-schema": "^7.0.12",
+				"@types/semver": "^7.5.0",
+				"@typescript-eslint/scope-manager": "6.16.0",
+				"@typescript-eslint/types": "6.16.0",
+				"@typescript-eslint/typescript-estree": "6.16.0",
+				"semver": "^7.5.4"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependencies": {
+				"eslint": "^7.0.0 || ^8.0.0"
+			}
+		},
+		"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": {
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz",
+			"integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==",
+			"dev": true,
+			"dependencies": {
+				"@typescript-eslint/types": "6.16.0",
+				"eslint-visitor-keys": "^3.4.1"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/@typescript-eslint/eslint-plugin/node_modules/brace-expansion": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+			"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+			"dev": true,
+			"dependencies": {
+				"balanced-match": "^1.0.0"
+			}
+		},
+		"node_modules/@typescript-eslint/eslint-plugin/node_modules/minimatch": {
+			"version": "9.0.3",
+			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+			"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+			"dev": true,
+			"dependencies": {
+				"brace-expansion": "^2.0.1"
+			},
+			"engines": {
+				"node": ">=16 || 14 >=14.17"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
 		"node_modules/@typescript-eslint/parser": {
-			"version": "6.7.2",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.2.tgz",
-			"integrity": "sha512-KA3E4ox0ws+SPyxQf9iSI25R6b4Ne78ORhNHeVKrPQnoYsb9UhieoiRoJgrzgEeKGOXhcY1i8YtOeCHHTDa6Fw==",
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.16.0.tgz",
+			"integrity": "sha512-H2GM3eUo12HpKZU9njig3DF5zJ58ja6ahj1GoHEHOgQvYxzoFJJEvC1MQ7T2l9Ha+69ZSOn7RTxOdpC/y3ikMw==",
 			"dev": true,
 			"dependencies": {
-				"@typescript-eslint/scope-manager": "6.7.2",
-				"@typescript-eslint/types": "6.7.2",
-				"@typescript-eslint/typescript-estree": "6.7.2",
-				"@typescript-eslint/visitor-keys": "6.7.2",
+				"@typescript-eslint/scope-manager": "6.16.0",
+				"@typescript-eslint/types": "6.16.0",
+				"@typescript-eslint/typescript-estree": "6.16.0",
+				"@typescript-eslint/visitor-keys": "6.16.0",
 				"debug": "^4.3.4"
 			},
 			"engines": {
@@ -1611,6 +1735,105 @@
 				}
 			}
 		},
+		"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": {
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz",
+			"integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==",
+			"dev": true,
+			"dependencies": {
+				"@typescript-eslint/types": "6.16.0",
+				"@typescript-eslint/visitor-keys": "6.16.0"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": {
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz",
+			"integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==",
+			"dev": true,
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": {
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz",
+			"integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==",
+			"dev": true,
+			"dependencies": {
+				"@typescript-eslint/types": "6.16.0",
+				"@typescript-eslint/visitor-keys": "6.16.0",
+				"debug": "^4.3.4",
+				"globby": "^11.1.0",
+				"is-glob": "^4.0.3",
+				"minimatch": "9.0.3",
+				"semver": "^7.5.4",
+				"ts-api-utils": "^1.0.1"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependenciesMeta": {
+				"typescript": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": {
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz",
+			"integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==",
+			"dev": true,
+			"dependencies": {
+				"@typescript-eslint/types": "6.16.0",
+				"eslint-visitor-keys": "^3.4.1"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/@typescript-eslint/parser/node_modules/brace-expansion": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+			"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+			"dev": true,
+			"dependencies": {
+				"balanced-match": "^1.0.0"
+			}
+		},
+		"node_modules/@typescript-eslint/parser/node_modules/minimatch": {
+			"version": "9.0.3",
+			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+			"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+			"dev": true,
+			"dependencies": {
+				"brace-expansion": "^2.0.1"
+			},
+			"engines": {
+				"node": ">=16 || 14 >=14.17"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
 		"node_modules/@typescript-eslint/scope-manager": {
 			"version": "6.7.2",
 			"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.2.tgz",
@@ -1629,13 +1852,13 @@
 			}
 		},
 		"node_modules/@typescript-eslint/type-utils": {
-			"version": "6.7.2",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.2.tgz",
-			"integrity": "sha512-36F4fOYIROYRl0qj95dYKx6kybddLtsbmPIYNK0OBeXv2j9L5nZ17j9jmfy+bIDHKQgn2EZX+cofsqi8NPATBQ==",
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.16.0.tgz",
+			"integrity": "sha512-ThmrEOcARmOnoyQfYkHw/DX2SEYBalVECmoldVuH6qagKROp/jMnfXpAU/pAIWub9c4YTxga+XwgAkoA0pxfmg==",
 			"dev": true,
 			"dependencies": {
-				"@typescript-eslint/typescript-estree": "6.7.2",
-				"@typescript-eslint/utils": "6.7.2",
+				"@typescript-eslint/typescript-estree": "6.16.0",
+				"@typescript-eslint/utils": "6.16.0",
 				"debug": "^4.3.4",
 				"ts-api-utils": "^1.0.1"
 			},
@@ -1655,6 +1878,130 @@
 				}
 			}
 		},
+		"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": {
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz",
+			"integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==",
+			"dev": true,
+			"dependencies": {
+				"@typescript-eslint/types": "6.16.0",
+				"@typescript-eslint/visitor-keys": "6.16.0"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": {
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz",
+			"integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==",
+			"dev": true,
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": {
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz",
+			"integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==",
+			"dev": true,
+			"dependencies": {
+				"@typescript-eslint/types": "6.16.0",
+				"@typescript-eslint/visitor-keys": "6.16.0",
+				"debug": "^4.3.4",
+				"globby": "^11.1.0",
+				"is-glob": "^4.0.3",
+				"minimatch": "9.0.3",
+				"semver": "^7.5.4",
+				"ts-api-utils": "^1.0.1"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependenciesMeta": {
+				"typescript": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": {
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.16.0.tgz",
+			"integrity": "sha512-T83QPKrBm6n//q9mv7oiSvy/Xq/7Hyw9SzSEhMHJwznEmQayfBM87+oAlkNAMEO7/MjIwKyOHgBJbxB0s7gx2A==",
+			"dev": true,
+			"dependencies": {
+				"@eslint-community/eslint-utils": "^4.4.0",
+				"@types/json-schema": "^7.0.12",
+				"@types/semver": "^7.5.0",
+				"@typescript-eslint/scope-manager": "6.16.0",
+				"@typescript-eslint/types": "6.16.0",
+				"@typescript-eslint/typescript-estree": "6.16.0",
+				"semver": "^7.5.4"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			},
+			"peerDependencies": {
+				"eslint": "^7.0.0 || ^8.0.0"
+			}
+		},
+		"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": {
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz",
+			"integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==",
+			"dev": true,
+			"dependencies": {
+				"@typescript-eslint/types": "6.16.0",
+				"eslint-visitor-keys": "^3.4.1"
+			},
+			"engines": {
+				"node": "^16.0.0 || >=18.0.0"
+			},
+			"funding": {
+				"type": "opencollective",
+				"url": "https://opencollective.com/typescript-eslint"
+			}
+		},
+		"node_modules/@typescript-eslint/type-utils/node_modules/brace-expansion": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+			"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+			"dev": true,
+			"dependencies": {
+				"balanced-match": "^1.0.0"
+			}
+		},
+		"node_modules/@typescript-eslint/type-utils/node_modules/minimatch": {
+			"version": "9.0.3",
+			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+			"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+			"dev": true,
+			"dependencies": {
+				"brace-expansion": "^2.0.1"
+			},
+			"engines": {
+				"node": ">=16 || 14 >=14.17"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/isaacs"
+			}
+		},
 		"node_modules/@typescript-eslint/types": {
 			"version": "6.7.2",
 			"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.2.tgz",
@@ -2271,12 +2618,12 @@
 			}
 		},
 		"node_modules/braces": {
-			"version": "3.0.2",
-			"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-			"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+			"version": "3.0.3",
+			"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+			"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
 			"dev": true,
 			"dependencies": {
-				"fill-range": "^7.0.1"
+				"fill-range": "^7.1.1"
 			},
 			"engines": {
 				"node": ">=8"
@@ -4160,9 +4507,9 @@
 			}
 		},
 		"node_modules/fill-range": {
-			"version": "7.0.1",
-			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-			"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+			"version": "7.1.1",
+			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+			"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
 			"dev": true,
 			"dependencies": {
 				"to-regex-range": "^5.0.1"
@@ -4325,9 +4672,9 @@
 			}
 		},
 		"node_modules/follow-redirects": {
-			"version": "1.15.3",
-			"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
-			"integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==",
+			"version": "1.15.4",
+			"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
+			"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
 			"dev": true,
 			"funding": [
 				{
@@ -10343,12 +10690,12 @@
 			}
 		},
 		"@babel/generator": {
-			"version": "7.22.15",
-			"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz",
-			"integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==",
+			"version": "7.23.0",
+			"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
+			"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
 			"dev": true,
 			"requires": {
-				"@babel/types": "^7.22.15",
+				"@babel/types": "^7.23.0",
 				"@jridgewell/gen-mapping": "^0.3.2",
 				"@jridgewell/trace-mapping": "^0.3.17",
 				"jsesc": "^2.5.1"
@@ -10390,13 +10737,13 @@
 			"dev": true
 		},
 		"@babel/helper-function-name": {
-			"version": "7.22.5",
-			"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
-			"integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
+			"version": "7.23.0",
+			"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+			"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
 			"dev": true,
 			"requires": {
-				"@babel/template": "^7.22.5",
-				"@babel/types": "^7.22.5"
+				"@babel/template": "^7.22.15",
+				"@babel/types": "^7.23.0"
 			}
 		},
 		"@babel/helper-hoist-variables": {
@@ -10547,9 +10894,9 @@
 			}
 		},
 		"@babel/parser": {
-			"version": "7.22.16",
-			"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz",
-			"integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==",
+			"version": "7.23.0",
+			"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
+			"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
 			"dev": true
 		},
 		"@babel/runtime": {
@@ -10573,19 +10920,19 @@
 			}
 		},
 		"@babel/traverse": {
-			"version": "7.22.20",
-			"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.20.tgz",
-			"integrity": "sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw==",
+			"version": "7.23.2",
+			"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
+			"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
 			"dev": true,
 			"requires": {
 				"@babel/code-frame": "^7.22.13",
-				"@babel/generator": "^7.22.15",
+				"@babel/generator": "^7.23.0",
 				"@babel/helper-environment-visitor": "^7.22.20",
-				"@babel/helper-function-name": "^7.22.5",
+				"@babel/helper-function-name": "^7.23.0",
 				"@babel/helper-hoist-variables": "^7.22.5",
 				"@babel/helper-split-export-declaration": "^7.22.6",
-				"@babel/parser": "^7.22.16",
-				"@babel/types": "^7.22.19",
+				"@babel/parser": "^7.23.0",
+				"@babel/types": "^7.23.0",
 				"debug": "^4.1.0",
 				"globals": "^11.1.0"
 			},
@@ -10599,13 +10946,13 @@
 			}
 		},
 		"@babel/types": {
-			"version": "7.22.19",
-			"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.19.tgz",
-			"integrity": "sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg==",
+			"version": "7.23.0",
+			"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
+			"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
 			"dev": true,
 			"requires": {
 				"@babel/helper-string-parser": "^7.22.5",
-				"@babel/helper-validator-identifier": "^7.22.19",
+				"@babel/helper-validator-identifier": "^7.22.20",
 				"to-fast-properties": "^2.0.0"
 			}
 		},
@@ -11409,22 +11756,99 @@
 			"dev": true
 		},
 		"@typescript-eslint/eslint-plugin": {
-			"version": "6.7.2",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.2.tgz",
-			"integrity": "sha512-ooaHxlmSgZTM6CHYAFRlifqh1OAr3PAQEwi7lhYhaegbnXrnh7CDcHmc3+ihhbQC7H0i4JF0psI5ehzkF6Yl6Q==",
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.16.0.tgz",
+			"integrity": "sha512-O5f7Kv5o4dLWQtPX4ywPPa+v9G+1q1x8mz0Kr0pXUtKsevo+gIJHLkGc8RxaZWtP8RrhwhSNIWThnW42K9/0rQ==",
 			"dev": true,
 			"requires": {
 				"@eslint-community/regexpp": "^4.5.1",
-				"@typescript-eslint/scope-manager": "6.7.2",
-				"@typescript-eslint/type-utils": "6.7.2",
-				"@typescript-eslint/utils": "6.7.2",
-				"@typescript-eslint/visitor-keys": "6.7.2",
+				"@typescript-eslint/scope-manager": "6.16.0",
+				"@typescript-eslint/type-utils": "6.16.0",
+				"@typescript-eslint/utils": "6.16.0",
+				"@typescript-eslint/visitor-keys": "6.16.0",
 				"debug": "^4.3.4",
 				"graphemer": "^1.4.0",
 				"ignore": "^5.2.4",
 				"natural-compare": "^1.4.0",
 				"semver": "^7.5.4",
 				"ts-api-utils": "^1.0.1"
+			},
+			"dependencies": {
+				"@typescript-eslint/scope-manager": {
+					"version": "6.16.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz",
+					"integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==",
+					"dev": true,
+					"requires": {
+						"@typescript-eslint/types": "6.16.0",
+						"@typescript-eslint/visitor-keys": "6.16.0"
+					}
+				},
+				"@typescript-eslint/types": {
+					"version": "6.16.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz",
+					"integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==",
+					"dev": true
+				},
+				"@typescript-eslint/typescript-estree": {
+					"version": "6.16.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz",
+					"integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==",
+					"dev": true,
+					"requires": {
+						"@typescript-eslint/types": "6.16.0",
+						"@typescript-eslint/visitor-keys": "6.16.0",
+						"debug": "^4.3.4",
+						"globby": "^11.1.0",
+						"is-glob": "^4.0.3",
+						"minimatch": "9.0.3",
+						"semver": "^7.5.4",
+						"ts-api-utils": "^1.0.1"
+					}
+				},
+				"@typescript-eslint/utils": {
+					"version": "6.16.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.16.0.tgz",
+					"integrity": "sha512-T83QPKrBm6n//q9mv7oiSvy/Xq/7Hyw9SzSEhMHJwznEmQayfBM87+oAlkNAMEO7/MjIwKyOHgBJbxB0s7gx2A==",
+					"dev": true,
+					"requires": {
+						"@eslint-community/eslint-utils": "^4.4.0",
+						"@types/json-schema": "^7.0.12",
+						"@types/semver": "^7.5.0",
+						"@typescript-eslint/scope-manager": "6.16.0",
+						"@typescript-eslint/types": "6.16.0",
+						"@typescript-eslint/typescript-estree": "6.16.0",
+						"semver": "^7.5.4"
+					}
+				},
+				"@typescript-eslint/visitor-keys": {
+					"version": "6.16.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz",
+					"integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==",
+					"dev": true,
+					"requires": {
+						"@typescript-eslint/types": "6.16.0",
+						"eslint-visitor-keys": "^3.4.1"
+					}
+				},
+				"brace-expansion": {
+					"version": "2.0.1",
+					"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+					"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+					"dev": true,
+					"requires": {
+						"balanced-match": "^1.0.0"
+					}
+				},
+				"minimatch": {
+					"version": "9.0.3",
+					"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+					"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+					"dev": true,
+					"requires": {
+						"brace-expansion": "^2.0.1"
+					}
+				}
 			}
 		},
 		"@typescript-eslint/eslint-plugin-tslint": {
@@ -11437,16 +11861,78 @@
 			}
 		},
 		"@typescript-eslint/parser": {
-			"version": "6.7.2",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.2.tgz",
-			"integrity": "sha512-KA3E4ox0ws+SPyxQf9iSI25R6b4Ne78ORhNHeVKrPQnoYsb9UhieoiRoJgrzgEeKGOXhcY1i8YtOeCHHTDa6Fw==",
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.16.0.tgz",
+			"integrity": "sha512-H2GM3eUo12HpKZU9njig3DF5zJ58ja6ahj1GoHEHOgQvYxzoFJJEvC1MQ7T2l9Ha+69ZSOn7RTxOdpC/y3ikMw==",
 			"dev": true,
 			"requires": {
-				"@typescript-eslint/scope-manager": "6.7.2",
-				"@typescript-eslint/types": "6.7.2",
-				"@typescript-eslint/typescript-estree": "6.7.2",
-				"@typescript-eslint/visitor-keys": "6.7.2",
+				"@typescript-eslint/scope-manager": "6.16.0",
+				"@typescript-eslint/types": "6.16.0",
+				"@typescript-eslint/typescript-estree": "6.16.0",
+				"@typescript-eslint/visitor-keys": "6.16.0",
 				"debug": "^4.3.4"
+			},
+			"dependencies": {
+				"@typescript-eslint/scope-manager": {
+					"version": "6.16.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz",
+					"integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==",
+					"dev": true,
+					"requires": {
+						"@typescript-eslint/types": "6.16.0",
+						"@typescript-eslint/visitor-keys": "6.16.0"
+					}
+				},
+				"@typescript-eslint/types": {
+					"version": "6.16.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz",
+					"integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==",
+					"dev": true
+				},
+				"@typescript-eslint/typescript-estree": {
+					"version": "6.16.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz",
+					"integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==",
+					"dev": true,
+					"requires": {
+						"@typescript-eslint/types": "6.16.0",
+						"@typescript-eslint/visitor-keys": "6.16.0",
+						"debug": "^4.3.4",
+						"globby": "^11.1.0",
+						"is-glob": "^4.0.3",
+						"minimatch": "9.0.3",
+						"semver": "^7.5.4",
+						"ts-api-utils": "^1.0.1"
+					}
+				},
+				"@typescript-eslint/visitor-keys": {
+					"version": "6.16.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz",
+					"integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==",
+					"dev": true,
+					"requires": {
+						"@typescript-eslint/types": "6.16.0",
+						"eslint-visitor-keys": "^3.4.1"
+					}
+				},
+				"brace-expansion": {
+					"version": "2.0.1",
+					"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+					"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+					"dev": true,
+					"requires": {
+						"balanced-match": "^1.0.0"
+					}
+				},
+				"minimatch": {
+					"version": "9.0.3",
+					"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+					"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+					"dev": true,
+					"requires": {
+						"brace-expansion": "^2.0.1"
+					}
+				}
 			}
 		},
 		"@typescript-eslint/scope-manager": {
@@ -11460,15 +11946,92 @@
 			}
 		},
 		"@typescript-eslint/type-utils": {
-			"version": "6.7.2",
-			"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.2.tgz",
-			"integrity": "sha512-36F4fOYIROYRl0qj95dYKx6kybddLtsbmPIYNK0OBeXv2j9L5nZ17j9jmfy+bIDHKQgn2EZX+cofsqi8NPATBQ==",
+			"version": "6.16.0",
+			"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.16.0.tgz",
+			"integrity": "sha512-ThmrEOcARmOnoyQfYkHw/DX2SEYBalVECmoldVuH6qagKROp/jMnfXpAU/pAIWub9c4YTxga+XwgAkoA0pxfmg==",
 			"dev": true,
 			"requires": {
-				"@typescript-eslint/typescript-estree": "6.7.2",
-				"@typescript-eslint/utils": "6.7.2",
+				"@typescript-eslint/typescript-estree": "6.16.0",
+				"@typescript-eslint/utils": "6.16.0",
 				"debug": "^4.3.4",
 				"ts-api-utils": "^1.0.1"
+			},
+			"dependencies": {
+				"@typescript-eslint/scope-manager": {
+					"version": "6.16.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz",
+					"integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==",
+					"dev": true,
+					"requires": {
+						"@typescript-eslint/types": "6.16.0",
+						"@typescript-eslint/visitor-keys": "6.16.0"
+					}
+				},
+				"@typescript-eslint/types": {
+					"version": "6.16.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz",
+					"integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==",
+					"dev": true
+				},
+				"@typescript-eslint/typescript-estree": {
+					"version": "6.16.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz",
+					"integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==",
+					"dev": true,
+					"requires": {
+						"@typescript-eslint/types": "6.16.0",
+						"@typescript-eslint/visitor-keys": "6.16.0",
+						"debug": "^4.3.4",
+						"globby": "^11.1.0",
+						"is-glob": "^4.0.3",
+						"minimatch": "9.0.3",
+						"semver": "^7.5.4",
+						"ts-api-utils": "^1.0.1"
+					}
+				},
+				"@typescript-eslint/utils": {
+					"version": "6.16.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.16.0.tgz",
+					"integrity": "sha512-T83QPKrBm6n//q9mv7oiSvy/Xq/7Hyw9SzSEhMHJwznEmQayfBM87+oAlkNAMEO7/MjIwKyOHgBJbxB0s7gx2A==",
+					"dev": true,
+					"requires": {
+						"@eslint-community/eslint-utils": "^4.4.0",
+						"@types/json-schema": "^7.0.12",
+						"@types/semver": "^7.5.0",
+						"@typescript-eslint/scope-manager": "6.16.0",
+						"@typescript-eslint/types": "6.16.0",
+						"@typescript-eslint/typescript-estree": "6.16.0",
+						"semver": "^7.5.4"
+					}
+				},
+				"@typescript-eslint/visitor-keys": {
+					"version": "6.16.0",
+					"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz",
+					"integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==",
+					"dev": true,
+					"requires": {
+						"@typescript-eslint/types": "6.16.0",
+						"eslint-visitor-keys": "^3.4.1"
+					}
+				},
+				"brace-expansion": {
+					"version": "2.0.1",
+					"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+					"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+					"dev": true,
+					"requires": {
+						"balanced-match": "^1.0.0"
+					}
+				},
+				"minimatch": {
+					"version": "9.0.3",
+					"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+					"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+					"dev": true,
+					"requires": {
+						"brace-expansion": "^2.0.1"
+					}
+				}
 			}
 		},
 		"@typescript-eslint/types": {
@@ -11920,12 +12483,12 @@
 			}
 		},
 		"braces": {
-			"version": "3.0.2",
-			"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-			"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+			"version": "3.0.3",
+			"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+			"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
 			"dev": true,
 			"requires": {
-				"fill-range": "^7.0.1"
+				"fill-range": "^7.1.1"
 			}
 		},
 		"brotli-size": {
@@ -13340,9 +13903,9 @@
 			}
 		},
 		"fill-range": {
-			"version": "7.0.1",
-			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-			"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+			"version": "7.1.1",
+			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+			"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
 			"dev": true,
 			"requires": {
 				"to-regex-range": "^5.0.1"
@@ -13482,9 +14045,9 @@
 			}
 		},
 		"follow-redirects": {
-			"version": "1.15.3",
-			"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
-			"integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==",
+			"version": "1.15.4",
+			"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
+			"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
 			"dev": true
 		},
 		"for-each": {
diff --git a/package.json b/package.json
index 00bf11ae..0005dd57 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "fontoxpath",
-	"version": "3.30.2",
+	"version": "3.32.0",
 	"description": "A minimalistic XPath 3.1 engine in JavaScript",
 	"main": "dist/fontoxpath.js",
 	"module": "dist/fontoxpath.esm.js",
diff --git a/src/domFacade/ConcreteNode.ts b/src/domFacade/ConcreteNode.ts
index 8f84393e..7ed11174 100644
--- a/src/domFacade/ConcreteNode.ts
+++ b/src/domFacade/ConcreteNode.ts
@@ -28,6 +28,9 @@ export type ConcreteCDATASectionNode = CDATASection & { nodeType: NODE_TYPES.CDA
 export type ConcreteDocumentTypeNode = DocumentType & { nodeType: NODE_TYPES.DOCUMENT_TYPE_NODE };
 export type ConcreteAttributeNode = Attr & { nodeType: NODE_TYPES.ATTRIBUTE_NODE };
 export type ConcreteDocumentNode = Document & { nodeType: NODE_TYPES.DOCUMENT_NODE };
+export type ConcreteDocumentFragmentNode = DocumentFragment & {
+	nodeType: NODE_TYPES.DOCUMENT_FRAGMENT_NODE;
+};
 export type ConcreteProcessingInstructionNode = ProcessingInstruction & {
 	nodeType: NODE_TYPES.PROCESSING_INSTRUCTION_NODE;
 };
@@ -47,4 +50,5 @@ export type ConcreteNode =
 	| ConcreteChildNode
 	| ConcreteParentNode
 	| ConcreteAttributeNode
-	| ConcreteDocumentTypeNode;
+	| ConcreteDocumentTypeNode
+	| ConcreteDocumentFragmentNode;
diff --git a/src/expressions/dataTypes/Value.ts b/src/expressions/dataTypes/Value.ts
index 857fb6a6..311b94c3 100644
--- a/src/expressions/dataTypes/Value.ts
+++ b/src/expressions/dataTypes/Value.ts
@@ -81,10 +81,11 @@ export const enum ValueType {
 }
 
 /**
- * Handles the occurances in the XPath specs.
- * Zero or one matches to '?';
- * One or more matches to '+';
- * Zero or more matches to '*'
+ * Handles the occurences in the XPath specs.
+ *
+ * * Zero or one matches to '?';
+ * * One or more matches to '+';
+ * * Zero or more matches to '*';
  *
  * @private
  */
diff --git a/src/expressions/dataTypes/atomize.ts b/src/expressions/dataTypes/atomize.ts
index b5bb53c3..77ecbdb2 100644
--- a/src/expressions/dataTypes/atomize.ts
+++ b/src/expressions/dataTypes/atomize.ts
@@ -79,7 +79,11 @@ export function atomizeSingleValue(
 				);
 				return;
 			}
-			if (aNodeType === NODE_TYPES.ELEMENT_NODE || aNodeType === NODE_TYPES.DOCUMENT_NODE) {
+			if (
+				aNodeType === NODE_TYPES.ELEMENT_NODE ||
+				aNodeType === NODE_TYPES.DOCUMENT_NODE ||
+				aNodeType === NODE_TYPES.DOCUMENT_FRAGMENT_NODE
+			) {
 				const children = domFacade.getChildNodes(
 					aNode as ConcreteParentNode | TinyParentNode,
 				);
diff --git a/src/expressions/functions/builtInFunctions_node.ts b/src/expressions/functions/builtInFunctions_node.ts
index 23235f0c..42006831 100644
--- a/src/expressions/functions/builtInFunctions_node.ts
+++ b/src/expressions/functions/builtInFunctions_node.ts
@@ -30,7 +30,7 @@ import { errXPDY0002 } from '../XPathErrors';
 import { BuiltinDeclarationType } from './builtInFunctions';
 import builtinStringFunctions from './builtInFunctions_string';
 import FunctionDefinitionType from './FunctionDefinitionType';
-
+import generateId from './generateId';
 const fnString = builtinStringFunctions.functions.string;
 
 function contextItemAsFirstArgument(
@@ -123,6 +123,23 @@ const fnData: FunctionDefinitionType = (
 	return atomize(sequence, executionParameters);
 };
 
+const fnGenerateId: FunctionDefinitionType = (
+	dynamicContext,
+	executionParameters,
+	_staticContext,
+	nodeValue,
+) => {
+	if (nodeValue.isEmpty()) {
+		return sequenceFactory.singleton(createAtomicValue('', ValueType.XSSTRING));
+	}
+	if (!isSubtypeOf(nodeValue.first().type, ValueType.NODE)) {
+		throw new Error('XPTY0004: The context item must be a node.');
+	}
+	const node = nodeValue.first().value as NodePointer;
+
+	return sequenceFactory.singleton(createAtomicValue(generateId(node), ValueType.XSSTRING));
+};
+
 const fnHasChildren: FunctionDefinitionType = (
 	_dynamicContext,
 	executionParameters,
@@ -165,6 +182,78 @@ function areSameNode(
 	return true;
 }
 
+/**
+ * Test if a string should match the xml:lang attribute string of a node.
+ */
+function langMatchString(truth: string, test: string): boolean {
+	truth = truth.toLowerCase();
+	test = test.toLowerCase();
+	if (truth === test) {
+		return true;
+	} else {
+		return truth.length < 5 || !truth.startsWith(test)
+			? false
+			: /* Strip the least specific part and test again */
+			  langMatchString(truth.replace(/-[a-z0-9]+$/, ''), test);
+	}
+}
+
+/**
+ * Starting at a given node, test the xml:lang attribute to see if it
+   matches a test. Move up the tree until the test passes or fails.
+ */
+function langMatchNode(node: NodePointer, domFacade: DomFacade, test: string): ISequence {
+	let toTest = node;
+	while (toTest) {
+		if (domFacade.getNodeType(toTest) !== NODE_TYPES.ELEMENT_NODE) {
+			toTest = domFacade.getParentNodePointer(toTest as AttributeNodePointer);
+		} else if (domFacade.getNodeType(toTest) === NODE_TYPES.ELEMENT_NODE) {
+			const attrValue = domFacade.getAttribute(toTest as ElementNodePointer, 'xml:lang');
+			if (attrValue) {
+				return langMatchString(attrValue, test)
+					? sequenceFactory.singletonTrueSequence()
+					: sequenceFactory.singletonFalseSequence();
+			} else {
+				toTest = domFacade.getParentNodePointer(toTest as ElementNodePointer);
+			}
+		}
+	}
+	return sequenceFactory.singletonFalseSequence();
+}
+
+const fnLang: FunctionDefinitionType = (
+	dynamicContext,
+	executionParameters,
+	_staticContext,
+	langTestValue,
+	nodeValue,
+) => {
+	const domFacade = executionParameters.domFacade;
+	let langTest;
+	if (langTestValue.isEmpty()) {
+		langTest = '';
+	} else if (!isSubtypeOf(langTestValue.first().type, ValueType.XSSTRING)) {
+		throw new Error('XPTY0004: The first argument of lang must be a string.');
+	} else {
+		langTest = langTestValue.first().value;
+	}
+	let node;
+	if (!nodeValue) {
+		if (!dynamicContext || !dynamicContext.contextItem) {
+			throw errXPDY0002(
+				`The function lang depends on dynamic context if a node is not passed as the second argument.`,
+			);
+		}
+		if (!isSubtypeOf(dynamicContext.contextItem.type, ValueType.NODE)) {
+			throw new Error('XPTY0004: The context item must be a node.');
+		}
+		node = dynamicContext.contextItem.value;
+	} else {
+		node = nodeValue.first().value;
+	}
+	return langMatchNode(node, domFacade, langTest);
+};
+
 const fnPath: FunctionDefinitionType = (
 	_dynamicContext,
 	executionParameters,
@@ -545,6 +634,38 @@ const declarations: BuiltinDeclarationType[] = [
 		namespaceURI: BUILT_IN_NAMESPACE_URIS.FUNCTIONS_NAMESPACE_URI,
 		returnType: { type: ValueType.XSANYATOMICTYPE, mult: SequenceMultiplicity.ZERO_OR_MORE },
 	},
+
+	{
+		argumentTypes: [{ type: ValueType.XSSTRING, mult: SequenceMultiplicity.ZERO_OR_ONE }],
+		callFunction: fnLang,
+		localName: 'lang',
+		namespaceURI: BUILT_IN_NAMESPACE_URIS.FUNCTIONS_NAMESPACE_URI,
+		returnType: { type: ValueType.XSBOOLEAN, mult: SequenceMultiplicity.EXACTLY_ONE },
+	},
+	{
+		argumentTypes: [
+			{ type: ValueType.XSSTRING, mult: SequenceMultiplicity.ZERO_OR_ONE },
+			{ type: ValueType.NODE, mult: SequenceMultiplicity.EXACTLY_ONE },
+		],
+		callFunction: fnLang,
+		localName: 'lang',
+		namespaceURI: BUILT_IN_NAMESPACE_URIS.FUNCTIONS_NAMESPACE_URI,
+		returnType: { type: ValueType.XSBOOLEAN, mult: SequenceMultiplicity.EXACTLY_ONE },
+	},
+	{
+		argumentTypes: [],
+		callFunction: contextItemAsFirstArgument.bind(null, 'generate-id', fnGenerateId),
+		localName: 'generate-id',
+		namespaceURI: BUILT_IN_NAMESPACE_URIS.FUNCTIONS_NAMESPACE_URI,
+		returnType: { type: ValueType.XSSTRING, mult: SequenceMultiplicity.EXACTLY_ONE },
+	},
+	{
+		argumentTypes: [{ type: ValueType.NODE, mult: SequenceMultiplicity.ZERO_OR_ONE }],
+		callFunction: fnGenerateId,
+		localName: 'generate-id',
+		namespaceURI: BUILT_IN_NAMESPACE_URIS.FUNCTIONS_NAMESPACE_URI,
+		returnType: { type: ValueType.XSSTRING, mult: SequenceMultiplicity.EXACTLY_ONE },
+	},
 ];
 
 export default {
diff --git a/src/expressions/functions/builtInFunctions_string.ts b/src/expressions/functions/builtInFunctions_string.ts
index f347b16d..291c775b 100644
--- a/src/expressions/functions/builtInFunctions_string.ts
+++ b/src/expressions/functions/builtInFunctions_string.ts
@@ -355,11 +355,25 @@ const fnTokenize: FunctionDefinitionType = (
 	const patternString: string = pattern.first().value;
 
 	const regex = compileJSRegex(patternString);
+	regex.lastIndex = 0;
+	const results = [];
+	let result = regex.exec(inputString);
+
+	let index = 0;
+
+	// Repeatedly execute the regex to get all the outputs
+	// TODO: with this approach it should not be too difficult to actually use XSPattern here.
+	while (result) {
+		results.push(inputString.slice(index, result.index));
+		index = regex.lastIndex;
+		result = regex.exec(inputString);
+	}
+
+	// Don't forget the last split part!
+	results.push(inputString.slice(index));
 
 	return sequenceFactory.create(
-		inputString
-			.split(regex)
-			.map((token: string) => createAtomicValue(token, ValueType.XSSTRING)),
+		results.map((token: string) => createAtomicValue(token, ValueType.XSSTRING)),
 	);
 };
 
diff --git a/src/expressions/functions/generateId.ts b/src/expressions/functions/generateId.ts
new file mode 100644
index 00000000..c92b2344
--- /dev/null
+++ b/src/expressions/functions/generateId.ts
@@ -0,0 +1,15 @@
+import { ConcreteNode } from '../../domFacade/ConcreteNode';
+import { NodePointer, TinyNode } from '../../domClone/Pointer';
+
+const generateIdMap: WeakMap<TinyNode | ConcreteNode, string> = new WeakMap();
+let generateIdCounter = 0;
+
+function generateId(ptr: NodePointer): string {
+	const node = ptr.node;
+	if (!generateIdMap.has(node)) {
+		generateIdMap.set(node, `id${++generateIdCounter}`);
+	}
+	return generateIdMap.get(node);
+}
+
+export default generateId;
diff --git a/src/expressions/xquery/SwitchExpression.ts b/src/expressions/xquery/SwitchExpression.ts
new file mode 100644
index 00000000..fb77e6f8
--- /dev/null
+++ b/src/expressions/xquery/SwitchExpression.ts
@@ -0,0 +1,135 @@
+import ISequence from '../dataTypes/ISequence';
+import sequenceFactory from '../dataTypes/sequenceFactory';
+import { SequenceType } from '../dataTypes/Value';
+import DynamicContext from '../DynamicContext';
+import ExecutionParameters from '../ExecutionParameters';
+import Expression, { RESULT_ORDERINGS } from '../Expression';
+import sequenceDeepEqual, {
+	itemDeepEqual,
+} from '../functions/builtInFunctions_sequences_deepEqual';
+import PossiblyUpdatingExpression, { SequenceCallbacks } from '../PossiblyUpdatingExpression';
+import Specificity from '../Specificity';
+import StaticContext from '../StaticContext';
+import atomizeSequence from '../util/atomizeSequence';
+import { IterationHint } from '../util/iterators';
+import { errXUST0001 } from '../xquery-update/XQueryUpdateFacilityErrors';
+import { errXPTY0004 } from './XQueryErrors';
+
+export type SwitchExpressionClause = {
+	caseClauseExpression: PossiblyUpdatingExpression;
+	tests: Expression[];
+};
+
+class SwitchExpression extends PossiblyUpdatingExpression {
+	private _amountOfCases: number;
+	private _argExpression: Expression;
+	private _testsByCase: Expression[][];
+
+	constructor(
+		argExpression: Expression,
+		caseClauses: SwitchExpressionClause[],
+		defaultExpression: PossiblyUpdatingExpression,
+		type: SequenceType,
+	) {
+		const specificity = new Specificity({});
+		super(
+			specificity,
+			[
+				argExpression,
+				defaultExpression,
+				...caseClauses.map((clause) => clause.caseClauseExpression),
+			].concat(...caseClauses.map((clause) => clause.tests.map((test) => test))),
+			{
+				canBeStaticallyEvaluated: false,
+				peer: false,
+				resultOrder: RESULT_ORDERINGS.UNSORTED,
+				subtree: false,
+			},
+			type,
+		);
+		this._argExpression = argExpression;
+		this._amountOfCases = caseClauses.length;
+		this._testsByCase = caseClauses.map((clause) => clause.tests);
+	}
+
+	public performFunctionalEvaluation(
+		dynamicContext: DynamicContext,
+		executionParameters: ExecutionParameters,
+		sequenceCallbacks: ((dynamicContext: DynamicContext) => ISequence)[],
+	) {
+		// Pick the argumentExpression.
+		const evaluatedExpression = atomizeSequence(
+			sequenceCallbacks[0](dynamicContext),
+			executionParameters,
+		);
+		const [
+			_argSequenceCallback,
+			defaultSequenceCallback,
+			...caseClauseAndTestSequenceCallbacks
+		] = sequenceCallbacks;
+		// Map over all values the type test, and return the result.
+		return evaluatedExpression.switchCases({
+			multiple: () => {
+				throw errXPTY0004(
+					'The operand for a switch expression should result in zero or one item',
+				);
+			},
+			default: () => {
+				const singleValue = evaluatedExpression.first();
+				const isEmpty = !singleValue;
+
+				for (let i = 0; i < this._amountOfCases; i++) {
+					const results = this._testsByCase[i].map((x) =>
+						x.evaluateMaybeStatically(dynamicContext, executionParameters),
+					);
+
+					for (const result of results) {
+						const atomizedResult = atomizeSequence(result, executionParameters);
+						if (atomizedResult.isEmpty()) {
+							if (isEmpty) {
+								return caseClauseAndTestSequenceCallbacks[i](dynamicContext);
+							}
+							continue;
+						}
+
+						if (!atomizedResult.isSingleton()) {
+							throw errXPTY0004(
+								'The operand for a switch case should result in zero or one item',
+							);
+						}
+
+						if (isEmpty) {
+							continue;
+						}
+
+						const first = atomizedResult.first();
+
+						if (
+							itemDeepEqual(
+								dynamicContext,
+								executionParameters,
+								null,
+								singleValue,
+								first,
+							).next(IterationHint.NONE).value
+						) {
+							return caseClauseAndTestSequenceCallbacks[i](dynamicContext);
+						}
+					}
+				}
+
+				return defaultSequenceCallback(dynamicContext);
+			},
+		});
+	}
+
+	public performStaticEvaluation(staticContext: StaticContext) {
+		super.performStaticEvaluation(staticContext);
+
+		if (this._argExpression.isUpdating) {
+			throw errXUST0001();
+		}
+	}
+}
+
+export default SwitchExpression;
diff --git a/src/parsing/compileAstToExpression.ts b/src/parsing/compileAstToExpression.ts
index babe7aec..39fb3c10 100644
--- a/src/parsing/compileAstToExpression.ts
+++ b/src/parsing/compileAstToExpression.ts
@@ -68,6 +68,7 @@ import ElementConstructor from '../expressions/xquery/ElementConstructor';
 import PIConstructor from '../expressions/xquery/PIConstructor';
 import TextConstructor from '../expressions/xquery/TextConstructor';
 import TypeSwitchExpression from '../expressions/xquery/TypeSwitchExpression';
+import SwitchExpression from '../expressions/xquery/SwitchExpression';
 import astHelper, { IAST } from './astHelper';
 
 const COMPILATION_OPTIONS = {
@@ -204,6 +205,8 @@ function compile(ast: IAST, compilationOptions: CompilationOptions): Expression
 
 		case 'typeswitchExpr':
 			return typeswitchExpr(ast, compilationOptions);
+		case 'switchExpr':
+			return switchExpr(ast, compilationOptions);
 
 		// XQuery node constructors
 		case 'elementConstructor':
@@ -1481,7 +1484,7 @@ function typeswitchExpr(ast: IAST, compilationOptions: CompilationOptions) {
 	const caseClause = astHelper.getChildren(ast, 'typeswitchExprCaseClause');
 
 	const caseClauseExpressions = caseClause.map((caseClauseExpression) => {
-		const sequenceTypesAstNodes: IAST[] =
+		const caseNodes: IAST[] =
 			astHelper.getChildren(caseClauseExpression, 'sequenceTypeUnion').length === 0
 				? [astHelper.getFirstChild(caseClauseExpression, 'sequenceType')]
 				: astHelper.getChildren(
@@ -1496,7 +1499,7 @@ function typeswitchExpr(ast: IAST, compilationOptions: CompilationOptions) {
 
 		return {
 			caseClauseExpression: resultExpression,
-			typeTests: sequenceTypesAstNodes.map((sequenceTypeAstNode: IAST) => {
+			typeTests: caseNodes.map((sequenceTypeAstNode: IAST) => {
 				const occurrenceIndicator = astHelper.getFirstChild(
 					sequenceTypeAstNode,
 					'occurrenceIndicator',
@@ -1522,6 +1525,44 @@ function typeswitchExpr(ast: IAST, compilationOptions: CompilationOptions) {
 	return new TypeSwitchExpression(argExpr, caseClauseExpressions, defaultExpression, type);
 }
 
+function switchExpr(ast: IAST, compilationOptions: CompilationOptions) {
+	if (!compilationOptions.allowXQuery) {
+		throw new Error('XPST0003: Use of XQuery functionality is not allowed in XPath context');
+	}
+
+	const type = astHelper.getAttribute(ast, 'type');
+
+	const argExpr = compile(
+		astHelper.getFirstChild(astHelper.getFirstChild(ast, 'argExpr'), '*'),
+		compilationOptions,
+	);
+
+	const caseClauses = astHelper.getChildren(ast, 'switchExprCaseClause');
+
+	const caseClauseExpressions = caseClauses.map((caseClauseExpression) => {
+		const caseNodes: IAST[] = astHelper.getChildren(caseClauseExpression, 'switchCaseExpr');
+
+		const resultExpression = compile(
+			astHelper.followPath(caseClauseExpression, ['resultExpr', '*']),
+			compilationOptions,
+		) as PossiblyUpdatingExpression;
+
+		return {
+			caseClauseExpression: resultExpression,
+			tests: caseNodes.map((caseNode) =>
+				compile(astHelper.getFirstChild(caseNode, '*'), compilationOptions),
+			),
+		};
+	});
+
+	const defaultExpression = compile(
+		astHelper.followPath(ast, ['switchExprDefaultClause', 'resultExpr', '*']),
+		compilationOptions,
+	) as PossiblyUpdatingExpression;
+
+	return new SwitchExpression(argExpr, caseClauseExpressions, defaultExpression, type);
+}
+
 export default function (xPathAst: IAST, compilationOptions: CompilationOptions): Expression {
 	return compile(xPathAst, compilationOptions);
 }
diff --git a/src/parsing/prscParser.ts b/src/parsing/prscParser.ts
index 1287f7a3..7f62f52f 100644
--- a/src/parsing/prscParser.ts
+++ b/src/parsing/prscParser.ts
@@ -1813,25 +1813,33 @@ function generateParser(options: { outputDebugInfo: boolean; xquery: boolean }):
 
 	const switchCaseClause: Parser<IAST> = then(
 		plus(
-			map(precededMultiple([tokens.CASE, whitespacePlus], switchCaseOperand), (x) => [
-				'switchCaseExpr',
-				x,
-			]),
+			then(
+				map(
+					precededMultiple([tokens.CASE, whitespacePlus], cut(switchCaseOperand)),
+					(x) => ['switchCaseExpr', x],
+				),
+				cut(whitespacePlus),
+				(x, _) => x,
+			),
 		),
-		precededMultiple([whitespacePlus, tokens.RETURN, whitespacePlus], exprSingle),
+		cut(precededMultiple([tokens.RETURN, whitespacePlus], cut(exprSingle))),
 		(operands, exprPart) =>
 			['switchExprCaseClause', ...operands, ['resultExpr', exprPart]] as IAST,
 	);
 
 	const switchExpr: Parser<IAST> = then3(
-		precededMultiple([tokens.SWITCH, whitespace, tokens.BRACE_OPEN], expr),
-		precededMultiple(
-			[whitespace, tokens.BRACE_CLOSE, whitespace],
-			plus(followed(switchCaseClause, whitespace)),
+		precededMultiple([tokens.SWITCH, whitespace, tokens.BRACE_OPEN], cut(expr)),
+		cut(
+			precededMultiple(
+				[whitespace, tokens.BRACE_CLOSE, cut(whitespace)],
+				plus(followed(switchCaseClause, whitespace)),
+			),
 		),
-		precededMultiple(
-			[tokens.DEFAULT, whitespacePlus, tokens.RETURN, whitespacePlus],
-			exprSingle,
+		cut(
+			precededMultiple(
+				[tokens.DEFAULT, whitespacePlus, tokens.RETURN, whitespacePlus],
+				exprSingle,
+			),
 		),
 		(exprPart, clauses, resultExpr) => [
 			'switchExpr',
diff --git a/src/registerXQueryModule.ts b/src/registerXQueryModule.ts
index 25004bba..d0c7055b 100644
--- a/src/registerXQueryModule.ts
+++ b/src/registerXQueryModule.ts
@@ -49,10 +49,15 @@ export default function registerXQueryModule(
 	moduleString: string,
 	options: { debug: boolean } = { debug: false },
 ): string {
-	const parsedModule = parseExpression(moduleString, {
-		allowXQuery: true,
-		debug: options['debug'],
-	});
+	let parsedModule;
+	try {
+		parsedModule = parseExpression(moduleString, {
+			allowXQuery: true,
+			debug: options['debug'],
+		});
+	} catch (error) {
+		printAndRethrowError(moduleString, error);
+	}
 
 	annotateAst(parsedModule, new AnnotationContext(undefined));
 


Test patch:
diff --git a/test/assets/failingXQueryXTestNames.csv b/test/assets/failingXQueryXTestNames.csv
index 91e30755..049247f6 100644
--- a/test/assets/failingXQueryXTestNames.csv
+++ b/test/assets/failingXQueryXTestNames.csv
@@ -2670,8 +2670,6 @@ string-constructor-026,Parse error
 string-constructor-910,Parse error
 string-constructor-911,Parse error
 string-constructor-912,Parse error
-switch-004,Parse error
-switch-005,Parse error
 try-001,Parse error
 try-002,Parse error
 try-003,Parse error
diff --git a/test/assets/runnableTestSets.csv b/test/assets/runnableTestSets.csv
index 09794f25..f864b73d 100644
--- a/test/assets/runnableTestSets.csv
+++ b/test/assets/runnableTestSets.csv
@@ -111,7 +111,7 @@ fn-insert-before,true
 fn-iri-to-uri,true
 fn-json-doc,false
 fn-json-to-xml,false
-fn-lang,false
+fn-lang,true
 fn-last,true
 fn-load-xquery-module,false
 fn-local-name,false
@@ -408,7 +408,7 @@ prod-SequenceType,true
 prod-SquareArrayConstructor,true
 prod-StepExpr,true
 prod-StringConstructor,true
-prod-SwitchExpr,false
+prod-SwitchExpr,true
 prod-TreatExpr,false
 prod-TryCatchExpr,false
 prod-TypeswitchExpr,true
diff --git a/test/assets/unrunnableTestCases.csv b/test/assets/unrunnableTestCases.csv
index 013e0a8e..79a5f487 100644
--- a/test/assets/unrunnableTestCases.csv
+++ b/test/assets/unrunnableTestCases.csv
@@ -607,10 +607,6 @@ fn-function-lookup-259,AssertionError: Expected XPath exists(function-lookup(fn:
 fn-function-lookup-260,Error: XPTY0004: Expected base expression of a function call to evaluate to a sequence of single function item
 fn-function-lookup-261,AssertionError: Expected XPath exists(function-lookup(fn:QName('http://www.w3.org/2005/xpath-functions', 'in-scope-prefixes'), 1)) to resolve to true: expected false to be true
 fn-function-lookup-262,Error: XPTY0004: Expected base expression of a function call to evaluate to a sequence of single function item
-fn-function-lookup-275,AssertionError: Expected XPath exists(function-lookup(fn:QName('http://www.w3.org/2005/xpath-functions', 'lang'), 1)) to resolve to true: expected false to be true
-fn-function-lookup-276,Error: XPTY0004: Expected base expression of a function call to evaluate to a sequence of single function item
-fn-function-lookup-277,AssertionError: Expected XPath exists(function-lookup(fn:QName('http://www.w3.org/2005/xpath-functions', 'lang'), 2)) to resolve to true: expected false to be true
-fn-function-lookup-278,Error: XPTY0004: Expected base expression of a function call to evaluate to a sequence of single function item
 fn-function-lookup-318,Error: FOCH0002: No collations are supported
 fn-function-lookup-320,Error: XPTY0004: eqOp not available for xs:integer and xs:string
 fn-function-lookup-322,Error: FOCH0002: No collations are supported
@@ -621,10 +617,6 @@ fn-function-lookup-353,AssertionError: Expected XPath exists(function-lookup(fn:
 fn-function-lookup-354,Error: XPTY0004: Expected base expression of a function call to evaluate to a sequence of single function item
 fn-function-lookup-355,AssertionError: Expected XPath exists(function-lookup(fn:QName('http://www.w3.org/2005/xpath-functions', 'element-with-id'), 2)) to resolve to true: expected false to be true
 fn-function-lookup-356,Error: XPTY0004: Expected base expression of a function call to evaluate to a sequence of single function item
-fn-function-lookup-361,AssertionError: Expected XPath exists(function-lookup(fn:QName('http://www.w3.org/2005/xpath-functions', 'generate-id'), 0)) to resolve to true: expected false to be true
-fn-function-lookup-362,Error: XPTY0004: Expected base expression of a function call to evaluate to a sequence of single function item
-fn-function-lookup-363,AssertionError: Expected XPath exists(function-lookup(fn:QName('http://www.w3.org/2005/xpath-functions', 'generate-id'), 1)) to resolve to true: expected false to be true
-fn-function-lookup-364,Error: XPTY0004: Expected base expression of a function call to evaluate to a sequence of single function item
 fn-function-lookup-365,AssertionError: Expected XPath exists(function-lookup(fn:QName('http://www.w3.org/2005/xpath-functions', 'doc'), 1)) to resolve to true: expected false to be true
 fn-function-lookup-366,Error: XPTY0004: Expected base expression of a function call to evaluate to a sequence of single function item
 fn-function-lookup-367,AssertionError: Expected XPath exists(function-lookup(fn:QName('http://www.w3.org/2005/xpath-functions', 'doc-available'), 1)) to resolve to true: expected false to be true
@@ -727,33 +719,13 @@ fn-function-name-014,AssertionError: Expected executing the XPath "fn:function-n
 fn-function-name-018,AssertionError: Expected executing the XPath "fn:function-name( concat#340282366920938463463374607431768211456 )" to resolve to one of the expected results, but got AssertionError: expected [Function] to throw error matching /FOAR0002/ but got 'Invalid array length', RangeError: Invalid array length.
 fn-function-name-023,Error: 1: ( 2: 	declare function local:add($arg1, $arg2, $arg3)    	        ^ 3:         { 4:            $arg1 + $arg2 + $arg3  Error: XPST0003: Failed to parse script. Expected -,+,validate,(#,(,#,parent::,ancestor::,preceding-sibling::,preceding::,ancestor-or-self::,..,child::,descendant::,attribute::,self::,descendant-or-self::,following-sibling::,following::,document-node(,element,attribute,schema-element,schema-attribute(,processing-instruction(,processing-instruction(),comment(),text(),namespace-node(),node(),:*,Q,[A-Z_a-z\xC0-\xD6\xD8-\xF6\xF8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD],[\uD800-\uDB7F],/,//   at <>:2:10 - 2:11
 fn-function-name-024,Error: No selector counterpart for: typedFunctionTest.
-generate-id-000,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 1 not registered. No similar functions found.
-generate-id-001,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 1 not registered. No similar functions found.
-generate-id-002,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 1 not registered. No similar functions found.
-generate-id-003,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 1 not registered. No similar functions found.
-generate-id-004,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 1 not registered. No similar functions found.
-generate-id-005,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 1 not registered. No similar functions found.
-generate-id-006,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 1 not registered. No similar functions found.
-generate-id-008,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 0 not registered. No similar functions found.
-generate-id-009,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 0 not registered. No similar functions found.
-generate-id-010,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 0 not registered. No similar functions found.
 generate-id-012,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}collection with arity of 0 not registered. No similar functions found.
 generate-id-013,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}collection with arity of 0 not registered. No similar functions found.
 generate-id-014,Error: No selector counterpart for: computedDocumentConstructor.
 generate-id-015,Error: No selector counterpart for: computedDocumentConstructor.
 generate-id-016,Error: No selector counterpart for: computedDocumentConstructor.
 generate-id-017,Error: No selector counterpart for: computedDocumentConstructor.
-generate-id-018,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 1 not registered. No similar functions found.
-generate-id-019,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 0 not registered. No similar functions found.
-generate-id-020,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 1 not registered. No similar functions found.
-generate-id-021,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 1 not registered. No similar functions found.
-generate-id-022,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 1 not registered. No similar functions found.
-generate-id-023,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 1 not registered. No similar functions found.
-generate-id-901,AssertionError: expected [Function] to throw error matching /XPDY0002/ but got 'XPST0017: Function Q{http://www.w3.or…'
-generate-id-902,AssertionError: expected [Function] to throw error matching /XPTY0004/ but got 'XPST0017: Function Q{http://www.w3.or…'
-generate-id-903,AssertionError: expected [Function] to throw error matching /XPTY0004/ but got 'XPST0017: Function Q{http://www.w3.or…'
-generate-id-904,AssertionError: expected [Function] to throw error matching /XPTY0004/ but got 'XPST0017: Function Q{http://www.w3.or…'
-generate-id-905,AssertionError: expected [Function] to throw error matching /XPTY0004/ but got 'XPST0017: Function Q{http://www.w3.or…'
+generate-id-018,Error: XPTY0004: Multiplicity of function argument of type node()? for generate-id is incorrect. Expected "?", but got "+".
 fn-has-children-007,AssertionError: Expected executing the XPath "(1)[fn:has-children()]" to resolve to one of the expected results, but got AssertionError: expected [Function] to throw error matching /XPTY0004/ but got 'Cannot read properties of undefined (…'.
 fn-has-children-008,AssertionError: Expected executing the XPath "(fn:concat#2)[fn:has-children()]" to resolve to one of the expected results, but got AssertionError: expected [Function] to throw error matching /XPTY0004/ but got 'Cannot read properties of undefined (…'.
 fn-has-children-012,AssertionError: expected [Function] to throw an error
@@ -804,6 +776,8 @@ K-SeqInsertBeforeFunc-17,Error: No selector counterpart for: treatExpr.
 K-SeqInsertBeforeFunc-18,Error: No selector counterpart for: treatExpr.
 K-SeqInsertBeforeFunc-19,Error: No selector counterpart for: treatExpr.
 K-SeqInsertBeforeFunc-20,Error: No selector counterpart for: treatExpr.
+fn-lang-31,AssertionError: Expected XPath let $l := /langs/para[4]!fn:lang#1 return /langs/para[1]!$l('en') to resolve to false: expected true to be false
+fn-lang-32,AssertionError: Expected XPath let $l := /langs/para[4]!fn:lang#1 return /langs/para[1]!$l('de') to resolve to true: expected false to be true
 K-ContextLastFunc-5,Error: No selector counterpart for: treatExpr.
 K-ContextLastFunc-24,Error: No selector counterpart for: treatExpr.
 K-ContextLastFunc-25,Error: No selector counterpart for: treatExpr.
@@ -1625,7 +1599,6 @@ cbcl-timezone-from-date-007,Error: XPST0017: Function Q{http://www.w3.org/2005/x
 fn-tokenize-2,AssertionError: expected [Function] to throw error matching /FORX0001/ but got 'Not implemented: Using flags in token…'
 fn-tokenize-5,Error: Not implemented: Using flags in tokenize is not supported
 fn-tokenize-6,Error: Not implemented: Using flags in tokenize is not supported
-fn-tokenize-9,AssertionError: string-join(fn:tokenize("abracadabra", "(ab)|(a)"), '#'): expected '#ab##r##a#c##a#d#ab##r##a#' to equal '#r#c#d#r#'
 fn-tokenize-31,Error: Not implemented: Using flags in tokenize is not supported
 fn-tokenize-32,Error: Not implemented: Using flags in tokenize is not supported
 fn-tokenize-35,Error: Not implemented: Using flags in tokenize is not supported
@@ -2984,7 +2957,6 @@ K-FunctionCallExpr-5,AssertionError: expected [Function] to throw error matching
 K-FunctionCallExpr-15a,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}format-number with arity of 2 not registered. Did you mean "Q{http://www.w3.org/2005/xpath-functions}format-integer (xs:integer?, xs:string)"?
 K-FunctionCallExpr-16a,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}format-time with arity of 2 not registered. Did you mean "Q{http://www.w3.org/2005/xpath-functions}current-time ()" or "Q{http://www.w3.org/2005/xpath-functions}format-integer (xs:integer?, xs:string)"?
 K-FunctionCallExpr-17a,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}format-time with arity of 5 not registered. Did you mean "Q{http://www.w3.org/2005/xpath-functions}current-time ()" or "Q{http://www.w3.org/2005/xpath-functions}format-integer (xs:integer?, xs:string)"?
-K-FunctionCallExpr-25a,Error: XPST0017: Function generate-id with arity of 1 not registered. No similar functions found.
 function-call-reserved-function-names-034,AssertionError: expected [Function] to throw error matching /XPST0017/ but got '1: \n2: \tnamespace-node(1)\n   \t   …'
 function-declaration-017,Error: XPST0008, The variable v is not in scope.
 function-declaration-022,AssertionError: expected [Function] to throw error matching /XQST0034/ but got 'XQST0049: The function or variable "Q…'
@@ -3161,10 +3133,6 @@ function-literal-259,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-fu
 function-literal-260,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}namespace-uri-for-prefix with arity of 2 not registered. Did you mean "Q{http://www.w3.org/2005/xpath-functions}namespace-uri-from-QName (xs:QName?)", "Q{http://www.w3.org/2005/xpath-functions}namespace-uri (node())" or "Q{http://www.w3.org/2005/xpath-functions}namespace-uri ()"?
 function-literal-261,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}in-scope-prefixes with arity of 1 not registered. No similar functions found.
 function-literal-262,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}in-scope-prefixes with arity of 1 not registered. No similar functions found.
-function-literal-275,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}lang with arity of 1 not registered. Did you mean "Q{http://www.w3.org/2001/XMLSchema}long (xs:anyAtomicType?)"?
-function-literal-276,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}lang with arity of 1 not registered. Did you mean "Q{http://www.w3.org/2001/XMLSchema}long (xs:anyAtomicType?)"?
-function-literal-277,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}lang with arity of 2 not registered. Did you mean "Q{http://www.w3.org/2001/XMLSchema}long (xs:anyAtomicType?)"?
-function-literal-278,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}lang with arity of 2 not registered. Did you mean "Q{http://www.w3.org/2001/XMLSchema}long (xs:anyAtomicType?)"?
 function-literal-318,Error: FOCH0002: No collations are supported
 function-literal-320,Error: XPTY0004: eqOp not available for xs:integer and xs:string
 function-literal-322,Error: FOCH0002: No collations are supported
@@ -3175,10 +3143,6 @@ function-literal-353,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-fu
 function-literal-354,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}element-with-id with arity of 1 not registered. No similar functions found.
 function-literal-355,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}element-with-id with arity of 2 not registered. No similar functions found.
 function-literal-356,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}element-with-id with arity of 2 not registered. No similar functions found.
-function-literal-361,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 0 not registered. No similar functions found.
-function-literal-362,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 0 not registered. No similar functions found.
-function-literal-363,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 1 not registered. No similar functions found.
-function-literal-364,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}generate-id with arity of 1 not registered. No similar functions found.
 function-literal-365,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}doc with arity of 1 not registered. No similar functions found.
 function-literal-366,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}doc with arity of 1 not registered. No similar functions found.
 function-literal-367,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}doc-available with arity of 1 not registered. No similar functions found.
@@ -3443,6 +3407,7 @@ string-constructor-028,Error: 1: ( 2:         declare variable $n external := <e
 string-constructor-910,AssertionError: expected [Function] to throw error matching /FOTY0013/ but got '1: \n2:         declare variable $n e…'
 string-constructor-911,AssertionError: expected [Function] to throw error matching /FOTY0013/ but got '1: \n2:         declare variable $n e…'
 string-constructor-912,Error: 1:  2:         declare variable $n as xs:integer external := 10;  3:         ``[There were `{1 to $n}` green bottles]``            ^ 4:        = "There were 1 2 3 4 5 6 7 8 9 10 green bottles"  Error: XPST0003: Failed to parse script. Expected -,+,validate,(#,(,#,parent::,ancestor::,preceding-sibling::,preceding::,ancestor-or-self::,..,child::,descendant::,attribute::,self::,descendant-or-self::,following-sibling::,following::,document-node(,element,attribute,schema-element,schema-attribute(,processing-instruction(,processing-instruction(),comment(),text(),namespace-node(),node(),:*,Q,[A-Z_a-z\xC0-\xD6\xD8-\xF6\xF8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD],[\uD800-\uDB7F],/,//   at <>:3:9 - 3:10
+switch-018,AssertionError: Expected XPath            let $v := xs:time('00:00:00Z')          return switch($v)          case xs:time('24:00:00Z') return 1          default return 2        to resolve to 1: expected false to be true
 typeswitchhc16,Error: XPST0008, The variable i is not in scope.
 typeswitchhc20,Error: XPST0008, The variable i is not in scope.
 K-sequenceExprTypeswitch-6,Error: No selector counterpart for: voidSequenceType.
@@ -3784,13 +3749,6 @@ functx-fn-escape-html-uri-2,Error: XPST0017: Function Q{http://www.w3.org/2005/x
 functx-fn-escape-html-uri-all,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}escape-html-uri with arity of 1 not registered. Did you mean "Q{http://www.w3.org/2005/xpath-functions}encode-for-uri (xs:string?)"?
 functx-fn-index-of-5,Error: XPTY0004: eqOp not available for xs:integer and xs:string
 functx-fn-index-of-all,Error: XPTY0004: eqOp not available for xs:integer and xs:string
-functx-fn-lang-1,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}lang with arity of 1 not registered. Did you mean "Q{http://www.w3.org/2001/XMLSchema}long (xs:anyAtomicType?)"?
-functx-fn-lang-2,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}lang with arity of 1 not registered. Did you mean "Q{http://www.w3.org/2001/XMLSchema}long (xs:anyAtomicType?)"?
-functx-fn-lang-3,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}lang with arity of 1 not registered. Did you mean "Q{http://www.w3.org/2001/XMLSchema}long (xs:anyAtomicType?)"?
-functx-fn-lang-4,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}lang with arity of 1 not registered. Did you mean "Q{http://www.w3.org/2001/XMLSchema}long (xs:anyAtomicType?)"?
-functx-fn-lang-5,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}lang with arity of 1 not registered. Did you mean "Q{http://www.w3.org/2001/XMLSchema}long (xs:anyAtomicType?)"?
-functx-fn-lang-6,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}lang with arity of 1 not registered. Did you mean "Q{http://www.w3.org/2001/XMLSchema}long (xs:anyAtomicType?)"?
-functx-fn-lang-all,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}lang with arity of 1 not registered. Did you mean "Q{http://www.w3.org/2001/XMLSchema}long (xs:anyAtomicType?)"?
 functx-fn-matches-10,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}matches with arity of 3 not registered. Did you mean "Q{http://www.w3.org/2005/xpath-functions}matches (xs:string?, xs:string)"?
 functx-fn-matches-12,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}matches with arity of 3 not registered. Did you mean "Q{http://www.w3.org/2005/xpath-functions}matches (xs:string?, xs:string)"?
 functx-fn-matches-14,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}matches with arity of 3 not registered. Did you mean "Q{http://www.w3.org/2005/xpath-functions}matches (xs:string?, xs:string)"?
@@ -3838,8 +3796,6 @@ functx-functx-dynamic-path-all,Error: No selector counterpart for: computedDocum
 functx-functx-get-matches-1,AssertionError: declare namespace functx = "http://www.example.com/";                     (:~ : Splits a string into matching and non-matching regions : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_get-matches-and-non-matches.html : @param $string the string to split : @param $regex the pattern :)          declare function functx:get-matches-and-non-matches ( $string as xs:string? , $regex as xs:string ) as element()* { let $iomf := functx:index-of-match-first($string, $regex) return if (empty($iomf)) then <non-match>{$string}</non-match> else if ($iomf > 1) then (<non-match>{substring($string,1,$iomf - 1)}</non-match>, functx:get-matches-and-non-matches( substring($string,$iomf),$regex)) else let $length := string-length($string) - string-length(functx:replace-first($string, $regex,'')) return (<match>{substring($string,1,$length)}</match>, if (string-length($string) > $length) then functx:get-matches-and-non-matches( substring($string,$length + 1),$regex) else ()) } ;                     (:~ : Return the matching regions of a string : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_get-matches.html : @param $string the string to split : @param $regex the pattern :)          declare function functx:get-matches ( $string as xs:string? , $regex as xs:string ) as xs:string* { functx:get-matches-and-non-matches($string,$regex)/ string(self::match) } ;                     (:~ : The first position of a matching substring : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_index-of-match-first.html : @param $arg the string : @param $pattern the pattern to match :)          declare function functx:index-of-match-first ( $arg as xs:string? , $pattern as xs:string ) as xs:integer? { if (matches($arg,$pattern)) then string-length(tokenize($arg, $pattern)[1]) + 1 else () } ;                     (:~ : Replaces the first match of a pattern : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_replace-first.html : @param $arg the entire string to change : @param $pattern the pattern of characters to replace : @param $replacement the replacement string :)          declare function functx:replace-first ( $arg as xs:string? , $pattern as xs:string , $replacement as xs:string ) as xs:string { replace($arg, concat('(^.*?)', $pattern), concat('$1',$replacement)) } ;                     (functx:get-matches( 'abc123def', '\d+')): expected '123  ' to equal ' 123 '
 functx-functx-get-matches-2,AssertionError: declare namespace functx = "http://www.example.com/";                     (:~ : Splits a string into matching and non-matching regions : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_get-matches-and-non-matches.html : @param $string the string to split : @param $regex the pattern :)          declare function functx:get-matches-and-non-matches ( $string as xs:string? , $regex as xs:string ) as element()* { let $iomf := functx:index-of-match-first($string, $regex) return if (empty($iomf)) then <non-match>{$string}</non-match> else if ($iomf > 1) then (<non-match>{substring($string,1,$iomf - 1)}</non-match>, functx:get-matches-and-non-matches( substring($string,$iomf),$regex)) else let $length := string-length($string) - string-length(functx:replace-first($string, $regex,'')) return (<match>{substring($string,1,$length)}</match>, if (string-length($string) > $length) then functx:get-matches-and-non-matches( substring($string,$length + 1),$regex) else ()) } ;                     (:~ : Return the matching regions of a string : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_get-matches.html : @param $string the string to split : @param $regex the pattern :)          declare function functx:get-matches ( $string as xs:string? , $regex as xs:string ) as xs:string* { functx:get-matches-and-non-matches($string,$regex)/ string(self::match) } ;                     (:~ : The first position of a matching substring : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_index-of-match-first.html : @param $arg the string : @param $pattern the pattern to match :)          declare function functx:index-of-match-first ( $arg as xs:string? , $pattern as xs:string ) as xs:integer? { if (matches($arg,$pattern)) then string-length(tokenize($arg, $pattern)[1]) + 1 else () } ;                     (:~ : Replaces the first match of a pattern : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_replace-first.html : @param $arg the entire string to change : @param $pattern the pattern of characters to replace : @param $replacement the replacement string :)          declare function functx:replace-first ( $arg as xs:string? , $pattern as xs:string , $replacement as xs:string ) as xs:string { replace($arg, concat('(^.*?)', $pattern), concat('$1',$replacement)) } ;                     (functx:get-matches( 'abc123def', '\d')): expected ' 1 3  2' to equal ' 1 2 3 '
 functx-functx-get-matches-all,AssertionError: declare namespace functx = "http://www.example.com/";                     (:~ : Splits a string into matching and non-matching regions : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_get-matches-and-non-matches.html : @param $string the string to split : @param $regex the pattern :)          declare function functx:get-matches-and-non-matches ( $string as xs:string? , $regex as xs:string ) as element()* { let $iomf := functx:index-of-match-first($string, $regex) return if (empty($iomf)) then <non-match>{$string}</non-match> else if ($iomf > 1) then (<non-match>{substring($string,1,$iomf - 1)}</non-match>, functx:get-matches-and-non-matches( substring($string,$iomf),$regex)) else let $length := string-length($string) - string-length(functx:replace-first($string, $regex,'')) return (<match>{substring($string,1,$length)}</match>, if (string-length($string) > $length) then functx:get-matches-and-non-matches( substring($string,$length + 1),$regex) else ()) } ;                     (:~ : Return the matching regions of a string : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_get-matches.html : @param $string the string to split : @param $regex the pattern :)          declare function functx:get-matches ( $string as xs:string? , $regex as xs:string ) as xs:string* { functx:get-matches-and-non-matches($string,$regex)/ string(self::match) } ;                     (:~ : The first position of a matching substring : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_index-of-match-first.html : @param $arg the string : @param $pattern the pattern to match :)          declare function functx:index-of-match-first ( $arg as xs:string? , $pattern as xs:string ) as xs:integer? { if (matches($arg,$pattern)) then string-length(tokenize($arg, $pattern)[1]) + 1 else () } ;                     (:~ : Replaces the first match of a pattern : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_replace-first.html : @param $arg the entire string to change : @param $pattern the pattern of characters to replace : @param $replacement the replacement string :)          declare function functx:replace-first ( $arg as xs:string? , $pattern as xs:string , $replacement as xs:string ) as xs:string { replace($arg, concat('(^.*?)', $pattern), concat('$1',$replacement)) } ;                     (functx:get-matches( 'abc123def', '\d+'), functx:get-matches( 'abc123def', '\d'), functx:get-matches( 'abc123def', '[a-z]{2}')): expected '123    1 3  2 ab  de ' to equal ' 123   1 2 3  ab  de '
-functx-functx-line-count-2,AssertionError: Expected XPath declare namespace functx = "http://www.example.com/";                     (:~ : The number of lines : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_line-count.html : @param $arg the string to test :)          declare function functx:line-count ( $arg as xs:string? ) as xs:integer { count(functx:lines($arg)) } ;                     (:~ : Split a string into separate lines : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_lines.html : @param $arg the string to split :)          declare function functx:lines ( $arg as xs:string? ) as xs:string* { tokenize($arg, '(\r\n?|\n\r?)') } ;          let $lines := 'a              value              on              many              lines' return (functx:line-count($lines))        to resolve to 5: expected false to be true
-functx-functx-line-count-all,AssertionError: declare namespace functx = "http://www.example.com/";                     (:~ : The number of lines : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_line-count.html : @param $arg the string to test :)          declare function functx:line-count ( $arg as xs:string? ) as xs:integer { count(functx:lines($arg)) } ;                     (:~ : Split a string into separate lines : : @author Priscilla Walmsley, Datypic : @version 1.0 : @see http://www.xqueryfunctions.com/xq/functx_lines.html : @param $arg the string to split :)          declare function functx:lines ( $arg as xs:string? ) as xs:string* { tokenize($arg, '(\r\n?|\n\r?)') } ;          let $lines := 'a                      value                      on                      many                      lines'           return (functx:line-count('a value'), functx:line-count($lines)): expected '1 9' to equal '1 5'
 functx-functx-next-day-1,Error: Not implemented: adding durations to xs:date
 functx-functx-next-day-2,Error: Not implemented: adding durations to xs:date
 functx-functx-next-day-all,Error: Not implemented: adding durations to xs:date
@@ -3876,7 +3832,6 @@ UseCaseR31-002,Error: Not implemented: groupByClause is not implemented yet.
 UseCaseR31-003,Error: Not implemented: groupByClause is not implemented yet.
 UseCaseR31-004,Error: 1: let $result := (        ^ 2:         declare namespace map="http://www.w3.org/2005/xpath-functions/map"; 3:   Error: XPST0003: Failed to parse script. Expected end of input   at <>:1:5 - 1:6
 UseCaseR31-009,Error: 1: let $result := (        ^ 2:       declare namespace map="http://www.w3.org/2005/xpath-functions/map"; 3:       declare variable $book:= (<book>  Error: XPST0003: Failed to parse script. Expected end of input   at <>:1:5 - 1:6
-UseCaseR31-012,Error: No selector counterpart for: switchExpr.
 UseCaseR31-015,Error: Not implemented: groupByClause is not implemented yet.
 UseCaseR31-016,Error: 1: deep-equal((              ^ 2:               declare variable $s :=[['A', 'DT'], ['bride', 'NN'], [',', ','], ['you', 'PRP'], ['know', 'VBP'], [',', ','], ['must', 'MD'], 3:  ['appear', 'VB'], ['like', 'IN'], ['a', 'DT'], ['bride', 'NN'], [',', ','], ['but', 'CC'], ['my', 'PRP$'],  Error: XPST0003: Failed to parse script. Expected end of input   at <>:1:11 - 1:12
 UseCaseR31-017,Error: 1: deep-equal((              ^ 2:               declare variable $s :=[['A', 'DT'], ['bride', 'NN'], [',', ','], ['you', 'PRP'], ['know', 'VBP'], [',', ','], ['must', 'MD'], 3:  ['appear', 'VB'], ['like', 'IN'], ['a', 'DT'], ['bride', 'NN'], [',', ','], ['but', 'CC'], ['my', 'PRP$'],  Error: XPST0003: Failed to parse script. Expected end of input   at <>:1:11 - 1:12
@@ -4131,7 +4086,6 @@ fo-test-fn-idref-001,Error: No selector counterpart for: validateExpr.
 fo-test-fn-idref-002,Error: No selector counterpart for: validateExpr.
 fo-test-fn-serialize-001,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}serialize with arity of 2 not registered. Did you mean "Q{http://www.w3.org/2005/xpath-functions}serialize (item()*)"?
 fo-test-fn-serialize-002,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}serialize with arity of 2 not registered. Did you mean "Q{http://www.w3.org/2005/xpath-functions}serialize (item()*)"?
-fo-test-fn-filter-002,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}lang with arity of 2 not registered. Did you mean "Q{http://www.w3.org/2001/XMLSchema}long (xs:anyAtomicType?)"?
 fo-test-fn-for-each-pair-001,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}for-each-pair with arity of 3 not registered. Did you mean "Q{http://www.w3.org/2005/xpath-functions/array}for-each-pair (array(*), array(*), function(*))", "Q{http://www.w3.org/2005/xpath-functions/array}for-each (array(*), function(*))", "Q{http://www.w3.org/2005/xpath-functions/map}for-each (map(*), item()*)" or "Q{http://www.w3.org/2005/xpath-functions}for-each (item()*, function(*))"?
 fo-test-fn-for-each-pair-002,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}for-each-pair with arity of 3 not registered. Did you mean "Q{http://www.w3.org/2005/xpath-functions/array}for-each-pair (array(*), array(*), function(*))", "Q{http://www.w3.org/2005/xpath-functions/array}for-each (array(*), function(*))", "Q{http://www.w3.org/2005/xpath-functions/map}for-each (map(*), item()*)" or "Q{http://www.w3.org/2005/xpath-functions}for-each (item()*, function(*))"?
 fo-test-fn-for-each-pair-003,Error: XPST0017: Function Q{http://www.w3.org/2005/xpath-functions}for-each-pair with arity of 3 not registered. Did you mean "Q{http://www.w3.org/2005/xpath-functions/array}for-each-pair (array(*), array(*), function(*))", "Q{http://www.w3.org/2005/xpath-functions/array}for-each (array(*), function(*))", "Q{http://www.w3.org/2005/xpath-functions/map}for-each (map(*), item()*)" or "Q{http://www.w3.org/2005/xpath-functions}for-each (item()*, function(*))"?
diff --git a/test/specs/parsing/functions/functions.node.tests.ts b/test/specs/parsing/functions/functions.node.tests.ts
index bdd9f877..520a8444 100644
--- a/test/specs/parsing/functions/functions.node.tests.ts
+++ b/test/specs/parsing/functions/functions.node.tests.ts
@@ -16,6 +16,113 @@ beforeEach(() => {
 });
 
 describe('functions over nodes', () => {
+	describe('generate-id()', () => {
+		it('returns the same value for the same node', () => {
+			jsonMlMapper.parse(['someElement'], documentNode);
+			chai.assert.isTrue(
+				evaluateXPathToBoolean('generate-id(/) = generate-id(/)', documentNode),
+			);
+		});
+
+		it('returns the empty string for the empty sequence', () => {
+			jsonMlMapper.parse(['someElement'], documentNode);
+			chai.assert.isTrue(evaluateXPathToBoolean('generate-id(()) = ""', documentNode));
+		});
+
+		it('throws the correct error when the context item is not a node', () => {
+			chai.assert.throws(
+				() => evaluateXPathToBoolean('"not a node" ! generate-id()'),
+				'XPTY0004',
+			);
+		});
+
+		it('returns the same value for subsequent calls', () => {
+			jsonMlMapper.parse(['someElement'], documentNode);
+			const id = evaluateXPathToString('generate-id(/)', documentNode);
+			chai.assert.equal(evaluateXPathToString('generate-id(/)', documentNode), id);
+		});
+	});
+
+	describe('lang()', () => {
+		it('returns true when the node has the right lang', () => {
+			jsonMlMapper.parse(['someElement', { 'xml:lang': 'en' }], documentNode);
+			chai.assert.equal(
+				evaluateXPathToBoolean('lang("en", .)', documentNode.firstChild),
+				true,
+			);
+		});
+
+		it('returns false when the node has the wrong lang', () => {
+			jsonMlMapper.parse(['someElement', { 'xml:lang': 'en' }], documentNode);
+			chai.assert.equal(
+				evaluateXPathToBoolean('lang("es", .)', documentNode.firstChild),
+				false,
+			);
+		});
+
+		it('returns true when the node has the right lang, but capitalized', () => {
+			jsonMlMapper.parse(['someElement', { 'xml:lang': 'EN' }], documentNode);
+			chai.assert.equal(
+				evaluateXPathToBoolean('lang("en", .)', documentNode.firstChild),
+				true,
+			);
+		});
+
+		it('returns true when the node has the right lang, but more specific', () => {
+			jsonMlMapper.parse(['someElement', { 'xml:lang': 'en-gb' }], documentNode);
+			chai.assert.equal(
+				evaluateXPathToBoolean('lang("en", .)', documentNode.firstChild),
+				true,
+			);
+		});
+
+		it('returns false when the node has the right lang, but not specific enough', () => {
+			jsonMlMapper.parse(['someElement', { 'xml:lang': 'en' }], documentNode);
+			chai.assert.equal(
+				evaluateXPathToBoolean('lang("en-gb", .)', documentNode.firstChild),
+				false,
+			);
+		});
+
+		it('returns true for implied context', () => {
+			jsonMlMapper.parse(['someElement', { 'xml:lang': 'en' }], documentNode);
+			chai.assert.equal(evaluateXPathToBoolean('lang("en")', documentNode.firstChild), true);
+		});
+
+		it('returns true when the parent is true', () => {
+			jsonMlMapper.parse(
+				['someElement', { 'xml:lang': 'en' }, ['child', 'Hello']],
+				documentNode,
+			);
+			chai.assert.equal(
+				evaluateXPathToBoolean('lang("en")', documentNode.firstChild.firstChild),
+				true,
+			);
+		});
+
+		it('returns false even if the parent is true', () => {
+			jsonMlMapper.parse(
+				['someElement', { 'xml:lang': 'en' }, ['child', { 'xml:lang': 'de' }, 'Hello']],
+				documentNode,
+			);
+			chai.assert.equal(
+				evaluateXPathToBoolean('lang("en")', documentNode.firstChild.firstChild),
+				false,
+			);
+		});
+
+		it('returns true even if the parent is false', () => {
+			jsonMlMapper.parse(
+				['someElement', { 'xml:lang': 'de' }, ['child', { 'xml:lang': 'en' }, 'Hello']],
+				documentNode,
+			);
+			chai.assert.equal(
+				evaluateXPathToBoolean('lang("en")', documentNode.firstChild.firstChild),
+				true,
+			);
+		});
+	});
+
 	describe('node-name()', () => {
 		it('returns an empty sequence if $arg is an empty sequence', () =>
 			chai.assert.isEmpty(evaluateXPathToStrings('node-name(())', documentNode)));
diff --git a/test/specs/parsing/functions/functions.string.tests.ts b/test/specs/parsing/functions/functions.string.tests.ts
index da3f5f9d..a3135c4a 100644
--- a/test/specs/parsing/functions/functions.string.tests.ts
+++ b/test/specs/parsing/functions/functions.string.tests.ts
@@ -95,6 +95,13 @@ describe('functions over strings', () => {
 			));
 	});
 
+	it('tokenize("abracadabra", "(ab)|(a)") returns ("","r","c","d","r","")', () => {
+		chai.assert.sameOrderedMembers(
+			evaluateXPathToStrings('fn:tokenize("abracadabra", "(ab)|(a)")'),
+			['', 'r', 'c', 'd', 'r', ''],
+		);
+	});
+
 	describe('normalize-space()', () => {
 		it('Returns the value of $arg with whitespace normalized by stripping leading and trailing whitespace and replacing sequences of one or more than one whitespace character with a single space, #x20.', () =>
 			chai.assert.equal(
@@ -223,6 +230,19 @@ describe('functions over strings', () => {
 			chai.assert.equal(evaluateXPathToString('string()', document), 'Some <CDATA>');
 		});
 
+		it('regards documentFragment nodes as normal parents', () => {
+			const document = new slimdom.Document();
+			const f = document.createDocumentFragment();
+			const foo = f.appendChild(document.createElement('foo'));
+			f.firstChild.appendChild(document.createTextNode('Test'));
+			f.appendChild(foo.cloneNode(true));
+			chai.assert.equal(
+				evaluateXPathToString('string($f)', undefined, undefined, { f }),
+				'TestTest',
+			);
+			chai.assert.equal(evaluateXPathToString('string(.)', f, undefined), 'TestTest');
+		});
+
 		it('If $arg is the empty sequence, the function returns the zero-length string.', () =>
 			chai.assert.equal(evaluateXPathToString('string(())', documentNode), ''));
 
diff --git a/test/specs/parsing/registerXQueryModule.tests.ts b/test/specs/parsing/registerXQueryModule.tests.ts
index be06d1c1..f4834560 100644
--- a/test/specs/parsing/registerXQueryModule.tests.ts
+++ b/test/specs/parsing/registerXQueryModule.tests.ts
@@ -345,4 +345,13 @@ declare function bar:baz() {
 			'XPST0017',
 		);
 	});
+
+	it('throws a proper error for parse errors', () => {
+		chai.expect(() => {
+			registerXQueryModule(
+				`declare function local:one() { 1 }(:missing semicolon:)
+				declare function local:two() { 2 };`,
+			);
+		}).to.throw('XPST0003: Failed to parse script. Expected ;');
+	});
 });
diff --git a/test/specs/parsing/xquery/SwitchExpression.tests.ts b/test/specs/parsing/xquery/SwitchExpression.tests.ts
new file mode 100644
index 00000000..dcc6ad0c
--- /dev/null
+++ b/test/specs/parsing/xquery/SwitchExpression.tests.ts
@@ -0,0 +1,102 @@
+import * as chai from 'chai';
+
+import { evaluateXPath, evaluateXPathToNumber } from 'fontoxpath';
+
+describe('Switch', () => {
+	it('works', () =>
+		chai.assert.equal(
+			evaluateXPathToNumber(
+				`
+switch (1)
+case 1 return 1
+default return 0`,
+
+				null,
+				null,
+				null,
+				{
+					debug: true,
+					language: evaluateXPath.XQUERY_3_1_LANGUAGE,
+				},
+			),
+			1,
+		));
+
+	it('works hitting the default case', () =>
+		chai.assert.equal(
+			evaluateXPathToNumber(
+				`
+switch (0)
+case 1 return 1
+default return 0`,
+
+				null,
+				null,
+				null,
+				{
+					debug: true,
+					language: evaluateXPath.XQUERY_3_1_LANGUAGE,
+				},
+			),
+			0,
+		));
+
+	it('works hitting the empty sequence case', () =>
+		chai.assert.equal(
+			evaluateXPathToNumber(
+				`
+switch (())
+case () return 1
+default return 0`,
+
+				null,
+				null,
+				null,
+				{
+					debug: true,
+					language: evaluateXPath.XQUERY_3_1_LANGUAGE,
+				},
+			),
+			1,
+		));
+
+	it('works hitting the empty sequence case as a default', () =>
+		chai.assert.equal(
+			evaluateXPathToNumber(
+				`
+switch (())
+case 1 return 1
+default return 0`,
+
+				null,
+				null,
+				null,
+				{
+					debug: true,
+					language: evaluateXPath.XQUERY_3_1_LANGUAGE,
+				},
+			),
+			0,
+		));
+
+	it('works hitting overload cases', () =>
+		chai.assert.equal(
+			evaluateXPathToNumber(
+				`
+switch (1)
+case ()
+case 1 return 1
+
+default return 0`,
+
+				null,
+				null,
+				null,
+				{
+					debug: true,
+					language: evaluateXPath.XQUERY_3_1_LANGUAGE,
+				},
+			),
+			1,
+		));
+});