#
tokens: 56926/50000 1/1644 files (page 172/179)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 172 of 179. Use http://codebase.md/xmlui-org/xmlui/tools/vscode/resources/xmlui-markup-syntax-highlighting.png?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .changeset
│   ├── cold-items-taste.md
│   ├── config.json
│   ├── empty-spiders-dress.md
│   ├── shy-windows-allow.md
│   ├── sour-coins-read.md
│   ├── tame-zebras-invite.md
│   ├── three-ideas-invent.md
│   ├── twenty-jeans-watch.md
│   ├── warm-spies-melt.md
│   └── whole-ways-cry.md
├── .eslintrc.cjs
├── .github
│   ├── build-checklist.png
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.md
│   │   └── feature_request.md
│   └── workflows
│       ├── deploy-docs-optimized.yml
│       ├── deploy-docs.yml
│       ├── prepare-versions.yml
│       ├── release-packages.yml
│       ├── run-all-tests.yml
│       └── run-smoke-tests.yml
├── .gitignore
├── .prettierrc.js
├── .vscode
│   ├── launch.json
│   └── settings.json
├── blog
│   ├── .gitignore
│   ├── .gitkeep
│   ├── CHANGELOG.md
│   ├── extensions.ts
│   ├── index.html
│   ├── index.ts
│   ├── package.json
│   ├── public
│   │   ├── blog
│   │   │   ├── images
│   │   │   │   ├── blog-page-component.png
│   │   │   │   ├── blog-scrabble.png
│   │   │   │   ├── integrated-blog-search.png
│   │   │   │   └── lorem-ipsum.png
│   │   │   ├── lorem-ipsum.md
│   │   │   ├── newest-post.md
│   │   │   ├── older-post.md
│   │   │   └── welcome-to-the-xmlui-blog.md
│   │   ├── mockServiceWorker.js
│   │   ├── resources
│   │   │   ├── favicon.ico
│   │   │   ├── files
│   │   │   │   └── for-download
│   │   │   │       └── xmlui
│   │   │   │           └── xmlui-standalone.umd.js
│   │   │   ├── github.svg
│   │   │   ├── llms.txt
│   │   │   ├── logo-dark.svg
│   │   │   ├── logo.svg
│   │   │   ├── pg-popout.svg
│   │   │   └── xmlui-logo.svg
│   │   ├── serve.json
│   │   └── web.config
│   ├── scripts
│   │   ├── download-latest-xmlui.js
│   │   ├── generate-rss.js
│   │   ├── get-releases.js
│   │   └── utils.js
│   ├── src
│   │   ├── components
│   │   │   ├── BlogOverview.xmlui
│   │   │   ├── BlogPage.xmlui
│   │   │   └── PageNotFound.xmlui
│   │   ├── config.ts
│   │   ├── Main.xmlui
│   │   └── themes
│   │       ├── docs-theme.ts
│   │       ├── earthtone.ts
│   │       ├── xmlui-gray-on-default.ts
│   │       ├── xmlui-green-on-default.ts
│   │       └── xmlui-orange-on-default.ts
│   └── tsconfig.json
├── CONTRIBUTING.md
├── docs
│   ├── .gitignore
│   ├── CHANGELOG.md
│   ├── ComponentRefLinks.txt
│   ├── content
│   │   ├── _meta.json
│   │   ├── components
│   │   │   ├── _meta.json
│   │   │   ├── _overview.md
│   │   │   ├── APICall.md
│   │   │   ├── App.md
│   │   │   ├── AppHeader.md
│   │   │   ├── AppState.md
│   │   │   ├── AutoComplete.md
│   │   │   ├── Avatar.md
│   │   │   ├── Backdrop.md
│   │   │   ├── Badge.md
│   │   │   ├── BarChart.md
│   │   │   ├── Bookmark.md
│   │   │   ├── Breakout.md
│   │   │   ├── Button.md
│   │   │   ├── Card.md
│   │   │   ├── Carousel.md
│   │   │   ├── ChangeListener.md
│   │   │   ├── Checkbox.md
│   │   │   ├── CHStack.md
│   │   │   ├── ColorPicker.md
│   │   │   ├── Column.md
│   │   │   ├── ContentSeparator.md
│   │   │   ├── CVStack.md
│   │   │   ├── DataSource.md
│   │   │   ├── DateInput.md
│   │   │   ├── DatePicker.md
│   │   │   ├── DonutChart.md
│   │   │   ├── DropdownMenu.md
│   │   │   ├── EmojiSelector.md
│   │   │   ├── ExpandableItem.md
│   │   │   ├── FileInput.md
│   │   │   ├── FileUploadDropZone.md
│   │   │   ├── FlowLayout.md
│   │   │   ├── Footer.md
│   │   │   ├── Form.md
│   │   │   ├── FormItem.md
│   │   │   ├── FormSection.md
│   │   │   ├── Fragment.md
│   │   │   ├── H1.md
│   │   │   ├── H2.md
│   │   │   ├── H3.md
│   │   │   ├── H4.md
│   │   │   ├── H5.md
│   │   │   ├── H6.md
│   │   │   ├── Heading.md
│   │   │   ├── HSplitter.md
│   │   │   ├── HStack.md
│   │   │   ├── Icon.md
│   │   │   ├── IFrame.md
│   │   │   ├── Image.md
│   │   │   ├── Items.md
│   │   │   ├── LabelList.md
│   │   │   ├── Legend.md
│   │   │   ├── LineChart.md
│   │   │   ├── Link.md
│   │   │   ├── List.md
│   │   │   ├── Logo.md
│   │   │   ├── Markdown.md
│   │   │   ├── MenuItem.md
│   │   │   ├── MenuSeparator.md
│   │   │   ├── ModalDialog.md
│   │   │   ├── NavGroup.md
│   │   │   ├── NavLink.md
│   │   │   ├── NavPanel.md
│   │   │   ├── NoResult.md
│   │   │   ├── NumberBox.md
│   │   │   ├── Option.md
│   │   │   ├── Page.md
│   │   │   ├── PageMetaTitle.md
│   │   │   ├── Pages.md
│   │   │   ├── Pagination.md
│   │   │   ├── PasswordInput.md
│   │   │   ├── PieChart.md
│   │   │   ├── ProgressBar.md
│   │   │   ├── Queue.md
│   │   │   ├── RadioGroup.md
│   │   │   ├── RealTimeAdapter.md
│   │   │   ├── Redirect.md
│   │   │   ├── Select.md
│   │   │   ├── Slider.md
│   │   │   ├── Slot.md
│   │   │   ├── SpaceFiller.md
│   │   │   ├── Spinner.md
│   │   │   ├── Splitter.md
│   │   │   ├── Stack.md
│   │   │   ├── StickyBox.md
│   │   │   ├── SubMenuItem.md
│   │   │   ├── Switch.md
│   │   │   ├── TabItem.md
│   │   │   ├── Table.md
│   │   │   ├── TableOfContents.md
│   │   │   ├── Tabs.md
│   │   │   ├── Text.md
│   │   │   ├── TextArea.md
│   │   │   ├── TextBox.md
│   │   │   ├── Theme.md
│   │   │   ├── TimeInput.md
│   │   │   ├── Timer.md
│   │   │   ├── ToneChangerButton.md
│   │   │   ├── ToneSwitch.md
│   │   │   ├── Tooltip.md
│   │   │   ├── Tree.md
│   │   │   ├── VSplitter.md
│   │   │   ├── VStack.md
│   │   │   ├── xmlui-animations
│   │   │   │   ├── _meta.json
│   │   │   │   ├── _overview.md
│   │   │   │   ├── Animation.md
│   │   │   │   ├── FadeAnimation.md
│   │   │   │   ├── FadeInAnimation.md
│   │   │   │   ├── FadeOutAnimation.md
│   │   │   │   ├── ScaleAnimation.md
│   │   │   │   └── SlideInAnimation.md
│   │   │   ├── xmlui-pdf
│   │   │   │   ├── _meta.json
│   │   │   │   ├── _overview.md
│   │   │   │   └── Pdf.md
│   │   │   ├── xmlui-spreadsheet
│   │   │   │   ├── _meta.json
│   │   │   │   ├── _overview.md
│   │   │   │   └── Spreadsheet.md
│   │   │   └── xmlui-website-blocks
│   │   │       ├── _meta.json
│   │   │       ├── _overview.md
│   │   │       ├── Carousel.md
│   │   │       ├── HelloMd.md
│   │   │       ├── HeroSection.md
│   │   │       └── ScrollToTop.md
│   │   └── extensions
│   │       ├── _meta.json
│   │       ├── xmlui-animations
│   │       │   ├── _meta.json
│   │       │   ├── _overview.md
│   │       │   ├── Animation.md
│   │       │   ├── FadeAnimation.md
│   │       │   ├── FadeInAnimation.md
│   │       │   ├── FadeOutAnimation.md
│   │       │   ├── ScaleAnimation.md
│   │       │   └── SlideInAnimation.md
│   │       └── xmlui-website-blocks
│   │           ├── _meta.json
│   │           ├── _overview.md
│   │           ├── Carousel.md
│   │           ├── HelloMd.md
│   │           ├── HeroSection.md
│   │           └── ScrollToTop.md
│   ├── extensions.ts
│   ├── index.html
│   ├── index.ts
│   ├── package.json
│   ├── public
│   │   ├── feed.rss
│   │   ├── mockServiceWorker.js
│   │   ├── pages
│   │   │   ├── _meta.json
│   │   │   ├── app-structure.md
│   │   │   ├── build-editor-component.md
│   │   │   ├── build-hello-world-component.md
│   │   │   ├── components-intro.md
│   │   │   ├── context-variables.md
│   │   │   ├── forms.md
│   │   │   ├── globals.md
│   │   │   ├── glossary.md
│   │   │   ├── helper-tags.md
│   │   │   ├── hosted-deployment.md
│   │   │   ├── howto
│   │   │   │   ├── assign-a-complex-json-literal-to-a-component-variable.md
│   │   │   │   ├── chain-a-refetch.md
│   │   │   │   ├── debug-a-component.md
│   │   │   │   ├── delay-a-datasource-until-another-datasource-is-ready.md
│   │   │   │   ├── delegate-a-method.md
│   │   │   │   ├── do-custom-form-validation.md
│   │   │   │   ├── expose-a-method-from-a-component.md
│   │   │   │   ├── filter-and-transform-data-from-an-api.md
│   │   │   │   ├── group-items-in-list-by-a-property.md
│   │   │   │   ├── handle-background-operations.md
│   │   │   │   ├── hide-an-element-until-its-datasource-is-ready.md
│   │   │   │   ├── make-a-set-of-equal-width-cards.md
│   │   │   │   ├── make-a-table-responsive.md
│   │   │   │   ├── modify-a-value-reported-in-a-column.md
│   │   │   │   ├── paginate-a-list.md
│   │   │   │   ├── pass-data-to-a-modal-dialog.md
│   │   │   │   ├── react-to-button-click-not-keystrokes.md
│   │   │   │   ├── set-the-initial-value-of-a-select-from-fetched-data.md
│   │   │   │   ├── share-a-modaldialog-across-components.md
│   │   │   │   ├── sync-selections-between-table-and-list-views.md
│   │   │   │   ├── update-ui-optimistically.md
│   │   │   │   ├── use-built-in-form-validation.md
│   │   │   │   └── use-the-same-modaldialog-to-add-or-edit.md
│   │   │   ├── howto.md
│   │   │   ├── intro.md
│   │   │   ├── layout.md
│   │   │   ├── markup.md
│   │   │   ├── mcp.md
│   │   │   ├── modal-dialogs.md
│   │   │   ├── news-and-reviews.md
│   │   │   ├── reactive-intro.md
│   │   │   ├── refactoring.md
│   │   │   ├── routing-and-links.md
│   │   │   ├── samples
│   │   │   │   ├── color-palette.xmlui
│   │   │   │   ├── color-values.xmlui
│   │   │   │   ├── shadow-sizes.xmlui
│   │   │   │   ├── spacing-sizes.xmlui
│   │   │   │   ├── swatch.xmlui
│   │   │   │   ├── theme-gallery-brief.xmlui
│   │   │   │   └── theme-gallery.xmlui
│   │   │   ├── scoping.md
│   │   │   ├── scripting.md
│   │   │   ├── styles-and-themes
│   │   │   │   ├── common-units.md
│   │   │   │   ├── layout-props.md
│   │   │   │   ├── theme-variable-defaults.md
│   │   │   │   ├── theme-variables.md
│   │   │   │   └── themes.md
│   │   │   ├── template-properties.md
│   │   │   ├── test.md
│   │   │   ├── tutorial-01.md
│   │   │   ├── tutorial-02.md
│   │   │   ├── tutorial-03.md
│   │   │   ├── tutorial-04.md
│   │   │   ├── tutorial-05.md
│   │   │   ├── tutorial-06.md
│   │   │   ├── tutorial-07.md
│   │   │   ├── tutorial-08.md
│   │   │   ├── tutorial-09.md
│   │   │   ├── tutorial-10.md
│   │   │   ├── tutorial-11.md
│   │   │   ├── tutorial-12.md
│   │   │   ├── universal-properties.md
│   │   │   ├── user-defined-components.md
│   │   │   ├── vscode.md
│   │   │   ├── working-with-markdown.md
│   │   │   ├── working-with-text.md
│   │   │   ├── xmlui-animations
│   │   │   │   ├── _meta.json
│   │   │   │   ├── _overview.md
│   │   │   │   ├── Animation.md
│   │   │   │   ├── FadeAnimation.md
│   │   │   │   ├── FadeInAnimation.md
│   │   │   │   ├── FadeOutAnimation.md
│   │   │   │   ├── ScaleAnimation.md
│   │   │   │   └── SlideInAnimation.md
│   │   │   ├── xmlui-charts
│   │   │   │   ├── _meta.json
│   │   │   │   ├── _overview.md
│   │   │   │   ├── BarChart.md
│   │   │   │   ├── DonutChart.md
│   │   │   │   ├── LabelList.md
│   │   │   │   ├── Legend.md
│   │   │   │   ├── LineChart.md
│   │   │   │   └── PieChart.md
│   │   │   ├── xmlui-pdf
│   │   │   │   ├── _meta.json
│   │   │   │   ├── _overview.md
│   │   │   │   └── Pdf.md
│   │   │   └── xmlui-spreadsheet
│   │   │       ├── _meta.json
│   │   │       ├── _overview.md
│   │   │       └── Spreadsheet.md
│   │   ├── resources
│   │   │   ├── devdocs
│   │   │   │   ├── debug-proxy-object-2.png
│   │   │   │   ├── debug-proxy-object.png
│   │   │   │   ├── table_editor_01.png
│   │   │   │   ├── table_editor_02.png
│   │   │   │   ├── table_editor_03.png
│   │   │   │   ├── table_editor_04.png
│   │   │   │   ├── table_editor_05.png
│   │   │   │   ├── table_editor_06.png
│   │   │   │   ├── table_editor_07.png
│   │   │   │   ├── table_editor_08.png
│   │   │   │   ├── table_editor_09.png
│   │   │   │   ├── table_editor_10.png
│   │   │   │   ├── table_editor_11.png
│   │   │   │   ├── table-editor-01.png
│   │   │   │   ├── table-editor-02.png
│   │   │   │   ├── table-editor-03.png
│   │   │   │   ├── table-editor-04.png
│   │   │   │   ├── table-editor-06.png
│   │   │   │   ├── table-editor-07.png
│   │   │   │   ├── table-editor-08.png
│   │   │   │   ├── table-editor-09.png
│   │   │   │   └── xmlui-rendering-of-tiptap-markdown.png
│   │   │   ├── favicon.ico
│   │   │   ├── files
│   │   │   │   ├── clients.json
│   │   │   │   ├── daily-revenue.json
│   │   │   │   ├── dashboard-stats.json
│   │   │   │   ├── demo.xmlui
│   │   │   │   ├── demo.xmlui.xs
│   │   │   │   ├── downloads
│   │   │   │   │   └── downloads.json
│   │   │   │   ├── for-download
│   │   │   │   │   ├── index-with-api.html
│   │   │   │   │   ├── index.html
│   │   │   │   │   ├── mockApi.js
│   │   │   │   │   ├── start-darwin.sh
│   │   │   │   │   ├── start-linux.sh
│   │   │   │   │   ├── start.bat
│   │   │   │   │   └── xmlui
│   │   │   │   │       └── xmlui-standalone.umd.js
│   │   │   │   ├── getting-started
│   │   │   │   │   ├── cl-tutorial-final.zip
│   │   │   │   │   ├── cl-tutorial.zip
│   │   │   │   │   ├── cl-tutorial2.zip
│   │   │   │   │   ├── cl-tutorial3.zip
│   │   │   │   │   ├── cl-tutorial4.zip
│   │   │   │   │   ├── cl-tutorial5.zip
│   │   │   │   │   ├── cl-tutorial6.zip
│   │   │   │   │   ├── getting-started.zip
│   │   │   │   │   ├── hello-xmlui.zip
│   │   │   │   │   ├── xmlui-empty.zip
│   │   │   │   │   └── xmlui-starter.zip
│   │   │   │   ├── howto
│   │   │   │   │   └── component-icons
│   │   │   │   │       └── up-arrow.svg
│   │   │   │   ├── invoices.json
│   │   │   │   ├── monthly-status.json
│   │   │   │   ├── news-and-reviews.json
│   │   │   │   ├── products.json
│   │   │   │   ├── releases.json
│   │   │   │   ├── tutorials
│   │   │   │   │   ├── datasource
│   │   │   │   │   │   └── api.ts
│   │   │   │   │   └── p2do
│   │   │   │   │       ├── api.ts
│   │   │   │   │       └── todo-logo.svg
│   │   │   │   └── xmlui.json
│   │   │   ├── github.svg
│   │   │   ├── images
│   │   │   │   ├── apiaction-tutorial
│   │   │   │   │   ├── add-success.png
│   │   │   │   │   ├── apiaction-param.png
│   │   │   │   │   ├── change-completed.png
│   │   │   │   │   ├── change-in-progress.png
│   │   │   │   │   ├── confirm-delete.png
│   │   │   │   │   ├── data-error.png
│   │   │   │   │   ├── data-progress.png
│   │   │   │   │   ├── data-success.png
│   │   │   │   │   ├── display-1.png
│   │   │   │   │   ├── item-deleted.png
│   │   │   │   │   ├── item-updated.png
│   │   │   │   │   ├── missing-api-key.png
│   │   │   │   │   ├── new-item-added.png
│   │   │   │   │   └── test-message.png
│   │   │   │   ├── chat-api
│   │   │   │   │   └── domain-model.svg
│   │   │   │   ├── components
│   │   │   │   │   ├── image
│   │   │   │   │   │   └── breakfast.jpg
│   │   │   │   │   ├── markdown
│   │   │   │   │   │   └── colors.png
│   │   │   │   │   └── modal
│   │   │   │   │       ├── deep_link_dialog_1.jpg
│   │   │   │   │       └── deep_link_dialog_2.jpg
│   │   │   │   ├── create-apps
│   │   │   │   │   ├── collapsed-vertical.png
│   │   │   │   │   ├── using-forms-warning-dialog.png
│   │   │   │   │   └── using-forms.png
│   │   │   │   ├── datasource-tutorial
│   │   │   │   │   ├── data-with-header.png
│   │   │   │   │   ├── filtered-data.png
│   │   │   │   │   ├── filtered-items.png
│   │   │   │   │   ├── initial-page-items.png
│   │   │   │   │   ├── list-items.png
│   │   │   │   │   ├── next-page-items.png
│   │   │   │   │   ├── no-data.png
│   │   │   │   │   ├── pagination-1.jpg
│   │   │   │   │   ├── pagination-1.png
│   │   │   │   │   ├── polling-1.png
│   │   │   │   │   ├── refetch-data.png
│   │   │   │   │   ├── slow-loading.png
│   │   │   │   │   ├── test-message.png
│   │   │   │   │   ├── Thumbs.db
│   │   │   │   │   ├── unconventional-data.png
│   │   │   │   │   └── unfiltered-items.png
│   │   │   │   ├── flower.jpg
│   │   │   │   ├── get-started
│   │   │   │   │   ├── add-new-contact.png
│   │   │   │   │   ├── app-modified.png
│   │   │   │   │   ├── app-start.png
│   │   │   │   │   ├── app-with-boxes.png
│   │   │   │   │   ├── app-with-toast.png
│   │   │   │   │   ├── boilerplate-structure.png
│   │   │   │   │   ├── cl-initial.png
│   │   │   │   │   ├── cl-start.png
│   │   │   │   │   ├── contact-counts.png
│   │   │   │   │   ├── contact-dialog-title.png
│   │   │   │   │   ├── contact-dialog.png
│   │   │   │   │   ├── contact-menus.png
│   │   │   │   │   ├── contact-predicates.png
│   │   │   │   │   ├── context-menu.png
│   │   │   │   │   ├── dashboard-numbers.png
│   │   │   │   │   ├── default-contact-list.png
│   │   │   │   │   ├── delete-contact.png
│   │   │   │   │   ├── delete-task.png
│   │   │   │   │   ├── detailed-template.png
│   │   │   │   │   ├── edit-contact-details.png
│   │   │   │   │   ├── edited-contact-saved.png
│   │   │   │   │   ├── empty-sections.png
│   │   │   │   │   ├── filter-completed.png
│   │   │   │   │   ├── fullwidth-desktop.png
│   │   │   │   │   ├── fullwidth-mobile.png
│   │   │   │   │   ├── initial-table.png
│   │   │   │   │   ├── items-and-badges.png
│   │   │   │   │   ├── loading-message.png
│   │   │   │   │   ├── new-contact-button.png
│   │   │   │   │   ├── new-contact-saved.png
│   │   │   │   │   ├── no-empty-sections.png
│   │   │   │   │   ├── personal-todo-initial.png
│   │   │   │   │   ├── piechart.png
│   │   │   │   │   ├── review-today.png
│   │   │   │   │   ├── rudimentary-dashboard.png
│   │   │   │   │   ├── section-collapsed.png
│   │   │   │   │   ├── sectioned-items.png
│   │   │   │   │   ├── sections-ordered.png
│   │   │   │   │   ├── spacex-list-with-links.png
│   │   │   │   │   ├── spacex-list.png
│   │   │   │   │   ├── start-personal-todo-1.png
│   │   │   │   │   ├── submit-new-contact.png
│   │   │   │   │   ├── submit-new-task.png
│   │   │   │   │   ├── syntax-highlighting.png
│   │   │   │   │   ├── table-with-badge.png
│   │   │   │   │   ├── template-with-card.png
│   │   │   │   │   ├── test-emulated-api.png
│   │   │   │   │   ├── Thumbs.db
│   │   │   │   │   ├── todo-logo.png
│   │   │   │   │   └── xmlui-tools.png
│   │   │   │   ├── HelloApp.png
│   │   │   │   ├── HelloApp2.png
│   │   │   │   ├── logos
│   │   │   │   │   ├── xmlui1.svg
│   │   │   │   │   ├── xmlui2.svg
│   │   │   │   │   ├── xmlui3.svg
│   │   │   │   │   ├── xmlui4.svg
│   │   │   │   │   ├── xmlui5.svg
│   │   │   │   │   ├── xmlui6.svg
│   │   │   │   │   └── xmlui7.svg
│   │   │   │   ├── pdf
│   │   │   │   │   └── dummy-pdf.jpg
│   │   │   │   ├── rendering-engine
│   │   │   │   │   ├── AppEngine-flow.svg
│   │   │   │   │   ├── Component.svg
│   │   │   │   │   ├── CompoundComponent.svg
│   │   │   │   │   ├── RootComponent.svg
│   │   │   │   │   └── tree-with-containers.svg
│   │   │   │   ├── reviewers-guide
│   │   │   │   │   ├── AppEngine-flow.svg
│   │   │   │   │   └── incbutton-in-action.png
│   │   │   │   ├── tools
│   │   │   │   │   └── boilerplate-structure.png
│   │   │   │   ├── try.svg
│   │   │   │   ├── tutorial
│   │   │   │   │   ├── app-chat-history.png
│   │   │   │   │   ├── app-content-placeholder.png
│   │   │   │   │   ├── app-header-and-content.png
│   │   │   │   │   ├── app-links-channel-selected.png
│   │   │   │   │   ├── app-links-click.png
│   │   │   │   │   ├── app-navigation.png
│   │   │   │   │   ├── finished-ex01.png
│   │   │   │   │   ├── finished-ex02.png
│   │   │   │   │   ├── hello.png
│   │   │   │   │   ├── splash-screen-advanced.png
│   │   │   │   │   ├── splash-screen-after-click.png
│   │   │   │   │   ├── splash-screen-centered.png
│   │   │   │   │   ├── splash-screen-events.png
│   │   │   │   │   ├── splash-screen-expression.png
│   │   │   │   │   ├── splash-screen-reuse-after.png
│   │   │   │   │   ├── splash-screen-reuse-before.png
│   │   │   │   │   └── splash-screen.png
│   │   │   │   └── tutorial-01.png
│   │   │   ├── llms.txt
│   │   │   ├── logo-dark.svg
│   │   │   ├── logo.svg
│   │   │   ├── pg-popout.svg
│   │   │   └── xmlui-logo.svg
│   │   ├── serve.json
│   │   └── web.config
│   ├── scripts
│   │   ├── download-latest-xmlui.js
│   │   ├── generate-rss.js
│   │   ├── get-releases.js
│   │   └── utils.js
│   ├── src
│   │   ├── components
│   │   │   ├── BlogOverview.xmlui
│   │   │   ├── BlogPage.xmlui
│   │   │   ├── Boxes.xmlui
│   │   │   ├── Breadcrumb.xmlui
│   │   │   ├── ChangeLog.xmlui
│   │   │   ├── ColorPalette.xmlui
│   │   │   ├── DocumentLinks.xmlui
│   │   │   ├── DocumentPage.xmlui
│   │   │   ├── DocumentPageNoTOC.xmlui
│   │   │   ├── Icons.xmlui
│   │   │   ├── IncButton.xmlui
│   │   │   ├── IncButton2.xmlui
│   │   │   ├── NameValue.xmlui
│   │   │   ├── PageNotFound.xmlui
│   │   │   ├── PaletteItem.xmlui
│   │   │   ├── Palettes.xmlui
│   │   │   ├── SectionHeader.xmlui
│   │   │   ├── TBD.xmlui
│   │   │   ├── Test.xmlui
│   │   │   ├── ThemesIntro.xmlui
│   │   │   ├── ThousandThemes.xmlui
│   │   │   ├── TubeStops.xmlui
│   │   │   ├── TubeStops.xmlui.xs
│   │   │   └── TwoColumnCode.xmlui
│   │   ├── config.ts
│   │   ├── Main.xmlui
│   │   └── themes
│   │       ├── docs-theme.ts
│   │       ├── earthtone.ts
│   │       ├── xmlui-gray-on-default.ts
│   │       ├── xmlui-green-on-default.ts
│   │       └── xmlui-orange-on-default.ts
│   └── tsconfig.json
├── LICENSE
├── package-lock.json
├── package.json
├── packages
│   ├── xmlui-animations
│   │   ├── .gitignore
│   │   ├── CHANGELOG.md
│   │   ├── demo
│   │   │   └── Main.xmlui
│   │   ├── index.html
│   │   ├── index.ts
│   │   ├── meta
│   │   │   └── componentsMetadata.ts
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── Animation.tsx
│   │   │   ├── AnimationNative.tsx
│   │   │   ├── FadeAnimation.tsx
│   │   │   ├── FadeInAnimation.tsx
│   │   │   ├── FadeOutAnimation.tsx
│   │   │   ├── index.tsx
│   │   │   ├── ScaleAnimation.tsx
│   │   │   └── SlideInAnimation.tsx
│   │   └── tsconfig.json
│   ├── xmlui-devtools
│   │   ├── .gitignore
│   │   ├── CHANGELOG.md
│   │   ├── demo
│   │   │   └── Main.xmlui
│   │   ├── index.html
│   │   ├── index.ts
│   │   ├── meta
│   │   │   └── componentsMetadata.ts
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── devtools
│   │   │   │   ├── DevTools.tsx
│   │   │   │   ├── DevToolsNative.module.scss
│   │   │   │   ├── DevToolsNative.tsx
│   │   │   │   ├── ModalDialog.module.scss
│   │   │   │   ├── ModalDialog.tsx
│   │   │   │   ├── ModalVisibilityContext.tsx
│   │   │   │   ├── Tooltip.module.scss
│   │   │   │   ├── Tooltip.tsx
│   │   │   │   └── utils.ts
│   │   │   ├── editor
│   │   │   │   └── Editor.tsx
│   │   │   └── index.tsx
│   │   ├── tsconfig.json
│   │   └── vite.config-overrides.ts
│   ├── xmlui-hello-world
│   │   ├── .gitignore
│   │   ├── index.ts
│   │   ├── meta
│   │   │   └── componentsMetadata.ts
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── HelloWorld.module.scss
│   │   │   ├── HelloWorld.tsx
│   │   │   ├── HelloWorldNative.tsx
│   │   │   └── index.tsx
│   │   └── tsconfig.json
│   ├── xmlui-os-frames
│   │   ├── .gitignore
│   │   ├── demo
│   │   │   └── Main.xmlui
│   │   ├── index.html
│   │   ├── index.ts
│   │   ├── meta
│   │   │   └── componentsMetadata.ts
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── index.tsx
│   │   │   ├── IPhoneFrame.module.scss
│   │   │   ├── IPhoneFrame.tsx
│   │   │   ├── MacOSAppFrame.module.scss
│   │   │   ├── MacOSAppFrame.tsx
│   │   │   ├── WindowsAppFrame.module.scss
│   │   │   └── WindowsAppFrame.tsx
│   │   └── tsconfig.json
│   ├── xmlui-pdf
│   │   ├── .gitignore
│   │   ├── CHANGELOG.md
│   │   ├── demo
│   │   │   ├── components
│   │   │   │   └── Pdf.xmlui
│   │   │   └── Main.xmlui
│   │   ├── index.html
│   │   ├── index.ts
│   │   ├── meta
│   │   │   └── componentsMetadata.ts
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── index.tsx
│   │   │   ├── LazyPdfNative.tsx
│   │   │   ├── Pdf.module.scss
│   │   │   └── Pdf.tsx
│   │   └── tsconfig.json
│   ├── xmlui-playground
│   │   ├── .gitignore
│   │   ├── CHANGELOG.md
│   │   ├── demo
│   │   │   └── Main.xmlui
│   │   ├── index.html
│   │   ├── index.ts
│   │   ├── meta
│   │   │   └── componentsMetadata.ts
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── hooks
│   │   │   │   ├── usePlayground.ts
│   │   │   │   └── useToast.ts
│   │   │   ├── index.tsx
│   │   │   ├── playground
│   │   │   │   ├── Box.module.scss
│   │   │   │   ├── Box.tsx
│   │   │   │   ├── CodeSelector.tsx
│   │   │   │   ├── ConfirmationDialog.module.scss
│   │   │   │   ├── ConfirmationDialog.tsx
│   │   │   │   ├── Editor.tsx
│   │   │   │   ├── Header.module.scss
│   │   │   │   ├── Header.tsx
│   │   │   │   ├── Playground.tsx
│   │   │   │   ├── PlaygroundContent.module.scss
│   │   │   │   ├── PlaygroundContent.tsx
│   │   │   │   ├── PlaygroundNative.module.scss
│   │   │   │   ├── PlaygroundNative.tsx
│   │   │   │   ├── Preview.module.scss
│   │   │   │   ├── Preview.tsx
│   │   │   │   ├── Select.module.scss
│   │   │   │   ├── StandalonePlayground.tsx
│   │   │   │   ├── StandalonePlaygroundNative.module.scss
│   │   │   │   ├── StandalonePlaygroundNative.tsx
│   │   │   │   ├── ThemeSwitcher.module.scss
│   │   │   │   ├── ThemeSwitcher.tsx
│   │   │   │   ├── ToneSwitcher.tsx
│   │   │   │   ├── Tooltip.module.scss
│   │   │   │   ├── Tooltip.tsx
│   │   │   │   └── utils.ts
│   │   │   ├── providers
│   │   │   │   ├── Toast.module.scss
│   │   │   │   └── ToastProvider.tsx
│   │   │   ├── state
│   │   │   │   └── store.ts
│   │   │   ├── themes
│   │   │   │   └── theme.ts
│   │   │   └── utils
│   │   │       └── helpers.ts
│   │   └── tsconfig.json
│   ├── xmlui-search
│   │   ├── .gitignore
│   │   ├── CHANGELOG.md
│   │   ├── demo
│   │   │   └── Main.xmlui
│   │   ├── index.html
│   │   ├── index.ts
│   │   ├── meta
│   │   │   └── componentsMetadata.ts
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── index.tsx
│   │   │   ├── Search.module.scss
│   │   │   └── Search.tsx
│   │   └── tsconfig.json
│   ├── xmlui-spreadsheet
│   │   ├── .gitignore
│   │   ├── demo
│   │   │   └── Main.xmlui
│   │   ├── index.html
│   │   ├── index.ts
│   │   ├── meta
│   │   │   └── componentsMetadata.ts
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── index.tsx
│   │   │   ├── Spreadsheet.tsx
│   │   │   └── SpreadsheetNative.tsx
│   │   └── tsconfig.json
│   └── xmlui-website-blocks
│       ├── .gitignore
│       ├── CHANGELOG.md
│       ├── demo
│       │   ├── components
│       │   │   ├── HeroBackgroundBreakoutPage.xmlui
│       │   │   ├── HeroBackgroundsPage.xmlui
│       │   │   ├── HeroContentsPage.xmlui
│       │   │   ├── HeroTextAlignPage.xmlui
│       │   │   ├── HeroTextPage.xmlui
│       │   │   └── HeroTonesPage.xmlui
│       │   ├── Main.xmlui
│       │   └── themes
│       │       └── default.ts
│       ├── index.html
│       ├── index.ts
│       ├── meta
│       │   └── componentsMetadata.ts
│       ├── package.json
│       ├── public
│       │   └── resources
│       │       ├── building.jpg
│       │       └── xmlui-logo.svg
│       ├── src
│       │   ├── Carousel
│       │   │   ├── Carousel.module.scss
│       │   │   ├── Carousel.tsx
│       │   │   ├── CarouselContext.tsx
│       │   │   └── CarouselNative.tsx
│       │   ├── FancyButton
│       │   │   ├── FancyButton.module.scss
│       │   │   ├── FancyButton.tsx
│       │   │   └── FancyButton.xmlui
│       │   ├── Hello
│       │   │   ├── Hello.tsx
│       │   │   ├── Hello.xmlui
│       │   │   └── Hello.xmlui.xs
│       │   ├── HeroSection
│       │   │   ├── HeroSection.module.scss
│       │   │   ├── HeroSection.tsx
│       │   │   └── HeroSectionNative.tsx
│       │   ├── index.tsx
│       │   ├── ScrollToTop
│       │   │   ├── ScrollToTop.module.scss
│       │   │   ├── ScrollToTop.tsx
│       │   │   └── ScrollToTopNative.tsx
│       │   └── vite-env.d.ts
│       └── tsconfig.json
├── README.md
├── tools
│   ├── codefence
│   │   └── xmlui-code-fence-docs.md
│   ├── create-app
│   │   ├── .gitignore
│   │   ├── CHANGELOG.md
│   │   ├── create-app.ts
│   │   ├── helpers
│   │   │   ├── copy.ts
│   │   │   ├── get-pkg-manager.ts
│   │   │   ├── git.ts
│   │   │   ├── install.ts
│   │   │   ├── is-folder-empty.ts
│   │   │   ├── is-writeable.ts
│   │   │   ├── make-dir.ts
│   │   │   └── validate-pkg.ts
│   │   ├── index.ts
│   │   ├── package.json
│   │   ├── templates
│   │   │   ├── default
│   │   │   │   └── ts
│   │   │   │       ├── gitignore
│   │   │   │       ├── index.html
│   │   │   │       ├── index.ts
│   │   │   │       ├── public
│   │   │   │       │   ├── mockServiceWorker.js
│   │   │   │       │   ├── resources
│   │   │   │       │   │   ├── favicon.ico
│   │   │   │       │   │   └── xmlui-logo.svg
│   │   │   │       │   └── serve.json
│   │   │   │       └── src
│   │   │   │           ├── components
│   │   │   │           │   ├── ApiAware.xmlui
│   │   │   │           │   ├── Home.xmlui
│   │   │   │           │   ├── IncButton.xmlui
│   │   │   │           │   └── PagePanel.xmlui
│   │   │   │           ├── config.ts
│   │   │   │           └── Main.xmlui
│   │   │   ├── index.ts
│   │   │   └── types.ts
│   │   └── tsconfig.json
│   ├── create-xmlui-hello-world
│   │   ├── index.js
│   │   └── package.json
│   └── vscode
│       ├── .gitignore
│       ├── .vscode
│       │   ├── launch.json
│       │   └── tasks.json
│       ├── .vscodeignore
│       ├── build.sh
│       ├── CHANGELOG.md
│       ├── esbuild.js
│       ├── eslint.config.mjs
│       ├── formatter-docs.md
│       ├── generate-test-sample.sh
│       ├── LICENSE.md
│       ├── package-lock.json
│       ├── package.json
│       ├── README.md
│       ├── resources
│       │   ├── xmlui-logo.png
│       │   └── xmlui-markup-syntax-highlighting.png
│       ├── src
│       │   ├── extension.ts
│       │   └── server.ts
│       ├── syntaxes
│       │   └── xmlui.tmLanguage.json
│       ├── test-samples
│       │   └── sample.xmlui
│       ├── tsconfig.json
│       └── tsconfig.tsbuildinfo
├── turbo.json
└── xmlui
    ├── .gitignore
    ├── bin
    │   ├── bootstrap.js
    │   ├── build-lib.ts
    │   ├── build.ts
    │   ├── index.ts
    │   ├── preview.ts
    │   ├── start.ts
    │   ├── vite-xmlui-plugin.ts
    │   └── viteConfig.ts
    ├── CHANGELOG.md
    ├── conventions
    │   ├── component-qa-checklist.md
    │   ├── copilot-conventions.md
    │   ├── create-xmlui-components.md
    │   ├── mermaid.md
    │   ├── testing-conventions.md
    │   └── xmlui-in-a-nutshell.md
    ├── dev-docs
    │   ├── accessibility.md
    │   ├── actions.md
    │   ├── AppRoot.md
    │   ├── component-apis.md
    │   ├── component-rendering.md
    │   ├── component-review-checklist.md
    │   ├── containers.md
    │   ├── data-sources.md
    │   ├── e2e-summary.md
    │   ├── expression-evaluation.md
    │   ├── glossary.md
    │   ├── helper-components.md
    │   ├── index.md
    │   ├── loaders.md
    │   ├── next
    │   │   ├── component-dev-guide.md
    │   │   ├── configuration-management-enhancement-summary.md
    │   │   ├── documentation-scripts-refactoring-complete-summary.md
    │   │   ├── documentation-scripts-refactoring-plan.md
    │   │   ├── duplicate-pattern-extraction-summary.md
    │   │   ├── error-handling-standardization-summary.md
    │   │   ├── generating-component-reference.md
    │   │   ├── index.md
    │   │   ├── logging-consistency-implementation-summary.md
    │   │   ├── project-build.md
    │   │   ├── project-structure.md
    │   │   ├── theme-context.md
    │   │   ├── tiptap-design-considerations.md
    │   │   ├── working-with-code.md
    │   │   ├── xmlui-runtime-architecture
    │   │   └── xmlui-wcag-accessibility-report.md
    │   ├── react-fundamentals.md
    │   ├── release-method.md
    │   ├── rendering-fundamentals.md
    │   ├── reusable-components.md
    │   ├── standalone-apps.md
    │   ├── state-management.md
    │   └── xmlui-extensibility.xlsx
    ├── package.json
    ├── playwright.config.ts
    ├── scripts
    │   ├── coverage-only.js
    │   ├── e2e-test-summary.js
    │   ├── generate-docs
    │   │   ├── build-downloads-map.mjs
    │   │   ├── build-pages-map.mjs
    │   │   ├── components-config.json
    │   │   ├── configuration-management.mjs
    │   │   ├── constants.mjs
    │   │   ├── create-theme-files.mjs
    │   │   ├── DocsGenerator.mjs
    │   │   ├── error-handling.mjs
    │   │   ├── extensions-config.json
    │   │   ├── folders.mjs
    │   │   ├── generate-summary-files.mjs
    │   │   ├── get-docs.mjs
    │   │   ├── input-handler.mjs
    │   │   ├── logger.mjs
    │   │   ├── logging-standards.mjs
    │   │   ├── MetadataProcessor.mjs
    │   │   ├── pattern-utilities.mjs
    │   │   └── utils.mjs
    │   ├── get-langserver-metadata.mjs
    │   ├── inline-links.mjs
    │   └── README-e2e-summary.md
    ├── src
    │   ├── abstractions
    │   │   ├── _conventions.md
    │   │   ├── ActionDefs.ts
    │   │   ├── AppContextDefs.ts
    │   │   ├── ComponentDefs.ts
    │   │   ├── ContainerDefs.ts
    │   │   ├── ExtensionDefs.ts
    │   │   ├── FunctionDefs.ts
    │   │   ├── RendererDefs.ts
    │   │   ├── scripting
    │   │   │   ├── BlockScope.ts
    │   │   │   ├── Compilation.ts
    │   │   │   ├── LogicalThread.ts
    │   │   │   ├── LoopScope.ts
    │   │   │   ├── modules.ts
    │   │   │   ├── ScriptParserError.ts
    │   │   │   ├── Token.ts
    │   │   │   ├── TryScope.ts
    │   │   │   └── TryScopeExp.ts
    │   │   └── ThemingDefs.ts
    │   ├── components
    │   │   ├── _conventions.md
    │   │   ├── abstractions.ts
    │   │   ├── Accordion
    │   │   │   ├── Accordion.md
    │   │   │   ├── Accordion.module.scss
    │   │   │   ├── Accordion.spec.ts
    │   │   │   ├── Accordion.tsx
    │   │   │   ├── AccordionContext.tsx
    │   │   │   ├── AccordionItem.tsx
    │   │   │   ├── AccordionItemNative.tsx
    │   │   │   └── AccordionNative.tsx
    │   │   ├── Animation
    │   │   │   └── AnimationNative.tsx
    │   │   ├── APICall
    │   │   │   ├── APICall.md
    │   │   │   ├── APICall.spec.ts
    │   │   │   ├── APICall.tsx
    │   │   │   └── APICallNative.tsx
    │   │   ├── App
    │   │   │   ├── App.md
    │   │   │   ├── App.module.scss
    │   │   │   ├── App.spec.ts
    │   │   │   ├── App.tsx
    │   │   │   ├── AppLayoutContext.ts
    │   │   │   ├── AppNative.tsx
    │   │   │   ├── AppStateContext.ts
    │   │   │   ├── doc-resources
    │   │   │   │   ├── condensed-sticky.xmlui
    │   │   │   │   ├── condensed.xmlui
    │   │   │   │   ├── horizontal-sticky.xmlui
    │   │   │   │   ├── horizontal.xmlui
    │   │   │   │   ├── vertical-full-header.xmlui
    │   │   │   │   ├── vertical-sticky.xmlui
    │   │   │   │   └── vertical.xmlui
    │   │   │   ├── IndexerContext.ts
    │   │   │   ├── LinkInfoContext.ts
    │   │   │   ├── SearchContext.tsx
    │   │   │   ├── Sheet.module.scss
    │   │   │   └── Sheet.tsx
    │   │   ├── AppHeader
    │   │   │   ├── AppHeader.md
    │   │   │   ├── AppHeader.module.scss
    │   │   │   ├── AppHeader.spec.ts
    │   │   │   ├── AppHeader.tsx
    │   │   │   └── AppHeaderNative.tsx
    │   │   ├── AppState
    │   │   │   ├── AppState.md
    │   │   │   ├── AppState.spec.ts
    │   │   │   ├── AppState.tsx
    │   │   │   └── AppStateNative.tsx
    │   │   ├── AutoComplete
    │   │   │   ├── AutoComplete.md
    │   │   │   ├── AutoComplete.module.scss
    │   │   │   ├── AutoComplete.spec.ts
    │   │   │   ├── AutoComplete.tsx
    │   │   │   ├── AutoCompleteContext.tsx
    │   │   │   └── AutoCompleteNative.tsx
    │   │   ├── Avatar
    │   │   │   ├── Avatar.md
    │   │   │   ├── Avatar.module.scss
    │   │   │   ├── Avatar.spec.ts
    │   │   │   ├── Avatar.tsx
    │   │   │   └── AvatarNative.tsx
    │   │   ├── Backdrop
    │   │   │   ├── Backdrop.md
    │   │   │   ├── Backdrop.module.scss
    │   │   │   ├── Backdrop.spec.ts
    │   │   │   ├── Backdrop.tsx
    │   │   │   └── BackdropNative.tsx
    │   │   ├── Badge
    │   │   │   ├── Badge.md
    │   │   │   ├── Badge.module.scss
    │   │   │   ├── Badge.spec.ts
    │   │   │   ├── Badge.tsx
    │   │   │   └── BadgeNative.tsx
    │   │   ├── Bookmark
    │   │   │   ├── Bookmark.md
    │   │   │   ├── Bookmark.module.scss
    │   │   │   ├── Bookmark.spec.ts
    │   │   │   ├── Bookmark.tsx
    │   │   │   └── BookmarkNative.tsx
    │   │   ├── Breakout
    │   │   │   ├── Breakout.module.scss
    │   │   │   ├── Breakout.spec.ts
    │   │   │   ├── Breakout.tsx
    │   │   │   └── BreakoutNative.tsx
    │   │   ├── Button
    │   │   │   ├── Button-style.spec.ts
    │   │   │   ├── Button.md
    │   │   │   ├── Button.module.scss
    │   │   │   ├── Button.spec.ts
    │   │   │   ├── Button.tsx
    │   │   │   └── ButtonNative.tsx
    │   │   ├── Card
    │   │   │   ├── Card.md
    │   │   │   ├── Card.module.scss
    │   │   │   ├── Card.spec.ts
    │   │   │   ├── Card.tsx
    │   │   │   └── CardNative.tsx
    │   │   ├── Carousel
    │   │   │   ├── Carousel.md
    │   │   │   ├── Carousel.module.scss
    │   │   │   ├── Carousel.spec.ts
    │   │   │   ├── Carousel.tsx
    │   │   │   ├── CarouselContext.tsx
    │   │   │   ├── CarouselItem.tsx
    │   │   │   ├── CarouselItemNative.tsx
    │   │   │   └── CarouselNative.tsx
    │   │   ├── ChangeListener
    │   │   │   ├── ChangeListener.md
    │   │   │   ├── ChangeListener.spec.ts
    │   │   │   ├── ChangeListener.tsx
    │   │   │   └── ChangeListenerNative.tsx
    │   │   ├── chart-color-schemes.ts
    │   │   ├── Charts
    │   │   │   ├── AreaChart
    │   │   │   │   ├── AreaChart.md
    │   │   │   │   ├── AreaChart.spec.ts
    │   │   │   │   ├── AreaChart.tsx
    │   │   │   │   └── AreaChartNative.tsx
    │   │   │   ├── BarChart
    │   │   │   │   ├── BarChart.md
    │   │   │   │   ├── BarChart.module.scss
    │   │   │   │   ├── BarChart.spec.ts
    │   │   │   │   ├── BarChart.tsx
    │   │   │   │   └── BarChartNative.tsx
    │   │   │   ├── DonutChart
    │   │   │   │   ├── DonutChart.spec.ts
    │   │   │   │   └── DonutChart.tsx
    │   │   │   ├── LabelList
    │   │   │   │   ├── LabelList.spec.ts
    │   │   │   │   ├── LabelList.tsx
    │   │   │   │   ├── LabelListNative.module.scss
    │   │   │   │   └── LabelListNative.tsx
    │   │   │   ├── Legend
    │   │   │   │   ├── Legend.spec.ts
    │   │   │   │   ├── Legend.tsx
    │   │   │   │   └── LegendNative.tsx
    │   │   │   ├── LineChart
    │   │   │   │   ├── LineChart.md
    │   │   │   │   ├── LineChart.module.scss
    │   │   │   │   ├── LineChart.spec.ts
    │   │   │   │   ├── LineChart.tsx
    │   │   │   │   └── LineChartNative.tsx
    │   │   │   ├── PieChart
    │   │   │   │   ├── PieChart.md
    │   │   │   │   ├── PieChart.spec.ts
    │   │   │   │   ├── PieChart.tsx
    │   │   │   │   ├── PieChartNative.module.scss
    │   │   │   │   └── PieChartNative.tsx
    │   │   │   ├── RadarChart
    │   │   │   │   ├── RadarChart.md
    │   │   │   │   ├── RadarChart.spec.ts
    │   │   │   │   ├── RadarChart.tsx
    │   │   │   │   └── RadarChartNative.tsx
    │   │   │   ├── Tooltip
    │   │   │   │   ├── TooltipContent.module.scss
    │   │   │   │   ├── TooltipContent.spec.ts
    │   │   │   │   └── TooltipContent.tsx
    │   │   │   └── utils
    │   │   │       ├── abstractions.ts
    │   │   │       └── ChartProvider.tsx
    │   │   ├── Checkbox
    │   │   │   ├── Checkbox.md
    │   │   │   ├── Checkbox.spec.ts
    │   │   │   └── Checkbox.tsx
    │   │   ├── CodeBlock
    │   │   │   ├── CodeBlock.module.scss
    │   │   │   ├── CodeBlock.spec.ts
    │   │   │   ├── CodeBlock.tsx
    │   │   │   ├── CodeBlockNative.tsx
    │   │   │   └── highlight-code.ts
    │   │   ├── collectedComponentMetadata.ts
    │   │   ├── ColorPicker
    │   │   │   ├── ColorPicker.md
    │   │   │   ├── ColorPicker.module.scss
    │   │   │   ├── ColorPicker.spec.ts
    │   │   │   ├── ColorPicker.tsx
    │   │   │   └── ColorPickerNative.tsx
    │   │   ├── Column
    │   │   │   ├── Column.md
    │   │   │   ├── Column.tsx
    │   │   │   ├── ColumnNative.tsx
    │   │   │   ├── doc-resources
    │   │   │   │   └── list-component-data.js
    │   │   │   └── TableContext.tsx
    │   │   ├── component-utils.ts
    │   │   ├── ComponentProvider.tsx
    │   │   ├── ComponentRegistryContext.tsx
    │   │   ├── container-helpers.tsx
    │   │   ├── ContentSeparator
    │   │   │   ├── ContentSeparator.md
    │   │   │   ├── ContentSeparator.module.scss
    │   │   │   ├── ContentSeparator.spec.ts
    │   │   │   ├── ContentSeparator.tsx
    │   │   │   └── ContentSeparatorNative.tsx
    │   │   ├── DataSource
    │   │   │   ├── DataSource.md
    │   │   │   └── DataSource.tsx
    │   │   ├── DateInput
    │   │   │   ├── DateInput.md
    │   │   │   ├── DateInput.module.scss
    │   │   │   ├── DateInput.spec.ts
    │   │   │   ├── DateInput.tsx
    │   │   │   └── DateInputNative.tsx
    │   │   ├── DatePicker
    │   │   │   ├── DatePicker.md
    │   │   │   ├── DatePicker.module.scss
    │   │   │   ├── DatePicker.spec.ts
    │   │   │   ├── DatePicker.tsx
    │   │   │   └── DatePickerNative.tsx
    │   │   ├── DropdownMenu
    │   │   │   ├── DropdownMenu.md
    │   │   │   ├── DropdownMenu.module.scss
    │   │   │   ├── DropdownMenu.spec.ts
    │   │   │   ├── DropdownMenu.tsx
    │   │   │   ├── DropdownMenuNative.tsx
    │   │   │   ├── MenuItem.md
    │   │   │   └── SubMenuItem.md
    │   │   ├── EmojiSelector
    │   │   │   ├── EmojiSelector.md
    │   │   │   ├── EmojiSelector.spec.ts
    │   │   │   ├── EmojiSelector.tsx
    │   │   │   └── EmojiSelectorNative.tsx
    │   │   ├── ExpandableItem
    │   │   │   ├── ExpandableItem.module.scss
    │   │   │   ├── ExpandableItem.spec.ts
    │   │   │   ├── ExpandableItem.tsx
    │   │   │   └── ExpandableItemNative.tsx
    │   │   ├── FileInput
    │   │   │   ├── FileInput.md
    │   │   │   ├── FileInput.module.scss
    │   │   │   ├── FileInput.spec.ts
    │   │   │   ├── FileInput.tsx
    │   │   │   └── FileInputNative.tsx
    │   │   ├── FileUploadDropZone
    │   │   │   ├── FileUploadDropZone.md
    │   │   │   ├── FileUploadDropZone.module.scss
    │   │   │   ├── FileUploadDropZone.spec.ts
    │   │   │   ├── FileUploadDropZone.tsx
    │   │   │   └── FileUploadDropZoneNative.tsx
    │   │   ├── FlowLayout
    │   │   │   ├── FlowLayout.md
    │   │   │   ├── FlowLayout.module.scss
    │   │   │   ├── FlowLayout.spec.ts
    │   │   │   ├── FlowLayout.spec.ts-snapshots
    │   │   │   │   └── Edge-cases-boxShadow-is-not-clipped-1-non-smoke-darwin.png
    │   │   │   ├── FlowLayout.tsx
    │   │   │   └── FlowLayoutNative.tsx
    │   │   ├── Footer
    │   │   │   ├── Footer.md
    │   │   │   ├── Footer.module.scss
    │   │   │   ├── Footer.spec.ts
    │   │   │   ├── Footer.tsx
    │   │   │   └── FooterNative.tsx
    │   │   ├── Form
    │   │   │   ├── Form.md
    │   │   │   ├── Form.module.scss
    │   │   │   ├── Form.spec.ts
    │   │   │   ├── Form.tsx
    │   │   │   ├── formActions.ts
    │   │   │   ├── FormContext.ts
    │   │   │   └── FormNative.tsx
    │   │   ├── FormItem
    │   │   │   ├── FormItem.md
    │   │   │   ├── FormItem.module.scss
    │   │   │   ├── FormItem.spec.ts
    │   │   │   ├── FormItem.tsx
    │   │   │   ├── FormItemNative.tsx
    │   │   │   ├── HelperText.module.scss
    │   │   │   ├── HelperText.tsx
    │   │   │   ├── ItemWithLabel.tsx
    │   │   │   └── Validations.ts
    │   │   ├── FormSection
    │   │   │   ├── FormSection.md
    │   │   │   ├── FormSection.ts
    │   │   │   └── FormSection.xmlui
    │   │   ├── Fragment
    │   │   │   ├── Fragment.spec.ts
    │   │   │   └── Fragment.tsx
    │   │   ├── Heading
    │   │   │   ├── abstractions.ts
    │   │   │   ├── H1.md
    │   │   │   ├── H1.spec.ts
    │   │   │   ├── H2.md
    │   │   │   ├── H2.spec.ts
    │   │   │   ├── H3.md
    │   │   │   ├── H3.spec.ts
    │   │   │   ├── H4.md
    │   │   │   ├── H4.spec.ts
    │   │   │   ├── H5.md
    │   │   │   ├── H5.spec.ts
    │   │   │   ├── H6.md
    │   │   │   ├── H6.spec.ts
    │   │   │   ├── Heading.md
    │   │   │   ├── Heading.module.scss
    │   │   │   ├── Heading.spec.ts
    │   │   │   ├── Heading.tsx
    │   │   │   └── HeadingNative.tsx
    │   │   ├── HoverCard
    │   │   │   ├── HoverCard.tsx
    │   │   │   └── HovercardNative.tsx
    │   │   ├── HtmlTags
    │   │   │   ├── HtmlTags.module.scss
    │   │   │   ├── HtmlTags.spec.ts
    │   │   │   └── HtmlTags.tsx
    │   │   ├── Icon
    │   │   │   ├── AdmonitionDanger.tsx
    │   │   │   ├── AdmonitionInfo.tsx
    │   │   │   ├── AdmonitionNote.tsx
    │   │   │   ├── AdmonitionTip.tsx
    │   │   │   ├── AdmonitionWarning.tsx
    │   │   │   ├── ApiIcon.tsx
    │   │   │   ├── ArrowDropDown.module.scss
    │   │   │   ├── ArrowDropDown.tsx
    │   │   │   ├── ArrowDropUp.module.scss
    │   │   │   ├── ArrowDropUp.tsx
    │   │   │   ├── ArrowLeft.module.scss
    │   │   │   ├── ArrowLeft.tsx
    │   │   │   ├── ArrowRight.module.scss
    │   │   │   ├── ArrowRight.tsx
    │   │   │   ├── Attach.tsx
    │   │   │   ├── Binding.module.scss
    │   │   │   ├── Binding.tsx
    │   │   │   ├── BoardIcon.tsx
    │   │   │   ├── BoxIcon.tsx
    │   │   │   ├── CheckIcon.tsx
    │   │   │   ├── ChevronDownIcon.tsx
    │   │   │   ├── ChevronLeft.tsx
    │   │   │   ├── ChevronRight.tsx
    │   │   │   ├── ChevronUpIcon.tsx
    │   │   │   ├── CodeFileIcon.tsx
    │   │   │   ├── CodeSandbox.tsx
    │   │   │   ├── CompactListIcon.tsx
    │   │   │   ├── ContentCopyIcon.tsx
    │   │   │   ├── DarkToLightIcon.tsx
    │   │   │   ├── DatabaseIcon.module.scss
    │   │   │   ├── DatabaseIcon.tsx
    │   │   │   ├── DocFileIcon.tsx
    │   │   │   ├── DocIcon.tsx
    │   │   │   ├── DotMenuHorizontalIcon.tsx
    │   │   │   ├── DotMenuIcon.tsx
    │   │   │   ├── EmailIcon.tsx
    │   │   │   ├── EmptyFolderIcon.tsx
    │   │   │   ├── ErrorIcon.tsx
    │   │   │   ├── ExpressionIcon.tsx
    │   │   │   ├── FillPlusCricleIcon.tsx
    │   │   │   ├── FilterIcon.tsx
    │   │   │   ├── FolderIcon.tsx
    │   │   │   ├── GlobeIcon.tsx
    │   │   │   ├── HomeIcon.tsx
    │   │   │   ├── HyperLinkIcon.tsx
    │   │   │   ├── Icon.md
    │   │   │   ├── Icon.module.scss
    │   │   │   ├── Icon.spec.ts
    │   │   │   ├── Icon.tsx
    │   │   │   ├── IconNative.tsx
    │   │   │   ├── ImageFileIcon.tsx
    │   │   │   ├── Inspect.tsx
    │   │   │   ├── LightToDark.tsx
    │   │   │   ├── LinkIcon.tsx
    │   │   │   ├── ListIcon.tsx
    │   │   │   ├── LooseListIcon.tsx
    │   │   │   ├── MoonIcon.tsx
    │   │   │   ├── MoreOptionsIcon.tsx
    │   │   │   ├── NoSortIcon.tsx
    │   │   │   ├── PDFIcon.tsx
    │   │   │   ├── PenIcon.tsx
    │   │   │   ├── PhoneIcon.tsx
    │   │   │   ├── PhotoIcon.tsx
    │   │   │   ├── PlusIcon.tsx
    │   │   │   ├── SearchIcon.tsx
    │   │   │   ├── ShareIcon.tsx
    │   │   │   ├── SortAscendingIcon.tsx
    │   │   │   ├── SortDescendingIcon.tsx
    │   │   │   ├── StarsIcon.tsx
    │   │   │   ├── SunIcon.tsx
    │   │   │   ├── svg
    │   │   │   │   ├── admonition_danger.svg
    │   │   │   │   ├── admonition_info.svg
    │   │   │   │   ├── admonition_note.svg
    │   │   │   │   ├── admonition_tip.svg
    │   │   │   │   ├── admonition_warning.svg
    │   │   │   │   ├── api.svg
    │   │   │   │   ├── arrow-dropdown.svg
    │   │   │   │   ├── arrow-left.svg
    │   │   │   │   ├── arrow-right.svg
    │   │   │   │   ├── arrow-up.svg
    │   │   │   │   ├── attach.svg
    │   │   │   │   ├── binding.svg
    │   │   │   │   ├── box.svg
    │   │   │   │   ├── bulb.svg
    │   │   │   │   ├── code-file.svg
    │   │   │   │   ├── code-sandbox.svg
    │   │   │   │   ├── dark_to_light.svg
    │   │   │   │   ├── database.svg
    │   │   │   │   ├── doc.svg
    │   │   │   │   ├── empty-folder.svg
    │   │   │   │   ├── expression.svg
    │   │   │   │   ├── eye-closed.svg
    │   │   │   │   ├── eye-dark.svg
    │   │   │   │   ├── eye.svg
    │   │   │   │   ├── file-text.svg
    │   │   │   │   ├── filter.svg
    │   │   │   │   ├── folder.svg
    │   │   │   │   ├── img.svg
    │   │   │   │   ├── inspect.svg
    │   │   │   │   ├── light_to_dark.svg
    │   │   │   │   ├── moon.svg
    │   │   │   │   ├── pdf.svg
    │   │   │   │   ├── photo.svg
    │   │   │   │   ├── share.svg
    │   │   │   │   ├── stars.svg
    │   │   │   │   ├── sun.svg
    │   │   │   │   ├── trending-down.svg
    │   │   │   │   ├── trending-level.svg
    │   │   │   │   ├── trending-up.svg
    │   │   │   │   ├── txt.svg
    │   │   │   │   ├── unknown-file.svg
    │   │   │   │   ├── unlink.svg
    │   │   │   │   └── xls.svg
    │   │   │   ├── TableDeleteColumnIcon.tsx
    │   │   │   ├── TableDeleteRowIcon.tsx
    │   │   │   ├── TableInsertColumnIcon.tsx
    │   │   │   ├── TableInsertRowIcon.tsx
    │   │   │   ├── TrashIcon.tsx
    │   │   │   ├── TrendingDownIcon.tsx
    │   │   │   ├── TrendingLevelIcon.tsx
    │   │   │   ├── TrendingUpIcon.tsx
    │   │   │   ├── TxtIcon.tsx
    │   │   │   ├── UnknownFileIcon.tsx
    │   │   │   ├── UnlinkIcon.tsx
    │   │   │   ├── UserIcon.tsx
    │   │   │   ├── WarningIcon.tsx
    │   │   │   └── XlsIcon.tsx
    │   │   ├── IconProvider.tsx
    │   │   ├── IconRegistryContext.tsx
    │   │   ├── IFrame
    │   │   │   ├── IFrame.md
    │   │   │   ├── IFrame.module.scss
    │   │   │   ├── IFrame.spec.ts
    │   │   │   ├── IFrame.tsx
    │   │   │   └── IFrameNative.tsx
    │   │   ├── Image
    │   │   │   ├── Image.md
    │   │   │   ├── Image.module.scss
    │   │   │   ├── Image.spec.ts
    │   │   │   ├── Image.tsx
    │   │   │   └── ImageNative.tsx
    │   │   ├── Input
    │   │   │   ├── index.ts
    │   │   │   ├── InputAdornment.module.scss
    │   │   │   ├── InputAdornment.tsx
    │   │   │   ├── InputDivider.module.scss
    │   │   │   ├── InputDivider.tsx
    │   │   │   ├── InputLabel.module.scss
    │   │   │   ├── InputLabel.tsx
    │   │   │   ├── PartialInput.module.scss
    │   │   │   └── PartialInput.tsx
    │   │   ├── InspectButton
    │   │   │   ├── InspectButton.module.scss
    │   │   │   └── InspectButton.tsx
    │   │   ├── Items
    │   │   │   ├── Items.md
    │   │   │   ├── Items.spec.ts
    │   │   │   ├── Items.tsx
    │   │   │   └── ItemsNative.tsx
    │   │   ├── Link
    │   │   │   ├── Link.md
    │   │   │   ├── Link.module.scss
    │   │   │   ├── Link.spec.ts
    │   │   │   ├── Link.tsx
    │   │   │   └── LinkNative.tsx
    │   │   ├── List
    │   │   │   ├── doc-resources
    │   │   │   │   └── list-component-data.js
    │   │   │   ├── List.md
    │   │   │   ├── List.module.scss
    │   │   │   ├── List.spec.ts
    │   │   │   ├── List.tsx
    │   │   │   └── ListNative.tsx
    │   │   ├── Logo
    │   │   │   ├── doc-resources
    │   │   │   │   └── xmlui-logo.svg
    │   │   │   ├── Logo.md
    │   │   │   ├── Logo.tsx
    │   │   │   └── LogoNative.tsx
    │   │   ├── Markdown
    │   │   │   ├── CodeText.module.scss
    │   │   │   ├── CodeText.tsx
    │   │   │   ├── Markdown.md
    │   │   │   ├── Markdown.module.scss
    │   │   │   ├── Markdown.spec.ts
    │   │   │   ├── Markdown.tsx
    │   │   │   ├── MarkdownNative.tsx
    │   │   │   ├── parse-binding-expr.ts
    │   │   │   └── utils.ts
    │   │   ├── metadata-helpers.ts
    │   │   ├── ModalDialog
    │   │   │   ├── ConfirmationModalContextProvider.tsx
    │   │   │   ├── Dialog.module.scss
    │   │   │   ├── Dialog.tsx
    │   │   │   ├── ModalDialog.md
    │   │   │   ├── ModalDialog.module.scss
    │   │   │   ├── ModalDialog.spec.ts
    │   │   │   ├── ModalDialog.tsx
    │   │   │   ├── ModalDialogNative.tsx
    │   │   │   └── ModalVisibilityContext.tsx
    │   │   ├── NavGroup
    │   │   │   ├── NavGroup.md
    │   │   │   ├── NavGroup.module.scss
    │   │   │   ├── NavGroup.spec.ts
    │   │   │   ├── NavGroup.tsx
    │   │   │   ├── NavGroupContext.ts
    │   │   │   └── NavGroupNative.tsx
    │   │   ├── NavLink
    │   │   │   ├── NavLink.md
    │   │   │   ├── NavLink.module.scss
    │   │   │   ├── NavLink.spec.ts
    │   │   │   ├── NavLink.tsx
    │   │   │   └── NavLinkNative.tsx
    │   │   ├── NavPanel
    │   │   │   ├── NavPanel.md
    │   │   │   ├── NavPanel.module.scss
    │   │   │   ├── NavPanel.spec.ts
    │   │   │   ├── NavPanel.tsx
    │   │   │   └── NavPanelNative.tsx
    │   │   ├── NestedApp
    │   │   │   ├── AppWithCodeView.module.scss
    │   │   │   ├── AppWithCodeView.tsx
    │   │   │   ├── AppWithCodeViewNative.tsx
    │   │   │   ├── defaultProps.tsx
    │   │   │   ├── logo.svg
    │   │   │   ├── NestedApp.module.scss
    │   │   │   ├── NestedApp.tsx
    │   │   │   ├── NestedAppNative.tsx
    │   │   │   ├── Tooltip.module.scss
    │   │   │   ├── Tooltip.tsx
    │   │   │   └── utils.ts
    │   │   ├── NoResult
    │   │   │   ├── NoResult.md
    │   │   │   ├── NoResult.module.scss
    │   │   │   ├── NoResult.spec.ts
    │   │   │   ├── NoResult.tsx
    │   │   │   └── NoResultNative.tsx
    │   │   ├── NumberBox
    │   │   │   ├── numberbox-abstractions.ts
    │   │   │   ├── NumberBox.md
    │   │   │   ├── NumberBox.module.scss
    │   │   │   ├── NumberBox.spec.ts
    │   │   │   ├── NumberBox.tsx
    │   │   │   └── NumberBoxNative.tsx
    │   │   ├── Option
    │   │   │   ├── Option.md
    │   │   │   ├── Option.spec.ts
    │   │   │   ├── Option.tsx
    │   │   │   ├── OptionNative.tsx
    │   │   │   └── OptionTypeProvider.tsx
    │   │   ├── PageMetaTitle
    │   │   │   ├── PageMetaTilteNative.tsx
    │   │   │   ├── PageMetaTitle.md
    │   │   │   ├── PageMetaTitle.spec.ts
    │   │   │   └── PageMetaTitle.tsx
    │   │   ├── Pages
    │   │   │   ├── Page.md
    │   │   │   ├── Pages.md
    │   │   │   ├── Pages.module.scss
    │   │   │   ├── Pages.tsx
    │   │   │   └── PagesNative.tsx
    │   │   ├── Pagination
    │   │   │   ├── Pagination.md
    │   │   │   ├── Pagination.module.scss
    │   │   │   ├── Pagination.spec.ts
    │   │   │   ├── Pagination.tsx
    │   │   │   └── PaginationNative.tsx
    │   │   ├── PositionedContainer
    │   │   │   ├── PositionedContainer.module.scss
    │   │   │   ├── PositionedContainer.tsx
    │   │   │   └── PositionedContainerNative.tsx
    │   │   ├── ProfileMenu
    │   │   │   ├── ProfileMenu.module.scss
    │   │   │   └── ProfileMenu.tsx
    │   │   ├── ProgressBar
    │   │   │   ├── ProgressBar.md
    │   │   │   ├── ProgressBar.module.scss
    │   │   │   ├── ProgressBar.spec.ts
    │   │   │   ├── ProgressBar.tsx
    │   │   │   └── ProgressBarNative.tsx
    │   │   ├── Queue
    │   │   │   ├── Queue.md
    │   │   │   ├── Queue.spec.ts
    │   │   │   ├── Queue.tsx
    │   │   │   ├── queueActions.ts
    │   │   │   └── QueueNative.tsx
    │   │   ├── RadioGroup
    │   │   │   ├── RadioGroup.md
    │   │   │   ├── RadioGroup.module.scss
    │   │   │   ├── RadioGroup.spec.ts
    │   │   │   ├── RadioGroup.tsx
    │   │   │   ├── RadioGroupNative.tsx
    │   │   │   ├── RadioItem.tsx
    │   │   │   └── RadioItemNative.tsx
    │   │   ├── RealTimeAdapter
    │   │   │   ├── RealTimeAdapter.tsx
    │   │   │   └── RealTimeAdapterNative.tsx
    │   │   ├── Redirect
    │   │   │   ├── Redirect.md
    │   │   │   ├── Redirect.spec.ts
    │   │   │   └── Redirect.tsx
    │   │   ├── ResponsiveBar
    │   │   │   ├── README.md
    │   │   │   ├── ResponsiveBar.md
    │   │   │   ├── ResponsiveBar.module.scss
    │   │   │   ├── ResponsiveBar.spec.ts
    │   │   │   ├── ResponsiveBar.tsx
    │   │   │   └── ResponsiveBarNative.tsx
    │   │   ├── Select
    │   │   │   ├── HiddenOption.tsx
    │   │   │   ├── MultiSelectOption.tsx
    │   │   │   ├── OptionContext.ts
    │   │   │   ├── Select.md
    │   │   │   ├── Select.module.scss
    │   │   │   ├── Select.spec.ts
    │   │   │   ├── Select.tsx
    │   │   │   ├── SelectContext.tsx
    │   │   │   ├── SelectNative.tsx
    │   │   │   ├── SelectOption.tsx
    │   │   │   └── SimpleSelect.tsx
    │   │   ├── SelectionStore
    │   │   │   ├── SelectionStore.md
    │   │   │   ├── SelectionStore.tsx
    │   │   │   └── SelectionStoreNative.tsx
    │   │   ├── Slider
    │   │   │   ├── Slider.md
    │   │   │   ├── Slider.module.scss
    │   │   │   ├── Slider.spec.ts
    │   │   │   ├── Slider.tsx
    │   │   │   └── SliderNative.tsx
    │   │   ├── Slot
    │   │   │   ├── Slot.md
    │   │   │   ├── Slot.spec.ts
    │   │   │   └── Slot.ts
    │   │   ├── SlotItem.tsx
    │   │   ├── SpaceFiller
    │   │   │   ├── SpaceFiller.md
    │   │   │   ├── SpaceFiller.module.scss
    │   │   │   ├── SpaceFiller.spec.ts
    │   │   │   ├── SpaceFiller.tsx
    │   │   │   └── SpaceFillerNative.tsx
    │   │   ├── Spinner
    │   │   │   ├── Spinner.md
    │   │   │   ├── Spinner.module.scss
    │   │   │   ├── Spinner.spec.ts
    │   │   │   ├── Spinner.tsx
    │   │   │   └── SpinnerNative.tsx
    │   │   ├── Splitter
    │   │   │   ├── HSplitter.md
    │   │   │   ├── HSplitter.spec.ts
    │   │   │   ├── Splitter.md
    │   │   │   ├── Splitter.module.scss
    │   │   │   ├── Splitter.spec.ts
    │   │   │   ├── Splitter.tsx
    │   │   │   ├── SplitterNative.tsx
    │   │   │   ├── utils.ts
    │   │   │   ├── VSplitter.md
    │   │   │   └── VSplitter.spec.ts
    │   │   ├── Stack
    │   │   │   ├── CHStack.md
    │   │   │   ├── CHStack.spec.ts
    │   │   │   ├── CVStack.md
    │   │   │   ├── CVStack.spec.ts
    │   │   │   ├── HStack.md
    │   │   │   ├── HStack.spec.ts
    │   │   │   ├── Stack.md
    │   │   │   ├── Stack.module.scss
    │   │   │   ├── Stack.spec.ts
    │   │   │   ├── Stack.tsx
    │   │   │   ├── StackNative.tsx
    │   │   │   ├── VStack.md
    │   │   │   └── VStack.spec.ts
    │   │   ├── StickyBox
    │   │   │   ├── StickyBox.md
    │   │   │   ├── StickyBox.module.scss
    │   │   │   ├── StickyBox.tsx
    │   │   │   └── StickyBoxNative.tsx
    │   │   ├── Switch
    │   │   │   ├── Switch.md
    │   │   │   ├── Switch.spec.ts
    │   │   │   └── Switch.tsx
    │   │   ├── Table
    │   │   │   ├── doc-resources
    │   │   │   │   └── list-component-data.js
    │   │   │   ├── react-table-config.d.ts
    │   │   │   ├── Table.md
    │   │   │   ├── Table.module.scss
    │   │   │   ├── Table.spec.ts
    │   │   │   ├── Table.tsx
    │   │   │   ├── TableNative.tsx
    │   │   │   └── useRowSelection.tsx
    │   │   ├── TableOfContents
    │   │   │   ├── TableOfContents.module.scss
    │   │   │   ├── TableOfContents.spec.ts
    │   │   │   ├── TableOfContents.tsx
    │   │   │   └── TableOfContentsNative.tsx
    │   │   ├── Tabs
    │   │   │   ├── TabContext.tsx
    │   │   │   ├── TabItem.md
    │   │   │   ├── TabItem.tsx
    │   │   │   ├── TabItemNative.tsx
    │   │   │   ├── Tabs.md
    │   │   │   ├── Tabs.module.scss
    │   │   │   ├── Tabs.spec.ts
    │   │   │   ├── Tabs.tsx
    │   │   │   └── TabsNative.tsx
    │   │   ├── Text
    │   │   │   ├── Text.md
    │   │   │   ├── Text.module.scss
    │   │   │   ├── Text.spec.ts
    │   │   │   ├── Text.tsx
    │   │   │   └── TextNative.tsx
    │   │   ├── TextArea
    │   │   │   ├── TextArea.md
    │   │   │   ├── TextArea.module.scss
    │   │   │   ├── TextArea.spec.ts
    │   │   │   ├── TextArea.tsx
    │   │   │   ├── TextAreaNative.tsx
    │   │   │   ├── TextAreaResizable.tsx
    │   │   │   └── useComposedRef.ts
    │   │   ├── TextBox
    │   │   │   ├── TextBox.md
    │   │   │   ├── TextBox.module.scss
    │   │   │   ├── TextBox.spec.ts
    │   │   │   ├── TextBox.tsx
    │   │   │   └── TextBoxNative.tsx
    │   │   ├── Theme
    │   │   │   ├── NotificationToast.tsx
    │   │   │   ├── Theme.md
    │   │   │   ├── Theme.module.scss
    │   │   │   ├── Theme.spec.ts
    │   │   │   ├── Theme.tsx
    │   │   │   └── ThemeNative.tsx
    │   │   ├── TimeInput
    │   │   │   ├── TimeInput.md
    │   │   │   ├── TimeInput.module.scss
    │   │   │   ├── TimeInput.spec.ts
    │   │   │   ├── TimeInput.tsx
    │   │   │   ├── TimeInputNative.tsx
    │   │   │   └── utils.ts
    │   │   ├── Timer
    │   │   │   ├── Timer.md
    │   │   │   ├── Timer.spec.ts
    │   │   │   ├── Timer.tsx
    │   │   │   └── TimerNative.tsx
    │   │   ├── Toggle
    │   │   │   ├── Toggle.module.scss
    │   │   │   └── Toggle.tsx
    │   │   ├── ToneChangerButton
    │   │   │   ├── ToneChangerButton.md
    │   │   │   ├── ToneChangerButton.spec.ts
    │   │   │   └── ToneChangerButton.tsx
    │   │   ├── ToneSwitch
    │   │   │   ├── ToneSwitch.md
    │   │   │   ├── ToneSwitch.module.scss
    │   │   │   ├── ToneSwitch.spec.ts
    │   │   │   ├── ToneSwitch.tsx
    │   │   │   └── ToneSwitchNative.tsx
    │   │   ├── Tooltip
    │   │   │   ├── Tooltip.md
    │   │   │   ├── Tooltip.module.scss
    │   │   │   ├── Tooltip.spec.ts
    │   │   │   ├── Tooltip.tsx
    │   │   │   └── TooltipNative.tsx
    │   │   ├── Tree
    │   │   │   ├── testData.ts
    │   │   │   ├── Tree-dynamic.spec.ts
    │   │   │   ├── Tree-icons.spec.ts
    │   │   │   ├── Tree.md
    │   │   │   ├── Tree.spec.ts
    │   │   │   ├── TreeComponent.module.scss
    │   │   │   ├── TreeComponent.tsx
    │   │   │   └── TreeNative.tsx
    │   │   ├── TreeDisplay
    │   │   │   ├── TreeDisplay.md
    │   │   │   ├── TreeDisplay.module.scss
    │   │   │   ├── TreeDisplay.tsx
    │   │   │   └── TreeDisplayNative.tsx
    │   │   ├── ValidationSummary
    │   │   │   ├── ValidationSummary.module.scss
    │   │   │   └── ValidationSummary.tsx
    │   │   └── VisuallyHidden.tsx
    │   ├── components-core
    │   │   ├── abstractions
    │   │   │   ├── ComponentRenderer.ts
    │   │   │   ├── LoaderRenderer.ts
    │   │   │   ├── standalone.ts
    │   │   │   └── treeAbstractions.ts
    │   │   ├── action
    │   │   │   ├── actions.ts
    │   │   │   ├── APICall.tsx
    │   │   │   ├── FileDownloadAction.tsx
    │   │   │   ├── FileUploadAction.tsx
    │   │   │   ├── NavigateAction.tsx
    │   │   │   └── TimedAction.tsx
    │   │   ├── ApiBoundComponent.tsx
    │   │   ├── appContext
    │   │   │   ├── date-functions.ts
    │   │   │   ├── math-function.ts
    │   │   │   └── misc-utils.ts
    │   │   ├── AppContext.tsx
    │   │   ├── behaviors
    │   │   │   ├── Behavior.tsx
    │   │   │   ├── BehaviorContext.tsx
    │   │   │   └── CoreBehaviors.tsx
    │   │   ├── component-hooks.ts
    │   │   ├── ComponentDecorator.tsx
    │   │   ├── ComponentViewer.tsx
    │   │   ├── CompoundComponent.tsx
    │   │   ├── constants.ts
    │   │   ├── DebugViewProvider.tsx
    │   │   ├── descriptorHelper.ts
    │   │   ├── devtools
    │   │   │   ├── InspectorDialog.module.scss
    │   │   │   ├── InspectorDialog.tsx
    │   │   │   └── InspectorDialogVisibilityContext.tsx
    │   │   ├── EngineError.ts
    │   │   ├── event-handlers.ts
    │   │   ├── InspectorButton.module.scss
    │   │   ├── InspectorContext.tsx
    │   │   ├── interception
    │   │   │   ├── abstractions.ts
    │   │   │   ├── ApiInterceptor.ts
    │   │   │   ├── ApiInterceptorProvider.tsx
    │   │   │   ├── apiInterceptorWorker.ts
    │   │   │   ├── Backend.ts
    │   │   │   ├── Errors.ts
    │   │   │   ├── IndexedDb.ts
    │   │   │   ├── initMock.ts
    │   │   │   ├── InMemoryDb.ts
    │   │   │   ├── ReadonlyCollection.ts
    │   │   │   └── useApiInterceptorContext.tsx
    │   │   ├── loader
    │   │   │   ├── ApiLoader.tsx
    │   │   │   ├── DataLoader.tsx
    │   │   │   ├── ExternalDataLoader.tsx
    │   │   │   ├── Loader.tsx
    │   │   │   ├── MockLoaderRenderer.tsx
    │   │   │   └── PageableLoader.tsx
    │   │   ├── LoaderComponent.tsx
    │   │   ├── markup-check.ts
    │   │   ├── parts.ts
    │   │   ├── renderers.ts
    │   │   ├── rendering
    │   │   │   ├── AppContent.tsx
    │   │   │   ├── AppRoot.tsx
    │   │   │   ├── AppWrapper.tsx
    │   │   │   ├── buildProxy.ts
    │   │   │   ├── collectFnVarDeps.ts
    │   │   │   ├── ComponentAdapter.tsx
    │   │   │   ├── ComponentWrapper.tsx
    │   │   │   ├── Container.tsx
    │   │   │   ├── containers.ts
    │   │   │   ├── ContainerWrapper.tsx
    │   │   │   ├── ErrorBoundary.module.scss
    │   │   │   ├── ErrorBoundary.tsx
    │   │   │   ├── InvalidComponent.module.scss
    │   │   │   ├── InvalidComponent.tsx
    │   │   │   ├── nodeUtils.ts
    │   │   │   ├── reducer.ts
    │   │   │   ├── renderChild.tsx
    │   │   │   ├── StandaloneComponent.tsx
    │   │   │   ├── StateContainer.tsx
    │   │   │   ├── UnknownComponent.module.scss
    │   │   │   ├── UnknownComponent.tsx
    │   │   │   └── valueExtractor.ts
    │   │   ├── reportEngineError.ts
    │   │   ├── RestApiProxy.ts
    │   │   ├── script-runner
    │   │   │   ├── asyncProxy.ts
    │   │   │   ├── AttributeValueParser.ts
    │   │   │   ├── bannedFunctions.ts
    │   │   │   ├── BindingTreeEvaluationContext.ts
    │   │   │   ├── eval-tree-async.ts
    │   │   │   ├── eval-tree-common.ts
    │   │   │   ├── eval-tree-sync.ts
    │   │   │   ├── ParameterParser.ts
    │   │   │   ├── process-statement-async.ts
    │   │   │   ├── process-statement-common.ts
    │   │   │   ├── process-statement-sync.ts
    │   │   │   ├── ScriptingSourceTree.ts
    │   │   │   ├── simplify-expression.ts
    │   │   │   ├── statement-queue.ts
    │   │   │   └── visitors.ts
    │   │   ├── StandaloneApp.tsx
    │   │   ├── StandaloneExtensionManager.ts
    │   │   ├── TableOfContentsContext.tsx
    │   │   ├── theming
    │   │   │   ├── _themes.scss
    │   │   │   ├── component-layout-resolver.ts
    │   │   │   ├── extendThemeUtils.ts
    │   │   │   ├── hvar.ts
    │   │   │   ├── layout-resolver.ts
    │   │   │   ├── parse-layout-props.ts
    │   │   │   ├── StyleContext.tsx
    │   │   │   ├── StyleRegistry.ts
    │   │   │   ├── ThemeContext.tsx
    │   │   │   ├── ThemeProvider.tsx
    │   │   │   ├── themes
    │   │   │   │   ├── base-utils.ts
    │   │   │   │   ├── palette.ts
    │   │   │   │   ├── root.ts
    │   │   │   │   ├── solid.ts
    │   │   │   │   ├── theme-colors.ts
    │   │   │   │   └── xmlui.ts
    │   │   │   ├── themeVars.module.scss
    │   │   │   ├── themeVars.ts
    │   │   │   ├── transformThemeVars.ts
    │   │   │   └── utils.ts
    │   │   ├── utils
    │   │   │   ├── actionUtils.ts
    │   │   │   ├── audio-utils.ts
    │   │   │   ├── compound-utils.ts
    │   │   │   ├── css-utils.ts
    │   │   │   ├── DataLoaderQueryKeyGenerator.ts
    │   │   │   ├── date-utils.ts
    │   │   │   ├── extractParam.ts
    │   │   │   ├── hooks.tsx
    │   │   │   ├── LruCache.ts
    │   │   │   ├── mergeProps.ts
    │   │   │   ├── misc.ts
    │   │   │   ├── request-params.ts
    │   │   │   ├── statementUtils.ts
    │   │   │   └── treeUtils.ts
    │   │   └── xmlui-parser.ts
    │   ├── index-standalone.ts
    │   ├── index.scss
    │   ├── index.ts
    │   ├── language-server
    │   │   ├── server-common.ts
    │   │   ├── server-web-worker.ts
    │   │   ├── server.ts
    │   │   ├── services
    │   │   │   ├── common
    │   │   │   │   ├── docs-generation.ts
    │   │   │   │   ├── lsp-utils.ts
    │   │   │   │   ├── metadata-utils.ts
    │   │   │   │   └── syntax-node-utilities.ts
    │   │   │   ├── completion.ts
    │   │   │   ├── diagnostic.ts
    │   │   │   ├── format.ts
    │   │   │   └── hover.ts
    │   │   └── xmlui-metadata-generated.mjs
    │   ├── logging
    │   │   ├── LoggerContext.tsx
    │   │   ├── LoggerInitializer.tsx
    │   │   ├── LoggerService.ts
    │   │   └── xmlui.ts
    │   ├── logo.svg
    │   ├── parsers
    │   │   ├── common
    │   │   │   ├── GenericToken.ts
    │   │   │   ├── InputStream.ts
    │   │   │   └── utils.ts
    │   │   ├── scripting
    │   │   │   ├── code-behind-collect.ts
    │   │   │   ├── Lexer.ts
    │   │   │   ├── modules.ts
    │   │   │   ├── Parser.ts
    │   │   │   ├── ParserError.ts
    │   │   │   ├── ScriptingNodeTypes.ts
    │   │   │   ├── TokenTrait.ts
    │   │   │   ├── TokenType.ts
    │   │   │   └── tree-visitor.ts
    │   │   ├── style-parser
    │   │   │   ├── errors.ts
    │   │   │   ├── source-tree.ts
    │   │   │   ├── StyleInputStream.ts
    │   │   │   ├── StyleLexer.ts
    │   │   │   ├── StyleParser.ts
    │   │   │   └── tokens.ts
    │   │   └── xmlui-parser
    │   │       ├── CharacterCodes.ts
    │   │       ├── diagnostics.ts
    │   │       ├── fileExtensions.ts
    │   │       ├── index.ts
    │   │       ├── lint.ts
    │   │       ├── parser.ts
    │   │       ├── ParserError.ts
    │   │       ├── scanner.ts
    │   │       ├── syntax-kind.ts
    │   │       ├── syntax-node.ts
    │   │       ├── transform.ts
    │   │       ├── utils.ts
    │   │       ├── xmlui-serializer.ts
    │   │       └── xmlui-tree.ts
    │   ├── react-app-env.d.ts
    │   ├── syntax
    │   │   ├── monaco
    │   │   │   ├── grammar.monacoLanguage.ts
    │   │   │   ├── index.ts
    │   │   │   ├── xmlui-dark.ts
    │   │   │   ├── xmlui-light.ts
    │   │   │   └── xmluiscript.monacoLanguage.ts
    │   │   └── textMate
    │   │       ├── index.ts
    │   │       ├── xmlui-dark.json
    │   │       ├── xmlui-light.json
    │   │       ├── xmlui.json
    │   │       └── xmlui.tmLanguage.json
    │   ├── testing
    │   │   ├── assertions.ts
    │   │   ├── component-test-helpers.ts
    │   │   ├── ComponentDrivers.ts
    │   │   ├── drivers
    │   │   │   ├── DateInputDriver.ts
    │   │   │   ├── ModalDialogDriver.ts
    │   │   │   ├── NumberBoxDriver.ts
    │   │   │   ├── TextBoxDriver.ts
    │   │   │   ├── TimeInputDriver.ts
    │   │   │   ├── TimerDriver.ts
    │   │   │   └── TreeDriver.ts
    │   │   ├── fixtures.ts
    │   │   ├── infrastructure
    │   │   │   ├── index.html
    │   │   │   ├── main.tsx
    │   │   │   ├── public
    │   │   │   │   ├── mockServiceWorker.js
    │   │   │   │   ├── resources
    │   │   │   │   │   ├── bell.svg
    │   │   │   │   │   ├── box.svg
    │   │   │   │   │   ├── doc.svg
    │   │   │   │   │   ├── eye.svg
    │   │   │   │   │   ├── flower-640x480.jpg
    │   │   │   │   │   ├── sun.svg
    │   │   │   │   │   ├── test-image-100x100.jpg
    │   │   │   │   │   └── txt.svg
    │   │   │   │   └── serve.json
    │   │   │   └── TestBed.tsx
    │   │   └── themed-app-test-helpers.ts
    │   └── vite-env.d.ts
    ├── tests
    │   ├── components
    │   │   ├── CodeBlock
    │   │   │   └── hightlight-code.test.ts
    │   │   ├── playground-pattern.test.ts
    │   │   └── Tree
    │   │       └── Tree-states.test.ts
    │   ├── components-core
    │   │   ├── abstractions
    │   │   │   └── treeAbstractions.test.ts
    │   │   ├── container
    │   │   │   └── buildProxy.test.ts
    │   │   ├── interception
    │   │   │   ├── orderBy.test.ts
    │   │   │   ├── ReadOnlyCollection.test.ts
    │   │   │   └── request-param-converter.test.ts
    │   │   ├── scripts-runner
    │   │   │   ├── AttributeValueParser.test.ts
    │   │   │   ├── eval-tree-arrow-async.test.ts
    │   │   │   ├── eval-tree-arrow.test.ts
    │   │   │   ├── eval-tree-func-decl-async.test.ts
    │   │   │   ├── eval-tree-func-decl.test.ts
    │   │   │   ├── eval-tree-pre-post.test.ts
    │   │   │   ├── eval-tree-regression.test.ts
    │   │   │   ├── eval-tree.test.ts
    │   │   │   ├── function-proxy.test.ts
    │   │   │   ├── parser-regression.test.ts
    │   │   │   ├── process-event.test.ts
    │   │   │   ├── process-function.test.ts
    │   │   │   ├── process-implicit-context.test.ts
    │   │   │   ├── process-statement-asgn.test.ts
    │   │   │   ├── process-statement-destruct.test.ts
    │   │   │   ├── process-statement-regs.test.ts
    │   │   │   ├── process-statement-sync.test.ts
    │   │   │   ├── process-statement.test.ts
    │   │   │   ├── process-switch-sync.test.ts
    │   │   │   ├── process-switch.test.ts
    │   │   │   ├── process-try-sync.test.ts
    │   │   │   ├── process-try.test.ts
    │   │   │   └── test-helpers.ts
    │   │   ├── test-metadata-handler.ts
    │   │   ├── theming
    │   │   │   ├── border-segments.test.ts
    │   │   │   ├── component-layout.resolver.test.ts
    │   │   │   ├── layout-property-parser.test.ts
    │   │   │   ├── layout-resolver.test.ts
    │   │   │   ├── layout-resolver2.test.ts
    │   │   │   ├── layout-vp-override.test.ts
    │   │   │   └── padding-segments.test.ts
    │   │   └── utils
    │   │       ├── date-utils.test.ts
    │   │       ├── format-human-elapsed-time.test.ts
    │   │       └── LruCache.test.ts
    │   ├── language-server
    │   │   ├── completion.test.ts
    │   │   ├── format.test.ts
    │   │   ├── hover.test.ts
    │   │   └── mockData.ts
    │   └── parsers
    │       ├── common
    │       │   └── input-stream.test.ts
    │       ├── markdown
    │       │   └── parse-binding-expression.test.ts
    │       ├── parameter-parser.test.ts
    │       ├── paremeter-parser.test.ts
    │       ├── scripting
    │       │   ├── eval-tree-arrow.test.ts
    │       │   ├── eval-tree-pre-post.test.ts
    │       │   ├── eval-tree.test.ts
    │       │   ├── function-proxy.test.ts
    │       │   ├── lexer-literals.test.ts
    │       │   ├── lexer-misc.test.ts
    │       │   ├── module-parse.test.ts
    │       │   ├── parser-arrow.test.ts
    │       │   ├── parser-assignments.test.ts
    │       │   ├── parser-binary.test.ts
    │       │   ├── parser-destructuring.test.ts
    │       │   ├── parser-errors.test.ts
    │       │   ├── parser-expressions.test.ts
    │       │   ├── parser-function.test.ts
    │       │   ├── parser-literals.test.ts
    │       │   ├── parser-primary.test.ts
    │       │   ├── parser-regex.test.ts
    │       │   ├── parser-statements.test.ts
    │       │   ├── parser-unary.test.ts
    │       │   ├── process-event.test.ts
    │       │   ├── process-implicit-context.test.ts
    │       │   ├── process-statement-asgn.test.ts
    │       │   ├── process-statement-destruct.test.ts
    │       │   ├── process-statement-regs.test.ts
    │       │   ├── process-statement-sync.test.ts
    │       │   ├── process-statement.test.ts
    │       │   ├── process-switch-sync.test.ts
    │       │   ├── process-switch.test.ts
    │       │   ├── process-try-sync.test.ts
    │       │   ├── process-try.test.ts
    │       │   ├── simplify-expression.test.ts
    │       │   ├── statement-hooks.test.ts
    │       │   └── test-helpers.ts
    │       ├── style-parser
    │       │   ├── generateHvarChain.test.ts
    │       │   ├── parseHVar.test.ts
    │       │   ├── parser.test.ts
    │       │   └── tokens.test.ts
    │       └── xmlui
    │           ├── lint.test.ts
    │           ├── parser.test.ts
    │           ├── scanner.test.ts
    │           ├── transform.attr.test.ts
    │           ├── transform.circular.test.ts
    │           ├── transform.element.test.ts
    │           ├── transform.errors.test.ts
    │           ├── transform.escape.test.ts
    │           ├── transform.regression.test.ts
    │           ├── transform.script.test.ts
    │           ├── transform.test.ts
    │           └── xmlui.ts
    ├── tests-e2e
    │   ├── api-bound-component-regression.spec.ts
    │   ├── api-call-as-extracted-component.spec.ts
    │   ├── assign-to-object-or-array-regression.spec.ts
    │   ├── binding-regression.spec.ts
    │   ├── children-as-template-context-vars.spec.ts
    │   ├── compound-component.spec.ts
    │   ├── context-vars-regression.spec.ts
    │   ├── data-bindings.spec.ts
    │   ├── datasource-and-api-usage-in-var.spec.ts
    │   ├── datasource-direct-binding.spec.ts
    │   ├── datasource-onLoaded-regression.spec.ts
    │   ├── modify-array-item-regression.spec.ts
    │   ├── namespaces.spec.ts
    │   ├── push-to-array-regression.spec.ts
    │   ├── screen-breakpoints.spec.ts
    │   ├── scripting.spec.ts
    │   ├── state-scope-in-pages.spec.ts
    │   └── state-var-scopes.spec.ts
    ├── tsconfig.bin.json
    ├── tsconfig.json
    ├── tsconfig.node.json
    ├── vite.config.ts
    └── vitest.config.ts
