├── .npmrc
├── README.md
├── .github
├── FUNDING.yml
└── workflows
│ ├── release-pr.yml
│ └── unit-test.yml
├── packages
├── compiler-rs
│ ├── rustfmt.toml
│ ├── tests
│ │ ├── mod.rs
│ │ ├── transform
│ │ │ ├── mod.rs
│ │ │ ├── snapshots
│ │ │ │ ├── r#mod__transform__ssr__ssr_export.snap
│ │ │ │ ├── r#mod__transform__ssr__ssr_export_default.snap
│ │ │ │ ├── r#mod__transform__hmr__export.snap
│ │ │ │ ├── r#mod__transform__hmr__export_default_with_function_declaration.snap
│ │ │ │ ├── r#mod__transform__hmr__export_default_with_identifier.snap
│ │ │ │ ├── r#mod__transform__hmr__export_default.snap
│ │ │ │ ├── r#mod__transform__hmr__exports_with_define_component.snap
│ │ │ │ ├── r#mod__transform__interop__basic.snap
│ │ │ │ └── r#mod__transform__hmr__exports.snap
│ │ │ ├── interop.rs
│ │ │ └── ssr.rs
│ │ └── vapor
│ │ │ ├── snapshots
│ │ │ ├── r#mod__vapor__transform_element__component_.snap
│ │ │ ├── r#mod__vapor__transform_element__component_dynamic_props.snap
│ │ │ ├── r#mod__vapor__transform_children__fragment.snap
│ │ │ ├── r#mod__vapor__transform_text__consecutive_text.snap
│ │ │ ├── r#mod__vapor__transform_children__comments.snap
│ │ │ ├── r#mod__vapor__transform_text__on_consecutive_text.snap
│ │ │ ├── r#mod__vapor__v_once__inside_v_once.snap
│ │ │ ├── r#mod__vapor__transform_text__interpolation.snap
│ │ │ ├── r#mod__vapor__transform_text__text_like.snap
│ │ │ ├── r#mod__vapor__transform_element__props_children.snap
│ │ │ ├── r#mod__vapor__transform_element__static_props.snap
│ │ │ ├── r#mod__vapor__transform_element__component_fragment_should_not_mark_as_single_root.snap
│ │ │ ├── r#mod__vapor__transform_text__static_template.snap
│ │ │ ├── r#mod__vapor__v_bind__no_expression.snap
│ │ │ ├── r#mod__vapor__v_once__as_root_node.snap
│ │ │ ├── r#mod__vapor__v_show__basic.snap
│ │ │ ├── r#mod__vapor__transform_element__component_generate_single_root_component.snap
│ │ │ ├── r#mod__vapor__v_on__namespace_event_with_component.snap
│ │ │ ├── r#mod__vapor__transform_element__component_resolve_namespaced_component.snap
│ │ │ ├── r#mod__vapor__transform_element__component_event_with_once_modifier.snap
│ │ │ ├── r#mod__vapor__transform_text__escapes_raw_static_text_when_generating_the_template_string.snap
│ │ │ ├── r#mod__vapor__v_bind__attr_modifier_with_no_expression.snap
│ │ │ ├── r#mod__vapor__v_bind__camel_modifier_with_no_expression.snap
│ │ │ ├── r#mod__vapor__v_bind__prop_modifier_with_no_expression.snap
│ │ │ ├── r#mod__vapor__v_slot__quote_slot_name.snap
│ │ │ ├── r#mod__vapor__transform_element__component_props_merging_class.snap
│ │ │ ├── r#mod__vapor__v_on__basic.snap
│ │ │ ├── r#mod__vapor__v_model__basic.snap
│ │ │ ├── r#mod__vapor__transform_element__component_dynamic_props_before_static_prop.snap
│ │ │ ├── r#mod__vapor__transform_element__component_props_merging_style.snap
│ │ │ ├── r#mod__vapor__v_bind__basic.snap
│ │ │ ├── r#mod__vapor__v_on__should_delegate_event.snap
│ │ │ ├── r#mod__vapor__custom_directive__basic.snap
│ │ │ ├── r#mod__vapor__transform_element__component_static_props.snap
│ │ │ ├── r#mod__vapor__v_slot__nested_component_slot.snap
│ │ │ ├── r#mod__vapor__transform_element__props_merging_style.snap
│ │ │ ├── r#mod__vapor__v_bind__attr_modifier.snap
│ │ │ ├── r#mod__vapor__v_bind__camel_modifier.snap
│ │ │ ├── r#mod__vapor__v_once__with_v_if.snap
│ │ │ ├── r#mod__vapor__v_model__component.snap
│ │ │ ├── r#mod__vapor__v_model__component_with_arguments.snap
│ │ │ ├── r#mod__vapor__v_on__expression_with_type.snap
│ │ │ ├── r#mod__vapor__transform_element__component_dynamic_props_after_static_prop.snap
│ │ │ ├── r#mod__vapor__transform_element__component_v_on.snap
│ │ │ ├── r#mod__vapor__v_bind__prop_modifier.snap
│ │ │ ├── r#mod__vapor__v_if__component.snap
│ │ │ ├── r#mod__vapor__v_model__modifiers_lazy.snap
│ │ │ ├── r#mod__vapor__v_model__modifiers_trim.snap
│ │ │ ├── r#mod__vapor__v_once__with_v_for.snap
│ │ │ ├── r#mod__vapor__custom_directive__binding_value.snap
│ │ │ ├── r#mod__vapor__v_model__modifiers_number.snap
│ │ │ ├── r#mod__vapor__v_once__on_nested_plain_element.snap
│ │ │ ├── r#mod__vapor__v_html__should_convert_v_html_to_inner_html.snap
│ │ │ ├── r#mod__vapor__v_model__should_support_input_text.snap
│ │ │ ├── r#mod__vapor__v_model__should_support_select.snap
│ │ │ ├── r#mod__vapor__v_model__should_support_textarea.snap
│ │ │ ├── r#mod__vapor__v_model__should_support_input_radio.snap
│ │ │ ├── r#mod__vapor__transform_element__v_on.snap
│ │ │ ├── r#mod__vapor__v_model__component_with_dynamic_arguments.snap
│ │ │ ├── r#mod__vapor__v_model__should_support_member_expression.snap
│ │ │ ├── r#mod__vapor__transform_element__component_dynamic_props_between_static_prop.snap
│ │ │ ├── r#mod__vapor__v_bind__number_value.snap
│ │ │ ├── r#mod__vapor__v_model__should_support_input_checkbox.snap
│ │ │ ├── r#mod__vapor__transform_element__dynamic_props.snap
│ │ │ ├── r#mod__vapor__transform_element__props_merging_class.snap
│ │ │ ├── r#mod__vapor__transform_element__component_generate_multi_root_component.snap
│ │ │ ├── r#mod__vapor__v_slots__basic.snap
│ │ │ ├── r#mod__vapor__v_slot__on_component_default_slot.snap
│ │ │ ├── r#mod__vapor__custom_directive__dynamic_argument.snap
│ │ │ ├── r#mod__vapor__custom_directive__static_parameters.snap
│ │ │ ├── r#mod__vapor__transform_children__basic.snap
│ │ │ ├── r#mod__vapor__v_on__should_transform_click_middle.snap
│ │ │ ├── r#mod__vapor__transform_template_ref__static_ref.snap
│ │ │ ├── r#mod__vapor__v_on__should_transform_click_right.snap
│ │ │ ├── r#mod__vapor__v_slot__implicit_default_slot.snap
│ │ │ ├── r#mod__vapor__custom_directive__modifiers.snap
│ │ │ ├── r#mod__vapor__transform_element__dynamic_props_after_static_prop.snap
│ │ │ ├── r#mod__vapor__transform_element__dynamic_props_before_static_prop.snap
│ │ │ ├── r#mod__vapor__v_slot__dynamic_slots_name.snap
│ │ │ ├── r#mod__vapor__v_if__v_if_v_else.snap
│ │ │ ├── r#mod__vapor__v_on__should_not_error_if_no_expression_but_has_modifier.snap
│ │ │ ├── r#mod__vapor__v_on__should_not_wrap_keys_guard_if_no_key_modifier_is_present.snap
│ │ │ ├── r#mod__vapor__v_on__should_wrap_keys_guard_for_static_key_event_with_left_or_right_modifiers.snap
│ │ │ ├── r#mod__vapor__custom_directive__modifiers_with_binding.snap
│ │ │ ├── r#mod__vapor__v_on__should_support_multiple_modifiers_and_event_options.snap
│ │ │ ├── r#mod__vapor__custom_directive__static_argument_and_modifiers.snap
│ │ │ ├── r#mod__vapor__v_once__with_v_if_else.snap
│ │ │ ├── r#mod__vapor__v_slot__on_component_named_slot.snap
│ │ │ ├── r#mod__vapor__transform_element__component_v_for_should_not_mark_as_single_root.snap
│ │ │ ├── r#mod__vapor__v_if__dedupe_same_template.snap
│ │ │ ├── r#mod__vapor__v_on__should_wrap_keys_guard_for_keyboard_events_or_dynamic_events.snap
│ │ │ ├── r#mod__vapor__transform_element__component_import_resolve_component.snap
│ │ │ ├── r#mod__vapor__transform_element__component_with_fallback.snap
│ │ │ ├── r#mod__vapor__v_once__on_component.snap
│ │ │ ├── r#mod__vapor__v_if__basic.snap
│ │ │ ├── r#mod__vapor__v_if__v_if_v_if_else.snap
│ │ │ ├── r#mod__vapor__v_text__should_convert_v_text_to_set_text.snap
│ │ │ ├── r#mod__vapor__transform_element__invalid_html_nesting.snap
│ │ │ ├── r#mod__vapor__v_once__basic.snap
│ │ │ ├── r#mod__vapor__v_slots__nested.snap
│ │ │ ├── r#mod__vapor__v_model__should_support_input_dynamic_type.snap
│ │ │ ├── r#mod__vapor__v_slot__on_component_dynamically_named_slot.snap
│ │ │ ├── r#mod__vapor__transform_element__dynamic_props_between_static_prop.snap
│ │ │ ├── r#mod__vapor__transform_template_ref__dynamic_ref.snap
│ │ │ ├── r#mod__vapor__v_model__component_should_generate_model_value_modifiers.snap
│ │ │ ├── r#mod__vapor__transform_element__props_merging_event_handlers.snap
│ │ │ ├── r#mod__vapor__v_model__should_support_dynamic_props.snap
│ │ │ ├── r#mod__vapor__transform_children__efficient_find.snap
│ │ │ ├── r#mod__vapor__v_if__v_on_with_v_if.snap
│ │ │ ├── r#mod__vapor__v_on__should_support_multiple_events_and_modifiers_options.snap
│ │ │ ├── r#mod__vapor__v_on__should_use_delegate_helper_when_have_multiple_events_of_same_name.snap
│ │ │ ├── r#mod__vapor__v_for__selector_pattern3.snap
│ │ │ ├── r#mod__vapor__v_for__key_only_binding_pattern.snap
│ │ │ ├── r#mod__vapor__v_for__multi_effect.snap
│ │ │ ├── r#mod__vapor__v_for__aliases_with_complex_expressions.snap
│ │ │ ├── r#mod__vapor__v_model__component_with_arguments_should_generate_model_modifiers.snap
│ │ │ ├── r#mod__vapor__v_slot__dynamic_slots_name_with_v_for.snap
│ │ │ ├── r#mod__vapor__transform_children__jsx_component_in_jsx_expression_container.snap
│ │ │ ├── r#mod__vapor__v_if__v_if_v_else_if_v_else.snap
│ │ │ ├── r#mod__vapor__v_model__component_with_dynamic_arguments_with_v_for.snap
│ │ │ ├── r#mod__vapor__v_for__object_de_structured_value.snap
│ │ │ ├── r#mod__vapor__transform_template_ref__ref_v_if.snap
│ │ │ ├── r#mod__vapor__v_for__array_de_structured_value.snap
│ │ │ ├── r#mod__vapor__v_for__on_component.snap
│ │ │ ├── r#mod__vapor__v_slot__named_slots_with_comment.snap
│ │ │ ├── r#mod__vapor__v_for__object_value_key_and_index.snap
│ │ │ ├── r#mod__vapor__transform_text__expression_logical.snap
│ │ │ ├── r#mod__vapor__v_slot__nested_slots_scoping.snap
│ │ │ ├── r#mod__vapor__transform_children__anchor_insertion_in_middle.snap
│ │ │ ├── r#mod__vapor__v_for__on_template_with_single_component_child.snap
│ │ │ ├── r#mod__vapor__v_for__selector_pattern4.snap
│ │ │ ├── r#mod__vapor__v_for__selector_pattern2.snap
│ │ │ ├── r#mod__vapor__v_for__basic.snap
│ │ │ ├── r#mod__vapor__v_model__component_with_dynamic_arguments_should_generate_model_modifiers.snap
│ │ │ ├── r#mod__vapor__v_slot__on_component_named_slot_multiple.snap
│ │ │ ├── r#mod__vapor__v_if__comment_between_branches.snap
│ │ │ ├── r#mod__vapor__v_slot__named_slots_with_implicit_default_slot.snap
│ │ │ ├── r#mod__vapor__transform_template_ref__ref_v_for.snap
│ │ │ ├── r#mod__vapor__v_model__should_support_member_expression_with_inline.snap
│ │ │ ├── r#mod__vapor__v_for__fast_remove_flag.snap
│ │ │ ├── r#mod__vapor__v_for__object_de_structured_value_with_rest.snap
│ │ │ ├── r#mod__vapor__v_for__array_de_structured_value_with_rest.snap
│ │ │ ├── r#mod__vapor__v_for__expression_object.snap
│ │ │ ├── r#mod__vapor__v_if__template.snap
│ │ │ ├── r#mod__vapor__v_for__selector_pattern1.snap
│ │ │ ├── r#mod__vapor__transform_text__expression_conditional.snap
│ │ │ ├── r#mod__vapor__v_once__execution_order.snap
│ │ │ ├── r#mod__vapor__v_once__with_conditional_expression.snap
│ │ │ ├── r#mod__vapor__v_bind__with_constant_value.snap
│ │ │ ├── r#mod__vapor__transform_children__children_sibling_references.snap
│ │ │ ├── r#mod__vapor__v_if__v_if_v_if_or_v_elses.snap
│ │ │ ├── r#mod__vapor__v_for__nested_v_for.snap
│ │ │ ├── r#mod__vapor__transform_children__efficient_traversal.snap
│ │ │ ├── r#mod__vapor__transform_template_ref__function_ref.snap
│ │ │ ├── r#mod__vapor__custom_directive__component.snap
│ │ │ ├── r#mod__vapor__v_for__identifiers.snap
│ │ │ ├── r#mod__vapor__transform_text__expression_map.snap
│ │ │ ├── r#mod__vapor__transform_children__next_child_and_nthchild_should_be_above_the_set_insertion_state.snap
│ │ │ └── r#mod__vapor__v_slot__dynamic_slots_name_with_v_if_and_v_else_if.snap
│ │ │ ├── mod.rs
│ │ │ ├── v_show.rs
│ │ │ ├── transform_template_ref.rs
│ │ │ ├── v_text.rs
│ │ │ ├── v_html.rs
│ │ │ ├── custom_directive.rs
│ │ │ └── transform_text.rs
│ ├── crates
│ │ ├── vapor
│ │ │ ├── src
│ │ │ │ ├── ir.rs
│ │ │ │ ├── lib.rs
│ │ │ │ ├── transform
│ │ │ │ │ ├── v_once.rs
│ │ │ │ │ ├── v_show.rs
│ │ │ │ │ └── v_html.rs
│ │ │ │ └── generate
│ │ │ │ │ ├── html.rs
│ │ │ │ │ ├── dom.rs
│ │ │ │ │ └── v_show.rs
│ │ │ └── Cargo.toml
│ │ └── common
│ │ │ ├── src
│ │ │ └── lib.rs
│ │ │ └── Cargo.toml
│ ├── browser.js
│ ├── build.rs
│ ├── .cargo
│ │ └── config.toml
│ ├── README.md
│ ├── tsconfig.json
│ ├── wasi-worker-browser.mjs
│ ├── benches
│ │ └── bench.rs
│ ├── Cargo.toml
│ ├── wasi-worker.mjs
│ └── compiler-rs.wasi-browser.js
├── macros
│ ├── src
│ │ ├── api.ts
│ │ ├── rollup.ts
│ │ ├── rspack.ts
│ │ ├── vite.ts
│ │ ├── esbuild.ts
│ │ ├── rolldown.ts
│ │ ├── webpack.ts
│ │ ├── index.ts
│ │ ├── astro.ts
│ │ ├── core
│ │ │ ├── helper
│ │ │ │ ├── index.ts
│ │ │ │ └── with-defaults.ts
│ │ │ ├── define-expose.ts
│ │ │ ├── style.ts
│ │ │ ├── define-component
│ │ │ │ └── return.ts
│ │ │ ├── define-slots.ts
│ │ │ ├── define-model.ts
│ │ │ └── utils.ts
│ │ ├── nuxt.ts
│ │ ├── volar.ts
│ │ └── raw.ts
│ ├── tsdown.config.ts
│ └── tests
│ │ ├── fixtures
│ │ ├── define-slots.tsx
│ │ ├── define-expose.tsx
│ │ ├── define-model.tsx
│ │ ├── define-style.tsx
│ │ └── define-component.tsx
│ │ └── fixtures.spec.ts
├── vue-jsx-vapor
│ ├── src
│ │ ├── api.ts
│ │ ├── index.ts
│ │ ├── vite.ts
│ │ ├── esbuild.ts
│ │ ├── rollup.ts
│ │ ├── rspack.ts
│ │ ├── webpack.ts
│ │ ├── rolldown.ts
│ │ ├── astro.ts
│ │ ├── unplugin.ts
│ │ ├── nuxt.ts
│ │ ├── options.d.ts
│ │ ├── core
│ │ │ ├── index.ts
│ │ │ ├── vue-jsx.ts
│ │ │ └── ssr.ts
│ │ └── volar.ts
│ ├── tsdown.config.ts
│ └── jsx-runtime
│ │ ├── index.js
│ │ ├── index.d.ts
│ │ └── index.cjs
├── eslint
│ ├── tsdown.config.ts
│ ├── src
│ │ ├── rules
│ │ │ ├── define-style
│ │ │ │ └── types.ts
│ │ │ ├── index.ts
│ │ │ └── jsx-sort-props
│ │ │ │ └── types.ts
│ │ └── index.ts
│ ├── test
│ │ ├── __snapshots__
│ │ │ ├── define-style.spec.ts.snap
│ │ │ └── jsx-sort-props.spec.ts.snap
│ │ └── define-style.spec.ts
│ └── package.json
└── runtime
│ ├── tsdown.config.ts
│ ├── src
│ ├── index.ts
│ ├── vdom.ts
│ ├── block.ts
│ └── helpers.ts
│ └── package.json
├── docs
├── netlify.toml
├── vite.config.ts
├── public
│ └── logo.svg
├── package.json
├── zh
│ ├── features
│ │ └── use-ref.md
│ ├── index.md
│ └── introduction
│ │ ├── eslint.md
│ │ └── getting-started.md
├── .vitepress
│ └── theme
│ │ └── index.ts
├── features
│ └── use-ref.md
└── index.md
├── .prettierrc.json
├── .stackblitzrc
├── playground
├── src
│ ├── Comp.vue
│ ├── count.tsx
│ ├── once.tsx
│ ├── show.tsx
│ ├── html.tsx
│ ├── model.tsx
│ ├── interop.tsx
│ ├── element.tsx
│ ├── slot.tsx
│ ├── for.tsx
│ ├── if.tsx
│ └── App.tsx
├── vite.js
├── index.html
├── vite.config.ts
├── tsconfig.json
├── main.ts
└── package.json
├── .vscode
├── settings.json
└── launch.json
├── ts-macro.config.ts
├── benchmark
└── package.json
├── tsdown.config.ts
├── tsconfig.json
├── vitest.config.ts
├── eslint.config.ts
├── pnpm-workspace.yaml
├── LICENSE
└── package.json
/.npmrc:
--------------------------------------------------------------------------------
1 | ignore-workspace-root-check=true
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ./packages/vue-jsx-vapor/README.md
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [zhiyuanzmj]
2 |
--------------------------------------------------------------------------------
/packages/compiler-rs/rustfmt.toml:
--------------------------------------------------------------------------------
1 | tab_spaces = 2
2 |
--------------------------------------------------------------------------------
/packages/macros/src/api.ts:
--------------------------------------------------------------------------------
1 | export * from './core'
2 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/api.ts:
--------------------------------------------------------------------------------
1 | export * from './core'
2 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/mod.rs:
--------------------------------------------------------------------------------
1 | mod transform;
2 | mod vapor;
3 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/index.ts:
--------------------------------------------------------------------------------
1 | export * from '@vue-jsx-vapor/runtime'
2 |
--------------------------------------------------------------------------------
/packages/compiler-rs/crates/vapor/src/ir.rs:
--------------------------------------------------------------------------------
1 | pub mod component;
2 | pub mod index;
3 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/transform/mod.rs:
--------------------------------------------------------------------------------
1 | mod hmr;
2 | mod interop;
3 | mod ssr;
4 |
--------------------------------------------------------------------------------
/docs/netlify.toml:
--------------------------------------------------------------------------------
1 | [[rewrites]]
2 | from = "/*"
3 | to = "/:path.html"
4 | status = 200
--------------------------------------------------------------------------------
/packages/compiler-rs/browser.js:
--------------------------------------------------------------------------------
1 | export * from '@vue-jsx-vapor/compiler-rs-wasm32-wasi'
2 |
--------------------------------------------------------------------------------
/packages/macros/src/rollup.ts:
--------------------------------------------------------------------------------
1 | import unplugin from '.'
2 |
3 | export default unplugin.rollup
4 |
--------------------------------------------------------------------------------
/packages/macros/src/rspack.ts:
--------------------------------------------------------------------------------
1 | import unplugin from '.'
2 |
3 | export default unplugin.rspack
4 |
--------------------------------------------------------------------------------
/packages/macros/src/vite.ts:
--------------------------------------------------------------------------------
1 | import unplugin from '.'
2 |
3 | export default unplugin.vite
4 |
--------------------------------------------------------------------------------
/packages/macros/src/esbuild.ts:
--------------------------------------------------------------------------------
1 | import unplugin from '.'
2 |
3 | export default unplugin.esbuild
4 |
--------------------------------------------------------------------------------
/packages/macros/src/rolldown.ts:
--------------------------------------------------------------------------------
1 | import unplugin from '.'
2 |
3 | export default unplugin.rolldown
4 |
--------------------------------------------------------------------------------
/packages/macros/src/webpack.ts:
--------------------------------------------------------------------------------
1 | import unplugin from '.'
2 |
3 | export default unplugin.webpack
4 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "singleQuote": true,
4 | "trailingComma": "all"
5 | }
6 |
--------------------------------------------------------------------------------
/.stackblitzrc:
--------------------------------------------------------------------------------
1 | {
2 | "installDependencies": true,
3 | "startCommand": "npm run dev | npm run play"
4 | }
--------------------------------------------------------------------------------
/packages/compiler-rs/crates/vapor/src/lib.rs:
--------------------------------------------------------------------------------
1 | pub mod generate;
2 | pub mod ir;
3 | pub mod transform;
4 |
--------------------------------------------------------------------------------
/packages/compiler-rs/build.rs:
--------------------------------------------------------------------------------
1 | extern crate napi_build;
2 |
3 | fn main() {
4 | napi_build::setup();
5 | }
6 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/vite.ts:
--------------------------------------------------------------------------------
1 | import unplugin from './unplugin'
2 |
3 | export default unplugin.vite
4 |
--------------------------------------------------------------------------------
/playground/src/Comp.vue:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/packages/eslint/tsdown.config.ts:
--------------------------------------------------------------------------------
1 | import { config } from '../../tsdown.config.ts'
2 |
3 | export default config()
4 |
--------------------------------------------------------------------------------
/packages/macros/tsdown.config.ts:
--------------------------------------------------------------------------------
1 | import { config } from '../../tsdown.config.ts'
2 |
3 | export default config()
4 |
--------------------------------------------------------------------------------
/packages/runtime/tsdown.config.ts:
--------------------------------------------------------------------------------
1 | import { config } from '../../tsdown.config.ts'
2 |
3 | export default config()
4 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/esbuild.ts:
--------------------------------------------------------------------------------
1 | import unplugin from './unplugin'
2 |
3 | export default unplugin.esbuild
4 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/rollup.ts:
--------------------------------------------------------------------------------
1 | import unplugin from './unplugin'
2 |
3 | export default unplugin.rollup
4 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/rspack.ts:
--------------------------------------------------------------------------------
1 | import unplugin from './unplugin'
2 |
3 | export default unplugin.rspack
4 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/webpack.ts:
--------------------------------------------------------------------------------
1 | import unplugin from './unplugin'
2 |
3 | export default unplugin.webpack
4 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.codeActionsOnSave": {
3 | "source.fixAll.eslint": "explicit"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/playground/vite.js:
--------------------------------------------------------------------------------
1 | import { startVite } from 'vite-hyper-config'
2 |
3 | startVite(undefined, {
4 | resolve: {
5 | conditions: ['jsx-vapor-dev'],
6 | },
7 | })
8 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 |
6 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/tsdown.config.ts:
--------------------------------------------------------------------------------
1 | import { config } from '../../tsdown.config.ts'
2 |
3 | export default config({
4 | entry: ['./src/*.ts', '!./**.d.ts'],
5 | })
6 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_dynamic_props.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 |
6 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/rolldown.ts:
--------------------------------------------------------------------------------
1 | import { createRollupPlugin } from 'unplugin'
2 | import { unpluginFactory } from './unplugin'
3 |
4 | export default createRollupPlugin(unpluginFactory)
5 |
--------------------------------------------------------------------------------
/packages/compiler-rs/crates/common/src/lib.rs:
--------------------------------------------------------------------------------
1 | pub mod check;
2 | pub mod directive;
3 | pub mod dom;
4 | pub mod error;
5 | pub mod expression;
6 | pub mod options;
7 | pub mod text;
8 | pub mod walk;
9 |
--------------------------------------------------------------------------------
/ts-macro.config.ts:
--------------------------------------------------------------------------------
1 | import vueJsxVapor from './packages/vue-jsx-vapor/src/volar'
2 |
3 | export default {
4 | plugins: [
5 | vueJsxVapor({
6 | macros: true,
7 | }),
8 | ],
9 | }
10 |
--------------------------------------------------------------------------------
/packages/compiler-rs/.cargo/config.toml:
--------------------------------------------------------------------------------
1 | [target.x86_64-pc-windows-msvc]
2 | rustflags = ["-C", "target-feature=+crt-static"]
3 |
4 | [target.i686-pc-windows-msvc]
5 | rustflags = ["-C", "target-feature=+crt-static"]
6 |
--------------------------------------------------------------------------------
/docs/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 |
3 | export default defineConfig({
4 | resolve: {
5 | conditions: ['jsx-vapor-dev'],
6 | },
7 | optimizeDeps: {
8 | exclude: ['vitepress'],
9 | },
10 | })
11 |
--------------------------------------------------------------------------------
/playground/src/count.tsx:
--------------------------------------------------------------------------------
1 | import { computed, defineVaporComponent } from 'vue'
2 |
3 | export default defineVaporComponent(({ value = '' }) => {
4 | defineExpose({
5 | double: computed(() => +value * 2),
6 | })
7 | return
{value}
8 | })
9 |
--------------------------------------------------------------------------------
/playground/src/once.tsx:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default () => {
4 | const count = ref(3)
5 |
6 | return (
7 | <>
8 |
9 | {count.value}
10 | >
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/README.md:
--------------------------------------------------------------------------------
1 | # @vue-jsx-vapor/compiler-rs
2 |
3 | [](https://www.npmjs.com/package/@vue-jsx-vapor/compiler-rs)
4 |
5 | Rust version of @vue-jsx-vapor/compiler.
6 |
--------------------------------------------------------------------------------
/packages/runtime/src/index.ts:
--------------------------------------------------------------------------------
1 | export { shallowRef as useRef } from 'vue'
2 | export * from './jsx'
3 | export * from './h'
4 | export * from './node'
5 | export * from './block'
6 | export * from './component'
7 | export * from './helpers'
8 | export * from './vue'
9 | export * from './vdom'
10 |
--------------------------------------------------------------------------------
/playground/src/show.tsx:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default () => {
4 | const show = ref(false)
5 |
6 | return (
7 | <>
8 |
9 | {String(show.value)}
10 | >
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/playground/src/html.tsx:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default () => {
4 | const foo = ref('foo
')
5 |
6 | return (
7 | <>
8 |
9 |
10 |
11 | >
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/packages/eslint/src/rules/define-style/types.ts:
--------------------------------------------------------------------------------
1 | export interface DefineStyleSchema0 {
2 | tabWidth?: number
3 | }
4 |
5 | export type DefineStyleRuleOptions = [DefineStyleSchema0?]
6 |
7 | export type RuleOptions = DefineStyleRuleOptions
8 | export type MessageIds = 'define-style' | 'define-style-syntax-error'
9 |
--------------------------------------------------------------------------------
/packages/macros/src/index.ts:
--------------------------------------------------------------------------------
1 | import { createUnplugin, type UnpluginInstance } from 'unplugin'
2 | import plugin from './raw'
3 | import type { Options } from './options'
4 |
5 | export * from './options'
6 |
7 | const unplugin: UnpluginInstance = createUnplugin(plugin)
8 | export default unplugin
9 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_children__fragment.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_children.rs
3 | expression: code
4 | ---
5 | import { createNodes as _createNodes } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createNodes(() => foo);
8 | return n0;
9 | })();
10 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_text__consecutive_text.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_text.rs
3 | expression: code
4 | ---
5 | import { createNodes as _createNodes } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createNodes(() => msg);
8 | return n0;
9 | })();
10 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/transform/snapshots/r#mod__transform__ssr__ssr_export.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/transform/ssr.rs
3 | expression: code
4 | ---
5 | import { ssrRegisterHelper } from "/__vue-jsx-ssr-register-helper";
6 | const __moduleId = "index.jsx";
7 | export const foo = () => {};
8 | ssrRegisterHelper(foo, __moduleId);
9 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_children__comments.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_children.rs
3 | expression: code
4 | ---
5 | import { template as _template } from "vue";
6 | const t0 = _template("");
7 | (() => {
8 | const n1 = t0();
9 | return n1;
10 | })();
11 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_text__on_consecutive_text.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_text.rs
3 | expression: code
4 | ---
5 | import { createNodes as _createNodes } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createNodes("hello world");
8 | return n0;
9 | })();
10 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_once__inside_v_once.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_once.rs
3 | expression: code
4 | ---
5 | import { template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | return n0;
10 | })();
11 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_text__interpolation.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_text.rs
3 | expression: code
4 | ---
5 | import { createNodes as _createNodes } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createNodes(1, 2, () => a + b + c);
8 | return n0;
9 | })();
10 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_text__text_like.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_text.rs
3 | expression: code
4 | ---
5 | import { template as _template } from "vue";
6 | const t0 = _template("2foo111
", true);
7 | (() => {
8 | const n0 = t0();
9 | return n0;
10 | })();
11 |
--------------------------------------------------------------------------------
/docs/public/logo.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/mod.rs:
--------------------------------------------------------------------------------
1 | mod custom_directive;
2 | mod transform_children;
3 | mod transform_element;
4 | mod transform_template_ref;
5 | mod transform_text;
6 | mod v_bind;
7 | mod v_for;
8 | mod v_html;
9 | mod v_if;
10 | mod v_model;
11 | mod v_on;
12 | mod v_once;
13 | mod v_show;
14 | mod v_slot;
15 | mod v_slots;
16 | mod v_text;
17 |
--------------------------------------------------------------------------------
/playground/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/benchmark/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "module",
3 | "scripts": {
4 | "bench": "node ./bench.js"
5 | },
6 | "devDependencies": {
7 | "@babel/core": "catalog:",
8 | "@vue-jsx-vapor/babel": "2.6.8",
9 | "@vue-jsx-vapor/compiler-rs": "workspace:*",
10 | "@vue/babel-plugin-jsx": "^1.5.0",
11 | "tinybench": "^5.0.1"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__props_children.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { template as _template } from "vue";
6 | const t0 = _template("
", true);
7 | (() => {
8 | const n0 = t0();
9 | return n0;
10 | })();
11 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__static_props.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | return n0;
10 | })();
11 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/transform/snapshots/r#mod__transform__ssr__ssr_export_default.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/transform/ssr.rs
3 | expression: code
4 | ---
5 | import { ssrRegisterHelper } from "/__vue-jsx-ssr-register-helper";
6 | const __moduleId = "index.jsx";
7 | const Comp = () => {};
8 | export default Comp;
9 | ssrRegisterHelper(Comp, __moduleId);
10 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_fragment_should_not_mark_as_single_root.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Comp);
8 | return n0;
9 | })();
10 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_text__static_template.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_text.rs
3 | expression: code
4 | ---
5 | import { template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | return n0;
10 | })();
11 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_bind__no_expression.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_bind.rs
3 | expression: code
4 | ---
5 | import { setProp as _setProp, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _setProp(n0, "id", true);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_once__as_root_node.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_once.rs
3 | expression: code
4 | ---
5 | import { setProp as _setProp, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _setProp(n0, "id", foo);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_show__basic.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_show.rs
3 | expression: code
4 | ---
5 | import { applyVShow as _applyVShow, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _applyVShow(n0, () => foo);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_generate_single_root_component.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Comp, null, null, true);
8 | return n0;
9 | })();
10 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_on__namespace_event_with_component.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_on.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Comp, { "onUpdate:modelValue": () => () => {} }, null, true);
8 | return n0;
9 | })();
10 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_resolve_namespaced_component.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Foo.Example, null, null, true);
8 | return n0;
9 | })();
10 |
--------------------------------------------------------------------------------
/packages/macros/src/astro.ts:
--------------------------------------------------------------------------------
1 | import type { Options } from './options'
2 | import unplugin from '.'
3 |
4 | export default (options: Options) => ({
5 | name: 'vue-jsx-vapor',
6 | hooks: {
7 | 'astro:config:setup': (astro: any) => {
8 | astro.config.vite.plugins ||= []
9 | astro.config.vite.plugins.push(unplugin.vite(options))
10 | },
11 | },
12 | })
13 |
--------------------------------------------------------------------------------
/packages/macros/tests/fixtures/define-slots.tsx:
--------------------------------------------------------------------------------
1 | export const Comp = () => {
2 | const slots = defineSlots<{
3 | default: () => any
4 | }>()
5 | return {slots.default?.()}
6 | }
7 |
8 | export default function () {
9 | const slots = defineSlots({
10 | default: () => default
,
11 | })
12 | return {slots.default?.()}
13 | }
14 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_event_with_once_modifier.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Foo, { onFooOnce: () => bar }, null, true);
8 | return n0;
9 | })();
10 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_text__escapes_raw_static_text_when_generating_the_template_string.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_text.rs
3 | expression: code
4 | ---
5 | import { template as _template } from "vue";
6 | const t0 = _template("<script>", true);
7 | (() => {
8 | const n0 = t0();
9 | return n0;
10 | })();
11 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_bind__attr_modifier_with_no_expression.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_bind.rs
3 | expression: code
4 | ---
5 | import { setAttr as _setAttr, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _setAttr(n0, "foo-bar", true);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_bind__camel_modifier_with_no_expression.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_bind.rs
3 | expression: code
4 | ---
5 | import { setAttr as _setAttr, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _setAttr(n0, "foo-bar", true);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_bind__prop_modifier_with_no_expression.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_bind.rs
3 | expression: code
4 | ---
5 | import { setProp as _setProp, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _setProp(n0, "fooBar", true);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_slot__quote_slot_name.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_slot.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n3 = _createComponent(Comp, null, { "nav-bar-title-before": () => {
8 | return null;
9 | } }, true);
10 | return n3;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/runtime/src/vdom.ts:
--------------------------------------------------------------------------------
1 | import { getCurrentInstance } from 'vue'
2 |
3 | const cacheMap = new WeakMap()
4 |
5 | export function useVdomCache() {
6 | const i = getCurrentInstance()
7 | if (i) {
8 | !cacheMap.has(i) && cacheMap.set(i, [])
9 | const caches = cacheMap.get(i)
10 | return (caches[caches.length] = [])
11 | } else {
12 | return []
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/packages/macros/src/core/helper/index.ts:
--------------------------------------------------------------------------------
1 | export const helperPrefix = '/vue-jsx-vapor/macros' as const
2 |
3 | export const useModelHelperId = `${helperPrefix}/use-model`
4 | export { default as useModelHelperCode } from './use-model?raw'
5 |
6 | export const withDefaultsHelperId = `${helperPrefix}/with-defaults` as const
7 | export { default as withDefaultsHelperCode } from './with-defaults?raw'
8 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/astro.ts:
--------------------------------------------------------------------------------
1 | import unplugin from './unplugin'
2 | import type { Options } from './options'
3 |
4 | export default (options: Options) => ({
5 | name: 'vue-jsx-vapor',
6 | hooks: {
7 | 'astro:config:setup': (astro: any) => {
8 | astro.config.vite.plugins ||= []
9 | astro.config.vite.plugins.push(unplugin.vite(options))
10 | },
11 | },
12 | })
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_props_merging_class.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Foo, { class: () => ["foo", { bar: isBar }] }, null, true);
8 | return n0;
9 | })();
10 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_on__basic.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_on.rs
3 | expression: code
4 | ---
5 | _delegateEvents("click");
6 | import { delegateEvents as _delegateEvents, template as _template } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n0 = t0();
10 | n0.$evtclick = handleClick;
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__basic.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { applyTextModel as _applyTextModel, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _applyTextModel(n0, () => model, (_value) => model = _value);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_dynamic_props_before_static_prop.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Foo, { $: [() => obj, { id: () => "foo" }] }, null, true);
8 | return n0;
9 | })();
10 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_props_merging_style.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Foo, { style: () => ["color: green", { color: "red" }] }, null, true);
8 | return n0;
9 | })();
10 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_bind__basic.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_bind.rs
3 | expression: code
4 | ---
5 | import { renderEffect as _renderEffect, setProp as _setProp, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _renderEffect(() => _setProp(n0, "id", id));
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_on__should_delegate_event.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_on.rs
3 | expression: code
4 | ---
5 | _delegateEvents("click");
6 | import { delegateEvents as _delegateEvents, template as _template } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n0 = t0();
10 | n0.$evtclick = test;
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__custom_directive__basic.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/custom_directive.rs
3 | expression: code
4 | ---
5 | import { template as _template, withVaporDirectives as _withVaporDirectives } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _withVaporDirectives(n0, [[vExample]]);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_static_props.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Foo, {
8 | id: () => "foo",
9 | class: () => "bar"
10 | }, null, true);
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_slot__nested_component_slot.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_slot.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n1 = _createComponent(A, null, { default: () => {
8 | const n0 = _createComponent(B);
9 | return n0;
10 | } }, true);
11 | return n1;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/macros/tests/fixtures/define-expose.tsx:
--------------------------------------------------------------------------------
1 | export function Comp() {
2 | defineExpose({
3 | foo: 1,
4 | })
5 | return
6 | }
7 |
8 | export const Comp1 = function (props: any) {
9 | defineExpose({
10 | foo: props.foo,
11 | })
12 | return
13 | }
14 |
15 | export const Comp2 = ({ foo }: any) => {
16 | defineExpose({
17 | foo,
18 | })
19 | return
20 | }
21 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__props_merging_style.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { setStyle as _setStyle, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _setStyle(n0, ["color: green", { color: "red" }]);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_bind__attr_modifier.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_bind.rs
3 | expression: code
4 | ---
5 | import { renderEffect as _renderEffect, setAttr as _setAttr, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _renderEffect(() => _setAttr(n0, "foo-bar", id));
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_bind__camel_modifier.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_bind.rs
3 | expression: code
4 | ---
5 | import { renderEffect as _renderEffect, setProp as _setProp, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _renderEffect(() => _setProp(n0, "fooBar", id));
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_once__with_v_if.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_once.rs
3 | expression: code
4 | ---
5 | import { createIf as _createIf, template as _template } from "vue";
6 | const t0 = _template("");
7 | (() => {
8 | const n0 = _createIf(() => expr, () => {
9 | const n2 = t0();
10 | return n2;
11 | }, null, true);
12 | return n0;
13 | })();
14 |
--------------------------------------------------------------------------------
/playground/src/model.tsx:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | const Comp = () => {
4 | const model = defineModel()
5 | return
6 | }
7 |
8 | export default () => {
9 | const model = ref('model')
10 |
11 | return (
12 | <>
13 |
14 |
15 | {model.value}
16 | >
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__component.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Comp, {
8 | modelValue: () => foo,
9 | "onUpdate:modelValue": () => (_value) => foo = _value
10 | }, null, true);
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__component_with_arguments.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Comp, {
8 | bar: () => foo,
9 | "onUpdate:bar": () => (_value) => foo = _value
10 | }, null, true);
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_on__expression_with_type.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_on.rs
3 | expression: code
4 | ---
5 | _delegateEvents("click");
6 | import { delegateEvents as _delegateEvents, template as _template } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n0 = t0();
10 | n0.$evtclick = handleClick as any;
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_dynamic_props_after_static_prop.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Foo, {
8 | id: () => "foo",
9 | $: [() => obj]
10 | }, null, true);
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_v_on.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { toHandlers as _toHandlers } from "vue";
7 | (() => {
8 | const n0 = _createComponent(Foo, { $: [() => _toHandlers(obj)] }, null, true);
9 | return n0;
10 | })();
11 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_bind__prop_modifier.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_bind.rs
3 | expression: code
4 | ---
5 | import { renderEffect as _renderEffect, setDOMProp as _setDOMProp, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _renderEffect(() => _setDOMProp(n0, "fooBar", id));
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_if__component.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_if.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { createIf as _createIf } from "vue";
7 | (() => {
8 | const n0 = _createIf(() => foo, () => {
9 | const n2 = _createComponent(Comp);
10 | return n2;
11 | });
12 | return n0;
13 | })();
14 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__modifiers_lazy.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { applyTextModel as _applyTextModel, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _applyTextModel(n0, () => model, (_value) => model = _value, { lazy: true });
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__modifiers_trim.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { applyTextModel as _applyTextModel, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _applyTextModel(n0, () => model, (_value) => model = _value, { trim: true });
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_once__with_v_for.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_once.rs
3 | expression: code
4 | ---
5 | import { createFor as _createFor, template as _template } from "vue";
6 | const t0 = _template("");
7 | (() => {
8 | const n0 = _createFor(() => list, (_for_item0) => {
9 | const n2 = t0();
10 | return n2;
11 | }, void 0, 4);
12 | return n0;
13 | })();
14 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__custom_directive__binding_value.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/custom_directive.rs
3 | expression: code
4 | ---
5 | import { template as _template, withVaporDirectives as _withVaporDirectives } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _withVaporDirectives(n0, [[vExample, () => msg]]);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__modifiers_number.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { applyTextModel as _applyTextModel, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _applyTextModel(n0, () => model, (_value) => model = _value, { number: true });
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_once__on_nested_plain_element.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_once.rs
3 | expression: code
4 | ---
5 | import { child as _child, setProp as _setProp, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n1 = t0();
9 | const n0 = _child(n1);
10 | _setProp(n0, "id", foo);
11 | return n1;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "module": "CommonJS",
5 | "moduleResolution": "node",
6 | "strict": true,
7 | "noUnusedLocals": true,
8 | "noUnusedParameters": true,
9 | "allowSyntheticDefaultImports": true,
10 | "esModuleInterop": true
11 | },
12 | "include": ["."],
13 | "exclude": ["node_modules", "benchmark", "__test__"]
14 | }
15 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/jsx-runtime/index.js:
--------------------------------------------------------------------------------
1 | import { Fragment } from 'vue'
2 | import { h } from 'vue-jsx-vapor'
3 |
4 | function jsx(type, props, key) {
5 | const { children, 'v-slots': vSlots } = props
6 | delete props.children
7 | delete props['v-slots']
8 | if (arguments.length > 2) props.key = key
9 | return h(type, props, vSlots || children)
10 | }
11 |
12 | export { Fragment, jsx, jsx as jsxDEV, jsx as jsxs }
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_html__should_convert_v_html_to_inner_html.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_html.rs
3 | expression: code
4 | ---
5 | import { renderEffect as _renderEffect, setHtml as _setHtml, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _renderEffect(() => _setHtml(n0, code.value));
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__should_support_input_text.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { applyTextModel as _applyTextModel, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _applyTextModel(n0, () => model, (_value) => model = _value);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__should_support_select.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { applySelectModel as _applySelectModel, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _applySelectModel(n0, () => model, (_value) => model = _value);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__should_support_textarea.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { applyTextModel as _applyTextModel, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _applyTextModel(n0, () => model, (_value) => model = _value);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__should_support_input_radio.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { applyRadioModel as _applyRadioModel, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _applyRadioModel(n0, () => model, (_value) => model = _value);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/crates/vapor/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "vapor"
3 | version = "0.1.0"
4 | edition = "2024"
5 |
6 | [dependencies]
7 | oxc_ast = { workspace = true }
8 | oxc_allocator = { workspace = true }
9 | oxc_span = { workspace = true }
10 | oxc_ast_visit = { workspace = true }
11 | oxc_traverse = { workspace = true }
12 |
13 | napi = { workspace = true }
14 | indexmap = { workspace = true }
15 | common = { workspace = true }
16 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__v_on.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { renderEffect as _renderEffect, setDynamicEvents as _setDynamicEvents, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _renderEffect(() => _setDynamicEvents(n0, obj));
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__component_with_dynamic_arguments.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Comp, { $: [() => ({
8 | [arg]: foo,
9 | ["onUpdate:" + arg]: () => (_value) => foo = _value
10 | })] }, null, true);
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__should_support_member_expression.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { applyTextModel as _applyTextModel, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _applyTextModel(n0, () => setupRef.child, (_value) => setupRef.child = _value);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_dynamic_props_between_static_prop.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Foo, {
8 | id: () => "foo",
9 | $: [() => obj, { class: () => "bar" }]
10 | }, null, true);
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/transform/snapshots/r#mod__transform__hmr__export.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/transform/hmr.rs
3 | expression: code
4 | ---
5 | export const foo = () => {};
6 | foo.__hmrId = "3b6957b69bea9439";
7 | __VUE_HMR_RUNTIME__.createRecord("3b6957b69bea9439", foo);
8 | if (import.meta.hot) import.meta.hot.accept((mod) => {
9 | __VUE_HMR_RUNTIME__[typeof mod.foo === "function" ? "rerender" : "reload"](mod.foo.__hmrId, mod.foo);
10 | });
11 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_bind__number_value.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_bind.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { template as _template } from "vue";
7 | const t0 = _template("");
8 | (() => {
9 | const n1 = t0();
10 | const n3 = _createComponent(Comp, { depth: () => 0 });
11 | return [n1, n3];
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__should_support_input_checkbox.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { applyCheckboxModel as _applyCheckboxModel, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _applyCheckboxModel(n0, () => model, (_value) => model = _value);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__dynamic_props.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _renderEffect(() => _setDynamicProps(n0, [obj], true));
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__props_merging_class.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { renderEffect as _renderEffect, setClass as _setClass, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _renderEffect(() => _setClass(n0, ["foo", { bar: isBar }]));
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_generate_multi_root_component.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { template as _template } from "vue";
7 | const t0 = _template("123");
8 | (() => {
9 | const n0 = _createComponent(Comp);
10 | const n1 = t0();
11 | return [n0, n1];
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_slots__basic.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_slots.rs
3 | expression: code
4 | ---
5 | import { createNodes as _createNodes, createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Comp, null, { $: [{ default: ({ foo }) => (() => {
8 | const n0 = _createNodes(() => foo + bar);
9 | return n0;
10 | })() }] }, true);
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_slot__on_component_default_slot.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_slot.rs
3 | expression: code
4 | ---
5 | import { createNodes as _createNodes, createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n1 = _createComponent(Comp, null, { default: (scope) => {
8 | const n0 = _createNodes(() => scope.foo + bar);
9 | return n0;
10 | } }, true);
11 | return n1;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__custom_directive__dynamic_argument.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/custom_directive.rs
3 | expression: code
4 | ---
5 | import { template as _template, withVaporDirectives as _withVaporDirectives } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _withVaporDirectives(n0, [[
10 | vExample,
11 | () => msg,
12 | foo
13 | ]]);
14 | return n0;
15 | })();
16 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__custom_directive__static_parameters.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/custom_directive.rs
3 | expression: code
4 | ---
5 | import { template as _template, withVaporDirectives as _withVaporDirectives } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _withVaporDirectives(n0, [[
10 | vExample,
11 | () => msg,
12 | "foo"
13 | ]]);
14 | return n0;
15 | })();
16 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_children__basic.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_children.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, template as _template } from "vue";
7 | const t0 = _template("
", true);
8 | (() => {
9 | const n0 = t0();
10 | const x0 = _child(n0);
11 | _setNodes(x0, () => foo, " ", () => bar);
12 | return n0;
13 | })();
14 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_on__should_transform_click_middle.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_on.rs
3 | expression: code
4 | ---
5 | _delegateEvents("mouseup");
6 | import { delegateEvents as _delegateEvents, template as _template, withModifiers as _withModifiers } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n0 = t0();
10 | n0.$evtmouseup = _withModifiers(test, ["middle"]);
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/unplugin.ts:
--------------------------------------------------------------------------------
1 | import { createUnplugin, type UnpluginFactory } from 'unplugin'
2 | import plugin from './raw'
3 | import type { Options } from './options'
4 |
5 | export type { Options }
6 |
7 | export const unpluginFactory: UnpluginFactory = (
8 | options = {},
9 | ) => {
10 | return plugin(options)
11 | }
12 |
13 | export const unplugin = /* #__PURE__ */ createUnplugin(unpluginFactory)
14 |
15 | export default unplugin
16 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_template_ref__static_ref.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_template_ref.rs
3 | expression: code
4 | ---
5 | import { createTemplateRefSetter as _createTemplateRefSetter, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const _setTemplateRef = _createTemplateRefSetter();
9 | const n0 = t0();
10 | _setTemplateRef(n0, "foo");
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_on__should_transform_click_right.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_on.rs
3 | expression: code
4 | ---
5 | _delegateEvents("contextmenu");
6 | import { delegateEvents as _delegateEvents, template as _template, withModifiers as _withModifiers } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n0 = t0();
10 | n0.$evtcontextmenu = _withModifiers(test, ["right"]);
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_slot__implicit_default_slot.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_slot.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { template as _template } from "vue";
7 | const t0 = _template("");
8 | (() => {
9 | const n1 = _createComponent(Comp, null, { default: () => {
10 | const n0 = t0();
11 | return n0;
12 | } }, true);
13 | return n1;
14 | })();
15 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__custom_directive__modifiers.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/custom_directive.rs
3 | expression: code
4 | ---
5 | import { template as _template, withVaporDirectives as _withVaporDirectives } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _withVaporDirectives(n0, [[
10 | vExample,
11 | () => msg,
12 | void 0,
13 | { bar: true }
14 | ]]);
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__dynamic_props_after_static_prop.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _renderEffect(() => _setDynamicProps(n0, [{ id: "foo" }, obj], true));
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__dynamic_props_before_static_prop.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _renderEffect(() => _setDynamicProps(n0, [obj, { id: "foo" }], true));
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_slot__dynamic_slots_name.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_slot.rs
3 | expression: code
4 | ---
5 | import { createNodes as _createNodes, createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n4 = _createComponent(Comp, null, { $: [() => ({
8 | name,
9 | fn: () => {
10 | const n1 = _createNodes(() => foo);
11 | return n1;
12 | }
13 | })] }, true);
14 | return n4;
15 | })();
16 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_if__v_if_v_else.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_if.rs
3 | expression: code
4 | ---
5 | import { createIf as _createIf, template as _template } from "vue";
6 | const t0 = _template("");
7 | const t1 = _template("");
8 | (() => {
9 | const n0 = _createIf(() => ok, () => {
10 | const n2 = t0();
11 | return n2;
12 | }, () => {
13 | const n4 = t1();
14 | return n4;
15 | });
16 | return n0;
17 | })();
18 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_on__should_not_error_if_no_expression_but_has_modifier.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_on.rs
3 | expression: code
4 | ---
5 | _delegateEvents("click");
6 | import { delegateEvents as _delegateEvents, template as _template, withModifiers as _withModifiers } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n0 = t0();
10 | n0.$evtclick = _withModifiers(() => {}, ["prevent"]);
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_on__should_not_wrap_keys_guard_if_no_key_modifier_is_present.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_on.rs
3 | expression: code
4 | ---
5 | _delegateEvents("keyup");
6 | import { delegateEvents as _delegateEvents, template as _template, withModifiers as _withModifiers } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n0 = t0();
10 | n0.$evtkeyup = _withModifiers(test, ["exact"]);
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_on__should_wrap_keys_guard_for_static_key_event_with_left_or_right_modifiers.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_on.rs
3 | expression: code
4 | ---
5 | _delegateEvents("keyup");
6 | import { delegateEvents as _delegateEvents, template as _template, withKeys as _withKeys } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n0 = t0();
10 | n0.$evtkeyup = _withKeys(test, ["left"]);
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/crates/common/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "common"
3 | version = "0.1.0"
4 | edition = "2024"
5 |
6 | [features]
7 | default = ["napi"]
8 | napi = []
9 |
10 | [dependencies]
11 | oxc_span = { workspace = true }
12 | oxc_ast = { workspace = true }
13 | oxc_traverse = { workspace = true }
14 | oxc_allocator = { workspace = true }
15 | oxc_semantic = { workspace = true }
16 |
17 | napi-derive = { workspace = true }
18 | napi = { workspace = true }
19 | phf = { workspace = true }
20 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/transform/snapshots/r#mod__transform__hmr__export_default_with_function_declaration.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/transform/hmr.rs
3 | expression: code
4 | ---
5 | export default function Comp() {}
6 | Comp.__hmrId = "52164bac249078a3";
7 | __VUE_HMR_RUNTIME__.createRecord("52164bac249078a3", Comp);
8 | if (import.meta.hot) import.meta.hot.accept((mod) => {
9 | __VUE_HMR_RUNTIME__[typeof mod.default === "function" ? "rerender" : "reload"](mod.default.__hmrId, mod.default);
10 | });
11 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__custom_directive__modifiers_with_binding.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/custom_directive.rs
3 | expression: code
4 | ---
5 | import { template as _template, withVaporDirectives as _withVaporDirectives } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _withVaporDirectives(n0, [[
10 | vExample,
11 | void 0,
12 | void 0,
13 | { "foo-bar": true }
14 | ]]);
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_on__should_support_multiple_modifiers_and_event_options.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_on.rs
3 | expression: code
4 | ---
5 | import { on as _on, template as _template, withModifiers as _withModifiers } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _on(n0, "click", _withModifiers(test, ["stop", "prevent"]), {
10 | capture: true,
11 | once: true
12 | });
13 | return n0;
14 | })();
15 |
--------------------------------------------------------------------------------
/packages/macros/src/core/define-expose.ts:
--------------------------------------------------------------------------------
1 | import { importHelperFn, type MagicStringAST } from '@vue-macros/common'
2 | import type { CallExpression } from '@babel/types'
3 |
4 | export function transformDefineExpose(
5 | node: CallExpression,
6 | s: MagicStringAST,
7 | ): void {
8 | s.overwriteNode(node.callee, ';')
9 | s.appendRight(
10 | node.arguments[0]?.start || node.end! - 1,
11 | `${importHelperFn(s, 0, 'getCurrentInstance', undefined, 'vue-jsx-vapor')}().exposed = `,
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/transform/snapshots/r#mod__transform__hmr__export_default_with_identifier.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/transform/hmr.rs
3 | expression: code
4 | ---
5 | const Comp = () => {};
6 | export default Comp;
7 | Comp.__hmrId = "52164bac249078a3";
8 | __VUE_HMR_RUNTIME__.createRecord("52164bac249078a3", Comp);
9 | if (import.meta.hot) import.meta.hot.accept((mod) => {
10 | __VUE_HMR_RUNTIME__[typeof mod.default === "function" ? "rerender" : "reload"](mod.default.__hmrId, mod.default);
11 | });
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__custom_directive__static_argument_and_modifiers.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/custom_directive.rs
3 | expression: code
4 | ---
5 | import { template as _template, withVaporDirectives as _withVaporDirectives } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _withVaporDirectives(n0, [[
10 | vExample,
11 | () => msg,
12 | "foo",
13 | { bar: true }
14 | ]]);
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_once__with_v_if_else.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_once.rs
3 | expression: code
4 | ---
5 | import { createIf as _createIf, template as _template } from "vue";
6 | const t0 = _template("");
7 | const t1 = _template("");
8 | (() => {
9 | const n0 = _createIf(() => expr, () => {
10 | const n2 = t0();
11 | return n2;
12 | }, () => {
13 | const n4 = t1();
14 | return n4;
15 | }, true);
16 | return n0;
17 | })();
18 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_slot__on_component_named_slot.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_slot.rs
3 | expression: code
4 | ---
5 | import { createNodes as _createNodes, createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n2 = _createComponent(Comp, null, { named: (_slotProps0) => {
8 | const n0 = _createNodes(() => ({ foo: _slotProps0.foo }), () => ({ foo: _slotProps0.foo }));
9 | return n0;
10 | } }, true);
11 | return n2;
12 | })();
13 |
--------------------------------------------------------------------------------
/playground/vite.config.ts:
--------------------------------------------------------------------------------
1 | import Vue from '@vitejs/plugin-vue'
2 | import DefineRender from '@vue-macros/define-render/vite'
3 | import { defineConfig } from 'vite'
4 | import Inspect from 'vite-plugin-inspect'
5 | import VueJsxVapor from 'vue-jsx-vapor/vite'
6 |
7 | export default defineConfig({
8 | plugins: [
9 | Vue(),
10 | VueJsxVapor({
11 | // interop: true,
12 | macros: true,
13 | }),
14 | DefineRender({
15 | vapor: true,
16 | }),
17 | Inspect(),
18 | ],
19 | })
20 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_v_for_should_not_mark_as_single_root.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { createFor as _createFor } from "vue";
7 | (() => {
8 | const n0 = _createFor(() => items, (_for_item0) => {
9 | const n2 = _createComponent(Comp);
10 | return n2;
11 | }, (item) => item, 2);
12 | return n0;
13 | })();
14 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_if__dedupe_same_template.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_if.rs
3 | expression: code
4 | ---
5 | import { createIf as _createIf, template as _template } from "vue";
6 | const t0 = _template("hello
");
7 | (() => {
8 | const n0 = _createIf(() => ok, () => {
9 | const n2 = t0();
10 | return n2;
11 | });
12 | const n3 = _createIf(() => ok, () => {
13 | const n5 = t0();
14 | return n5;
15 | });
16 | return [n0, n3];
17 | })();
18 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_on__should_wrap_keys_guard_for_keyboard_events_or_dynamic_events.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_on.rs
3 | expression: code
4 | ---
5 | import { on as _on, template as _template, withKeys as _withKeys, withModifiers as _withModifiers } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _on(n0, "keydown", _withKeys(_withModifiers(test, ["stop", "ctrl"]), ["a"]), { capture: true });
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/transform/snapshots/r#mod__transform__hmr__export_default.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/transform/hmr.rs
3 | expression: code
4 | ---
5 | const __default__ = () => {};
6 | export default __default__;
7 | __default__.__hmrId = "52164bac249078a3";
8 | __VUE_HMR_RUNTIME__.createRecord("52164bac249078a3", __default__);
9 | if (import.meta.hot) import.meta.hot.accept((mod) => {
10 | __VUE_HMR_RUNTIME__[typeof mod.default === "function" ? "rerender" : "reload"](mod.default.__hmrId, mod.default);
11 | });
12 |
--------------------------------------------------------------------------------
/playground/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "jsx": "preserve",
5 | "jsxImportSource": "vue-jsx-vapor",
6 | "lib": ["ESNext", "DOM"],
7 | "customConditions": ["jsx-vapor-dev"],
8 | "module": "ESNext",
9 | "moduleResolution": "bundler",
10 | "resolveJsonModule": true,
11 | "types": ["vite/client", "@vue-macros/define-render/macros-global.d.ts"],
12 | "strict": true,
13 | "strictNullChecks": true,
14 | "esModuleInterop": true
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_import_resolve_component.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { createComponentWithFallback as _createComponentWithFallback } from "vue-jsx-vapor";
6 | import { resolveComponent as _resolveComponent } from "vue";
7 | (() => {
8 | const _component_Foo = _resolveComponent("Foo");
9 | const n0 = _createComponentWithFallback(_component_Foo, null, null, true);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__component_with_fallback.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { createComponentWithFallback as _createComponentWithFallback } from "vue-jsx-vapor";
6 | import { resolveComponent as _resolveComponent } from "vue";
7 | (() => {
8 | const _component_foo_bar = _resolveComponent("foo-bar");
9 | const n0 = _createComponentWithFallback(_component_foo_bar, null, null, true);
10 | return n0;
11 | })();
12 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_once__on_component.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_once.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { setInsertionState as _setInsertionState, template as _template } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n1 = t0();
10 | _setInsertionState(n1);
11 | const n0 = _createComponent(Comp, { id: () => foo }, null, null, true);
12 | return n1;
13 | })();
14 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_if__basic.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_if.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, createIf as _createIf, template as _template } from "vue";
7 | const t0 = _template("
");
8 | (() => {
9 | const n0 = _createIf(() => ok, () => {
10 | const n2 = t0();
11 | const x2 = _child(n2);
12 | _setNodes(x2, () => msg);
13 | return n2;
14 | });
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_if__v_if_v_if_else.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_if.rs
3 | expression: code
4 | ---
5 | import { createIf as _createIf, template as _template } from "vue";
6 | const t0 = _template("");
7 | const t1 = _template("");
8 | (() => {
9 | const n0 = _createIf(() => ok, () => {
10 | const n2 = t0();
11 | return n2;
12 | }, () => _createIf(() => orNot, () => {
13 | const n4 = t1();
14 | return n4;
15 | }));
16 | return n0;
17 | })();
18 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_text__should_convert_v_text_to_set_text.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_text.rs
3 | expression: code
4 | ---
5 | import { child as _child, renderEffect as _renderEffect, setText as _setText, template as _template, toDisplayString as _toDisplayString } from "vue";
6 | const t0 = _template("
", true);
7 | (() => {
8 | const n0 = t0();
9 | const x0 = _child(n0);
10 | _renderEffect(() => _setText(x0, _toDisplayString(str.value)));
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/eslint/test/__snapshots__/define-style.spec.ts.snap:
--------------------------------------------------------------------------------
1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2 |
3 | exports[`define-style > basic 1`] = `
4 | "
5 | defineStyle(\`
6 | .foo {
7 | color: red;
8 | }
9 | \`)
10 | "
11 | `;
12 |
13 | exports[`define-style > syntax error 1`] = `
14 | "
15 | defineStyle(\`
16 | .foo {
17 | color: red
18 | background: blue;
19 | }
20 | \`)
21 | "
22 | `;
23 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__invalid_html_nesting.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { template as _template } from "vue";
6 | const t0 = _template("123
");
7 | const t1 = _template("");
8 | const t2 = _template("");
9 | (() => {
10 | const n1 = t1();
11 | const n0 = t0();
12 | const n4 = t2();
13 | const n3 = t2();
14 | insert(n0, n1);
15 | insert(n3, n4);
16 | return [n1, n4];
17 | })();
18 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_once__basic.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_once.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, next as _next, setClass as _setClass, template as _template } from "vue";
7 | const t0 = _template("
", true);
8 | (() => {
9 | const n2 = t0();
10 | const n0 = _child(n2);
11 | const n1 = _next(n0);
12 | _setNodes(n0, msg);
13 | _setClass(n1, clz);
14 | return n2;
15 | })();
16 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_slots__nested.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_slots.rs
3 | expression: code
4 | ---
5 | import { createNodes as _createNodes, createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n5 = _createComponent(Comp, null, { default: (_slotProps0) => {
8 | const n2 = _createComponent(Comp, { bar: () => _slotProps0.bar });
9 | const n3 = _createNodes(() => _slotProps0.bar);
10 | return [n2, n3];
11 | } }, true);
12 | return n5;
13 | })();
14 |
--------------------------------------------------------------------------------
/playground/main.ts:
--------------------------------------------------------------------------------
1 | import {
2 | createVaporApp,
3 | // vaporInteropPlugin,
4 | } from 'vue'
5 |
6 | const modules = import.meta.glob('./src/*.tsx')
7 | const mod = (
8 | modules[`./src${location.pathname}.tsx`] || modules['./src/App.tsx']
9 | )()
10 |
11 | mod.then(({ default: mod }) => {
12 | const app = createVaporApp(mod)
13 | // app.use(vaporInteropPlugin).
14 | .mount('#app')
15 |
16 | // @ts-expect-error
17 | globalThis.unmount = () => {
18 | // @ts-expect-error
19 | app.unmount()
20 | }
21 | })
22 |
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "docs",
3 | "private": true,
4 | "type": "module",
5 | "scripts": {
6 | "dev": "vitepress dev",
7 | "build": "vitepress build",
8 | "preview": "vitepress preview"
9 | },
10 | "dependencies": {
11 | "@vue-jsx-vapor/eslint": "workspace:*",
12 | "vue": "catalog:",
13 | "vue-jsx-vapor": "workspace:*"
14 | },
15 | "devDependencies": {
16 | "@shikijs/vitepress-twoslash": "^3.13.0",
17 | "@ts-macro/twoslash": "^0.0.5",
18 | "vitepress": "2.0.0-alpha.5"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__should_support_input_dynamic_type.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { applyDynamicModel as _applyDynamicModel, renderEffect as _renderEffect, setProp as _setProp, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _applyDynamicModel(n0, () => model, (_value) => model = _value);
10 | _renderEffect(() => _setProp(n0, "type", foo));
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_slot__on_component_dynamically_named_slot.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_slot.rs
3 | expression: code
4 | ---
5 | import { createNodes as _createNodes, createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n1 = _createComponent(Comp, null, { $: [() => ({
8 | name: named,
9 | fn: (_slotProps0) => {
10 | const n0 = _createNodes(() => _slotProps0.foo + bar);
11 | return n0;
12 | }
13 | })] }, true);
14 | return n1;
15 | })();
16 |
--------------------------------------------------------------------------------
/packages/macros/tests/fixtures/define-model.tsx:
--------------------------------------------------------------------------------
1 |
2 | import { defineVaporComponent, unref } from 'vue'
3 |
4 | const $ = unref
5 |
6 | export const Comp = defineVaporComponent(({ bar }: { bar: string }) => {
7 | const foo = defineModel('foo', { default: bar })
8 | return {foo.value}
9 | })
10 |
11 | export default function () {
12 | const modelValue = $(defineModel()!)
13 | return (
14 |
15 | {modelValue}
16 |
17 | )
18 | }
19 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__dynamic_props_between_static_prop.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | import { renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _renderEffect(() => _setDynamicProps(n0, [
10 | { id: "foo" },
11 | obj,
12 | { class: "bar" }
13 | ], true));
14 | return n0;
15 | })();
16 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_template_ref__dynamic_ref.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_template_ref.rs
3 | expression: code
4 | ---
5 | import { createTemplateRefSetter as _createTemplateRefSetter, renderEffect as _renderEffect, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const _setTemplateRef = _createTemplateRefSetter();
9 | const n0 = t0();
10 | let r0;
11 | _renderEffect(() => r0 = _setTemplateRef(n0, foo, r0));
12 | return n0;
13 | })();
14 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__component_should_generate_model_value_modifiers.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Comp, {
8 | modelValue: () => foo,
9 | "onUpdate:modelValue": () => (_value) => foo = _value,
10 | modelValueModifiers: () => ({
11 | trim: true,
12 | "bar-baz": true
13 | })
14 | }, null, true);
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_element__props_merging_event_handlers.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_element.rs
3 | expression: code
4 | ---
5 | _delegateEvents("click");
6 | import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template, withKeys as _withKeys } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n0 = t0();
10 | _delegate(n0, "click", _withKeys(a, ["foo"]));
11 | _delegate(n0, "click", _withKeys(b, ["bar"]));
12 | return n0;
13 | })();
14 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__should_support_dynamic_props.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { applyDynamicModel as _applyDynamicModel, renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _applyDynamicModel(n0, () => model, (_value) => model = _value);
10 | _renderEffect(() => _setDynamicProps(n0, [obj], true));
11 | return n0;
12 | })();
13 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_children__efficient_find.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_children.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, nthChild as _nthChild, template as _template } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n1 = t0();
10 | const n0 = _nthChild(n1, 2);
11 | const x0 = _child(n0);
12 | _setNodes(x0, () => msg);
13 | return n1;
14 | })();
15 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_if__v_on_with_v_if.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_if.rs
3 | expression: code
4 | ---
5 | import { createIf as _createIf, renderEffect as _renderEffect, setDynamicEvents as _setDynamicEvents, template as _template } from "vue";
6 | const t0 = _template("");
7 | (() => {
8 | const n0 = _createIf(() => true, () => {
9 | const n2 = t0();
10 | _renderEffect(() => _setDynamicEvents(n2, { click: clickEvent }));
11 | return n2;
12 | }, null, true);
13 | return n0;
14 | })();
15 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_on__should_support_multiple_events_and_modifiers_options.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_on.rs
3 | expression: code
4 | ---
5 | _delegateEvents("click", "keyup");
6 | import { delegateEvents as _delegateEvents, template as _template, withKeys as _withKeys, withModifiers as _withModifiers } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n0 = t0();
10 | n0.$evtclick = _withModifiers(test, ["stop"]);
11 | n0.$evtkeyup = _withKeys(test, ["enter"]);
12 | return n0;
13 | })();
14 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_on__should_use_delegate_helper_when_have_multiple_events_of_same_name.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_on.rs
3 | expression: code
4 | ---
5 | _delegateEvents("click");
6 | import { delegate as _delegate, delegateEvents as _delegateEvents, template as _template, withModifiers as _withModifiers } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n0 = t0();
10 | _delegate(n0, "click", test);
11 | _delegate(n0, "click", _withModifiers(test, ["stop"]));
12 | return n0;
13 | })();
14 |
--------------------------------------------------------------------------------
/playground/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "playground",
3 | "version": "3.0.4",
4 | "private": true,
5 | "type": "module",
6 | "scripts": {
7 | "dev": "node vite.js --port 5174",
8 | "build": "node vite.js build"
9 | },
10 | "devDependencies": {
11 | "@vitejs/plugin-vue": "^6.0.1",
12 | "@vue-macros/define-render": "catalog:",
13 | "vite": "catalog:",
14 | "vite-hyper-config": "^0.7.1",
15 | "vite-node": "^3.2.4",
16 | "vite-plugin-inspect": "^11.3.3",
17 | "vue": "catalog:",
18 | "vue-jsx-vapor": "workspace:*"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__selector_pattern3.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { createFor as _createFor, renderEffect as _renderEffect, setClass as _setClass, template as _template } from "vue";
6 | const t0 = _template("
");
7 | (() => {
8 | const n0 = _createFor(() => rows, (_for_item0) => {
9 | const n2 = t0();
10 | _renderEffect(() => _setClass(n2, _for_item0.value.label === _for_item0.value.id ? "danger" : ""));
11 | return n2;
12 | }, (row) => row.id);
13 | return n0;
14 | })();
15 |
--------------------------------------------------------------------------------
/packages/eslint/test/__snapshots__/jsx-sort-props.spec.ts.snap:
--------------------------------------------------------------------------------
1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2 |
3 | exports[`jsx-sort-props > basic 1`] = `
4 | "
5 |
6 | "
7 | `;
8 |
9 | exports[`jsx-sort-props > reservedFirst 1`] = `""`;
10 |
11 | exports[`jsx-sort-props > reservedFirst and reservedLast 1`] = `" {}} v-slot:a={{ foo }} v-slot:b={{ foo }} />"`;
12 |
13 | exports[`jsx-sort-props > reservedLast 1`] = `" {}} v-slot={{ foo }} />"`;
14 |
--------------------------------------------------------------------------------
/packages/macros/src/core/style.ts:
--------------------------------------------------------------------------------
1 | import { compileStyleAsync } from '@vue/compiler-sfc'
2 | import type { OptionsResolved } from '../options'
3 |
4 | export async function transformStyle(
5 | code: string,
6 | id: string,
7 | options: OptionsResolved,
8 | ): Promise {
9 | const query = new URLSearchParams(id.split('?')[1])
10 | const result = await compileStyleAsync({
11 | filename: id,
12 | id: `data-v-${query.get('scopeId')}`,
13 | isProd: options.isProduction,
14 | source: code,
15 | scoped: query.get('scoped') === 'true',
16 | })
17 |
18 | return result.code
19 | }
20 |
--------------------------------------------------------------------------------
/packages/macros/src/nuxt.ts:
--------------------------------------------------------------------------------
1 | import { addVitePlugin, addWebpackPlugin, defineNuxtModule } from '@nuxt/kit'
2 | import vite from './vite'
3 | import webpack from './webpack'
4 | import type { Options } from './options'
5 | import '@nuxt/schema'
6 |
7 | export interface ModuleOptions extends Options {}
8 |
9 | export default defineNuxtModule({
10 | meta: {
11 | name: 'nuxt-vue-jsx-vapor',
12 | configKey: 'unpluginStarter',
13 | },
14 | setup(options) {
15 | addVitePlugin(() => vite(options))
16 | addWebpackPlugin(() => webpack(options))
17 |
18 | // ...
19 | },
20 | })
21 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/nuxt.ts:
--------------------------------------------------------------------------------
1 | import { addVitePlugin, addWebpackPlugin, defineNuxtModule } from '@nuxt/kit'
2 | import vite from './vite'
3 | import webpack from './webpack'
4 | import type { Options } from './options'
5 | import '@nuxt/schema'
6 |
7 | export interface ModuleOptions extends Options {}
8 |
9 | export default defineNuxtModule({
10 | meta: {
11 | name: 'nuxt-vue-jsx-vapor',
12 | configKey: 'jsxVapor',
13 | },
14 | setup(options) {
15 | addVitePlugin(() => vite(options))
16 | addWebpackPlugin(() => webpack(options))
17 |
18 | // ...
19 | },
20 | })
21 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__key_only_binding_pattern.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, createFor as _createFor, template as _template } from "vue";
7 | const t0 = _template("
");
8 | (() => {
9 | const n0 = _createFor(() => rows, (_for_item0) => {
10 | const n2 = t0();
11 | const x2 = _child(n2);
12 | _setNodes(x2, () => _for_item0.value.id + _for_item0.value.id);
13 | return n2;
14 | }, (row) => row.id);
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__multi_effect.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { createFor as _createFor, renderEffect as _renderEffect, setProp as _setProp, template as _template } from "vue";
6 | const t0 = _template("");
7 | (() => {
8 | const n0 = _createFor(() => items, (_for_item0, _for_key0) => {
9 | const n2 = t0();
10 | _renderEffect(() => {
11 | _setProp(n2, "item", _for_item0.value);
12 | _setProp(n2, "index", _for_key0.value);
13 | });
14 | return n2;
15 | });
16 | return n0;
17 | })();
18 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__aliases_with_complex_expressions.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, createFor as _createFor, template as _template } from "vue";
7 | const t0 = _template("
");
8 | (() => {
9 | const n0 = _createFor(() => list, (_for_item0) => {
10 | const n2 = t0();
11 | const x2 = _child(n2);
12 | _setNodes(x2, () => _for_item0.value.foo + baz + _for_item0.value.baz[0]);
13 | return n2;
14 | });
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__component_with_arguments_should_generate_model_modifiers.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Comp, {
8 | foo: () => foo,
9 | "onUpdate:foo": () => (_value) => foo = _value,
10 | fooModifiers: () => ({ trim: true }),
11 | bar: () => bar,
12 | "onUpdate:bar": () => (_value) => bar = _value,
13 | barModifiers: () => ({ number: true })
14 | }, null, true);
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_slot__dynamic_slots_name_with_v_for.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_slot.rs
3 | expression: code
4 | ---
5 | import { createNodes as _createNodes, createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { createForSlots as _createForSlots } from "vue";
7 | (() => {
8 | const n4 = _createComponent(Comp, null, { $: [() => _createForSlots(list, (item) => ({
9 | name: item,
10 | fn: (_slotProps0) => {
11 | const n1 = _createNodes(() => _slotProps0.bar);
12 | return n1;
13 | }
14 | }))] }, true);
15 | return n4;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_children__jsx_component_in_jsx_expression_container.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_children.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes, createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { child as _child, template as _template } from "vue";
7 | const t0 = _template("
", true);
8 | (() => {
9 | const n0 = t0();
10 | const x0 = _child(n0);
11 | _setNodes(x0, () => (() => {
12 | const n0 = _createComponent(Comp, null, null, true);
13 | return n0;
14 | })());
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/macros/src/core/define-component/return.ts:
--------------------------------------------------------------------------------
1 | import { isFunctionalNode, type FunctionalNode } from '../utils'
2 | import type { MagicStringAST } from '@vue-macros/common'
3 |
4 | export function transformReturn(root: FunctionalNode, s: MagicStringAST): void {
5 | const node =
6 | root.body.type === 'BlockStatement'
7 | ? root.body.body.find((node) => node.type === 'ReturnStatement')?.argument
8 | : root.body
9 | if (!node || isFunctionalNode(node)) return
10 |
11 | s.appendRight(
12 | node.extra?.parenthesized ? (node.extra.parenStart as number) : node.start!,
13 | '() => ',
14 | )
15 | }
16 |
--------------------------------------------------------------------------------
/docs/zh/features/use-ref.md:
--------------------------------------------------------------------------------
1 | # useRef
2 |
3 | 自动为 `useRef` 推断类型。它是 `shallowRef` 的别名。
4 |
5 | ## 基本用法
6 |
7 | ```tsx twoslash
8 | import { defineVaporComponent } from 'vue'
9 | import { useRef } from 'vue-jsx-vapor'
10 | // 或者
11 | // import { shallowRef as useRef } from 'vue'
12 |
13 | export const Comp = () => {
14 | defineExpose({
15 | foo: 1,
16 | })
17 |
18 | return
19 | }
20 |
21 | export default defineVaporComponent(() => {
22 | const comp = useRef()
23 | comp.value?.foo
24 | // ^?
25 |
26 | return (
27 |
28 |
29 |
30 | )
31 | })
32 | ```
33 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_if__v_if_v_else_if_v_else.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_if.rs
3 | expression: code
4 | ---
5 | import { createIf as _createIf, template as _template } from "vue";
6 | const t0 = _template("");
7 | const t1 = _template("");
8 | const t2 = _template("fine");
9 | (() => {
10 | const n0 = _createIf(() => ok, () => {
11 | const n2 = t0();
12 | return n2;
13 | }, () => _createIf(() => orNot, () => {
14 | const n4 = t1();
15 | return n4;
16 | }, () => {
17 | const n7 = t2();
18 | return n7;
19 | }));
20 | return n0;
21 | })();
22 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__component_with_dynamic_arguments_with_v_for.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { createFor as _createFor } from "vue";
7 | (() => {
8 | const n0 = _createFor(() => list, (_for_item0) => {
9 | const n2 = _createComponent(Comp, { $: [() => ({
10 | [_for_item0.value.arg]: foo,
11 | ["onUpdate:" + _for_item0.value.arg]: () => (_value) => foo = _value
12 | })] });
13 | return n2;
14 | }, void 0, 2);
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/macros/src/core/define-slots.ts:
--------------------------------------------------------------------------------
1 | import { importHelperFn, type MagicStringAST } from '@vue-macros/common'
2 | import type { CallExpression } from '@babel/types'
3 |
4 | export function transformDefineSlots(
5 | node: CallExpression,
6 | s: MagicStringAST,
7 | ): void {
8 | s.overwrite(
9 | node.start!,
10 | (node.arguments[0]?.start && node.arguments[0].start - 1) ||
11 | node.typeArguments?.end ||
12 | node.callee.end!,
13 | `Object.assign`,
14 | )
15 | const slots = `${importHelperFn(s, 0, 'useSlots')}()`
16 | s.appendLeft(node.end! - 1, `${node.arguments[0] ? ',' : '{}, '}${slots}`)
17 | }
18 |
--------------------------------------------------------------------------------
/tsdown.config.ts:
--------------------------------------------------------------------------------
1 | import process from 'node:process'
2 | import { defineConfig, type Options } from 'tsdown'
3 | import Raw from 'unplugin-raw/rolldown'
4 |
5 | export const config = (options: Options = {}) =>
6 | defineConfig({
7 | entry: ['./src/*.ts', '!./**.d.ts'],
8 | clean: true,
9 | format: ['cjs', 'esm'],
10 | watch: !!process.env.DEV,
11 | dts: !process.env.DEV,
12 | external: ['vue'],
13 | define: {
14 | __DEV__: 'true',
15 | },
16 | plugins: [Raw()],
17 | outputOptions: {
18 | exports: 'named',
19 | },
20 | ...options,
21 | })
22 |
23 | export default config()
24 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__object_de_structured_value.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, createFor as _createFor, template as _template } from "vue";
7 | const t0 = _template(" ");
8 | (() => {
9 | const n0 = _createFor(() => items, (_for_item0) => {
10 | const n2 = t0();
11 | const x2 = _child(n2);
12 | _setNodes(x2, () => _for_item0.value.id, () => _for_item0.value.value);
13 | return n2;
14 | }, ({ id, value }) => id);
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/options.d.ts:
--------------------------------------------------------------------------------
1 | import type { CompilerOptions } from '@vue-jsx-vapor/compiler'
2 | import type { Options as MacrosOptions } from '@vue-jsx-vapor/macros'
3 | import type { FilterPattern } from 'unplugin-utils'
4 |
5 | export interface Options {
6 | // define your plugin options here
7 | include?: FilterPattern
8 | exclude?: FilterPattern
9 | interop?: boolean
10 | compile?: CompilerOptions
11 | sourceMap?: boolean
12 | /** @default true */
13 | ref?:
14 | | {
15 | alias?: string[]
16 | }
17 | | boolean
18 | /** @default false */
19 | macros?: MacrosOptions | boolean
20 | }
21 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "jsx": "preserve",
5 | "jsxImportSource": "vue-jsx-vapor",
6 | "lib": ["esnext", "DOM"],
7 | "useDefineForClassFields": false,
8 | "customConditions": ["jsx-vapor-dev"],
9 | "module": "esnext",
10 | "moduleResolution": "bundler",
11 | "resolveJsonModule": true,
12 | "types": ["vite/client"],
13 | "allowImportingTsExtensions": true,
14 | "strict": true,
15 | "strictNullChecks": true,
16 | "noEmit": true,
17 | "esModuleInterop": true,
18 | "skipLibCheck": true
19 | },
20 | "include": ["packages"]
21 | }
22 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/core/index.ts:
--------------------------------------------------------------------------------
1 | import { transform } from '@vue-jsx-vapor/compiler-rs'
2 | import type { Options } from '../options'
3 |
4 | export type { Options }
5 |
6 | export function transformVueJsxVapor(
7 | code: string,
8 | id: string,
9 | options?: Options,
10 | needSourceMap = false,
11 | needHMR = false,
12 | ssr = false,
13 | ) {
14 | const params = new URLSearchParams(id)
15 | const vapor = params.get('vapor')
16 | return transform(code, {
17 | filename: id,
18 | sourceMap: needSourceMap,
19 | interop: vapor ? false : options?.interop,
20 | hmr: needHMR,
21 | ssr,
22 | })
23 | }
24 |
--------------------------------------------------------------------------------
/playground/src/interop.tsx:
--------------------------------------------------------------------------------
1 | import { defineComponent, defineVaporComponent, ref } from 'vue'
2 |
3 | const VaporComp = defineVaporComponent(
4 | (props) => {
5 | return (
6 |
7 | Vapor Component:
8 | {props.model}
9 |
10 | )
11 | },
12 | { props: ['model'] },
13 | )
14 |
15 | const Comp = (props) => Virtual Dom Component:{props.model}
16 |
17 | export default defineComponent(() => {
18 | const model = ref('')
19 | return () => [
20 | ,
21 | ,
22 | ,
23 | ]
24 | })
25 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/transform/interop.rs:
--------------------------------------------------------------------------------
1 | use compiler_rs::{TransformOptions, transform};
2 | use insta::assert_snapshot;
3 |
4 | #[test]
5 | fn basic() {
6 | let code = transform(
7 | "const A = defineComponent(() => {
8 | defineVaporComponent(() => )
9 | return () =>
10 | })
11 | const B = defineVaporComponent(() => {
12 | const C = defineComponent(() => )
13 | const D = <>{foo} >
14 | return
15 | })",
16 | Some(TransformOptions {
17 | interop: true,
18 | ..Default::default()
19 | }),
20 | )
21 | .code;
22 | assert_snapshot!(code);
23 | }
24 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/index.ts:
--------------------------------------------------------------------------------
1 | import TwoslashFloatingVue from '@shikijs/vitepress-twoslash/client'
2 | import DefaultTheme from 'vitepress/theme'
3 | // https://vitepress.dev/guide/custom-theme
4 | import { h } from 'vue'
5 | import type { Theme } from 'vitepress'
6 | import './style.css'
7 | import '@shikijs/vitepress-twoslash/style.css'
8 |
9 | export default {
10 | extends: DefaultTheme,
11 | Layout: () => {
12 | return h(DefaultTheme.Layout, null, {
13 | // https://vitepress.dev/guide/extending-default-theme#layout-slots
14 | })
15 | },
16 | enhanceApp({ app }) {
17 | app.use(TwoslashFloatingVue)
18 | },
19 | } satisfies Theme
20 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_template_ref__ref_v_if.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_template_ref.rs
3 | expression: code
4 | ---
5 | import { createIf as _createIf, createTemplateRefSetter as _createTemplateRefSetter, renderEffect as _renderEffect, template as _template } from "vue";
6 | const t0 = _template("");
7 | (() => {
8 | const _setTemplateRef = _createTemplateRefSetter();
9 | const n0 = _createIf(() => true, () => {
10 | const n2 = t0();
11 | let r2;
12 | _renderEffect(() => r2 = _setTemplateRef(n2, foo, r2));
13 | return n2;
14 | }, null, true);
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__array_de_structured_value.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, createFor as _createFor, template as _template } from "vue";
7 | const t0 = _template("
");
8 | (() => {
9 | const n0 = _createFor(() => list, (_for_item0, _for_key0) => {
10 | const n2 = t0();
11 | const x2 = _child(n2);
12 | _setNodes(x2, () => _for_item0.value[0] + _for_item0.value[1] + _for_key0.value);
13 | return n2;
14 | }, ([id, other], index) => id);
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__on_component.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes, createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { createFor as _createFor, template as _template } from "vue";
7 | const t0 = _template(" ");
8 | (() => {
9 | const n0 = _createFor(() => list, (_for_item0) => {
10 | const n3 = _createComponent(Comp, null, { default: () => {
11 | const n2 = t0();
12 | _setNodes(n2, () => _for_item0.value);
13 | return n2;
14 | } });
15 | return n3;
16 | }, void 0, 2);
17 | return n0;
18 | })();
19 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_slot__named_slots_with_comment.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_slot.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { template as _template } from "vue";
7 | const t0 = _template("foo");
8 | const t1 = _template("");
9 | (() => {
10 | const n8 = _createComponent(Comp, null, {
11 | one: () => {
12 | const n3 = t0();
13 | return n3;
14 | },
15 | default: () => {
16 | const n5 = t0();
17 | const n6 = t1();
18 | return [n5, n6];
19 | }
20 | }, true);
21 | return n8;
22 | })();
23 |
--------------------------------------------------------------------------------
/docs/features/use-ref.md:
--------------------------------------------------------------------------------
1 | # useRef
2 |
3 | Automatically infer type for `useRef`. It's an alias of `shallowRef`.
4 |
5 | ## Basic Usage
6 |
7 | ```tsx twoslash
8 | import { defineVaporComponent } from 'vue'
9 | import { useRef } from 'vue-jsx-vapor'
10 | // or
11 | // import { shallowRef as useRef } from 'vue'
12 |
13 | export const Comp = () => {
14 | defineExpose({
15 | foo: 1
16 | })
17 |
18 | return
19 | }
20 |
21 | export default defineVaporComponent(() => {
22 | const comp = useRef()
23 | comp.value?.foo
24 | // ^?
25 |
26 | return (
27 |
28 |
29 |
30 | )
31 | })
32 | ```
33 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__object_value_key_and_index.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, createFor as _createFor, template as _template } from "vue";
7 | const t0 = _template(" ");
8 | (() => {
9 | const n0 = _createFor(() => items, (_for_item0, _for_key0, _for_index0) => {
10 | const n2 = t0();
11 | const x2 = _child(n2);
12 | _setNodes(x2, () => id, () => _for_item0.value, () => _for_index0.value);
13 | return n2;
14 | }, (value, key, index) => id);
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_text__expression_logical.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_text.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes, createNodes as _createNodes } from "vue-jsx-vapor";
6 | import { child as _child, createIf as _createIf, template as _template } from "vue";
7 | const t0 = _template("
");
8 | (() => {
9 | const n0 = _createIf(() => ok, () => {
10 | const n2 = t0();
11 | const x2 = _child(n2);
12 | _setNodes(x2, () => msg);
13 | return n2;
14 | }, () => {
15 | const n4 = _createNodes(() => ok);
16 | return n4;
17 | });
18 | return n0;
19 | })();
20 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_slot__nested_slots_scoping.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_slot.rs
3 | expression: code
4 | ---
5 | import { createNodes as _createNodes, createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n11 = _createComponent(Comp, null, { default: (_slotProps0) => {
8 | const n5 = _createComponent(Inner, null, { default: (_slotProps1) => {
9 | const n3 = _createNodes(() => _slotProps0.foo + _slotProps1.bar + baz);
10 | return n3;
11 | } });
12 | const n7 = _createNodes(() => _slotProps0.foo + bar + baz);
13 | return [n5, n7];
14 | } }, true);
15 | return n11;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/macros/src/core/define-model.ts:
--------------------------------------------------------------------------------
1 | import { importHelperFn, type MagicStringAST } from '@vue-macros/common'
2 | import { useModelHelperId } from './helper'
3 | import type { CallExpression } from '@babel/types'
4 |
5 | export function transformDefineModel(
6 | node: CallExpression,
7 | propsName: string,
8 | s: MagicStringAST,
9 | ): void {
10 | s.overwriteNode(
11 | node.callee,
12 | importHelperFn(s, 0, 'useModel', undefined, useModelHelperId),
13 | )
14 | s.appendRight(
15 | node.arguments[0]?.start || node.end! - 1,
16 | `${propsName}, ${
17 | node.arguments[0]?.type !== 'StringLiteral' ? `'modelValue',` : ''
18 | }`,
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_children__anchor_insertion_in_middle.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_children.rs
3 | expression: code
4 | ---
5 | import { child as _child, createIf as _createIf, next as _next, setInsertionState as _setInsertionState, template as _template } from "vue";
6 | const t0 = _template("");
7 | const t1 = _template("", true);
8 | (() => {
9 | const n4 = t1();
10 | const n3 = _next(_child(n4));
11 | _setInsertionState(n4, n3);
12 | const n0 = _createIf(() => 1, () => {
13 | const n2 = t0();
14 | return n2;
15 | }, null, true);
16 | return n4;
17 | })();
18 |
--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vitest/config'
2 |
3 | export default defineConfig({
4 | resolve: {
5 | conditions: ['jsx-vapor-dev'],
6 | },
7 | test: {
8 | include: ['./packages/**/*.spec.ts'],
9 | },
10 | define: {
11 | __DEV__: true,
12 | __TEST__: true,
13 | __VERSION__: '"test"',
14 | __GLOBAL__: false,
15 | __ESM_BUNDLER__: true,
16 | __ESM_BROWSER__: false,
17 | __CJS__: true,
18 | __SSR__: true,
19 | __FEATURE_OPTIONS_API__: true,
20 | __FEATURE_SUSPENSE__: true,
21 | __FEATURE_PROD_DEVTOOLS__: false,
22 | __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__: false,
23 | __COMPAT__: true,
24 | },
25 | })
26 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__on_template_with_single_component_child.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes, createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { createFor as _createFor, template as _template } from "vue";
7 | const t0 = _template(" ");
8 | (() => {
9 | const n0 = _createFor(() => list, (_for_item0) => {
10 | const n3 = _createComponent(Comp, null, { default: () => {
11 | const n2 = t0();
12 | _setNodes(n2, () => _for_item0.value);
13 | return n2;
14 | } });
15 | return n3;
16 | }, void 0, 2);
17 | return n0;
18 | })();
19 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__selector_pattern4.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { createFor as _createFor, setClass as _setClass, template as _template } from "vue";
6 | const t0 = _template("
");
7 | (() => {
8 | let _selector0_0;
9 | const n0 = _createFor(() => rows, (_for_item0) => {
10 | const n2 = t0();
11 | _selector0_0(() => {
12 | _setClass(n2, { danger: _for_item0.value.id === selected });
13 | });
14 | return n2;
15 | }, (row) => row.id, void 0, ({ createSelector }) => {
16 | _selector0_0 = createSelector(() => selected);
17 | });
18 | return n0;
19 | })();
20 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__selector_pattern2.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { createFor as _createFor, setClass as _setClass, template as _template } from "vue";
6 | const t0 = _template("
");
7 | (() => {
8 | let _selector0_0;
9 | const n0 = _createFor(() => rows, (_for_item0) => {
10 | const n2 = t0();
11 | _selector0_0(() => {
12 | _setClass(n2, selected === _for_item0.value.id ? "danger" : "");
13 | });
14 | return n2;
15 | }, (row) => row.id, void 0, ({ createSelector }) => {
16 | _selector0_0 = createSelector(() => selected);
17 | });
18 | return n0;
19 | })();
20 |
--------------------------------------------------------------------------------
/.github/workflows/release-pr.yml:
--------------------------------------------------------------------------------
1 | name: Publish Any Commit
2 | on: [pull_request]
3 |
4 | jobs:
5 | build:
6 | runs-on: ubuntu-latest
7 |
8 | steps:
9 | - name: Checkout Repo
10 | uses: actions/checkout@v4
11 | with:
12 | fetch-depth: 0
13 |
14 | - uses: pnpm/action-setup@v4.0.0
15 |
16 | - name: Setup Node.js
17 | uses: actions/setup-node@v4
18 | with:
19 | node-version: lts/*
20 | cache: pnpm
21 |
22 | - name: Install dependencies
23 | run: pnpm install
24 |
25 | - name: Build
26 | run: pnpm build
27 |
28 | - name: Publish
29 | run: pnpm dlx pkg-pr-new@0.0 publish
30 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__basic.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | _delegateEvents("click");
6 | import { setNodes as _setNodes } from "vue-jsx-vapor";
7 | import { child as _child, createFor as _createFor, delegateEvents as _delegateEvents, template as _template } from "vue";
8 | const t0 = _template("
");
9 | (() => {
10 | const n0 = _createFor(() => items, (_for_item0) => {
11 | const n2 = t0();
12 | n2.$evtclick = () => remove(_for_item0.value);
13 | const x2 = _child(n2);
14 | _setNodes(x2, () => _for_item0.value);
15 | return n2;
16 | }, (item) => item.id);
17 | return n0;
18 | })();
19 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__component_with_dynamic_arguments_should_generate_model_modifiers.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | (() => {
7 | const n0 = _createComponent(Comp, { $: [() => ({
8 | [foo]: foo,
9 | ["onUpdate:" + foo]: () => (_value) => foo = _value,
10 | [foo + "Modifiers"]: () => ({ trim: true })
11 | }), () => ({
12 | [bar.value]: bar,
13 | ["onUpdate:" + bar.value]: () => (_value) => bar = _value,
14 | [bar.value + "Modifiers"]: () => ({ number: true })
15 | })] }, null, true);
16 | return n0;
17 | })();
18 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_slot__on_component_named_slot_multiple.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_slot.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { template as _template } from "vue";
7 | const t0 = _template("foo");
8 | (() => {
9 | const n10 = _createComponent(Comp, null, {
10 | left: () => {
11 | const n1 = t0();
12 | return n1;
13 | },
14 | right: () => {
15 | const n6 = _createComponent(Comp, null, { left: () => {
16 | const n5 = t0();
17 | return n5;
18 | } });
19 | return n6;
20 | }
21 | }, true);
22 | return n10;
23 | })();
24 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/transform/ssr.rs:
--------------------------------------------------------------------------------
1 | use compiler_rs::{TransformOptions, transform};
2 | use insta::assert_snapshot;
3 |
4 | #[test]
5 | pub fn ssr_export() {
6 | let code = transform(
7 | "export const foo = () => {}",
8 | Some(TransformOptions {
9 | ssr: true,
10 | ..Default::default()
11 | }),
12 | )
13 | .code;
14 | assert_snapshot!(code);
15 | }
16 |
17 | #[test]
18 | pub fn ssr_export_default() {
19 | let code = transform(
20 | "
21 | const Comp = () => {}
22 | export default Comp
23 | ",
24 | Some(TransformOptions {
25 | ssr: true,
26 | ..Default::default()
27 | }),
28 | )
29 | .code;
30 | assert_snapshot!(code);
31 | }
32 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_if__comment_between_branches.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_if.rs
3 | expression: code
4 | ---
5 | import { createIf as _createIf, template as _template } from "vue";
6 | const t0 = _template("");
7 | const t1 = _template("");
8 | const t2 = _template("fine");
9 | const t3 = _template("text
");
10 | (() => {
11 | const n1 = _createIf(() => ok, () => {
12 | const n3 = t0();
13 | return n3;
14 | }, () => _createIf(() => orNot, () => {
15 | const n8 = t1();
16 | return n8;
17 | }, () => {
18 | const n14 = t2();
19 | return n14;
20 | }));
21 | const n18 = t3();
22 | return [n1, n18];
23 | })();
24 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_slot__named_slots_with_implicit_default_slot.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_slot.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { template as _template } from "vue";
7 | const t0 = _template("foo");
8 | const t1 = _template("bar");
9 | const t2 = _template("");
10 | (() => {
11 | const n6 = _createComponent(Comp, null, {
12 | one: () => {
13 | const n1 = t0();
14 | return n1;
15 | },
16 | default: () => {
17 | const n3 = t1();
18 | const n4 = t2();
19 | return [n3, n4];
20 | }
21 | }, true);
22 | return n6;
23 | })();
24 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_template_ref__ref_v_for.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_template_ref.rs
3 | expression: code
4 | ---
5 | import { createFor as _createFor, createTemplateRefSetter as _createTemplateRefSetter, renderEffect as _renderEffect, template as _template } from "vue";
6 | const t0 = _template("");
7 | (() => {
8 | const _setTemplateRef = _createTemplateRefSetter();
9 | const n0 = _createFor(() => [
10 | 1,
11 | 2,
12 | 3
13 | ], (_for_item0) => {
14 | const n2 = t0();
15 | let r2;
16 | _renderEffect(() => r2 = _setTemplateRef(n2, foo, r2, true));
17 | return n2;
18 | }, void 0, 4);
19 | return n0;
20 | })();
21 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_model__should_support_member_expression_with_inline.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_model.rs
3 | expression: code
4 | ---
5 | import { applyTextModel as _applyTextModel, template as _template } from "vue";
6 | const t0 = _template("");
7 | (() => {
8 | const n0 = t0();
9 | const n1 = t0();
10 | const n2 = t0();
11 | _applyTextModel(n0, () => setupRef.child, (_value) => setupRef.child = _value);
12 | _applyTextModel(n1, () => setupLet.child, (_value) => setupLet.child = _value);
13 | _applyTextModel(n2, () => setupMaybeRef.child, (_value) => setupMaybeRef.child = _value);
14 | return [
15 | n0,
16 | n1,
17 | n2
18 | ];
19 | })();
20 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/jsx-runtime/index.d.ts:
--------------------------------------------------------------------------------
1 | import { Fragment, type Block, type VNode } from 'vue'
2 | import type { h, NativeElements, ReservedProps } from 'vue-jsx-vapor'
3 |
4 | declare function jsx(type: any, props: any, key: any): ReturnType
5 | declare global {
6 | namespace JSX {
7 | type Element = VNode | Block | Element[]
8 | interface ElementAttributesProperty {
9 | $props
10 | }
11 | interface IntrinsicElements extends NativeElements {
12 | [name: string]: any
13 | }
14 | interface IntrinsicAttributes extends ReservedProps {
15 | class?: unknown
16 | style?: unknown
17 | }
18 | }
19 | }
20 | export { Fragment, jsx, jsx as jsxDEV, jsx as jsxs }
21 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "node",
9 | "request": "launch",
10 | "name": "Vitest - Debug Current Test File",
11 | "autoAttachChildProcesses": true,
12 | "skipFiles": ["/**", "**/node_modules/**"],
13 | "program": "${workspaceRoot}/node_modules/vitest/vitest.mjs",
14 | "args": ["run", "${relativeFile}"],
15 | "smartStep": true,
16 | "console": "integratedTerminal"
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__fast_remove_flag.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, createFor as _createFor, setInsertionState as _setInsertionState, template as _template } from "vue";
7 | const t0 = _template(" ");
8 | const t1 = _template("", true);
9 | (() => {
10 | const n3 = t1();
11 | _setInsertionState(n3);
12 | const n0 = _createFor(() => i, (_for_item0) => {
13 | const n2 = t0();
14 | const x2 = _child(n2);
15 | _setNodes(x2, () => _for_item0.value + i);
16 | return n2;
17 | }, void 0, 1);
18 | return n3;
19 | })();
20 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__object_de_structured_value_with_rest.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, createFor as _createFor, getRestElement as _getRestElement, template as _template } from "vue";
7 | const t0 = _template("
");
8 | (() => {
9 | const n0 = _createFor(() => list, (_for_item0, _for_key0) => {
10 | const n2 = t0();
11 | const x2 = _child(n2);
12 | _setNodes(x2, () => _for_item0.value.id + _getRestElement(_for_item0.value, ["id"]) + _for_key0.value);
13 | return n2;
14 | }, ({ id, ...other }, index) => id);
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__array_de_structured_value_with_rest.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, createFor as _createFor, template as _template } from "vue";
7 | const t0 = _template("
");
8 | (() => {
9 | const n0 = _createFor(() => list, (_for_item0, _for_key0) => {
10 | const n2 = t0();
11 | const x2 = _child(n2);
12 | _setNodes(x2, () => _for_item0.value[0] + _for_item0.value.slice(3) + _for_key0.value + _for_item0.value[1][0] + _for_item0.value[2].bar);
13 | return n2;
14 | }, ([id, [foo], {bar}, ...other], index) => id);
15 | return n0;
16 | })();
17 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/v_show.rs:
--------------------------------------------------------------------------------
1 | use std::cell::RefCell;
2 |
3 | use common::{error::ErrorCodes, options::TransformOptions};
4 | use compiler_rs::transform;
5 | use insta::assert_snapshot;
6 |
7 | #[test]
8 | fn basic() {
9 | let code = transform("", None).code;
10 | assert_snapshot!(code);
11 | }
12 |
13 | #[test]
14 | fn should_raise_error_if_has_no_expression() {
15 | let error = RefCell::new(None);
16 | transform(
17 | "",
18 | Some(TransformOptions {
19 | on_error: Box::new(|e, _| {
20 | *error.borrow_mut() = Some(e);
21 | }),
22 | ..Default::default()
23 | }),
24 | );
25 | assert_eq!(*error.borrow(), Some(ErrorCodes::VShowNoExpression));
26 | }
27 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__expression_object.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, createFor as _createFor, renderEffect as _renderEffect, setProp as _setProp, template as _template } from "vue";
7 | const t0 = _template("
");
8 | (() => {
9 | const n0 = _createFor(() => Array.from({ length: count.value }).map((_, id) => ({ id })), (_for_item0, _for_key0) => {
10 | const n2 = t0();
11 | const x2 = _child(n2);
12 | _setNodes(x2, () => _for_item0.value);
13 | _renderEffect(() => _setProp(n2, "id", _for_key0.value));
14 | return n2;
15 | });
16 | return n0;
17 | })();
18 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_if__template.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_if.rs
3 | expression: code
4 | ---
5 | import { child as _child, createIf as _createIf, renderEffect as _renderEffect, setText as _setText, template as _template, toDisplayString as _toDisplayString } from "vue";
6 | const t0 = _template("");
7 | const t1 = _template("hello");
8 | const t2 = _template("
");
9 | (() => {
10 | const n0 = _createIf(() => ok, () => {
11 | const n2 = t0();
12 | const n3 = t1();
13 | const n4 = t2();
14 | const x4 = _child(n4);
15 | _renderEffect(() => _setText(x4, _toDisplayString(msg)));
16 | return [
17 | n2,
18 | n3,
19 | n4
20 | ];
21 | });
22 | return n0;
23 | })();
24 |
--------------------------------------------------------------------------------
/packages/eslint/src/rules/index.ts:
--------------------------------------------------------------------------------
1 | import _defineStyle from './define-style'
2 | import jsxSortProps from './jsx-sort-props'
3 | import type { DefineStyleRuleOptions } from './define-style/types'
4 | import type { JsxSortPropsRuleOptions } from './jsx-sort-props/types'
5 | import type { Linter } from 'eslint'
6 |
7 | const ruleOptions = {
8 | 'jsx-sort-props': jsxSortProps,
9 | 'define-style': _defineStyle,
10 | }
11 |
12 | export interface RuleOptions {
13 | 'vue-jsx-vapor/jsx-sort-props': JsxSortPropsRuleOptions
14 | 'vue-jsx-vapor/define-style': DefineStyleRuleOptions
15 | }
16 |
17 | export type Rules = Partial<{
18 | [K in keyof RuleOptions]:
19 | | Linter.RuleSeverity
20 | | [Linter.RuleSeverity, ...RuleOptions[K]]
21 | }>
22 |
23 | export default ruleOptions
24 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__selector_pattern1.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { child as _child, createFor as _createFor, setText as _setText, template as _template, toDisplayString as _toDisplayString } from "vue";
6 | const t0 = _template("
");
7 | (() => {
8 | let _selector0_0;
9 | const n0 = _createFor(() => rows, (_for_item0) => {
10 | const n2 = t0();
11 | const x2 = _child(n2);
12 | _selector0_0(() => {
13 | _setText(x2, _toDisplayString(selected === _for_item0.value.id ? "danger" : ""));
14 | });
15 | return n2;
16 | }, (row) => row.id, void 0, ({ createSelector }) => {
17 | _selector0_0 = createSelector(() => selected);
18 | });
19 | return n0;
20 | })();
21 |
--------------------------------------------------------------------------------
/packages/eslint/src/rules/jsx-sort-props/types.ts:
--------------------------------------------------------------------------------
1 | export interface JsxSortPropsSchema0 {
2 | callbacksLast?: boolean
3 | shorthandFirst?: boolean
4 | shorthandLast?: boolean
5 | multiline?: 'ignore' | 'first' | 'last'
6 | ignoreCase?: boolean
7 | noSortAlphabetically?: boolean
8 | reservedFirst?: string[] | boolean
9 | reservedLast?: string[]
10 | locale?: string
11 | }
12 |
13 | export type JsxSortPropsRuleOptions = [JsxSortPropsSchema0?]
14 |
15 | export type RuleOptions = JsxSortPropsRuleOptions
16 | export type MessageIds =
17 | | 'listIsEmpty'
18 | | 'listReservedPropsFirst'
19 | | 'listReservedPropsLast'
20 | | 'listCallbacksLast'
21 | | 'listShorthandFirst'
22 | | 'listShorthandLast'
23 | | 'listMultilineFirst'
24 | | 'listMultilineLast'
25 | | 'sortPropsByAlpha'
26 |
--------------------------------------------------------------------------------
/packages/compiler-rs/crates/vapor/src/transform/v_once.rs:
--------------------------------------------------------------------------------
1 | use common::directive::find_prop;
2 | use napi::Either;
3 | use oxc_ast::ast::JSXChild;
4 |
5 | use crate::{
6 | ir::index::BlockIRNode,
7 | transform::{ContextNode, TransformContext},
8 | };
9 |
10 | /// # SAFETY
11 | pub unsafe fn transform_v_once<'a>(
12 | context_node: *mut ContextNode<'a>,
13 | context: &'a TransformContext<'a>,
14 | _: &'a mut BlockIRNode<'a>,
15 | _: &'a mut ContextNode<'a>,
16 | ) -> Option> {
17 | let Either::B(node) = (unsafe { &*context_node }) else {
18 | return None;
19 | };
20 |
21 | if let JSXChild::Element(node) = &node
22 | && find_prop(node, Either::A(String::from("v-once"))).is_some()
23 | {
24 | *context.in_v_once.borrow_mut() = true;
25 | }
26 | None
27 | }
28 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_text__expression_conditional.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_text.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes, createNodes as _createNodes } from "vue-jsx-vapor";
6 | import { child as _child, createIf as _createIf, template as _template } from "vue";
7 | const t0 = _template(" ");
8 | const t1 = _template("fail
");
9 | (() => {
10 | const n0 = _createIf(() => ok, () => {
11 | const n2 = t0();
12 | const x2 = _child(n2);
13 | _setNodes(x2, () => msg);
14 | return n2;
15 | }, () => _createIf(() => fail, () => {
16 | const n4 = t1();
17 | return n4;
18 | }, () => {
19 | const n6 = _createNodes(null);
20 | return n6;
21 | }));
22 | return n0;
23 | })();
24 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_once__execution_order.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_once.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, next as _next, nthChild as _nthChild, setProp as _setProp, template as _template } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n4 = t0();
10 | const n0 = _child(n4);
11 | const n1 = _next(n0);
12 | const n2 = _nthChild(n4, 3);
13 | const n3 = _next(n2);
14 | const x0 = _child(n0);
15 | _setNodes(x0, foo);
16 | _setNodes(n1, () => bar);
17 | _setNodes(n2, () => baz);
18 | _setProp(n3, "foo", true);
19 | const x3 = _child(n3);
20 | _setNodes(x3, () => foo);
21 | return n4;
22 | })();
23 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_once__with_conditional_expression.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_once.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, createIf as _createIf, setInsertionState as _setInsertionState, template as _template } from "vue";
7 | const t0 = _template(" ");
8 | const t1 = _template("fail
");
9 | const t2 = _template("", true);
10 | (() => {
11 | const n5 = t2();
12 | _setInsertionState(n5);
13 | const n0 = _createIf(() => ok, () => {
14 | const n2 = t0();
15 | const x2 = _child(n2);
16 | _setNodes(x2, msg);
17 | return n2;
18 | }, () => {
19 | const n4 = t1();
20 | return n4;
21 | }, true);
22 | return n5;
23 | })();
24 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/transform/snapshots/r#mod__transform__hmr__exports_with_define_component.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/transform/hmr.rs
3 | expression: code
4 | ---
5 | export const Comp = defineComponent(() => {});
6 | const __default__ = defineVaporComponent(() => {});
7 | export default __default__;
8 | Comp.__hmrId = "8ed58763ca2bbfd5";
9 | __VUE_HMR_RUNTIME__.createRecord("8ed58763ca2bbfd5", Comp);
10 | __default__.__hmrId = "52164bac249078a3";
11 | __VUE_HMR_RUNTIME__.createRecord("52164bac249078a3", __default__);
12 | if (import.meta.hot) import.meta.hot.accept((mod) => {
13 | __VUE_HMR_RUNTIME__[typeof mod.Comp === "function" ? "rerender" : "reload"](mod.Comp.__hmrId, mod.Comp);
14 | __VUE_HMR_RUNTIME__[typeof mod.default === "function" ? "rerender" : "reload"](mod.default.__hmrId, mod.default);
15 | });
16 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_bind__with_constant_value.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_bind.rs
3 | expression: code
4 | ---
5 | import { setProp as _setProp, template as _template } from "vue";
6 | const t0 = _template("", true);
7 | (() => {
8 | const n0 = t0();
9 | _setProp(n0, "a", void 0);
10 | _setProp(n0, "b", 1 > 2);
11 | _setProp(n0, "c", 1 + 2);
12 | _setProp(n0, "d", 1 ? 2 : 3);
13 | _setProp(n0, "i", true);
14 | _setProp(n0, "j", null);
15 | _setProp(n0, "l", { foo: 1 });
16 | _setProp(n0, "n", { ...{ foo: 1 } });
17 | _setProp(n0, "o", [
18 | 1,
19 | ,
20 | 3
21 | ]);
22 | _setProp(n0, "p", [1, ...[2, 3]]);
23 | _setProp(n0, "q", [1, 2]);
24 | _setProp(n0, "r", /\s+/);
25 | return n0;
26 | })();
27 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_children__children_sibling_references.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_children.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, next as _next, renderEffect as _renderEffect, setProp as _setProp, template as _template } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n3 = t0();
10 | const n0 = _child(n3);
11 | const n1 = _next(n0);
12 | const n2 = _next(n1);
13 | const x0 = _child(n0);
14 | _setNodes(x0, () => first);
15 | _setNodes(n1, "123 ", () => second, " 456 ", () => foo);
16 | const x2 = _child(n2);
17 | _setNodes(x2, () => forth);
18 | _renderEffect(() => _setProp(n3, "id", id));
19 | return n3;
20 | })();
21 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_if__v_if_v_if_or_v_elses.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_if.rs
3 | expression: code
4 | ---
5 | import { createIf as _createIf, setInsertionState as _setInsertionState, template as _template } from "vue";
6 | const t0 = _template("foo");
7 | const t1 = _template("bar");
8 | const t2 = _template("baz");
9 | const t3 = _template("", true);
10 | (() => {
11 | const n8 = t3();
12 | _setInsertionState(n8);
13 | const n0 = _createIf(() => "foo", () => {
14 | const n2 = t0();
15 | return n2;
16 | });
17 | _setInsertionState(n8);
18 | const n3 = _createIf(() => "bar", () => {
19 | const n5 = t1();
20 | return n5;
21 | }, () => {
22 | const n7 = t2();
23 | return n7;
24 | });
25 | return n8;
26 | })();
27 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__nested_v_for.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, createFor as _createFor, setInsertionState as _setInsertionState, template as _template } from "vue";
7 | const t0 = _template(" ");
8 | const t1 = _template("");
9 | (() => {
10 | const n0 = _createFor(() => list, (_for_item0) => {
11 | const n5 = t1();
12 | _setInsertionState(n5);
13 | const n2 = _createFor(() => _for_item0.value, (_for_item1) => {
14 | const n4 = t0();
15 | const x4 = _child(n4);
16 | _setNodes(x4, () => _for_item1.value + _for_item0.value);
17 | return n4;
18 | }, void 0, 1);
19 | return n5;
20 | });
21 | return n0;
22 | })();
23 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/core/vue-jsx.ts:
--------------------------------------------------------------------------------
1 | import { transformSync } from '@babel/core'
2 | // @ts-ignore missing type
3 | import babelTypescript from '@babel/plugin-transform-typescript'
4 | import jsx from '@vue/babel-plugin-jsx'
5 |
6 | export function transformVueJsx(
7 | code: string,
8 | id: string,
9 | needSourceMap = false,
10 | ) {
11 | const result = transformSync(code, {
12 | plugins: [
13 | jsx,
14 | ...(id.endsWith('.tsx')
15 | ? [[babelTypescript, { isTSX: true, allowExtensions: true }]]
16 | : []),
17 | ],
18 | filename: id,
19 | sourceMaps: needSourceMap,
20 | sourceFileName: id,
21 | babelrc: false,
22 | configFile: false,
23 | })
24 | if (result?.code && result.code !== code) {
25 | return {
26 | code: result.code,
27 | map: result.map,
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/transform/snapshots/r#mod__transform__interop__basic.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/transform/interop.rs
3 | expression: code
4 | ---
5 | import { createNodes as _createNodes } from "vue-jsx-vapor";
6 | import { template as _template } from "vue";
7 | const t0 = _template("", true);
8 | const t1 = _template("");
9 | const t2 = _template("", true);
10 | const A = defineComponent(() => {
11 | defineVaporComponent(() => (() => {
12 | const n0 = t0();
13 | return n0;
14 | })());
15 | return () => ;
16 | });
17 | const B = defineVaporComponent(() => {
18 | const C = defineComponent(() => );
19 | const D = (() => {
20 | const n2 = t1();
21 | const n0 = _createNodes(() => foo, " ");
22 | return [n0, n2];
23 | })();
24 | return (() => {
25 | const n0 = t2();
26 | return n0;
27 | })();
28 | });
29 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_children__efficient_traversal.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_children.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, next as _next, template as _template } from "vue";
7 | const t0 = _template("", true);
8 | (() => {
9 | const n3 = t0();
10 | const p0 = _next(_child(n3));
11 | const p1 = _next(p0);
12 | const p2 = _next(p1);
13 | const n2 = _child(p2);
14 | const n1 = _child(p1);
15 | const n0 = _child(p0);
16 | const x0 = _child(n0);
17 | _setNodes(x0, () => ({ msg }));
18 | const x1 = _child(n1);
19 | _setNodes(x1, () => ({ msg }));
20 | const x2 = _child(n2);
21 | _setNodes(x2, () => ({ msg }));
22 | return n3;
23 | })();
24 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_template_ref__function_ref.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_template_ref.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { createTemplateRefSetter as _createTemplateRefSetter, renderEffect as _renderEffect, template as _template } from "vue";
7 | const t0 = _template("");
8 | (() => {
9 | const _setTemplateRef = _createTemplateRefSetter();
10 | const n3 = _createComponent(Comp, null, { default: (_slotProps0) => {
11 | const n1 = t0();
12 | let r1;
13 | _renderEffect(() => r1 = _setTemplateRef(n1, (bar) => {
14 | foo.value = bar;
15 | ({baz: _slotProps0.baz, bar: _slotProps0.baz} = bar);
16 | console.log(foo.value, _slotProps0.baz);
17 | }, r1));
18 | return n1;
19 | } }, true);
20 | return n3;
21 | })();
22 |
--------------------------------------------------------------------------------
/packages/compiler-rs/crates/vapor/src/generate/html.rs:
--------------------------------------------------------------------------------
1 | use oxc_ast::NONE;
2 | use oxc_ast::ast::Statement;
3 | use oxc_span::SPAN;
4 |
5 | use crate::generate::CodegenContext;
6 | use crate::generate::expression::gen_expression;
7 | use crate::ir::index::SetHtmlIRNode;
8 |
9 | pub fn gen_set_html<'a>(oper: SetHtmlIRNode<'a>, context: &'a CodegenContext<'a>) -> Statement<'a> {
10 | let ast = &context.ast;
11 | let SetHtmlIRNode { value, element, .. } = oper;
12 |
13 | ast.statement_expression(
14 | SPAN,
15 | ast.expression_call(
16 | SPAN,
17 | ast.expression_identifier(SPAN, ast.atom(&context.helper("setHtml"))),
18 | NONE,
19 | ast.vec_from_array([
20 | ast
21 | .expression_identifier(SPAN, ast.atom(&format!("n{element}")))
22 | .into(),
23 | gen_expression(value, context, None, None).into(),
24 | ]),
25 | false,
26 | ),
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/packages/macros/tests/fixtures/define-style.tsx:
--------------------------------------------------------------------------------
1 | import { defineComponent, ref } from 'vue'
2 |
3 | export const Comp = () => {
4 | const color = ref('red')
5 | defineStyle(`
6 | .foo {
7 | color: ${color.value};
8 | }
9 | `)
10 | return foo
11 | }
12 |
13 | export default defineComponent(() => {
14 | const color = ref('red')
15 | const styles = defineStyle.scss(`
16 | .bar {
17 | color: ${color.value};
18 | .bar-baz {
19 | background: red;
20 | }
21 | }
22 | `)
23 | const { default: Default, ...slots } = defineSlots()
24 | return () => (
25 | <>
26 | foo
27 |
28 | bar
29 |
30 |
31 |
32 |
33 | >
34 | )
35 | })
36 |
37 | defineStyle.scss(`
38 | .bar {
39 | color: red;
40 | }
41 | `)
42 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__custom_directive__component.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/custom_directive.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { createIf as _createIf, setInsertionState as _setInsertionState, template as _template, withVaporDirectives as _withVaporDirectives } from "vue";
7 | const t0 = _template("");
8 | (() => {
9 | const n0 = _createComponent(Comp, null, { default: () => {
10 | const n2 = _createIf(() => true, () => {
11 | const n5 = t0();
12 | _setInsertionState(n5);
13 | const n4 = _createComponent(Bar);
14 | _withVaporDirectives(n4, [[
15 | vHello,
16 | void 0,
17 | void 0,
18 | { world: true }
19 | ]]);
20 | return n5;
21 | }, null, true);
22 | return n2;
23 | } }, true);
24 | _withVaporDirectives(n0, [[vTest]]);
25 | return n0;
26 | })();
27 |
--------------------------------------------------------------------------------
/eslint.config.ts:
--------------------------------------------------------------------------------
1 | import { sxzz } from '@sxzz/eslint-config'
2 | import vueJsxVapor from './packages/eslint/src/index'
3 |
4 | export default [
5 | {
6 | ignores: ['**/wasi-worker**', '**/compiler-rs.wasi**'],
7 | },
8 | ...(await sxzz()
9 | .removeRules(
10 | 'unicorn/filename-case',
11 | 'import/no-default-export',
12 | 'unicorn/no-new-array',
13 | 'unicorn/prefer-dom-node-remove',
14 | 'unused-imports/no-unused-imports',
15 | '@eslint-community/eslint-comments/no-unlimited-disable',
16 | )
17 | .append([
18 | {
19 | name: 'docs',
20 | files: ['**/*.md/*.tsx'],
21 | rules: {
22 | 'no-var': 'off',
23 | 'no-mutable-exports': 'off',
24 | 'no-duplicate-imports': 'off',
25 | 'import/first': 'off',
26 | 'unused-imports/no-unused-vars': 'off',
27 | },
28 | },
29 | ])),
30 | vueJsxVapor({
31 | ignores: ['**/docs/**'],
32 | }),
33 | ]
34 |
--------------------------------------------------------------------------------
/packages/runtime/src/block.ts:
--------------------------------------------------------------------------------
1 | import { createTextNode, isFragment, isVaporComponent, type Block } from 'vue'
2 |
3 | type NodeChildAtom = Block | string | number | boolean | null | undefined | void
4 |
5 | export type NodeArrayChildren = Array
6 |
7 | export type NodeChild = NodeChildAtom | NodeArrayChildren
8 |
9 | export function normalizeNode(node: NodeChild): Block {
10 | if (node == null || typeof node === 'boolean') {
11 | return document.createComment('')
12 | } else if (Array.isArray(node) && node.length) {
13 | return node.map(normalizeNode)
14 | } else if (isBlock(node)) {
15 | return node
16 | } else {
17 | // strings and numbers
18 | return createTextNode(String(node))
19 | }
20 | }
21 |
22 | export function isBlock(val: NonNullable): val is Block {
23 | return (
24 | val instanceof Node ||
25 | Array.isArray(val) ||
26 | isVaporComponent(val) ||
27 | isFragment(val)
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_for__identifiers.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_for.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes } from "vue-jsx-vapor";
6 | import { child as _child, createFor as _createFor, renderEffect as _renderEffect, setProp as _setProp, template as _template } from "vue";
7 | const t0 = _template("
");
8 | (() => {
9 | const n0 = _createFor(() => items, (_for_item0, _for_key0) => {
10 | const n2 = t0();
11 | const x2 = _child(n2);
12 | _setNodes(x2, () => ((item) => {
13 | let index = 1;
14 | return [item, index];
15 | })(_for_item0.value), () => (() => {
16 | switch (_for_item0.value) {
17 | case _for_key0.value: {
18 | let item = "";
19 | return `${[item, _for_key0.value]}`;
20 | }
21 | }
22 | })());
23 | _renderEffect(() => _setProp(n2, "id", _for_key0.value));
24 | return n2;
25 | });
26 | return n0;
27 | })();
28 |
--------------------------------------------------------------------------------
/docs/zh/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | # https://vitepress.dev/reference/default-theme-home-page
3 | layout: home
4 |
5 | hero:
6 | name: "Vue JSX Vapor"
7 | text: "类型安全、高性能、更舒适的开发体验"
8 | tagline: Vue JSX 的 Vapor 模式
9 | image:
10 | src: /logo.svg
11 | alt: Vue JSX Vapor
12 | actions:
13 | - theme: brand
14 | text: 快速上手
15 | link: /zh/introduction/getting-started
16 | - theme: alt
17 | text: 功能特性
18 | link: /zh/features/directives
19 |
20 | features:
21 | - icon: ⚒️ ️
22 | title: 指令
23 | details: 支持 Vue 的所有内置指令。
24 | - icon: ✨
25 | title: 宏
26 | details: 支持 Vue 的大部分宏,对 JSX 友好。
27 | - icon: 🦾
28 | title: 类型安全
29 | details: 通过安装 TS Macro (VSCode 插件) 提供 Volar 插件支持。
30 | - icon: ⚡️
31 | title: 高性能
32 | details: 拥有与 Vue Vapor 同等的性能!
33 | - icon: 🦀
34 | title: Rust 编译器
35 | details: 基于 Oxc,相比于 Babel 插件 性能提升了20倍。
36 | - icon: ⚙️
37 | title: ESLint
38 | details: 提供 ESLint 插件为 vue-jsx-vapor 自动格式化代码。
39 | ---
40 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_text__expression_map.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_text.rs
3 | expression: code
4 | ---
5 | import { setNodes as _setNodes, createNodes as _createNodes } from "vue-jsx-vapor";
6 | import { child as _child, template as _template } from "vue";
7 | const t0 = _template("1
", true);
8 | const t1 = _template(" ", true);
9 | const t2 = _template("
", true);
10 | (() => {
11 | const n0 = _createNodes(() => Array.from({ length: count.value }).map((_, index) => {
12 | if (index > 1) {
13 | return (() => {
14 | const n0 = t0();
15 | return n0;
16 | })();
17 | } else {
18 | return [(() => {
19 | const n0 = t1();
20 | const x0 = _child(n0);
21 | _setNodes(x0, "(", () => index, ") lt 1");
22 | return n0;
23 | })(), (() => {
24 | const n0 = t2();
25 | return n0;
26 | })()];
27 | }
28 | }));
29 | return n0;
30 | })();
31 |
--------------------------------------------------------------------------------
/packages/compiler-rs/wasi-worker-browser.mjs:
--------------------------------------------------------------------------------
1 | import { instantiateNapiModuleSync, MessageHandler, WASI } from '@napi-rs/wasm-runtime'
2 |
3 | const handler = new MessageHandler({
4 | onLoad({ wasmModule, wasmMemory }) {
5 | const wasi = new WASI({
6 | print: function () {
7 | // eslint-disable-next-line no-console
8 | console.log.apply(console, arguments)
9 | },
10 | printErr: function() {
11 | // eslint-disable-next-line no-console
12 | console.error.apply(console, arguments)
13 | },
14 | })
15 | return instantiateNapiModuleSync(wasmModule, {
16 | childThread: true,
17 | wasi,
18 | overwriteImports(importObject) {
19 | importObject.env = {
20 | ...importObject.env,
21 | ...importObject.napi,
22 | ...importObject.emnapi,
23 | memory: wasmMemory,
24 | }
25 | },
26 | })
27 | },
28 | })
29 |
30 | globalThis.onmessage = function (e) {
31 | handler.handle(e)
32 | }
33 |
--------------------------------------------------------------------------------
/packages/eslint/test/define-style.spec.ts:
--------------------------------------------------------------------------------
1 | import { createRuleTester } from 'eslint-vitest-rule-tester'
2 | import { describe, expect, it } from 'vitest'
3 | import _defineStyle from '../src/rules/define-style'
4 |
5 | describe('define-style', () => {
6 | const { invalid } = createRuleTester({
7 | name: 'define-style',
8 | rule: _defineStyle,
9 | })
10 |
11 | it('basic', async () => {
12 | const { result } = await invalid({
13 | code: `
14 | defineStyle(\` .foo { color: red; } \`)
15 | `,
16 | errors: ['define-style'],
17 | })
18 | expect(result.output).toMatchSnapshot()
19 | })
20 |
21 | it('syntax error', async () => {
22 | const { result } = await invalid({
23 | code: `
24 | defineStyle(\`
25 | .foo {
26 | color: red
27 | background: blue;
28 | }
29 | \`)
30 | `,
31 | errors: ['define-style-syntax-error'],
32 | })
33 | expect(result.output).toMatchSnapshot()
34 | })
35 | })
36 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/volar.ts:
--------------------------------------------------------------------------------
1 | import jsxMacros from '@vue-jsx-vapor/macros/volar'
2 | import jsxDirective from '@vue-macros/volar/jsx-directive'
3 | import jsxRef from '@vue-macros/volar/jsx-ref'
4 | import { createPlugin, type PluginReturn } from 'ts-macro'
5 | import jsxElement from './volar/jsx-element'
6 | import type { Options } from './options'
7 |
8 | const plugin: PluginReturn = createPlugin(
9 | (ctx, options = ctx.vueCompilerOptions?.['vue-jsx-vapor']) => {
10 | return [
11 | jsxDirective()(ctx),
12 | options?.ref === false
13 | ? []
14 | : jsxRef(options?.ref === true ? undefined : options?.ref)(ctx),
15 | options?.macros === false
16 | ? []
17 | : options?.macros
18 | ? jsxMacros(options.macros === true ? undefined : options.macros)(ctx)
19 | : [],
20 | options?.interop ? [] : jsxElement()(ctx),
21 | ].flat()
22 | },
23 | )
24 |
25 | export default plugin
26 | export { plugin as 'module.exports' }
27 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/transform_template_ref.rs:
--------------------------------------------------------------------------------
1 | use compiler_rs::transform;
2 | use insta::assert_snapshot;
3 |
4 | #[test]
5 | fn static_ref() {
6 | let code = transform("", None).code;
7 | assert_snapshot!(code);
8 | }
9 |
10 | #[test]
11 | fn dynamic_ref() {
12 | let code = transform("", None).code;
13 | assert_snapshot!(code);
14 | }
15 |
16 | #[test]
17 | fn function_ref() {
18 | let code = transform(
19 | "
20 | {
21 | foo.value = bar
22 | ;({ baz, bar: baz } = bar)
23 | console.log(foo.value, baz)
24 | }} />
25 | ",
26 | None,
27 | )
28 | .code;
29 | assert_snapshot!(code);
30 | }
31 |
32 | #[test]
33 | fn ref_v_if() {
34 | let code = transform("
", None).code;
35 | assert_snapshot!(code);
36 | }
37 |
38 | #[test]
39 | fn ref_v_for() {
40 | let code = transform("
", None).code;
41 | assert_snapshot!(code);
42 | }
43 |
--------------------------------------------------------------------------------
/packages/eslint/src/index.ts:
--------------------------------------------------------------------------------
1 | import rules, { type Rules } from './rules'
2 | import type { Linter } from 'eslint'
3 |
4 | export const plugins = {
5 | 'vue-jsx-vapor': {
6 | rules,
7 | },
8 | }
9 |
10 | export { rules, type Rules }
11 |
12 | export default ({ rules = {}, ...options }: Linter.Config
= {}) => ({
13 | name: 'vue-jsx-vapor',
14 | plugins,
15 | rules: {
16 | 'style/jsx-sort-props': 'off',
17 | 'react/jsx-sort-props': 'off',
18 | 'vue-jsx-vapor/jsx-sort-props': rules['vue-jsx-vapor/jsx-sort-props'] || [
19 | 'warn',
20 | {
21 | callbacksLast: true,
22 | shorthandFirst: true,
23 | reservedFirst: [
24 | 'v-if',
25 | 'v-else-if',
26 | 'v-else',
27 | 'v-for',
28 | 'key',
29 | 'ref',
30 | 'v-model',
31 | ],
32 | reservedLast: ['v-slot', 'v-slots', 'v-text', 'v-html'],
33 | },
34 | ],
35 | 'vue-jsx-vapor/define-style': rules['vue-jsx-vapor/define-style'] || 'warn',
36 | } satisfies Rules & Record,
37 | ...options,
38 | })
39 |
--------------------------------------------------------------------------------
/playground/src/element.tsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable unused-imports/no-unused-vars */
2 | /* eslint-disable @typescript-eslint/no-unused-expressions */
3 | /* eslint-disable @typescript-eslint/consistent-type-assertions */
4 | import { computed, defineComponent, defineVaporComponent } from 'vue'
5 |
6 | const Comp = () => {
7 | const A =
8 | A.href = '#foo'
9 | return A
10 | }
11 | const comp =
12 | comp.block.href
13 |
14 | const VaporComp = defineVaporComponent((props: { id: number }) => {
15 | defineSlots({
16 | default: (props: { id: 1 }) => [],
17 | })
18 | defineExpose({
19 | id: computed(() => 1),
20 | })
21 | return {props.id}
22 | })
23 | const vaporComp =
24 | vaporComp.props.id
25 | vaporComp.exposeProxy?.id === ({} as number)
26 | vaporComp.block.style
27 |
28 | const VDomComp = defineComponent((props: { id: number }) => {
29 | defineSlots({
30 | default: (props: { id: 1 }) => ,
31 | })
32 | return () => {props.id}
33 | })
34 | const vdompComp =
35 | vdompComp.props
36 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__transform_children__next_child_and_nthchild_should_be_above_the_set_insertion_state.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/transform_children.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { child as _child, createIf as _createIf, next as _next, nthChild as _nthChild, renderEffect as _renderEffect, setInsertionState as _setInsertionState, setProp as _setProp, template as _template } from "vue";
7 | const t0 = _template("");
8 | const t1 = _template("", true);
9 | (() => {
10 | const n6 = t1();
11 | const n5 = _next(_child(n6));
12 | const n7 = _nthChild(n6, 3);
13 | const p0 = _next(n7);
14 | const n4 = _child(p0);
15 | _setInsertionState(n6, n5);
16 | const n0 = _createComponent(Comp);
17 | _setInsertionState(n6, n7);
18 | const n1 = _createIf(() => true, () => {
19 | const n3 = t0();
20 | return n3;
21 | }, null, true);
22 | _renderEffect(() => _setProp(n4, "disabled", foo));
23 | return n6;
24 | })();
25 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/snapshots/r#mod__vapor__v_slot__dynamic_slots_name_with_v_if_and_v_else_if.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/vapor/v_slot.rs
3 | expression: code
4 | ---
5 | import { createComponent as _createComponent } from "vue-jsx-vapor";
6 | import { template as _template } from "vue";
7 | const t0 = _template("condition slot");
8 | const t1 = _template("another condition");
9 | const t2 = _template("other condition");
10 | const t3 = _template("else condition");
11 | (() => {
12 | const n13 = _createComponent(Comp, null, { $: [() => condition ? {
13 | name: "condition",
14 | fn: () => {
15 | const n1 = t0();
16 | return n1;
17 | }
18 | } : anotherCondition ? {
19 | name: "condition",
20 | fn: (_slotProps0) => {
21 | const n4 = t1();
22 | return n4;
23 | }
24 | } : otherCondition ? {
25 | name: "condition",
26 | fn: () => {
27 | const n7 = t2();
28 | return n7;
29 | }
30 | } : {
31 | name: "condition",
32 | fn: () => {
33 | const n10 = t3();
34 | return n10;
35 | }
36 | }] }, true);
37 | return n13;
38 | })();
39 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - packages/*
3 | - playground
4 | - docs
5 | - benchmark
6 |
7 | defines:
8 | - &babel ^7.28.4
9 | - &vue-macros ^3.0.1
10 | - &ts-macro ^0.3.6
11 | - &vue 3.6.0-alpha.2
12 |
13 | catalog:
14 | '@babel/core': *babel
15 | '@babel/parser': *babel
16 | '@babel/plugin-syntax-jsx': ^7.27.1
17 | '@babel/plugin-transform-typescript': ^7.28.0
18 | '@babel/traverse': *babel
19 | '@babel/types': *babel
20 | '@types/babel__core': ^7.20.5
21 |
22 | '@nuxt/kit': ^3.19.2
23 | '@nuxt/schema': ^3.19.2
24 |
25 | '@vue/compiler-sfc': *vue
26 | '@vue/shared': *vue
27 |
28 | '@vue-macros/common': *vue-macros
29 | '@vue-macros/define-render': *vue-macros
30 | '@vue-macros/jsx-directive': *vue-macros
31 | '@vue-macros/test-utils': *vue-macros
32 | '@vue-macros/volar': *vue-macros
33 |
34 | '@ts-macro/tsc': *ts-macro
35 | '@types/hash-sum': ^1.0.2
36 | ast-kit: ^2.1.2
37 | hash-sum: ^2.0.0
38 | source-map-js: ^1.2.1
39 | ts-macro: *ts-macro
40 | unplugin: ^2.3.10
41 | unplugin-utils: ^0.2.5
42 | vite: ^7.1.6
43 | vitest: ^3.2.4
44 | vue: *vue
45 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 zhiyuanzmj
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/runtime/src/helpers.ts:
--------------------------------------------------------------------------------
1 | import { proxyRefs, toRefs, useAttrs, type GenericComponentInstance } from 'vue'
2 | import * as Vue from 'vue'
3 |
4 | export function getCurrentInstance(): GenericComponentInstance | null {
5 | // @ts-ignore
6 | return Vue.currentInstance || Vue.getCurrentInstance()
7 | }
8 |
9 | /**
10 | * Returns the props of the current component instance.
11 | *
12 | * @example
13 | * ```tsx
14 | * import { useProps } from 'vue-jsx-vapor'
15 | *
16 | * defineComponent(({ foo = '' })=>{
17 | * const props = useProps() // { foo: '' }
18 | * })
19 | * ```
20 | */
21 | export function useProps() {
22 | const i = getCurrentInstance()
23 | return i!.props
24 | }
25 |
26 | /**
27 | * Returns the merged props and attrs of the current component.\
28 | * Equivalent to `useProps()` + `useAttrs()`.
29 | *
30 | * @example
31 | * ```tsx
32 | * import { useFullProps } from 'vue-jsx-vapor'
33 | *
34 | * defineComponent((props) => {
35 | * const fullProps = useFullProps() // = useAttrs() + useProps()
36 | * })
37 | */
38 | export function useFullProps() {
39 | return proxyRefs({
40 | ...toRefs(useProps()),
41 | ...toRefs(useAttrs()),
42 | })
43 | }
44 |
--------------------------------------------------------------------------------
/playground/src/slot.tsx:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | const Comp = (props: { foo: string }, { slots }) => {
4 | return (
5 | <>
6 | {slots.default ? (
7 |
8 | ) : (
9 | default slot
10 | )}
11 | >
12 | )
13 | }
14 |
15 | const slots = {
16 | default: (scope) => {scope.foo}
,
17 | }
18 |
19 | // eslint-disable-next-line unused-imports/no-unused-vars
20 | const slotName = ref('default')
21 | export default () => {
22 | const foo = ref('foo')
23 | return (
24 | <>
25 |
26 |
27 |
36 |
37 |
43 |
44 | >
45 | )
46 | }
47 |
--------------------------------------------------------------------------------
/packages/compiler-rs/benches/bench.rs:
--------------------------------------------------------------------------------
1 | use compiler_rs::transform;
2 | use criterion::{Criterion, criterion_group, criterion_main};
3 |
4 | fn bench_compile(b: &mut Criterion) {
5 | b.bench_function("compile", |b| {
6 | b.iter(|| {
7 | transform(
8 | &format!(
9 | "<>{}>",
10 | " alert(1)}
14 | v-show={true}
15 | v-model={foo}
16 | v-once
17 | v-slot={foo}
18 | >
19 |
24 | {item}
25 |
26 |
27 | bar
28 |
29 |
30 | default
31 |
32 | {bar}
33 |
34 |
35 | "
36 | .repeat(12)
37 | ),
38 | None,
39 | )
40 | })
41 | });
42 | }
43 |
44 | criterion_group!(benches, bench_compile);
45 | criterion_main!(benches);
46 |
--------------------------------------------------------------------------------
/packages/macros/src/volar.ts:
--------------------------------------------------------------------------------
1 | import { createFilter, REGEX_VUE_SFC } from '@vue-macros/common'
2 | import { createPlugin, type PluginReturn } from 'ts-macro'
3 | import { resolveOptions, type Options } from './options'
4 | import { getGlobalTypes, getRootMap, transformJsxMacros } from './volar/index'
5 |
6 | const plugin: PluginReturn = createPlugin(
7 | ({ ts }, userOptions = {}) => {
8 | const resolvedOptions = resolveOptions(userOptions!)
9 | ;(resolvedOptions.include as any[]).push(REGEX_VUE_SFC)
10 | const filter = createFilter(resolvedOptions)
11 |
12 | return {
13 | name: '@vue-jsx-vapor/macros',
14 | resolveVirtualCode(virtualCode) {
15 | const { filePath, codes } = virtualCode
16 | if (!filter(filePath)) return
17 |
18 | const options = {
19 | ts,
20 | ...virtualCode,
21 | ...resolvedOptions,
22 | }
23 | const rootMap = getRootMap(options)
24 | if (rootMap.size) {
25 | transformJsxMacros(rootMap, options)
26 | }
27 | codes.push(getGlobalTypes(rootMap, options))
28 | },
29 | }
30 | },
31 | )
32 | export default plugin
33 | export { plugin as 'module.exports' }
34 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/v_text.rs:
--------------------------------------------------------------------------------
1 | use std::cell::RefCell;
2 |
3 | use common::{error::ErrorCodes, options::TransformOptions};
4 | use compiler_rs::transform;
5 | use insta::assert_snapshot;
6 |
7 | #[test]
8 | fn should_convert_v_text_to_set_text() {
9 | let code = transform("", None).code;
10 | assert_snapshot!(code);
11 | }
12 |
13 | #[test]
14 | fn should_raise_error_and_ignore_children_when_v_text_is_present() {
15 | let error = RefCell::new(None);
16 | transform(
17 | "hello
",
18 | Some(TransformOptions {
19 | on_error: Box::new(|e, _| {
20 | *error.borrow_mut() = Some(e);
21 | }),
22 | ..Default::default()
23 | }),
24 | );
25 | assert_eq!(*error.borrow(), Some(ErrorCodes::VTextWithChildren));
26 | }
27 |
28 | #[test]
29 | fn should_raise_error_if_has_no_expression() {
30 | let error = RefCell::new(None);
31 | transform(
32 | "",
33 | Some(TransformOptions {
34 | on_error: Box::new(|e, _| {
35 | *error.borrow_mut() = Some(e);
36 | }),
37 | ..Default::default()
38 | }),
39 | );
40 | assert_eq!(*error.borrow(), Some(ErrorCodes::VTextNoExpression));
41 | }
42 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | # https://vitepress.dev/reference/default-theme-home-page
3 | layout: home
4 |
5 | hero:
6 | name: "Vue JSX Vapor"
7 | text: "Type-safe, Improve DX, High Performance"
8 | tagline: Vapor Mode of Vue JSX
9 | image:
10 | src: /logo.svg
11 | alt: Vue JSX Vapor
12 | actions:
13 | - theme: brand
14 | text: Get Started
15 | link: /introduction/getting-started
16 | - theme: alt
17 | text: Features
18 | link: /features/directives
19 |
20 | features:
21 | - icon: ⚒️ ️
22 | title: Directives
23 | details: Support all build-in directives of Vue.
24 | - icon: ✨
25 | title: Macros
26 | details: Support most macros of Vue, Friendly to JSX.
27 | - icon: 🦾
28 | title: Type Safe
29 | details: Provide Volar plugin support by install TS Macro (VSCode plugin).
30 | - icon: ⚡️
31 | title: High Performance
32 | details: It has the same performance as Vue Vapor!
33 | - icon: 🦀
34 | title: Compiler rewritten in Rust
35 | details: Based on Oxc, 20x performance improvement over Babel plugin.
36 | - icon: ⚙️
37 | title: ESLint
38 | details: Provide an ESLint plugin for vue-jsx-vapor to automatically format directives and macros.
39 | ---
40 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/v_html.rs:
--------------------------------------------------------------------------------
1 | use std::cell::RefCell;
2 |
3 | use common::{error::ErrorCodes, options::TransformOptions};
4 | use compiler_rs::transform;
5 | use insta::assert_snapshot;
6 |
7 | #[test]
8 | fn should_convert_v_html_to_inner_html() {
9 | let code = transform("", None).code;
10 | assert_snapshot!(code);
11 | }
12 |
13 | #[test]
14 | fn should_raise_error_and_ignore_children_when_v_html_is_present() {
15 | let error = RefCell::new(None);
16 | transform(
17 | "hello
",
18 | Some(TransformOptions {
19 | on_error: Box::new(|e, _| {
20 | *error.borrow_mut() = Some(e);
21 | }),
22 | ..Default::default()
23 | }),
24 | );
25 | assert_eq!(*error.borrow(), Some(ErrorCodes::VHtmlWithChildren));
26 | }
27 |
28 | #[test]
29 | fn should_raise_error_if_has_no_expression() {
30 | let error = RefCell::new(None);
31 | transform(
32 | "",
33 | Some(TransformOptions {
34 | on_error: Box::new(|e, _| {
35 | *error.borrow_mut() = Some(e);
36 | }),
37 | ..Default::default()
38 | }),
39 | );
40 | assert_eq!(*error.borrow(), Some(ErrorCodes::VHtmlNoExpression));
41 | }
42 |
--------------------------------------------------------------------------------
/packages/runtime/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@vue-jsx-vapor/runtime",
3 | "version": "3.0.4",
4 | "description": "Vue JSX Vapor Runtime",
5 | "type": "module",
6 | "keywords": [
7 | "vue",
8 | "jsx",
9 | "vapor",
10 | "runtime"
11 | ],
12 | "license": "MIT",
13 | "homepage": "https://github.com/vuejs/vue-jsx-vapor#readme",
14 | "bugs": {
15 | "url": "https://github.com/vuejs/vue-jsx-vapor/issues"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git+https://github.com/vuejs/vue-jsx-vapor.git"
20 | },
21 | "files": [
22 | "dist"
23 | ],
24 | "main": "dist/index.cjs",
25 | "module": "dist/index.js",
26 | "types": "dist/index.d.ts",
27 | "exports": {
28 | ".": {
29 | "types": "./dist/index.d.ts",
30 | "jsx-vapor-dev": "./src/index.ts",
31 | "require": "./dist/index.cjs",
32 | "import": "./dist/index.js"
33 | },
34 | "./*": "./*"
35 | },
36 | "scripts": {
37 | "build": "tsdown",
38 | "dev": "DEV=true tsdown",
39 | "release": "bumpp && npm publish",
40 | "test": "vitest"
41 | },
42 | "peerDependencies": {
43 | "vue": "^3.6.0-alpha.2"
44 | },
45 | "devDependencies": {
46 | "csstype": "^3.1.3"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/packages/compiler-rs/crates/vapor/src/transform/v_show.rs:
--------------------------------------------------------------------------------
1 | use napi::bindgen_prelude::Either16;
2 | use oxc_ast::ast::{JSXAttribute, JSXElement};
3 |
4 | use crate::{
5 | ir::index::{BlockIRNode, DirectiveIRNode},
6 | transform::{DirectiveTransformResult, TransformContext},
7 | };
8 | use common::{directive::resolve_directive, error::ErrorCodes, expression::SimpleExpressionNode};
9 |
10 | pub fn transform_v_show<'a>(
11 | _dir: &'a mut JSXAttribute<'a>,
12 | _: &JSXElement,
13 | context: &'a TransformContext<'a>,
14 | context_block: &'a mut BlockIRNode<'a>,
15 | ) -> Option> {
16 | let mut dir = resolve_directive(_dir, context.ir.borrow().source);
17 | if dir.exp.is_none() {
18 | context.options.on_error.as_ref()(ErrorCodes::VShowNoExpression, dir.loc);
19 | dir.exp = Some(SimpleExpressionNode::default())
20 | }
21 |
22 | let element = context.reference(&mut context_block.dynamic);
23 | context.register_operation(
24 | context_block,
25 | Either16::M(DirectiveIRNode {
26 | directive: true,
27 | element,
28 | dir,
29 | name: String::from("show"),
30 | builtin: Some(true),
31 | asset: None,
32 | model_type: None,
33 | }),
34 | None,
35 | );
36 | None
37 | }
38 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/transform/snapshots/r#mod__transform__hmr__exports.snap:
--------------------------------------------------------------------------------
1 | ---
2 | source: tests/transform/hmr.rs
3 | expression: code
4 | ---
5 | const Comp = () => {};
6 | function Comp1() {}
7 | export { Comp, Comp1 };
8 | export function Comp2() {}
9 | const __default__ = function() {};
10 | export default __default__;
11 | Comp.__hmrId = "8ed58763ca2bbfd5";
12 | __VUE_HMR_RUNTIME__.createRecord("8ed58763ca2bbfd5", Comp);
13 | Comp1.__hmrId = "f144a08cc37ed966";
14 | __VUE_HMR_RUNTIME__.createRecord("f144a08cc37ed966", Comp1);
15 | Comp2.__hmrId = "c36ea49ad2d3847e";
16 | __VUE_HMR_RUNTIME__.createRecord("c36ea49ad2d3847e", Comp2);
17 | __default__.__hmrId = "52164bac249078a3";
18 | __VUE_HMR_RUNTIME__.createRecord("52164bac249078a3", __default__);
19 | if (import.meta.hot) import.meta.hot.accept((mod) => {
20 | __VUE_HMR_RUNTIME__[typeof mod.Comp === "function" ? "rerender" : "reload"](mod.Comp.__hmrId, mod.Comp);
21 | __VUE_HMR_RUNTIME__[typeof mod.Comp1 === "function" ? "rerender" : "reload"](mod.Comp1.__hmrId, mod.Comp1);
22 | __VUE_HMR_RUNTIME__[typeof mod.Comp2 === "function" ? "rerender" : "reload"](mod.Comp2.__hmrId, mod.Comp2);
23 | __VUE_HMR_RUNTIME__[typeof mod.default === "function" ? "rerender" : "reload"](mod.default.__hmrId, mod.default);
24 | });
25 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/src/core/ssr.ts:
--------------------------------------------------------------------------------
1 | import type { ComponentOptions } from 'vue'
2 |
3 | export const ssrRegisterHelperId = '/__vue-jsx-ssr-register-helper'
4 | export const ssrRegisterHelperCode =
5 | `import { useSSRContext } from "vue"\n` +
6 | // the const here is just to work around the Bun bug where
7 | // Function.toString() isn't working as intended
8 | // https://github.com/oven-sh/bun/issues/9543
9 | `export const ssrRegisterHelper = ${ssrRegisterHelper.toString()}`
10 |
11 | /**
12 | * This function is serialized with toString() and evaluated as a virtual
13 | * module during SSR
14 | */
15 | function ssrRegisterHelper(comp: ComponentOptions, filename: string) {
16 | if (typeof comp === 'function') {
17 | // @ts-ignore
18 | comp.__setup = () => {
19 | // @ts-ignore
20 | const ssrContext = useSSRContext()
21 | ;(ssrContext.modules || (ssrContext.modules = new Set())).add(filename)
22 | }
23 | } else {
24 | const setup = comp.setup
25 | comp.setup = (props, ctx) => {
26 | // @ts-ignore
27 | const ssrContext = useSSRContext()
28 | ;(ssrContext.modules || (ssrContext.modules = new Set())).add(filename)
29 | if (setup) {
30 | return setup(props, ctx)
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/packages/eslint/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@vue-jsx-vapor/eslint",
3 | "version": "3.0.4",
4 | "description": "Vue JSX Vapor ESLint Plugin",
5 | "type": "module",
6 | "keywords": [
7 | "vue",
8 | "jsx",
9 | "vapor",
10 | "eslint"
11 | ],
12 | "license": "MIT",
13 | "homepage": "https://github.com/vuejs/vue-jsx-vapor#readme",
14 | "bugs": {
15 | "url": "https://github.com/vuejs/vue-jsx-vapor/issues"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git+https://github.com/vuejs/vue-jsx-vapor.git"
20 | },
21 | "files": [
22 | "dist"
23 | ],
24 | "main": "dist/index.cjs",
25 | "module": "dist/index.js",
26 | "types": "dist/index.d.ts",
27 | "exports": {
28 | ".": {
29 | "types": "./dist/index.d.ts",
30 | "jsx-vapor-dev": "./src/index.ts",
31 | "require": "./dist/index.cjs",
32 | "import": "./dist/index.js"
33 | },
34 | "./*": "./*"
35 | },
36 | "scripts": {
37 | "build": "tsdown",
38 | "dev": "DEV=true tsdown",
39 | "release": "bumpp && npm publish",
40 | "test": "vitest"
41 | },
42 | "dependencies": {
43 | "@prettier/sync": "^0.6.1"
44 | },
45 | "devDependencies": {
46 | "@typescript-eslint/utils": "^8.44.0",
47 | "eslint-vitest-rule-tester": "^2.2.1"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/packages/macros/src/core/helper/with-defaults.ts:
--------------------------------------------------------------------------------
1 | function resolveDefaultProps(paths: Record): any {
2 | const result: Record = {}
3 |
4 | for (const path of Object.keys(paths)) {
5 | const segments = path.split(/[.?[\]]/).filter(Boolean)
6 | let current = result
7 |
8 | for (let i = 0; i < segments.length; i++) {
9 | const segment = segments[i]
10 | if (i === segments.length - 1) {
11 | current[segment] = paths[path]
12 | } else {
13 | if (!current[segment]) {
14 | current[segment] = Number.isNaN(Number(segments[i + 1])) ? {} : []
15 | }
16 | current = current[segment]
17 | }
18 | }
19 | }
20 |
21 | return result
22 | }
23 |
24 | export function createPropsDefaultProxy(
25 | props: Record,
26 | defaults: Record,
27 | ): Record {
28 | const defaultProps = resolveDefaultProps(defaults)
29 | const result: Record = {}
30 |
31 | for (const key of [
32 | ...new Set([...Object.keys(props), ...Object.keys(defaultProps)]),
33 | ]) {
34 | Object.defineProperty(result, key, {
35 | enumerable: true,
36 | get: () => (props[key] === undefined ? defaultProps[key] : props[key]),
37 | })
38 | }
39 |
40 | return result
41 | }
42 |
--------------------------------------------------------------------------------
/playground/src/for.tsx:
--------------------------------------------------------------------------------
1 | import { ref } from 'vue'
2 |
3 | export default () => {
4 | const count = ref(3)
5 |
6 | const Arr = (
7 | <>
8 | {Array.from({ length: count.value }).map((_, index) => {
9 | if (index > 1) {
10 | return (
11 | <>
12 | ({index}) lg 1
13 | >
14 | )
15 | } else {
16 | return [({index}) lt 1,
]
17 | }
18 | })}
19 | >
20 | )
21 |
22 | const selected = ref(0)
23 | return (
24 |
25 |
26 |
27 |
28 |
32 |
33 |
47 |
48 |
49 | )
50 | }
51 |
52 | defineStyle(`
53 | .text-red {
54 | color: red;
55 | }
56 | `)
57 |
--------------------------------------------------------------------------------
/packages/compiler-rs/crates/vapor/src/transform/v_html.rs:
--------------------------------------------------------------------------------
1 | use common::{error::ErrorCodes, expression::SimpleExpressionNode};
2 | use napi::bindgen_prelude::{Either3, Either16};
3 | use oxc_ast::ast::{JSXAttribute, JSXElement};
4 |
5 | use crate::{
6 | ir::index::{BlockIRNode, SetHtmlIRNode},
7 | transform::{DirectiveTransformResult, TransformContext},
8 | };
9 |
10 | pub fn transform_v_html<'a>(
11 | dir: &'a mut JSXAttribute<'a>,
12 | node: &JSXElement,
13 | context: &'a TransformContext<'a>,
14 | context_block: &'a mut BlockIRNode<'a>,
15 | ) -> Option> {
16 | let exp = if let Some(value) = &mut dir.value {
17 | SimpleExpressionNode::new(Either3::C(value), context.ir.borrow().source)
18 | } else {
19 | context.options.on_error.as_ref()(ErrorCodes::VHtmlNoExpression, dir.span);
20 | SimpleExpressionNode::default()
21 | };
22 |
23 | if !node.children.is_empty() {
24 | context.options.on_error.as_ref()(ErrorCodes::VHtmlWithChildren, node.span);
25 | return None;
26 | }
27 |
28 | let element = context.reference(&mut context_block.dynamic);
29 | context.register_effect(
30 | context_block,
31 | context.is_operation(vec![&exp]),
32 | Either16::I(SetHtmlIRNode {
33 | set_html: true,
34 | element,
35 | value: exp,
36 | }),
37 | None,
38 | None,
39 | );
40 | None
41 | }
42 |
--------------------------------------------------------------------------------
/.github/workflows/unit-test.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | pull_request:
9 | branches:
10 | - main
11 |
12 | jobs:
13 | lint:
14 | runs-on: ubuntu-latest
15 | steps:
16 | - uses: actions/checkout@v3
17 | - name: Set node
18 | uses: actions/setup-node@v3
19 | with:
20 | node-version: 20.x
21 |
22 | - name: Setup
23 | run: npm i -g @antfu/ni
24 |
25 | - name: Install
26 | run: nci
27 |
28 | - name: Lint
29 | run: nr lint
30 |
31 | test:
32 | runs-on: ${{ matrix.os }}
33 |
34 | strategy:
35 | matrix:
36 | node: [20.x]
37 | os:
38 | - ubuntu-latest
39 | # windows-latest, TODO: hash-sum result different with linux
40 | - macos-latest
41 |
42 | fail-fast: false
43 |
44 | steps:
45 | - uses: actions/checkout@v3
46 | - name: Set node ${{ matrix.node }}
47 | uses: actions/setup-node@v3
48 | with:
49 | node-version: ${{ matrix.node }}
50 |
51 | - name: Setup
52 | run: npm i -g @antfu/ni
53 |
54 | - name: Install
55 | run: nci
56 |
57 | - name: Build
58 | run: nr build
59 |
60 | - name: Type Check
61 | run: nr typecheck
62 |
63 | - name: Test
64 | run: nr test
65 |
66 | - name: Docs Build
67 | run: nr docs:build
68 |
--------------------------------------------------------------------------------
/playground/src/if.tsx:
--------------------------------------------------------------------------------
1 | import { defineVaporComponent, ref } from 'vue'
2 |
3 | export default defineVaporComponent(() => {
4 | const count = ref(1)
5 |
6 | const Foo = () => 2
7 |
8 | return (
9 |
10 |
11 |
12 |
13 |
14 |
28 |
29 |
41 |
42 |
43 | )
44 | defineStyle(`
45 | .foo {
46 | color: red;
47 | }
48 | `)
49 | })
50 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/custom_directive.rs:
--------------------------------------------------------------------------------
1 | use compiler_rs::transform;
2 | use insta::assert_snapshot;
3 |
4 | #[test]
5 | fn basic() {
6 | let code = transform("", None).code;
7 | assert_snapshot!(code);
8 | }
9 |
10 | #[test]
11 | fn binding_value() {
12 | let code = transform("", None).code;
13 | assert_snapshot!(code);
14 | }
15 |
16 | #[test]
17 | fn static_parameters() {
18 | let code = transform("", None).code;
19 | assert_snapshot!(code);
20 | }
21 |
22 | #[test]
23 | fn modifiers() {
24 | let code = transform("", None).code;
25 | assert_snapshot!(code);
26 | }
27 |
28 | #[test]
29 | fn modifiers_with_binding() {
30 | let code = transform("", None).code;
31 | assert_snapshot!(code);
32 | }
33 |
34 | #[test]
35 | fn static_argument_and_modifiers() {
36 | let code = transform("", None).code;
37 | assert_snapshot!(code);
38 | }
39 |
40 | #[test]
41 | fn dynamic_argument() {
42 | let code = transform("", None).code;
43 | assert_snapshot!(code);
44 | }
45 |
46 | #[test]
47 | fn component() {
48 | let code = transform(
49 | "
50 |
51 |
52 |
53 | ",
54 | None,
55 | )
56 | .code;
57 | assert_snapshot!(code);
58 | }
59 |
--------------------------------------------------------------------------------
/packages/compiler-rs/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors = ["zhiyuanzmj <260480378@qq.com>"]
3 | edition = "2024"
4 | name = "compiler-rs"
5 | version = "0.1.0"
6 |
7 | [lib]
8 | crate-type = ["cdylib", "rlib"]
9 |
10 | [features]
11 | default = ["napi"]
12 | napi = []
13 |
14 | [workspace]
15 | resolver = "3"
16 | members = ["crates/*"]
17 |
18 | [workspace.dependencies]
19 | napi = { version = "3.3.0", features = ["napi9"] }
20 | napi-derive = "3.3.0"
21 |
22 | oxc_parser = "0.99.0"
23 | oxc_ast = "0.99.0"
24 | oxc_allocator = "0.99.0"
25 | oxc_span = "0.99.0"
26 | oxc_ast_visit = "0.99.0"
27 | oxc_traverse = "0.99.0"
28 | oxc_semantic = "0.99.0"
29 | oxc_codegen = "0.99.0"
30 | phf = "0.13.1"
31 | indexmap = "2.12.0"
32 |
33 | vdom = { path = "crates/vdom" }
34 | vapor = { path = "crates/vapor" }
35 | common = { path = "crates/common" }
36 |
37 | [dependencies]
38 | napi = { workspace = true }
39 | napi-derive = { workspace = true }
40 |
41 | oxc_parser = { workspace = true }
42 | oxc_ast = { workspace = true }
43 | oxc_allocator = { workspace = true }
44 | oxc_span = { workspace = true }
45 | oxc_traverse = { workspace = true }
46 | oxc_semantic = { workspace = true }
47 | oxc_codegen = { workspace = true }
48 |
49 | common = { workspace = true }
50 | vapor = { workspace = true }
51 |
52 | [dev-dependencies]
53 | insta = "1.43.2"
54 | criterion = "0.7.0"
55 |
56 | [[bench]]
57 | name = "bench"
58 | harness = false
59 |
60 | [build-dependencies]
61 | napi-build = "2"
62 |
63 | [profile.release]
64 | lto = true
65 | codegen-units = 1
66 | strip = "symbols"
67 |
--------------------------------------------------------------------------------
/packages/compiler-rs/crates/vapor/src/generate/dom.rs:
--------------------------------------------------------------------------------
1 | use oxc_ast::NONE;
2 | use oxc_ast::ast::Statement;
3 | use oxc_span::SPAN;
4 |
5 | use crate::generate::CodegenContext;
6 | use crate::ir::index::InsertNodeIRNode;
7 |
8 | pub fn gen_insert_node<'a>(oper: InsertNodeIRNode, context: &CodegenContext<'a>) -> Statement<'a> {
9 | let ast = &context.ast;
10 | let InsertNodeIRNode {
11 | parent,
12 | elements,
13 | anchor,
14 | ..
15 | } = oper;
16 |
17 | let mut arguments = ast.vec();
18 | if elements.len() > 1 {
19 | arguments.push(
20 | ast
21 | .expression_array(
22 | SPAN,
23 | ast.vec_from_iter(elements.into_iter().map(|element| {
24 | ast
25 | .expression_identifier(SPAN, ast.atom(&format!("n{}", element)))
26 | .into()
27 | })),
28 | )
29 | .into(),
30 | );
31 | } else {
32 | arguments.push(
33 | ast
34 | .expression_identifier(SPAN, ast.atom(&format!("n{}", elements[0])))
35 | .into(),
36 | )
37 | }
38 |
39 | arguments.push(
40 | ast
41 | .expression_identifier(SPAN, ast.atom(&format!("n{parent}")))
42 | .into(),
43 | );
44 |
45 | if let Some(anchor) = anchor {
46 | arguments.push(
47 | ast
48 | .expression_identifier(SPAN, ast.atom(&format!("n{anchor}")))
49 | .into(),
50 | );
51 | }
52 |
53 | ast.statement_expression(
54 | SPAN,
55 | ast.expression_call(
56 | SPAN,
57 | ast.expression_identifier(SPAN, ast.atom("insert")),
58 | NONE,
59 | arguments,
60 | false,
61 | ),
62 | )
63 | }
64 |
--------------------------------------------------------------------------------
/packages/compiler-rs/crates/vapor/src/generate/v_show.rs:
--------------------------------------------------------------------------------
1 | use oxc_ast::NONE;
2 | use oxc_ast::ast::FormalParameterKind;
3 | use oxc_ast::ast::Statement;
4 | use oxc_span::SPAN;
5 |
6 | use crate::generate::CodegenContext;
7 | use crate::generate::expression::gen_expression;
8 | use crate::ir::index::DirectiveIRNode;
9 |
10 | pub fn gen_v_show<'a>(oper: DirectiveIRNode<'a>, context: &'a CodegenContext<'a>) -> Statement<'a> {
11 | let ast = &context.ast;
12 | let DirectiveIRNode { dir, element, .. } = oper;
13 |
14 | ast.statement_expression(
15 | SPAN,
16 | ast.expression_call(
17 | SPAN,
18 | ast.expression_identifier(SPAN, ast.atom(&context.helper("applyVShow"))),
19 | NONE,
20 | ast.vec_from_array([
21 | ast
22 | .expression_identifier(SPAN, ast.atom(&format!("n{element}")))
23 | .into(),
24 | ast
25 | .expression_arrow_function(
26 | SPAN,
27 | true,
28 | false,
29 | NONE,
30 | ast.formal_parameters(
31 | SPAN,
32 | FormalParameterKind::ArrowFormalParameters,
33 | ast.vec(),
34 | NONE,
35 | ),
36 | NONE,
37 | ast.function_body(
38 | SPAN,
39 | ast.vec(),
40 | ast.vec1(
41 | ast.statement_expression(
42 | SPAN,
43 | gen_expression(dir.exp.unwrap(), context, None, None),
44 | ),
45 | ),
46 | ),
47 | )
48 | .into(),
49 | ]),
50 | false,
51 | ),
52 | )
53 | }
54 |
--------------------------------------------------------------------------------
/packages/macros/src/raw.ts:
--------------------------------------------------------------------------------
1 | import { createFilter, normalizePath } from '@vue-macros/common'
2 | import { transformJsxMacros } from './core'
3 | import {
4 | helperPrefix,
5 | useModelHelperCode,
6 | useModelHelperId,
7 | withDefaultsHelperCode,
8 | withDefaultsHelperId,
9 | } from './core/helper'
10 | import { transformStyle } from './core/style'
11 | import { resolveOptions, type Options } from './options'
12 | import type { UnpluginOptions } from 'unplugin'
13 |
14 | const name = '@vue-jsx-vapor/macros'
15 |
16 | const plugin = (userOptions: Options = {}): UnpluginOptions => {
17 | const options = resolveOptions(userOptions)
18 | const filter = createFilter(options)
19 | const importMap = new Map()
20 |
21 | return {
22 | name,
23 | enforce: 'pre',
24 |
25 | resolveId(id) {
26 | if (normalizePath(id).startsWith(helperPrefix)) return id
27 | },
28 | loadInclude(id) {
29 | return normalizePath(id).startsWith(helperPrefix)
30 | },
31 | load(_id) {
32 | const id = normalizePath(_id)
33 | if (id === useModelHelperId) return useModelHelperCode
34 | else if (id === withDefaultsHelperId) return withDefaultsHelperCode
35 | else if (importMap.get(id)) return importMap.get(id)
36 | },
37 |
38 | transformInclude(id) {
39 | if (importMap.get(id)) return true
40 | return filter(id)
41 | },
42 | transform(code, id, opt?: { ssr?: boolean }) {
43 | if (opt?.ssr) {
44 | options.defineComponent.autoReturnFunction = true
45 | }
46 | if (importMap.get(id)) return transformStyle(code, id, options)
47 | return transformJsxMacros(code, id, importMap, options)
48 | },
49 | }
50 | }
51 | export default plugin
52 |
--------------------------------------------------------------------------------
/packages/compiler-rs/wasi-worker.mjs:
--------------------------------------------------------------------------------
1 | import fs from "node:fs";
2 | import { createRequire } from "node:module";
3 | import { parse } from "node:path";
4 | import { WASI } from "node:wasi";
5 | import { parentPort, Worker } from "node:worker_threads";
6 |
7 | const require = createRequire(import.meta.url);
8 |
9 | const { instantiateNapiModuleSync, MessageHandler, getDefaultContext } = require("@napi-rs/wasm-runtime");
10 |
11 | if (parentPort) {
12 | parentPort.on("message", (data) => {
13 | globalThis.onmessage({ data });
14 | });
15 | }
16 |
17 | Object.assign(globalThis, {
18 | self: globalThis,
19 | require,
20 | Worker,
21 | importScripts: function (f) {
22 | ;(0, eval)(fs.readFileSync(f, "utf8") + "//# sourceURL=" + f);
23 | },
24 | postMessage: function (msg) {
25 | if (parentPort) {
26 | parentPort.postMessage(msg);
27 | }
28 | },
29 | });
30 |
31 | const emnapiContext = getDefaultContext();
32 |
33 | const __rootDir = parse(process.cwd()).root;
34 |
35 | const handler = new MessageHandler({
36 | onLoad({ wasmModule, wasmMemory }) {
37 | const wasi = new WASI({
38 | version: 'preview1',
39 | env: process.env,
40 | preopens: {
41 | [__rootDir]: __rootDir,
42 | },
43 | });
44 |
45 | return instantiateNapiModuleSync(wasmModule, {
46 | childThread: true,
47 | wasi,
48 | context: emnapiContext,
49 | overwriteImports(importObject) {
50 | importObject.env = {
51 | ...importObject.env,
52 | ...importObject.napi,
53 | ...importObject.emnapi,
54 | memory: wasmMemory
55 | };
56 | },
57 | });
58 | },
59 | });
60 |
61 | globalThis.onmessage = function (e) {
62 | handler.handle(e);
63 | };
64 |
--------------------------------------------------------------------------------
/packages/vue-jsx-vapor/jsx-runtime/index.cjs:
--------------------------------------------------------------------------------
1 | //#region rolldown:runtime
2 | const __create = Object.create
3 | const __defProp = Object.defineProperty
4 | const __getOwnPropDesc = Object.getOwnPropertyDescriptor
5 | const __getOwnPropNames = Object.getOwnPropertyNames
6 | const __getProtoOf = Object.getPrototypeOf
7 | const __hasOwnProp = Object.prototype.hasOwnProperty
8 | const __copyProps = (to, from, except, desc) => {
9 | if ((from && typeof from === 'object') || typeof from === 'function')
10 | for (
11 | let keys = __getOwnPropNames(from), i = 0, n = keys.length, key;
12 | i < n;
13 | i++
14 | ) {
15 | key = keys[i]
16 | if (!__hasOwnProp.call(to, key) && key !== except)
17 | __defProp(to, key, {
18 | get: ((k) => from[k]).bind(null, key),
19 | enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable,
20 | })
21 | }
22 | return to
23 | }
24 | const __toESM = (mod, isNodeMode, target) => (
25 | (target = mod != null ? __create(__getProtoOf(mod)) : {}),
26 | __copyProps(
27 | isNodeMode || !mod || !mod.__esModule
28 | ? __defProp(target, 'default', {
29 | value: mod,
30 | enumerable: true,
31 | })
32 | : target,
33 | mod,
34 | )
35 | )
36 | //#endregion
37 | const vue = __toESM(require('vue'))
38 | const vue_jsx_vapor = __toESM(require('vue-jsx-vapor'))
39 |
40 | function jsx(type, props, key) {
41 | const { children, 'v-slots': vSlots } = props
42 | delete props.children
43 | delete props['v-slots']
44 | if (arguments.length > 2) props.key = key
45 | return (0, vue_jsx_vapor.h)(type, props, vSlots || children)
46 | }
47 |
48 | exports.Fragment = vue.Fragment
49 | exports.jsx = jsx
50 | exports.jsxDEV = jsx
51 | exports.jsxs = jsx
52 |
--------------------------------------------------------------------------------
/packages/macros/src/core/utils.ts:
--------------------------------------------------------------------------------
1 | import type {
2 | ArrowFunctionExpression,
3 | FunctionDeclaration,
4 | FunctionExpression,
5 | Node,
6 | } from '@babel/types'
7 | import type { MagicStringAST } from '@vue-macros/common'
8 |
9 | export type FunctionalNode =
10 | | FunctionDeclaration
11 | | FunctionExpression
12 | | ArrowFunctionExpression
13 |
14 | export function prependFunctionalNode(
15 | node: FunctionalNode,
16 | s: MagicStringAST,
17 | result: string,
18 | ): void {
19 | const isBlockStatement = node.body.type === 'BlockStatement'
20 | const start = node.body.extra?.parenthesized
21 | ? (node.body.extra.parenStart as number)
22 | : node.body.start!
23 | s.appendRight(
24 | start + (isBlockStatement ? 1 : 0),
25 | `${result};${!isBlockStatement ? 'return ' : ''}`,
26 | )
27 | if (!isBlockStatement) {
28 | s.appendLeft(start, '{')
29 | s.appendRight(node.end!, '}')
30 | }
31 | }
32 |
33 | export function isFunctionalNode(node?: Node | null): node is FunctionalNode {
34 | return !!(
35 | node &&
36 | (node.type === 'ArrowFunctionExpression' ||
37 | node.type === 'FunctionDeclaration' ||
38 | node.type === 'FunctionExpression')
39 | )
40 | }
41 |
42 | export function getParamsStart(node: FunctionalNode, code: string): number {
43 | return node.params[0]
44 | ? node.params[0].start!
45 | : node.start! +
46 | (code.slice(node.start!, node.body.start!).match(/\(\s*\)/)?.index ||
47 | 0) +
48 | 1
49 | }
50 |
51 | export function getDefaultValue(node: Node): Node {
52 | if (node.type === 'TSNonNullExpression') {
53 | return getDefaultValue(node.expression)
54 | }
55 | if (node.type === 'TSAsExpression') {
56 | return getDefaultValue(node.expression)
57 | }
58 | return node
59 | }
60 |
--------------------------------------------------------------------------------
/packages/compiler-rs/compiler-rs.wasi-browser.js:
--------------------------------------------------------------------------------
1 | import {
2 | createOnMessage as __wasmCreateOnMessageForFsProxy,
3 | getDefaultContext as __emnapiGetDefaultContext,
4 | instantiateNapiModuleSync as __emnapiInstantiateNapiModuleSync,
5 | WASI as __WASI,
6 | } from '@napi-rs/wasm-runtime'
7 |
8 |
9 |
10 | const __wasi = new __WASI({
11 | version: 'preview1',
12 | })
13 |
14 | const __wasmUrl = new URL('./compiler-rs.wasm32-wasi.wasm', import.meta.url).href
15 | const __emnapiContext = __emnapiGetDefaultContext()
16 |
17 |
18 | const __sharedMemory = new WebAssembly.Memory({
19 | initial: 4000,
20 | maximum: 65536,
21 | shared: true,
22 | })
23 |
24 | const __wasmFile = await fetch(__wasmUrl).then((res) => res.arrayBuffer())
25 |
26 | const {
27 | instance: __napiInstance,
28 | module: __wasiModule,
29 | napiModule: __napiModule,
30 | } = __emnapiInstantiateNapiModuleSync(__wasmFile, {
31 | context: __emnapiContext,
32 | asyncWorkPoolSize: 4,
33 | wasi: __wasi,
34 | onCreateWorker() {
35 | const worker = new Worker(new URL('./wasi-worker-browser.mjs', import.meta.url), {
36 | type: 'module',
37 | })
38 |
39 | return worker
40 | },
41 | overwriteImports(importObject) {
42 | importObject.env = {
43 | ...importObject.env,
44 | ...importObject.napi,
45 | ...importObject.emnapi,
46 | memory: __sharedMemory,
47 | }
48 | return importObject
49 | },
50 | beforeInit({ instance }) {
51 | for (const name of Object.keys(instance.exports)) {
52 | if (name.startsWith('__napi_register__')) {
53 | instance.exports[name]()
54 | }
55 | }
56 | },
57 | })
58 | export default __napiModule.exports
59 | export const ErrorCodes = __napiModule.exports.ErrorCodes
60 | export const transform = __napiModule.exports.transform
61 |
--------------------------------------------------------------------------------
/packages/macros/tests/fixtures.spec.ts:
--------------------------------------------------------------------------------
1 | import process from 'node:process'
2 | import { testFixtures } from '@vue-macros/test-utils'
3 | import { describe } from 'vitest'
4 | import { transformJsxMacros } from '../src/core'
5 |
6 | const options = {
7 | defineModel: { alias: ['defineModel'] },
8 | defineSlots: { alias: ['defineSlots'] },
9 | defineStyle: { alias: ['defineStyle'] },
10 | defineExpose: { alias: ['defineExpose'] },
11 | defineComponent: { alias: ['defineComponent', 'defineVaporComponent'] },
12 | }
13 |
14 | // TODO: hash-sum's result is different on Windows and Linux
15 | const globs =
16 | process.platform === 'win32'
17 | ? import.meta.glob(
18 | ['./fixtures/**/*.tsx', '!./fixtures/**/define-style.tsx'],
19 | {
20 | eager: true,
21 | as: 'raw',
22 | },
23 | )
24 | : import.meta.glob('./fixtures/**/*.tsx', {
25 | eager: true,
26 | as: 'raw',
27 | })
28 |
29 | describe('fixtures', async () => {
30 | await testFixtures(
31 | globs,
32 | (args, id, code) =>
33 | transformJsxMacros(code, id, new Map(), {
34 | include: ['*.tsx'],
35 | version: 3.6,
36 | ...options,
37 | })?.code,
38 | )
39 | })
40 |
41 | describe('defineComponent autoReturnFunction fixtures', async () => {
42 | await testFixtures(
43 | import.meta.glob('./fixtures/**/define-component.tsx', {
44 | eager: true,
45 | as: 'raw',
46 | }),
47 | (args, id, code) =>
48 | transformJsxMacros(code, id, new Map(), {
49 | include: ['*.tsx'],
50 | version: 3.6,
51 | ...options,
52 | defineComponent: {
53 | alias: ['defineComponent', 'defineVaporComponent'],
54 | autoReturnFunction: true,
55 | },
56 | })?.code,
57 | )
58 | })
59 |
--------------------------------------------------------------------------------
/docs/zh/introduction/eslint.md:
--------------------------------------------------------------------------------
1 | # ESLint
2 |
3 | 用于给 `vue-jsx-vapor` 自动格式化代码的 ESLint 插件。
4 |
5 | ## 安装
6 |
7 | ```sh
8 | pnpm add @vue-jsx-vapor/eslint
9 | ```
10 |
11 | ## 配置
12 |
13 | ```ts
14 | // eslint.config.ts
15 | import vueJsxVapor from '@vue-jsx-vapor/eslint'
16 |
17 | export default [
18 | vueJsxVapor()
19 | ]
20 | ```
21 |
22 | ## define-style
23 |
24 | 使用 `prettier` 来格式化 `defineStyle` 宏中的样式。
25 |
26 | ```ts twoslash
27 | import vueJsxVapor from '@vue-jsx-vapor/eslint'
28 |
29 | export default [
30 | vueJsxVapor({
31 | rules: {
32 | 'vue-jsx-vapor/define-style': ['error', { tabWidth: 2 }]
33 | }
34 | })
35 | ]
36 | ```
37 |
38 | ## jsx-sort-props
39 |
40 | 这是 [@stylistic/jsx/jsx-sort-props](https://eslint.style/rules/jsx/jsx-sort-props) 的修改版,支持自定义 `reservedFirst` 和 `reservedLast` 选项。
41 |
42 | ```ts twoslash
43 | import vueJsxVapor from '@vue-jsx-vapor/eslint'
44 |
45 | export default [
46 | vueJsxVapor({
47 | rules: {
48 | 'vue-jsx-vapor/jsx-sort-props': ['error', {
49 | reservedFirst: ['v-if', 'v-for'],
50 | reservedLast: ['v-slot'],
51 | }]
52 | }
53 | })
54 | ]
55 | ```
56 |
57 | ### `reservedFirst`
58 |
59 | 默认为 `['v-if', 'v-else-if', 'v-else', 'v-for', 'key', 'ref', 'v-model']`
60 |
61 | 如果提供一个数组,数组中的值将覆盖默认的保留 props 列表。
62 | 这些 props 将遵循数组中指定的顺序:
63 |
64 | ```jsx
65 | // 转换前
66 | const Before =
67 |
68 | // 转换后
69 | const After =
70 | ```
71 |
72 | ### `reservedLast`
73 |
74 | 默认为 `['v-slot', 'v-slots', 'v-text', 'v-html']`
75 |
76 | 这是一个数组选项。这些 props 必须在所有其他 props 之后列出。
77 | 它们将遵循数组中指定的顺序:
78 |
79 | ```jsx
80 | // 转换前
81 | const Before =
82 |
83 | // 转换后
84 | const After =
85 | ```
86 |
--------------------------------------------------------------------------------
/packages/macros/tests/fixtures/define-component.tsx:
--------------------------------------------------------------------------------
1 | import { defineComponent, defineVaporComponent, nextTick, unref, VaporComponentInstance, VNode } from 'vue'
2 |
3 | const $ = unref
4 |
5 | const Comp = defineVaporComponent(
6 | ({ bar = 'bar'! as string, Comp, ...attrs }: { bar: string; baz: 'baz', Comp: any }) => {
7 | defineModel()
8 | const foo = $(
9 | defineModel('foo', {
10 | validator: (value) => {
11 | return value === 'foo'
12 | },
13 | type: String,
14 | })!,
15 | )
16 | return
17 | {[foo, bar, attrs.baz]}
18 |
19 |
20 | },
21 | { name: 'Comp', props: { Comp: Object } },
22 | )
23 |
24 | const Comp1 = defineVaporComponent((props: { bar: 'bar'; 'onUpdate:bar': any, comp: any }) => {
25 | const foo = defineModel('foo')
26 | return
27 | {[foo.value, props['bar'], props['onUpdate:bar']]}
28 |
29 |
30 | })
31 |
32 | const Comp2 = defineComponent(async () => {
33 | await nextTick()
34 | let foo = await new Promise((resolve) => {
35 | setTimeout(() => resolve('foo'), 1000)
36 | })
37 | return () => {foo}
38 | })
39 |
40 | const foo = () => {}
41 | defineVaporComponent(({
42 | a = 0,
43 | b = 'b',
44 | c = true,
45 | d = () => {},
46 | e = {},
47 | f = [],
48 | g = foo,
49 | h = null,
50 | i = undefined!,
51 | }) => {
52 | return (
53 | <>
54 | {a}
55 | {b}
56 | {c}
57 | {d}
58 | {e}
59 | {f}
60 | {g}
61 | {h}
62 | {i}
63 | >
64 | )
65 | })
66 |
67 | // #21
68 | const Comp3 = defineComponent(()=>{
69 | return () => 123
70 | })
71 | ; == ({} as VNode)
72 | const Comp4 = defineVaporComponent(() => {
73 | return 123
74 | })
75 | ; == ({} as VaporComponentInstance)
--------------------------------------------------------------------------------
/docs/zh/introduction/getting-started.md:
--------------------------------------------------------------------------------
1 | # 快速上手
2 |
3 | `vue-jsx-vapor` 是 `vue-jsx` 的 Vapor 模式。它支持 Vue 的所有指令和大部分宏。
4 |
5 | 在继续之前,我们假设您已经熟悉 Vue 的基本用法。
6 |
7 | ## 环境要求
8 |
9 | - Vue `>= v3.6`。
10 | - VSCode 扩展 [TS Macro](https://marketplace.visualstudio.com/items?itemName=zhiyuanzmj.vscode-ts-macro) 并且需要安装 `@ts-macro/tsc` 来替代 `tsc` 进行类型检查。
11 | ```json
12 | // package.json
13 | {
14 | "scripts": {
15 | "typecheck": "tsmc --noEmit"
16 | // ...
17 | }
18 | }
19 | ```
20 |
21 | ## 安装
22 |
23 | ```bash [pnpm]
24 | # 插件
25 | pnpm add vue-jsx-vapor
26 |
27 | # 运行时
28 | pnpm add vue@3.6.0-alpha.2
29 | ```
30 |
31 | ## 配置
32 |
33 | ::: code-group
34 |
35 | ```ts [vite.config.ts]
36 | import { defineConfig } from 'vite'
37 | import vueJsxVapor from 'vue-jsx-vapor/vite'
38 |
39 | export default defineConfig({
40 | plugins: [
41 | vueJsxVapor({
42 | macros: true,
43 | }),
44 | ],
45 | })
46 | ```
47 |
48 | :::
49 |
50 | ## Typescript
51 |
52 | ### 配置 `tsconfig.json`
53 | ```json
54 | {
55 | "compilerOptions": {
56 | "jsx": "preserve",
57 | "jsxImportSource": "vue-jsx-vapor",
58 | // ...
59 | }
60 | }
61 | ```
62 |
63 | ### Volar 插件
64 |
65 | 由于 `vue-jsx-vapor` 支持 Vue 指令和 Vue 宏,所以需要安装 [TS Macro](https://marketplace.visualstudio.com/items?itemName=zhiyuanzmj.vscode-ts-macro) 的 VSCode 插件来加载 `vue-jsx-vapor/volar` 插件, 以获得类型支持。
66 |
67 | `TS Macro` 的 VSCode 会通过分析 `vite.config.ts` 来自动加载 `vue-jsx-vapor/volar` 插件并共享 `vue-jsx-vapor/vite` 插件的用户配置,无需手动配置 `ts-macro.config.ts`。
68 |
69 |
70 | ::: details 手动配置
71 |
72 | ::: code-group
73 |
74 | ```ts [ts-macro.config.ts]
75 | import vueJsxVapor from 'vue-jsx-vapor/volar'
76 |
77 | export default {
78 | plugins: [
79 | vueJsxVapor({
80 | macros: true,
81 | }),
82 | ],
83 | }
84 | ```
85 |
86 | :::
87 |
88 | ## 模板
89 |
90 | - [vitesse-jsx-vapor](https://github.com/zhiyuanzmj/vitesse-jsx-vapor)
91 |
--------------------------------------------------------------------------------
/packages/compiler-rs/tests/vapor/transform_text.rs:
--------------------------------------------------------------------------------
1 | use compiler_rs::transform;
2 | use insta::assert_snapshot;
3 |
4 | #[test]
5 | fn static_template() {
6 | let code = transform(
7 | "",
12 | None,
13 | )
14 | .code;
15 | assert_snapshot!(code);
16 | }
17 |
18 | #[test]
19 | fn interpolation() {
20 | let code = transform("<>{ 1 }{ 2 }{a +b + c }>", None).code;
21 | assert_snapshot!(code);
22 | }
23 |
24 | #[test]
25 | fn on_consecutive_text() {
26 | let code = transform("<>{ \"hello world\" }>", None).code;
27 | assert_snapshot!(code);
28 | }
29 |
30 | #[test]
31 | fn consecutive_text() {
32 | let code = transform("<>{ msg }>", None).code;
33 | assert_snapshot!(code);
34 | }
35 |
36 | #[test]
37 | fn escapes_raw_static_text_when_generating_the_template_string() {
38 | let code = transform("<script>", None).code;
39 | assert_snapshot!(code);
40 | }
41 |
42 | #[test]
43 | fn text_like() {
44 | let code = transform("{ (2) }{`foo${1}`}{1}{1n}
", None).code;
45 | assert_snapshot!(code);
46 | }
47 |
48 | #[test]
49 | fn expression_conditional() {
50 | let code = transform(
51 | "<>{ok? ({msg}) : fail ? (fail
) : null }>",
52 | None,
53 | )
54 | .code;
55 | assert_snapshot!(code);
56 | }
57 |
58 | #[test]
59 | fn expression_logical() {
60 | let code = transform("<>{ok && ({msg}
)}>", None).code;
61 | assert_snapshot!(code);
62 | }
63 |
64 | #[test]
65 | fn expression_map() {
66 | let code = transform(
67 | "<>{Array.from({ length: count.value }).map((_, index) => {
68 | if (index > 1) {
69 | return 1
70 | } else {
71 | return [({index}) lt 1,
]
72 | }
73 | })}>",
74 | None,
75 | )
76 | .code;
77 | assert_snapshot!(code);
78 | }
79 |
--------------------------------------------------------------------------------
/playground/src/App.tsx:
--------------------------------------------------------------------------------
1 | import { defineVaporComponent, ref, type Ref } from 'vue'
2 | import { useRef } from 'vue-jsx-vapor'
3 | import VueComp from './Comp.vue'
4 | import Count2 from './count'
5 | import For from './for'
6 | import Html from './html'
7 | import If from './if'
8 | import Model from './model'
9 | import Once from './once'
10 | import Show from './show'
11 | import Slot from './slot'
12 |
13 | export default defineVaporComponent(() => {
14 | const count = ref('1')
15 |
16 | const Count = (props: { value: string }) => {
17 | return {props.value}
18 | }
19 |
20 | const Count1 = ({ value }: { value: Ref }) => {
21 | return {value.value}
22 | }
23 |
24 | const compRef = useRef()
25 |
26 | return (
27 | <>
28 |
40 |
41 |
45 |
46 |
50 |
51 |
55 |
56 |
60 |
61 |
65 |
66 |
69 |
70 |
71 |
75 | >
76 | )
77 | })
78 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "3.0.4",
3 | "packageManager": "pnpm@10.17.0",
4 | "description": "Vue JSX Vapor",
5 | "type": "module",
6 | "keywords": [
7 | "unplugin",
8 | "vite",
9 | "webpack",
10 | "rollup",
11 | "transform",
12 | "vue-jsx",
13 | "volar",
14 | "vapor",
15 | "babel",
16 | "compiler"
17 | ],
18 | "license": "MIT",
19 | "homepage": "https://github.com/vuejs/vue-jsx-vapor#readme",
20 | "bugs": {
21 | "url": "https://github.com/vuejs/vue-jsx-vapor/issues"
22 | },
23 | "repository": {
24 | "type": "git",
25 | "url": "git+https://github.com/vuejs/vue-jsx-vapor.git"
26 | },
27 | "scripts": {
28 | "dev": "pnpm run --filter=\"./packages/*\" --parallel dev",
29 | "build": "pnpm run --filter=\"./packages/*\" --parallel build",
30 | "bench": "pnpm run -C ./benchmark bench",
31 | "typecheck": "tsmc --noEmit",
32 | "lint": "eslint .",
33 | "play": "npm -C playground run dev",
34 | "test": "vitest",
35 | "test-rs": "pnpm run --filter=\"compiler-rs\" test",
36 | "release": "bumpp -r --all -x 'pnpm run changelog'",
37 | "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
38 | "docs:dev": "pnpm run -C ./docs dev",
39 | "docs:preview": "pnpm run -C ./docs preview",
40 | "docs:build": "pnpm run -C ./docs build"
41 | },
42 | "devDependencies": {
43 | "@sxzz/eslint-config": "^7.1.4",
44 | "@ts-macro/tsc": "catalog:",
45 | "@types/node": "^22.18.6",
46 | "bumpp": "^10.2.3",
47 | "conventional-changelog-cli": "^5.0.0",
48 | "eslint": "^9.36.0",
49 | "tsdown": "^0.15.12",
50 | "typescript": "^5.9.2",
51 | "unplugin-raw": "^0.5.1",
52 | "vite": "catalog:",
53 | "vitest": "catalog:",
54 | "vue-jsx-vapor": "workspace:*"
55 | },
56 | "pnpm": {
57 | "overrides": {
58 | "estree-walker": "2.0.2",
59 | "ts-macro": "catalog:"
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------