Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions graph/javascript/engine/call-edge-generation/jsx.dl
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,21 @@ jsx_loader_name("lazy").
jsx_loader_name("dynamic").
jsx_loader_name("loadable").
jsx_component_loader(w) :- expr_kind(_, "CALL", _, w), call_site("client", _, n, _, _, _, w, _, _), jsx_loader_name(n).
// A Vue DEFINER — `defineComponent({ setup() {…} })` (Nuxt: `defineNuxtComponent`): the
// tag invokes the options object's `setup` with its props, or its `render` when there is
// no setup; a render function setup returns is reached from setup's body. The function
// form, `defineComponent((props) => () => …)`, is argument 0 itself, as for memo. Named by
// the definer, so the same object handed to any other call stays out.
jsx_vue_definer_name("defineComponent").
jsx_vue_definer_name("defineNuxtComponent").
jsx_vue_definer(w) :- expr_kind(_, "CALL", _, w), call_site("client", _, n, _, _, _, w, _, _), jsx_vue_definer_name(n).

// jsx_holds(Expr, Call) — the wrapper or loader call an expression holds, followed the
// ways a component reaches a tag: the call itself, a const initialised with it, a named
// or default import of an export that holds it, and a re-export of one.
jsx_holds(w, w) :- jsx_component_wrapper(w).
jsx_holds(w, w) :- jsx_component_loader(w).
jsx_holds(w, w) :- jsx_vue_definer(w).
jsx_holds(e, w) :- expr_binding(_, v, e), jsx_var_holds(v, w).
jsx_var_holds(v, w) :- var_init(_, _, e, v), !var_binding_form(_, "OBJECT_PATTERN", v), !var_binding_form(_, "ARRAY_PATTERN", v),
jsx_holds(e, w).
Expand Down Expand Up @@ -97,6 +106,16 @@ jsx_call_renders(w, k, i) :- jsx_loader_settles(w, "obj", o), prop_value("obj",
jsx_call_renders(w, k, i) :- jsx_loader_settles(w, k, i), jsx_component_kind(k).
jsx_component_kind("func").
jsx_component_kind("ctor").
// A Vue definer: the options object's `setup`, else its `render` — one target, not both.
// "Has a setup" is read off the literal's own keys, not the value layer, which this
// relation feeds.
jsx_call_renders(w, "func", m) :- jsx_vue_definer(w), call_arg(w, 0, a), expr_value(a, "obj", o),
prop_value("obj", o, "setup", "func", m).
jsx_call_renders(w, "func", m) :- jsx_vue_definer(w), call_arg(w, 0, a), expr_value(a, "obj", o),
!jsx_vue_has_setup(o), prop_value("obj", o, "render", "func", m).
jsx_call_renders(w, "func", f) :- jsx_vue_definer(w), call_arg(w, 0, a), expr_value(a, "func", f).
jsx_vue_has_setup(o) :- expr_kind(_, "OBJECT_LITERAL", _, o), expr_child(_, o, "PROPERTY_KEY", _, key), expr_name(_, "setup", key).
jsx_vue_has_setup(o) :- literal_owns_method(o, m), method_decl(_, "setup", _, _, _, _, _, m).

// ── jsx_renders(Element, Component) — the callables the element runs ───────
// A function component (a constructor FUNCTION is callable_value's "ctor" half).
Expand Down
3 changes: 3 additions & 0 deletions graph/javascript/souffle/decls_all.dl
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@
.decl jsx_component_wrapper(c0:symbol)
.decl jsx_loader_name(c0:symbol)
.decl jsx_component_loader(c0:symbol)
.decl jsx_vue_definer_name(c0:symbol)
.decl jsx_vue_definer(c0:symbol)
.decl jsx_vue_has_setup(c0:symbol)
.decl jsx_holds(c0:symbol, c1:symbol)
.decl jsx_var_holds(c0:symbol, c1:symbol)
.decl jsx_import_holds(c0:symbol, c1:symbol)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { defineComponent } from "vue";
import { makeStore } from "store-kit";
import DefVue from "./def";

export function leaf() { return 1; }
export function renderLeaf() { return 2; }
export function fnLeaf() { return 3; }
export function bothLeaf() { return 4; }
export function storeLeaf() { return 5; }

// A tag bound to a Vue definer renders the options object's setup…
export const SetupVue = defineComponent({ setup() { leaf(); return () => "v"; } });
// …or its render when there is no setup…
export const RenderVue = defineComponent({ render() { renderLeaf(); return "r"; } });
// …or, in the function form, argument 0 itself.
export const FnVue = defineComponent((props) => { fnLeaf(); return () => "f"; });
// Setup and render both: setup is what the tag invokes; render is reached from it.
export const BothVue = defineComponent({ setup() { bothLeaf(); return () => "b"; }, render() { return "x"; } });

// CONTROL: the same options object handed to a call that is not a definer.
export const Store = makeStore({ setup() { storeLeaf(); return () => "s"; } });

export function App() {
return (
<div>
<SetupVue />
<RenderVue />
<FnVue />
<BothVue />
<DefVue />
<Store />
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { defineComponent } from "vue";

export function defLeaf() { return 6; }

// The module's default export, rendered through a default import.
export default defineComponent({ setup() { defLeaf(); return () => "d"; } });
10 changes: 10 additions & 0 deletions graph/test/javascript/expected/71-jsx-vue-define-component.diag
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import_cause app.jsx:1:10 vue not_staged
import_cause app.jsx:2:10 store-kit not_staged
import_cause def.jsx:1:10 vue not_staged
package_entry @axiomcode/code-graph . [] MAIN dist/reason.js NOT_STAGED -> -
unresolved app.jsx:12:25 FUNCTION_CALL defineComponent callee_untyped
unresolved app.jsx:14:26 FUNCTION_CALL defineComponent callee_untyped
unresolved app.jsx:16:22 FUNCTION_CALL defineComponent callee_untyped
unresolved app.jsx:18:24 FUNCTION_CALL defineComponent callee_untyped
unresolved app.jsx:21:22 FUNCTION_CALL makeStore callee_untyped
unresolved def.jsx:6:16 FUNCTION_CALL defineComponent callee_untyped
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
app.jsx:12:25 FUNCTION_CALL defineComponent -> ambiguous_unknown -
app.jsx:12:25 FUNCTION_CALL defineComponent -> callback_registered app.jsx:12:43 setup
app.jsx:12:53 FUNCTION_CALL leaf -> known_edge app.jsx:5:1 leaf
app.jsx:14:26 FUNCTION_CALL defineComponent -> ambiguous_unknown -
app.jsx:14:26 FUNCTION_CALL defineComponent -> callback_registered app.jsx:14:44 render
app.jsx:14:55 FUNCTION_CALL renderLeaf -> known_edge app.jsx:6:1 renderLeaf
app.jsx:16:22 FUNCTION_CALL defineComponent -> ambiguous_unknown -
app.jsx:16:22 FUNCTION_CALL defineComponent -> callback_registered app.jsx:16:38 <arrow>
app.jsx:16:51 FUNCTION_CALL fnLeaf -> known_edge app.jsx:7:1 fnLeaf
app.jsx:18:24 FUNCTION_CALL defineComponent -> ambiguous_unknown -
app.jsx:18:24 FUNCTION_CALL defineComponent -> callback_registered app.jsx:18:42 setup
app.jsx:18:24 FUNCTION_CALL defineComponent -> callback_registered app.jsx:18:85 render
app.jsx:18:52 FUNCTION_CALL bothLeaf -> known_edge app.jsx:8:1 bothLeaf
app.jsx:21:22 FUNCTION_CALL makeStore -> ambiguous_unknown -
app.jsx:21:22 FUNCTION_CALL makeStore -> callback_registered app.jsx:21:34 setup
app.jsx:21:44 FUNCTION_CALL storeLeaf -> known_edge app.jsx:9:1 storeLeaf
app.jsx:26:7 JSX_ELEMENT <SetupVue /> -> known_edge app.jsx:12:43 setup
app.jsx:27:7 JSX_ELEMENT <RenderVue /> -> known_edge app.jsx:14:44 render
app.jsx:28:7 JSX_ELEMENT <FnVue /> -> known_edge app.jsx:16:38 <arrow>
app.jsx:29:7 JSX_ELEMENT <BothVue /> -> known_edge app.jsx:18:42 setup
app.jsx:30:7 JSX_ELEMENT <DefVue /> -> known_edge def.jsx:6:34 setup
app.jsx:31:7 JSX_ELEMENT <Store /> -> ambiguous_unknown -
def.jsx:6:16 FUNCTION_CALL defineComponent -> ambiguous_unknown -
def.jsx:6:16 FUNCTION_CALL defineComponent -> callback_registered def.jsx:6:34 setup
def.jsx:6:44 FUNCTION_CALL defLeaf -> known_edge def.jsx:3:1 defLeaf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
app.jsx:12:53 FUNCTION_CALL leaf EXACT app.jsx:5:1
app.jsx:14:55 FUNCTION_CALL renderLeaf EXACT app.jsx:6:1
app.jsx:16:51 FUNCTION_CALL fnLeaf EXACT app.jsx:7:1
app.jsx:18:52 FUNCTION_CALL bothLeaf EXACT app.jsx:8:1
app.jsx:21:44 FUNCTION_CALL storeLeaf EXACT app.jsx:9:1
def.jsx:6:44 FUNCTION_CALL defLeaf EXACT def.jsx:3:1
# defects: 0
Loading