```

# Files

--------------------------------------------------------------------------------
/xmlui/src/parsers/scripting/Parser.ts:
--------------------------------------------------------------------------------

```typescript
   1 | import {
   2 |   type ArrayDestructure,
   3 |   type ArrayLiteral,
   4 |   type ArrowExpression,
   5 |   type AssignmentExpression,
   6 |   type ScripNodeBase,
   7 |   type BinaryExpression,
   8 |   type BlockStatement,
   9 |   type BreakStatement,
  10 |   type CalculatedMemberAccessExpression,
  11 |   type ConditionalExpression,
  12 |   type ConstStatement,
  13 |   type ContinueStatement,
  14 |   type Destructure,
  15 |   type DoWhileStatement,
  16 |   type EmptyStatement,
  17 |   type Expression,
  18 |   type ExpressionStatement,
  19 |   type ForInStatement,
  20 |   type ForOfStatement,
  21 |   type ForStatement,
  22 |   type ForVarBinding,
  23 |   type FunctionDeclaration,
  24 |   type FunctionInvocationExpression,
  25 |   type Identifier,
  26 |   type IfStatement,
  27 |   type LetStatement,
  28 |   type Literal,
  29 |   type MemberAccessExpression,
  30 |   type NoArgExpression,
  31 |   type ObjectDestructure,
  32 |   type ObjectLiteral,
  33 |   type PostfixOpExpression,
  34 |   type PrefixOpExpression,
  35 |   type ReactiveVarDeclaration,
  36 |   type ReturnStatement,
  37 |   type SequenceExpression,
  38 |   type SpreadExpression,
  39 |   type Statement,
  40 |   type SwitchCase,
  41 |   type SwitchStatement,
  42 |   type ThrowStatement,
  43 |   type TryStatement,
  44 |   type UnaryExpression,
  45 |   type VarDeclaration,
  46 |   type VarStatement,
  47 |   type WhileStatement,
  48 |   type TemplateLiteralExpression,
  49 |   T_EMPTY_STATEMENT,
  50 |   T_BREAK_STATEMENT,
  51 |   T_CONTINUE_STATEMENT,
  52 |   T_EXPRESSION_STATEMENT,
  53 |   T_VAR_DECLARATION,
  54 |   T_LET_STATEMENT,
  55 |   T_CONST_STATEMENT,
  56 |   T_REACTIVE_VAR_DECLARATION,
  57 |   T_VAR_STATEMENT,
  58 |   T_ARRAY_DESTRUCTURE,
  59 |   T_BLOCK_STATEMENT,
  60 |   T_IF_STATEMENT,
  61 |   T_WHILE_STATEMENT,
  62 |   T_OBJECT_DESTRUCTURE,
  63 |   T_DO_WHILE_STATEMENT,
  64 |   T_RETURN_STATEMENT,
  65 |   T_FOR_STATEMENT,
  66 |   T_FOR_IN_STATEMENT,
  67 |   T_FOR_OF_STATEMENT,
  68 |   T_IDENTIFIER,
  69 |   T_THROW_STATEMENT,
  70 |   T_TRY_STATEMENT,
  71 |   T_SWITCH_CASE,
  72 |   T_SWITCH_STATEMENT,
  73 |   T_NO_ARG_EXPRESSION,
  74 |   T_SEQUENCE_EXPRESSION,
  75 |   T_OBJECT_LITERAL,
  76 |   T_ARRAY_LITERAL,
  77 |   T_SPREAD_EXPRESSION,
  78 |   T_FUNCTION_DECLARATION,
  79 |   T_ARROW_EXPRESSION,
  80 |   T_CONDITIONAL_EXPRESSION,
  81 |   T_ASSIGNMENT_EXPRESSION,
  82 |   T_BINARY_EXPRESSION,
  83 |   T_UNARY_EXPRESSION,
  84 |   T_FUNCTION_INVOCATION_EXPRESSION,
  85 |   T_MEMBER_ACCESS_EXPRESSION,
  86 |   T_CALCULATED_MEMBER_ACCESS_EXPRESSION,
  87 |   T_POSTFIX_OP_EXPRESSION,
  88 |   T_PREFIX_OP_EXPRESSION,
  89 |   T_LITERAL,
  90 |   T_TEMPLATE_LITERAL_EXPRESSION,
  91 |   T_DESTRUCTURE,
  92 | } from "../../components-core/script-runner/ScriptingSourceTree";
  93 | import type { GenericToken } from "../common/GenericToken";
  94 | import { InputStream } from "../common/InputStream";
  95 | import { Lexer } from "./Lexer";
  96 | import { ParserError, errorMessages } from "./ParserError";
  97 | import { tokenTraits } from "./TokenTrait";
  98 | import { TokenType } from "./TokenType";
  99 | import type { ErrorCodes, ParserErrorMessage } from "./ParserError";
 100 | 
 101 | type Token = GenericToken<TokenType>;
 102 | 
 103 | /**
 104 |  * States of the string parsing
 105 |  */
 106 | enum StrParseState {
 107 |   Normal,
 108 |   Backslash,
 109 |   X,
 110 |   Xh,
 111 |   UX1,
 112 |   UX2,
 113 |   UX3,
 114 |   UX4,
 115 |   Ucp1,
 116 |   Ucp2,
 117 |   Ucp3,
 118 |   Ucp4,
 119 |   Ucp5,
 120 |   Ucp6,
 121 |   UcpTail,
 122 | }
 123 | 
 124 | let lastNodeId = 0;
 125 | 
 126 | export function createXmlUiTreeNodeId(): number {
 127 |   return ++lastNodeId;
 128 | }
 129 | 
 130 | /**
 131 |  * This class parses a binding expression and transforms it into an evaluable expression tree
 132 |  */
 133 | export class Parser {
 134 |   // --- Keep track of error messages
 135 |   private _parseErrors: ParserErrorMessage[] = [];
 136 | 
 137 |   // --- Use this lexer
 138 |   private _lexer: Lexer;
 139 | 
 140 |   // --- Indicates the parsing level
 141 |   private _statementLevel = 0;
 142 | 
 143 |   /**
 144 |    * Initializes the parser with the specified source code
 145 |    * @param source Source code to parse
 146 |    */
 147 |   constructor(source?: string) {
 148 |     this._lexer = new Lexer(new InputStream(source ?? ""));
 149 |   }
 150 | 
 151 |   /**
 152 |    * Sets the source code to parse
 153 |    * @param source Source code to parse
 154 |    */
 155 |   setSource(source: string): void {
 156 |     this._lexer = new Lexer(new InputStream(source));
 157 |   }
 158 | 
 159 |   /**
 160 |    * The errors raised during the parse phase
 161 |    */
 162 |   get errors(): ParserErrorMessage[] {
 163 |     return this._parseErrors;
 164 |   }
 165 | 
 166 |   /**
 167 |    * Gets the current token
 168 |    */
 169 |   get current(): Token {
 170 |     return this._lexer.peek();
 171 |   }
 172 | 
 173 |   /**
 174 |    * Checks if we're at the end of the expression
 175 |    */
 176 |   get isEof(): boolean {
 177 |     return this._lexer.peek().type === TokenType.Eof;
 178 |   }
 179 | 
 180 |   /**
 181 |    * Gets the characters remaining after parsing
 182 |    */
 183 |   getTail(): string {
 184 |     return this._lexer.getTail();
 185 |   }
 186 | 
 187 |   // ==========================================================================
 188 |   // Statement parsing
 189 | 
 190 |   /**
 191 |    * Parses a list of statements:
 192 |    *
 193 |    * statements
 194 |    *   : statement*
 195 |    *   ;
 196 |    *
 197 |    * statement
 198 |    *   : emptyStatement
 199 |    *   | expressionStatement
 200 |    *   | letStatement
 201 |    *   | returnStatement
 202 |    *   ;
 203 |    */
 204 |   parseStatements(): Statement[] | null {
 205 |     this._statementLevel = 0;
 206 |     const statements: Statement[] = [];
 207 |     while (!this.isEof) {
 208 |       const statement = this.parseStatement();
 209 |       if (!statement) return null;
 210 |       statements.push(statement);
 211 |       if (statement.type !== T_EMPTY_STATEMENT) {
 212 |         this.skipToken(TokenType.Semicolon);
 213 |       }
 214 |     }
 215 |     return statements;
 216 |   }
 217 | 
 218 |   /**
 219 |    * Parses a single statement
 220 |    */
 221 |   private parseStatement(allowSequence = true): Statement | null {
 222 |     this._statementLevel++;
 223 |     try {
 224 |       const startToken = this._lexer.peek();
 225 |       switch (startToken.type) {
 226 |         case TokenType.Semicolon:
 227 |           return this.parseEmptyStatement();
 228 |         case TokenType.Let:
 229 |           return this.parseLetStatement();
 230 |         case TokenType.Const:
 231 |           return this.parseConstStatement();
 232 |         case TokenType.Var:
 233 |           return this.parseVarStatement();
 234 |         case TokenType.LBrace:
 235 |           return this.parseBlockStatement();
 236 |         case TokenType.If:
 237 |           return this.parseIfStatement();
 238 |         case TokenType.Do:
 239 |           return this.parseDoWhileStatement();
 240 |         case TokenType.While:
 241 |           return this.parseWhileStatement();
 242 |         case TokenType.Return:
 243 |           return this.parseReturnStatement();
 244 |         case TokenType.Break:
 245 |           this._lexer.get();
 246 |           return this.createStatementNode<BreakStatement>(
 247 |             T_BREAK_STATEMENT,
 248 |             {},
 249 |             startToken,
 250 |             startToken,
 251 |           );
 252 |         case TokenType.Continue:
 253 |           this._lexer.get();
 254 |           return this.createStatementNode<ContinueStatement>(
 255 |             T_CONTINUE_STATEMENT,
 256 |             {},
 257 |             startToken,
 258 |             startToken,
 259 |           );
 260 |         case TokenType.For:
 261 |           return this.parseForStatement();
 262 |         case TokenType.Throw:
 263 |           return this.parseThrowStatement();
 264 |         case TokenType.Try:
 265 |           return this.parseTryStatement();
 266 |         case TokenType.Switch:
 267 |           return this.parseSwitchStatement();
 268 |         case TokenType.Function:
 269 |           return this.parseFunctionDeclaration();
 270 |         default:
 271 |           if (this.isExpressionStart(startToken)) {
 272 |             return this.parseExpressionStatement(allowSequence);
 273 |           }
 274 |           this.reportError("W002", startToken, startToken.text);
 275 |           return null;
 276 |       }
 277 |     } finally {
 278 |       this._statementLevel--;
 279 |     }
 280 |   }
 281 | 
 282 |   /**
 283 |    * Parses an empty statement
 284 |    *
 285 |    * emptyStatement
 286 |    *   : ";"
 287 |    *   ;
 288 |    */
 289 |   private parseEmptyStatement(): EmptyStatement | null {
 290 |     const startToken = this._lexer.get();
 291 |     return this.createStatementNode<EmptyStatement>(T_EMPTY_STATEMENT, {}, startToken, startToken);
 292 |   }
 293 | 
 294 |   /**
 295 |    * Parses an expression statement
 296 |    *
 297 |    * expressionStatement
 298 |    *   : expression
 299 |    *   ;
 300 |    */
 301 |   private parseExpressionStatement(allowSequence = true): ExpressionStatement | null {
 302 |     const startToken = this._lexer.peek();
 303 |     const expr = this.getExpression(allowSequence);
 304 |     return expr
 305 |       ? this.createStatementNode<ExpressionStatement>(
 306 |           T_EXPRESSION_STATEMENT,
 307 |           {
 308 |             expr,
 309 |           },
 310 |           startToken,
 311 |           expr.endToken,
 312 |         )
 313 |       : null;
 314 |   }
 315 | 
 316 |   /**
 317 |    * Parses a let statement
 318 |    *
 319 |    * letStatement
 320 |    *   : "let" id ["=" expression] ("," id ["=" expression])*
 321 |    *   ;
 322 |    */
 323 |   private parseLetStatement(): LetStatement | null {
 324 |     const startToken = this._lexer.get();
 325 |     let endToken: Token | undefined = startToken;
 326 |     const decls: VarDeclaration[] = [];
 327 |     while (true) {
 328 |       const declStart = this._lexer.peek();
 329 |       let declarationProps: any = {};
 330 |       if (declStart.type === TokenType.LBrace) {
 331 |         // --- This is object destructure
 332 |         endToken = this._lexer.ahead(1);
 333 |         const oDestr = this.parseObjectDestructure();
 334 |         if (oDestr === null) return null;
 335 |         declarationProps = {
 336 |           oDestr,
 337 |         };
 338 |         endToken = oDestr.length > 0 ? oDestr[oDestr.length - 1].endToken : endToken;
 339 |       } else if (declStart.type === TokenType.LSquare) {
 340 |         // --- This is array destructure
 341 |         endToken = this._lexer.ahead(1);
 342 |         const aDestr = this.parseArrayDestructure();
 343 |         if (aDestr === null) return null;
 344 |         declarationProps = {
 345 |           aDestr,
 346 |         };
 347 |         endToken = aDestr.length > 0 ? aDestr[aDestr.length - 1].endToken : endToken;
 348 |       } else if (declStart.type === TokenType.Identifier) {
 349 |         if (declStart.text.startsWith("$")) {
 350 |           this.reportError("W031");
 351 |           return null;
 352 |         }
 353 |         endToken = this._lexer.get();
 354 |         declarationProps = {
 355 |           id: declStart.text,
 356 |         };
 357 |       } else {
 358 |         this.reportError("W003");
 359 |         return null;
 360 |       }
 361 | 
 362 |       // --- Optional initialization
 363 |       const initToken = this._lexer.peek();
 364 |       let expr: Expression | null = null;
 365 |       if (initToken.type === TokenType.Assignment) {
 366 |         this._lexer.get();
 367 |         expr = this.getExpression(false);
 368 |         if (expr === null) return null;
 369 |         declarationProps.expr = expr;
 370 |         endToken = expr.endToken;
 371 |       } else if (declarationProps.aDestr || declarationProps.oDestr) {
 372 |         this.reportError("W009", initToken);
 373 |         return null;
 374 |       }
 375 | 
 376 |       // --- New declaration reached
 377 |       decls.push(
 378 |         this.createExpressionNode<VarDeclaration>(
 379 |           T_VAR_DECLARATION,
 380 |           declarationProps,
 381 |           declStart,
 382 |           endToken,
 383 |         ),
 384 |       );
 385 | 
 386 |       // --- Check for more declarations
 387 |       if (this._lexer.peek().type !== TokenType.Comma) break;
 388 |       this._lexer.get();
 389 |     }
 390 | 
 391 |     // --- Done
 392 |     return this.createStatementNode<LetStatement>(
 393 |       T_LET_STATEMENT,
 394 |       {
 395 |         decls,
 396 |       },
 397 |       startToken,
 398 |       endToken,
 399 |     );
 400 |   }
 401 | 
 402 |   /**
 403 |    * Parses a const statement
 404 |    *
 405 |    * constStatement
 406 |    *   : "const" id "=" expression
 407 |    *   ;
 408 |    */
 409 |   private parseConstStatement(): ConstStatement | null {
 410 |     const startToken = this._lexer.get();
 411 |     let endToken: Token | undefined = startToken;
 412 |     const decls: VarDeclaration[] = [];
 413 |     while (true) {
 414 |       const declStart = this._lexer.peek();
 415 |       let declarationProps: any = {};
 416 |       if (declStart.type === TokenType.LBrace) {
 417 |         // --- This is object destructure
 418 |         endToken = this._lexer.ahead(1);
 419 |         const oDestr = this.parseObjectDestructure();
 420 |         if (oDestr === null) return null;
 421 |         declarationProps = {
 422 |           oDestr,
 423 |         };
 424 |         endToken = oDestr.length > 0 ? oDestr[oDestr.length - 1].endToken : endToken;
 425 |       } else if (declStart.type === TokenType.LSquare) {
 426 |         // --- This is array destructure
 427 |         endToken = this._lexer.ahead(1);
 428 |         const aDestr = this.parseArrayDestructure();
 429 |         if (aDestr === null) return null;
 430 |         declarationProps = {
 431 |           aDestr,
 432 |         };
 433 |         endToken = aDestr.length > 0 ? aDestr[aDestr.length - 1].endToken : endToken;
 434 |       } else if (declStart.type === TokenType.Identifier) {
 435 |         if (declStart.text.startsWith("$")) {
 436 |           this.reportError("W031");
 437 |           return null;
 438 |         }
 439 |         endToken = this._lexer.get();
 440 |         declarationProps = {
 441 |           id: declStart.text,
 442 |         };
 443 |       } else {
 444 |         this.reportError("W003");
 445 |         return null;
 446 |       }
 447 | 
 448 |       this.expectToken(TokenType.Assignment);
 449 |       const expr = this.getExpression(false);
 450 |       if (expr === null) return null;
 451 |       declarationProps.expr = expr;
 452 |       endToken = expr.endToken;
 453 | 
 454 |       // --- New declaration reached
 455 |       decls.push(
 456 |         this.createExpressionNode<VarDeclaration>(
 457 |           T_VAR_DECLARATION,
 458 |           declarationProps,
 459 |           declStart,
 460 |           endToken,
 461 |         ),
 462 |       );
 463 | 
 464 |       // --- Check for more declarations
 465 |       if (this._lexer.peek().type !== TokenType.Comma) break;
 466 |       this._lexer.get();
 467 |     }
 468 | 
 469 |     // --- Done
 470 |     return this.createStatementNode<ConstStatement>(
 471 |       T_CONST_STATEMENT,
 472 |       {
 473 |         decls,
 474 |       },
 475 |       startToken,
 476 |       endToken,
 477 |     );
 478 |   }
 479 | 
 480 |   /**
 481 |    * Parses a var statement
 482 |    *
 483 |    * constStatement
 484 |    *   : "var" id "=" expression
 485 |    *   ;
 486 |    */
 487 |   private parseVarStatement(): VarStatement | null {
 488 |     const startToken = this._lexer.get();
 489 |     let endToken: Token | undefined = startToken;
 490 |     const decls: ReactiveVarDeclaration[] = [];
 491 |     while (true) {
 492 |       const declStart = this._lexer.peek();
 493 |       let declarationProps: any = {};
 494 |       if (declStart.type === TokenType.Identifier) {
 495 |         if (declStart.text.startsWith("$")) {
 496 |           this.reportError("W031");
 497 |           return null;
 498 |         }
 499 |         endToken = this._lexer.get();
 500 |         declarationProps = {
 501 |           id: {
 502 |             type: T_IDENTIFIER,
 503 |             name: declStart.text,
 504 |             startToken: declStart,
 505 |             endToken,
 506 |           },
 507 |         };
 508 |       } else {
 509 |         this.reportError("W003");
 510 |         return null;
 511 |       }
 512 | 
 513 |       // --- Mandatory initialization
 514 |       this.expectToken(TokenType.Assignment);
 515 |       const expr = this.getExpression(false);
 516 |       if (expr === null) return null;
 517 |       declarationProps.expr = expr;
 518 |       endToken = expr.endToken;
 519 |       // --- New declaration reached
 520 |       decls.push(
 521 |         this.createExpressionNode<ReactiveVarDeclaration>(
 522 |           T_REACTIVE_VAR_DECLARATION,
 523 |           declarationProps,
 524 |           declStart,
 525 |           endToken,
 526 |         ),
 527 |       );
 528 | 
 529 |       // --- Check for more declarations
 530 |       if (this._lexer.peek().type !== TokenType.Comma) break;
 531 |       this._lexer.get();
 532 |     }
 533 | 
 534 |     // --- Done
 535 |     return this.createStatementNode<VarStatement>(
 536 |       T_VAR_STATEMENT,
 537 |       {
 538 |         decls,
 539 |       },
 540 |       startToken,
 541 |       endToken,
 542 |     );
 543 |   }
 544 | 
 545 |   /**
 546 |    * Parses an object destructure expression
 547 |    */
 548 |   private parseObjectDestructure(): ObjectDestructure[] | null {
 549 |     const result: ObjectDestructure[] = [];
 550 | 
 551 |     // --- Skip the starting left brace
 552 |     const startToken = this._lexer.get();
 553 |     let endToken: Token | undefined = startToken;
 554 | 
 555 |     let nextToken = this._lexer.peek();
 556 |     while (nextToken.type === TokenType.Identifier) {
 557 |       // --- Obtain the ID
 558 |       const id = nextToken.text;
 559 |       if (id.startsWith("$")) {
 560 |         this.reportError("W031");
 561 |         return null;
 562 |       }
 563 | 
 564 |       let alias: string | undefined;
 565 |       let aDestr: ArrayDestructure[] | undefined | null;
 566 |       let oDestr: ObjectDestructure[] | undefined | null;
 567 |       this._lexer.get();
 568 | 
 569 |       nextToken = this._lexer.peek();
 570 |       if (nextToken.type === TokenType.Colon) {
 571 |         // --- Check the available cases
 572 |         this._lexer.get();
 573 |         nextToken = this._lexer.peek();
 574 |         if (nextToken.type === TokenType.Identifier) {
 575 |           alias = nextToken.text;
 576 |           endToken = nextToken;
 577 |           this._lexer.get();
 578 |         } else if (nextToken.type === TokenType.LSquare) {
 579 |           aDestr = this.parseArrayDestructure();
 580 |           if (aDestr === null) return null;
 581 |           endToken = aDestr[aDestr.length - 1].endToken;
 582 |         } else if (nextToken.type === TokenType.LBrace) {
 583 |           oDestr = this.parseObjectDestructure();
 584 |           if (oDestr === null) return null;
 585 |           endToken = oDestr[oDestr.length - 1].endToken;
 586 |         }
 587 |       }
 588 | 
 589 |       // --- Check for next segment
 590 |       nextToken = this._lexer.peek();
 591 |       if (nextToken.type === TokenType.Comma || nextToken.type === TokenType.RBrace) {
 592 |         result.push(
 593 |           this.createExpressionNode<ObjectDestructure>(
 594 |             T_OBJECT_DESTRUCTURE,
 595 |             { id, alias, aDestr, oDestr },
 596 |             startToken,
 597 |             endToken,
 598 |           ),
 599 |         );
 600 | 
 601 |         if (nextToken.type === TokenType.Comma) {
 602 |           // --- Skip the delimiter comma
 603 |           this._lexer.get();
 604 |           nextToken = this._lexer.peek();
 605 |         }
 606 |       }
 607 |     }
 608 | 
 609 |     // --- Expect a closing right brace
 610 |     this.expectToken(TokenType.RBrace, "W004");
 611 |     return result;
 612 |   }
 613 | 
 614 |   private parseArrayDestructure(): ArrayDestructure[] | null {
 615 |     const result: ArrayDestructure[] = [];
 616 | 
 617 |     // --- Skip the starting left square
 618 |     const startToken = this._lexer.get();
 619 |     let endToken: Token | undefined = startToken;
 620 | 
 621 |     do {
 622 |       let nextToken = this._lexer.peek();
 623 |       let id: string | undefined;
 624 |       let aDestr: ArrayDestructure[] | undefined | null;
 625 |       let oDestr: ObjectDestructure[] | undefined | null;
 626 |       if (nextToken.type === TokenType.Identifier) {
 627 |         id = nextToken.text;
 628 |         if (id.startsWith("$")) {
 629 |           this.reportError("W031");
 630 |           return null;
 631 |         }
 632 | 
 633 |         endToken = nextToken;
 634 |         nextToken = this._lexer.get();
 635 |       } else if (nextToken.type === TokenType.LSquare) {
 636 |         aDestr = this.parseArrayDestructure();
 637 |         if (aDestr === null) return null;
 638 |         endToken = aDestr[aDestr.length - 1].endToken;
 639 |       } else if (nextToken.type === TokenType.LBrace) {
 640 |         oDestr = this.parseObjectDestructure();
 641 |         if (oDestr === null) return null;
 642 |         endToken = oDestr[oDestr.length - 1].endToken;
 643 |       }
 644 | 
 645 |       nextToken = this._lexer.peek();
 646 |       if (nextToken.type === TokenType.Comma) {
 647 |         // --- Store the segment
 648 |         result.push(
 649 |           this.createExpressionNode<ArrayDestructure>(
 650 |             T_ARRAY_DESTRUCTURE,
 651 |             { id, aDestr, oDestr },
 652 |             startToken,
 653 |             endToken,
 654 |           ),
 655 |         );
 656 |         this._lexer.get();
 657 |       } else if (nextToken.type === TokenType.RSquare) {
 658 |         if (id || aDestr || oDestr) {
 659 |           // --- Store a non-empty the segment
 660 |           result.push(
 661 |             this.createExpressionNode<ArrayDestructure>(
 662 |               T_ARRAY_DESTRUCTURE,
 663 |               { id, aDestr, oDestr },
 664 |               startToken,
 665 |               endToken,
 666 |             ),
 667 |           );
 668 |         }
 669 |         break;
 670 |       } else {
 671 |         this.reportError("W002", nextToken);
 672 |         return null;
 673 |       }
 674 |     } while (true);
 675 | 
 676 |     // --- Expect a closing right square
 677 |     this.expectToken(TokenType.RSquare, "W005");
 678 |     return result;
 679 |   }
 680 | 
 681 |   /**
 682 |    * Parses a block statement
 683 |    *
 684 |    * blockStatement
 685 |    *   : "{" (statement [";"])* "}"
 686 |    *   ;
 687 |    */
 688 |   private parseBlockStatement(): BlockStatement | null {
 689 |     const startToken = this._lexer.get();
 690 |     const stmts: Statement[] = [];
 691 |     while (this._lexer.peek().type !== TokenType.RBrace) {
 692 |       const statement = this.parseStatement();
 693 |       if (!statement) return null;
 694 |       stmts.push(statement);
 695 |       if (statement.type !== T_EMPTY_STATEMENT) {
 696 |         this.skipToken(TokenType.Semicolon);
 697 |       }
 698 |     }
 699 |     const endToken = this._lexer.get();
 700 |     return this.createStatementNode<BlockStatement>(
 701 |       T_BLOCK_STATEMENT,
 702 |       { stmts },
 703 |       startToken,
 704 |       endToken,
 705 |     );
 706 |   }
 707 | 
 708 |   /**
 709 |    * Parses an if statement
 710 |    *
 711 |    * ifStatement
 712 |    *   : "if" "(" expression ")" statement ["else" statement]
 713 |    *   ;
 714 |    */
 715 |   private parseIfStatement(): IfStatement | null {
 716 |     const startToken = this._lexer.get();
 717 |     let endToken: Token | undefined = startToken;
 718 |     this.expectToken(TokenType.LParent, "W014");
 719 |     const cond = this.getExpression();
 720 |     if (!cond) return null;
 721 |     this.expectToken(TokenType.RParent, "W006");
 722 |     const thenB = this.parseStatement();
 723 |     if (!thenB) return null;
 724 |     endToken = thenB.endToken;
 725 |     let elseCanFollow = true;
 726 |     if (thenB.type !== T_BLOCK_STATEMENT) {
 727 |       // --- We need a closing semicolon before else
 728 |       if (this._lexer.peek().type === TokenType.Semicolon) {
 729 |         this._lexer.get();
 730 |       } else {
 731 |         elseCanFollow = false;
 732 |       }
 733 |     }
 734 |     let elseB: Statement | null = null;
 735 |     if (elseCanFollow && this._lexer.peek().type === TokenType.Else) {
 736 |       this._lexer.get();
 737 |       elseB = this.parseStatement();
 738 |       if (!elseB) return null;
 739 |       endToken = elseB.endToken;
 740 |     }
 741 |     return this.createStatementNode<IfStatement>(
 742 |       T_IF_STATEMENT,
 743 |       {
 744 |         cond,
 745 |         thenB,
 746 |         elseB,
 747 |       },
 748 |       startToken,
 749 |       endToken,
 750 |     );
 751 |   }
 752 | 
 753 |   /**
 754 |    * Parses a while statement
 755 |    *
 756 |    * whileStatement
 757 |    *   : "while" "(" condition ")" statement
 758 |    *   ;
 759 |    */
 760 |   private parseWhileStatement(): WhileStatement | null {
 761 |     const startToken = this._lexer.get();
 762 |     this.expectToken(TokenType.LParent, "W014");
 763 |     const cond = this.getExpression();
 764 |     if (!cond) return null;
 765 |     this.expectToken(TokenType.RParent, "W006");
 766 |     const body = this.parseStatement();
 767 |     if (!body) return null;
 768 | 
 769 |     return this.createStatementNode<WhileStatement>(
 770 |       T_WHILE_STATEMENT,
 771 |       {
 772 |         cond,
 773 |         body,
 774 |       },
 775 |       startToken,
 776 |       body.endToken,
 777 |     );
 778 |   }
 779 | 
 780 |   /**
 781 |    * Parses a do-while statement
 782 |    *
 783 |    * doWhileStatement
 784 |    *   : "do" statement "while" "(" condition ")"
 785 |    *   ;
 786 |    */
 787 |   private parseDoWhileStatement(): DoWhileStatement | null {
 788 |     const startToken = this._lexer.get();
 789 |     const body = this.parseStatement();
 790 |     if (!body) return null;
 791 |     if (body.type !== T_BLOCK_STATEMENT && body.type !== T_EMPTY_STATEMENT) {
 792 |       this.expectToken(TokenType.Semicolon);
 793 |     }
 794 |     this.expectToken(TokenType.While);
 795 |     this.expectToken(TokenType.LParent, "W014");
 796 |     const cond = this.getExpression();
 797 |     if (!cond) return null;
 798 |     const endToken = this._lexer.peek();
 799 |     this.expectToken(TokenType.RParent, "W006");
 800 | 
 801 |     return this.createStatementNode<DoWhileStatement>(
 802 |       T_DO_WHILE_STATEMENT,
 803 |       {
 804 |         cond,
 805 |         body,
 806 |       },
 807 |       startToken,
 808 |       endToken,
 809 |     );
 810 |   }
 811 | 
 812 |   /**
 813 |    * Parses an expression statement
 814 |    *
 815 |    * returnStatement
 816 |    *   : "return" expression?
 817 |    *   ;
 818 |    */
 819 |   private parseReturnStatement(): ReturnStatement | null {
 820 |     const startToken = this._lexer.peek();
 821 |     let endToken: Token | undefined = this._lexer.get();
 822 |     let expr: Expression | undefined | null;
 823 |     if (tokenTraits[this._lexer.peek().type].expressionStart) {
 824 |       expr = this.getExpression();
 825 |       if (expr === null) return null;
 826 |       endToken = expr.endToken;
 827 |     }
 828 |     return this.createStatementNode<ReturnStatement>(
 829 |       T_RETURN_STATEMENT,
 830 |       {
 831 |         expr,
 832 |       },
 833 |       startToken,
 834 |       endToken,
 835 |     );
 836 |   }
 837 | 
 838 |   /**
 839 |    * forStatement
 840 |    *   : "for" "(" initStatement? ";" expression? ";" expression? ")" statement
 841 |    *   | forInOfStatement
 842 |    *   ;
 843 |    */
 844 |   private parseForStatement(): ForStatement | ForInStatement | ForOfStatement | null {
 845 |     const startToken = this._lexer.peek();
 846 |     this._lexer.get();
 847 |     this.expectToken(TokenType.LParent, "W014");
 848 | 
 849 |     // --- Check for..in and for..of
 850 |     let nextToken = this._lexer.peek();
 851 |     if (nextToken.type === TokenType.Identifier) {
 852 |       if (this._lexer.ahead(1).type === TokenType.In) {
 853 |         return this.parseForInOfStatement(startToken, "none", nextToken, T_FOR_IN_STATEMENT);
 854 |       } else if (this._lexer.ahead(1).type === TokenType.Of) {
 855 |         return this.parseForInOfStatement(startToken, "none", nextToken, T_FOR_OF_STATEMENT);
 856 |       }
 857 |     } else if (nextToken.type === TokenType.Let) {
 858 |       const idToken = this._lexer.ahead(1);
 859 |       if (idToken.type === TokenType.Identifier) {
 860 |         const inOfToken = this._lexer.ahead(2);
 861 |         if (inOfToken.type === TokenType.In) {
 862 |           return this.parseForInOfStatement(startToken, "let", idToken, T_FOR_IN_STATEMENT);
 863 |         } else if (inOfToken.type === TokenType.Of) {
 864 |           return this.parseForInOfStatement(startToken, "let", idToken, T_FOR_OF_STATEMENT);
 865 |         }
 866 |       }
 867 |     } else if (nextToken.type === TokenType.Const) {
 868 |       const idToken = this._lexer.ahead(1);
 869 |       if (idToken.type === TokenType.Identifier) {
 870 |         const inOfToken = this._lexer.ahead(2);
 871 |         if (inOfToken.type === TokenType.In) {
 872 |           return this.parseForInOfStatement(startToken, "const", idToken, T_FOR_IN_STATEMENT);
 873 |         } else if (inOfToken.type === TokenType.Of) {
 874 |           return this.parseForInOfStatement(startToken, "const", idToken, T_FOR_OF_STATEMENT);
 875 |         }
 876 |       }
 877 |     }
 878 | 
 879 |     // --- We accept only let statement, empty statement, and expression
 880 |     let init: ExpressionStatement | LetStatement | undefined;
 881 |     nextToken = this._lexer.peek();
 882 |     if (nextToken.type === TokenType.Semicolon) {
 883 |       // --- Empty statement: no init in the for loop
 884 |       this._lexer.get();
 885 |     } else if (nextToken.type === TokenType.Let) {
 886 |       // --- Let statement
 887 |       const letStmt = this.parseLetStatement();
 888 |       if (letStmt === null) {
 889 |         return null;
 890 |       }
 891 |       init = letStmt;
 892 |       if (init.decls.some((d) => !d.expr)) {
 893 |         this.reportError("W011");
 894 |         return null;
 895 |       }
 896 |       this.expectToken(TokenType.Semicolon);
 897 |     } else if (tokenTraits[nextToken.type].expressionStart) {
 898 |       // --- Expression statement
 899 |       const exprStmt = this.parseExpressionStatement();
 900 |       if (exprStmt === null) {
 901 |         return null;
 902 |       }
 903 |       init = exprStmt;
 904 |       this.expectToken(TokenType.Semicolon);
 905 |     }
 906 | 
 907 |     // --- Parse the condition
 908 |     let cond: Expression | null | undefined;
 909 |     nextToken = this._lexer.peek();
 910 |     if (nextToken.type === TokenType.Semicolon) {
 911 |       // --- No condition
 912 |       this._lexer.get();
 913 |     } else {
 914 |       cond = this.getExpression();
 915 |       if (cond === null) {
 916 |         return null;
 917 |       }
 918 |       this.expectToken(TokenType.Semicolon);
 919 |     }
 920 | 
 921 |     // --- Parse the update expression
 922 |     let upd: Expression | null | undefined;
 923 |     nextToken = this._lexer.peek();
 924 |     if (nextToken.type !== TokenType.RParent) {
 925 |       upd = this.getExpression();
 926 |       if (upd === null) {
 927 |         return null;
 928 |       }
 929 |     }
 930 | 
 931 |     // --- Close the declaration part
 932 |     this.expectToken(TokenType.RParent, "W006");
 933 | 
 934 |     // --- Get the body
 935 |     const body = this.parseStatement();
 936 |     if (!body) return null;
 937 | 
 938 |     return this.createStatementNode<ForStatement>(
 939 |       T_FOR_STATEMENT,
 940 |       {
 941 |         init,
 942 |         cond,
 943 |         upd,
 944 |         body,
 945 |       },
 946 |       startToken,
 947 |       body.endToken,
 948 |     );
 949 |   }
 950 | 
 951 |   /**
 952 |    * forInOfStatement
 953 |    *   : "for" "(" [ "let" | "const" ] identifier ( "in" | "of" ) expression? ")" statement
 954 |    *   | forInOfStatement
 955 |    *   ;
 956 |    *
 957 |    * @param startToken Statement start token
 958 |    * @param varB Variable binding of the for..in/of statement
 959 |    * @param id ID name
 960 |    * @param type Is it a for..in or a for..of?
 961 |    */
 962 |   private parseForInOfStatement(
 963 |     startToken: Token,
 964 |     varB: ForVarBinding,
 965 |     idToken: Token,
 966 |     type: number,
 967 |   ): ForInStatement | ForOfStatement | null {
 968 |     if (varB !== "none") {
 969 |       // --- Skip variable binding type
 970 |       if (idToken.text.startsWith("$")) {
 971 |         this.reportError("W031");
 972 |         return null;
 973 |       }
 974 |       this._lexer.get();
 975 |     }
 976 | 
 977 |     // --- Skip variable name, in/of token
 978 |     this._lexer.get();
 979 |     this._lexer.get();
 980 | 
 981 |     // --- Get the expression
 982 |     const expr = this.getExpression(true);
 983 | 
 984 |     // --- Close the declaration part
 985 |     this.expectToken(TokenType.RParent, "W006");
 986 | 
 987 |     // --- Get the body
 988 |     const body = this.parseStatement();
 989 |     if (!body) return null;
 990 | 
 991 |     return type === T_FOR_IN_STATEMENT
 992 |       ? this.createStatementNode<ForInStatement>(
 993 |           T_FOR_IN_STATEMENT,
 994 |           {
 995 |             varB,
 996 |             id: {
 997 |               type: T_IDENTIFIER,
 998 |               name: idToken.text,
 999 |               startToken: idToken,
1000 |               endToken: idToken,
1001 |             },
1002 |             expr,
1003 |             body,
1004 |           },
1005 |           startToken,
1006 |           body.endToken,
1007 |         )
1008 |       : this.createStatementNode<ForOfStatement>(
1009 |           T_FOR_OF_STATEMENT,
1010 |           {
1011 |             varB,
1012 |             id: {
1013 |               type: T_IDENTIFIER,
1014 |               name: idToken.text,
1015 |               startToken: idToken,
1016 |               endToken: idToken,
1017 |             },
1018 |             expr,
1019 |             body,
1020 |           },
1021 |           startToken,
1022 |           body.endToken,
1023 |         );
1024 |   }
1025 | 
1026 |   /**
1027 |    * Parses a throw statement
1028 |    *
1029 |    * throwStatement
1030 |    *   : "throw" expression
1031 |    *   ;
1032 |    */
1033 |   private parseThrowStatement(): ThrowStatement | null {
1034 |     const startToken = this._lexer.peek();
1035 |     this._lexer.get();
1036 |     let expr: Expression | undefined | null;
1037 |     expr = this.getExpression();
1038 |     if (expr === null) return null;
1039 |     return this.createStatementNode<ThrowStatement>(
1040 |       T_THROW_STATEMENT,
1041 |       {
1042 |         expr,
1043 |       },
1044 |       startToken,
1045 |       expr.endToken,
1046 |     );
1047 |   }
1048 | 
1049 |   /**
1050 |    * Parses a try..catch..finally statement
1051 |    *
1052 |    * tryStatement
1053 |    *   : "try" blockStatement catchClause finallyClause?
1054 |    *   | "try" blockStatement catchClause? finallyClause
1055 |    *   ;
1056 |    *
1057 |    * catchClause
1058 |    *   : "catch" [ "(" identifier ") ]? blockStatement
1059 |    *   ;
1060 |    *
1061 |    * finallyClause
1062 |    *   : "finally" blockStatement
1063 |    */
1064 |   private parseTryStatement(): TryStatement | null {
1065 |     const getBlock: () => BlockStatement | null = () => {
1066 |       const nextToken = this._lexer.peek();
1067 |       if (nextToken.type !== TokenType.LBrace) {
1068 |         this.reportError("W012", nextToken);
1069 |         return null;
1070 |       }
1071 |       return this.parseBlockStatement();
1072 |     };
1073 | 
1074 |     const startToken = this._lexer.peek();
1075 |     let endToken: Token | undefined = this._lexer.get();
1076 | 
1077 |     // --- Get "try" block
1078 |     const tryB = getBlock()!;
1079 |     let catchB: BlockStatement | undefined;
1080 |     let catchV: Identifier | undefined;
1081 |     let finallyB: BlockStatement | undefined;
1082 |     let nextToken = this._lexer.peek();
1083 |     if (nextToken.type === TokenType.Catch) {
1084 |       // --- Catch found
1085 |       this._lexer.get();
1086 |       nextToken = this._lexer.peek();
1087 |       if (nextToken.type === TokenType.LParent) {
1088 |         // --- Catch variable found
1089 |         this._lexer.get();
1090 |         nextToken = this._lexer.peek();
1091 |         if (nextToken.type !== TokenType.Identifier) {
1092 |           this.reportError("W003", nextToken);
1093 |           return null;
1094 |         }
1095 |         catchV = {
1096 |           type: T_IDENTIFIER,
1097 |           nodeId: createXmlUiTreeNodeId(),
1098 |           name: nextToken.text,
1099 |           startToken: nextToken,
1100 |           endToken: nextToken,
1101 |         };
1102 |         this._lexer.get();
1103 |         this.expectToken(TokenType.RParent, "W006");
1104 |       }
1105 | 
1106 |       // --- Get catch block
1107 |       catchB = getBlock()!;
1108 |       endToken = catchB.endToken;
1109 |       if (this._lexer.peek().type === TokenType.Finally) {
1110 |         // --- Finally after catch
1111 |         this._lexer.get();
1112 |         finallyB = getBlock()!;
1113 |         endToken = finallyB.endToken;
1114 |       }
1115 |     } else if (nextToken.type === TokenType.Finally) {
1116 |       // --- Finally found
1117 |       this._lexer.get();
1118 |       finallyB = getBlock()!;
1119 |       endToken = finallyB.endToken;
1120 |     } else {
1121 |       this.reportError("W013", nextToken);
1122 |       return null;
1123 |     }
1124 | 
1125 |     return this.createStatementNode<TryStatement>(
1126 |       T_TRY_STATEMENT,
1127 |       {
1128 |         tryB,
1129 |         catchB,
1130 |         catchV,
1131 |         finallyB,
1132 |       },
1133 |       startToken,
1134 |       endToken,
1135 |     );
1136 |   }
1137 | 
1138 |   /**
1139 |    * Parses a switch statement
1140 |    *
1141 |    * switchStatement
1142 |    *   : "switch" "(" expression ")" "{" caseClauses "}"
1143 |    *   ;
1144 |    *
1145 |    * caseClauses
1146 |    *   : "case" expression ":" statement*
1147 |    *   | "default" ":" statement*
1148 |    *   ;
1149 |    */
1150 |   private parseSwitchStatement(): SwitchStatement | null {
1151 |     const startToken = this._lexer.get();
1152 | 
1153 |     // --- Parse the switch expression
1154 |     this.expectToken(TokenType.LParent, "W014");
1155 |     const expr = this.getExpression();
1156 |     if (!expr) return null;
1157 |     this.expectToken(TokenType.RParent, "W006");
1158 | 
1159 |     // --- Parse the case blocks
1160 |     this.expectToken(TokenType.LBrace, "W012");
1161 |     const cases: SwitchCase[] = [];
1162 |     let defaultCaseFound = false;
1163 |     while (true) {
1164 |       let nextToken = this._lexer.peek();
1165 |       let caseE: Expression | null | undefined;
1166 |       if (nextToken.type === TokenType.Case) {
1167 |         // --- Process "case"
1168 |         this._lexer.get();
1169 |         caseE = this.getExpression();
1170 |         if (!caseE) return null;
1171 |       } else if (nextToken.type === TokenType.Default) {
1172 |         // --- Process "default"
1173 |         if (defaultCaseFound) {
1174 |           this.reportError("W016");
1175 |           return null;
1176 |         }
1177 |         defaultCaseFound = true;
1178 |         this._lexer.get();
1179 |       } else if (nextToken.type === TokenType.RBrace) {
1180 |         break;
1181 |       } else {
1182 |         this.reportError("W015");
1183 |         return null;
1184 |       }
1185 | 
1186 |       // --- Process label statements
1187 |       this.expectToken(TokenType.Colon, "W008");
1188 |       let stmts: Statement[] = [];
1189 |       let collected = false;
1190 |       while (!collected) {
1191 |         const stmtToken = this._lexer.peek();
1192 |         switch (stmtToken.type) {
1193 |           case TokenType.Case:
1194 |           case TokenType.Default:
1195 |           case TokenType.RBrace:
1196 |             // --- No more case to process
1197 |             collected = true;
1198 |             break;
1199 |           default:
1200 |             // --- Try to get the next statement
1201 |             const stmt = this.parseStatement();
1202 |             if (stmt === null) {
1203 |               collected = true;
1204 |               break;
1205 |             }
1206 |             stmts.push(stmt);
1207 |             if (stmt.type !== T_EMPTY_STATEMENT) {
1208 |               this.skipToken(TokenType.Semicolon);
1209 |             }
1210 |         }
1211 |       }
1212 | 
1213 |       cases.push(
1214 |         this.createNode(
1215 |           T_SWITCH_CASE,
1216 |           {
1217 |             caseE,
1218 |             stmts,
1219 |           },
1220 |           startToken,
1221 |         ),
1222 |       );
1223 |     }
1224 | 
1225 |     // --- Closing
1226 |     const endToken = this._lexer.peek();
1227 |     this.expectToken(TokenType.RBrace, "W004");
1228 |     return this.createStatementNode<SwitchStatement>(
1229 |       T_SWITCH_STATEMENT,
1230 |       {
1231 |         expr,
1232 |         cases,
1233 |       },
1234 |       startToken,
1235 |       endToken,
1236 |     );
1237 |   }
1238 | 
1239 |   /**
1240 |    * Parses a function declaration
1241 |    *
1242 |    * functionDeclaration
1243 |    *   : "function" identifier "(" [parameterList] ")" blockStatement
1244 |    *   ;
1245 |    */
1246 |   private parseFunctionDeclaration(allowNoName = false): FunctionDeclaration | null {
1247 |     const startToken = this._lexer.get();
1248 | 
1249 |     // --- Get the function name
1250 |     let functionName: string | undefined;
1251 |     const funcId = this._lexer.peek();
1252 |     if (allowNoName) {
1253 |       if (funcId.type !== TokenType.LParent) {
1254 |         if (funcId.type !== TokenType.Identifier) {
1255 |           this.reportError("W003", funcId);
1256 |           return null;
1257 |         }
1258 |         functionName = funcId.text;
1259 |         this._lexer.get();
1260 |       }
1261 |     } else {
1262 |       if (funcId.type !== TokenType.Identifier) {
1263 |         this.reportError("W003", funcId);
1264 |         return null;
1265 |       }
1266 |       functionName = funcId.text;
1267 |       this._lexer.get();
1268 |     }
1269 | 
1270 |     // --- Get the parameter list;
1271 |     const nextToken = this._lexer.peek();
1272 |     if (nextToken.type !== TokenType.LParent) {
1273 |       this.reportError("W014", nextToken);
1274 |       return null;
1275 |     }
1276 | 
1277 |     // --- Now, get the parameter list as an expression
1278 |     const exprList = this.getExpression(true);
1279 | 
1280 |     // --- We turn the expression into a parameter list
1281 |     let isValid: boolean;
1282 |     const args: Expression[] = [];
1283 |     switch (exprList!.type) {
1284 |       case T_NO_ARG_EXPRESSION:
1285 |         isValid = true;
1286 |         break;
1287 |       case T_IDENTIFIER:
1288 |         isValid = (exprList.parenthesized ?? 0) <= 1;
1289 |         args.push(exprList);
1290 |         break;
1291 |       case T_SEQUENCE_EXPRESSION:
1292 |         isValid = exprList.parenthesized === 1;
1293 |         let spreadFound = false;
1294 |         if (isValid) {
1295 |           for (const expr of exprList.exprs) {
1296 |             // --- Spread operator can be used only in the last position
1297 |             if (spreadFound) {
1298 |               isValid = false;
1299 |               break;
1300 |             }
1301 |             switch (expr.type) {
1302 |               case T_IDENTIFIER:
1303 |                 isValid = !expr.parenthesized;
1304 |                 args.push(expr);
1305 |                 break;
1306 |               case T_OBJECT_LITERAL: {
1307 |                 isValid = !expr.parenthesized;
1308 |                 if (isValid) {
1309 |                   const des = this.convertToObjectDestructure(expr);
1310 |                   if (des) args.push(des);
1311 |                 }
1312 |                 break;
1313 |               }
1314 |               case T_ARRAY_LITERAL: {
1315 |                 isValid = !expr.parenthesized;
1316 |                 if (isValid) {
1317 |                   const des = this.convertToArrayDestructure(expr);
1318 |                   if (des) args.push(des);
1319 |                 }
1320 |                 break;
1321 |               }
1322 |               case T_SPREAD_EXPRESSION: {
1323 |                 spreadFound = true;
1324 |                 if (expr.expr.type !== T_IDENTIFIER) {
1325 |                   isValid = false;
1326 |                   break;
1327 |                 }
1328 |                 args.push(expr);
1329 |                 break;
1330 |               }
1331 |               default:
1332 |                 isValid = false;
1333 |                 break;
1334 |             }
1335 |           }
1336 |         }
1337 |         break;
1338 |       case T_OBJECT_LITERAL:
1339 |         isValid = exprList.parenthesized === 1;
1340 |         if (isValid) {
1341 |           const des = this.convertToObjectDestructure(exprList);
1342 |           if (des) args.push(des);
1343 |         }
1344 |         break;
1345 |       case T_ARRAY_LITERAL:
1346 |         isValid = exprList.parenthesized === 1;
1347 |         if (isValid) {
1348 |           const des = this.convertToArrayDestructure(exprList);
1349 |           if (des) args.push(des);
1350 |         }
1351 |         break;
1352 |       case T_SPREAD_EXPRESSION:
1353 |         if (exprList.expr.type !== T_IDENTIFIER) {
1354 |           isValid = false;
1355 |           break;
1356 |         }
1357 |         isValid = true;
1358 |         args.push(exprList);
1359 |         break;
1360 |       default:
1361 |         isValid = false;
1362 |     }
1363 |     if (!isValid) {
1364 |       this.reportError("W010", startToken);
1365 |       return null;
1366 |     }
1367 | 
1368 |     // --- Get the function body (statement block)
1369 |     if (this._lexer.peek().type !== TokenType.LBrace) {
1370 |       this.reportError("W012", this._lexer.peek());
1371 |       return null;
1372 |     }
1373 | 
1374 |     const stmt = this.parseBlockStatement();
1375 |     if (!stmt) return null;
1376 | 
1377 |     // --- Done.
1378 |     return this.createStatementNode<FunctionDeclaration>(
1379 |       T_FUNCTION_DECLARATION,
1380 |       {
1381 |         id: { type: T_IDENTIFIER, name: functionName },
1382 |         args,
1383 |         stmt,
1384 |       },
1385 |       startToken,
1386 |       stmt.endToken,
1387 |     );
1388 |   }
1389 | 
1390 |   // ==========================================================================
1391 |   // Expression parsing
1392 | 
1393 |   /**
1394 |    * Parses an expression:
1395 |    *
1396 |    * expr
1397 |    *   : sequenceExpr
1398 |    *   ;
1399 |    */
1400 |   parseExpr(allowSequence = true): Expression | null {
1401 |     return allowSequence
1402 |       ? this.parseSequenceExpression()
1403 |       : this.parseCondOrSpreadOrAsgnOrArrowExpr();
1404 |   }
1405 | 
1406 |   /**
1407 |    * sequenceExpr
1408 |    *   : conditionalExpr ( "," conditionalExpr )?
1409 |    */
1410 |   private parseSequenceExpression(): Expression | null {
1411 |     const start = this._lexer.peek();
1412 |     let endToken: Token | undefined = start;
1413 |     let leftExpr = this.parseCondOrSpreadOrAsgnOrArrowExpr();
1414 |     if (!leftExpr) {
1415 |       return null;
1416 |     }
1417 |     endToken = leftExpr.endToken;
1418 |     const exprs: Expression[] = [];
1419 |     let loose = false;
1420 | 
1421 |     if (this._lexer.peek().type === TokenType.Comma) {
1422 |       exprs.push(leftExpr);
1423 |       while (this.skipToken(TokenType.Comma)) {
1424 |         if (this._lexer.peek().type === TokenType.Comma) {
1425 |           loose = true;
1426 |           endToken = this._lexer.peek();
1427 |           exprs.push(
1428 |             this.createExpressionNode<NoArgExpression>(T_NO_ARG_EXPRESSION, {}, endToken, endToken),
1429 |           );
1430 |         } else {
1431 |           const nextExpr = this.parseCondOrSpreadOrAsgnOrArrowExpr();
1432 |           if (!nextExpr) {
1433 |             break;
1434 |           }
1435 |           endToken = nextExpr.endToken;
1436 |           exprs.push(nextExpr);
1437 |         }
1438 |       }
1439 |     }
1440 | 
1441 |     if (!exprs.length) {
1442 |       // --- No sequence
1443 |       return leftExpr;
1444 |     }
1445 | 
1446 |     // --- Create the sequence expression
1447 |     leftExpr = this.createExpressionNode<SequenceExpression>(
1448 |       T_SEQUENCE_EXPRESSION,
1449 |       {
1450 |         exprs,
1451 |         loose,
1452 |       },
1453 |       start,
1454 |       endToken,
1455 |     );
1456 | 
1457 |     // --- Check for "loose" sequence expression
1458 |     if (loose) {
1459 |       leftExpr = this.convertToArrayDestructure(leftExpr);
1460 |     }
1461 | 
1462 |     // --- Done.
1463 |     return leftExpr;
1464 |   }
1465 | 
1466 |   /**
1467 |    * conditionalOrSpreadOrAsgnOrArrowExpr
1468 |    *   : nullCoalescingExpr ( "?" expr ":" expr )?
1469 |    *   | "..." nullCoalescingExpr
1470 |    *   | identifier "=" expr
1471 |    *   ;
1472 |    */
1473 |   private parseCondOrSpreadOrAsgnOrArrowExpr(): Expression | null {
1474 |     const startToken = this._lexer.peek();
1475 |     if (startToken.type === TokenType.Spread) {
1476 |       // --- Spread expression
1477 |       this._lexer.get();
1478 |       const spreadOperand = this.parseNullCoalescingExpr();
1479 |       return spreadOperand
1480 |         ? this.createExpressionNode<SpreadExpression>(
1481 |             T_SPREAD_EXPRESSION,
1482 |             {
1483 |               expr: spreadOperand,
1484 |             },
1485 |             startToken,
1486 |             spreadOperand.endToken,
1487 |           )
1488 |         : null;
1489 |     }
1490 | 
1491 |     if (startToken.type === TokenType.Function) {
1492 |       const funcDecl = this.parseFunctionDeclaration(true);
1493 |       return funcDecl
1494 |         ? this.createExpressionNode<ArrowExpression>(
1495 |             T_ARROW_EXPRESSION,
1496 |             {
1497 |               name: funcDecl.id.name,
1498 |               args: funcDecl.args,
1499 |               statement: funcDecl.stmt,
1500 |             },
1501 |             startToken,
1502 |             funcDecl.endToken,
1503 |           )
1504 |         : null;
1505 |     }
1506 | 
1507 |     const otherExpr = this.parseNullCoalescingExpr();
1508 |     if (!otherExpr) {
1509 |       return null;
1510 |     }
1511 | 
1512 |     const nextToken = this._lexer.peek();
1513 |     if (nextToken.type === TokenType.Arrow) {
1514 |       // --- It is an arrow expression
1515 |       return this.parseArrowExpression(startToken, otherExpr);
1516 |     }
1517 | 
1518 |     if (nextToken.type === TokenType.QuestionMark) {
1519 |       this._lexer.get();
1520 |       // --- Conditional expression
1521 |       const trueExpr = this.getExpression(false);
1522 |       this.expectToken(TokenType.Colon);
1523 |       const falseExpr = this.getExpression(false);
1524 | 
1525 |       return this.createExpressionNode<ConditionalExpression>(
1526 |         T_CONDITIONAL_EXPRESSION,
1527 |         {
1528 |           cond: otherExpr,
1529 |           thenE: trueExpr,
1530 |           elseE: falseExpr,
1531 |         },
1532 |         startToken,
1533 |         falseExpr!.endToken,
1534 |       );
1535 |     }
1536 | 
1537 |     if (tokenTraits[nextToken.type].isAssignment) {
1538 |       // --- Assignment
1539 |       this._lexer.get();
1540 |       const expr = this.getExpression();
1541 |       return expr
1542 |         ? this.createExpressionNode<AssignmentExpression>(
1543 |             T_ASSIGNMENT_EXPRESSION,
1544 |             {
1545 |               leftValue: otherExpr,
1546 |               op: nextToken.text,
1547 |               expr,
1548 |             },
1549 |             startToken,
1550 |             expr.endToken,
1551 |           )
1552 |         : null;
1553 |     }
1554 | 
1555 |     return otherExpr;
1556 |   }
1557 | 
1558 |   /**
1559 |    * Parses an arrow expression
1560 |    * @param start Start token
1561 |    * @param left Expression to the left from the arrow
1562 |    */
1563 |   private parseArrowExpression(start: Token, left: Expression): ArrowExpression | null {
1564 |     // --- Check the left expression
1565 |     let isValid: boolean;
1566 |     const args: Expression[] = [];
1567 |     switch (left.type) {
1568 |       case T_NO_ARG_EXPRESSION:
1569 |         isValid = true;
1570 |         break;
1571 |       case T_IDENTIFIER:
1572 |         isValid = (left.parenthesized ?? 0) <= 1;
1573 |         args.push(left);
1574 |         break;
1575 |       case T_SEQUENCE_EXPRESSION:
1576 |         isValid = left.parenthesized === 1;
1577 |         let spreadFound = false;
1578 |         if (isValid) {
1579 |           for (const expr of left.exprs) {
1580 |             if (spreadFound) {
1581 |               isValid = false;
1582 |               break;
1583 |             }
1584 |             switch (expr.type) {
1585 |               case T_IDENTIFIER:
1586 |                 isValid = !expr.parenthesized;
1587 |                 args.push(expr);
1588 |                 break;
1589 |               case T_OBJECT_LITERAL: {
1590 |                 isValid = !expr.parenthesized;
1591 |                 if (isValid) {
1592 |                   const des = this.convertToObjectDestructure(expr);
1593 |                   if (des) args.push(des);
1594 |                 }
1595 |                 break;
1596 |               }
1597 |               case T_ARRAY_LITERAL: {
1598 |                 isValid = !expr.parenthesized;
1599 |                 if (isValid) {
1600 |                   const des = this.convertToArrayDestructure(expr);
1601 |                   if (des) args.push(des);
1602 |                 }
1603 |                 break;
1604 |               }
1605 |               case T_SPREAD_EXPRESSION: {
1606 |                 spreadFound = true;
1607 |                 if (expr.expr.type !== T_IDENTIFIER) {
1608 |                   isValid = false;
1609 |                   break;
1610 |                 }
1611 |                 args.push(expr);
1612 |                 break;
1613 |               }
1614 |               default:
1615 |                 isValid = false;
1616 |                 break;
1617 |             }
1618 |           }
1619 |         }
1620 |         break;
1621 |       case T_OBJECT_LITERAL:
1622 |         isValid = left.parenthesized === 1;
1623 |         if (isValid) {
1624 |           const des = this.convertToObjectDestructure(left);
1625 |           if (des) args.push(des);
1626 |         }
1627 |         break;
1628 |       case T_ARRAY_LITERAL:
1629 |         isValid = left.parenthesized === 1;
1630 |         if (isValid) {
1631 |           const des = this.convertToArrayDestructure(left);
1632 |           if (des) args.push(des);
1633 |         }
1634 |         break;
1635 |       case T_SPREAD_EXPRESSION:
1636 |         isValid = left.expr.type === T_IDENTIFIER;
1637 |         if (isValid) {
1638 |           args.push(left);
1639 |         }
1640 |         break;
1641 |       default:
1642 |         isValid = false;
1643 |     }
1644 |     if (!isValid) {
1645 |       this.reportError("W010", start);
1646 |       return null;
1647 |     }
1648 | 
1649 |     // --- Skip the arrow token
1650 |     this._lexer.get();
1651 | 
1652 |     // --- Get arrow expression statements
1653 |     const statement = this.parseStatement(false);
1654 |     return statement
1655 |       ? this.createExpressionNode<ArrowExpression>(
1656 |           T_ARROW_EXPRESSION,
1657 |           {
1658 |             args,
1659 |             statement,
1660 |           },
1661 |           start,
1662 |           statement.endToken,
1663 |         )
1664 |       : null;
1665 |   }
1666 | 
1667 |   /**
1668 |    * nullCoalescingExpr
1669 |    *   : logicalOrExpr ( "??" logicalOrExpr )?
1670 |    *   ;
1671 |    */
1672 |   private parseNullCoalescingExpr(): Expression | null {
1673 |     const startToken = this._lexer.peek();
1674 |     let leftExpr = this.parseLogicalOrExpr();
1675 |     if (!leftExpr) {
1676 |       return null;
1677 |     }
1678 |     while (this.skipToken(TokenType.NullCoalesce)) {
1679 |       const rightExpr = this.parseLogicalOrExpr();
1680 |       if (!rightExpr) {
1681 |         this.reportError("W001");
1682 |         return null;
1683 |       }
1684 |       let endToken = rightExpr.endToken;
1685 |       leftExpr = this.createExpressionNode<BinaryExpression>(
1686 |         T_BINARY_EXPRESSION,
1687 |         {
1688 |           op: "??",
1689 |           left: leftExpr,
1690 |           right: rightExpr,
1691 |         },
1692 |         startToken,
1693 |         endToken,
1694 |       );
1695 |     }
1696 |     return leftExpr;
1697 |   }
1698 | 
1699 |   /**
1700 |    * logicalOrExpr
1701 |    *   : logicalAndExpr ( "||" logicalAndExpr )?
1702 |    *   ;
1703 |    */
1704 |   private parseLogicalOrExpr(): Expression | null {
1705 |     const startToken = this._lexer.peek();
1706 |     let leftExpr = this.parseLogicalAndExpr();
1707 |     if (!leftExpr) {
1708 |       return null;
1709 |     }
1710 | 
1711 |     while (this.skipToken(TokenType.LogicalOr)) {
1712 |       const rightExpr = this.parseLogicalAndExpr();
1713 |       if (!rightExpr) {
1714 |         this.reportError("W001");
1715 |         return null;
1716 |       }
1717 |       let endToken = rightExpr.endToken;
1718 |       leftExpr = this.createExpressionNode<BinaryExpression>(
1719 |         T_BINARY_EXPRESSION,
1720 |         {
1721 |           op: "||",
1722 |           left: leftExpr,
1723 |           right: rightExpr,
1724 |         },
1725 |         startToken,
1726 |         endToken,
1727 |       );
1728 |     }
1729 |     return leftExpr;
1730 |   }
1731 | 
1732 |   /**
1733 |    * logicalAndExpr
1734 |    *   : bitwiseOrExpr ( "&&" bitwiseOrExpr )?
1735 |    *   ;
1736 |    */
1737 |   private parseLogicalAndExpr(): Expression | null {
1738 |     const startToken = this._lexer.peek();
1739 |     let leftExpr = this.parseBitwiseOrExpr();
1740 |     if (!leftExpr) {
1741 |       return null;
1742 |     }
1743 | 
1744 |     while (this.skipToken(TokenType.LogicalAnd)) {
1745 |       const rightExpr = this.parseBitwiseOrExpr();
1746 |       if (!rightExpr) {
1747 |         this.reportError("W001");
1748 |         return null;
1749 |       }
1750 |       let endToken = rightExpr.endToken;
1751 |       leftExpr = this.createExpressionNode<BinaryExpression>(
1752 |         T_BINARY_EXPRESSION,
1753 |         {
1754 |           op: "&&",
1755 |           left: leftExpr,
1756 |           right: rightExpr,
1757 |         },
1758 |         startToken,
1759 |         endToken,
1760 |       );
1761 |     }
1762 |     return leftExpr;
1763 |   }
1764 | 
1765 |   /**
1766 |    * bitwiseOrExpr
1767 |    *   : bitwiseXorExpr ( "|" bitwiseXorExpr )?
1768 |    *   ;
1769 |    */
1770 |   private parseBitwiseOrExpr(): Expression | null {
1771 |     const startToken = this._lexer.peek();
1772 |     let leftExpr = this.parseBitwiseXorExpr();
1773 |     if (!leftExpr) {
1774 |       return null;
1775 |     }
1776 | 
1777 |     while (this.skipToken(TokenType.BitwiseOr)) {
1778 |       const rightExpr = this.parseBitwiseXorExpr();
1779 |       if (!rightExpr) {
1780 |         this.reportError("W001");
1781 |         return null;
1782 |       }
1783 |       let endToken = rightExpr.endToken;
1784 |       leftExpr = this.createExpressionNode<BinaryExpression>(
1785 |         T_BINARY_EXPRESSION,
1786 |         {
1787 |           op: "|",
1788 |           left: leftExpr,
1789 |           right: rightExpr,
1790 |         },
1791 |         startToken,
1792 |         endToken,
1793 |       );
1794 |     }
1795 |     return leftExpr;
1796 |   }
1797 | 
1798 |   /**
1799 |    * bitwiseXorExpr
1800 |    *   : bitwiseAndExpr ( "^" bitwiseAndExpr )?
1801 |    *   ;
1802 |    */
1803 |   private parseBitwiseXorExpr(): Expression | null {
1804 |     const startToken = this._lexer.peek();
1805 |     let leftExpr = this.parseBitwiseAndExpr();
1806 |     if (!leftExpr) {
1807 |       return null;
1808 |     }
1809 | 
1810 |     while (this.skipToken(TokenType.BitwiseXor)) {
1811 |       const rightExpr = this.parseBitwiseAndExpr();
1812 |       if (!rightExpr) {
1813 |         this.reportError("W001");
1814 |         return null;
1815 |       }
1816 |       let endToken = rightExpr.endToken;
1817 |       leftExpr = this.createExpressionNode<BinaryExpression>(
1818 |         T_BINARY_EXPRESSION,
1819 |         {
1820 |           op: "^",
1821 |           left: leftExpr,
1822 |           right: rightExpr,
1823 |         },
1824 |         startToken,
1825 |         endToken,
1826 |       );
1827 |     }
1828 |     return leftExpr;
1829 |   }
1830 | 
1831 |   /**
1832 |    * bitwiseAndExpr
1833 |    *   : equExpr ( "&" equExpr )?
1834 |    *   ;
1835 |    */
1836 |   private parseBitwiseAndExpr(): Expression | null {
1837 |     const startToken = this._lexer.peek();
1838 |     let leftExpr = this.parseEquExpr();
1839 |     if (!leftExpr) {
1840 |       return null;
1841 |     }
1842 | 
1843 |     while (this.skipToken(TokenType.BitwiseAnd)) {
1844 |       const rightExpr = this.parseEquExpr();
1845 |       if (!rightExpr) {
1846 |         this.reportError("W001");
1847 |         return null;
1848 |       }
1849 |       let endToken = rightExpr.endToken;
1850 |       leftExpr = this.createExpressionNode<BinaryExpression>(
1851 |         T_BINARY_EXPRESSION,
1852 |         {
1853 |           op: "&",
1854 |           left: leftExpr,
1855 |           right: rightExpr,
1856 |         },
1857 |         startToken,
1858 |         endToken,
1859 |       );
1860 |     }
1861 |     return leftExpr;
1862 |   }
1863 | 
1864 |   /**
1865 |    * equExpr
1866 |    *   : relOrInExpr ( ( "==" | "!=" | "===" | "!==" ) relOrInExpr )?
1867 |    *   ;
1868 |    */
1869 |   private parseEquExpr(): Expression | null {
1870 |     const startToken = this._lexer.peek();
1871 |     let leftExpr = this.parseRelOrInExpr();
1872 |     if (!leftExpr) {
1873 |       return null;
1874 |     }
1875 | 
1876 |     let opType: Token | null;
1877 |     while (
1878 |       (opType = this.skipTokens(
1879 |         TokenType.Equal,
1880 |         TokenType.StrictEqual,
1881 |         TokenType.NotEqual,
1882 |         TokenType.StrictNotEqual,
1883 |       ))
1884 |     ) {
1885 |       const rightExpr = this.parseRelOrInExpr();
1886 |       if (!rightExpr) {
1887 |         this.reportError("W001");
1888 |         return null;
1889 |       }
1890 |       let endToken = rightExpr.endToken;
1891 |       leftExpr = this.createExpressionNode<BinaryExpression>(
1892 |         T_BINARY_EXPRESSION,
1893 |         {
1894 |           op: opType.text,
1895 |           left: leftExpr,
1896 |           right: rightExpr,
1897 |         },
1898 |         startToken,
1899 |         endToken,
1900 |       );
1901 |     }
1902 |     return leftExpr;
1903 |   }
1904 | 
1905 |   /**
1906 |    * relOrInExpr
1907 |    *   : shiftExpr ( ( "<" | "<=" | ">" | ">=", "in" ) shiftExpr )?
1908 |    *   ;
1909 |    */
1910 |   private parseRelOrInExpr(): Expression | null {
1911 |     const startToken = this._lexer.peek();
1912 |     let leftExpr = this.parseShiftExpr();
1913 |     if (!leftExpr) {
1914 |       return null;
1915 |     }
1916 | 
1917 |     let opType: Token | null;
1918 |     while (
1919 |       (opType = this.skipTokens(
1920 |         TokenType.LessThan,
1921 |         TokenType.LessThanOrEqual,
1922 |         TokenType.GreaterThan,
1923 |         TokenType.GreaterThanOrEqual,
1924 |         TokenType.In,
1925 |       ))
1926 |     ) {
1927 |       const rightExpr = this.parseShiftExpr();
1928 |       if (!rightExpr) {
1929 |         this.reportError("W001");
1930 |         return null;
1931 |       }
1932 |       let endToken = rightExpr.endToken;
1933 |       leftExpr = this.createExpressionNode<BinaryExpression>(
1934 |         T_BINARY_EXPRESSION,
1935 |         {
1936 |           op: opType.text,
1937 |           left: leftExpr,
1938 |           right: rightExpr,
1939 |         },
1940 |         startToken,
1941 |         endToken,
1942 |       );
1943 |     }
1944 |     return leftExpr;
1945 |   }
1946 | 
1947 |   /**
1948 |    * shiftExpr
1949 |    *   : addExpr ( ( "<<" | ">>" | ">>>" ) addExpr )?
1950 |    *   ;
1951 |    */
1952 |   private parseShiftExpr(): Expression | null {
1953 |     const startToken = this._lexer.peek();
1954 |     let leftExpr = this.parseAddExpr();
1955 |     if (!leftExpr) {
1956 |       return null;
1957 |     }
1958 | 
1959 |     let opType: Token | null;
1960 |     while (
1961 |       (opType = this.skipTokens(
1962 |         TokenType.ShiftLeft,
1963 |         TokenType.ShiftRight,
1964 |         TokenType.SignedShiftRight,
1965 |       ))
1966 |     ) {
1967 |       const rightExpr = this.parseAddExpr();
1968 |       if (!rightExpr) {
1969 |         this.reportError("W001");
1970 |         return null;
1971 |       }
1972 |       let endToken = rightExpr.endToken;
1973 |       leftExpr = this.createExpressionNode<BinaryExpression>(
1974 |         T_BINARY_EXPRESSION,
1975 |         {
1976 |           op: opType.text,
1977 |           left: leftExpr,
1978 |           right: rightExpr,
1979 |         },
1980 |         startToken,
1981 |         endToken,
1982 |       );
1983 |     }
1984 |     return leftExpr;
1985 |   }
1986 | 
1987 |   /**
1988 |    * addExpr
1989 |    *   : multExpr ( ( "+" | "-" ) multExpr )?
1990 |    *   ;
1991 |    */
1992 |   private parseAddExpr(): Expression | null {
1993 |     const startToken = this._lexer.peek();
1994 |     let leftExpr = this.parseMultExpr();
1995 |     if (!leftExpr) {
1996 |       return null;
1997 |     }
1998 | 
1999 |     let opType: Token | null;
2000 |     while ((opType = this.skipTokens(TokenType.Plus, TokenType.Minus))) {
2001 |       const rightExpr = this.parseMultExpr();
2002 |       if (!rightExpr) {
2003 |         this.reportError("W001");
2004 |         return null;
2005 |       }
2006 |       let endToken = rightExpr.endToken;
2007 |       leftExpr = this.createExpressionNode<BinaryExpression>(
2008 |         T_BINARY_EXPRESSION,
2009 |         {
2010 |           op: opType.text,
2011 |           left: leftExpr,
2012 |           right: rightExpr,
2013 |         },
2014 |         startToken,
2015 |         endToken,
2016 |       );
2017 |     }
2018 |     return leftExpr;
2019 |   }
2020 | 
2021 |   /**
2022 |    * multExpr
2023 |    *   : exponentialExpr ( ( "*" | "/" | "%") exponentialExpr )?
2024 |    *   ;
2025 |    */
2026 |   private parseMultExpr(): Expression | null {
2027 |     const startToken = this._lexer.peek();
2028 |     let leftExpr = this.parseExponentialExpr();
2029 |     if (!leftExpr) {
2030 |       return null;
2031 |     }
2032 | 
2033 |     let opType: Token | null;
2034 |     while ((opType = this.skipTokens(TokenType.Multiply, TokenType.Divide, TokenType.Remainder))) {
2035 |       const rightExpr = this.parseExponentialExpr();
2036 |       if (!rightExpr) {
2037 |         this.reportError("W001");
2038 |         return null;
2039 |       }
2040 |       let endToken = rightExpr.endToken;
2041 |       leftExpr = this.createExpressionNode<BinaryExpression>(
2042 |         T_BINARY_EXPRESSION,
2043 |         {
2044 |           op: opType.text,
2045 |           left: leftExpr,
2046 |           right: rightExpr,
2047 |         },
2048 |         startToken,
2049 |         endToken,
2050 |       );
2051 |     }
2052 |     return leftExpr;
2053 |   }
2054 | 
2055 |   /**
2056 |    * exponentialExpr
2057 |    *   : unaryExpr ( "**" unaryExpr )?
2058 |    *   ;
2059 |    */
2060 |   private parseExponentialExpr(): Expression | null {
2061 |     const startToken = this._lexer.peek();
2062 |     let leftExpr = this.parseUnaryOrPrefixExpr();
2063 |     if (!leftExpr) {
2064 |       return null;
2065 |     }
2066 | 
2067 |     let opType: Token | null;
2068 |     let count = 0;
2069 |     while ((opType = this.skipToken(TokenType.Exponent))) {
2070 |       let rightExpr = this.parseUnaryOrPrefixExpr();
2071 |       if (!rightExpr) {
2072 |         this.reportError("W001");
2073 |         return null;
2074 |       }
2075 |       let endToken = rightExpr.endToken;
2076 |       if (count === 0) {
2077 |         leftExpr = this.createExpressionNode<BinaryExpression>(
2078 |           T_BINARY_EXPRESSION,
2079 |           {
2080 |             op: opType.text,
2081 |             left: leftExpr,
2082 |             right: rightExpr,
2083 |           },
2084 |           startToken,
2085 |           endToken,
2086 |         );
2087 |       } else {
2088 |         const prevLeft = leftExpr as BinaryExpression;
2089 |         leftExpr = this.createExpressionNode<BinaryExpression>(
2090 |           T_BINARY_EXPRESSION,
2091 |           {
2092 |             op: opType.text,
2093 |             left: prevLeft.left,
2094 |             right: {
2095 |               type: T_BINARY_EXPRESSION,
2096 |               op: opType.text,
2097 |               left: prevLeft.right,
2098 |               right: rightExpr,
2099 |             },
2100 |           },
2101 |           startToken,
2102 |           endToken,
2103 |         );
2104 |       }
2105 |       count++;
2106 |     }
2107 |     return leftExpr;
2108 |   }
2109 | 
2110 |   /**
2111 |    * unaryExpr
2112 |    *   : ( "typeof" | "delete" | "+" | "-" | "~" | "!" ) memberOrInvocationExpr
2113 |    *   | memberOrInvocationExpr
2114 |    *   ;
2115 |    */
2116 |   private parseUnaryOrPrefixExpr(): Expression | null {
2117 |     const startToken = this._lexer.peek();
2118 |     if (tokenTraits[startToken.type].canBeUnary) {
2119 |       this._lexer.get();
2120 |       const unaryOperand = this.parseUnaryOrPrefixExpr();
2121 |       if (!unaryOperand) {
2122 |         return null;
2123 |       }
2124 |       return this.createExpressionNode<UnaryExpression>(
2125 |         T_UNARY_EXPRESSION,
2126 |         {
2127 |           op: startToken.text,
2128 |           expr: unaryOperand,
2129 |         },
2130 |         startToken,
2131 |         unaryOperand.endToken,
2132 |       );
2133 |     }
2134 | 
2135 |     if (startToken.type === TokenType.IncOp || startToken.type === TokenType.DecOp) {
2136 |       this._lexer.get();
2137 |       const prefixOperand = this.parseMemberOrInvocationExpr();
2138 |       if (!prefixOperand) {
2139 |         return null;
2140 |       }
2141 |       return this.createExpressionNode<PrefixOpExpression>(
2142 |         T_PREFIX_OP_EXPRESSION,
2143 |         {
2144 |           op: startToken.text,
2145 |           expr: prefixOperand,
2146 |         },
2147 |         startToken,
2148 |         prefixOperand.endToken,
2149 |       );
2150 |     }
2151 | 
2152 |     // --- Not unary or prefix
2153 |     return this.parseMemberOrInvocationExpr();
2154 |   }
2155 | 
2156 |   /**
2157 |    * memberOrInvocationExpr
2158 |    *   : primaryExpr "(" functionArgs ")"
2159 |    *   | primaryExpr "." identifier
2160 |    *   | primaryExpr "?." identifier
2161 |    *   | primaryExpr "[" expr "]"
2162 |    *   ;
2163 |    */
2164 |   private parseMemberOrInvocationExpr(): Expression | null {
2165 |     const startToken = this._lexer.peek();
2166 |     let primary = this.parsePrimaryExpr();
2167 |     if (!primary) {
2168 |       return null;
2169 |     }
2170 | 
2171 |     let exitLoop = false;
2172 |     do {
2173 |       const currentStart = this._lexer.peek();
2174 | 
2175 |       switch (currentStart.type) {
2176 |         case TokenType.LParent: {
2177 |           this._lexer.get();
2178 |           let args: Expression[] = [];
2179 |           if (this._lexer.peek().type !== TokenType.RParent) {
2180 |             const expr = this.parseExpr();
2181 |             if (!expr) {
2182 |               this.reportError("W001");
2183 |               return null;
2184 |             }
2185 |             args = expr.type === T_SEQUENCE_EXPRESSION ? expr.exprs : [expr];
2186 |           }
2187 |           const endToken = this._lexer.peek();
2188 |           this.expectToken(TokenType.RParent, "W006");
2189 |           primary = this.createExpressionNode<FunctionInvocationExpression>(
2190 |             T_FUNCTION_INVOCATION_EXPRESSION,
2191 |             {
2192 |               obj: primary,
2193 |               arguments: args,
2194 |             },
2195 |             startToken,
2196 |             endToken,
2197 |           );
2198 |           break;
2199 |         }
2200 | 
2201 |         case TokenType.Dot:
2202 |         case TokenType.OptionalChaining:
2203 |           this._lexer.get();
2204 |           const member = this._lexer.get();
2205 |           const memberTrait = tokenTraits[member.type];
2206 |           if (!memberTrait.keywordLike) {
2207 |             this.reportError("W003");
2208 |             return null;
2209 |           }
2210 |           primary = this.createExpressionNode<MemberAccessExpression>(
2211 |             T_MEMBER_ACCESS_EXPRESSION,
2212 |             {
2213 |               obj: primary,
2214 |               member: member.text,
2215 |               opt: currentStart.type === TokenType.OptionalChaining,
2216 |             },
2217 |             startToken,
2218 |             member,
2219 |           );
2220 |           break;
2221 | 
2222 |         case TokenType.LSquare:
2223 |           this._lexer.get();
2224 |           const memberExpr = this.getExpression();
2225 |           if (!memberExpr) {
2226 |             return null;
2227 |           }
2228 |           const endToken = this._lexer.peek();
2229 |           this.expectToken(TokenType.RSquare, "W005");
2230 |           primary = this.createExpressionNode<CalculatedMemberAccessExpression>(
2231 |             T_CALCULATED_MEMBER_ACCESS_EXPRESSION,
2232 |             {
2233 |               obj: primary,
2234 |               member: memberExpr,
2235 |             },
2236 |             startToken,
2237 |             endToken,
2238 |           );
2239 |           break;
2240 | 
2241 |         default:
2242 |           exitLoop = true;
2243 |           break;
2244 |       }
2245 |     } while (!exitLoop);
2246 | 
2247 |     // --- Check for postfix operators
2248 |     const nextToken = this._lexer.peek();
2249 |     if (nextToken.type === TokenType.IncOp || nextToken.type === TokenType.DecOp) {
2250 |       this._lexer.get();
2251 |       return this.createExpressionNode<PostfixOpExpression>(
2252 |         T_POSTFIX_OP_EXPRESSION,
2253 |         {
2254 |           op: nextToken.text,
2255 |           expr: primary,
2256 |         },
2257 |         startToken,
2258 |         nextToken,
2259 |       );
2260 |     }
2261 | 
2262 |     return primary;
2263 |   }
2264 | 
2265 |   /**
2266 |    * primaryExpr
2267 |    *   : literal
2268 |    *   | identifier
2269 |    *   | "::" identifier
2270 |    *   | "$item"
2271 |    *   | "(" expr ")"
2272 |    *   ;
2273 |    */
2274 |   private parsePrimaryExpr(): Expression | null {
2275 |     const start = this._lexer.peek();
2276 |     switch (start.type) {
2277 |       case TokenType.LParent:
2278 |         // --- Parenthesised or no-arg expression
2279 |         this._lexer.get();
2280 |         if (this._lexer.peek().type === TokenType.RParent) {
2281 |           // --- No-arg
2282 |           const endToken = this._lexer.get();
2283 |           return this.createExpressionNode<NoArgExpression>(
2284 |             T_NO_ARG_EXPRESSION,
2285 |             {},
2286 |             start,
2287 |             endToken,
2288 |           );
2289 |         }
2290 | 
2291 |         // --- Parenthesized
2292 |         let parenthesizedExpr = this.parseExpr();
2293 |         if (!parenthesizedExpr) {
2294 |           return null;
2295 |         }
2296 |         const endToken = this._lexer.peek();
2297 |         this.expectToken(TokenType.RParent, "W006");
2298 |         return {
2299 |           ...parenthesizedExpr,
2300 |           parenthesized: (parenthesizedExpr.parenthesized ?? 0) + 1,
2301 |           startToken: start,
2302 |           endToken,
2303 |         };
2304 | 
2305 |       case TokenType.Identifier: {
2306 |         const idToken = this._lexer.get();
2307 |         return this.createExpressionNode<Identifier>(
2308 |           T_IDENTIFIER,
2309 |           {
2310 |             name: idToken.text,
2311 |           },
2312 |           idToken,
2313 |           idToken,
2314 |         );
2315 |       }
2316 | 
2317 |       case TokenType.Global: {
2318 |         this._lexer.get();
2319 |         const idToken = this._lexer.get();
2320 |         if (idToken.type !== TokenType.Identifier) {
2321 |           this.reportError("W003");
2322 |           return null;
2323 |         }
2324 |         return this.createExpressionNode<Identifier>(
2325 |           T_IDENTIFIER,
2326 |           {
2327 |             name: idToken.text,
2328 |             isGlobal: true,
2329 |           },
2330 |           idToken,
2331 |           idToken,
2332 |         );
2333 |       }
2334 |       case TokenType.Backtick:
2335 |         return this.parseTemplateLiteral();
2336 | 
2337 |       case TokenType.False:
2338 |       case TokenType.True:
2339 |         this._lexer.get();
2340 |         return this.createExpressionNode<Literal>(
2341 |           T_LITERAL,
2342 |           {
2343 |             value: start.type === TokenType.True,
2344 |           },
2345 |           start,
2346 |           start,
2347 |         );
2348 | 
2349 |       case TokenType.BinaryLiteral:
2350 |         this._lexer.get();
2351 |         return this.parseBinaryLiteral(start);
2352 | 
2353 |       case TokenType.DecimalLiteral:
2354 |         this._lexer.get();
2355 |         return this.parseDecimalLiteral(start);
2356 | 
2357 |       case TokenType.HexadecimalLiteral:
2358 |         this._lexer.get();
2359 |         return this.parseHexadecimalLiteral(start);
2360 | 
2361 |       case TokenType.RealLiteral:
2362 |         this._lexer.get();
2363 |         return this.parseRealLiteral(start);
2364 | 
2365 |       case TokenType.StringLiteral:
2366 |         this._lexer.get();
2367 |         return this.parseStringLiteral(start);
2368 | 
2369 |       case TokenType.Infinity:
2370 |         this._lexer.get();
2371 |         return this.createExpressionNode<Literal>(
2372 |           T_LITERAL,
2373 |           {
2374 |             value: Infinity,
2375 |           },
2376 |           start,
2377 |           start,
2378 |         );
2379 | 
2380 |       case TokenType.NaN:
2381 |         this._lexer.get();
2382 |         return this.createExpressionNode<Literal>(
2383 |           T_LITERAL,
2384 |           {
2385 |             value: NaN,
2386 |           },
2387 |           start,
2388 |           start,
2389 |         );
2390 | 
2391 |       case TokenType.Null:
2392 |         this._lexer.get();
2393 |         return this.createExpressionNode<Literal>(
2394 |           T_LITERAL,
2395 |           {
2396 |             value: null,
2397 |           },
2398 |           start,
2399 |           start,
2400 |         );
2401 | 
2402 |       case TokenType.Undefined:
2403 |         this._lexer.get();
2404 |         return this.createExpressionNode<Literal>(
2405 |           T_LITERAL,
2406 |           {
2407 |             value: undefined,
2408 |           },
2409 |           start,
2410 |           start,
2411 |         );
2412 | 
2413 |       case TokenType.LSquare:
2414 |         return this.parseArrayLiteral();
2415 | 
2416 |       case TokenType.LBrace:
2417 |         return this.parseObjectLiteral();
2418 | 
2419 |       case TokenType.Divide:
2420 |         return this.parseRegExpLiteral();
2421 |     }
2422 | 
2423 |     return null;
2424 |   }
2425 | 
2426 |   private parseTemplateLiteral(): TemplateLiteralExpression {
2427 |     const startToken = this._lexer.get();
2428 |     this._lexer.setStartingPhaseToTemplateLiteral();
2429 |     const segments: (Literal | Expression)[] = [];
2430 |     loop: while (true) {
2431 |       let nextToken = this._lexer.peek();
2432 |       switch (nextToken.type) {
2433 |         case TokenType.StringLiteral:
2434 |           this._lexer.get();
2435 |           const str = this.parseStringLiteral(nextToken, false);
2436 |           segments.push(str);
2437 |           break;
2438 |         case TokenType.DollarLBrace:
2439 |           this._lexer.get();
2440 |           const innerExpr = this.parseExpr();
2441 |           segments.push(innerExpr);
2442 |           this.expectToken(TokenType.RBrace, "W004");
2443 |           this._lexer.setStartingPhaseToTemplateLiteral();
2444 |           break;
2445 |         case TokenType.Backtick:
2446 |           break loop;
2447 |         default:
2448 |           this.reportError("W004");
2449 |       }
2450 |     }
2451 |     const endToken = this._lexer.get();
2452 |     return this.createExpressionNode<TemplateLiteralExpression>(
2453 |       T_TEMPLATE_LITERAL_EXPRESSION,
2454 |       { segments },
2455 |       startToken,
2456 |       endToken,
2457 |     );
2458 |   }
2459 | 
2460 |   /**
2461 |    * Parses an array literal
2462 |    */
2463 |   private parseArrayLiteral(): ArrayLiteral | null {
2464 |     const start = this._lexer.get();
2465 |     let expressions: Expression[] = [];
2466 |     if (this._lexer.peek().type !== TokenType.RSquare) {
2467 |       const expr = this.getExpression();
2468 |       if (expr) {
2469 |         expressions = expr.type === T_SEQUENCE_EXPRESSION ? expr.exprs : [expr];
2470 |       }
2471 |     }
2472 |     const endToken = this._lexer.peek();
2473 |     this.expectToken(TokenType.RSquare);
2474 |     return this.createExpressionNode<ArrayLiteral>(
2475 |       T_ARRAY_LITERAL,
2476 |       {
2477 |         items: expressions,
2478 |       },
2479 |       start,
2480 |       endToken,
2481 |     );
2482 |   }
2483 | 
2484 |   /**
2485 |    * Parses an object literal
2486 |    */
2487 |   private parseObjectLiteral(): ObjectLiteral | null {
2488 |     const start = this._lexer.get();
2489 |     let props: (SpreadExpression | [Expression, Expression])[] = [];
2490 |     if (this._lexer.peek().type !== TokenType.RBrace) {
2491 |       while (this._lexer.peek().type !== TokenType.RBrace) {
2492 |         // --- Check the next token
2493 |         const nextToken = this._lexer.peek();
2494 |         const traits = tokenTraits[nextToken.type];
2495 |         let nameExpr: Expression | null;
2496 | 
2497 |         // --- Get property name or calculated property name
2498 |         if (traits.expressionStart) {
2499 |           if (nextToken.type === TokenType.LSquare) {
2500 |             this._lexer.get();
2501 |             nameExpr = this.getExpression();
2502 |             if (!nameExpr) {
2503 |               return null;
2504 |             }
2505 |             this.expectToken(TokenType.RSquare, "W005");
2506 |             nameExpr = this.createExpressionNode<SequenceExpression>(
2507 |               T_SEQUENCE_EXPRESSION,
2508 |               {
2509 |                 exprs: [nameExpr],
2510 |               },
2511 |               start,
2512 |             );
2513 |           } else if (traits.isPropLiteral) {
2514 |             nameExpr = this.getExpression(false);
2515 |             if (!nameExpr) {
2516 |               return null;
2517 |             }
2518 |             if (
2519 |               nameExpr.type !== T_IDENTIFIER &&
2520 |               nameExpr.type !== T_LITERAL &&
2521 |               nameExpr.type !== T_SPREAD_EXPRESSION
2522 |             ) {
2523 |               this.reportError("W007");
2524 |               return null;
2525 |             }
2526 |           } else {
2527 |             this.reportError("W007");
2528 |             return null;
2529 |           }
2530 |         } else if (traits.keywordLike) {
2531 |           nameExpr = {
2532 |             type: T_IDENTIFIER,
2533 |             nodeId: createXmlUiTreeNodeId(),
2534 |             name: nextToken.text,
2535 |             startToken: nextToken,
2536 |             endToken: nextToken,
2537 |           };
2538 |           this._lexer.get();
2539 |         } else {
2540 |           this.reportError("W001");
2541 |           return null;
2542 |         }
2543 | 
2544 |         const nameType = nameExpr.type;
2545 |         if (nameType === T_SPREAD_EXPRESSION) {
2546 |           props.push(nameExpr);
2547 |         } else {
2548 |           if (nameType === T_LITERAL) {
2549 |             const val = nameExpr.value;
2550 |             if (typeof val !== "number" && typeof val !== "string") {
2551 |               this.expectToken(TokenType.RBrace, "W007");
2552 |               return null;
2553 |             }
2554 |           }
2555 | 
2556 |           // --- Value is optional, when we have a name
2557 |           let valueExpr: Expression | null = null;
2558 | 
2559 |           if (nameType === T_IDENTIFIER) {
2560 |             const nameFollowerToken = this._lexer.peek();
2561 |             if (
2562 |               nameFollowerToken.type === TokenType.Comma ||
2563 |               nameFollowerToken.type === TokenType.RBrace
2564 |             ) {
2565 |               valueExpr = { ...nameExpr };
2566 |             }
2567 |           }
2568 | 
2569 |           // --- Move to property value
2570 |           if (!valueExpr) {
2571 |             this.expectToken(TokenType.Colon, "W008");
2572 |             valueExpr = this.getExpression(false);
2573 |             if (!valueExpr) {
2574 |               return null;
2575 |             }
2576 |           }
2577 | 
2578 |           props.push([nameExpr, valueExpr]);
2579 |         }
2580 | 
2581 |         // --- Test property termination
2582 |         const next = this._lexer.peek().type;
2583 |         if (next === TokenType.Comma) {
2584 |           this._lexer.get();
2585 |         } else {
2586 |           if (next !== TokenType.RBrace) {
2587 |             break;
2588 |           }
2589 |         }
2590 |       }
2591 |     }
2592 | 
2593 |     const endToken = this._lexer.peek();
2594 |     this.expectToken(TokenType.RBrace, "W004");
2595 |     return this.createExpressionNode<ObjectLiteral>(
2596 |       T_OBJECT_LITERAL,
2597 |       {
2598 |         props,
2599 |       },
2600 |       start,
2601 |       endToken,
2602 |     );
2603 |   }
2604 | 
2605 |   private parseRegExpLiteral(): Literal | null {
2606 |     const startToken = this._lexer.peek();
2607 |     const result = this._lexer.getRegEx();
2608 |     if (result.success) {
2609 |       return this.createExpressionNode<Literal>(
2610 |         T_LITERAL,
2611 |         {
2612 |           value: new RegExp(result.pattern!, result.flags),
2613 |         },
2614 |         startToken,
2615 |         this._lexer.peek(),
2616 |       );
2617 |     }
2618 |     this.reportError("W002", startToken, result.pattern ?? "");
2619 |     return null;
2620 |   }
2621 | 
2622 |   /**
2623 |    * Gets an expression
2624 |    */
2625 |   private getExpression(allowSequence = true): Expression | null {
2626 |     const expr = this.parseExpr(allowSequence);
2627 |     if (expr) {
2628 |       return expr;
2629 |     }
2630 |     this.reportError("W001");
2631 |     return null;
2632 |   }
2633 | 
2634 |   // ==========================================================================
2635 |   // Helpers
2636 | 
2637 |   /**
2638 |    * Tests the type of the next token
2639 |    * @param type Expected token type
2640 |    * @param errorCode Error to raise if the next token is not expected
2641 |    * @param allowEof Allow an EOF instead of the expected token?
2642 |    */
2643 |   private expectToken(type: TokenType, errorCode?: ErrorCodes, allowEof?: boolean): Token | null {
2644 |     const next = this._lexer.peek();
2645 |     if (next.type === type || (allowEof && next.type === TokenType.Eof)) {
2646 |       // --- Skip the expected token
2647 |       return this._lexer.get();
2648 |     }
2649 |     this.reportError(errorCode ?? "W002", next, next.text);
2650 |     return null;
2651 |   }
2652 | 
2653 |   /**
2654 |    * Skips the next token if the type is the specified one
2655 |    * @param type Token type to check
2656 |    */
2657 |   private skipToken(type: TokenType): Token | null {
2658 |     const next = this._lexer.peek();
2659 |     if (next.type === type) {
2660 |       this._lexer.get();
2661 |       return next;
2662 |     }
2663 |     return null;
2664 |   }
2665 | 
2666 |   /**
2667 |    * Skips the next token if the type is the specified one
2668 |    * @param types Token types to check
2669 |    */
2670 |   private skipTokens(...types: TokenType[]): Token | null {
2671 |     const next = this._lexer.peek();
2672 |     for (const type of types) {
2673 |       if (next.type === type) {
2674 |         this._lexer.get();
2675 |         return next;
2676 |       }
2677 |     }
2678 |     return null;
2679 |   }
2680 | 
2681 |   /**
2682 |    * Reports the specified error
2683 |    * @param errorCode Error code
2684 |    * @param token Token that represents the error's position
2685 |    * @param options Error message options
2686 |    */
2687 |   private reportError(errorCode: ErrorCodes, token?: Token, ...options: any[]): void {
2688 |     let errorText: string = errorMessages[errorCode] ?? "Unkonwn error";
2689 |     if (options) {
2690 |       options.forEach(
2691 |         (o, idx) => (errorText = replace(errorText, `{${idx}}`, options[idx].toString())),
2692 |       );
2693 |     }
2694 |     if (!token) {
2695 |       token = this._lexer.peek();
2696 |     }
2697 |     this._parseErrors.push({
2698 |       code: errorCode,
2699 |       text: errorText,
2700 |       line: token.startLine,
2701 |       column: token.startColumn,
2702 |     });
2703 |     throw new ParserError(errorText, errorCode);
2704 | 
2705 |     function replace(input: string, placeholder: string, replacement: string): string {
2706 |       do {
2707 |         input = input.replace(placeholder, replacement);
2708 |       } while (input.includes(placeholder));
2709 |       return input;
2710 |     }
2711 |   }
2712 | 
2713 |   /**
2714 |    * Creates an expression node
2715 |    * @param type Expression type
2716 |    * @param stump Stump properties
2717 |    * @param startToken The token that starts the expression
2718 |    * @param endToken The token that ends the expression
2719 |    * @param source Expression source code to store to the node
2720 |    */
2721 |   private createNode<T extends ScripNodeBase>(
2722 |     type: ScripNodeBase["type"],
2723 |     stump: any,
2724 |     startToken: Token,
2725 |     endToken?: Token,
2726 |   ): T {
2727 |     if (!endToken) {
2728 |       endToken = this._lexer.peek();
2729 |     }
2730 |     return Object.assign({}, stump, {
2731 |       type,
2732 |       startToken,
2733 |       endToken,
2734 |     } as ScripNodeBase);
2735 |   }
2736 | 
2737 |   /**
2738 |    * Creates an expression node
2739 |    * @param type Expression type
2740 |    * @param stump Stump properties
2741 |    * @param startToken The token that starts the expression
2742 |    * @param endToken The token that ends the expression
2743 |    * @param source Expression source code to store to the node
2744 |    */
2745 |   private createExpressionNode<T extends Expression>(
2746 |     type: Expression["type"],
2747 |     stump: any = {},
2748 |     startToken?: Token,
2749 |     endToken?: Token,
2750 |   ): T {
2751 |     if (!endToken) {
2752 |       endToken = this._lexer.peek();
2753 |     }
2754 |     if (!startToken) {
2755 |       startToken = endToken;
2756 |     }
2757 |     return Object.assign({}, stump, {
2758 |       type,
2759 |       nodeId: createXmlUiTreeNodeId(),
2760 |       startToken,
2761 |       endToken,
2762 |     });
2763 |   }
2764 | 
2765 |   /**
2766 |    * Creates a statement node
2767 |    * @param type Statement type
2768 |    * @param stump Stump properties
2769 |    * @param startToken The token that starts the statement
2770 |    * @param endToken The token that ends the statement
2771 |    */
2772 |   private createStatementNode<T extends Statement>(
2773 |     type: Statement["type"],
2774 |     stump: any,
2775 |     startToken?: Token,
2776 |     endToken?: Token,
2777 |   ): T {
2778 |     return Object.assign({}, stump, {
2779 |       type,
2780 |       nodeId: createXmlUiTreeNodeId(),
2781 |       startToken,
2782 |       endToken,
2783 |     } as Statement);
2784 |   }
2785 | 
2786 |   /**
2787 |    * Parses a binary literal
2788 |    * @param token Literal token
2789 |    */
2790 |   private parseBinaryLiteral(token: Token): Literal {
2791 |     let value: number | bigint;
2792 |     const bigValue = BigInt(token.text.replace(/[_']/g, ""));
2793 |     if (bigValue < Number.MIN_SAFE_INTEGER || bigValue > Number.MAX_SAFE_INTEGER) {
2794 |       value = bigValue;
2795 |     } else {
2796 |       value = parseInt(token.text.substring(2).replace(/[_']/g, ""), 2);
2797 |     }
2798 |     return this.createExpressionNode<Literal>(
2799 |       T_LITERAL,
2800 |       {
2801 |         value,
2802 |       },
2803 |       token,
2804 |       token,
2805 |     );
2806 |   }
2807 | 
2808 |   /**
2809 |    * Parses a decimal literal
2810 |    * @param token Literal token
2811 |    */
2812 |   private parseDecimalLiteral(token: Token): Literal {
2813 |     let value: number | bigint;
2814 |     const bigValue = BigInt(token.text.replace(/[_']/g, ""));
2815 |     if (bigValue < Number.MIN_SAFE_INTEGER || bigValue > Number.MAX_SAFE_INTEGER) {
2816 |       value = bigValue;
2817 |     } else {
2818 |       value = parseInt(token.text.replace(/[_']/g, ""), 10);
2819 |     }
2820 |     return this.createExpressionNode<Literal>(
2821 |       T_LITERAL,
2822 |       {
2823 |         value,
2824 |       },
2825 |       token,
2826 |       token,
2827 |     );
2828 |   }
2829 | 
2830 |   /**
2831 |    * Parses a hexadecimal literal
2832 |    * @param token Literal token
2833 |    */
2834 |   private parseHexadecimalLiteral(token: Token): Literal {
2835 |     let value: number | bigint;
2836 |     const bigValue = BigInt(token.text.replace(/[_']/g, ""));
2837 |     if (bigValue < Number.MIN_SAFE_INTEGER || bigValue > Number.MAX_SAFE_INTEGER) {
2838 |       value = bigValue;
2839 |     } else {
2840 |       value = parseInt(token.text.substring(2).replace(/[_']/g, ""), 16);
2841 |     }
2842 |     return this.createExpressionNode<Literal>(
2843 |       T_LITERAL,
2844 |       {
2845 |         value,
2846 |       },
2847 |       token,
2848 |       token,
2849 |     );
2850 |   }
2851 | 
2852 |   /**
2853 |    * Parses a real literal
2854 |    * @param token Literal token
2855 |    */
2856 |   private parseRealLiteral(token: Token): Literal {
2857 |     let value = parseFloat(token.text.replace(/[_']/g, ""));
2858 |     return this.createExpressionNode<Literal>(
2859 |       T_LITERAL,
2860 |       {
2861 |         value,
2862 |       },
2863 |       token,
2864 |       token,
2865 |     );
2866 |   }
2867 | 
2868 |   /**
2869 |    * Converts a string token to intrinsic string
2870 |    * @param token Literal token
2871 |    */
2872 |   private parseStringLiteral(token: Token, quoteSurrounded: boolean = true): Literal {
2873 |     let input = token.text;
2874 |     if (quoteSurrounded) {
2875 |       input = token.text.length < 2 ? "" : input.substring(1, input.length - 1);
2876 |     }
2877 |     let result = "";
2878 |     let state: StrParseState = StrParseState.Normal;
2879 |     let collect = 0;
2880 |     for (const ch of input) {
2881 |       switch (state) {
2882 |         case StrParseState.Normal:
2883 |           if (ch === "\\") {
2884 |             state = StrParseState.Backslash;
2885 |           } else {
2886 |             result += ch;
2887 |           }
2888 |           break;
2889 | 
2890 |         case StrParseState.Backslash:
2891 |           state = StrParseState.Normal;
2892 |           switch (ch) {
2893 |             case "b":
2894 |               result += "\b";
2895 |               break;
2896 |             case "f":
2897 |               result += "\f";
2898 |               break;
2899 |             case "n":
2900 |               result += "\n";
2901 |               break;
2902 |             case "r":
2903 |               result += "\r";
2904 |               break;
2905 |             case "t":
2906 |               result += "\t";
2907 |               break;
2908 |             case "v":
2909 |               result += "\v";
2910 |               break;
2911 |             case "S":
2912 |               result += "\xa0";
2913 |               break;
2914 |             case "0":
2915 |               result += String.fromCharCode(0x00);
2916 |               break;
2917 |             case "'":
2918 |               result += "'";
2919 |               break;
2920 |             case '"':
2921 |               result += '"';
2922 |               break;
2923 |             case "\\":
2924 |               result += "\\";
2925 |               break;
2926 |             case "x":
2927 |               state = StrParseState.X;
2928 |               break;
2929 |             case "u":
2930 |               state = StrParseState.UX1;
2931 |               break;
2932 |             default:
2933 |               result += ch;
2934 |               break;
2935 |           }
2936 |           break;
2937 | 
2938 |         case StrParseState.X:
2939 |           if (isHexaDecimal(ch)) {
2940 |             collect = parseInt(ch, 16);
2941 |             state = StrParseState.Xh;
2942 |           } else {
2943 |             result += "x";
2944 |             state = StrParseState.Normal;
2945 |           }
2946 |           break;
2947 | 
2948 |         case StrParseState.Xh:
2949 |           if (isHexaDecimal(ch)) {
2950 |             collect = collect * 0x10 + parseInt(ch, 16);
2951 |             result += String.fromCharCode(collect);
2952 |             state = StrParseState.Normal;
2953 |           } else {
2954 |             result += String.fromCharCode(collect);
2955 |             result += ch;
2956 |             state = StrParseState.Normal;
2957 |           }
2958 |           break;
2959 | 
2960 |         case StrParseState.UX1:
2961 |           if (ch === "{") {
2962 |             state = StrParseState.Ucp1;
2963 |             break;
2964 |           }
2965 |           if (isHexaDecimal(ch)) {
2966 |             collect = parseInt(ch, 16);
2967 |             state = StrParseState.UX2;
2968 |           } else {
2969 |             result += "x";
2970 |             state = StrParseState.Normal;
2971 |           }
2972 |           break;
2973 | 
2974 |         case StrParseState.UX2:
2975 |           if (isHexaDecimal(ch)) {
2976 |             collect = collect * 0x10 + parseInt(ch, 16);
2977 |             state = StrParseState.UX3;
2978 |           } else {
2979 |             result += String.fromCharCode(collect);
2980 |             result += ch;
2981 |             state = StrParseState.Normal;
2982 |           }
2983 |           break;
2984 | 
2985 |         case StrParseState.UX3:
2986 |           if (isHexaDecimal(ch)) {
2987 |             collect = collect * 0x10 + parseInt(ch, 16);
2988 |             state = StrParseState.UX4;
2989 |           } else {
2990 |             result += String.fromCharCode(collect);
2991 |             result += ch;
2992 |             state = StrParseState.Normal;
2993 |           }
2994 |           break;
2995 | 
2996 |         case StrParseState.UX4:
2997 |           if (isHexaDecimal(ch)) {
2998 |             collect = collect * 0x10 + parseInt(ch, 16);
2999 |             result += String.fromCharCode(collect);
3000 |             state = StrParseState.Normal;
3001 |           } else {
3002 |             result += String.fromCharCode(collect);
3003 |             result += ch;
3004 |             state = StrParseState.Normal;
3005 |           }
3006 |           break;
3007 | 
3008 |         case StrParseState.Ucp1:
3009 |           if (isHexaDecimal(ch)) {
3010 |             collect = parseInt(ch, 16);
3011 |             state = StrParseState.Ucp2;
3012 |           } else {
3013 |             result += "x";
3014 |             state = StrParseState.Normal;
3015 |           }
3016 |           break;
3017 | 
3018 |         case StrParseState.Ucp2:
3019 |           if (isHexaDecimal(ch)) {
3020 |             collect = collect * 0x10 + parseInt(ch, 16);
3021 |             state = StrParseState.Ucp3;
3022 |           } else {
3023 |             result += String.fromCharCode(collect);
3024 |             result += ch;
3025 |             state = StrParseState.Normal;
3026 |           }
3027 |           break;
3028 | 
3029 |         case StrParseState.Ucp3:
3030 |           if (isHexaDecimal(ch)) {
3031 |             collect = collect * 0x10 + parseInt(ch, 16);
3032 |             state = StrParseState.Ucp4;
3033 |           } else {
3034 |             result += String.fromCharCode(collect);
3035 |             result += ch;
3036 |             state = StrParseState.Normal;
3037 |           }
3038 |           break;
3039 | 
3040 |         case StrParseState.Ucp4:
3041 |           if (isHexaDecimal(ch)) {
3042 |             collect = collect * 0x10 + parseInt(ch, 16);
3043 |             state = StrParseState.Ucp5;
3044 |           } else {
3045 |             result += String.fromCharCode(collect);
3046 |             result += ch;
3047 |             state = StrParseState.Normal;
3048 |           }
3049 |           break;
3050 | 
3051 |         case StrParseState.Ucp5:
3052 |           if (isHexaDecimal(ch)) {
3053 |             collect = collect * 0x10 + parseInt(ch, 16);
3054 |             state = StrParseState.Ucp6;
3055 |           } else {
3056 |             result += String.fromCharCode(collect);
3057 |             result += ch;
3058 |             state = StrParseState.Normal;
3059 |           }
3060 |           break;
3061 | 
3062 |         case StrParseState.Ucp6:
3063 |           if (isHexaDecimal(ch)) {
3064 |             collect = collect * 0x10 + parseInt(ch, 16);
3065 |             state = StrParseState.UcpTail;
3066 |           } else {
3067 |             result += String.fromCharCode(collect);
3068 |             result += ch;
3069 |             state = StrParseState.Normal;
3070 |           }
3071 |           break;
3072 | 
3073 |         case StrParseState.UcpTail:
3074 |           result += String.fromCharCode(collect);
3075 |           if (ch !== "}") {
3076 |             result += ch;
3077 |           }
3078 |           state = StrParseState.Normal;
3079 |           break;
3080 |       }
3081 |     }
3082 | 
3083 |     // --- Handle the final machine state
3084 |     switch (state) {
3085 |       case StrParseState.Backslash:
3086 |         result += "\\";
3087 |         break;
3088 |       case StrParseState.X:
3089 |         result += "x";
3090 |         break;
3091 |       case StrParseState.Xh:
3092 |         result += String.fromCharCode(collect);
3093 |         break;
3094 |     }
3095 | 
3096 |     // --- Done
3097 |     return this.createExpressionNode<Literal>(
3098 |       T_LITERAL,
3099 |       {
3100 |         value: result,
3101 |       },
3102 |       token,
3103 |       token,
3104 |     );
3105 | 
3106 |     function isHexaDecimal(ch: string): boolean {
3107 |       return (ch >= "0" && ch <= "9") || (ch >= "a" && ch <= "f") || (ch >= "A" && ch <= "F");
3108 |     }
3109 |   }
3110 | 
3111 |   private convertToArrayDestructure(seq: SequenceExpression | ArrayLiteral): Destructure | null {
3112 |     const items = seq.type === T_SEQUENCE_EXPRESSION ? seq.exprs : seq.items;
3113 |     const result = this.createExpressionNode<Destructure>(
3114 |       T_DESTRUCTURE,
3115 |       { aDestr: [] },
3116 |       seq.startToken,
3117 |       seq.endToken,
3118 |     );
3119 | 
3120 |     // --- Convert all items
3121 |     for (const item of items) {
3122 |       let arrayD: ArrayDestructure | undefined;
3123 |       switch (item.type) {
3124 |         case T_NO_ARG_EXPRESSION:
3125 |           arrayD = this.createExpressionNode<ArrayDestructure>(
3126 |             T_ARRAY_DESTRUCTURE,
3127 |             {},
3128 |             item.startToken,
3129 |             item.endToken,
3130 |           );
3131 |           break;
3132 |         case T_IDENTIFIER:
3133 |           arrayD = this.createExpressionNode<ArrayDestructure>(
3134 |             T_ARRAY_DESTRUCTURE,
3135 |             { id: item.name },
3136 |             item.startToken,
3137 |             item.endToken,
3138 |           );
3139 |           break;
3140 |         case T_DESTRUCTURE:
3141 |           result.aDestr!.push(...item.aDestr!);
3142 |           break;
3143 |         case T_ARRAY_DESTRUCTURE:
3144 |           arrayD = item;
3145 |           break;
3146 |         case T_ARRAY_LITERAL: {
3147 |           const destructure = this.convertToArrayDestructure(item);
3148 |           if (destructure) {
3149 |             arrayD = this.createExpressionNode<ArrayDestructure>(
3150 |               T_ARRAY_DESTRUCTURE,
3151 |               {
3152 |                 aDestr: destructure.aDestr,
3153 |               },
3154 |               item.startToken,
3155 |               item.endToken,
3156 |             );
3157 |           }
3158 |           break;
3159 |         }
3160 |         case T_OBJECT_DESTRUCTURE:
3161 |           arrayD = this.createExpressionNode<ArrayDestructure>(
3162 |             T_ARRAY_DESTRUCTURE,
3163 |             {
3164 |               oDestr: item,
3165 |             },
3166 |             item.startToken,
3167 |             item.endToken,
3168 |           );
3169 |           break;
3170 |         case T_OBJECT_LITERAL: {
3171 |           const destructure = this.convertToObjectDestructure(item);
3172 |           if (destructure) {
3173 |             arrayD = this.createExpressionNode<ArrayDestructure>(
3174 |               T_ARRAY_DESTRUCTURE,
3175 |               {
3176 |                 oDestr: destructure.oDestr,
3177 |               },
3178 |               item.startToken,
3179 |               item.endToken,
3180 |             );
3181 |           }
3182 |           break;
3183 |         }
3184 | 
3185 |         default:
3186 |           this.reportError("W017");
3187 |           return null;
3188 |       }
3189 |       if (arrayD) result.aDestr?.push(arrayD);
3190 |     }
3191 | 
3192 |     // --- Done.
3193 |     return result;
3194 |   }
3195 | 
3196 |   private convertToObjectDestructure(objLit: ObjectLiteral): Destructure | null {
3197 |     const result = this.createExpressionNode<Destructure>(
3198 |       T_DESTRUCTURE,
3199 |       { oDestr: [] },
3200 |       objLit.startToken,
3201 |       objLit.endToken,
3202 |     );
3203 | 
3204 |     // --- Convert all items
3205 |     for (const prop of objLit.props) {
3206 |       if (Array.isArray(prop)) {
3207 |       } else {
3208 |         reportError("W018");
3209 |         return null;
3210 |       }
3211 | 
3212 |       const [propKey, propValue] = prop;
3213 |       if (propKey.type !== T_IDENTIFIER) {
3214 |         reportError("W018");
3215 |         return null;
3216 |       }
3217 | 
3218 |       let objD: ObjectDestructure | undefined;
3219 |       switch (propValue.type) {
3220 |         case T_IDENTIFIER:
3221 |           if (propValue.name === propKey.name) {
3222 |             objD = this.createExpressionNode<ObjectDestructure>(
3223 |               T_OBJECT_DESTRUCTURE,
3224 |               { id: propKey.name },
3225 |               propValue.startToken,
3226 |               propValue.endToken,
3227 |             );
3228 |           } else {
3229 |             objD = this.createExpressionNode<ObjectDestructure>(
3230 |               T_OBJECT_DESTRUCTURE,
3231 |               {
3232 |                 id: propKey.name,
3233 |                 alias: propValue.name,
3234 |               },
3235 |               propValue.startToken,
3236 |               propValue.endToken,
3237 |             );
3238 |           }
3239 |           break;
3240 |         case T_ARRAY_DESTRUCTURE: {
3241 |           objD = this.createExpressionNode<ObjectDestructure>(
3242 |             T_OBJECT_DESTRUCTURE,
3243 |             {
3244 |               id: propKey.name,
3245 |               aDestr: propValue,
3246 |             },
3247 |             propKey.startToken,
3248 |             propValue.endToken,
3249 |           );
3250 |           break;
3251 |         }
3252 |         case T_ARRAY_LITERAL: {
3253 |           const destructure = this.convertToArrayDestructure(propValue);
3254 |           if (destructure) {
3255 |             objD = this.createExpressionNode<ObjectDestructure>(
3256 |               T_OBJECT_DESTRUCTURE,
3257 |               {
3258 |                 id: propKey.name,
3259 |                 aDestr: destructure.aDestr,
3260 |               },
3261 |               propKey.startToken,
3262 |               propValue.endToken,
3263 |             );
3264 |           }
3265 |           break;
3266 |         }
3267 |         case T_OBJECT_DESTRUCTURE:
3268 |           objD = propValue;
3269 |           break;
3270 |         case T_OBJECT_LITERAL: {
3271 |           const destructure = this.convertToObjectDestructure(propValue);
3272 |           if (destructure) {
3273 |             objD = this.createExpressionNode<ObjectDestructure>(
3274 |               T_OBJECT_DESTRUCTURE,
3275 |               {
3276 |                 id: propKey.name,
3277 |                 oDestr: destructure.oDestr,
3278 |               },
3279 |               propKey.startToken,
3280 |               propValue.endToken,
3281 |             );
3282 |           }
3283 |           break;
3284 |         }
3285 |         default:
3286 |           this.reportError("W018");
3287 |           return null;
3288 |       }
3289 |       if (objD) result.oDestr?.push(objD);
3290 |     }
3291 | 
3292 |     // --- Done.
3293 |     return result;
3294 |   }
3295 | 
3296 |   /**
3297 |    * Tests if the specified token can be the start of an expression
3298 |    */
3299 |   private isExpressionStart(token: Token): boolean {
3300 |     return tokenTraits[token.type]?.expressionStart ?? false;
3301 |   }
3302 | }
3303 | 
```
Page 172/179FirstPrevNextLast