From 742d83f9182a290f785f1a48f68d12da87b7a042 Mon Sep 17 00:00:00 2001 From: Varixo Date: Tue, 31 Dec 2024 13:52:31 +0100 Subject: [PATCH] fix: convert destructured array's props to signal --- .changeset/unlucky-dodos-grab.md | 5 + .../qwik/src/core/shared/platform/platform.ts | 3 +- ...uld_wrap_prop_from_destructured_array.snap | 218 ++++++++++++++++++ packages/qwik/src/optimizer/core/src/test.rs | 43 ++++ .../qwik/src/optimizer/core/src/transform.rs | 17 +- 5 files changed, 275 insertions(+), 11 deletions(-) create mode 100644 .changeset/unlucky-dodos-grab.md create mode 100644 packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__should_wrap_prop_from_destructured_array.snap diff --git a/.changeset/unlucky-dodos-grab.md b/.changeset/unlucky-dodos-grab.md new file mode 100644 index 00000000000..b40439266a8 --- /dev/null +++ b/.changeset/unlucky-dodos-grab.md @@ -0,0 +1,5 @@ +--- +'@qwik.dev/core': patch +--- + +fix: convert destructured array's props to signal diff --git a/packages/qwik/src/core/shared/platform/platform.ts b/packages/qwik/src/core/shared/platform/platform.ts index 2ec9c01dd97..2d8099703b5 100644 --- a/packages/qwik/src/core/shared/platform/platform.ts +++ b/packages/qwik/src/core/shared/platform/platform.ts @@ -4,6 +4,7 @@ import { QError, qError } from '../error/error'; import { getSymbolHash } from '../qrl/qrl-class'; import { qDynamicPlatform } from '../utils/qdev'; import type { CorePlatform } from './types'; +import { QBaseAttr } from '../utils/markers'; export const createPlatform = (): CorePlatform => { return { @@ -65,7 +66,7 @@ export const createPlatform = (): CorePlatform => { */ export const toUrl = (doc: Document, containerEl: Element, url: string | URL): URL => { const baseURI = doc.baseURI; - const base = new URL(containerEl.getAttribute('q:base') ?? baseURI, baseURI); + const base = new URL(containerEl.getAttribute(QBaseAttr) ?? baseURI, baseURI); return new URL(url, base); }; diff --git a/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__should_wrap_prop_from_destructured_array.snap b/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__should_wrap_prop_from_destructured_array.snap new file mode 100644 index 00000000000..46fa2f61faf --- /dev/null +++ b/packages/qwik/src/optimizer/core/src/snapshots/qwik_core__test__should_wrap_prop_from_destructured_array.snap @@ -0,0 +1,218 @@ +--- +source: packages/qwik/src/optimizer/core/src/test.rs +assertion_line: 4118 +expression: output +snapshot_kind: text +--- +==INPUT== + + + import { component$, useStore, useTask$ } from '@qwik.dev/core'; + + export const Input = component$<{error: string, error2: string, error3: string}>( + (props) => { + useTask$(({ track }) => { + track(() => props.error); + track(() => props.error2); + track(() => props.error3); + }); + + return ( + <> + + ); + } + ); + + export default component$(() => { + const [store] = [useStore({errors: {}})]; + const [[store2]] = [[useStore({errors: {}})]]; + const { store3 } = { store3: useStore({errors: {}}) }; + + return ( +
+ + +
+ ); + }); + +============================= test.js == + +import { componentQrl } from "@qwik.dev/core"; +import { qrl } from "@qwik.dev/core"; +export const Input = /*#__PURE__*/ componentQrl(/*#__PURE__*/ qrl(()=>import("./test.tsx_Input_component_9metqqaxlN8"), "Input_component_9metqqaxlN8")); +export default /*#__PURE__*/ componentQrl(/*#__PURE__*/ qrl(()=>import("./test.tsx_test_component_LUXeXe0DQrg"), "test_component_LUXeXe0DQrg")); + + +Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;AAGE,OAAO,MAAM,sBAAQ,qHAanB;AAEF,6BAAe,mHAaZ\"}") +============================= test.tsx_test_component_LUXeXe0DQrg.js (ENTRY POINT)== + +import { Input } from "./test"; +import { _fnSignal } from "@qwik.dev/core"; +import { _jsxSorted } from "@qwik.dev/core"; +import { qrl } from "@qwik.dev/core"; +import { useStore } from "@qwik.dev/core"; +export const test_component_LUXeXe0DQrg = ()=>{ + const [store] = [ + useStore({ + errors: {} + }) + ]; + const [[store2]] = [ + [ + useStore({ + errors: {} + }) + ] + ]; + const { store3 } = { + store3: useStore({ + errors: {} + }) + }; + return /*#__PURE__*/ _jsxSorted("div", null, null, [ + /*#__PURE__*/ _jsxSorted("button", null, { + onClick$: /*#__PURE__*/ qrl(()=>import("./test.tsx_test_component_div_button_onClick_TfpwI5Xb2NU"), "test_component_div_button_onClick_TfpwI5Xb2NU", [ + store + ]) + }, "click", 3, null), + /*#__PURE__*/ _jsxSorted(Input, null, { + error: _fnSignal((p0)=>p0.errors.test, [ + store + ], "p0.errors.test"), + error2: _fnSignal((p0)=>p0.errors.test, [ + store2 + ], "p0.errors.test"), + error3: _fnSignal((p0)=>p0.errors.test, [ + store3 + ], "p0.errors.test") + }, null, 3, "u6_1") + ], 1, "u6_2"); +}; + + +Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;;0CAkB4B;IACzB,MAAM,CAAC,MAAM,GAAG;QAAC,SAAS;YAAC,QAAQ,CAAC;QAAC;KAAG;IACxC,MAAM,CAAC,CAAC,OAAO,CAAC,GAAG;QAAC;YAAC,SAAS;gBAAC,QAAQ,CAAC;YAAC;SAAG;KAAC;IAC7C,MAAM,EAAE,MAAM,EAAE,GAAG;QAAE,QAAQ,SAAS;YAAC,QAAQ,CAAC;QAAC;IAAG;IAEpD,qBACC,WAAC;sBACA,WAAC;YAAO,QAAQ;;;WAEb;sBACH,WAAC;YAAM,KAAK,kBAAE,GAAM,MAAM,CAAC,IAAI;;;YAAE,MAAM,kBAAE,GAAO,MAAM,CAAC,IAAI;;;YAAE,MAAM,kBAAE,GAAO,MAAM,CAAC,IAAI;;;;;AAG1F\"}") +/* +{ + "origin": "test.tsx", + "name": "test_component_LUXeXe0DQrg", + "entry": null, + "displayName": "test.tsx_test_component", + "hash": "LUXeXe0DQrg", + "canonicalFilename": "test.tsx_test_component_LUXeXe0DQrg", + "path": "", + "extension": "js", + "parent": null, + "ctxKind": "function", + "ctxName": "component$", + "captures": false, + "loc": [ + 380, + 807 + ] +} +*/ +============================= test.tsx_test_component_div_button_onClick_TfpwI5Xb2NU.js (ENTRY POINT)== + +import { useLexicalScope } from "@qwik.dev/core"; +export const test_component_div_button_onClick_TfpwI5Xb2NU = ()=>{ + const [store] = useLexicalScope(); + store.errors.test = store.errors.test ? undefined : 'ERROR TEST'; +}; + + +Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";6DAyBuB;;IACjB,MAAM,MAAM,CAAC,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,GAAG,YAAY\"}") +/* +{ + "origin": "test.tsx", + "name": "test_component_div_button_onClick_TfpwI5Xb2NU", + "entry": null, + "displayName": "test.tsx_test_component_div_button_onClick", + "hash": "TfpwI5Xb2NU", + "canonicalFilename": "test.tsx_test_component_div_button_onClick_TfpwI5Xb2NU", + "path": "", + "extension": "js", + "parent": "test_component_LUXeXe0DQrg", + "ctxKind": "eventHandler", + "ctxName": "onClick$", + "captures": true, + "loc": [ + 587, + 673 + ] +} +*/ +============================= test.tsx_Input_component_useTask_Sbgs9Wtfkt0.js (ENTRY POINT)== + +import { useLexicalScope } from "@qwik.dev/core"; +export const Input_component_useTask_Sbgs9Wtfkt0 = ({ track })=>{ + const [props] = useLexicalScope(); + track(()=>props.error); + track(()=>props.error2); + track(()=>props.error3); +}; +export { _hW } from "@qwik.dev/core"; + + +Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";mDAKa,CAAC,EAAE,KAAK,EAAE;;IAClB,MAAM,IAAM,MAAM,KAAK;IACvB,MAAM,IAAM,MAAM,MAAM;IACxB,MAAM,IAAM,MAAM,MAAM\"}") +/* +{ + "origin": "test.tsx", + "name": "Input_component_useTask_Sbgs9Wtfkt0", + "entry": null, + "displayName": "test.tsx_Input_component_useTask", + "hash": "Sbgs9Wtfkt0", + "canonicalFilename": "test.tsx_Input_component_useTask_Sbgs9Wtfkt0", + "path": "", + "extension": "js", + "parent": "Input_component_9metqqaxlN8", + "ctxKind": "function", + "ctxName": "useTask$", + "captures": true, + "loc": [ + 183, + 300 + ] +} +*/ +============================= test.tsx_Input_component_9metqqaxlN8.js (ENTRY POINT)== + +import { Fragment as _Fragment } from "@qwik.dev/core/jsx-runtime"; +import { _jsxSorted } from "@qwik.dev/core"; +import { qrl } from "@qwik.dev/core"; +import { useTaskQrl } from "@qwik.dev/core"; +export const Input_component_9metqqaxlN8 = (props)=>{ + useTaskQrl(/*#__PURE__*/ qrl(()=>import("./test.tsx_Input_component_useTask_Sbgs9Wtfkt0"), "Input_component_useTask_Sbgs9Wtfkt0", [ + props + ])); + return /*#__PURE__*/ _jsxSorted(_Fragment, null, null, null, 3, "u6_0"); +}; + + +Some("{\"version\":3,\"sources\":[\"/user/qwik/src/test.tsx\"],\"names\":[],\"mappings\":\";;;;2CAIG,CAAC;IACA;;;IAMA,qBACC;AAGF\"}") +/* +{ + "origin": "test.tsx", + "name": "Input_component_9metqqaxlN8", + "entry": null, + "displayName": "test.tsx_Input_component", + "hash": "9metqqaxlN8", + "canonicalFilename": "test.tsx_Input_component_9metqqaxlN8", + "path": "", + "extension": "js", + "parent": null, + "ctxKind": "function", + "ctxName": "component$", + "captures": false, + "loc": [ + 157, + 345 + ] +} +*/ +== DIAGNOSTICS == + +[] diff --git a/packages/qwik/src/optimizer/core/src/test.rs b/packages/qwik/src/optimizer/core/src/test.rs index d3b4b063463..5e37fdeadbd 100644 --- a/packages/qwik/src/optimizer/core/src/test.rs +++ b/packages/qwik/src/optimizer/core/src/test.rs @@ -3974,6 +3974,49 @@ fn rename_builder_io() { }); } +#[test] +fn should_wrap_prop_from_destructured_array() { + test_input!(TestInput { + code: r#" + import { component$, useStore, useTask$ } from '@qwik.dev/core'; + + export const Input = component$<{error: string, error2: string, error3: string}>( + (props) => { + useTask$(({ track }) => { + track(() => props.error); + track(() => props.error2); + track(() => props.error3); + }); + + return ( + <> + + ); + } + ); + + export default component$(() => { + const [store] = [useStore({errors: {}})]; + const [[store2]] = [[useStore({errors: {}})]]; + const { store3 } = { store3: useStore({errors: {}}) }; + + return ( +
+ + +
+ ); + }); + "# + .to_string(), + transpile_jsx: true, + transpile_ts: true, + ..TestInput::default() + }); +} + // TODO(misko): Make this test work by implementing strict serialization. // #[test] // fn example_of_synchronous_qrl_that_cant_be_serialized() { diff --git a/packages/qwik/src/optimizer/core/src/transform.rs b/packages/qwik/src/optimizer/core/src/transform.rs index bdd95719a38..7a7d0d57a02 100644 --- a/packages/qwik/src/optimizer/core/src/transform.rs +++ b/packages/qwik/src/optimizer/core/src/transform.rs @@ -1734,17 +1734,13 @@ impl<'a> Fold for QwikTransform<'a> { fn fold_var_decl(&mut self, node: ast::VarDecl) -> ast::VarDecl { if let Some(current_scope) = self.decl_stack.last_mut() { for decl in &node.decls { - let mut identifiers = Vec::with_capacity(node.decls.len() + 2); + let mut identifiers: Vec<(Id, Span)> = Vec::with_capacity(node.decls.len() + 2); collect_from_pat(&decl.name, &mut identifiers); - let ident_type = if node.kind == ast::VarDeclKind::Const - && matches!(decl.name, ast::Pat::Ident(_)) - && is_return_static(&decl.init) - { - IdentType::Var(true) - } else { - IdentType::Var(false) - }; - current_scope.extend(identifiers.into_iter().map(|(id, _)| (id, ident_type))); + let is_const = node.kind == ast::VarDeclKind::Const && is_return_static(&decl.init); + + for ident in identifiers { + current_scope.push((ident.0, IdentType::Var(is_const))); + } } } node.fold_children_with(self) @@ -2318,6 +2314,7 @@ fn is_return_static(expr: &Option>) -> bool { callee: ast::Callee::Expr(box ast::Expr::Ident(ident)), .. })) => ident.sym.ends_with('$') || ident.sym.ends_with("Qrl") || ident.sym.starts_with("use"), + Some(box (ast::Expr::Array(_) | ast::Expr::Object(_))) => true, Some(_) => false, None => true, }