```
├── .changeset/
├── README.md (100 tokens)
├── config.json (200 tokens)
├── .claude/
├── skills/
├── ripple.md
├── .codex/
├── skills/
├── ripple.md
├── .cursor/
├── environment.json
├── install.sh (300 tokens)
├── rules/
├── project.mdc (1200 tokens)
├── .editorconfig (omitted)
├── .gemini/
├── skills/
├── ripple.md
├── .gitattributes (omitted)
├── .github/
├── ISSUE_TEMPLATE/
├── bug-report.yml (500 tokens)
├── config.yml (100 tokens)
├── feature-request.yml (400 tokens)
├── agents/
├── ripple.agent.md (300 tokens)
├── copilot-instructions.md (1100 tokens)
├── workflows/
├── ci.yml (600 tokens)
├── copilot-setup-steps.yml (200 tokens)
├── livecodes-post-comment.yml (100 tokens)
├── livecodes-preview.yml (100 tokens)
├── pkg.pr.new.yml (700 tokens)
├── publish.yml (300 tokens)
├── release.yml (200 tokens)
├── rulesync.yml (100 tokens)
├── vsix-manual.yml (400 tokens)
├── vsix.yml (700 tokens)
├── .gitignore (200 tokens)
├── .livecodes/
├── playground.json (200 tokens)
├── .prettierignore (omitted)
├── .prettierrc (100 tokens)
├── .rulesync/
├── rules/
├── project.md (1200 tokens)
├── .vscode/
├── launch.json (1000 tokens)
├── settings.json (300 tokens)
├── tasks.json (200 tokens)
├── AGENTS.md (1200 tokens)
├── CLAUDE.md (1100 tokens)
├── CODE_OF_CONDUCT.md (400 tokens)
├── CONTRIBUTING.md (1600 tokens)
├── GEMINI.md (1200 tokens)
├── LICENSE (omitted)
├── README.md (2.3k tokens)
├── assets/
├── Ripple.tmbundle/
├── README.md (200 tokens)
├── Syntaxes/
├── ripple.tmLanguage (71.3k tokens)
├── info.plist
├── ripple-desktop.png
├── ripple-mobile.png
├── benchmarks/
├── package.json
├── tracked-values.js (800 tokens)
├── grammars/
├── textmate/
├── info.plist
├── ripple.tmLanguage.json (57.9k tokens)
├── tree-sitter/
├── .gitignore
├── Cargo.toml (100 tokens)
├── LICENSE (200 tokens)
├── README.md (100 tokens)
├── binding.gyp (100 tokens)
├── bindings/
├── node/
├── binding.cc (100 tokens)
├── grammar.js (5.5k tokens)
├── package.json (200 tokens)
├── queries/
├── brackets.scm (100 tokens)
├── folds.scm (100 tokens)
├── highlights.scm (900 tokens)
├── indents.nvim.scm (200 tokens)
├── indents.scm (100 tokens)
├── indents.zed.scm (200 tokens)
├── injections.scm (300 tokens)
├── locals.scm (200 tokens)
├── outline.scm (100 tokens)
├── textobjects.scm (300 tokens)
├── src/
├── grammar.json (35.1k tokens)
├── node-types.json (15.3k tokens)
├── parser.c (853.8k tokens)
├── scanner.c (900 tokens)
├── tree_sitter/
├── alloc.h (200 tokens)
├── array.h (2.7k tokens)
├── parser.h (1500 tokens)
├── test/
├── corpus/
├── components.txt (800 tokens)
├── control-flow.txt (1900 tokens)
├── javascript.txt (1300 tokens)
├── jsx.txt (1600 tokens)
├── main.txt
├── reactivity.txt (200 tokens)
├── tree-sitter.json (200 tokens)
├── package.json (900 tokens)
├── packages/
├── adapter-bun/
├── CHANGELOG.md (1700 tokens)
├── README.md (500 tokens)
├── package.json (200 tokens)
├── src/
├── index.js (1100 tokens)
├── tests/
├── serve.test.js (2.1k tokens)
├── types.test.js (200 tokens)
├── tsconfig.json
├── tsconfig.typecheck.json
├── types/
├── bun-shim.d.ts (omitted)
├── index.d.ts (omitted)
├── adapter-node/
├── CHANGELOG.md (1700 tokens)
├── README.md (600 tokens)
├── package.json (200 tokens)
├── src/
├── index.js (2.3k tokens)
├── tests/
├── serve.test.js (2.2k tokens)
├── types.test.js (200 tokens)
├── tsconfig.json
├── tsconfig.typecheck.json
├── types/
├── index.d.ts (omitted)
├── adapter-vercel/
├── CHANGELOG.md (1900 tokens)
├── README.md (1200 tokens)
├── package.json (200 tokens)
├── src/
├── adapt.js (2.7k tokens)
├── bin/
├── adapt.js (300 tokens)
├── index.js (100 tokens)
├── tests/
├── adapt.test.js (2.7k tokens)
├── types.test.js (600 tokens)
├── tsconfig.json
├── tsconfig.typecheck.json
├── types/
├── index.d.ts (omitted)
├── adapter/
├── CHANGELOG.md (500 tokens)
├── README.md (200 tokens)
├── package.json (200 tokens)
├── src/
├── index.js (600 tokens)
├── rpc.js (1400 tokens)
├── tests/
├── index.test.js (600 tokens)
├── types.test.js (100 tokens)
├── tsconfig.json
├── tsconfig.typecheck.json
├── types/
├── index.d.ts (omitted)
├── rpc.d.ts (omitted)
├── bun-plugin-preact/
├── CHANGELOG.md (1100 tokens)
├── README.md (200 tokens)
├── package.json (200 tokens)
├── src/
├── index.js (800 tokens)
├── tests/
├── basic.test.js (1200 tokens)
├── tsconfig.json (100 tokens)
├── tsconfig.typecheck.json
├── types/
├── index.d.ts (omitted)
├── bun-plugin-react/
├── CHANGELOG.md (1100 tokens)
├── README.md (200 tokens)
├── package.json (200 tokens)
├── src/
├── index.js (700 tokens)
├── tests/
├── basic.test.js (1200 tokens)
├── tsconfig.json (100 tokens)
├── tsconfig.typecheck.json
├── types/
├── index.d.ts (omitted)
├── bun-plugin-solid/
├── CHANGELOG.md (200 tokens)
├── README.md (200 tokens)
├── package.json (200 tokens)
├── src/
├── index.js (700 tokens)
├── tests/
├── basic.test.js (1100 tokens)
├── tsconfig.json (100 tokens)
├── tsconfig.typecheck.json
├── types/
├── index.d.ts (omitted)
├── bun-plugin-vue/
├── CHANGELOG.md (700 tokens)
├── README.md (200 tokens)
├── package.json (200 tokens)
├── src/
├── index.js (1100 tokens)
├── tests/
├── basic.test.js (1700 tokens)
├── tsconfig.json (100 tokens)
├── tsconfig.typecheck.json
├── types/
├── index.d.ts (omitted)
├── cli/
├── CHANGELOG.md (600 tokens)
├── LICENSE (200 tokens)
├── README.md (400 tokens)
├── package.json (300 tokens)
├── src/
├── commands/
├── create.js (1100 tokens)
├── constants.js (100 tokens)
├── index.js (400 tokens)
├── lib/
├── is-folder-empty.js (500 tokens)
├── package-manager.js (300 tokens)
├── project-creator.js (2k tokens)
├── prompts.js (800 tokens)
├── templates.js (700 tokens)
├── validation.js (700 tokens)
├── tests/
├── integration/
├── cli.test.js (1700 tokens)
├── project-creator.test.js (2.2k tokens)
├── unit/
├── prompts.test.js (1700 tokens)
├── templates.test.js (900 tokens)
├── validation.test.js (1200 tokens)
├── tsconfig.json
├── tsdown.config.js (100 tokens)
├── vitest.config.js (100 tokens)
├── compat-react/
├── CHANGELOG.md (2.7k tokens)
├── LICENSE (200 tokens)
├── package.json (200 tokens)
├── src/
├── index.js (2.3k tokens)
├── tests/
├── client.d.ts (omitted)
├── index.test.tsrx (4.3k tokens)
├── setup.js (300 tokens)
├── tsconfig.json (100 tokens)
├── tsconfig.typecheck.json
├── types/
├── index.d.ts (omitted)
├── create-ripple/
├── CHANGELOG.md (1600 tokens)
├── README.md (300 tokens)
├── package.json (200 tokens)
├── src/
├── index.js
├── tsconfig.json
├── tsdown.config.js (100 tokens)
├── eslint-parser/
├── .npmignore
├── CHANGELOG.md (1700 tokens)
├── README.md (500 tokens)
├── package.json (300 tokens)
├── src/
├── index.ts (1000 tokens)
├── tsconfig.json (100 tokens)
├── tsdown.config.js (100 tokens)
├── eslint-plugin/
├── .npmignore
├── CHANGELOG.md (2k tokens)
├── README.md (1100 tokens)
├── package.json (300 tokens)
├── src/
├── index.ts (500 tokens)
├── rules/
├── control-flow-jsx.ts (500 tokens)
├── no-lazy-destructuring-in-modules.ts (200 tokens)
├── no-module-scope-track.ts (300 tokens)
├── no-return-in-component.ts (300 tokens)
├── prefer-oninput.ts (400 tokens)
├── valid-for-of-key.ts (700 tokens)
├── tests/
├── configs.test.ts (100 tokens)
├── rules/
├── control-flow-jsx.test.ts (600 tokens)
├── no-lazy-destructuring-in-modules.test.ts (600 tokens)
├── no-module-scope-track.test.ts (300 tokens)
├── no-return-in-component.test.ts (100 tokens)
├── prefer-oninput.test.ts (200 tokens)
├── valid-for-of-key.test.ts (400 tokens)
├── tsconfig.json (100 tokens)
├── tsdown.config.js (100 tokens)
├── vitest.config.ts
├── intellij-plugin/
├── .gitignore (100 tokens)
├── README.md (200 tokens)
├── build.gradle.kts (200 tokens)
├── gradle.properties (100 tokens)
├── gradle/
├── wrapper/
├── gradle-wrapper.jar
├── gradle-wrapper.properties
├── gradlew (1600 tokens)
├── gradlew.bat (500 tokens)
├── package.json
├── settings.gradle.kts
├── src/
├── main/
├── kotlin/
├── com/
├── ripple_ts/
├── intellij_plugin/
├── RippleCommenter.kt (100 tokens)
├── RippleFileType.kt (100 tokens)
├── RippleIcons.kt
├── RippleLanguage.kt
├── RippleLanguageServer.kt (1700 tokens)
├── RippleLspServerDescriptor.kt (200 tokens)
├── RippleLspServerSupportProvider.kt (100 tokens)
├── RippleTextMateBundleProvider.kt (800 tokens)
├── resources/
├── META-INF/
├── plugin.xml (500 tokens)
├── pluginIcon.svg (200 tokens)
├── ripple-lsp.xml
├── icons/
├── ripple.png
├── ripple@2x.png
├── lsp-version.txt
├── language-server/
├── CHANGELOG.md (4.8k tokens)
├── LICENSE (200 tokens)
├── README.md (700 tokens)
├── package.json (200 tokens)
├── src/
├── autoInsertPlugin.js (900 tokens)
├── compileErrorDiagnosticPlugin.js (900 tokens)
├── completionPlugin.js (3.4k tokens)
├── definitionPlugin.js (1400 tokens)
├── documentHighlightPlugin.js (700 tokens)
├── hoverPlugin.js (800 tokens)
├── language-server.js
├── server.js (1000 tokens)
├── typescriptDiagnosticPlugin.js (800 tokens)
├── typescriptService.js (400 tokens)
├── utils.js (1000 tokens)
├── tsconfig.json (100 tokens)
├── tsconfig.typecheck.json
├── tsdown.config.js (200 tokens)
├── nvim-plugin/
├── LICENSE (200 tokens)
├── README.md (200 tokens)
├── lua/
├── ripple/
├── init.lua
├── lsp.lua (900 tokens)
├── treesitter.lua (200 tokens)
├── package.json (100 tokens)
├── plugin/
├── ripple.lua
├── queries/
├── ripple/
├── brackets.scm (100 tokens)
├── folds.scm (100 tokens)
├── highlights.scm (900 tokens)
├── indents.scm (200 tokens)
├── injections.scm (300 tokens)
├── locals.scm (200 tokens)
├── outline.scm (100 tokens)
├── textobjects.scm (300 tokens)
├── prettier-plugin/
├── CHANGELOG.md (4.9k tokens)
├── LICENSE (200 tokens)
├── README.md (100 tokens)
├── package.json (200 tokens)
├── src/
├── index.js (39.7k tokens)
├── index.test.js (30k tokens)
├── tsconfig.json (100 tokens)
├── tsconfig.typecheck.json
├── vitest-extensions.d.ts (omitted)
├── ripple/
├── CHANGELOG.md (8k tokens)
├── README.md (100 tokens)
├── package.json (500 tokens)
├── shims/
├── rollup-estree-types.d.ts (omitted)
├── src/
├── compiler/
├── index.js (100 tokens)
├── types/
├── import.d.ts (omitted)
├── constants.js (100 tokens)
├── helpers.d.ts (omitted)
├── html-tree-validation.js (1500 tokens)
├── jsx-runtime.d.ts (omitted)
├── jsx-runtime.js (300 tokens)
├── runtime/
├── array.js (500 tokens)
├── create-subscriber.js (200 tokens)
├── date.js (400 tokens)
├── element.js (100 tokens)
├── index-client.js (900 tokens)
├── index-server.js (500 tokens)
├── internal/
├── client/
├── bindings.js (3.8k tokens)
├── blocks.js (2k tokens)
├── compat.js (200 tokens)
├── composite.js (600 tokens)
├── constants.js (400 tokens)
├── context.js (300 tokens)
├── css.js (300 tokens)
├── events.js (2.2k tokens)
├── expression.js (1500 tokens)
├── for.js (3.7k tokens)
├── head.js (400 tokens)
├── hmr.js (500 tokens)
├── html.js (700 tokens)
├── hydration.js (400 tokens)
├── if.js (200 tokens)
├── index.js (500 tokens)
├── operations.js (800 tokens)
├── portal.js (500 tokens)
├── render.js (2k tokens)
├── rpc.js (200 tokens)
├── runtime.js (8k tokens)
├── script.js (100 tokens)
├── switch.js (300 tokens)
├── template.js (1400 tokens)
├── try.js (2.1k tokens)
├── types.d.ts (omitted)
├── utils.js (200 tokens)
├── server/
├── blocks.js (900 tokens)
├── constants.js (100 tokens)
├── context.js (300 tokens)
├── css-registry.js (200 tokens)
├── index.js (8.4k tokens)
├── rpc.js (100 tokens)
├── types.d.ts (omitted)
├── map.js (700 tokens)
├── media-query.js (300 tokens)
├── object.js (100 tokens)
├── proxy.js (1800 tokens)
├── reactive-value.js (200 tokens)
├── set.js (800 tokens)
├── url-search-params.js (600 tokens)
├── url.js (700 tokens)
├── server/
├── index.js (100 tokens)
├── utils/
├── async.js (200 tokens)
├── track-async-serialization.js (100 tokens)
├── tests/
├── client.d.ts (omitted)
├── client/
├── __snapshots__/
├── computed-properties.test.rsrx.snap
├── computed-properties.test.tsrx.snap
├── for.test.rsrx.snap
├── for.test.tsrx.snap
├── html.test.rsrx.snap
├── html.test.tsrx.snap
├── _etc.test.tsrx
├── array/
├── array.copy-within.test.tsrx (900 tokens)
├── array.derived.test.tsrx (3.2k tokens)
├── array.iteration.test.tsrx (700 tokens)
├── array.mutations.test.tsrx (2.5k tokens)
├── array.static.test.tsrx (1300 tokens)
├── array.to-methods.test.tsrx (600 tokens)
├── async-suspend.test.tsrx (4.1k tokens)
├── basic/
├── __snapshots__/
├── basic.attributes.test.rsrx.snap
├── basic.attributes.test.tsrx.snap
├── basic.rendering.test.rsrx.snap
├── basic.rendering.test.tsrx.snap
├── basic.attributes.test.tsrx (5k tokens)
├── basic.collections.test.tsrx (500 tokens)
├── basic.components.test.tsrx (2.9k tokens)
├── basic.errors.test.tsrx (1400 tokens)
├── basic.events.test.tsrx (1400 tokens)
├── basic.get-set.test.tsrx (1100 tokens)
├── basic.hmr.test.tsrx (500 tokens)
├── basic.reactivity.test.tsrx (1700 tokens)
├── basic.rendering.test.tsrx (1700 tokens)
├── basic.styling.test.tsrx (300 tokens)
├── basic.utilities.test.tsrx (100 tokens)
├── boundaries.test.tsrx (500 tokens)
├── capture-error.js
├── compiler/
├── __snapshots__/
├── compiler.assignments.test.rsrx.snap
├── compiler.assignments.test.tsrx.snap
├── compiler.typescript.test.rsrx.snap
├── compiler.typescript.test.tsrx.snap
├── compiler.assignments.test.tsrx (600 tokens)
├── compiler.attributes.test.tsrx (600 tokens)
├── compiler.basic.test.tsrx (6.1k tokens)
├── compiler.regex.test.tsrx (700 tokens)
├── compiler.tracked-access.test.tsrx (1200 tokens)
├── compiler.try-in-function.test.tsrx (900 tokens)
├── compiler.typescript.test.tsrx (300 tokens)
├── composite/
├── __snapshots__/
├── composite.render.test.rsrx.snap
├── composite.render.test.tsrx.snap
├── composite.dynamic-components.test.tsrx (400 tokens)
├── composite.generics.test.tsrx (1000 tokens)
├── composite.props.test.tsrx (900 tokens)
├── composite.reactivity.test.tsrx (1500 tokens)
├── composite.render.test.tsrx (1000 tokens)
├── computed-properties.test.tsrx (200 tokens)
├── context.test.tsrx (200 tokens)
├── css/
├── global-additional-cases.test.tsrx (3k tokens)
├── global-advanced-selectors.test.tsrx (900 tokens)
├── global-at-rules.test.tsrx (500 tokens)
├── global-basic.test.tsrx (600 tokens)
├── global-classes-ids.test.tsrx (700 tokens)
├── global-combinators.test.tsrx (500 tokens)
├── global-complex-nesting.test.tsrx (800 tokens)
├── global-edge-cases.test.tsrx (800 tokens)
├── global-keyframes.test.tsrx (700 tokens)
├── global-nested.test.tsrx (500 tokens)
├── global-pseudo.test.tsrx (600 tokens)
├── global-scoping.test.tsrx (900 tokens)
├── style-identifier.test.tsrx (2000 tokens)
├── date.test.tsrx (2000 tokens)
├── dynamic-elements.test.tsrx (4.2k tokens)
├── events.test.tsrx (3.5k tokens)
├── for.test.tsrx (1500 tokens)
├── function-overload-import.tsrx
├── function-overload.test.tsrx (200 tokens)
├── head.test.tsrx (800 tokens)
├── html.test.tsrx (300 tokens)
├── input-value.test.tsrx (20.4k tokens)
├── lazy-destructuring.test.tsrx (1800 tokens)
├── map.test.tsrx (1200 tokens)
├── media-query.test.tsrx (600 tokens)
├── object.test.tsrx (900 tokens)
├── portal.test.tsrx (900 tokens)
├── ref.test.tsrx (2.5k tokens)
├── return.test.tsrx (12.4k tokens)
├── set.test.tsrx (900 tokens)
├── svg.test.tsrx (2.8k tokens)
├── switch.test.tsrx (2.1k tokens)
├── track-async-hydration.test.tsrx (300 tokens)
├── try.test.tsrx (10k tokens)
├── tsconfig.json
├── tsx.test.tsrx (3.4k tokens)
├── typescript-generics.test.tsrx (800 tokens)
├── url-search-params/
├── url-search-params.derived.test.tsrx (500 tokens)
├── url-search-params.initialization.test.tsrx (400 tokens)
├── url-search-params.iteration.test.tsrx (900 tokens)
├── url-search-params.mutation.test.tsrx (2.2k tokens)
├── url-search-params.retrieval.test.tsrx (900 tokens)
├── url-search-params.serialization.test.tsrx (300 tokens)
├── url-search-params.tracked-url.test.tsrx (400 tokens)
├── url/
├── url.derived.test.tsrx (600 tokens)
├── url.parsing.test.tsrx (1100 tokens)
├── url.partial-removal.test.tsrx (1200 tokens)
├── url.reactivity.test.tsrx (3.1k tokens)
├── url.serialization.test.tsrx (300 tokens)
├── common.d.ts (omitted)
├── hydration.d.ts (omitted)
├── hydration/
├── basic.test.js (1200 tokens)
├── build-components.js (500 tokens)
├── compiled/
├── client/
├── basic.js (2k tokens)
├── composite.js (800 tokens)
├── events.js (1000 tokens)
├── for.js (5.9k tokens)
├── head.js (1000 tokens)
├── hmr.js (300 tokens)
├── html-in-template.js (300 tokens)
├── html.js (8.4k tokens)
├── if-children.js (2k tokens)
├── if.js (1300 tokens)
├── mixed-control-flow.js (2k tokens)
├── nested-control-flow.js (5.3k tokens)
├── portal.js (700 tokens)
├── reactivity.js (600 tokens)
├── return.js (9.1k tokens)
├── switch.js (1500 tokens)
├── track-async-serialization.js (1800 tokens)
├── try.js (500 tokens)
├── server/
├── basic.js (2.3k tokens)
├── composite.js (700 tokens)
├── events.js (900 tokens)
├── for.js (4.8k tokens)
├── head.js (1200 tokens)
├── hmr.js (300 tokens)
├── html-in-template.js (400 tokens)
├── html.js (9.2k tokens)
├── if-children.js (2.5k tokens)
├── if.js (1100 tokens)
├── mixed-control-flow.js (1400 tokens)
├── nested-control-flow.js (3.2k tokens)
├── portal.js (900 tokens)
├── reactivity.js (600 tokens)
├── return.js (7.3k tokens)
├── switch.js (1100 tokens)
├── track-async-serialization.js (1800 tokens)
├── try.js (500 tokens)
├── components/
├── basic.tsrx (700 tokens)
├── composite.tsrx (200 tokens)
├── events.tsrx (400 tokens)
├── for.tsrx (2.1k tokens)
├── head.tsrx (400 tokens)
├── hmr.tsrx (200 tokens)
├── html-in-template.tsrx (100 tokens)
├── html.tsrx (2.7k tokens)
├── if-children.tsrx (1100 tokens)
├── if.tsrx (400 tokens)
├── mixed-control-flow.tsrx (500 tokens)
├── nested-control-flow.tsrx (1300 tokens)
├── portal.tsrx (300 tokens)
├── reactivity.tsrx (200 tokens)
├── return.tsrx (2.1k tokens)
├── switch.tsrx (500 tokens)
├── track-async-serialization.tsrx (500 tokens)
├── try.tsrx (100 tokens)
├── composite.test.js (400 tokens)
├── events.test.js (700 tokens)
├── for.test.js (3.4k tokens)
├── head.test.js (800 tokens)
├── hmr.test.js (600 tokens)
├── html-in-template.test.js (400 tokens)
├── html.test.js (2000 tokens)
├── if-children.test.js (2k tokens)
├── if.test.js (700 tokens)
├── mixed-control-flow.test.js (600 tokens)
├── nested-control-flow.test.js (1700 tokens)
├── portal.test.js (500 tokens)
├── reactivity.test.js (300 tokens)
├── return.test.js (4.5k tokens)
├── switch.test.js (900 tokens)
├── track-async-serialization.test.js (1000 tokens)
├── try.test.js (500 tokens)
├── tsconfig.json
├── server.d.ts (omitted)
├── server/
├── __snapshots__/
├── compiler.test.tsrx.snap
├── await.test.tsrx (300 tokens)
├── basic.attributes.test.tsrx (2.9k tokens)
├── basic.components.test.tsrx (2.2k tokens)
├── basic.test.tsrx (1100 tokens)
├── compiler.test.tsrx (1700 tokens)
├── composite.props.test.tsrx (800 tokens)
├── composite.test.tsrx (1000 tokens)
├── context.test.tsrx (100 tokens)
├── dynamic-elements.test.tsrx (2.3k tokens)
├── for.test.tsrx (800 tokens)
├── head.test.tsrx (500 tokens)
├── html-nesting-validation.test.tsrx (1400 tokens)
├── if.test.tsrx (400 tokens)
├── lazy-destructuring.test.tsrx (2.8k tokens)
├── return.test.tsrx (5.7k tokens)
├── streaming-ssr.test.tsrx (600 tokens)
├── style-identifier.test.tsrx (1600 tokens)
├── switch.test.tsrx (500 tokens)
├── track-async-serialization.test.tsrx (1100 tokens)
├── try.test.tsrx (2.3k tokens)
├── tsconfig.json
├── setup-client.js (200 tokens)
├── setup-hydration.js (500 tokens)
├── setup-server.js (300 tokens)
├── utils/
├── compiler-compat-config.test.js (200 tokens)
├── runtime-imports.test.js (200 tokens)
├── vite-plugin-config.test.js (500 tokens)
├── vite-plugin-hmr.test.js (600 tokens)
├── tsconfig.json (100 tokens)
├── tsconfig.typecheck.json
├── types/
├── compiler.d.ts (omitted)
├── index.d.ts (omitted)
├── server.d.ts (omitted)
├── rollup-plugin/
├── CHANGELOG.md (1600 tokens)
├── LICENSE (200 tokens)
├── index.js (300 tokens)
├── package.json (200 tokens)
├── tsconfig.json
├── tsconfig.typecheck.json
├── rspack-plugin-preact/
├── CHANGELOG.md (1200 tokens)
├── package.json (200 tokens)
├── src/
├── css-loader.js (100 tokens)
├── index.js (500 tokens)
├── js-loader.js (200 tokens)
├── tests/
├── basic.test.js (1000 tokens)
├── tsconfig.json
├── types/
├── index.d.ts (omitted)
├── rspack-plugin-react/
├── CHANGELOG.md (1800 tokens)
├── package.json (200 tokens)
├── src/
├── css-loader.js (100 tokens)
├── index.js (500 tokens)
├── js-loader.js (200 tokens)
├── tests/
├── basic.test.js (900 tokens)
├── tsconfig.json
├── types/
├── index.d.ts (omitted)
├── rspack-core-shim.d.ts (omitted)
├── rspack-plugin-solid/
├── CHANGELOG.md (1000 tokens)
├── package.json (200 tokens)
├── src/
├── css-loader.js (100 tokens)
├── index.js (500 tokens)
├── js-loader.js (200 tokens)
├── tests/
├── basic.test.js (1000 tokens)
├── tsconfig.json
├── types/
├── index.d.ts (omitted)
├── rspack-plugin-vue/
├── CHANGELOG.md (1200 tokens)
├── package.json (200 tokens)
├── src/
├── css-loader.js (100 tokens)
├── index.js (500 tokens)
├── interop-loader.js
├── js-loader.js (200 tokens)
├── vapor-loader.js (600 tokens)
├── tests/
├── basic.test.js (1400 tokens)
├── tsconfig.json
├── types/
├── index.d.ts (omitted)
├── sublime-text-plugin/
├── .gitignore
├── package.json (100 tokens)
├── scripts/
├── build.js (100 tokens)
├── src/
├── .python-version
├── Ripple.sublime-settings
├── dependencies.json
├── language-server/
├── package-lock.json (3.2k tokens)
├── package.json
├── plugin.py (900 tokens)
├── tree-sitter/
├── build/
├── Makefile (2.8k tokens)
├── Release/
├── .deps/
├── Release/
├── obj.target/
├── tree_sitter_ripple_binding/
├── bindings/
├── node/
├── binding.o.d (500 tokens)
├── src/
├── parser.o.d (300 tokens)
├── scanner.o.d (300 tokens)
├── tree_sitter_ripple_binding.node.d (100 tokens)
├── obj.target/
├── tree_sitter_ripple_binding/
├── bindings/
├── node/
├── binding.o
├── src/
├── parser.o
├── scanner.o
├── tree_sitter_ripple_binding.node
├── binding.Makefile
├── config.gypi (4.1k tokens)
├── gyp-mac-tool (6.1k tokens)
├── tree_sitter_ripple_binding.target.mk (1200 tokens)
├── tsrx-mcp/
├── CHANGELOG.md (2.1k tokens)
├── README.md (800 tokens)
├── package.json (200 tokens)
├── scripts/
├── generate-docs-index.js (2.3k tokens)
├── src/
├── analyze.js (1400 tokens)
├── authoring.js (3.2k tokens)
├── compile.js (1000 tokens)
├── docs.js (200 tokens)
├── format.js (700 tokens)
├── generated/
├── docs.js (1900 tokens)
├── http.js (600 tokens)
├── index.js (200 tokens)
├── inspect.js (1300 tokens)
├── schemas.js (800 tokens)
├── server.js (4.5k tokens)
├── stdio.js (100 tokens)
├── target.js (1100 tokens)
├── validate.js (500 tokens)
├── tests/
├── authoring.test.js (500 tokens)
├── compile.test.js (4.5k tokens)
├── docs.test.js (300 tokens)
├── fixtures/
├── preact-project/
├── package.json
├── react-project/
├── package.json (100 tokens)
├── src/
├── Valid.tsrx
├── ripple-project/
├── package.json
├── solid-project/
├── package.json
├── vue-project/
├── package.json
├── http.test.js (1100 tokens)
├── package.test.js (400 tokens)
├── stdio.test.js (1900 tokens)
├── tsconfig.json (100 tokens)
├── tsconfig.typecheck.json
├── tsrx-preact/
├── CHANGELOG.md (6.6k tokens)
├── package.json (200 tokens)
├── src/
├── error-boundary.js (200 tokens)
├── index.js (500 tokens)
├── ref.js
├── runtime/
├── iterable.js
├── transform.js (300 tokens)
├── tests/
├── basic.test.js (2.1k tokens)
├── tsconfig.json
├── types/
├── error-boundary.d.ts (omitted)
├── index.d.ts (omitted)
├── ref.d.ts (omitted)
├── runtime/
├── iterable.d.ts (omitted)
├── tsrx-react/
├── CHANGELOG.md (7.8k tokens)
├── package.json (200 tokens)
├── src/
├── error-boundary.js (200 tokens)
├── index.js (500 tokens)
├── ref.js
├── runtime/
├── iterable.js
├── transform.js (200 tokens)
├── tests/
├── basic.test.js (12.2k tokens)
├── tsconfig.json
├── types/
├── error-boundary.d.ts (omitted)
├── index.d.ts (omitted)
├── ref.d.ts (omitted)
├── runtime/
├── iterable.d.ts (omitted)
├── tsrx-ripple/
├── CHANGELOG.md (4.5k tokens)
├── package.json (200 tokens)
├── src/
├── analyze/
├── index.js (15k tokens)
├── helpers.d.ts (omitted)
├── index.js (600 tokens)
├── transform/
├── client/
├── index.js (34.1k tokens)
├── server/
├── index.js (11.2k tokens)
├── utils.js (5.9k tokens)
├── tests/
├── basic.test.js (1800 tokens)
├── tsconfig.json (100 tokens)
├── types/
├── index.d.ts (omitted)
├── rpc.d.ts (omitted)
├── tsrx-solid/
├── CHANGELOG.md (7k tokens)
├── package.json (200 tokens)
├── src/
├── index.js (500 tokens)
├── ref.js
├── transform.js (12.6k tokens)
├── tests/
├── basic.test.js (5.4k tokens)
├── tsconfig.json
├── types/
├── index.d.ts (omitted)
├── ref.d.ts (omitted)
├── tsrx-vue/
├── CHANGELOG.md (4.7k tokens)
├── package.json (200 tokens)
├── src/
├── error-boundary.js (1000 tokens)
├── index.js (500 tokens)
├── interop.js (500 tokens)
├── ref.js
├── transform.js (6.9k tokens)
├── tests/
├── __snapshots__/
├── basic.test.js.snap
├── basic.test.js (6.4k tokens)
├── tsconfig.json
├── types/
├── error-boundary.d.ts (omitted)
├── index.d.ts (omitted)
├── interop.d.ts (omitted)
├── ref.d.ts (omitted)
├── tsrx/
├── CHANGELOG.md (8k tokens)
├── README.md (600 tokens)
├── package.json (600 tokens)
├── src/
├── analyze/
├── css-analyze.js (1000 tokens)
├── prune.js (6.5k tokens)
├── validation.js (1900 tokens)
├── comment-utils.js (500 tokens)
├── constants.js (100 tokens)
├── diagnostics.js (100 tokens)
├── errors.js (400 tokens)
├── helpers.d.ts (omitted)
├── identifier-utils.js (400 tokens)
├── index.js (1800 tokens)
├── parse/
├── index.js (5.7k tokens)
├── parse-module.js (100 tokens)
├── style.js (3.1k tokens)
├── plugin.js (21.6k tokens)
├── runtime/
├── events.js
├── hash.js
├── html.js
├── iterable.js (500 tokens)
├── language-helpers.js (400 tokens)
├── ref.js (1100 tokens)
├── scope.js (2.5k tokens)
├── source-map-utils.js (2.3k tokens)
├── transform/
├── await.js (300 tokens)
├── jsx-hoist.js (700 tokens)
├── jsx-interleave.js (600 tokens)
├── jsx/
├── ast-builders.js (2.9k tokens)
├── helpers.js (1700 tokens)
├── index.js (34.5k tokens)
├── lazy.js (6.4k tokens)
├── scoping.js (1500 tokens)
├── segments.js (14.7k tokens)
├── stylesheet.js (3.1k tokens)
├── utils.js (100 tokens)
├── utils/
├── ast.js (2000 tokens)
├── builders.js (7k tokens)
├── dom.js (500 tokens)
├── escaping.js (200 tokens)
├── events.js (600 tokens)
├── hashing.js (300 tokens)
├── normalize_css_property_name.js (100 tokens)
├── patterns.js (200 tokens)
├── sanitize_template_string.js
├── tests/
├── shared/
├── compile.js (22.5k tokens)
├── runtime/
├── switch-fallthrough-components.tsrx (400 tokens)
├── switch-fallthrough.js (1200 tokens)
├── source-mappings.js (9.3k tokens)
├── utils/
├── escaping.test.js (600 tokens)
├── events.test.js (1200 tokens)
├── normalize_css_property_name.test.js (400 tokens)
├── patterns.test.js (3.5k tokens)
├── ref-runtime.test.js (600 tokens)
├── ref-types.test.js (300 tokens)
├── sanitize_template_string.test.js (400 tokens)
├── tsconfig.json (100 tokens)
├── types/
├── acorn.d.ts (omitted)
├── estree-jsx.d.ts (omitted)
├── estree.d.ts (omitted)
├── index.d.ts (omitted)
├── jsx-platform.d.ts (omitted)
├── parse.d.ts (omitted)
├── runtime/
├── events.d.ts (omitted)
├── hash.d.ts (omitted)
├── html.d.ts (omitted)
├── iterable.d.ts (omitted)
├── language-helpers.d.ts (omitted)
├── ref.d.ts (omitted)
├── turbopack-plugin-react/
├── CHANGELOG.md (1700 tokens)
├── package.json (200 tokens)
├── src/
├── css-loader.js (100 tokens)
├── index.js (600 tokens)
├── loader.js (600 tokens)
├── tests/
├── basic.test.js (1300 tokens)
├── tsconfig.json
├── types/
├── index.d.ts (omitted)
├── typescript-plugin/
├── CHANGELOG.md (4.7k tokens)
├── LICENSE (200 tokens)
├── README.md (300 tokens)
├── package.json (300 tokens)
├── src/
├── index.js (100 tokens)
├── language.js (5.9k tokens)
├── tsc.js (100 tokens)
├── utils.js (300 tokens)
├── tests/
├── compiler-resolution.test.js (1700 tokens)
├── fixtures/
├── workspaces/
├── both-react/
├── package.json
├── both/
├── package.json
├── react-only/
├── package.json
├── ripple-only/
├── package.json
├── plugin-integration.test.js (1100 tokens)
├── workspace-fixtures.js (1400 tokens)
├── tsconfig.json (100 tokens)
├── tsconfig.typecheck.json
├── tsdown.config.js (200 tokens)
├── vite-plugin-preact/
├── CHANGELOG.md (1500 tokens)
├── package.json (200 tokens)
├── src/
├── index.js (600 tokens)
├── tests/
├── basic.test.js (300 tokens)
├── runtime.test.tsrx (2.6k tokens)
├── setup.js (100 tokens)
├── tsconfig.json (100 tokens)
├── types.d.ts (omitted)
├── tsconfig.json
├── types/
├── index.d.ts (omitted)
├── vite-plugin-react/
├── CHANGELOG.md (1900 tokens)
├── package.json (200 tokens)
├── src/
├── index.js (500 tokens)
├── tests/
├── basic.test.js (300 tokens)
├── fixtures/
├── react-aria/
├── App.tsrx (300 tokens)
├── AriaActionButton.tsx (200 tokens)
├── runtime.test.tsrx (200 tokens)
├── tsconfig.json
├── typecheck.test.js (300 tokens)
├── types.ts (100 tokens)
├── react-query/
├── App.tsrx (200 tokens)
├── QueryFixtureShell.tsx (600 tokens)
├── runtime.test.tsrx (600 tokens)
├── tsconfig.json
├── typecheck.test.js (300 tokens)
├── types.ts (100 tokens)
├── react-router/
├── App.tsrx (100 tokens)
├── RouterFixtureShell.tsx (300 tokens)
├── runtime.test.tsrx (200 tokens)
├── tsconfig.json
├── typecheck.test.js (300 tokens)
├── types.ts
├── runtime.test.tsrx (10.1k tokens)
├── setup.js (200 tokens)
├── tsconfig.json (100 tokens)
├── types.d.ts (omitted)
├── tsconfig.json
├── types/
├── index.d.ts (omitted)
├── vite-plugin-solid/
├── CHANGELOG.md (2000 tokens)
├── package.json (200 tokens)
├── src/
├── index.js (1200 tokens)
├── tests/
├── plugin.test.js (500 tokens)
├── runtime.test.tsrx (8.7k tokens)
├── setup.js (400 tokens)
├── tsconfig.json (100 tokens)
├── types.d.ts (omitted)
├── tsconfig.json
├── types/
├── index.d.ts (omitted)
├── vite-plugin-vue/
├── CHANGELOG.md (1300 tokens)
├── package.json (200 tokens)
├── src/
├── index.js (1300 tokens)
├── interop.js (200 tokens)
├── tests/
├── runtime.test.tsrx (8.3k tokens)
├── setup.js (200 tokens)
├── tsconfig.json (100 tokens)
├── types.d.ts (omitted)
├── vue-jsx-vapor-jsx-runtime-shim.js (100 tokens)
├── vue-jsx-vapor-shim.js (1900 tokens)
├── vue-runtime-shim.js
├── tsconfig.json
├── types/
├── index.d.ts (omitted)
├── vite-plugin/
├── CHANGELOG.md (3k tokens)
├── LICENSE (200 tokens)
├── package.json (200 tokens)
├── src/
├── bin/
├── preview.js (200 tokens)
├── constants.js
├── index.js (9.1k tokens)
├── load-config.js (1500 tokens)
├── routes.js (300 tokens)
├── server/
├── component-wrappers.js (300 tokens)
├── middleware.js (700 tokens)
├── production.js (1600 tokens)
├── render-route.js (1100 tokens)
├── router.js (600 tokens)
├── server-route.js (200 tokens)
├── virtual-entry.js (1400 tokens)
├── tests/
├── configure-server.test.js (1600 tokens)
├── render-route-props.test.js (800 tokens)
├── tsconfig.json (100 tokens)
├── tsconfig.typecheck.json
├── types/
├── index.d.ts (omitted)
├── production.d.ts (omitted)
├── vscode-plugin/
├── .gitignore
├── .vscodeignore
├── CHANGELOG.md (5.4k tokens)
├── LICENSE (200 tokens)
├── README.md
├── icons/
├── image.png
├── logo.png
├── language-configuration.json (900 tokens)
├── package.json (1200 tokens)
├── scripts/
├── repack-vsix.js (700 tokens)
├── src/
├── extension.js (4.9k tokens)
├── server.js
├── tsconfig.json (100 tokens)
├── tsconfig.typecheck.json
├── tsdown.config.js (500 tokens)
├── zed-plugin/
├── .gitignore
├── Cargo.lock (omitted)
├── Cargo.toml
├── DEVELOPMENT.md (700 tokens)
├── LICENSE (200 tokens)
├── README.md (300 tokens)
├── extension.toml (100 tokens)
├── languages/
├── tsrx/
├── brackets.scm (100 tokens)
├── config.toml (100 tokens)
├── folds.scm (100 tokens)
├── highlights.scm (900 tokens)
├── indents.scm (200 tokens)
├── injections.scm (300 tokens)
├── locals.scm (200 tokens)
├── outline.scm (100 tokens)
├── textobjects.scm (300 tokens)
├── package.json (100 tokens)
├── src/
├── lib.rs (2.2k tokens)
├── plans/
├── tsrx-double-quoted-text-children.md (600 tokens)
├── playground/
├── .vscode/
├── settings.json (100 tokens)
├── react/
├── CHANGELOG.md (300 tokens)
├── README.md (200 tokens)
├── index.html
├── package.json (200 tokens)
├── tsconfig.json (100 tokens)
├── vite.config.js
├── ripple/
├── demo.css (800 tokens)
├── eslint.config.js
├── index.html (100 tokens)
├── package.json (300 tokens)
├── ripple.config.ts
├── ssr-dev.js (600 tokens)
├── tsconfig.json (100 tokens)
├── vite.config.js (100 tokens)
├── solid/
├── CHANGELOG.md (300 tokens)
├── README.md (300 tokens)
├── index.html
├── package.json (200 tokens)
├── tsconfig.json (100 tokens)
├── vite.config.js
├── vue/
├── CHANGELOG.md (200 tokens)
├── README.md (200 tokens)
├── index.html
├── package.json (200 tokens)
├── src/
├── main.tsx
├── tsconfig.json (100 tokens)
├── vite.config.js
├── pnpm-lock.yaml (omitted)
├── pnpm-workspace.yaml (700 tokens)
├── rulesync.jsonc
├── scripts/
├── build-if-changed.js (700 tokens)
├── check-changesets.js (300 tokens)
├── check-zed-grammar-rev.js (400 tokens)
├── collect-external-deps.js (1000 tokens)
├── copy-external-deps.js (700 tokens)
├── copy-tree-sitter-queries.js (400 tokens)
├── debug-mode.js (500 tokens)
├── regenerate-textmate.js (800 tokens)
├── remove.js (200 tokens)
├── sync-zed-grammar-rev.js (300 tokens)
├── sync-zed-plugin-version.js (200 tokens)
├── transform-package.js (300 tokens)
├── templates/
├── basic/
├── .gitignore
├── .prettierignore
├── .prettierrc
├── README.md (200 tokens)
├── eslint.config.js
├── index.html (100 tokens)
├── package.json (200 tokens)
├── src/
├── App.tsrx (600 tokens)
├── assets/
├── favicon.ico
├── ripple-logo-horizontal.png
├── index.ts
├── tsconfig.json (100 tokens)
├── vite.config.js
├── tree-sitter
├── vitest.config.js (2.2k tokens)
├── website-mcp/
├── CHANGELOG.md (1600 tokens)
├── README.md (200 tokens)
├── api/
├── mcp.js
├── package.json (100 tokens)
├── public/
├── index.html (200 tokens)
├── scripts/
├── build.js
├── src/
├── handler.js (100 tokens)
├── server.js (200 tokens)
├── vercel.json (100 tokens)
├── website-new/
├── CHANGELOG.md (1500 tokens)
├── api/
├── handler.js (200 tokens)
├── docs/
├── best-practices.md (100 tokens)
├── comparison.md (100 tokens)
├── examples.ts (3.2k tokens)
├── guide/
├── application.md (700 tokens)
├── bindings.md (3.4k tokens)
├── components.md (1200 tokens)
├── control-flow.md (1400 tokens)
├── dom-refs.md (500 tokens)
├── events.md (1300 tokens)
├── head-management.md (100 tokens)
├── reactivity.md (3.1k tokens)
├── state-management.md (500 tokens)
├── styling.md (1400 tokens)
├── syntax.md (2k tokens)
├── introduction.md (600 tokens)
├── libraries.md (100 tokens)
├── quick-start.md (900 tokens)
├── troubleshooting.md (300 tokens)
├── index.html (300 tokens)
├── package.json (100 tokens)
├── playground.md
├── public/
├── 404.html (900 tokens)
├── favicon.ico
├── favicon.svg (200 tokens)
├── images/
├── favicon.ico
├── favicon.svg (200 tokens)
├── ripple-logo-horizontal.png
├── ripple-social.png
├── llms.txt (10.6k tokens)
├── ripple-logo-horizontal.png
├── ripple-social.png
├── robots.txt
├── sitemap.xml (100 tokens)
├── ripple.config.ts (100 tokens)
├── src/
├── components/
├── actions.tsrx (1000 tokens)
├── content.tsrx (500 tokens)
├── doc-badge.tsrx
├── doc-callout.tsrx (100 tokens)
├── doc-code-block.tsrx (200 tokens)
├── doc-heading.tsrx (100 tokens)
├── docs-footer.tsrx (100 tokens)
├── docs-header.tsrx (2.5k tokens)
├── docs-layout.tsrx (4k tokens)
├── editor.tsrx (1000 tokens)
├── header.tsrx (200 tokens)
├── layout.tsrx (700 tokens)
├── sidebar.tsrx (1900 tokens)
├── lib/
├── markdown.js (2000 tokens)
├── middlewares.ts (100 tokens)
├── pages/
├── 404.tsrx
├── docs/
├── best-practices.tsrx (100 tokens)
├── comparison.tsrx (100 tokens)
├── guide/
├── application.tsrx (100 tokens)
├── bindings.tsrx (100 tokens)
├── components.tsrx (100 tokens)
├── control-flow.tsrx (100 tokens)
├── dom-refs.tsrx (100 tokens)
├── events.tsrx (100 tokens)
├── head-management.tsrx (100 tokens)
├── reactivity.tsrx (100 tokens)
├── state-management.tsrx (100 tokens)
├── styling.tsrx (100 tokens)
├── syntax.tsrx (100 tokens)
├── introduction.tsrx (1000 tokens)
├── libraries.tsrx (100 tokens)
├── quick-start.tsrx (100 tokens)
├── troubleshooting.tsrx (100 tokens)
├── index.tsrx (100 tokens)
├── routes.ts (2.2k tokens)
├── tsconfig.json (100 tokens)
├── vercel.json (300 tokens)
├── vite.config.ts (100 tokens)
├── website-tsrx/
├── CHANGELOG.md (3.7k tokens)
├── api/
├── handler.js (100 tokens)
├── index.html (400 tokens)
├── package.json (200 tokens)
├── public/
├── images/
├── tsrx-mark.svg (600 tokens)
├── llms.txt (7k tokens)
├── ripple.config.ts (100 tokens)
├── src/
├── components/
├── brand-logo.tsrx (100 tokens)
├── compiler-demo.tsrx (3.9k tokens)
├── layout.tsrx (200 tokens)
├── lib/
├── demo-snippets.ts (1100 tokens)
├── demo.ts (100 tokens)
├── shiki-codemirror.ts (600 tokens)
├── pages/
├── docs.tsrx (10.7k tokens)
├── features.tsrx (15.7k tokens)
├── getting-started.tsrx (11k tokens)
├── index.tsrx (6.2k tokens)
├── playground.tsrx (800 tokens)
├── specification.tsrx (8.1k tokens)
├── routes.ts (1200 tokens)
├── tsconfig.json (100 tokens)
├── vercel.json (300 tokens)
├── vite.config.ts (400 tokens)
├── website/
├── .vitepress/
├── components/
├── Code.vue (300 tokens)
├── LiveCodes.vue (4.7k tokens)
├── Playground.vue (100 tokens)
├── PlaygroundProps.ts (100 tokens)
├── config.js (900 tokens)
├── theme/
├── index.js (100 tokens)
├── styles.css (300 tokens)
├── docs/
├── best-practices.md (100 tokens)
├── comparison.md (100 tokens)
├── examples.ts (3.2k tokens)
├── guide/
├── application.md (700 tokens)
├── bindings.md (3.4k tokens)
├── components.md (1200 tokens)
├── control-flow.md (1400 tokens)
├── dom-refs.md (1200 tokens)
├── events.md (1300 tokens)
├── head-management.md (100 tokens)
├── reactivity.md (3.1k tokens)
├── state-management.md (500 tokens)
├── styling.md (1500 tokens)
├── syntax.md (2k tokens)
├── introduction.md (600 tokens)
├── libraries.md (100 tokens)
├── quick-start.md (900 tokens)
├── troubleshooting.md (300 tokens)
├── package.json (100 tokens)
├── playground.md
├── public/
├── 404.html (900 tokens)
├── favicon.ico
├── favicon.svg (200 tokens)
├── index.html (6.8k tokens)
├── llms.txt (10.6k tokens)
├── ripple-logo-horizontal.png
├── ripple-social.png
├── robots.txt
├── sitemap.xml (100 tokens)
├── vercel.json (200 tokens)
```
## /.changeset/README.md
# Changesets
Hello and welcome! This folder has been automatically generated by
`@changesets/cli`, a build tool that works with multi-package repos, or
single-package repos to help you version and publish your code. You can find the
full documentation for it
[in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this
project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
## /.changeset/config.json
```json path="/.changeset/config.json"
{
"$schema": "https://unpkg.com/@changesets/config@3.1.2/schema.json",
"changelog": ["@changesets/changelog-github", { "repo": "Ripple-TS/ripple" }],
"commit": false,
"fixed": [
[
"@tsrx/core"
],
[
"@tsrx/ripple"
],
[
"ripple",
"@ripple-ts/cli",
"@ripple-ts/compat-react",
"create-ripple",
"@tsrx/eslint-parser",
"@tsrx/eslint-plugin",
"@ripple-ts/language-server",
"@tsrx/prettier-plugin",
"@ripple-ts/adapter",
"@ripple-ts/adapter-node",
"@ripple-ts/adapter-bun",
"@ripple-ts/adapter-vercel",
"@ripple-ts/rollup-plugin",
"@tsrx/typescript-plugin",
"@ripple-ts/vite-plugin"
]
],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": [
"@ripple-ts/playground",
"@ripple-ts/tree-sitter",
"@ripple-ts/nvim-plugin",
"@ripple-ts/intellij-plugin",
"@ripple-ts/sublime-text-plugin",
"@ripple-ts/zed-plugin"
]
}
```
## /.claude/skills/ripple.md
../../.agents/skills/ripple.md
## /.codex/skills/ripple.md
../../.agents/skills/ripple.md
## /.cursor/environment.json
```json path="/.cursor/environment.json"
{
"name": "ripple-monorepo",
"install": "bash .cursor/install.sh"
}
```
## /.cursor/install.sh
```sh path="/.cursor/install.sh"
#!/usr/bin/env bash
set -euo pipefail
WORKSPACE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
LOCKFILE_PATH="${WORKSPACE_ROOT}/pnpm-lock.yaml"
LOCKFILE_HASH_PATH="${HOME}/.cache/cursor/ripple-pnpm-lock.sha256"
PACKAGE_MANAGER="$(node -p "JSON.parse(require('node:fs').readFileSync(process.argv[1], 'utf8')).packageManager" "${WORKSPACE_ROOT}/package.json")"
if [[ "${PACKAGE_MANAGER}" != pnpm@* ]]; then
echo "Expected packageManager in package.json to be pnpm@<version>, got '${PACKAGE_MANAGER}'."
exit 1
fi
REQUIRED_PNPM_VERSION="${PACKAGE_MANAGER#pnpm@}"
cd "${WORKSPACE_ROOT}"
if [ ! -f "${LOCKFILE_PATH}" ]; then
echo "Expected lockfile at ${LOCKFILE_PATH}, but it was not found."
exit 1
fi
pnpm_version=""
if command -v pnpm >/dev/null 2>&1; then
pnpm_version="$(pnpm --version)"
fi
if [ "${pnpm_version}" != "${REQUIRED_PNPM_VERSION}" ]; then
corepack enable
corepack prepare "pnpm@${REQUIRED_PNPM_VERSION}" --activate >/dev/null
fi
lockfile_hash="$(sha256sum "${LOCKFILE_PATH}" | awk '{ print $1 }')"
cached_lockfile_hash=""
if [ -f "${LOCKFILE_HASH_PATH}" ]; then
read -r cached_lockfile_hash < "${LOCKFILE_HASH_PATH}" || true
fi
if [ -d "${WORKSPACE_ROOT}/node_modules" ] \
&& [ -x "${WORKSPACE_ROOT}/node_modules/.bin/vitest" ] \
&& [ "${cached_lockfile_hash}" = "${lockfile_hash}" ]; then
echo "pnpm dependencies are up to date; skipping install."
else
pnpm install --frozen-lockfile --prefer-offline
mkdir -p "$(dirname "${LOCKFILE_HASH_PATH}")"
printf '%s\n' "${lockfile_hash}" > "${LOCKFILE_HASH_PATH}"
fi
# Warm command resolution so vitest-based test runs start quickly.
pnpm exec vitest --version >/dev/null
```
## /.cursor/rules/project.mdc
```mdc path="/.cursor/rules/project.mdc"
---
description: Ripple project overview and development guidelines
globs: **/*
---
# Ripple Project Guide for AI Agents
Ripple is a TypeScript-first UI framework and monorepo maintained by Dominic
Gannaway. The current authoring format is centered on `.tsrx` files and the shared
TSRX compiler stack. Older `.ripple`-specific docs and compiler details still
exist in repo history and changelogs, but they are not the right default source of
truth for current work.
## Start From Current Sources
Use the nearest live source rather than historical summaries:
- `website/public/llms.txt` for current Ripple syntax, runtime APIs, and authoring
guidance
- `README.md` for project overview, positioning, and quick-start examples
- `packages/*/README.md` for package-specific usage and public APIs
- `vitest.config.js` for the current test projects and file globs
- `package.json` for workspace-wide scripts such as `rules:generate`, `test`,
`format`, `format:check`, and `typecheck`
If a guide in this repo conflicts with nearby code or package READMEs, trust the
nearby code and current package docs.
## RuleSync
This repository uses RuleSync as the single source of truth for shared AI agent
instructions. Edit `.rulesync/rules/` and regenerate derived files instead of
patching generated outputs directly.
Generated targets include:
- `AGENTS.md`
- `.github/copilot-instructions.md`
- `CLAUDE.md`
- `GEMINI.md`
- `.cursor/rules/project.mdc`
After changing RuleSync content, run:
\`\`\`bash
pnpm rules:generate
\`\`\`
## Monorepo Map
This is a pnpm monorepo. The current high-level layout is:
- `packages/tsrx/`: core parser, transforms, and shared compiler infrastructure
- `packages/tsrx-ripple/`, `packages/tsrx-react/`, `packages/tsrx-solid/`,
`packages/tsrx-preact/`: target-specific compiler layers
- `packages/ripple/`: Ripple runtime, server helpers, and framework behavior
- `packages/vite-plugin/`, `packages/rollup-plugin/`,
`packages/vite-plugin-react/`, `packages/vite-plugin-solid/`,
`packages/vite-plugin-preact/`, `packages/rspack-plugin-react/`,
`packages/turbopack-plugin-react/`: bundler integrations
- `packages/adapter/`, `packages/adapter-node/`, `packages/adapter-bun/`,
`packages/adapter-vercel/`: deployment and platform adapters
- `packages/language-server/`, `packages/typescript-plugin/`,
`packages/vscode-plugin/`, `packages/intellij-plugin/`, `packages/nvim-plugin/`,
`packages/sublime-text-plugin/`, `packages/zed-plugin/`: editor and language
tooling
- `packages/eslint-parser/`, `packages/eslint-plugin/`,
`packages/prettier-plugin/`, `packages/prettier-plugin-ripple/`: linting and
formatting
- `packages/create-ripple/`, `templates/`, `playground/`: scaffolding and local
examples
- `website/`, `website-new/`, `website-tsrx/`: documentation and website work
When routing a change, prefer the package that directly owns the behavior rather
than editing generated output, tests, or editor integrations first.
## Current Working Assumptions
- Default component files are `.tsrx`. Do not describe the project as primarily
using `.ripple` files unless the local file you are editing actually does.
- Some packages still preserve compatibility or historical references. Treat them
as compatibility context, not the default architecture description.
- Use `pnpm` for all package management and workspace scripts.
- Follow the conventions of the package you are changing. This repo mixes plain
JavaScript, JSDoc-typed JavaScript, and TypeScript depending on package.
- Match nearby naming, file layout, and test style instead of applying a single
convention repo-wide.
## Finding The Right Package
Use these rough routing rules:
- Ripple syntax, parsing, source transforms, or shared AST behavior:
`packages/tsrx/` and the relevant target package under `packages/tsrx-*`
- Ripple runtime behavior, hydration, reactivity, DOM updates, or server output:
`packages/ripple/`
- Vite, Rollup, Rspack, Turbopack, or adapter behavior: the relevant plugin or
adapter package in `packages/`
- Diagnostics, completions, hover, definitions, or editor integration:
`packages/language-server/`, `packages/typescript-plugin/`, and editor plugin
packages
- Formatting or lint behavior: `packages/prettier-plugin/`,
`packages/prettier-plugin-ripple/`, `packages/eslint-parser/`, or
`packages/eslint-plugin/`
## Validation
Prefer the smallest validation that covers the touched surface.
Common workspace commands:
\`\`\`bash
pnpm rules:generate
pnpm format:check
pnpm test
pnpm test --project ripple-client
pnpm test --project ripple-server
pnpm typecheck
\`\`\`
Current Vitest projects are defined in `vitest.config.js`. Ripple runtime suites
use `.test.tsrx` files for many client, server, and compat tests, while tooling
packages often use `.test.js` or `.test.ts`.
## Changesets
Add a changeset for user-facing package changes. Skip changesets for docs-only,
test-only, and internal tooling updates.
Only use `patch` changesets. Do not use `minor` or `major` bump types in this
repo; prerelease packages must stay on the patch track until a release plan
explicitly changes that policy.
\`\`\`bash
pnpm changeset
\`\`\`
Validate pending changesets before versioning or publishing:
\`\`\`bash
pnpm changeset:check
\`\`\`
## Practical Guidance For Agents
- Prefer the current docs in `website/public/llms.txt` over stale architectural
summaries.
- Avoid copying removed compiler APIs, old package layouts, or legacy `.ripple`
examples into new guidance.
- If you need exact behavior, read the owning package and its tests instead of
relying on a repo-wide summary.
- Keep documentation updates short and durable. High-level guidance ages better
than detailed internal call lists.
```
## /.gemini/skills/ripple.md
../../.agents/skills/ripple.md
## /.github/ISSUE_TEMPLATE/bug-report.yml
```yml path="/.github/ISSUE_TEMPLATE/bug-report.yml"
name: "🐛 Bug Report"
description: "Report a bug or unexpected behavior in Ripple"
title: "[Bug]: "
labels: ["bug", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to report this issue! Please search existing issues first to avoid duplicates.
- type: dropdown
id: category
attributes:
label: "Issue Category"
description: "What type of issue is this?"
options:
- "Compilation Bug"
- "Behavioral Bug"
- "Performance Issue"
- "Documentation Issue"
- "Security Concern"
- "Other"
validations:
required: true
- type: textarea
id: description
attributes:
label: "Bug Description"
description: "A clear description of what the bug is and what you expected to happen."
placeholder: "When I do X, Y happens, but I expected Z..."
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: "Reproduction Steps"
description: "Provide a minimal reproducible example. Link to a repo, StackBlitz, or detailed steps."
placeholder: |
1. Go to...
2. Click on...
3. See error...
OR provide a link to reproduction: https://...
validations:
required: true
- type: textarea
id: environment
attributes:
label: "Environment"
description: "Share relevant environment details"
placeholder: |
- OS: [e.g. macOS 13.1, Windows 11, Ubuntu 22.04]
- Browser: [e.g. Chrome 118, Firefox 119, Safari 16]
- Ripple Version: [e.g. 1.2.3]
- Node Version: [e.g. 22.19.0]
render: markdown
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: "Additional Context"
description: "Screenshots, logs, or any other context that might help"
placeholder: "Add any other context, screenshots, or logs here..."
validations:
required: false
- type: checkboxes
id: checklist
attributes:
label: "Checklist"
options:
- label: "I've searched for existing issues"
required: true
- label: "I'm willing to help implement a fix"
required: false
```
## /.github/ISSUE_TEMPLATE/config.yml
```yml path="/.github/ISSUE_TEMPLATE/config.yml"
blank_issues_enabled: true
contact_links:
- name: Discord Chat
url: https://discord.gg/JBF2ySrh2W
about: Ask questions and discuss ideas with other users real-time
- name: "Discussions"
url: "https://github.com/Ripple-TS/ripple/discussions"
about: "Ask questions and discuss ideas with the community"
```
## /.github/ISSUE_TEMPLATE/feature-request.yml
```yml path="/.github/ISSUE_TEMPLATE/feature-request.yml"
name: "✨ Feature Request"
description: "Suggest a new feature or enhancement for Ripple"
title: "[Feature]: "
labels: ["enhancement", "triage"]
body:
- type: markdown
attributes:
value: |
Thanks for suggesting a new feature! Please check existing issues and discussions first.
- type: dropdown
id: category
attributes:
label: "Feature Category"
description: "What area does this feature relate to?"
options:
- "Performance Enhancement"
- "Developer Experience"
- "Syntax/Language Improvement"
- "Tooling Integration"
- "Documentation"
- "Testing/Quality"
- "Other"
validations:
required: true
- type: textarea
id: problem
attributes:
label: "Problem Statement"
description: "What problem does this feature solve? What's the use case?"
placeholder: "As a user, I want to... so that I can..."
validations:
required: true
- type: textarea
id: solution
attributes:
label: "Proposed Solution"
description: "Describe your proposed solution or feature"
placeholder: "I would like to see... This could work by..."
validations:
required: true
- type: textarea
id: alternatives
attributes:
label: "Alternatives Considered"
description: "What other approaches have you considered? Any workarounds you're currently using?"
placeholder: "I considered... but this doesn't work because..."
validations:
required: false
- type: textarea
id: examples
attributes:
label: "Examples & References"
description: "Links to similar features in other tools, mockups, or code examples"
placeholder: "Similar to how X does Y... Here's a mockup/example..."
validations:
required: false
- type: checkboxes
id: checklist
attributes:
label: "Checklist"
options:
- label: "I've searched for existing feature requests"
required: true
- label: "I'm willing to help implement this feature"
required: false
```
## /.github/agents/ripple.agent.md
---
name: Ripple
description: An AI assistant specialized in the Ripple TypeScript UI framework
---
You are a helpful assistant specialized in **Ripple**, a TypeScript UI framework
that combines the best parts of React, Solid, and Svelte.
## Your Expertise
- Ripple component syntax and `.ripple` files
- Reactivity system: `track()`, `RippleArray`, `RippleMap`, etc. (imported from
`ripple`)
- Compiler architecture (parse → analyze → transform)
- SSR and hydration mechanisms
- Runtime internals (blocks, events, DOM operations)
- Editor tooling (language server, Prettier plugin, ESLint plugin)
## Key Resources
For detailed documentation, refer to:
- [AGENTS.md](../AGENTS.md) - Full project guide
- [website/public/llms.txt](../../website/public/llms.txt) - Comprehensive Ripple
documentation
## Code Conventions
- Use `snake_case` for variables and functions
- Use `SCREAMING_SNAKE_CASE` for constants
- Internal code is JavaScript with JSDoc annotations (not TypeScript)
- **Always use pnpm** - never npm or yarn
## Common Tasks
### Creating a Component
```ripple
component Button(label: string, onClick: () => void) {
<button onclick={onClick}>{label}</button>
}
```
### Reactive State
```ripple
import { track } from 'ripple';
let count = track(0); // tracked value
let doubled = track(() => @count * 2); // derived value
```
### Validation Commands
```bash
pnpm test # Run all tests
pnpm format # Format code
pnpm format:check # Check formatting
```
## /.github/copilot-instructions.md
# Ripple Project Guide for AI Agents
Ripple is a TypeScript-first UI framework and monorepo maintained by Dominic
Gannaway. The current authoring format is centered on `.tsrx` files and the shared
TSRX compiler stack. Older `.ripple`-specific docs and compiler details still
exist in repo history and changelogs, but they are not the right default source of
truth for current work.
## Start From Current Sources
Use the nearest live source rather than historical summaries:
- `website/public/llms.txt` for current Ripple syntax, runtime APIs, and authoring
guidance
- `README.md` for project overview, positioning, and quick-start examples
- `packages/*/README.md` for package-specific usage and public APIs
- `vitest.config.js` for the current test projects and file globs
- `package.json` for workspace-wide scripts such as `rules:generate`, `test`,
`format`, `format:check`, and `typecheck`
If a guide in this repo conflicts with nearby code or package READMEs, trust the
nearby code and current package docs.
## RuleSync
This repository uses RuleSync as the single source of truth for shared AI agent
instructions. Edit `.rulesync/rules/` and regenerate derived files instead of
patching generated outputs directly.
Generated targets include:
- `AGENTS.md`
- `.github/copilot-instructions.md`
- `CLAUDE.md`
- `GEMINI.md`
- `.cursor/rules/project.mdc`
After changing RuleSync content, run:
```bash
pnpm rules:generate
```
## Monorepo Map
This is a pnpm monorepo. The current high-level layout is:
- `packages/tsrx/`: core parser, transforms, and shared compiler infrastructure
- `packages/tsrx-ripple/`, `packages/tsrx-react/`, `packages/tsrx-solid/`,
`packages/tsrx-preact/`: target-specific compiler layers
- `packages/ripple/`: Ripple runtime, server helpers, and framework behavior
- `packages/vite-plugin/`, `packages/rollup-plugin/`,
`packages/vite-plugin-react/`, `packages/vite-plugin-solid/`,
`packages/vite-plugin-preact/`, `packages/rspack-plugin-react/`,
`packages/turbopack-plugin-react/`: bundler integrations
- `packages/adapter/`, `packages/adapter-node/`, `packages/adapter-bun/`,
`packages/adapter-vercel/`: deployment and platform adapters
- `packages/language-server/`, `packages/typescript-plugin/`,
`packages/vscode-plugin/`, `packages/intellij-plugin/`, `packages/nvim-plugin/`,
`packages/sublime-text-plugin/`, `packages/zed-plugin/`: editor and language
tooling
- `packages/eslint-parser/`, `packages/eslint-plugin/`,
`packages/prettier-plugin/`, `packages/prettier-plugin-ripple/`: linting and
formatting
- `packages/create-ripple/`, `templates/`, `playground/`: scaffolding and local
examples
- `website/`, `website-new/`, `website-tsrx/`: documentation and website work
When routing a change, prefer the package that directly owns the behavior rather
than editing generated output, tests, or editor integrations first.
## Current Working Assumptions
- Default component files are `.tsrx`. Do not describe the project as primarily
using `.ripple` files unless the local file you are editing actually does.
- Some packages still preserve compatibility or historical references. Treat them
as compatibility context, not the default architecture description.
- Use `pnpm` for all package management and workspace scripts.
- Follow the conventions of the package you are changing. This repo mixes plain
JavaScript, JSDoc-typed JavaScript, and TypeScript depending on package.
- Match nearby naming, file layout, and test style instead of applying a single
convention repo-wide.
## Finding The Right Package
Use these rough routing rules:
- Ripple syntax, parsing, source transforms, or shared AST behavior:
`packages/tsrx/` and the relevant target package under `packages/tsrx-*`
- Ripple runtime behavior, hydration, reactivity, DOM updates, or server output:
`packages/ripple/`
- Vite, Rollup, Rspack, Turbopack, or adapter behavior: the relevant plugin or
adapter package in `packages/`
- Diagnostics, completions, hover, definitions, or editor integration:
`packages/language-server/`, `packages/typescript-plugin/`, and editor plugin
packages
- Formatting or lint behavior: `packages/prettier-plugin/`,
`packages/prettier-plugin-ripple/`, `packages/eslint-parser/`, or
`packages/eslint-plugin/`
## Validation
Prefer the smallest validation that covers the touched surface.
Common workspace commands:
```bash
pnpm rules:generate
pnpm format:check
pnpm test
pnpm test --project ripple-client
pnpm test --project ripple-server
pnpm typecheck
```
Current Vitest projects are defined in `vitest.config.js`. Ripple runtime suites
use `.test.tsrx` files for many client, server, and compat tests, while tooling
packages often use `.test.js` or `.test.ts`.
## Changesets
Add a changeset for user-facing package changes. Skip changesets for docs-only,
test-only, and internal tooling updates.
Only use `patch` changesets. Do not use `minor` or `major` bump types in this
repo; prerelease packages must stay on the patch track until a release plan
explicitly changes that policy.
```bash
pnpm changeset
```
Validate pending changesets before versioning or publishing:
```bash
pnpm changeset:check
```
## Practical Guidance For Agents
- Prefer the current docs in `website/public/llms.txt` over stale architectural
summaries.
- Avoid copying removed compiler APIs, old package layouts, or legacy `.ripple`
examples into new guidance.
- If you need exact behavior, read the owning package and its tests instead of
relying on a repo-wide summary.
- Keep documentation updates short and durable. High-level guidance ages better
than detailed internal call lists.
## /.github/workflows/ci.yml
```yml path="/.github/workflows/ci.yml"
name: CI
on:
push:
branches: [main, develop]
tags: ["!**"]
paths:
- "packages/**"
- "package.json"
- "pnpm-lock.yaml"
- "pnpm-workspace.yaml"
- "scripts/**"
- "vitest.config.js"
- ".changeset/**"
- ".github/workflows/ci.yml"
pull_request:
branches: [main, develop]
paths:
- "packages/**"
- "package.json"
- "pnpm-lock.yaml"
- "pnpm-workspace.yaml"
- "scripts/**"
- "vitest.config.js"
- ".changeset/**"
- ".github/workflows/ci.yml"
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22, 24, 26]
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install pnpm
uses: pnpm/action-setup@v6
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: "pnpm"
- name: Install dependencies
run: pnpm install --prod false --frozen-lockfile
- name: Build cli
working-directory: ./packages/cli
run: pnpm build
- name: Build eslint-parser
working-directory: ./packages/eslint-parser
run: pnpm build
- name: Run tests
run: pnpm test
- name: Upload test results
uses: actions/upload-artifact@v7
if: failure()
with:
name: test-results-node-${{ matrix.node-version }}
path: |
packages/ripple/tests/__snapshots__/
coverage/
retention-days: 30
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install pnpm
uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Check formatting
run: pnpm format:check
changeset-check:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24
- name: Disallow major and minor bumps in changesets
run: node scripts/check-changesets.js
typecheck:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install pnpm
uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Type check
run: pnpm typecheck
```
## /.github/workflows/copilot-setup-steps.yml
```yml path="/.github/workflows/copilot-setup-steps.yml"
# GitHub Copilot agent environment setup
# See: https://gh.io/copilot/actions-setup-steps
name: Copilot Setup Steps
on: workflow_dispatch
jobs:
copilot-setup-steps:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install pnpm
uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: "24"
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build CLI
working-directory: ./packages/cli
run: pnpm build
- name: Build ESLint parser
working-directory: ./packages/eslint-parser
run: pnpm build
- name: Sync agent configurations
run: pnpm agents:sync
```
## /.github/workflows/livecodes-post-comment.yml
```yml path="/.github/workflows/livecodes-post-comment.yml"
name: comment
on:
workflow_run:
workflows: ["livecodes"] # the workflow that created the artifact
types:
- completed
jobs:
upload:
runs-on: ubuntu-latest
permissions:
pull-requests: write
if: >
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success'
steps:
- uses: live-codes/pr-comment-from-artifact@v1
with:
GITHUB_TOKEN: ${{ github.token }}
```
## /.github/workflows/livecodes-preview.yml
```yml path="/.github/workflows/livecodes-preview.yml"
name: livecodes
on:
workflow_run:
workflows: ["Publish to pkg.pr.new"]
types:
- completed
jobs:
build_and_prepare:
runs-on: ubuntu-latest
if: >
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.jobs[1].steps['Publish'].outcome == 'success'
name: Generate Playground
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Build and generate
uses: live-codes/preview-in-livecodes@v1
```
## /.github/workflows/pkg.pr.new.yml
```yml path="/.github/workflows/pkg.pr.new.yml"
name: Publish to pkg.pr.new
on:
push:
branches: [main, develop]
tags: ["!**"]
paths: ["packages/**"]
pull_request:
types: [opened, synchronize]
paths: ["packages/**"]
pull_request_review:
types: [submitted]
workflow_dispatch:
permissions:
contents: read
pull-requests: write
jobs:
approval-check:
name: Check for Collaborator Approval
# Github doesn't support conditional needs, so this needs to run no matter what. :')
# if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
outputs:
is_approved: ${{ steps.check_for_approval.outputs.result }}
steps:
- name: Check for approval by a collaborator
id: check_for_approval
uses: actions/github-script@v8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
result-encoding: string
script: |
const pr = context.payload.pull_request;
if (!pr) {
// This can happen on events that don't have a PR context.
return 'false';
}
const reviews = await github.rest.pulls.listReviews({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number
});
const isApproved = reviews.data.some(review =>
review.state === 'APPROVED' &&
['MEMBER', 'OWNER', 'COLLABORATOR'].includes(review.author_association)
);
console.log(`PR is approved by collaborator: ${isApproved}`);
return isApproved.toString();
publish:
# Only run if pushed to main, is a PR by a collaborator,
# or an external PR approved by a collaborator.
needs: approval-check
if: >-
(github.event_name == 'push') ||
(github.event_name == 'pull_request' && (
github.event.pull_request.author_association == 'MEMBER' ||
github.event.pull_request.author_association == 'OWNER' ||
github.event.pull_request.author_association == 'COLLABORATOR'
)) ||
(needs.approval-check.outputs.is_approved == 'true') ||
(github.event_name == 'pull_request_review' &&
github.event.review.state == 'approved' && (
github.event.review.author_association == 'MEMBER' ||
github.event.review.author_association == 'OWNER' ||
github.event.review.author_association == 'COLLABORATOR'
))
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install pnpm
uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24
cache: "pnpm"
- name: Install dependencies
run: pnpm install --prod false --frozen-lockfile
- name: Build cli
working-directory: ./packages/cli
run: pnpm build
- name: Publish
run: |
pnpm dlx pkg-pr-new publish \
'./packages/eslint-plugin' \
'./packages/eslint-parser' \
'./packages/typescript-plugin' \
'./packages/create-ripple' \
'./packages/prettier-plugin' \
'./packages/ripple' \
'./packages/adapter' \
'./packages/adapter-node' \
'./packages/adapter-bun' \
'./packages/rollup-plugin' \
'./packages/vite-plugin' \
'./packages/cli' \
--compact \
--comment=update \
--packageManager=pnpm \
--pnpm \
--template './templates/basic'
```
## /.github/workflows/publish.yml
```yml path="/.github/workflows/publish.yml"
name: Publish
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}
permissions: {}
jobs:
publish:
if: github.repository == 'Ripple-TS/ripple' && contains(github.event.head_commit.message, 'Version Packages')
permissions:
contents: write
id-token: write
name: Publish
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install pnpm
uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24.x
# Do not enable dependency caching in this workflow. This job has
# id-token: write and publishes to npm, so restoring shared Actions
# cache here can turn cache poisoning into a trusted publish compromise.
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Disallow major and minor bumps in changesets
run: pnpm changeset:check
- name: Publish to npm
id: changesets
uses: changesets/action@v1
with:
publish: pnpm changeset:publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PNPM_CONFIG_PROVENANCE: true
# keep for now just in case
NPM_CONFIG_PROVENANCE: true
```
## /.github/workflows/release.yml
```yml path="/.github/workflows/release.yml"
name: Release PR
on:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}
permissions: {}
jobs:
release-pr:
if: github.repository == 'Ripple-TS/ripple'
permissions:
contents: write
pull-requests: write
name: Release PR
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Install pnpm
uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24.x
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Disallow major and minor bumps in changesets
run: pnpm changeset:check
- name: Create or update release pull request
id: changesets
uses: changesets/action@v1
with:
version: pnpm changeset:version
commit: Version Packages
title: Version Packages
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
## /.github/workflows/rulesync.yml
```yml path="/.github/workflows/rulesync.yml"
name: RuleSync Check
on:
pull_request:
paths:
- ".rulesync/**"
- "rulesync.jsonc"
- "CLAUDE.md"
- "GEMINI.md"
- "AGENTS.md"
- ".github/copilot-instructions.md"
- ".cursor/rules/**"
permissions:
contents: read
jobs:
check:
name: Check RuleSync
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Install pnpm
uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Check RuleSync is up to date
run: pnpm rules:check
```
## /.github/workflows/vsix-manual.yml
```yml path="/.github/workflows/vsix-manual.yml"
on: workflow_dispatch
name: Publish VSC Extension (Manual)
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install pnpm
uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24.x
- name: Install deps w/ pnpm
working-directory: ./packages/vscode-plugin
run: pnpm install --frozen-lockfile
- name: Build VSIX
working-directory: ./packages/vscode-plugin
run: pnpm run build-and-package
- name: Upload VSIX
uses: actions/upload-artifact@v7
with:
name: vscode-plugin VSIX
path: ./packages/vscode-plugin/*.vsix
publish-vsm:
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Download VSIX
uses: actions/download-artifact@v7
with:
name: vscode-plugin VSIX
path: ./packages/vscode-plugin
- name: Install pnpm
uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24.x
- name: Install deps w/ pnpm
run: pnpm install --frozen-lockfile
- name: Publish to VSM
working-directory: ./packages/vscode-plugin
run: pnpm exec vsce publish -i *.vsix
env:
VSCE_PAT: ${{ secrets.VSM_TOKEN }}
publish-ovsx:
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Download VSIX
uses: actions/download-artifact@v7
with:
name: vscode-plugin VSIX
path: ./packages/vscode-plugin
- name: Install pnpm
uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24.x
- name: Install deps w/ pnpm
run: pnpm install --frozen-lockfile
- name: Publish to OVSX
working-directory: ./packages/vscode-plugin
run: pnpm exec ovsx publish *.vsix
env:
OVSX_PAT: ${{ secrets.OVSX_TOKEN }}
```
## /.github/workflows/vsix.yml
```yml path="/.github/workflows/vsix.yml"
on:
push:
branches: [main]
tags: ["!**"]
paths: ["packages/vscode-plugin/**"]
name: Publish VSC Extension
jobs:
# Note: this doesn't parse the versions, rather, it only checks if the versions are different.
version-check:
name: "Verify version change"
runs-on: ubuntu-latest
outputs:
version-changed: ${{ steps.compare_versions.outputs.changed }}
steps:
- name: Checkout Code
uses: actions/checkout@v6
with:
fetch-depth: 2
- name: Compare package.json versions
working-directory: ./packages/vscode-plugin
id: compare_versions
run: |
# jq -r returns raw string
CURRENT_VERSION=$(jq -r .version package.json)
PREVIOUS_VERSION=$(git show HEAD~1:./package.json | jq -r .version)
echo "Current version: ${CURRENT_VERSION}"
echo "Previous version: ${PREVIOUS_VERSION}"
if [ "${CURRENT_VERSION}" == "${PREVIOUS_VERSION}" ]; then
echo "::notice::Version number not changed, skipping publish..."
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo "::notice::Version was changed: ${PREVIOUS_VERSION} -> ${CURRENT_VERSION}"
echo "changed=true" >> "$GITHUB_OUTPUT"
fi
build:
needs: version-check
if: needs.version-check.outputs.version-changed == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install pnpm
uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24.x
- name: Install deps w/ pnpm
working-directory: ./packages/vscode-plugin
run: pnpm install --frozen-lockfile
- name: Build VSIX
working-directory: ./packages/vscode-plugin
run: pnpm run build-and-package
- name: Upload VSIX
uses: actions/upload-artifact@v7
with:
name: vscode-plugin VSIX
path: ./packages/vscode-plugin/*.vsix
publish-vsm:
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Download VSIX
uses: actions/download-artifact@v7
with:
name: vscode-plugin VSIX
path: ./packages/vscode-plugin
- name: Install pnpm
uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24.x
- name: Install deps w/ pnpm
run: pnpm install --frozen-lockfile
- name: Publish to VSM
working-directory: ./packages/vscode-plugin
run: pnpm exec vsce publish -i *.vsix
env:
VSCE_PAT: ${{ secrets.VSM_TOKEN }}
publish-ovsx:
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Download VSIX
uses: actions/download-artifact@v7
with:
name: vscode-plugin VSIX
path: ./packages/vscode-plugin
- name: Install pnpm
uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 24.x
- name: Install deps w/ pnpm
run: pnpm install --frozen-lockfile
- name: Publish to OVSX
working-directory: ./packages/vscode-plugin
run: pnpm exec ovsx publish *.vsix
env:
OVSX_PAT: ${{ secrets.OVSX_TOKEN }}
```
## /.gitignore
```gitignore path="/.gitignore"
# Dependency directories
node_modules/
# IDE related
.idea
# Test coverage
coverage
*.lcov
# Local settings
*.local.json
.claude/settings.json
packages/vscode-plugin/*.vsix
playground/src
playground/ripple/src
playground/react/src
playground/solid/src
playground/vue/src
website/.vitepress/dist/
website/.vitepress/cache/
website/.vitepress/.temp/
# Optional eslint cache
.eslintcache
# dotenv environment variables file
.env
.env.test
# build output
.vercel
# OS-specific
.DS_Store
# VS Code settings
.vscode/
!.vscode/settings.json
!.vscode/launch.json
!.vscode/tasks.json
# But include playground/.vscode/settings.json
!playground/.vscode/
playground/.vscode/*
!playground/.vscode/settings.json
# Chrome Debugger
.chrome-debug-profile/
tmp
dist
debug
.build-hash
.build-hash-built
**/*.d.tsrx.ts
# Temporary folders
tmp/
temp/
```
## /.livecodes/playground.json
```json path="/.livecodes/playground.json"
{
"appUrl": "https://ripple.livecodes.pages.dev",
"config": {
"customSettings": {
"ripple": { "version": "pr:ripple@{{LC::SHORT_SHA}}" }
},
"title": "Ripple Playground: {{LC::SHORT_SHA}}",
"activeEditor": "script",
"script": {
"language": "ripple",
"content": "import type { Component } from \"ripple\"\nimport { track } from \"ripple\"\n\nexport default component App() {\n <div class=\"container\">\n let &[count] = track(0);\n\n <button onClick={() => count++}>{count}</button>\n\n if (count > 1) {\n <div>{'Greater than 1!'}</div>\n }\n </div>\n\n <style>\n button {\n padding: 1rem;\n font-size: 1rem;\n cursor: pointer;\n }\n </style>\n}\n"
},
"style": {
"language": "css",
"content": "body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; background: hsl(0, 0%, 18%); color: #fff }"
}
}
}
```
## /.prettierrc
```prettierrc path="/.prettierrc"
{
"useTabs": true,
"tabWidth": 2,
"singleQuote": true,
"jsxSingleQuote": false,
"printWidth": 100,
"plugins": ["@tsrx/prettier-plugin"],
"overrides": [
{
"files": ["*.tsrx"],
"options": {
"bracketSameLine": false,
"parser": "ripple"
}
},
{
"files": ["**/*.md"],
"options": {
"useTabs": false,
"printWidth": 82,
"proseWrap": "always"
}
},
{
"files": ["website/docs/**/*.md", "website-new/docs/**/*.md"],
"options": {
"proseWrap": "preserve",
"embeddedLanguageFormatting": "off"
}
},
{
"files": ["**/*.json"],
"options": {
"useTabs": false
}
},
{
"files": ["**/*.yml", "**/*.yaml"],
"options": {
"singleQuote": false
}
}
]
}
```
## /.rulesync/rules/project.md
---
root: true
targets: ['*']
description: 'Ripple project overview and development guidelines'
globs: ['**/*']
---
# Ripple Project Guide for AI Agents
Ripple is a TypeScript-first UI framework and monorepo maintained by Dominic
Gannaway. The current authoring format is centered on `.tsrx` files and the shared
TSRX compiler stack. Older `.ripple`-specific docs and compiler details still
exist in repo history and changelogs, but they are not the right default source of
truth for current work.
## Start From Current Sources
Use the nearest live source rather than historical summaries:
- `website/public/llms.txt` for current Ripple syntax, runtime APIs, and authoring
guidance
- `README.md` for project overview, positioning, and quick-start examples
- `packages/*/README.md` for package-specific usage and public APIs
- `vitest.config.js` for the current test projects and file globs
- `package.json` for workspace-wide scripts such as `rules:generate`, `test`,
`format`, `format:check`, and `typecheck`
If a guide in this repo conflicts with nearby code or package READMEs, trust the
nearby code and current package docs.
## RuleSync
This repository uses RuleSync as the single source of truth for shared AI agent
instructions. Edit `.rulesync/rules/` and regenerate derived files instead of
patching generated outputs directly.
Generated targets include:
- `AGENTS.md`
- `.github/copilot-instructions.md`
- `CLAUDE.md`
- `GEMINI.md`
- `.cursor/rules/project.mdc`
After changing RuleSync content, run:
```bash
pnpm rules:generate
```
## Monorepo Map
This is a pnpm monorepo. The current high-level layout is:
- `packages/tsrx/`: core parser, transforms, and shared compiler infrastructure
- `packages/tsrx-ripple/`, `packages/tsrx-react/`, `packages/tsrx-solid/`,
`packages/tsrx-preact/`: target-specific compiler layers
- `packages/ripple/`: Ripple runtime, server helpers, and framework behavior
- `packages/vite-plugin/`, `packages/rollup-plugin/`,
`packages/vite-plugin-react/`, `packages/vite-plugin-solid/`,
`packages/vite-plugin-preact/`, `packages/rspack-plugin-react/`,
`packages/turbopack-plugin-react/`: bundler integrations
- `packages/adapter/`, `packages/adapter-node/`, `packages/adapter-bun/`,
`packages/adapter-vercel/`: deployment and platform adapters
- `packages/language-server/`, `packages/typescript-plugin/`,
`packages/vscode-plugin/`, `packages/intellij-plugin/`, `packages/nvim-plugin/`,
`packages/sublime-text-plugin/`, `packages/zed-plugin/`: editor and language
tooling
- `packages/eslint-parser/`, `packages/eslint-plugin/`,
`packages/prettier-plugin/`, `packages/prettier-plugin-ripple/`: linting and
formatting
- `packages/create-ripple/`, `templates/`, `playground/`: scaffolding and local
examples
- `website/`, `website-new/`, `website-tsrx/`: documentation and website work
When routing a change, prefer the package that directly owns the behavior rather
than editing generated output, tests, or editor integrations first.
## Current Working Assumptions
- Default component files are `.tsrx`. Do not describe the project as primarily
using `.ripple` files unless the local file you are editing actually does.
- Some packages still preserve compatibility or historical references. Treat them
as compatibility context, not the default architecture description.
- Use `pnpm` for all package management and workspace scripts.
- Follow the conventions of the package you are changing. This repo mixes plain
JavaScript, JSDoc-typed JavaScript, and TypeScript depending on package.
- Match nearby naming, file layout, and test style instead of applying a single
convention repo-wide.
## Finding The Right Package
Use these rough routing rules:
- Ripple syntax, parsing, source transforms, or shared AST behavior:
`packages/tsrx/` and the relevant target package under `packages/tsrx-*`
- Ripple runtime behavior, hydration, reactivity, DOM updates, or server output:
`packages/ripple/`
- Vite, Rollup, Rspack, Turbopack, or adapter behavior: the relevant plugin or
adapter package in `packages/`
- Diagnostics, completions, hover, definitions, or editor integration:
`packages/language-server/`, `packages/typescript-plugin/`, and editor plugin
packages
- Formatting or lint behavior: `packages/prettier-plugin/`,
`packages/prettier-plugin-ripple/`, `packages/eslint-parser/`, or
`packages/eslint-plugin/`
## Validation
Prefer the smallest validation that covers the touched surface.
Common workspace commands:
```bash
pnpm rules:generate
pnpm format:check
pnpm test
pnpm test --project ripple-client
pnpm test --project ripple-server
pnpm typecheck
```
Current Vitest projects are defined in `vitest.config.js`. Ripple runtime suites
use `.test.tsrx` files for many client, server, and compat tests, while tooling
packages often use `.test.js` or `.test.ts`.
## Changesets
Add a changeset for user-facing package changes. Skip changesets for docs-only,
test-only, and internal tooling updates.
Only use `patch` changesets. Do not use `minor` or `major` bump types in this
repo; prerelease packages must stay on the patch track until a release plan
explicitly changes that policy.
```bash
pnpm changeset
```
Validate pending changesets before versioning or publishing:
```bash
pnpm changeset:check
```
## Practical Guidance For Agents
- Prefer the current docs in `website/public/llms.txt` over stale architectural
summaries.
- Avoid copying removed compiler APIs, old package layouts, or legacy `.ripple`
examples into new guidance.
- If you need exact behavior, read the owning package and its tests instead of
relying on a repo-wide summary.
- Keep documentation updates short and durable. High-level guidance ages better
than detailed internal call lists.
## /.vscode/launch.json
```json path="/.vscode/launch.json"
{
"version": "0.2.1",
"configurations": [
{
"name": "VSCode Extension",
"type": "extensionHost",
"request": "launch",
"autoAttachChildProcesses": true,
"preLaunchTask": "build-vscode-plugin",
"args": [
"--disable-extension=ripple-ts.ripple-ts-vscode-plugin",
"--extensionDevelopmentPath=${workspaceFolder}/packages/vscode-plugin/",
"${workspaceFolder}/playground"
],
"outFiles": ["${workspaceFolder}/packages/vscode-plugin/dist/**/*.js"],
"sourceMaps": true,
"env": {
"RIPPLE_DEBUG": "true"
}
},
{
"name": "Ripple Tests - Current Tab",
"type": "node",
"request": "launch",
"runtimeExecutable": "pnpm",
"runtimeArgs": [
"run",
"test",
"${relativeFile}",
"-t",
"${input:rippeTestNamePattern}",
"--",
"--inspect-brk",
"--no-file-parallelism"
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Ripple Tests - File Path",
"type": "node",
"request": "launch",
"runtimeExecutable": "pnpm",
"runtimeArgs": [
"run",
"test",
"${input:rippleTestFile}",
"-t",
"${input:rippeTestNamePattern}",
"--",
"--inspect-brk",
"--no-file-parallelism"
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Volar Codegen / Mappings",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}/playground",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["run", "debug-volar"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"skipFiles": ["<node_internals>/**"]
},
{
"name": "SSR Rendering",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}/playground",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["run", "debug-ssr"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"skipFiles": ["<node_internals>/**"]
},
{
"name": "SSR Runtime - From Compiled",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}/playground",
"program": "${workspaceFolder}/playground/ssr-dev.js",
"env": {
"DEBUG_APP": "true"
},
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Client Rendering",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}/playground",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["run", "debug-client"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Client Runtime - Vite",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}/playground",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["run", "dev"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"presentation": {
"hidden": true
}
},
{
"name": "Client Runtime - Browser",
"type": "chrome",
"request": "launch",
"url": "http://localhost:5173",
"webRoot": "${workspaceFolder}/playground",
"runtimeArgs": [
"--auto-open-devtools-for-tabs",
"--user-data-dir=${workspaceFolder}/.vscode/chrome-client-debug-profile"
],
"pathMapping": {
"/@fs/": "/"
},
"resolveSourceMapLocations": null,
"presentation": {
"hidden": true
},
"preLaunchTask": "client-runtime-prelaunch"
},
{
"name": "Vite Plugin",
"type": "node",
"request": "launch",
"console": "integratedTerminal",
"cwd": "${workspaceFolder}/playground",
"runtimeExecutable": "node",
"runtimeArgs": ["--inspect"],
"program": "${workspaceFolder}/playground/node_modules/vite/bin/vite.js",
"args": ["--host"],
"autoAttachChildProcesses": true,
"skipFiles": ["<node_internals>/**"],
"sourceMaps": true,
"presentation": {
"hidden": true
}
}
],
"compounds": [
{
"name": "Client Runtime - From Source",
"configurations": ["Client Runtime - Vite", "Client Runtime - Browser"],
"stopAll": true
},
{
"name": "Vite Plugin - Client",
"configurations": ["Vite Plugin"],
"stopAll": true
}
],
"inputs": [
{
"id": "rippleTestFile",
"type": "promptString",
"description": "Test file path",
"default": "${relativeFile}"
},
{
"id": "rippeTestNamePattern",
"type": "promptString",
"description": "(Optional): Test name pattern to match",
"default": ""
}
]
}
```
## /.vscode/settings.json
```json path="/.vscode/settings.json"
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.detectIndentation": false,
"editor.formatOnSave": true,
"editor.insertSpaces": false,
"editor.tabSize": 2,
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true,
"files.exclude": {
"**/.build-hash": true,
"**/.build-hash-built": true
},
"prettier.requireConfig": true,
"js/ts.implicitProjectConfig.checkJs": true,
"js/ts.preferences.preferTypeOnlyAutoImports": true,
"js/ts.preferences.useAliasesForRenames": false,
"js/ts.preferences.importModuleSpecifierEnding": "js",
"js/ts.experimental.useTsgo": true,
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.insertSpaces": true
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.insertSpaces": true
},
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.insertSpaces": true
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"cSpell.words": ["esrap", "tsrx", "tstc", "tstt", "zimmerframe"]
}
```
## /.vscode/tasks.json
```json path="/.vscode/tasks.json"
{
"version": "2.0.0",
"tasks": [
{
"label": "wait-for-vite",
"type": "process",
"command": "pnpm",
"args": ["exec", "wait-on", "tcp:5173", "-d", "0"],
"problemMatcher": []
},
{
"label": "delete-client-chrome-debug-profile",
"type": "shell",
"command": "rm -rf .vscode/chrome-client-debug-profile"
},
{
"label": "client-runtime-prelaunch",
"dependsOn": ["delete-client-chrome-debug-profile", "wait-for-vite"],
"dependsOrder": "parallel"
},
{
"label": "build-vscode-plugin",
"type": "shell",
"command": "node scripts/build-if-changed.js packages/typescript-plugin packages/language-server packages/vscode-plugin",
"options": {
"shell": {
"args": ["-i", "-c"]
}
},
"group": "build",
"problemMatcher": []
}
]
}
```
## /AGENTS.md
# Additional Conventions Beyond the Built-in Functions
As this project's AI coding tool, you must follow the additional conventions below, in addition to the built-in functions.
# Ripple Project Guide for AI Agents
Ripple is a TypeScript-first UI framework and monorepo maintained by Dominic
Gannaway. The current authoring format is centered on `.tsrx` files and the shared
TSRX compiler stack. Older `.ripple`-specific docs and compiler details still
exist in repo history and changelogs, but they are not the right default source of
truth for current work.
## Start From Current Sources
Use the nearest live source rather than historical summaries:
- `website/public/llms.txt` for current Ripple syntax, runtime APIs, and authoring
guidance
- `README.md` for project overview, positioning, and quick-start examples
- `packages/*/README.md` for package-specific usage and public APIs
- `vitest.config.js` for the current test projects and file globs
- `package.json` for workspace-wide scripts such as `rules:generate`, `test`,
`format`, `format:check`, and `typecheck`
If a guide in this repo conflicts with nearby code or package READMEs, trust the
nearby code and current package docs.
## RuleSync
This repository uses RuleSync as the single source of truth for shared AI agent
instructions. Edit `.rulesync/rules/` and regenerate derived files instead of
patching generated outputs directly.
Generated targets include:
- `AGENTS.md`
- `.github/copilot-instructions.md`
- `CLAUDE.md`
- `GEMINI.md`
- `.cursor/rules/project.mdc`
After changing RuleSync content, run:
```bash
pnpm rules:generate
```
## Monorepo Map
This is a pnpm monorepo. The current high-level layout is:
- `packages/tsrx/`: core parser, transforms, and shared compiler infrastructure
- `packages/tsrx-ripple/`, `packages/tsrx-react/`, `packages/tsrx-solid/`,
`packages/tsrx-preact/`: target-specific compiler layers
- `packages/ripple/`: Ripple runtime, server helpers, and framework behavior
- `packages/vite-plugin/`, `packages/rollup-plugin/`,
`packages/vite-plugin-react/`, `packages/vite-plugin-solid/`,
`packages/vite-plugin-preact/`, `packages/rspack-plugin-react/`,
`packages/turbopack-plugin-react/`: bundler integrations
- `packages/adapter/`, `packages/adapter-node/`, `packages/adapter-bun/`,
`packages/adapter-vercel/`: deployment and platform adapters
- `packages/language-server/`, `packages/typescript-plugin/`,
`packages/vscode-plugin/`, `packages/intellij-plugin/`, `packages/nvim-plugin/`,
`packages/sublime-text-plugin/`, `packages/zed-plugin/`: editor and language
tooling
- `packages/eslint-parser/`, `packages/eslint-plugin/`,
`packages/prettier-plugin/`, `packages/prettier-plugin-ripple/`: linting and
formatting
- `packages/create-ripple/`, `templates/`, `playground/`: scaffolding and local
examples
- `website/`, `website-new/`, `website-tsrx/`: documentation and website work
When routing a change, prefer the package that directly owns the behavior rather
than editing generated output, tests, or editor integrations first.
## Current Working Assumptions
- Default component files are `.tsrx`. Do not describe the project as primarily
using `.ripple` files unless the local file you are editing actually does.
- Some packages still preserve compatibility or historical references. Treat them
as compatibility context, not the default architecture description.
- Use `pnpm` for all package management and workspace scripts.
- Follow the conventions of the package you are changing. This repo mixes plain
JavaScript, JSDoc-typed JavaScript, and TypeScript depending on package.
- Match nearby naming, file layout, and test style instead of applying a single
convention repo-wide.
## Finding The Right Package
Use these rough routing rules:
- Ripple syntax, parsing, source transforms, or shared AST behavior:
`packages/tsrx/` and the relevant target package under `packages/tsrx-*`
- Ripple runtime behavior, hydration, reactivity, DOM updates, or server output:
`packages/ripple/`
- Vite, Rollup, Rspack, Turbopack, or adapter behavior: the relevant plugin or
adapter package in `packages/`
- Diagnostics, completions, hover, definitions, or editor integration:
`packages/language-server/`, `packages/typescript-plugin/`, and editor plugin
packages
- Formatting or lint behavior: `packages/prettier-plugin/`,
`packages/prettier-plugin-ripple/`, `packages/eslint-parser/`, or
`packages/eslint-plugin/`
## Validation
Prefer the smallest validation that covers the touched surface.
Common workspace commands:
```bash
pnpm rules:generate
pnpm format:check
pnpm test
pnpm test --project ripple-client
pnpm test --project ripple-server
pnpm typecheck
```
Current Vitest projects are defined in `vitest.config.js`. Ripple runtime suites
use `.test.tsrx` files for many client, server, and compat tests, while tooling
packages often use `.test.js` or `.test.ts`.
## Changesets
Add a changeset for user-facing package changes. Skip changesets for docs-only,
test-only, and internal tooling updates.
Only use `patch` changesets. Do not use `minor` or `major` bump types in this
repo; prerelease packages must stay on the patch track until a release plan
explicitly changes that policy.
```bash
pnpm changeset
```
Validate pending changesets before versioning or publishing:
```bash
pnpm changeset:check
```
## Practical Guidance For Agents
- Prefer the current docs in `website/public/llms.txt` over stale architectural
summaries.
- Avoid copying removed compiler APIs, old package layouts, or legacy `.ripple`
examples into new guidance.
- If you need exact behavior, read the owning package and its tests instead of
relying on a repo-wide summary.
- Keep documentation updates short and durable. High-level guidance ages better
than detailed internal call lists.
## /CLAUDE.md
# Ripple Project Guide for AI Agents
Ripple is a TypeScript-first UI framework and monorepo maintained by Dominic
Gannaway. The current authoring format is centered on `.tsrx` files and the shared
TSRX compiler stack. Older `.ripple`-specific docs and compiler details still
exist in repo history and changelogs, but they are not the right default source of
truth for current work.
## Start From Current Sources
Use the nearest live source rather than historical summaries:
- `website/public/llms.txt` for current Ripple syntax, runtime APIs, and authoring
guidance
- `README.md` for project overview, positioning, and quick-start examples
- `packages/*/README.md` for package-specific usage and public APIs
- `vitest.config.js` for the current test projects and file globs
- `package.json` for workspace-wide scripts such as `rules:generate`, `test`,
`format`, `format:check`, and `typecheck`
If a guide in this repo conflicts with nearby code or package READMEs, trust the
nearby code and current package docs.
## RuleSync
This repository uses RuleSync as the single source of truth for shared AI agent
instructions. Edit `.rulesync/rules/` and regenerate derived files instead of
patching generated outputs directly.
Generated targets include:
- `AGENTS.md`
- `.github/copilot-instructions.md`
- `CLAUDE.md`
- `GEMINI.md`
- `.cursor/rules/project.mdc`
After changing RuleSync content, run:
```bash
pnpm rules:generate
```
## Monorepo Map
This is a pnpm monorepo. The current high-level layout is:
- `packages/tsrx/`: core parser, transforms, and shared compiler infrastructure
- `packages/tsrx-ripple/`, `packages/tsrx-react/`, `packages/tsrx-solid/`,
`packages/tsrx-preact/`: target-specific compiler layers
- `packages/ripple/`: Ripple runtime, server helpers, and framework behavior
- `packages/vite-plugin/`, `packages/rollup-plugin/`,
`packages/vite-plugin-react/`, `packages/vite-plugin-solid/`,
`packages/vite-plugin-preact/`, `packages/rspack-plugin-react/`,
`packages/turbopack-plugin-react/`: bundler integrations
- `packages/adapter/`, `packages/adapter-node/`, `packages/adapter-bun/`,
`packages/adapter-vercel/`: deployment and platform adapters
- `packages/language-server/`, `packages/typescript-plugin/`,
`packages/vscode-plugin/`, `packages/intellij-plugin/`, `packages/nvim-plugin/`,
`packages/sublime-text-plugin/`, `packages/zed-plugin/`: editor and language
tooling
- `packages/eslint-parser/`, `packages/eslint-plugin/`,
`packages/prettier-plugin/`, `packages/prettier-plugin-ripple/`: linting and
formatting
- `packages/create-ripple/`, `templates/`, `playground/`: scaffolding and local
examples
- `website/`, `website-new/`, `website-tsrx/`: documentation and website work
When routing a change, prefer the package that directly owns the behavior rather
than editing generated output, tests, or editor integrations first.
## Current Working Assumptions
- Default component files are `.tsrx`. Do not describe the project as primarily
using `.ripple` files unless the local file you are editing actually does.
- Some packages still preserve compatibility or historical references. Treat them
as compatibility context, not the default architecture description.
- Use `pnpm` for all package management and workspace scripts.
- Follow the conventions of the package you are changing. This repo mixes plain
JavaScript, JSDoc-typed JavaScript, and TypeScript depending on package.
- Match nearby naming, file layout, and test style instead of applying a single
convention repo-wide.
## Finding The Right Package
Use these rough routing rules:
- Ripple syntax, parsing, source transforms, or shared AST behavior:
`packages/tsrx/` and the relevant target package under `packages/tsrx-*`
- Ripple runtime behavior, hydration, reactivity, DOM updates, or server output:
`packages/ripple/`
- Vite, Rollup, Rspack, Turbopack, or adapter behavior: the relevant plugin or
adapter package in `packages/`
- Diagnostics, completions, hover, definitions, or editor integration:
`packages/language-server/`, `packages/typescript-plugin/`, and editor plugin
packages
- Formatting or lint behavior: `packages/prettier-plugin/`,
`packages/prettier-plugin-ripple/`, `packages/eslint-parser/`, or
`packages/eslint-plugin/`
## Validation
Prefer the smallest validation that covers the touched surface.
Common workspace commands:
```bash
pnpm rules:generate
pnpm format:check
pnpm test
pnpm test --project ripple-client
pnpm test --project ripple-server
pnpm typecheck
```
Current Vitest projects are defined in `vitest.config.js`. Ripple runtime suites
use `.test.tsrx` files for many client, server, and compat tests, while tooling
packages often use `.test.js` or `.test.ts`.
## Changesets
Add a changeset for user-facing package changes. Skip changesets for docs-only,
test-only, and internal tooling updates.
Only use `patch` changesets. Do not use `minor` or `major` bump types in this
repo; prerelease packages must stay on the patch track until a release plan
explicitly changes that policy.
```bash
pnpm changeset
```
Validate pending changesets before versioning or publishing:
```bash
pnpm changeset:check
```
## Practical Guidance For Agents
- Prefer the current docs in `website/public/llms.txt` over stale architectural
summaries.
- Avoid copying removed compiler APIs, old package layouts, or legacy `.ripple`
examples into new guidance.
- If you need exact behavior, read the owning package and its tests instead of
relying on a repo-wide summary.
- Keep documentation updates short and durable. High-level guidance ages better
than detailed internal call lists.
## /CODE_OF_CONDUCT.md
# Code of Conduct
This project is built by people who want to create something cool together. Let's
keep it fun, welcoming, focused, and worth everyone's time.
### Do
- **Be respectful** — Treat everyone with kindness. We're all here because we care
about the project.
- **Bring real value** — Make contributions that help the project move forward:
thoughtful code, clear docs, useful bug reports, or constructive ideas. When
submitting pull requests, focus on solving real problems or improving things for
users/maintainers—not just adding your name to the contributors list. Small,
high-quality changes beat big, low-effort ones every time.
- **Own your code** — If you're using AI tools to help write or suggest code,
review it carefully, understand it fully, test it, and make it your own.
Unreviewed or barely-touched AI output is just noise—don't spam the project with
it.
- **Stay on topic** — Keep discussions, issues, and PRs related to the project.
Save off-topic stuff for somewhere else.
- **Give constructive feedback** — Point out problems kindly and suggest fixes
when you can. We're all learning.
- **Assume good intent** — People usually mean well. If something feels off, ask
for clarification before assuming the worst.
- **Have fun and be excellent to each other** — Celebrate wins, thank people, and
enjoy the ride.
### Don't
- **Spam** — No drive-by comments, promo links, unrelated noise, or low-effort PRs
(including untouched AI-generated ones).
- **Harass or attack** — No insults, slurs, threats, personal attacks, or
unwelcome advances. Ever.
- **Troll** — Don't derail conversations or pick fights.
- **Push big drama** — If there's conflict, try to resolve it privately or with a
maintainer first.
### If something goes wrong
If you see behavior that breaks these guidelines, or you feel uncomfortable, reach
out on Discord: https://discord.gg/JBF2ySrh2W. We'll listen, handle it fairly, and
keep things confidential if needed. Maintainers can warn, remove comments/PRs, or
ban repeat offenders.
Thanks for helping make this a great place to collaborate. Let's build something
awesome together!
## /CONTRIBUTING.md
# Contributing to Ripple
Ripple is a TypeScript UI framework that combines the best parts of React, Solid,
and Svelte into one cohesive package. Built as a love letter to frontend
development, Ripple introduces a JS/TS-first approach with `.ripple` modules that
provide an excellent developer experience for both humans and LLMs.
The [Open Source Guides](https://opensource.guide/) website offers valuable
resources for individuals, communities, and companies looking to contribute to
open source projects. Both newcomers and experienced contributors will find these
guides particularly helpful:
- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/)
- [Building Welcoming Communities](https://opensource.guide/building-community/)
## Ways to Get Involved
There are numerous ways to contribute to Ripple, and many don't require writing
code. Here are some ideas to get started:
- **Start experimenting with Ripple**: Try out the
[Ripple Playground](https://www.ripplejs.com/playground) and see how it works.
If you encounter issues or unexpected behavior, we'd love to hear about it
through [opening an issue](#reporting-issues).
- **Browse existing issues**: Check out our
[open issues](https://github.com/Ripple-TS/ripple/issues). You can help by
providing workarounds or asking clarifying questions.
- **Submit fixes**: Found an issue you'd like to tackle? Consider
[opening a pull request](#pull-requests).
- **Help with documentation**: As Ripple grows, we'll need comprehensive
documentation. Any help improving clarity or filling gaps would be greatly
appreciated.
We welcome all contributions! If you need guidance in planning your contribution,
please reach out on our Discord server and let us know you're looking for some
direction.
### Issue Triage
A fantastic way to contribute without coding is helping triage issues and pull
requests:
- Request additional information when issues lack sufficient detail for
resolution.
- Identify stale issues that should be updated or closed.
- Review code and suggest improvements.
- Help organize and categorize incoming issues.
## Development Process
### Planning Major Changes
For significant new features or substantial changes, we encourage discussion
before implementation. While we don't have a formal RFC process yet, please open
an issue to discuss your ideas with the maintainers and community first.
### Current Focus
Ripple is in early alpha, so our priorities are:
1. Stabilizing core functionality
2. Improving TypeScript integration (note that the internal codebase is still
being migrated from JS, so some TypeScript errors are expected)
3. Expanding test coverage
4. Building and maintaining essential tooling
Keep in mind that this is a very early-stage project, so expect frequent changes
and some rough edges.
### Communication
Since Ripple is a new project with a small team, we'll do our best to respond to
issues and PRs promptly. Join [our Discord server](https://discord.gg/JBF2ySrh2W)
for real-time discussion and updates.
## Reporting Issues
We track bugs using [GitHub issues](https://github.com/Ripple-TS/ripple/issues).
Before reporting a new issue, please check if someone has already reported the
same problem.
For questions about using Ripple, our Discord server is the best place to get help
and connect with other developers.
### Creating Bug Reports
When [opening a new issue](https://github.com/Ripple-TS/ripple/issues/new), please
include:
- **Clear description**: Explain what you expected to happen and what actually
occurred.
- **Reproduction steps**: Provide step-by-step instructions to reproduce the
issue.
- **Environment details**: Include your operating system, Node.js version, and any
relevant setup information.
- **Minimal example**: If possible, create a minimal reproduction case that
demonstrates the problem.
**Important guidelines:**
- Report one bug per issue
- Be as specific as possible
- Include code samples when relevant
## Pull Requests
### Before You Start
For bug fixes, feel free to submit a pull request directly, but we recommend
filing an issue first to discuss the problem and proposed solution.
For new features, please open an issue to discuss the implementation before
starting work. This helps ensure your contribution aligns with the project's
direction.
Keep pull requests focused and reasonably sized for easier review.
### Development Setup
You'll need [Node.js](https://nodejs.org/) and
[pnpm](https://pnpm.io/installation) installed.
1. Fork the repository
2. Clone your fork locally
3. Run `pnpm install` to install dependencies
4. Create a new branch from `main` for your changes
### Development Workflow
Since Ripple is in development, the build process may evolve. Currently:
- Run development builds and watch for changes as needed
- Test your changes thoroughly
- Ensure TypeScript compilation succeeds (if working with TS code)
### Testing
While our test suite is still being developed, please:
- Test your changes manually
- Verify that existing functionality still works
- Include test cases for new features when possible
- Document your testing approach in the PR description
### Code Style
We'll be implementing consistent code formatting soon. For now:
- Follow existing code patterns in the repository
- Use meaningful variable and function names
- Include appropriate comments for complex logic
- Maintain TypeScript types where applicable
### Submitting Your PR
Before submitting:
1. **Test thoroughly**: Ensure your changes work as expected
2. **Write clear commit messages**: Describe what and why, not just what
3. **Update documentation**: If you've changed APIs or added features
4. **Add a changeset**: For user-facing changes (see below)
5. **Target the main branch**: All PRs should be opened against `main`
6. **Keep it focused**: One feature or fix per PR
### Changesets
We use [Changesets](https://github.com/changesets/changesets) to manage versioning
and changelogs. If your PR includes user-facing changes (bug fixes, new features,
breaking changes), you should add a changeset:
```bash
pnpm changeset
```
This will prompt you to:
1. Select the packages affected by your change
2. Choose the semver bump type (patch/minor/major)
3. Write a summary of your changes (this becomes the changelog entry)
The command creates a markdown file in `.changeset/` that should be committed with
your PR. When your PR is merged, the release workflow will automatically:
1. Aggregate all changesets into a "Version Packages" PR
2. When that PR is merged, publish to npm
**When to add a changeset:**
- Bug fixes → `patch`
- New features (backwards compatible) → `minor`
- Breaking changes → `major`
**When NOT to add a changeset:**
- Documentation-only changes
- Internal refactoring with no user-facing impact
- Test-only changes
- CI/tooling changes
Include in your PR description:
- Summary of changes
- Testing performed
- Any breaking changes
- Related issue numbers
## Development Guidelines
### Code Conventions
Since Ripple is TypeScript-first:
- Prioritize type safety
- Use descriptive names for variables and functions
- Follow existing patterns in the codebase
- Comment complex logic clearly
### Commit Messages
Write clear, descriptive commit messages that explain both what changed and why.
## License
By contributing to Ripple, you agree that your contributions will be licensed
under the same license as the project. [MIT License](./LICENSE)
## Getting Help
- **Discord**: Join [our community server](https://discord.gg/JBF2ySrh2W) for
real-time discussion
- **GitHub Issues**: For bugs and feature requests
- **GitHub Discussions**: For general questions and ideas (when available)
We're excited to have you contribute to Ripple's development! Even though the
project is young, every contribution helps shape its future.
## /GEMINI.md
# Additional Conventions Beyond the Built-in Functions
As this project's AI coding tool, you must follow the additional conventions below, in addition to the built-in functions.
# Ripple Project Guide for AI Agents
Ripple is a TypeScript-first UI framework and monorepo maintained by Dominic
Gannaway. The current authoring format is centered on `.tsrx` files and the shared
TSRX compiler stack. Older `.ripple`-specific docs and compiler details still
exist in repo history and changelogs, but they are not the right default source of
truth for current work.
## Start From Current Sources
Use the nearest live source rather than historical summaries:
- `website/public/llms.txt` for current Ripple syntax, runtime APIs, and authoring
guidance
- `README.md` for project overview, positioning, and quick-start examples
- `packages/*/README.md` for package-specific usage and public APIs
- `vitest.config.js` for the current test projects and file globs
- `package.json` for workspace-wide scripts such as `rules:generate`, `test`,
`format`, `format:check`, and `typecheck`
If a guide in this repo conflicts with nearby code or package READMEs, trust the
nearby code and current package docs.
## RuleSync
This repository uses RuleSync as the single source of truth for shared AI agent
instructions. Edit `.rulesync/rules/` and regenerate derived files instead of
patching generated outputs directly.
Generated targets include:
- `AGENTS.md`
- `.github/copilot-instructions.md`
- `CLAUDE.md`
- `GEMINI.md`
- `.cursor/rules/project.mdc`
After changing RuleSync content, run:
```bash
pnpm rules:generate
```
## Monorepo Map
This is a pnpm monorepo. The current high-level layout is:
- `packages/tsrx/`: core parser, transforms, and shared compiler infrastructure
- `packages/tsrx-ripple/`, `packages/tsrx-react/`, `packages/tsrx-solid/`,
`packages/tsrx-preact/`: target-specific compiler layers
- `packages/ripple/`: Ripple runtime, server helpers, and framework behavior
- `packages/vite-plugin/`, `packages/rollup-plugin/`,
`packages/vite-plugin-react/`, `packages/vite-plugin-solid/`,
`packages/vite-plugin-preact/`, `packages/rspack-plugin-react/`,
`packages/turbopack-plugin-react/`: bundler integrations
- `packages/adapter/`, `packages/adapter-node/`, `packages/adapter-bun/`,
`packages/adapter-vercel/`: deployment and platform adapters
- `packages/language-server/`, `packages/typescript-plugin/`,
`packages/vscode-plugin/`, `packages/intellij-plugin/`, `packages/nvim-plugin/`,
`packages/sublime-text-plugin/`, `packages/zed-plugin/`: editor and language
tooling
- `packages/eslint-parser/`, `packages/eslint-plugin/`,
`packages/prettier-plugin/`, `packages/prettier-plugin-ripple/`: linting and
formatting
- `packages/create-ripple/`, `templates/`, `playground/`: scaffolding and local
examples
- `website/`, `website-new/`, `website-tsrx/`: documentation and website work
When routing a change, prefer the package that directly owns the behavior rather
than editing generated output, tests, or editor integrations first.
## Current Working Assumptions
- Default component files are `.tsrx`. Do not describe the project as primarily
using `.ripple` files unless the local file you are editing actually does.
- Some packages still preserve compatibility or historical references. Treat them
as compatibility context, not the default architecture description.
- Use `pnpm` for all package management and workspace scripts.
- Follow the conventions of the package you are changing. This repo mixes plain
JavaScript, JSDoc-typed JavaScript, and TypeScript depending on package.
- Match nearby naming, file layout, and test style instead of applying a single
convention repo-wide.
## Finding The Right Package
Use these rough routing rules:
- Ripple syntax, parsing, source transforms, or shared AST behavior:
`packages/tsrx/` and the relevant target package under `packages/tsrx-*`
- Ripple runtime behavior, hydration, reactivity, DOM updates, or server output:
`packages/ripple/`
- Vite, Rollup, Rspack, Turbopack, or adapter behavior: the relevant plugin or
adapter package in `packages/`
- Diagnostics, completions, hover, definitions, or editor integration:
`packages/language-server/`, `packages/typescript-plugin/`, and editor plugin
packages
- Formatting or lint behavior: `packages/prettier-plugin/`,
`packages/prettier-plugin-ripple/`, `packages/eslint-parser/`, or
`packages/eslint-plugin/`
## Validation
Prefer the smallest validation that covers the touched surface.
Common workspace commands:
```bash
pnpm rules:generate
pnpm format:check
pnpm test
pnpm test --project ripple-client
pnpm test --project ripple-server
pnpm typecheck
```
Current Vitest projects are defined in `vitest.config.js`. Ripple runtime suites
use `.test.tsrx` files for many client, server, and compat tests, while tooling
packages often use `.test.js` or `.test.ts`.
## Changesets
Add a changeset for user-facing package changes. Skip changesets for docs-only,
test-only, and internal tooling updates.
Only use `patch` changesets. Do not use `minor` or `major` bump types in this
repo; prerelease packages must stay on the patch track until a release plan
explicitly changes that policy.
```bash
pnpm changeset
```
Validate pending changesets before versioning or publishing:
```bash
pnpm changeset:check
```
## Practical Guidance For Agents
- Prefer the current docs in `website/public/llms.txt` over stale architectural
summaries.
- Avoid copying removed compiler APIs, old package layouts, or legacy `.ripple`
examples into new guidance.
- If you need exact behavior, read the owning package and its tests instead of
relying on a repo-wide summary.
- Keep documentation updates short and durable. High-level guidance ages better
than detailed internal call lists.
## /README.md
<a href="https://ripplejs.com">
<picture>
<source media="(min-width: 768px)" srcset="assets/ripple-desktop.png">
<img src="assets/ripple-mobile.png" alt="Ripple - the elegant TypeScript UI framework" />
</picture>
</a>
[](https://github.com/Ripple-TS/ripple/actions/workflows/ci.yml)
[](https://discord.gg/JBF2ySrh2W)
[](https://stackblitz.com/github/Ripple-TS/ripple/tree/main/templates/basic)
# Ripple TS
Ripple is a TypeScript UI framework that combines the best parts of React, Solid,
and Svelte. Created by [@trueadm](https://github.com/trueadm), who has contributed
to [Inferno](https://github.com/infernojs/inferno),
[React](https://github.com/facebook/react),
[Lexical](https://github.com/facebook/lexical), and
[Svelte 5](https://github.com/sveltejs/svelte).
**Key Philosophy:** Ripple is TS-first with `.tsrx` as its default component file
extension. This allows seamless TypeScript integration and a unique syntax that
enhances both human and LLM developer experience.
> **`.tsrx` is also a standalone language:** the same source can now compile to
> React, Solid, or Ripple via [TSRX](https://tsrx.dev) — a TypeScript language
> extension that treats Ripple as one of several target runtimes. If you want the
> authoring ergonomics without committing to Ripple's runtime, start there.
📚 **[Ripple Docs](https://www.ripple-ts.com/docs)** | 🎮
**[Ripple Playground](https://www.ripple-ts.com/playground)** | 🧩
**[TSRX Website](https://tsrx.dev)**
## Features
- ⚡ **Fine-grained Reactivity**: `track` with lazy destructuring for a unique
reactivity system
- 🔥 **Performance**: Industry-leading rendering speed, bundle size, and memory
usage
- 📦 **Reactive Collections**: `RippleArray`, `RippleObject`, `RippleMap`,
`RippleSet` imported from `'ripple'` with full reactivity
- 🎯 **TypeScript First**: Complete type safety with the default `.tsrx` component
extension
- 🛠️ **Developer Tools**: VSCode extension, Prettier, and ESLint support
- 🎨 **Scoped Styling**: Component-level CSS with automatic scoping
## 🚀 Quick Start
### Using CLI (Recommended)
```bash
npx create-ripple
cd my-app
npm install && npm run dev
```
### Using Template
```bash
npx degit Ripple-TS/ripple/templates/basic my-app
cd my-app
npm install && npm run dev
```
### Add to Existing Project
```bash
npm install ripple @ripple-ts/vite-plugin
```
> **Note:** You can use `npm`, `pnpm`, `yarn`, or `bun` package managers.
**[→ Full Installation Guide](https://www.ripple-ts.com/docs/quick-start)**
### Mounting Your App
```ts
// index.ts
import { mount } from 'ripple';
import { App } from './App.tsrx';
mount(App, {
props: { title: 'Hello world!' },
target: document.getElementById('root'),
});
```
## 🔧 VSCode Extension
Install the
[Ripple VSCode extension](https://marketplace.visualstudio.com/items?itemName=Ripple-TS.ripple-ts-vscode-plugin)
for:
- Syntax highlighting
- TypeScript integration
- Real-time diagnostics
- IntelliSense autocomplete
**[→ Editor Setup Guide](https://www.ripple-ts.com/docs/quick-start#vs-code)**
## Core Concepts
### Components
Define components with the `component` keyword. Unlike React, you don't return
JSX—you write it directly:
```jsx
component Button(props: { text: string, onClick: () => void }) {
<button onClick={props.onClick}>
{props.text}
</button>
}
export component App() {
<Button text="Click me" onClick={() => console.log("Clicked!")} />
}
```
**[→ Component Guide](https://www.ripple-ts.com/docs/guide/components)**
### Reactivity
Create reactive state with `track` and use lazy destructuring (`&[]`) to access
the value directly:
```jsx
import { track } from 'ripple';
export component App() {
let &[count] = track(0);
<div>
<p>"Count: "{count}</p>
<button onClick={() => count++}>"Increment"</button>
</div>
}
```
You can also pass around the tracked value object from the second argument:
```jsx
import { track } from 'ripple';
export component App() {
let &[count, trackedCount] = track(0);
<div>{count}</div>
<IncrementButton {trackedCount} />
}
```
Alternatively, you can read and write tracked values directly using the `.value`
property on the `Tracked<V>` object:
```jsx
import { track } from 'ripple';
export component App() {
const count = track(0);
<div>{count.value}</div>
<button onClick={() => count.value++}>"Increment"</button>
}
```
Using `&[...]` is preferred in most cases for cleaner code, but `.value` is useful
when you need to keep the `Tracked<V>` object around — for example, when storing
tracked values in data structures or passing them as `Tracked<T>` props.
**Derived values** automatically update:
```jsx
import { track } from 'ripple';
export component App() {
let &[count] = track(0);
let &[double] = track(() => count * 2);
let &[quadruple] = track(() => double * 2);
<div>
<p>"Count: "{count}</p>
<p>"Double: "{double}</p>
<p>"Quadruple: "{quadruple}</p>
<button onClick={() => count++}>"Increment"</button>
</div>
}
```
**Reactive collections** with full reactivity:
```jsx
import { RippleArray, RippleObject, RippleMap, RippleSet } from 'ripple';
export component App() {
const items = new RippleArray(1, 2, 3); // RippleArray
const obj = new RippleObject({ a: 1, b: 2 }); // RippleObject
const map = new RippleMap([['k', 'v']]); // RippleMap
const set = new RippleSet([1, 2, 3]); // RippleSet
<div>
<p>"Items: "{items.join(', ')}</p>
<p>"Object: a="{obj.a}", b="{obj.b}", c="{obj.c}</p>
<button onClick={() => items.push(items.length + 1)}>"Add Item"</button>
<button onClick={() => obj.c = (obj.c ?? 0) + 1}>"Increment c"</button>
</div>
}
```
**[→ Reactivity Guide](https://www.ripple-ts.com/docs/guide/reactivity)**
### Transporting Reactivity
Pass the tracked ref (second element) across function boundaries:
```jsx
import { track } from 'ripple';
function createDouble(&[count]) {
return track(() => count * 2);
}
export component App() {
let &[count, countTracked] = track(0);
const &[double] = createDouble(countTracked);
<div>
<p>"Double: "{double}</p>
<button onClick={() => count++}>"Increment"</button>
</div>
}
```
**[→ Transporting Reactivity Guide](https://www.ripple-ts.com/docs/guide/reactivity#transporting-reactivity)**
### Effects & Side Effects
```jsx
import { track, effect } from 'ripple';
export component App() {
let &[count] = track(0);
effect(() => {
console.log('Count changed:', count);
});
<button onClick={() => count++}>"Increment"</button>
}
```
**[→ Effects & Reactivity Guide](https://www.ripple-ts.com/docs/guide/reactivity#effects)**
### Control Flow
**Conditionals:**
```jsx
import { track } from 'ripple';
export component App() {
let &[condition] = track(true);
<div>
if (condition) {
<div>"True"</div>
} else {
<div>"False"</div>
}
<button onClick={() => condition = !condition}>"Toggle"</button>
</div>
}
```
**Loops:**
```jsx
import { RippleArray } from 'ripple';
export component App() {
const items = new RippleArray(
{id: 1, name: 'Item 1'},
{id: 2, name: 'Item 2'},
{id: 3, name: 'Item 3'}
);
<div>
for (const item of items; index i; key item.id) {
<div>{item.name}" (index: "{i}")"</div>
}
<button onClick={() => items.push({id: items.length + 1, name: `Item ${items.length + 1}`})}>"Add Item"</button>
</div>
}
```
**Error Boundaries:**
```jsx
component ComponentThatMayFail(props: { shouldFail: boolean }) {
if (props.shouldFail) {
throw new Error('Component failed!');
"This will never render"
}
<div>"Component working fine"</div>
}
import { track } from 'ripple';
export component App() {
let &[shouldFail] = track(false);
<div>
try {
<ComponentThatMayFail {shouldFail} />
} catch (e) {
<div>"Error: "{e.message}</div>
}
<button onClick={() => shouldFail = !shouldFail}>"Toggle Error"</button>
</div>
}
```
**[→ Control Flow Guide](https://www.ripple-ts.com/docs/guide/control-flow)**
### DOM Refs
Capture DOM elements with the `{ref fn}` syntax:
```jsx
export component App() {
<div {ref (node) => console.log(node)}>"Hello"</div>
}
```
**[→ DOM Refs Guide](https://www.ripple-ts.com/docs/guide/dom-refs)**
### Events
Use React-style event handlers:
```jsx
import { track } from 'ripple';
export component App() {
let &[value] = track('');
<div>
<button onClick={() => console.log('Clicked')}>"Click"</button>
<input onInput={(e) => value = e.target.value} />
<p>"You typed: "{value}</p>
</div>
}
```
**[→ Events Guide](https://www.ripple-ts.com/docs/guide/events)**
### Styling
**Scoped CSS:**
```jsx
export component App() {
<div class="container">"Content"</div>
<style>
.container {
padding: 1rem;
background: lightblue;
border-radius: 8px;
}
</style>
}
```
**Dynamic styles:**
```jsx
import { track } from 'ripple';
export component App() {
let &[color] = track('red');
<div>
<div style={{ color, fontWeight: 'bold' }}>"Styled text"</div>
<button onClick={() => color = color === 'red' ? 'blue' : 'red'}>"Toggle Color"</button>
</div>
}
```
**[→ Styling Guide](https://www.ripple-ts.com/docs/guide/styling)**
## Advanced Features
### Context API
Share state across the component tree:
```jsx
import { Context, track } from 'ripple';
const ThemeContext = new Context();
component Child() {
const &[theme] = ThemeContext.get();
<div>"Theme: "{theme}</div>
}
export component App() {
let &[theme, themeTracked] = track('light');
ThemeContext.set(themeTracked);
<div>
<Child />
<button onClick={() => theme = theme === 'light' ? 'dark' : 'light'}>"Toggle Theme"</button>
</div>
}
```
**[→ State Management Guide](https://www.ripple-ts.com/docs/guide/state-management#context)**
### Portals
Render content outside the component hierarchy:
```jsx
import { Portal, track } from 'ripple';
export component App() {
let &[showModal] = track(false);
<div>
<button onClick={() => showModal = !showModal}>"Toggle Modal"</button>
if (showModal) {
<Portal target={document.body}>
<div class="modal">
<p>"Modal content"</p>
<button onClick={() => showModal = false}>"Close"</button>
</div>
</Portal>
}
</div>
}
```
**[→ Portal & Component Guide](https://www.ripple-ts.com/docs/guide/components#portal-component)**
## Resources
- 📚 **[Full Documentation](https://www.ripple-ts.com/docs)** - Complete guide and
API reference
- 🎮 **[Interactive Playground](https://www.ripple-ts.com/playground)** - Try
Ripple in your browser
- 🧩 **[TSRX Website](https://tsrx.dev)** - Author `.tsrx` once, compile to React,
Solid, or Ripple
- 🐛 **[GitHub Issues](https://github.com/Ripple-TS/ripple/issues)** - Report bugs
or request features
- 💬 **[Discord Community](https://discord.gg/JBF2ySrh2W)** - Get help and discuss
Ripple
- 📦 **[npm Package](https://www.npmjs.com/package/ripple)** - Install from npm
## Contributing
Contributions are welcome! Please see our
[contributing guidelines](CONTRIBUTING.md).
## License
MIT License - see [LICENSE](LICENSE) for details.
## /assets/Ripple.tmbundle/README.md
This provides syntax highlighting for Ripple files in editors that support
TextMate grammars, such as WebStorm/IntelliJ and Sublime Text.
# Installation
1. Create a directory named `Ripple.tmbundle`.
2. Create a directory named `Syntaxes` inside the `Ripple.tmbundle` directory.
3. Save the [`ripple.tmLanguage`](./Syntaxes/ripple.tmLanguage) file into the
`Syntaxes` directory.
4. Install it:
- **WebStorm/IntelliJ**:
1. Save the [`info.plist`](./info.plist) file into the `Ripple.tmbundle`
directory.
2. Go to `Settings` > `Editor` > `TextMate Bundles`, click the `+` icon, and
select the `Ripple.tmbundle` directory.
3. All `.ripple` files should now have syntax highlighting.
- **Sublime Text**:
1. Go to `Preferences` > `Browse Packages`, and move the `Ripple.tmbundle`
directory into the opened folder.
2. You should now be able to select `Ripple` in `View` > `Syntax`.
## /assets/Ripple.tmbundle/info.plist
```plist path="/assets/Ripple.tmbundle/info.plist"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>name</key><string>Ripple</string>
</dict>
</plist>
```
## /assets/ripple-desktop.png
Binary file available at https://raw.githubusercontent.com/trueadm/ripple/refs/heads/main/assets/ripple-desktop.png
## /assets/ripple-mobile.png
Binary file available at https://raw.githubusercontent.com/trueadm/ripple/refs/heads/main/assets/ripple-mobile.png
## /benchmarks/package.json
```json path="/benchmarks/package.json"
{
"name": "ripple-benchmarks",
"private": true,
"type": "module",
"scripts": {
"bench": "node tracked-values.js"
},
"dependencies": {
"ripple": "workspace:*",
"tinybench": "^2.9.0"
}
}
```
## /benchmarks/tracked-values.js
```js path="/benchmarks/tracked-values.js"
import { Bench } from 'tinybench';
import { tracked, derived, get, set, root } from 'ripple/internal/client';
const SCALES = [10, 100, 1_000, 10_000, 100_000];
/**
* Run benchmarks for tracked value operations at a given scale.
* @param {number} n - Number of tracked values to create
*/
async function run_suite(n) {
console.log(`\n${'='.repeat(60)}`);
console.log(` Tracked Values Benchmark — n = ${n.toLocaleString()}`);
console.log(`${'='.repeat(60)}\n`);
/** @type {import('ripple/internal/client').Block} */
let block;
// Create a root block context (required by tracked/derived)
root(() => {
// Grab the block from the first tracked value we create inside root
const probe = tracked(0);
block = probe.b;
});
const bench = new Bench({
warmupIterations: 100,
iterations: 1000,
time: 2000,
});
// Pre-allocate arrays for setup/teardown
let values;
// ── Creation ──────────────────────────────────────────────
bench.add(`create ${n.toLocaleString()} tracked values`, () => {
const arr = new Array(n);
for (let i = 0; i < n; i++) {
arr[i] = tracked(i, block);
}
values = arr;
});
// ── Read ─────────────────────────────────────────────────
bench.add(
`read ${n.toLocaleString()} tracked values`,
() => {
let sum = 0;
for (let i = 0; i < values.length; i++) {
sum += get(values[i]);
}
return sum;
},
{
beforeAll() {
values = new Array(n);
for (let i = 0; i < n; i++) {
values[i] = tracked(i, block);
}
},
},
);
// ── Write ────────────────────────────────────────────────
bench.add(
`write ${n.toLocaleString()} tracked values`,
() => {
for (let i = 0; i < values.length; i++) {
set(values[i], i + 1);
}
},
{
beforeAll() {
values = new Array(n);
for (let i = 0; i < n; i++) {
values[i] = tracked(i, block);
}
},
beforeEach() {
// Reset values so set() detects a change each iteration
for (let i = 0; i < values.length; i++) {
values[i].__v = i;
}
},
},
);
// ── Write then Read (dirty-check path) ───────────────────
bench.add(
`write+read ${n.toLocaleString()} tracked values`,
() => {
for (let i = 0; i < values.length; i++) {
set(values[i], i + 1);
}
let sum = 0;
for (let i = 0; i < values.length; i++) {
sum += get(values[i]);
}
return sum;
},
{
beforeAll() {
values = new Array(n);
for (let i = 0; i < n; i++) {
values[i] = tracked(i, block);
}
},
beforeEach() {
for (let i = 0; i < values.length; i++) {
values[i].__v = i;
}
},
},
);
// ── Derived creation + read ──────────────────────────────
bench.add(
`create+read ${n.toLocaleString()} derived values`,
() => {
const arr = new Array(n);
for (let i = 0; i < n; i++) {
arr[i] = derived(() => get(values[i]) * 2, block);
}
let sum = 0;
for (let i = 0; i < arr.length; i++) {
sum += get(arr[i]);
}
return sum;
},
{
beforeAll() {
values = new Array(n);
for (let i = 0; i < n; i++) {
values[i] = tracked(i, block);
}
},
},
);
await bench.run();
console.table(
bench.tasks.map((task) => ({
Task: task.name,
'ops/sec': Math.round(task.result.hz).toLocaleString(),
'Mean (ms)': task.result.mean.toFixed(4),
'P75 (ms)': task.result.p75.toFixed(4),
'P99 (ms)': task.result.p99.toFixed(4),
Margin: `±${task.result.rme.toFixed(2)}%`,
Samples: task.result.samples.length,
})),
);
// ── Sanity check ─────────────────────────────────────────
const t = tracked(42, block);
if (get(t) !== 42) throw new Error('Sanity check failed: initial get');
set(t, 99);
if (get(t) !== 99) throw new Error('Sanity check failed: get after set');
const d = derived(() => get(t) * 2, block);
if (get(d) !== 198) throw new Error('Sanity check failed: derived get');
}
// ── Main ──────────────────────────────────────────────────────
console.log('Ripple Tracked Values Benchmark');
console.log(`Node ${process.version} — ${process.platform} ${process.arch}`);
console.log(`Date: ${new Date().toISOString()}`);
for (const n of SCALES) {
await run_suite(n);
}
console.log('\nDone.');
```
## /grammars/textmate/info.plist
```plist path="/grammars/textmate/info.plist"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>name</key><string>Ripple</string>
</dict>
</plist>
```
## /grammars/tree-sitter/.gitignore
```gitignore path="/grammars/tree-sitter/.gitignore"
node_modules/
build/
*.log
package-lock.json
yarn.lock
*.exp
*.lib
*.obj
*.dll
*.so
```
## /grammars/tree-sitter/Cargo.toml
```toml path="/grammars/tree-sitter/Cargo.toml"
[package]
name = "tree-sitter"
description = "Ripple grammar for tree-sitter"
version = "0.0.1"
keywords = ["incremental", "parsing", "ripple"]
categories = ["parsing", "text-editors"]
repository = "https://github.com/trueadm/ripple"
edition = "2021"
license = "MIT"
[lib]
path = "bindings/rust/lib.rs"
[dependencies]
tree-sitter = "~0.22"
[build-dependencies]
cc = "1.0"
```
## /grammars/tree-sitter/LICENSE
``` path="/grammars/tree-sitter/LICENSE"
MIT License
Copyright (c) 2025 Ripple Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
## /grammars/tree-sitter/README.md
# @ripple-ts/tree-sitter
Tree-sitter grammar for [Ripple](https://www.ripplejs.com).
## Overview
Ripple is a JS/TS-first UI framework that extends TypeScript with component syntax
and reactive primitives. This Tree-sitter grammar provides parsing support for it.
## /grammars/tree-sitter/binding.gyp
```gyp path="/grammars/tree-sitter/binding.gyp"
{
"targets": [
{
"target_name": "tree_sitter_ripple_binding",
"include_dirs": [
"node_modules/node-addon-api",
"src"
],
"sources": [
"bindings/node/binding.cc",
"src/parser.c",
"src/scanner.c"
],
"cflags_c": [
"-std=c99"
],
"defines": ["NAPI_VERSION=6", "NAPI_DISABLE_CPP_EXCEPTIONS"]
}
]
}
```
## /grammars/tree-sitter/bindings/node/binding.cc
```cc path="/grammars/tree-sitter/bindings/node/binding.cc"
#include "napi.h"
typedef struct TSLanguage TSLanguage;
extern "C" TSLanguage *tree_sitter_ripple();
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports["language"] = Napi::External<TSLanguage>::New(env, tree_sitter_ripple());
return exports;
}
NODE_API_MODULE(tree_sitter_ripple_binding, Init)
```
## /grammars/tree-sitter/grammar.js
```js path="/grammars/tree-sitter/grammar.js"
const PREC = {
COMMA: -1,
DECLARATION: 1,
ASSIGN: 0,
OBJECT: 1,
TERNARY: 1,
OR: 2,
AND: 3,
REL: 4,
PLUS: 5,
TIMES: 6,
EXP: 7,
TYPEOF: 8,
DELETE: 8,
VOID: 8,
NOT: 9,
NEG: 10,
INC: 11,
CALL: 12,
NEW: 13,
MEMBER: 14,
};
module.exports = grammar({
name: 'ripple',
externals: ($) => [$._automatic_semicolon, $._template_chars, $._ternary_qmark, $.jsx_text],
extras: ($) => [/\s/, $.comment],
supertypes: ($) => [$.statement, $.declaration, $.expression, $.primary_expression, $.pattern],
inline: ($) => [
$._formal_parameter,
$.statement,
$._semicolon,
$._reserved_identifier,
$._jsx_attribute,
$._jsx_child,
$._jsx_attribute_value,
],
word: ($) => $.identifier,
conflicts: ($) => [
[$.primary_expression, $.pattern],
[$.array_pattern, $.array],
[$.object_pattern, $.object],
[$.expression, $.jsx_element_name],
[$.statement_block, $.object],
[$.method_definition, $.arrow_function],
[$.shorthand_property_identifier, $.shorthand_property_identifier_pattern],
[$.labeled_statement, $.arrow_function, $.property_name],
[$.primary_expression, $.property_name],
[$.assignment_expression, $.shorthand_property_identifier_pattern],
[$.import_statement],
[$.required_parameter, $.primary_expression],
[$.pattern, $.assignment_expression],
[$.jsx_element_name, $.jsx_non_namespaced_element_name],
[$.primary_expression, $.jsx_element_name],
[$.primary_expression, $.jsx_member_name],
[$.rest_pattern, $.primary_expression],
[$.variable_declaration, $.lexical_declaration],
[$.field_definition, $.method_definition],
[$.type, $.type_identifier],
[$.class_declaration, $.class_expression],
[$.primary_expression, $.literal_type],
[$.primary_expression, $.type, $.type_identifier],
[$.primary_expression, $.generic_type],
[$.primary_expression, $.nested_type_identifier],
[$.arrow_function, $.type, $.type_identifier],
[$.primary_expression, $.arrow_function],
[$.component_declaration],
[$.fragment_declaration],
[$.computed_property_name, $.array],
[$.assignment_expression, $.initializer],
[$.do_statement],
[$.component_statement, $.primary_expression],
[$.function_declaration, $.function_expression],
[$.required_parameter, $.type, $.type_identifier],
[$.statement_block, $.object, $.object_type],
[$.object, $.object_type],
[$.method_definition, $.property_signature],
[$.required_parameter, $.primary_expression, $.type, $.type_identifier],
[$.pattern, $.primary_expression, $.type, $.type_identifier],
[$.primary_expression, $.jsx_element_name, $.type_parameter],
[$.spread_element, $.jsx_expression],
[$.if_statement],
[$.switch_default],
[$.switch_case],
[$.object_pattern, $.object_type],
[$.object_pattern, $.object, $.object_type],
[$.pattern, $.type, $.type_identifier],
[$.array_type, $.function_type],
[$.intersection_type, $.function_type],
[$.union_type, $.function_type],
[$.for_in_statement, $.primary_expression],
],
rules: {
program: ($) => seq(optional($.hash_bang_line), repeat($.statement)),
hash_bang_line: ($) => /#!.*/,
export_statement: ($) =>
choice(
seq(
'export',
choice(
seq('*', $.from_clause),
seq($.namespace_export, $.from_clause),
seq($.export_clause, optional($.from_clause)),
seq('default', choice($.declaration, seq($.expression, $._semicolon))),
$.declaration,
),
$._semicolon,
),
seq(
'export',
'type',
choice(seq('*', $.from_clause), seq($.export_clause, optional($.from_clause))),
$._semicolon,
),
),
namespace_export: ($) => seq('*', 'as', $.identifier),
export_clause: ($) => seq('{', commaSep($.export_specifier), optional(','), '}'),
export_specifier: ($) =>
seq(
optional('type'),
field('name', $.identifier),
optional(seq('as', field('alias', $.identifier))),
),
import_statement: ($) =>
seq(
'import',
optional('type'),
choice(seq($.import_clause, $.from_clause), $.string),
optional($._semicolon),
),
import_clause: ($) =>
choice(
$.namespace_import,
$.named_imports,
seq($.identifier, optional(seq(',', choice($.namespace_import, $.named_imports)))),
),
from_clause: ($) => seq('from', choice($.string, $.identifier)),
namespace_import: ($) => seq('*', 'as', $.identifier),
named_imports: ($) => seq('{', commaSep($.import_specifier), optional(','), '}'),
import_specifier: ($) =>
seq(
optional('type'),
field('name', choice($.identifier, $.string)),
optional(seq('as', field('alias', $.identifier))),
),
statement: ($) =>
choice(
$.export_statement,
$.import_statement,
$.declaration,
$.module_declaration,
$.expression_statement,
$.if_statement,
$.switch_statement,
$.for_statement,
$.for_in_statement,
$.for_of_statement,
$.while_statement,
$.do_statement,
$.try_statement,
$.return_statement,
$.throw_statement,
$.break_statement,
$.continue_statement,
$.debugger_statement,
$.labeled_statement,
$.empty_statement,
$.statement_block,
),
expression_statement: ($) => seq($.expression, $._semicolon),
variable_declaration: ($) =>
seq(choice('var', 'let', 'const'), commaSep1($.variable_declarator), $._semicolon),
variable_declarator: ($) =>
seq(
field('name', choice($.identifier, $._destructuring_pattern)),
optional($._type_annotation),
optional($.initializer),
),
lexical_declaration: ($) =>
seq(choice('let', 'const'), commaSep1($.variable_declarator), $._semicolon),
statement_block: ($) => seq('{', repeat($.statement), '}'),
if_statement: ($) =>
seq(
'if',
field('condition', $.parenthesized_expression),
field('consequence', $.statement),
optional(seq('else', field('alternative', $.statement))),
),
switch_statement: ($) =>
seq('switch', field('value', $.parenthesized_expression), field('body', $.switch_body)),
switch_body: ($) => seq('{', repeat(choice($.switch_case, $.switch_default)), '}'),
switch_case: ($) => seq('case', field('value', $.expression), ':', repeat($.statement)),
switch_default: ($) => seq('default', ':', repeat($.statement)),
for_statement: ($) =>
seq(
'for',
optional('await'),
'(',
field(
'initializer',
choice(
$.lexical_declaration,
$.variable_declaration,
$.expression_statement,
$.empty_statement,
),
),
field('condition', choice($.expression_statement, $.empty_statement)),
field('increment', optional($.expression)),
')',
field('body', $.statement),
),
for_in_statement: ($) =>
seq(
'for',
optional('await'),
'(',
choice(
seq(choice('let', 'const', 'var'), choice($._destructuring_pattern, $.identifier)),
$.identifier,
),
'in',
field('right', $.expression),
')',
field('body', $.statement),
),
for_of_statement: ($) =>
seq(
'for',
optional('await'),
'(',
choice(
seq(choice('let', 'const', 'var'), choice($._destructuring_pattern, $.identifier)),
$.identifier,
),
'of',
field('right', $.expression),
optional(seq(';', 'index', $.identifier)),
optional(seq(';', 'key', $.expression)),
')',
field('body', $.statement),
),
while_statement: ($) =>
seq('while', field('condition', $.parenthesized_expression), field('body', $.statement)),
do_statement: ($) =>
seq(
'do',
field('body', $.statement),
'while',
field('condition', $.parenthesized_expression),
optional($._semicolon),
),
try_statement: ($) =>
seq(
'try',
field('body', $.statement_block),
optional(field('pending', $.pending_clause)),
optional(field('handler', $.catch_clause)),
optional(field('finalizer', $.finally_clause)),
),
pending_clause: ($) => seq('pending', field('body', $.statement_block)),
catch_clause: ($) =>
seq(
'catch',
optional(seq('(', field('parameter', choice($.identifier, $._destructuring_pattern)), ')')),
field('body', $.statement_block),
),
finally_clause: ($) => seq('finally', field('body', $.statement_block)),
return_statement: ($) => seq('return', optional($.expression), $._semicolon),
throw_statement: ($) => seq('throw', $.expression, $._semicolon),
break_statement: ($) => seq('break', optional($.identifier), $._semicolon),
continue_statement: ($) => seq('continue', optional($.identifier), $._semicolon),
debugger_statement: ($) => seq('debugger', $._semicolon),
labeled_statement: ($) =>
prec.dynamic(-1, seq(field('label', $.identifier), ':', field('body', $.statement))),
empty_statement: ($) => ';',
declaration: ($) =>
choice(
$.function_declaration,
$.component_declaration,
$.fragment_declaration,
$.class_declaration,
$.lexical_declaration,
$.variable_declaration,
),
component_declaration: ($) =>
prec.left(
PREC.DECLARATION,
seq(
optional('export'),
optional('default'),
'component',
optional(field('name', $.identifier)),
optional(field('type_parameters', $.type_parameters)),
field('parameters', $.formal_parameters),
optional($._type_annotation),
field('body', $.component_body),
),
),
fragment_declaration: ($) =>
prec.left(
PREC.DECLARATION,
seq(
optional('export'),
optional('default'),
'fragment',
optional(field('name', $.identifier)),
optional(field('type_parameters', $.type_parameters)),
field('parameters', $.formal_parameters),
optional($._type_annotation),
field('body', $.component_body),
),
),
component_body: ($) => seq('{', repeat($.component_statement), '}'),
component_statement: ($) =>
choice(
$.jsx_element,
$.jsx_fragment,
$.jsx_self_closing_element,
$.variable_declaration,
$.lexical_declaration,
$.function_declaration,
$.class_declaration,
$.expression_statement,
$.if_statement,
$.switch_statement,
$.for_statement,
$.for_in_statement,
$.for_of_statement,
$.while_statement,
$.do_statement,
$.try_statement,
$.return_statement,
$.throw_statement,
$.break_statement,
$.continue_statement,
$.debugger_statement,
$.empty_statement,
$.style_element,
),
style_element: ($) =>
seq(
'<style',
repeat($._jsx_attribute),
'>',
optional(alias($._style_content, $.raw_text)),
'</style>',
),
_style_content: ($) => /[^<]+/,
function_declaration: ($) =>
seq(
optional('async'),
'function',
optional('*'),
field('name', $.identifier),
optional(field('type_parameters', $.type_parameters)),
field('parameters', $.formal_parameters),
optional($._type_annotation),
field('body', $.statement_block),
),
class_declaration: ($) =>
seq(
optional('abstract'),
'class',
field('name', $.identifier),
optional(field('type_parameters', $.type_parameters)),
optional($.class_heritage),
field('body', $.class_body),
),
class_heritage: ($) =>
choice(
seq('extends', $.expression),
seq('implements', commaSep1($.type)),
seq('extends', $.expression, 'implements', commaSep1($.type)),
),
class_body: ($) =>
seq(
'{',
repeat(choice($.method_definition, $.field_definition, $.class_static_block, ';')),
'}',
),
class_static_block: ($) => seq('static', $.statement_block),
field_definition: ($) =>
seq(
repeat(choice('static', 'readonly', 'declare', 'abstract', 'override')),
field('property', $.property_name),
optional('?'),
optional($._type_annotation),
optional($.initializer),
$._semicolon,
),
method_definition: ($) =>
seq(
repeat(choice('static', 'async', 'readonly', 'abstract', 'override')),
optional(choice('get', 'set', '*')),
field('name', $.property_name),
optional(field('type_parameters', $.type_parameters)),
field('parameters', $.formal_parameters),
optional($._type_annotation),
field('body', $.statement_block),
),
formal_parameters: ($) => seq('(', optional(commaSep($._formal_parameter)), optional(','), ')'),
_formal_parameter: ($) => choice($.required_parameter, $.rest_parameter),
required_parameter: ($) =>
seq(
field('pattern', choice($.identifier, $._destructuring_pattern)),
optional('?'),
optional($._type_annotation),
optional($.initializer),
),
rest_parameter: ($) => seq('...', $.identifier, optional($._type_annotation)),
_destructuring_pattern: ($) =>
choice($.object_pattern, $.array_pattern, $.lazy_object_pattern, $.lazy_array_pattern),
lazy_object_pattern: ($) => seq('&', $.object_pattern),
lazy_array_pattern: ($) => seq('&', $.array_pattern),
object_pattern: ($) =>
seq(
'{',
commaSep(
choice(
$.pair_pattern,
$.rest_pattern,
$.object_assignment_pattern,
$.shorthand_property_identifier_pattern,
),
),
optional(','),
'}',
),
pair_pattern: ($) =>
seq(
field('key', $.property_name),
':',
field('value', choice($.pattern, $.assignment_pattern)),
),
rest_pattern: ($) => seq('...', $.identifier),
object_assignment_pattern: ($) =>
seq(
field('left', choice($.shorthand_property_identifier_pattern, $._reserved_identifier)),
'=',
field('right', $.expression),
),
array_pattern: ($) =>
seq(
'[',
commaSep(choice($.pattern, $.assignment_pattern, $.rest_pattern)),
optional(','),
']',
),
assignment_pattern: ($) => seq(field('left', $.pattern), '=', field('right', $.expression)),
pattern: ($) => choice($.identifier, $._reserved_identifier, $._destructuring_pattern),
expression: ($) =>
choice(
$.primary_expression,
$.assignment_expression,
$.augmented_assignment_expression,
$.await_expression,
$.unary_expression,
$.binary_expression,
$.ternary_expression,
$.update_expression,
$.new_expression,
$.yield_expression,
$.parenthesized_expression,
),
primary_expression: ($) =>
choice(
$.this,
$.super,
$.identifier,
$._reserved_identifier,
$.number,
$.string,
$.template_string,
$.regex,
$.true,
$.false,
$.null,
$.undefined,
$.object,
$.array,
$.function_expression,
$.arrow_function,
$.class_expression,
$.call_expression,
$.member_expression,
$.subscript_expression,
$.jsx_element,
$.jsx_fragment,
$.jsx_self_closing_element,
),
module_declaration: ($) =>
seq('module', field('name', $.identifier), field('body', $.module_body)),
module_body: ($) => seq('{', repeat($.statement), '}'),
yield_expression: ($) => prec.right(seq('yield', optional('*'), optional($.expression))),
await_expression: ($) => prec.left(PREC.CALL, seq('await', $.expression)),
parenthesized_expression: ($) => seq('(', $.expression, ')'),
assignment_expression: ($) =>
prec.right(
PREC.ASSIGN,
seq(
field(
'left',
choice(
$.identifier,
$.member_expression,
$.subscript_expression,
$._destructuring_pattern,
),
),
'=',
field('right', $.expression),
),
),
augmented_assignment_expression: ($) =>
prec.right(
PREC.ASSIGN,
seq(
field('left', choice($.identifier, $.member_expression, $.subscript_expression)),
field(
'operator',
choice(
'+=',
'-=',
'*=',
'/=',
'%=',
'^=',
'&=',
'|=',
'>>=',
'>>>=',
'<<=',
'**=',
'&&=',
'||=',
'??=',
),
),
field('right', $.expression),
),
),
ternary_expression: ($) =>
prec.right(
PREC.TERNARY,
seq(
field('condition', $.expression),
$._ternary_qmark,
field('consequence', $.expression),
':',
field('alternative', $.expression),
),
),
binary_expression: ($) =>
choice(
...[
['&&', PREC.AND],
['||', PREC.OR],
['??', PREC.OR],
['>>', PREC.TIMES],
['>>>', PREC.TIMES],
['<<', PREC.TIMES],
['&', PREC.AND],
['^', PREC.OR],
['|', PREC.OR],
['+', PREC.PLUS],
['-', PREC.PLUS],
['*', PREC.TIMES],
['/', PREC.TIMES],
['%', PREC.TIMES],
['**', PREC.EXP],
['<', PREC.REL],
['<=', PREC.REL],
['==', PREC.REL],
['===', PREC.REL],
['!=', PREC.REL],
['!==', PREC.REL],
['>=', PREC.REL],
['>', PREC.REL],
['instanceof', PREC.REL],
['in', PREC.REL],
].map(([operator, precedence]) =>
prec.left(
precedence,
seq(
field('left', $.expression),
field('operator', operator),
field('right', $.expression),
),
),
),
),
unary_expression: ($) =>
prec.left(
PREC.NOT,
choice(
...[
['!', PREC.NOT],
['~', PREC.NOT],
['-', PREC.NEG],
['+', PREC.NEG],
['typeof', PREC.TYPEOF],
['void', PREC.VOID],
['delete', PREC.DELETE],
].map(([operator, precedence]) =>
prec.right(
precedence,
seq(field('operator', operator), field('argument', $.expression)),
),
),
),
),
update_expression: ($) =>
prec.left(
PREC.INC,
choice(
seq(field('argument', $.expression), field('operator', choice('++', '--'))),
seq(field('operator', choice('++', '--')), field('argument', $.expression)),
),
),
call_expression: ($) =>
prec(
PREC.CALL,
seq(
field('function', choice($.expression, $.import)),
field('arguments', choice($.arguments, $.template_string)),
),
),
new_expression: ($) =>
prec.right(
PREC.NEW,
seq(
'new',
field('constructor', $.primary_expression),
optional(field('arguments', $.arguments)),
),
),
member_expression: ($) =>
prec(
PREC.MEMBER,
seq(
field('object', choice($.expression, $.primary_expression)),
choice('.', '?.'),
field('property', choice($.identifier, $.private_property_identifier)),
),
),
subscript_expression: ($) =>
prec.right(
PREC.MEMBER,
seq(
field('object', choice($.expression, $.primary_expression)),
optional('?'),
'[',
field('index', $.expression),
']',
),
),
arguments: ($) =>
seq('(', commaSep(choice($.expression, $.spread_element)), optional(','), ')'),
function_expression: ($) =>
seq(
optional('async'),
'function',
optional('*'),
optional(field('name', $.identifier)),
optional(field('type_parameters', $.type_parameters)),
field('parameters', $.formal_parameters),
optional($._type_annotation),
field('body', $.statement_block),
),
arrow_function: ($) =>
seq(
optional('async'),
choice(field('parameter', $.identifier), field('parameters', $.formal_parameters)),
optional($._type_annotation),
'=>',
field('body', choice($.expression, $.statement_block)),
),
class_expression: ($) =>
seq(
optional('abstract'),
'class',
optional(field('name', $.identifier)),
optional(field('type_parameters', $.type_parameters)),
optional($.class_heritage),
field('body', $.class_body),
),
object: ($) =>
seq(
'{',
commaSep(
choice(
$.pair,
$.spread_element,
$.method_definition,
$.shorthand_property_identifier,
$._reserved_identifier,
),
),
optional(','),
'}',
),
pair: ($) =>
prec(PREC.OBJECT, seq(field('key', $.property_name), ':', field('value', $.expression))),
spread_element: ($) => seq('...', $.expression),
property_name: ($) =>
choice(
$.identifier,
$.private_property_identifier,
$.string,
$.number,
$.computed_property_name,
),
computed_property_name: ($) => seq('[', $.expression, ']'),
shorthand_property_identifier: ($) =>
alias($.identifier, $.shorthand_property_identifier_pattern),
shorthand_property_identifier_pattern: ($) =>
alias($.identifier, $.shorthand_property_identifier),
array: ($) => seq('[', commaSep(choice($.expression, $.spread_element)), optional(','), ']'),
template_string: ($) =>
seq('`', repeat(choice($._template_chars, $.template_substitution)), '`'),
template_substitution: ($) => seq('${', $.expression, '}'),
jsx_element: ($) =>
seq(
field('open_tag', $.jsx_opening_element),
repeat(field('children', $._jsx_child)),
field('close_tag', $.jsx_closing_element),
),
jsx_fragment: ($) =>
seq(
field('open_tag', $.jsx_opening_fragment),
repeat(field('children', $._jsx_child)),
field('close_tag', $.jsx_closing_fragment),
),
jsx_opening_element: ($) =>
seq(
'<',
optional('@'),
field('name', $.jsx_element_name),
repeat(field('attribute', $._jsx_attribute)),
'>',
),
jsx_opening_fragment: () => seq('<', '>'),
jsx_closing_element: ($) => seq('</', optional('@'), field('name', $.jsx_element_name), '>'),
jsx_closing_fragment: () => seq('</', '>'),
// In Ripple, namespaced TSX-compat elements like <tsx:react> cannot be self-closing
// so we disallow jsx_namespace_name here by using a narrowed name rule.
jsx_self_closing_element: ($) =>
seq(
'<',
optional('@'),
field('name', $.jsx_non_namespaced_element_name),
repeat(field('attribute', $._jsx_attribute)),
'/>',
),
jsx_element_name: ($) =>
choice($.identifier, $.jsx_namespace_name, $.jsx_member_name, $.member_expression),
// Non-namespaced variant (used for self-closing elements)
jsx_non_namespaced_element_name: ($) =>
choice($.identifier, $.jsx_member_name, $.member_expression),
// Support dotted names in JSX element names (e.g. Namespace.Component)
// Implemented iteratively to avoid left recursion
jsx_member_name: ($) => seq($.identifier, repeat1(seq('.', $.identifier))),
jsx_namespace_name: ($) => seq($.identifier, ':', $.identifier),
jsx_hyphenated_name: ($) => seq($.identifier, repeat1(seq('-', $.identifier))),
_jsx_attribute: ($) => choice($.jsx_attribute, $.jsx_expression),
jsx_attribute: ($) =>
seq(
field('name', choice($.identifier, $.jsx_namespace_name, $.jsx_hyphenated_name)),
optional(seq('=', field('value', $._jsx_attribute_value))),
),
jsx_expression: ($) =>
seq(
'{',
optional(
choice(
$.expression,
$.spread_element,
seq('...', $.expression),
seq('ref', choice($.identifier, $.arrow_function, $.function_expression)),
seq('html', $.expression),
seq('text', $.expression),
$.style_directive,
repeat1($.component_statement),
),
),
'}',
),
style_directive: ($) => seq('style', $.string),
_jsx_attribute_value: ($) =>
choice($.string, $.jsx_expression, $.jsx_element, $.jsx_fragment, $.jsx_self_closing_element),
_jsx_child: ($) =>
choice(
$.jsx_text,
$.jsx_element,
$.jsx_fragment,
$.jsx_self_closing_element,
$.jsx_expression,
),
this: ($) => 'this',
super: ($) => 'super',
true: ($) => 'true',
false: ($) => 'false',
null: ($) => 'null',
undefined: ($) => 'undefined',
import: ($) => 'import',
identifier: ($) => {
const alpha = /[^\x00-\x1F\s\p{Zs}0-9:;`"'@#.,|^&<=>+\-*/\\%?!~()\[\]{}\uFEFF\u2060\u200B]/;
const alphanumeric =
/[^\x00-\x1F\s\p{Zs}:;`"'@#.,|^&<=>+\-*/\\%?!~()\[\]{}\uFEFF\u2060\u200B]/;
return token(seq(alpha, repeat(alphanumeric)));
},
private_property_identifier: ($) => /#[a-zA-Z_$][a-zA-Z0-9_$]*/,
_reserved_identifier: ($) =>
choice('arguments', 'await', 'component', 'fragment', 'track', 'untrack'),
comment: ($) => token(choice(seq('//', /.*/), seq('/*', /[^*]*\*+([^/*][^*]*\*+)*/, '/'))),
number: ($) => {
const hex_literal = seq(choice('0x', '0X'), /[\da-fA-F](_?[\da-fA-F])*/);
const decimal_digits = /\d(_?\d)*/;
const signed_integer = seq(optional(choice('-', '+')), decimal_digits);
const exponent_part = seq(choice('e', 'E'), signed_integer);
const binary_literal = seq(choice('0b', '0B'), /[0-1](_?[0-1])*/);
const octal_literal = seq(choice('0o', '0O'), /[0-7](_?[0-7])*/);
const bigint_literal = seq(
choice(hex_literal, binary_literal, octal_literal, decimal_digits),
'n',
);
const decimal_integer_literal = choice(
'0',
seq(optional('0'), /[1-9]/, optional(seq(optional('_'), decimal_digits))),
);
const decimal_literal = choice(
seq(decimal_integer_literal, '.', optional(decimal_digits), optional(exponent_part)),
seq('.', decimal_digits, optional(exponent_part)),
seq(decimal_integer_literal, exponent_part),
decimal_digits,
);
return token(
choice(hex_literal, decimal_literal, binary_literal, octal_literal, bigint_literal),
);
},
string: ($) =>
choice(
seq('"', repeat(choice(token.immediate(prec(1, /[^"\\\n]+/)), $.escape_sequence)), '"'),
seq("'", repeat(choice(token.immediate(prec(1, /[^'\\\n]+/)), $.escape_sequence)), "'"),
),
escape_sequence: ($) =>
token.immediate(
seq(
'\\',
choice(
/[^xu0-7]/,
/[0-7]{1,3}/,
/x[0-9a-fA-F]{2}/,
/u[0-9a-fA-F]{4}/,
/u\{[0-9a-fA-F]+\}/,
/[\r?][\n\u2028\u2029]/,
),
),
),
regex: ($) =>
seq(
'/',
field('pattern', $.regex_pattern),
token.immediate('/'),
optional(field('flags', $.regex_flags)),
),
regex_pattern: ($) =>
token.immediate(
prec(
-1,
repeat1(
choice(seq('[', repeat(choice(/[^\]\n\\]/, /\\./)), ']'), seq('\\', /./), /[^/\\\[\n]/),
),
),
),
regex_flags: ($) => token.immediate(/[a-z]+/),
type_parameters: ($) => seq('<', commaSep1($.type_parameter), optional(','), '>'),
type_parameter: ($) =>
seq($.identifier, optional(seq('extends', $.type)), optional(seq('=', $.type))),
_type_annotation: ($) => seq(':', $.type),
type: ($) =>
choice(
$.identifier,
$.predefined_type,
$.type_identifier,
$.nested_type_identifier,
$.generic_type,
$.object_type,
$.array_type,
$.tuple_type,
$.union_type,
$.intersection_type,
$.function_type,
$.literal_type,
$.parenthesized_type,
),
predefined_type: ($) =>
choice('any', 'number', 'boolean', 'string', 'symbol', 'void', 'unknown', 'never', 'object'),
type_identifier: ($) => alias($.identifier, $.type_identifier),
nested_type_identifier: ($) =>
seq(choice($.identifier, $.nested_type_identifier), '.', $.type_identifier),
generic_type: ($) => seq(choice($.identifier, $.nested_type_identifier), $.type_arguments),
type_arguments: ($) => seq('<', commaSep1($.type), optional(','), '>'),
object_type: ($) => seq('{', commaSep($.property_signature), optional(','), '}'),
property_signature: ($) =>
seq(optional('readonly'), field('name', $.property_name), optional('?'), $._type_annotation),
array_type: ($) => seq($.type, '[', ']'),
tuple_type: ($) => seq('[', commaSep1($.type), optional(','), ']'),
union_type: ($) => prec.left(seq($.type, '|', $.type)),
intersection_type: ($) => prec.left(seq($.type, '&', $.type)),
function_type: ($) => seq(optional($.type_parameters), $.formal_parameters, '=>', $.type),
literal_type: ($) => choice($.number, $.string, $.true, $.false, $.null),
parenthesized_type: ($) => seq('(', $.type, ')'),
initializer: ($) => seq('=', $.expression),
_semicolon: ($) => choice($._automatic_semicolon, ';'),
},
});
function commaSep(rule) {
return optional(commaSep1(rule));
}
function commaSep1(rule) {
return seq(rule, repeat(seq(',', rule)));
}
```
## /grammars/tree-sitter/package.json
```json path="/grammars/tree-sitter/package.json"
{
"name": "@ripple-ts/tree-sitter",
"version": "0.2.208",
"description": "Ripple grammar for tree-sitter",
"private": true,
"main": "bindings/node",
"types": "bindings/node",
"keywords": [
"tree-sitter",
"parser",
"ripple"
],
"author": "Dominic Gannaway",
"license": "MIT",
"dependencies": {
"node-addon-api": "^8.6.0",
"node-gyp-build": "^4.8.0"
},
"devDependencies": {
"tree-sitter-cli": "^0.26.6",
"prebuildify": "^6.0.0",
"node-gyp": "^12.3.0"
},
"scripts": {
"generate": "tree-sitter generate",
"build": "tree-sitter generate && node-gyp rebuild",
"install": "node-gyp-build",
"prestart": "tree-sitter build --wasm",
"start": "tree-sitter playground",
"test": "tree-sitter test"
},
"tree-sitter": [
{
"scope": "source.tsrx",
"file-types": [
"ripple"
],
"injection-regex": "ripple"
}
],
"gypfile": true
}
```
## /grammars/tree-sitter/queries/brackets.scm
```scm path="/grammars/tree-sitter/queries/brackets.scm"
; Bracket pairs for cursor navigation
(jsx_opening_element
"<" @open
">" @close)
(jsx_opening_fragment
"<" @open
">" @close)
(jsx_closing_element
"</" @open
">" @close)
(jsx_closing_fragment
"</" @open
">" @close)
(jsx_self_closing_element
"<" @open
"/>" @close)
("(" @open ")" @close)
("[" @open "]" @close)
("{" @open "}" @close)
```
## /grammars/tree-sitter/queries/folds.scm
```scm path="/grammars/tree-sitter/queries/folds.scm"
; Folds for code blocks
[
(statement_block)
(component_body)
(class_body)
(object)
(object_pattern)
(array)
(array_pattern)
(switch_body)
] @fold
; Fold multi-line JSX elements
(jsx_element) @fold
(jsx_fragment) @fold
; Fold style elements
(style_element) @fold
; Fold submodules
(module_declaration) @fold
; Fold comments
(comment) @fold
; Fold template strings
(template_string) @fold
```
## /grammars/tree-sitter/queries/highlights.scm
```scm path="/grammars/tree-sitter/queries/highlights.scm"
; Keywords
(component_declaration "component" @keyword)
(fragment_declaration "fragment" @keyword)
(module_declaration
"module" @keyword
name: (identifier) @namespace)
; Lazy destructuring
(lazy_object_pattern "&" @operator)
(lazy_array_pattern "&" @operator)
(style_directive
"style" @keyword
(string) @string)
(jsx_expression "html" @keyword)
; Reserved identifiers
[
"track"
"untrack"
] @function.builtin
; Functions
(component_declaration
name: (identifier) @function)
(fragment_declaration
name: (identifier) @function)
(function_declaration
name: (identifier) @function)
(class_declaration
name: (identifier) @type)
(method_definition
name: (property_name) @function.method)
(field_definition
property: (property_name) @property)
(call_expression
function: (identifier) @function.call)
(call_expression
function: (member_expression
property: (identifier) @function.method.call))
; Variables
(identifier) @variable
; Parameters
(required_parameter
pattern: (identifier) @variable.parameter)
(rest_parameter
(identifier) @variable.parameter)
; JSX/Components
(jsx_opening_element
"<" @tag.delimiter
name: (jsx_element_name) @tag
">" @tag.delimiter)
(jsx_opening_fragment
"<" @tag.delimiter
">" @tag.delimiter)
(jsx_closing_element
"</" @tag.delimiter
name: (jsx_element_name) @tag
">" @tag.delimiter)
(jsx_closing_fragment
"</" @tag.delimiter
">" @tag.delimiter)
(jsx_self_closing_element
"<" @tag.delimiter
name: (jsx_non_namespaced_element_name) @tag
"/>" @tag.delimiter)
; Override identifier coloring for JSX element names
; These must come after the general (identifier) @variable pattern to have higher priority
; Regular element names (plain identifiers)
(jsx_opening_element
name: (jsx_element_name (identifier) @tag))
(jsx_closing_element
name: (jsx_element_name (identifier) @tag))
(jsx_self_closing_element
name: (jsx_non_namespaced_element_name (identifier) @tag))
(jsx_attribute
name: [(identifier) (jsx_namespace_name) (jsx_hyphenated_name)] @attribute)
(jsx_expression
"{" @punctuation.bracket
"}" @punctuation.bracket)
; Style elements
(style_element
"<style" @tag
">" @tag.delimiter
"</style>" @tag)
(style_element
(raw_text) @string.special)
; Types
(type_identifier) @type
(predefined_type) @type.builtin
(type_parameter (identifier) @type.parameter)
; Type annotations (commented out - _type_annotation is hidden)
; The colon will be captured as punctuation.delimiter via other rules
; Literals
(string) @string
(template_string) @string
(number) @number
(true) @constant.builtin.boolean
(false) @constant.builtin.boolean
(null) @constant.builtin
(undefined) @constant.builtin
; Regex
(regex) @string.regexp
(regex_pattern) @string.regexp
(regex_flags) @string.regexp
; Comments
(comment) @comment
; Operators
(unary_expression operator: _ @operator)
(binary_expression operator: _ @operator)
(augmented_assignment_expression operator: _ @operator)
(update_expression operator: _ @operator)
; Control flow keywords
[
"if"
"else"
"switch"
"case"
"default"
"for"
"while"
"do"
"break"
"continue"
"return"
"throw"
"try"
"pending"
"catch"
"finally"
] @keyword.control
[
"await"
"async"
] @keyword.control.flow
[
"import"
"export"
"from"
"as"
] @keyword.control.import
; Other keywords
[
"function"
"class"
"extends"
"implements"
"new"
"typeof"
"instanceof"
"in"
"of"
"void"
"delete"
"yield"
"static"
"get"
"set"
"abstract"
"readonly"
"declare"
"override"
] @keyword
[
"let"
"const"
"var"
] @keyword.storage
; Special identifiers
[
(this)
(super)
] @variable.builtin
; Properties
(property_signature
name: (property_name) @property)
(pair
key: (property_name) @property)
(member_expression
property: (identifier) @property)
(shorthand_property_identifier) @property
(shorthand_property_identifier_pattern) @property
; Private properties
(private_property_identifier) @property.private
; Punctuation
["(" ")" "[" "]" "{" "}"] @punctuation.bracket
["." "," ";" ":" "..."] @punctuation.delimiter
; Note: < and > are handled separately in JSX contexts as @tag.delimiter
(template_substitution
"${" @punctuation.special
"}" @punctuation.special)
; Special: Arrow function
"=>" @operator
; Hash bang
(hash_bang_line) @comment
```
## /grammars/tree-sitter/queries/indents.nvim.scm
```scm path="/grammars/tree-sitter/queries/indents.nvim.scm"
; Neovim (nvim-treesitter) indentation rules.
[
(statement_block "}" @indent.end)
(component_body "}" @indent.end)
(class_body "}" @indent.end)
(switch_body "}" @indent.end)
(object "}" @indent.end)
(object_pattern "}" @indent.end)
(array "]" @indent.end)
(array_pattern "]" @indent.end)
(arguments ")" @indent.end)
(formal_parameters ")" @indent.end)
(parenthesized_expression ")" @indent.end)
(jsx_expression "}" @indent.end)
(style_element "</style>" @indent.end)
(module_body "}" @indent.end)
] @indent.begin
[
(jsx_element)
(jsx_fragment)
(jsx_self_closing_element)
] @indent.begin
((jsx_opening_element) @indent.begin
(#set! indent.immediate)
(#set! indent.start_at_same_line))
((jsx_opening_fragment) @indent.begin
(#set! indent.immediate)
(#set! indent.start_at_same_line))
(jsx_closing_element ">" @indent.end)
(jsx_closing_fragment ">" @indent.end)
(jsx_self_closing_element "/>" @indent.end)
[
"}"
"]"
")"
"</style>"
(jsx_closing_element)
(jsx_closing_fragment)
] @indent.branch
(jsx_self_closing_element "/>" @indent.branch)
```
## /grammars/tree-sitter/queries/indents.scm
```scm path="/grammars/tree-sitter/queries/indents.scm"
; Helix indentation rules.
[
(statement_block)
(component_body)
(class_body)
(switch_body)
(object)
(object_pattern)
(array)
(array_pattern)
(arguments)
(formal_parameters)
(parenthesized_expression)
(jsx_element)
(jsx_fragment)
(jsx_self_closing_element)
(style_element)
(module_body)
] @indent
[
"}"
"]"
")"
"</style>"
] @outdent
(jsx_closing_element) @outdent
(jsx_closing_fragment) @outdent
```
## /grammars/tree-sitter/queries/indents.zed.scm
```scm path="/grammars/tree-sitter/queries/indents.zed.scm"
; Zed indents use @indent plus @end markers.
[
(statement_block "}" @end)
(component_body "}" @end)
(class_body "}" @end)
(switch_body "}" @end)
(object "}" @end)
(object_pattern "}" @end)
(array "]" @end)
(array_pattern "]" @end)
(arguments ")" @end)
(formal_parameters ")" @end)
(parenthesized_expression ")" @end)
(jsx_expression "}" @end)
(style_element "</style>" @end)
(module_body "}" @end)
(jsx_self_closing_element "/>" @end)
] @indent
(_ "[" "]" @end) @indent
(_ "{" "}" @end) @indent
(_ "(" ")" @end) @indent
(jsx_opening_element ">" @end) @indent
(jsx_opening_fragment ">" @end) @indent
(jsx_element
(jsx_opening_element) @start
(jsx_closing_element)? @end) @indent
(jsx_fragment
(jsx_opening_fragment) @start
(jsx_closing_fragment)? @end) @indent
```
## /grammars/tree-sitter/queries/injections.scm
```scm path="/grammars/tree-sitter/queries/injections.scm"
; Inject CSS into style elements
(style_element
(raw_text) @injection.content
(#set! injection.combined)
(#set! injection.language "css"))
; Inject JavaScript/TypeScript into submodules
; Note: statement is inlined, so we need to match specific statement types
; Commenting out for now as it requires matching all concrete statement types
; Template string interpolations
(template_substitution
(expression) @injection.content
(#set! injection.language "typescript"))
; TSX expression islands. Shorthand fragments and <tsx> blocks use TSX syntax
; rather than Ripple template statements.
((jsx_fragment) @injection.content
(#set! injection.language "tsx"))
((jsx_element
open_tag: (jsx_opening_element
name: (jsx_element_name (identifier) @_tsx_name))) @injection.content
(#eq? @_tsx_name "tsx")
(#set! injection.language "tsx"))
((jsx_element
open_tag: (jsx_opening_element
name: (jsx_element_name
(jsx_namespace_name
(identifier) @_tsx_namespace
(identifier) @_tsx_name)))) @injection.content
(#eq? @_tsx_namespace "tsx")
(#eq? @_tsx_name "react")
(#set! injection.language "tsx"))
; Inject Ripple into JSX text blocks so statement-like template code
; (e.g. const/if lines in JSX children) is highlighted consistently.
((jsx_text) @injection.content
(#set! injection.language "ripple"))
```
## /grammars/tree-sitter/queries/locals.scm
```scm path="/grammars/tree-sitter/queries/locals.scm"
; Scopes
[
(statement_block)
(function_declaration)
(arrow_function)
(function_expression)
(component_declaration)
(fragment_declaration)
(class_declaration)
(for_statement)
(for_of_statement)
(for_in_statement)
(while_statement)
(catch_clause)
] @local.scope
; Definitions
(component_declaration
name: (identifier) @local.definition.function)
(fragment_declaration
name: (identifier) @local.definition.function)
(function_declaration
name: (identifier) @local.definition.function)
(class_declaration
name: (identifier) @local.definition.type)
(method_definition
name: (property_name) @local.definition.method)
(variable_declarator
name: (identifier) @local.definition.var)
(required_parameter
pattern: (identifier) @local.definition.parameter)
(rest_parameter
(identifier) @local.definition.parameter)
; References
(identifier) @local.reference
; Imports
(import_specifier
name: (identifier) @local.definition.import)
(namespace_import
(identifier) @local.definition.namespace)
; Exports
(export_specifier
name: (identifier) @local.definition.export)
```
## /grammars/tree-sitter/queries/outline.scm
```scm path="/grammars/tree-sitter/queries/outline.scm"
; Code outline/structure for symbol navigation
; Components
(component_declaration
name: (identifier) @name) @item
; Fragments
(fragment_declaration
name: (identifier) @name) @item
; Functions
(function_declaration
name: (identifier) @name) @item
; Classes
(class_declaration
name: (identifier) @name) @item
; Methods
(method_definition
name: (property_name) @name) @item
; Variables (const/let)
(variable_declarator
name: (identifier) @name) @item
```
## /grammars/tree-sitter/queries/textobjects.scm
```scm path="/grammars/tree-sitter/queries/textobjects.scm"
; Functions / components
(function_declaration) @function.around
(function_declaration) @function.outer
(function_declaration body: (statement_block) @function.inside)
(function_declaration body: (statement_block) @function.inner)
(component_declaration) @function.around
(component_declaration) @function.outer
(component_declaration body: (component_body) @function.inside)
(component_declaration body: (component_body) @function.inner)
(fragment_declaration) @function.around
(fragment_declaration) @function.outer
(fragment_declaration body: (component_body) @function.inside)
(fragment_declaration body: (component_body) @function.inner)
(method_definition) @function.around
(method_definition) @function.outer
(method_definition body: (statement_block) @function.inside)
(method_definition body: (statement_block) @function.inner)
; Classes / interfaces
(class_declaration) @class.around
(class_declaration) @class.outer
(class_declaration body: (class_body) @class.inside)
(class_declaration body: (class_body) @class.inner)
; Parameters
(required_parameter) @parameter.around
(required_parameter) @parameter.outer
(required_parameter pattern: (_) @parameter.inside)
(required_parameter pattern: (_) @parameter.inner)
(rest_parameter) @parameter.around
(rest_parameter) @parameter.outer
(rest_parameter (identifier) @parameter.inside)
(rest_parameter (identifier) @parameter.inner)
; Comments
(comment) @comment.around
(comment) @comment.outer
(comment) @comment.inside
(comment) @comment.inner
; Object entries
(pair) @entry.around
(pair) @entry.outer
(pair key: (_) @entry.inside)
(pair key: (_) @entry.inner)
```
## /grammars/tree-sitter/src/node-types.json
```json path="/grammars/tree-sitter/src/node-types.json"
[
{
"type": "declaration",
"named": true,
"subtypes": [
{
"type": "class_declaration",
"named": true
},
{
"type": "component_declaration",
"named": true
},
{
"type": "fragment_declaration",
"named": true
},
{
"type": "function_declaration",
"named": true
},
{
"type": "lexical_declaration",
"named": true
},
{
"type": "variable_declaration",
"named": true
}
]
},
{
"type": "expression",
"named": true,
"subtypes": [
{
"type": "assignment_expression",
"named": true
},
{
"type": "augmented_assignment_expression",
"named": true
},
{
"type": "await_expression",
"named": true
},
{
"type": "binary_expression",
"named": true
},
{
"type": "new_expression",
"named": true
},
{
"type": "parenthesized_expression",
"named": true
},
{
"type": "primary_expression",
"named": true
},
{
"type": "ternary_expression",
"named": true
},
{
"type": "unary_expression",
"named": true
},
{
"type": "update_expression",
"named": true
},
{
"type": "yield_expression",
"named": true
}
]
},
{
"type": "pattern",
"named": true,
"subtypes": [
{
"type": "arguments",
"named": false
},
{
"type": "array_pattern",
"named": true
},
{
"type": "await",
"named": false
},
{
"type": "component",
"named": false
},
{
"type": "fragment",
"named": false
},
{
"type": "identifier",
"named": true
},
{
"type": "lazy_array_pattern",
"named": true
},
{
"type": "lazy_object_pattern",
"named": true
},
{
"type": "object_pattern",
"named": true
},
{
"type": "track",
"named": false
},
{
"type": "untrack",
"named": false
}
]
},
{
"type": "primary_expression",
"named": true,
"subtypes": [
{
"type": "arguments",
"named": false
},
{
"type": "array",
"named": true
},
{
"type": "arrow_function",
"named": true
},
{
"type": "await",
"named": false
},
{
"type": "call_expression",
"named": true
},
{
"type": "class_expression",
"named": true
},
{
"type": "component",
"named": false
},
{
"type": "false",
"named": true
},
{
"type": "fragment",
"named": false
},
{
"type": "function_expression",
"named": true
},
{
"type": "identifier",
"named": true
},
{
"type": "jsx_element",
"named": true
},
{
"type": "jsx_fragment",
"named": true
},
{
"type": "jsx_self_closing_element",
"named": true
},
{
"type": "member_expression",
"named": true
},
{
"type": "null",
"named": true
},
{
"type": "number",
"named": true
},
{
"type": "object",
"named": true
},
{
"type": "regex",
"named": true
},
{
"type": "string",
"named": true
},
{
"type": "subscript_expression",
"named": true
},
{
"type": "super",
"named": true
},
{
"type": "template_string",
"named": true
},
{
"type": "this",
"named": true
},
{
"type": "track",
"named": false
},
{
"type": "true",
"named": true
},
{
"type": "undefined",
"named": true
},
{
"type": "untrack",
"named": false
}
]
},
{
"type": "statement",
"named": true,
"subtypes": [
{
"type": "break_statement",
"named": true
},
{
"type": "continue_statement",
"named": true
},
{
"type": "debugger_statement",
"named": true
},
{
"type": "declaration",
"named": true
},
{
"type": "do_statement",
"named": true
},
{
"type": "empty_statement",
"named": true
},
{
"type": "export_statement",
"named": true
},
{
"type": "expression_statement",
"named": true
},
{
"type": "for_in_statement",
"named": true
},
{
"type": "for_of_statement",
"named": true
},
{
"type": "for_statement",
"named": true
},
{
"type": "if_statement",
"named": true
},
{
"type": "import_statement",
"named": true
},
{
"type": "labeled_statement",
"named": true
},
{
"type": "module_declaration",
"named": true
},
{
"type": "return_statement",
"named": true
},
{
"type": "statement_block",
"named": true
},
{
"type": "switch_statement",
"named": true
},
{
"type": "throw_statement",
"named": true
},
{
"type": "try_statement",
"named": true
},
{
"type": "while_statement",
"named": true
}
]
},
{
"type": "arguments",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "expression",
"named": true
},
{
"type": "spread_element",
"named": true
}
]
}
},
{
"type": "array",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "expression",
"named": true
},
{
"type": "spread_element",
"named": true
}
]
}
},
{
"type": "array_pattern",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "assignment_pattern",
"named": true
},
{
"type": "pattern",
"named": true
},
{
"type": "rest_pattern",
"named": true
}
]
}
},
{
"type": "array_type",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "type",
"named": true
}
]
}
},
{
"type": "arrow_function",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
},
{
"type": "statement_block",
"named": true
}
]
},
"parameter": {
"multiple": false,
"required": false,
"types": [
{
"type": "identifier",
"named": true
}
]
},
"parameters": {
"multiple": false,
"required": false,
"types": [
{
"type": "formal_parameters",
"named": true
}
]
}
},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "type",
"named": true
}
]
}
},
{
"type": "assignment_expression",
"named": true,
"fields": {
"left": {
"multiple": false,
"required": true,
"types": [
{
"type": "array_pattern",
"named": true
},
{
"type": "identifier",
"named": true
},
{
"type": "lazy_array_pattern",
"named": true
},
{
"type": "lazy_object_pattern",
"named": true
},
{
"type": "member_expression",
"named": true
},
{
"type": "object_pattern",
"named": true
},
{
"type": "subscript_expression",
"named": true
}
]
},
"right": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
}
},
{
"type": "assignment_pattern",
"named": true,
"fields": {
"left": {
"multiple": false,
"required": true,
"types": [
{
"type": "pattern",
"named": true
}
]
},
"right": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
}
},
{
"type": "augmented_assignment_expression",
"named": true,
"fields": {
"left": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
},
{
"type": "member_expression",
"named": true
},
{
"type": "subscript_expression",
"named": true
}
]
},
"operator": {
"multiple": false,
"required": true,
"types": [
{
"type": "%=",
"named": false
},
{
"type": "&&=",
"named": false
},
{
"type": "&=",
"named": false
},
{
"type": "**=",
"named": false
},
{
"type": "*=",
"named": false
},
{
"type": "+=",
"named": false
},
{
"type": "-=",
"named": false
},
{
"type": "/=",
"named": false
},
{
"type": "<<=",
"named": false
},
{
"type": ">>=",
"named": false
},
{
"type": ">>>=",
"named": false
},
{
"type": "??=",
"named": false
},
{
"type": "^=",
"named": false
},
{
"type": "|=",
"named": false
},
{
"type": "||=",
"named": false
}
]
},
"right": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
}
},
{
"type": "await_expression",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
{
"type": "binary_expression",
"named": true,
"fields": {
"left": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
},
"operator": {
"multiple": false,
"required": true,
"types": [
{
"type": "!=",
"named": false
},
{
"type": "!==",
"named": false
},
{
"type": "%",
"named": false
},
{
"type": "&",
"named": false
},
{
"type": "&&",
"named": false
},
{
"type": "*",
"named": false
},
{
"type": "**",
"named": false
},
{
"type": "+",
"named": false
},
{
"type": "-",
"named": false
},
{
"type": "/",
"named": false
},
{
"type": "<",
"named": false
},
{
"type": "<<",
"named": false
},
{
"type": "<=",
"named": false
},
{
"type": "==",
"named": false
},
{
"type": "===",
"named": false
},
{
"type": ">",
"named": false
},
{
"type": ">=",
"named": false
},
{
"type": ">>",
"named": false
},
{
"type": ">>>",
"named": false
},
{
"type": "??",
"named": false
},
{
"type": "^",
"named": false
},
{
"type": "in",
"named": false
},
{
"type": "instanceof",
"named": false
},
{
"type": "|",
"named": false
},
{
"type": "||",
"named": false
}
]
},
"right": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
}
},
{
"type": "break_statement",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "identifier",
"named": true
}
]
}
},
{
"type": "call_expression",
"named": true,
"fields": {
"arguments": {
"multiple": false,
"required": true,
"types": [
{
"type": "arguments",
"named": true
},
{
"type": "template_string",
"named": true
}
]
},
"function": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
},
{
"type": "import",
"named": true
}
]
}
}
},
{
"type": "catch_clause",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "statement_block",
"named": true
}
]
},
"parameter": {
"multiple": false,
"required": false,
"types": [
{
"type": "array_pattern",
"named": true
},
{
"type": "identifier",
"named": true
},
{
"type": "lazy_array_pattern",
"named": true
},
{
"type": "lazy_object_pattern",
"named": true
},
{
"type": "object_pattern",
"named": true
}
]
}
}
},
{
"type": "class_body",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "class_static_block",
"named": true
},
{
"type": "field_definition",
"named": true
},
{
"type": "method_definition",
"named": true
}
]
}
},
{
"type": "class_declaration",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "class_body",
"named": true
}
]
},
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
},
"type_parameters": {
"multiple": false,
"required": false,
"types": [
{
"type": "type_parameters",
"named": true
}
]
}
},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "class_heritage",
"named": true
}
]
}
},
{
"type": "class_expression",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "class_body",
"named": true
}
]
},
"name": {
"multiple": false,
"required": false,
"types": [
{
"type": "identifier",
"named": true
}
]
},
"type_parameters": {
"multiple": false,
"required": false,
"types": [
{
"type": "type_parameters",
"named": true
}
]
}
},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "class_heritage",
"named": true
}
]
}
},
{
"type": "class_heritage",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "expression",
"named": true
},
{
"type": "type",
"named": true
}
]
}
},
{
"type": "class_static_block",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "statement_block",
"named": true
}
]
}
},
{
"type": "component_body",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "component_statement",
"named": true
}
]
}
},
{
"type": "component_declaration",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "component_body",
"named": true
}
]
},
"name": {
"multiple": false,
"required": false,
"types": [
{
"type": "identifier",
"named": true
}
]
},
"parameters": {
"multiple": false,
"required": true,
"types": [
{
"type": "formal_parameters",
"named": true
}
]
},
"type_parameters": {
"multiple": false,
"required": false,
"types": [
{
"type": "type_parameters",
"named": true
}
]
}
},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "type",
"named": true
}
]
}
},
{
"type": "component_statement",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "break_statement",
"named": true
},
{
"type": "class_declaration",
"named": true
},
{
"type": "continue_statement",
"named": true
},
{
"type": "debugger_statement",
"named": true
},
{
"type": "do_statement",
"named": true
},
{
"type": "empty_statement",
"named": true
},
{
"type": "expression_statement",
"named": true
},
{
"type": "for_in_statement",
"named": true
},
{
"type": "for_of_statement",
"named": true
},
{
"type": "for_statement",
"named": true
},
{
"type": "function_declaration",
"named": true
},
{
"type": "if_statement",
"named": true
},
{
"type": "jsx_element",
"named": true
},
{
"type": "jsx_fragment",
"named": true
},
{
"type": "jsx_self_closing_element",
"named": true
},
{
"type": "lexical_declaration",
"named": true
},
{
"type": "return_statement",
"named": true
},
{
"type": "style_element",
"named": true
},
{
"type": "switch_statement",
"named": true
},
{
"type": "throw_statement",
"named": true
},
{
"type": "try_statement",
"named": true
},
{
"type": "variable_declaration",
"named": true
},
{
"type": "while_statement",
"named": true
}
]
}
},
{
"type": "computed_property_name",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
{
"type": "continue_statement",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "identifier",
"named": true
}
]
}
},
{
"type": "debugger_statement",
"named": true,
"fields": {}
},
{
"type": "do_statement",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "statement",
"named": true
}
]
},
"condition": {
"multiple": false,
"required": true,
"types": [
{
"type": "parenthesized_expression",
"named": true
}
]
}
}
},
{
"type": "empty_statement",
"named": true,
"fields": {}
},
{
"type": "export_clause",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "export_specifier",
"named": true
}
]
}
},
{
"type": "export_specifier",
"named": true,
"fields": {
"alias": {
"multiple": false,
"required": false,
"types": [
{
"type": "identifier",
"named": true
}
]
},
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
}
}
},
{
"type": "export_statement",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "declaration",
"named": true
},
{
"type": "export_clause",
"named": true
},
{
"type": "expression",
"named": true
},
{
"type": "from_clause",
"named": true
},
{
"type": "namespace_export",
"named": true
}
]
}
},
{
"type": "expression_statement",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
{
"type": "field_definition",
"named": true,
"fields": {
"property": {
"multiple": false,
"required": true,
"types": [
{
"type": "property_name",
"named": true
}
]
}
},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "initializer",
"named": true
},
{
"type": "type",
"named": true
}
]
}
},
{
"type": "finally_clause",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "statement_block",
"named": true
}
]
}
}
},
{
"type": "for_in_statement",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "statement",
"named": true
}
]
},
"right": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "array_pattern",
"named": true
},
{
"type": "identifier",
"named": true
},
{
"type": "lazy_array_pattern",
"named": true
},
{
"type": "lazy_object_pattern",
"named": true
},
{
"type": "object_pattern",
"named": true
}
]
}
},
{
"type": "for_of_statement",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "statement",
"named": true
}
]
},
"right": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "array_pattern",
"named": true
},
{
"type": "expression",
"named": true
},
{
"type": "identifier",
"named": true
},
{
"type": "lazy_array_pattern",
"named": true
},
{
"type": "lazy_object_pattern",
"named": true
},
{
"type": "object_pattern",
"named": true
}
]
}
},
{
"type": "for_statement",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "statement",
"named": true
}
]
},
"condition": {
"multiple": false,
"required": true,
"types": [
{
"type": "empty_statement",
"named": true
},
{
"type": "expression_statement",
"named": true
}
]
},
"increment": {
"multiple": false,
"required": false,
"types": [
{
"type": "expression",
"named": true
}
]
},
"initializer": {
"multiple": false,
"required": true,
"types": [
{
"type": "empty_statement",
"named": true
},
{
"type": "expression_statement",
"named": true
},
{
"type": "lexical_declaration",
"named": true
},
{
"type": "variable_declaration",
"named": true
}
]
}
}
},
{
"type": "formal_parameters",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "required_parameter",
"named": true
},
{
"type": "rest_parameter",
"named": true
}
]
}
},
{
"type": "fragment_declaration",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "component_body",
"named": true
}
]
},
"name": {
"multiple": false,
"required": false,
"types": [
{
"type": "identifier",
"named": true
}
]
},
"parameters": {
"multiple": false,
"required": true,
"types": [
{
"type": "formal_parameters",
"named": true
}
]
},
"type_parameters": {
"multiple": false,
"required": false,
"types": [
{
"type": "type_parameters",
"named": true
}
]
}
},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "type",
"named": true
}
]
}
},
{
"type": "from_clause",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
},
{
"type": "string",
"named": true
}
]
}
},
{
"type": "function_declaration",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "statement_block",
"named": true
}
]
},
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
},
"parameters": {
"multiple": false,
"required": true,
"types": [
{
"type": "formal_parameters",
"named": true
}
]
},
"type_parameters": {
"multiple": false,
"required": false,
"types": [
{
"type": "type_parameters",
"named": true
}
]
}
},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "type",
"named": true
}
]
}
},
{
"type": "function_expression",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "statement_block",
"named": true
}
]
},
"name": {
"multiple": false,
"required": false,
"types": [
{
"type": "identifier",
"named": true
}
]
},
"parameters": {
"multiple": false,
"required": true,
"types": [
{
"type": "formal_parameters",
"named": true
}
]
},
"type_parameters": {
"multiple": false,
"required": false,
"types": [
{
"type": "type_parameters",
"named": true
}
]
}
},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "type",
"named": true
}
]
}
},
{
"type": "function_type",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "formal_parameters",
"named": true
},
{
"type": "type",
"named": true
},
{
"type": "type_parameters",
"named": true
}
]
}
},
{
"type": "generic_type",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "identifier",
"named": true
},
{
"type": "nested_type_identifier",
"named": true
},
{
"type": "type_arguments",
"named": true
}
]
}
},
{
"type": "if_statement",
"named": true,
"fields": {
"alternative": {
"multiple": false,
"required": false,
"types": [
{
"type": "statement",
"named": true
}
]
},
"condition": {
"multiple": false,
"required": true,
"types": [
{
"type": "parenthesized_expression",
"named": true
}
]
},
"consequence": {
"multiple": false,
"required": true,
"types": [
{
"type": "statement",
"named": true
}
]
}
}
},
{
"type": "import",
"named": true,
"fields": {}
},
{
"type": "import_clause",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "identifier",
"named": true
},
{
"type": "named_imports",
"named": true
},
{
"type": "namespace_import",
"named": true
}
]
}
},
{
"type": "import_specifier",
"named": true,
"fields": {
"alias": {
"multiple": false,
"required": false,
"types": [
{
"type": "identifier",
"named": true
}
]
},
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
},
{
"type": "string",
"named": true
}
]
}
}
},
{
"type": "import_statement",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "from_clause",
"named": true
},
{
"type": "import_clause",
"named": true
},
{
"type": "string",
"named": true
}
]
}
},
{
"type": "initializer",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
{
"type": "intersection_type",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "type",
"named": true
}
]
}
},
{
"type": "jsx_attribute",
"named": true,
"fields": {
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
},
{
"type": "jsx_hyphenated_name",
"named": true
},
{
"type": "jsx_namespace_name",
"named": true
}
]
},
"value": {
"multiple": false,
"required": false,
"types": [
{
"type": "jsx_element",
"named": true
},
{
"type": "jsx_expression",
"named": true
},
{
"type": "jsx_fragment",
"named": true
},
{
"type": "jsx_self_closing_element",
"named": true
},
{
"type": "string",
"named": true
}
]
}
}
},
{
"type": "jsx_closing_element",
"named": true,
"fields": {
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "jsx_element_name",
"named": true
}
]
}
}
},
{
"type": "jsx_closing_fragment",
"named": true,
"fields": {}
},
{
"type": "jsx_element",
"named": true,
"fields": {
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "jsx_element",
"named": true
},
{
"type": "jsx_expression",
"named": true
},
{
"type": "jsx_fragment",
"named": true
},
{
"type": "jsx_self_closing_element",
"named": true
},
{
"type": "jsx_text",
"named": true
}
]
},
"close_tag": {
"multiple": false,
"required": true,
"types": [
{
"type": "jsx_closing_element",
"named": true
}
]
},
"open_tag": {
"multiple": false,
"required": true,
"types": [
{
"type": "jsx_opening_element",
"named": true
}
]
}
}
},
{
"type": "jsx_element_name",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
},
{
"type": "jsx_member_name",
"named": true
},
{
"type": "jsx_namespace_name",
"named": true
},
{
"type": "member_expression",
"named": true
}
]
}
},
{
"type": "jsx_expression",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "arrow_function",
"named": true
},
{
"type": "component_statement",
"named": true
},
{
"type": "expression",
"named": true
},
{
"type": "function_expression",
"named": true
},
{
"type": "identifier",
"named": true
},
{
"type": "spread_element",
"named": true
},
{
"type": "style_directive",
"named": true
}
]
}
},
{
"type": "jsx_fragment",
"named": true,
"fields": {
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "jsx_element",
"named": true
},
{
"type": "jsx_expression",
"named": true
},
{
"type": "jsx_fragment",
"named": true
},
{
"type": "jsx_self_closing_element",
"named": true
},
{
"type": "jsx_text",
"named": true
}
]
},
"close_tag": {
"multiple": false,
"required": true,
"types": [
{
"type": "jsx_closing_fragment",
"named": true
}
]
},
"open_tag": {
"multiple": false,
"required": true,
"types": [
{
"type": "jsx_opening_fragment",
"named": true
}
]
}
}
},
{
"type": "jsx_hyphenated_name",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
}
},
{
"type": "jsx_member_name",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
}
},
{
"type": "jsx_namespace_name",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
}
},
{
"type": "jsx_non_namespaced_element_name",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
},
{
"type": "jsx_member_name",
"named": true
},
{
"type": "member_expression",
"named": true
}
]
}
},
{
"type": "jsx_opening_element",
"named": true,
"fields": {
"attribute": {
"multiple": true,
"required": false,
"types": [
{
"type": "jsx_attribute",
"named": true
},
{
"type": "jsx_expression",
"named": true
}
]
},
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "jsx_element_name",
"named": true
}
]
}
}
},
{
"type": "jsx_opening_fragment",
"named": true,
"fields": {}
},
{
"type": "jsx_self_closing_element",
"named": true,
"fields": {
"attribute": {
"multiple": true,
"required": false,
"types": [
{
"type": "jsx_attribute",
"named": true
},
{
"type": "jsx_expression",
"named": true
}
]
},
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "jsx_non_namespaced_element_name",
"named": true
}
]
}
}
},
{
"type": "labeled_statement",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "statement",
"named": true
}
]
},
"label": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
}
}
},
{
"type": "lazy_array_pattern",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "array_pattern",
"named": true
}
]
}
},
{
"type": "lazy_object_pattern",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "object_pattern",
"named": true
}
]
}
},
{
"type": "lexical_declaration",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "variable_declarator",
"named": true
}
]
}
},
{
"type": "literal_type",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "false",
"named": true
},
{
"type": "null",
"named": true
},
{
"type": "number",
"named": true
},
{
"type": "string",
"named": true
},
{
"type": "true",
"named": true
}
]
}
},
{
"type": "member_expression",
"named": true,
"fields": {
"object": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
},
"property": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
},
{
"type": "private_property_identifier",
"named": true
}
]
}
}
},
{
"type": "method_definition",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "statement_block",
"named": true
}
]
},
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "property_name",
"named": true
}
]
},
"parameters": {
"multiple": false,
"required": true,
"types": [
{
"type": "formal_parameters",
"named": true
}
]
},
"type_parameters": {
"multiple": false,
"required": false,
"types": [
{
"type": "type_parameters",
"named": true
}
]
}
},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "type",
"named": true
}
]
}
},
{
"type": "module_body",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "statement",
"named": true
}
]
}
},
{
"type": "module_declaration",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "module_body",
"named": true
}
]
},
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
}
}
},
{
"type": "named_imports",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "import_specifier",
"named": true
}
]
}
},
{
"type": "namespace_export",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
}
},
{
"type": "namespace_import",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
}
},
{
"type": "nested_type_identifier",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "identifier",
"named": true
},
{
"type": "nested_type_identifier",
"named": true
},
{
"type": "type_identifier",
"named": true
}
]
}
},
{
"type": "new_expression",
"named": true,
"fields": {
"arguments": {
"multiple": false,
"required": false,
"types": [
{
"type": "arguments",
"named": true
}
]
},
"constructor": {
"multiple": false,
"required": true,
"types": [
{
"type": "primary_expression",
"named": true
}
]
}
}
},
{
"type": "object",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "method_definition",
"named": true
},
{
"type": "pair",
"named": true
},
{
"type": "shorthand_property_identifier",
"named": true
},
{
"type": "spread_element",
"named": true
}
]
}
},
{
"type": "object_assignment_pattern",
"named": true,
"fields": {
"left": {
"multiple": false,
"required": true,
"types": [
{
"type": "arguments",
"named": false
},
{
"type": "await",
"named": false
},
{
"type": "component",
"named": false
},
{
"type": "fragment",
"named": false
},
{
"type": "shorthand_property_identifier_pattern",
"named": true
},
{
"type": "track",
"named": false
},
{
"type": "untrack",
"named": false
}
]
},
"right": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
}
},
{
"type": "object_pattern",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "object_assignment_pattern",
"named": true
},
{
"type": "pair_pattern",
"named": true
},
{
"type": "rest_pattern",
"named": true
},
{
"type": "shorthand_property_identifier_pattern",
"named": true
}
]
}
},
{
"type": "object_type",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "property_signature",
"named": true
}
]
}
},
{
"type": "pair",
"named": true,
"fields": {
"key": {
"multiple": false,
"required": true,
"types": [
{
"type": "property_name",
"named": true
}
]
},
"value": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
}
},
{
"type": "pair_pattern",
"named": true,
"fields": {
"key": {
"multiple": false,
"required": true,
"types": [
{
"type": "property_name",
"named": true
}
]
},
"value": {
"multiple": false,
"required": true,
"types": [
{
"type": "assignment_pattern",
"named": true
},
{
"type": "pattern",
"named": true
}
]
}
}
},
{
"type": "parenthesized_expression",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
{
"type": "parenthesized_type",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "type",
"named": true
}
]
}
},
{
"type": "pending_clause",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "statement_block",
"named": true
}
]
}
}
},
{
"type": "predefined_type",
"named": true,
"fields": {}
},
{
"type": "program",
"named": true,
"root": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "hash_bang_line",
"named": true
},
{
"type": "statement",
"named": true
}
]
}
},
{
"type": "property_name",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "computed_property_name",
"named": true
},
{
"type": "identifier",
"named": true
},
{
"type": "number",
"named": true
},
{
"type": "private_property_identifier",
"named": true
},
{
"type": "string",
"named": true
}
]
}
},
{
"type": "property_signature",
"named": true,
"fields": {
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "property_name",
"named": true
}
]
}
},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "type",
"named": true
}
]
}
},
{
"type": "regex",
"named": true,
"fields": {
"flags": {
"multiple": false,
"required": false,
"types": [
{
"type": "regex_flags",
"named": true
}
]
},
"pattern": {
"multiple": false,
"required": true,
"types": [
{
"type": "regex_pattern",
"named": true
}
]
}
}
},
{
"type": "required_parameter",
"named": true,
"fields": {
"pattern": {
"multiple": false,
"required": true,
"types": [
{
"type": "array_pattern",
"named": true
},
{
"type": "identifier",
"named": true
},
{
"type": "lazy_array_pattern",
"named": true
},
{
"type": "lazy_object_pattern",
"named": true
},
{
"type": "object_pattern",
"named": true
}
]
}
},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "initializer",
"named": true
},
{
"type": "type",
"named": true
}
]
}
},
{
"type": "rest_parameter",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "identifier",
"named": true
},
{
"type": "type",
"named": true
}
]
}
},
{
"type": "rest_pattern",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "identifier",
"named": true
}
]
}
},
{
"type": "return_statement",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
{
"type": "shorthand_property_identifier",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "shorthand_property_identifier_pattern",
"named": true
}
]
}
},
{
"type": "shorthand_property_identifier_pattern",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "shorthand_property_identifier",
"named": true
}
]
}
},
{
"type": "spread_element",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
{
"type": "statement_block",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "statement",
"named": true
}
]
}
},
{
"type": "string",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "escape_sequence",
"named": true
}
]
}
},
{
"type": "style_directive",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "string",
"named": true
}
]
}
},
{
"type": "style_element",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "jsx_attribute",
"named": true
},
{
"type": "jsx_expression",
"named": true
},
{
"type": "raw_text",
"named": true
}
]
}
},
{
"type": "subscript_expression",
"named": true,
"fields": {
"index": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
},
"object": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
}
},
{
"type": "switch_body",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "switch_case",
"named": true
},
{
"type": "switch_default",
"named": true
}
]
}
},
{
"type": "switch_case",
"named": true,
"fields": {
"value": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "statement",
"named": true
}
]
}
},
{
"type": "switch_default",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "statement",
"named": true
}
]
}
},
{
"type": "switch_statement",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "switch_body",
"named": true
}
]
},
"value": {
"multiple": false,
"required": true,
"types": [
{
"type": "parenthesized_expression",
"named": true
}
]
}
}
},
{
"type": "template_string",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "template_substitution",
"named": true
}
]
}
},
{
"type": "template_substitution",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
{
"type": "ternary_expression",
"named": true,
"fields": {
"alternative": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
},
"condition": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
},
"consequence": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
}
},
{
"type": "throw_statement",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
{
"type": "try_statement",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "statement_block",
"named": true
}
]
},
"finalizer": {
"multiple": false,
"required": false,
"types": [
{
"type": "finally_clause",
"named": true
}
]
},
"handler": {
"multiple": false,
"required": false,
"types": [
{
"type": "catch_clause",
"named": true
}
]
},
"pending": {
"multiple": false,
"required": false,
"types": [
{
"type": "pending_clause",
"named": true
}
]
}
}
},
{
"type": "tuple_type",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "type",
"named": true
}
]
}
},
{
"type": "type",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": true,
"types": [
{
"type": "array_type",
"named": true
},
{
"type": "function_type",
"named": true
},
{
"type": "generic_type",
"named": true
},
{
"type": "identifier",
"named": true
},
{
"type": "intersection_type",
"named": true
},
{
"type": "literal_type",
"named": true
},
{
"type": "nested_type_identifier",
"named": true
},
{
"type": "object_type",
"named": true
},
{
"type": "parenthesized_type",
"named": true
},
{
"type": "predefined_type",
"named": true
},
{
"type": "tuple_type",
"named": true
},
{
"type": "type_identifier",
"named": true
},
{
"type": "union_type",
"named": true
}
]
}
},
{
"type": "type_arguments",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "type",
"named": true
}
]
}
},
{
"type": "type_identifier",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "type_identifier",
"named": true
}
]
}
},
{
"type": "type_parameter",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "identifier",
"named": true
},
{
"type": "type",
"named": true
}
]
}
},
{
"type": "type_parameters",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "type_parameter",
"named": true
}
]
}
},
{
"type": "unary_expression",
"named": true,
"fields": {
"argument": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
},
"operator": {
"multiple": false,
"required": true,
"types": [
{
"type": "!",
"named": false
},
{
"type": "+",
"named": false
},
{
"type": "-",
"named": false
},
{
"type": "delete",
"named": false
},
{
"type": "typeof",
"named": false
},
{
"type": "void",
"named": false
},
{
"type": "~",
"named": false
}
]
}
}
},
{
"type": "union_type",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "type",
"named": true
}
]
}
},
{
"type": "update_expression",
"named": true,
"fields": {
"argument": {
"multiple": false,
"required": true,
"types": [
{
"type": "expression",
"named": true
}
]
},
"operator": {
"multiple": false,
"required": true,
"types": [
{
"type": "++",
"named": false
},
{
"type": "--",
"named": false
}
]
}
}
},
{
"type": "variable_declaration",
"named": true,
"fields": {},
"children": {
"multiple": true,
"required": true,
"types": [
{
"type": "variable_declarator",
"named": true
}
]
}
},
{
"type": "variable_declarator",
"named": true,
"fields": {
"name": {
"multiple": false,
"required": true,
"types": [
{
"type": "array_pattern",
"named": true
},
{
"type": "identifier",
"named": true
},
{
"type": "lazy_array_pattern",
"named": true
},
{
"type": "lazy_object_pattern",
"named": true
},
{
"type": "object_pattern",
"named": true
}
]
}
},
"children": {
"multiple": true,
"required": false,
"types": [
{
"type": "initializer",
"named": true
},
{
"type": "type",
"named": true
}
]
}
},
{
"type": "while_statement",
"named": true,
"fields": {
"body": {
"multiple": false,
"required": true,
"types": [
{
"type": "statement",
"named": true
}
]
},
"condition": {
"multiple": false,
"required": true,
"types": [
{
"type": "parenthesized_expression",
"named": true
}
]
}
}
},
{
"type": "yield_expression",
"named": true,
"fields": {},
"children": {
"multiple": false,
"required": false,
"types": [
{
"type": "expression",
"named": true
}
]
}
},
{
"type": "!",
"named": false
},
{
"type": "!=",
"named": false
},
{
"type": "!==",
"named": false
},
{
"type": "\"",
"named": false
},
{
"type": "${",
"named": false
},
{
"type": "%",
"named": false
},
{
"type": "%=",
"named": false
},
{
"type": "&",
"named": false
},
{
"type": "&&",
"named": false
},
{
"type": "&&=",
"named": false
},
{
"type": "&=",
"named": false
},
{
"type": "'",
"named": false
},
{
"type": "(",
"named": false
},
{
"type": ")",
"named": false
},
{
"type": "*",
"named": false
},
{
"type": "**",
"named": false
},
{
"type": "**=",
"named": false
},
{
"type": "*=",
"named": false
},
{
"type": "+",
"named": false
},
{
"type": "++",
"named": false
},
{
"type": "+=",
"named": false
},
{
"type": ",",
"named": false
},
{
"type": "-",
"named": false
},
{
"type": "--",
"named": false
},
{
"type": "-=",
"named": false
},
{
"type": ".",
"named": false
},
{
"type": "...",
"named": false
},
{
"type": "/",
"named": false
},
{
"type": "/=",
"named": false
},
{
"type": "/>",
"named": false
},
{
"type": ":",
"named": false
},
{
"type": ";",
"named": false
},
{
"type": "<",
"named": false
},
{
"type": "</",
"named": false
},
{
"type": "</style>",
"named": false
},
{
"type": "<<",
"named": false
},
{
"type": "<<=",
"named": false
},
{
"type": "<=",
"named": false
},
{
"type": "<style",
"named": false
},
{
"type": "=",
"named": false
},
{
"type": "==",
"named": false
},
{
"type": "===",
"named": false
},
{
"type": "=>",
"named": false
},
{
"type": ">",
"named": false
},
{
"type": ">=",
"named": false
},
{
"type": ">>",
"named": false
},
{
"type": ">>=",
"named": false
},
{
"type": ">>>",
"named": false
},
{
"type": ">>>=",
"named": false
},
{
"type": "?",
"named": false
},
{
"type": "?.",
"named": false
},
{
"type": "??",
"named": false
},
{
"type": "??=",
"named": false
},
{
"type": "@",
"named": false
},
{
"type": "[",
"named": false
},
{
"type": "]",
"named": false
},
{
"type": "^",
"named": false
},
{
"type": "^=",
"named": false
},
{
"type": "`",
"named": false
},
{
"type": "abstract",
"named": false
},
{
"type": "any",
"named": false
},
{
"type": "arguments",
"named": false
},
{
"type": "as",
"named": false
},
{
"type": "async",
"named": false
},
{
"type": "await",
"named": false
},
{
"type": "boolean",
"named": false
},
{
"type": "break",
"named": false
},
{
"type": "case",
"named": false
},
{
"type": "catch",
"named": false
},
{
"type": "class",
"named": false
},
{
"type": "comment",
"named": true,
"extra": true
},
{
"type": "component",
"named": false
},
{
"type": "const",
"named": false
},
{
"type": "continue",
"named": false
},
{
"type": "debugger",
"named": false
},
{
"type": "declare",
"named": false
},
{
"type": "default",
"named": false
},
{
"type": "delete",
"named": false
},
{
"type": "do",
"named": false
},
{
"type": "else",
"named": false
},
{
"type": "escape_sequence",
"named": true
},
{
"type": "export",
"named": false
},
{
"type": "extends",
"named": false
},
{
"type": "false",
"named": true
},
{
"type": "finally",
"named": false
},
{
"type": "for",
"named": false
},
{
"type": "fragment",
"named": false
},
{
"type": "from",
"named": false
},
{
"type": "function",
"named": false
},
{
"type": "get",
"named": false
},
{
"type": "hash_bang_line",
"named": true
},
{
"type": "html",
"named": false
},
{
"type": "identifier",
"named": true
},
{
"type": "if",
"named": false
},
{
"type": "implements",
"named": false
},
{
"type": "import",
"named": false
},
{
"type": "in",
"named": false
},
{
"type": "index",
"named": false
},
{
"type": "instanceof",
"named": false
},
{
"type": "jsx_text",
"named": true
},
{
"type": "key",
"named": false
},
{
"type": "let",
"named": false
},
{
"type": "module",
"named": false
},
{
"type": "never",
"named": false
},
{
"type": "new",
"named": false
},
{
"type": "null",
"named": true
},
{
"type": "number",
"named": false
},
{
"type": "number",
"named": true
},
{
"type": "object",
"named": false
},
{
"type": "of",
"named": false
},
{
"type": "override",
"named": false
},
{
"type": "pending",
"named": false
},
{
"type": "private_property_identifier",
"named": true
},
{
"type": "raw_text",
"named": true
},
{
"type": "readonly",
"named": false
},
{
"type": "ref",
"named": false
},
{
"type": "regex_flags",
"named": true
},
{
"type": "regex_pattern",
"named": true
},
{
"type": "return",
"named": false
},
{
"type": "set",
"named": false
},
{
"type": "static",
"named": false
},
{
"type": "string",
"named": false
},
{
"type": "style",
"named": false
},
{
"type": "super",
"named": true
},
{
"type": "switch",
"named": false
},
{
"type": "symbol",
"named": false
},
{
"type": "text",
"named": false
},
{
"type": "this",
"named": true
},
{
"type": "throw",
"named": false
},
{
"type": "track",
"named": false
},
{
"type": "true",
"named": true
},
{
"type": "try",
"named": false
},
{
"type": "type",
"named": false
},
{
"type": "typeof",
"named": false
},
{
"type": "undefined",
"named": true
},
{
"type": "unknown",
"named": false
},
{
"type": "untrack",
"named": false
},
{
"type": "var",
"named": false
},
{
"type": "void",
"named": false
},
{
"type": "while",
"named": false
},
{
"type": "yield",
"named": false
},
{
"type": "{",
"named": false
},
{
"type": "|",
"named": false
},
{
"type": "|=",
"named": false
},
{
"type": "||",
"named": false
},
{
"type": "||=",
"named": false
},
{
"type": "}",
"named": false
},
{
"type": "~",
"named": false
}
]
```
## /grammars/tree-sitter/src/scanner.c
```c path="/grammars/tree-sitter/src/scanner.c"
#include <tree_sitter/parser.h>
#include <wctype.h>
enum TokenType {
AUTOMATIC_SEMICOLON,
TEMPLATE_CHARS,
TERNARY_QMARK,
JSX_TEXT,
};
void *tree_sitter_ripple_external_scanner_create() { return NULL; }
void tree_sitter_ripple_external_scanner_destroy(void *p) {}
void tree_sitter_ripple_external_scanner_reset(void *p) {}
unsigned tree_sitter_ripple_external_scanner_serialize(void *p, char *buffer) { return 0; }
void tree_sitter_ripple_external_scanner_deserialize(void *p, const char *b, unsigned n) {}
static void advance(TSLexer *lexer) { lexer->advance(lexer, false); }
static void skip(TSLexer *lexer) { lexer->advance(lexer, true); }
static bool scan_whitespace_and_comments(TSLexer *lexer) {
for (;;) {
while (iswspace(lexer->lookahead)) {
skip(lexer);
}
if (lexer->lookahead == '/') {
skip(lexer);
if (lexer->lookahead == '/') {
skip(lexer);
while (lexer->lookahead != 0 && lexer->lookahead != '\n') {
skip(lexer);
}
} else if (lexer->lookahead == '*') {
skip(lexer);
while (true) {
if (lexer->lookahead == 0) return false;
if (lexer->lookahead == '*') {
skip(lexer);
if (lexer->lookahead == '/') {
skip(lexer);
break;
}
} else {
skip(lexer);
}
}
} else {
return false;
}
} else {
return true;
}
}
}
static bool scan_automatic_semicolon(TSLexer *lexer) {
lexer->result_symbol = AUTOMATIC_SEMICOLON;
lexer->mark_end(lexer);
for (;;) {
if (lexer->lookahead == 0) return true;
if (lexer->lookahead == '}') return true;
if (lexer->is_at_included_range_start(lexer)) return true;
if (lexer->lookahead == '\n') break;
if (!iswspace(lexer->lookahead)) return false;
skip(lexer);
}
skip(lexer);
if (!scan_whitespace_and_comments(lexer)) return false;
if (lexer->lookahead == ',') return false;
if (lexer->lookahead == '.') return false;
if (lexer->lookahead == ':') return false;
if (lexer->lookahead == ';') return false;
if (lexer->lookahead == '*') return false;
if (lexer->lookahead == '%') return false;
if (lexer->lookahead == '^') return false;
if (lexer->lookahead == '+') return false;
if (lexer->lookahead == '-') return false;
if (lexer->lookahead == '/') return false;
if (lexer->lookahead == '<') return false;
if (lexer->lookahead == '=') return false;
if (lexer->lookahead == '>') return false;
if (lexer->lookahead == '|') return false;
if (lexer->lookahead == '&') return false;
if (lexer->lookahead == '?') return false;
if (lexer->lookahead == '[') return false;
if (lexer->lookahead == '(') return false;
return true;
}
static bool scan_template_chars(TSLexer *lexer) {
lexer->result_symbol = TEMPLATE_CHARS;
for (bool has_content = false;; has_content = true) {
lexer->mark_end(lexer);
switch (lexer->lookahead) {
case '`':
return has_content;
case '{{contextString}}#39;:
advance(lexer);
if (lexer->lookahead == '{') {
return has_content;
}
break;
case '\\':
return has_content;
case 0:
return false;
default:
advance(lexer);
}
}
}
static bool scan_ternary_qmark(TSLexer *lexer) {
for (;;) {
if (!iswspace(lexer->lookahead)) break;
skip(lexer);
}
if (lexer->lookahead == '?') {
advance(lexer);
if (lexer->lookahead != '?') {
lexer->mark_end(lexer);
lexer->result_symbol = TERNARY_QMARK;
if (lexer->lookahead == '.') return false;
return true;
}
}
return false;
}
static bool scan_jsx_text(TSLexer *lexer) {
lexer->result_symbol = JSX_TEXT;
for (bool has_content = false;; has_content = true) {
lexer->mark_end(lexer);
switch (lexer->lookahead) {
case '<':
case '{':
case 0:
return has_content;
default:
advance(lexer);
}
}
}
bool tree_sitter_ripple_external_scanner_scan(void *payload, TSLexer *lexer,
const bool *valid_symbols) {
if (valid_symbols[TEMPLATE_CHARS]) {
return scan_template_chars(lexer);
}
if (valid_symbols[AUTOMATIC_SEMICOLON]) {
bool ret = scan_automatic_semicolon(lexer);
if (!ret && !valid_symbols[TERNARY_QMARK] && lexer->lookahead == '?') {
return false;
}
return ret;
}
if (valid_symbols[TERNARY_QMARK]) {
return scan_ternary_qmark(lexer);
}
if (valid_symbols[JSX_TEXT]) {
return scan_jsx_text(lexer);
}
return false;
}
```
## /grammars/tree-sitter/src/tree_sitter/alloc.h
```h path="/grammars/tree-sitter/src/tree_sitter/alloc.h"
#ifndef TREE_SITTER_ALLOC_H_
#define TREE_SITTER_ALLOC_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
// Allow clients to override allocation functions
#ifdef TREE_SITTER_REUSE_ALLOCATOR
extern void *(*ts_current_malloc)(size_t size);
extern void *(*ts_current_calloc)(size_t count, size_t size);
extern void *(*ts_current_realloc)(void *ptr, size_t size);
extern void (*ts_current_free)(void *ptr);
#ifndef ts_malloc
#define ts_malloc ts_current_malloc
#endif
#ifndef ts_calloc
#define ts_calloc ts_current_calloc
#endif
#ifndef ts_realloc
#define ts_realloc ts_current_realloc
#endif
#ifndef ts_free
#define ts_free ts_current_free
#endif
#else
#ifndef ts_malloc
#define ts_malloc malloc
#endif
#ifndef ts_calloc
#define ts_calloc calloc
#endif
#ifndef ts_realloc
#define ts_realloc realloc
#endif
#ifndef ts_free
#define ts_free free
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_ALLOC_H_
```
## /grammars/tree-sitter/src/tree_sitter/array.h
```h path="/grammars/tree-sitter/src/tree_sitter/array.h"
#ifndef TREE_SITTER_ARRAY_H_
#define TREE_SITTER_ARRAY_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "./alloc.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4101)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"
#endif
#define Array(T) \
struct { \
T *contents; \
uint32_t size; \
uint32_t capacity; \
}
/// Initialize an array.
#define array_init(self) \
((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL)
/// Create an empty array.
#define array_new() \
{ NULL, 0, 0 }
/// Get a pointer to the element at a given `index` in the array.
#define array_get(self, _index) \
(assert((uint32_t)(_index) < (self)->size), &(self)->contents[_index])
/// Get a pointer to the first element in the array.
#define array_front(self) array_get(self, 0)
/// Get a pointer to the last element in the array.
#define array_back(self) array_get(self, (self)->size - 1)
/// Clear the array, setting its size to zero. Note that this does not free any
/// memory allocated for the array's contents.
#define array_clear(self) ((self)->size = 0)
/// Reserve `new_capacity` elements of space in the array. If `new_capacity` is
/// less than the array's current capacity, this function has no effect.
#define array_reserve(self, new_capacity) \
((self)->contents = _array__reserve( \
(void *)(self)->contents, &(self)->capacity, \
array_elem_size(self), new_capacity) \
)
/// Free any memory allocated for this array. Note that this does not free any
/// memory allocated for the array's contents.
#define array_delete(self) \
do { \
if ((self)->contents) ts_free((self)->contents); \
(self)->contents = NULL; \
(self)->size = 0; \
(self)->capacity = 0; \
} while (0)
/// Push a new `element` onto the end of the array.
#define array_push(self, element) \
do { \
(self)->contents = _array__grow( \
(void *)(self)->contents, (self)->size, &(self)->capacity, \
1, array_elem_size(self) \
); \
(self)->contents[(self)->size++] = (element); \
} while(0)
/// Increase the array's size by `count` elements.
/// New elements are zero-initialized.
#define array_grow_by(self, count) \
do { \
if ((count) == 0) break; \
(self)->contents = _array__grow( \
(self)->contents, (self)->size, &(self)->capacity, \
count, array_elem_size(self) \
); \
memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \
(self)->size += (count); \
} while (0)
/// Append all elements from one array to the end of another.
#define array_push_all(self, other) \
array_extend((self), (other)->size, (other)->contents)
/// Append `count` elements to the end of the array, reading their values from the
/// `contents` pointer.
#define array_extend(self, count, other_contents) \
(self)->contents = _array__splice( \
(void*)(self)->contents, &(self)->size, &(self)->capacity, \
array_elem_size(self), (self)->size, 0, count, other_contents \
)
/// Remove `old_count` elements from the array starting at the given `index`. At
/// the same index, insert `new_count` new elements, reading their values from the
/// `new_contents` pointer.
#define array_splice(self, _index, old_count, new_count, new_contents) \
(self)->contents = _array__splice( \
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
array_elem_size(self), _index, old_count, new_count, new_contents \
)
/// Insert one `element` into the array at the given `index`.
#define array_insert(self, _index, element) \
(self)->contents = _array__splice( \
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
array_elem_size(self), _index, 0, 1, &(element) \
)
/// Remove one element from the array at the given `index`.
#define array_erase(self, _index) \
_array__erase((void *)(self)->contents, &(self)->size, array_elem_size(self), _index)
/// Pop the last element off the array, returning the element by value.
#define array_pop(self) ((self)->contents[--(self)->size])
/// Assign the contents of one array to another, reallocating if necessary.
#define array_assign(self, other) \
(self)->contents = _array__assign( \
(void *)(self)->contents, &(self)->size, &(self)->capacity, \
(const void *)(other)->contents, (other)->size, array_elem_size(self) \
)
/// Swap one array with another
#define array_swap(self, other) \
do { \
void *_array_swap_tmp = (void *)(self)->contents; \
(self)->contents = (other)->contents; \
(other)->contents = _array_swap_tmp; \
_array__swap(&(self)->size, &(self)->capacity, \
&(other)->size, &(other)->capacity); \
} while (0)
/// Get the size of the array contents
#define array_elem_size(self) (sizeof *(self)->contents)
/// Search a sorted array for a given `needle` value, using the given `compare`
/// callback to determine the order.
///
/// If an existing element is found to be equal to `needle`, then the `index`
/// out-parameter is set to the existing value's index, and the `exists`
/// out-parameter is set to true. Otherwise, `index` is set to an index where
/// `needle` should be inserted in order to preserve the sorting, and `exists`
/// is set to false.
#define array_search_sorted_with(self, compare, needle, _index, _exists) \
_array__search_sorted(self, 0, compare, , needle, _index, _exists)
/// Search a sorted array for a given `needle` value, using integer comparisons
/// of a given struct field (specified with a leading dot) to determine the order.
///
/// See also `array_search_sorted_with`.
#define array_search_sorted_by(self, field, needle, _index, _exists) \
_array__search_sorted(self, 0, _compare_int, field, needle, _index, _exists)
/// Insert a given `value` into a sorted array, using the given `compare`
/// callback to determine the order.
#define array_insert_sorted_with(self, compare, value) \
do { \
unsigned _index, _exists; \
array_search_sorted_with(self, compare, &(value), &_index, &_exists); \
if (!_exists) array_insert(self, _index, value); \
} while (0)
/// Insert a given `value` into a sorted array, using integer comparisons of
/// a given struct field (specified with a leading dot) to determine the order.
///
/// See also `array_search_sorted_by`.
#define array_insert_sorted_by(self, field, value) \
do { \
unsigned _index, _exists; \
array_search_sorted_by(self, field, (value) field, &_index, &_exists); \
if (!_exists) array_insert(self, _index, value); \
} while (0)
// Private
// Pointers to individual `Array` fields (rather than the entire `Array` itself)
// are passed to the various `_array__*` functions below to address strict aliasing
// violations that arises when the _entire_ `Array` struct is passed as `Array(void)*`.
//
// The `Array` type itself was not altered as a solution in order to avoid breakage
// with existing consumers (in particular, parsers with external scanners).
/// This is not what you're looking for, see `array_erase`.
static inline void _array__erase(void* self_contents, uint32_t *size,
size_t element_size, uint32_t index) {
assert(index < *size);
char *contents = (char *)self_contents;
memmove(contents + index * element_size, contents + (index + 1) * element_size,
(*size - index - 1) * element_size);
(*size)--;
}
/// This is not what you're looking for, see `array_reserve`.
static inline void *_array__reserve(void *contents, uint32_t *capacity,
size_t element_size, uint32_t new_capacity) {
void *new_contents = contents;
if (new_capacity > *capacity) {
if (contents) {
new_contents = ts_realloc(contents, new_capacity * element_size);
} else {
new_contents = ts_malloc(new_capacity * element_size);
}
*capacity = new_capacity;
}
return new_contents;
}
/// This is not what you're looking for, see `array_assign`.
static inline void *_array__assign(void* self_contents, uint32_t *self_size, uint32_t *self_capacity,
const void *other_contents, uint32_t other_size, size_t element_size) {
void *new_contents = _array__reserve(self_contents, self_capacity, element_size, other_size);
*self_size = other_size;
memcpy(new_contents, other_contents, *self_size * element_size);
return new_contents;
}
/// This is not what you're looking for, see `array_swap`.
static inline void _array__swap(uint32_t *self_size, uint32_t *self_capacity,
uint32_t *other_size, uint32_t *other_capacity) {
uint32_t tmp_size = *self_size;
uint32_t tmp_capacity = *self_capacity;
*self_size = *other_size;
*self_capacity = *other_capacity;
*other_size = tmp_size;
*other_capacity = tmp_capacity;
}
/// This is not what you're looking for, see `array_push` or `array_grow_by`.
static inline void *_array__grow(void *contents, uint32_t size, uint32_t *capacity,
uint32_t count, size_t element_size) {
void *new_contents = contents;
uint32_t new_size = size + count;
if (new_size > *capacity) {
uint32_t new_capacity = *capacity * 2;
if (new_capacity < 8) new_capacity = 8;
if (new_capacity < new_size) new_capacity = new_size;
new_contents = _array__reserve(contents, capacity, element_size, new_capacity);
}
return new_contents;
}
/// This is not what you're looking for, see `array_splice`.
static inline void *_array__splice(void *self_contents, uint32_t *size, uint32_t *capacity,
size_t element_size,
uint32_t index, uint32_t old_count,
uint32_t new_count, const void *elements) {
uint32_t new_size = *size + new_count - old_count;
uint32_t old_end = index + old_count;
uint32_t new_end = index + new_count;
assert(old_end <= *size);
void *new_contents = _array__reserve(self_contents, capacity, element_size, new_size);
char *contents = (char *)new_contents;
if (*size > old_end) {
memmove(
contents + new_end * element_size,
contents + old_end * element_size,
(*size - old_end) * element_size
);
}
if (new_count > 0) {
if (elements) {
memcpy(
(contents + index * element_size),
elements,
new_count * element_size
);
} else {
memset(
(contents + index * element_size),
0,
new_count * element_size
);
}
}
*size += new_count - old_count;
return new_contents;
}
/// A binary search routine, based on Rust's `std::slice::binary_search_by`.
/// This is not what you're looking for, see `array_search_sorted_with` or `array_search_sorted_by`.
#define _array__search_sorted(self, start, compare, suffix, needle, _index, _exists) \
do { \
*(_index) = start; \
*(_exists) = false; \
uint32_t size = (self)->size - *(_index); \
if (size == 0) break; \
int comparison; \
while (size > 1) { \
uint32_t half_size = size / 2; \
uint32_t mid_index = *(_index) + half_size; \
comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \
if (comparison <= 0) *(_index) = mid_index; \
size -= half_size; \
} \
comparison = compare(&((self)->contents[*(_index)] suffix), (needle)); \
if (comparison == 0) *(_exists) = true; \
else if (comparison < 0) *(_index) += 1; \
} while (0)
/// Helper macro for the `_sorted_by` routines below. This takes the left (existing)
/// parameter by reference in order to work with the generic sorting function above.
#define _compare_int(a, b) ((int)*(a) - (int)(b))
#ifdef _MSC_VER
#pragma warning(pop)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#ifdef __cplusplus
}
#endif
#endif // TREE_SITTER_ARRAY_H_
```
## /grammars/tree-sitter/test/corpus/components.txt
==================
Component Declaration
==================
component Button(props: { text: string }) {
<button>{props.text}</button>
}
---
(program
(component_declaration
name: (identifier)
parameters: (formal_parameters
(required_parameter
pattern: (identifier)
(type
(object_type
(property_signature
name: (property_name
(identifier))
(type
(predefined_type)))))))
body: (component_body
(component_statement
(expression_statement
(jsx_element
open_tag: (jsx_opening_element
name: (jsx_element_name
(identifier)))
children: (jsx_expression
(component_statement
(expression_statement
(member_expression
object: (identifier)
property: (identifier)))))
close_tag: (jsx_closing_element
name: (jsx_element_name
(identifier)))))))))
==================
Export Component
==================
export component App() {
<div>{'Hello World'}</div>
}
---
(program
(export_statement
(component_declaration
name: (identifier)
parameters: (formal_parameters)
body: (component_body
(component_statement
(expression_statement
(jsx_element
open_tag: (jsx_opening_element
name: (jsx_element_name
(identifier)))
children: (jsx_expression
(component_statement
(expression_statement
(string))))
close_tag: (jsx_closing_element
name: (jsx_element_name
(identifier))))))))))
==================
Fragment Declaration
==================
fragment ListItems(props: { items: Array<string> }) {
for (const item of props.items) {
<li>{item}</li>
}
}
---
(program
(fragment_declaration
name: (identifier)
parameters: (formal_parameters
(required_parameter
pattern: (identifier)
(type
(object_type
(property_signature
name: (property_name
(identifier))
(type
(generic_type
(identifier)
(type_arguments
(type
(predefined_type))))))))))
body: (component_body
(component_statement
(for_of_statement
(identifier)
right: (member_expression
object: (identifier)
property: (identifier))
body: (statement_block
(expression_statement
(jsx_element
open_tag: (jsx_opening_element
name: (jsx_element_name
(identifier)))
children: (jsx_expression
(component_statement
(expression_statement
(identifier))))
close_tag: (jsx_closing_element
name: (jsx_element_name
(identifier)))))))))))
==================
Children Prop
==================
component Card({ children }) {
<div class="card">
{children}
</div>
}
---
(program
(component_declaration
name: (identifier)
parameters: (formal_parameters
(required_parameter
pattern: (object_pattern
(shorthand_property_identifier_pattern
(shorthand_property_identifier)))))
body: (component_body
(component_statement
(expression_statement
(jsx_element
open_tag: (jsx_opening_element
name: (jsx_element_name
(identifier))
attribute: (jsx_attribute
name: (identifier)
value: (string)))
children: (jsx_text)
children: (jsx_expression
(component_statement
(expression_statement
(identifier))))
children: (jsx_text)
close_tag: (jsx_closing_element
name: (jsx_element_name
(identifier)))))))))
## /grammars/tree-sitter/test/corpus/main.txt
## /grammars/tree-sitter/test/corpus/reactivity.txt
==================
Ripple Server Module Import And Style Directive
==================
module server {
export const data = () => null;
}
import { data as serverData } from server;
const element = <Child className={style 'button'} />;
---
(program
(module_declaration
name: (identifier)
body: (module_body
(export_statement
(variable_declaration
(variable_declarator
name: (identifier)
(initializer
(arrow_function
parameters: (formal_parameters)
body: (null))))))))
(import_statement
(import_clause
(named_imports
(import_specifier
name: (identifier)
alias: (identifier))))
(from_clause
(identifier)))
(variable_declaration
(variable_declarator
name: (identifier)
(initializer
(jsx_self_closing_element
name: (jsx_non_namespaced_element_name
(identifier))
attribute: (jsx_attribute
name: (identifier)
value: (jsx_expression
(style_directive
(string)))))))))
## /grammars/tree-sitter/tree-sitter.json
```json path="/grammars/tree-sitter/tree-sitter.json"
{
"$schema": "https://tree-sitter.github.io/tree-sitter/assets/schemas/config.schema.json",
"grammars": [
{
"name": "ripple",
"camelcase": "Ripple",
"title": "Ripple",
"scope": "source.tsrx",
"file-types": ["ripple"],
"injection-regex": "^ripple{{contextString}}quot;,
"class-name": "TreeSitterRipple"
}
],
"metadata": {
"version": "0.1.0",
"license": "MIT",
"description": "Ripple grammar for tree-sitter",
"authors": [
{
"name": "Ripple"
}
],
"links": {
"repository": "https://github.com/trueadm/ripple/grammars/tree-sitter"
}
},
"bindings": {
"c": false,
"go": false,
"node": true,
"python": false,
"rust": true,
"swift": false,
"zig": false
}
}
```
## /packages/adapter-bun/package.json
```json path="/packages/adapter-bun/package.json"
{
"name": "@ripple-ts/adapter-bun",
"description": "Bun adapter for Ripple metaframework (Web Request/Response bridge)",
"license": "MIT",
"author": "Dominic Gannaway",
"version": "0.3.61",
"type": "module",
"module": "src/index.js",
"main": "src/index.js",
"exports": {
".": {
"types": "./types/index.d.ts",
"import": "./src/index.js",
"default": "./src/index.js"
}
},
"scripts": {
"test": "pnpm -w test --project adapter-bun"
},
"dependencies": {
"@ripple-ts/adapter": "workspace:*"
},
"devDependencies": {
"@types/bun": "catalog:default"
},
"homepage": "https://ripple-ts.com",
"repository": {
"type": "git",
"url": "git+https://github.com/Ripple-TS/ripple.git",
"directory": "packages/adapter-bun"
},
"peerDependencies": {
"bun": "^1.0.0"
},
"bugs": {
"url": "https://github.com/Ripple-TS/ripple/issues"
}
}
```
## /packages/create-ripple/src/index.js
```js path="/packages/create-ripple/src/index.js"
#!/usr/bin/env node
import '@ripple-ts/cli';
```
The content has been capped at 50000 tokens. The user could consider applying other filters to refine the result. The better and more specific the context, the better the LLM can follow instructions. If the context seems verbose, the user can refine the filter using uithub. Thank you for using https://uithub.com - Perfect LLM context for any GitHub repo.