feat(resolution): bridge Vuex string dispatch/commit to actions and mutations
Completes the Vue store dispatch family (the Pinia bridge was 8ea3205). Vuex
dispatches by a runtime STRING key — `dispatch('user/login')` /
`commit('SET_TOKEN')` / `this.$store.dispatch('app/toggleDevice')` — with no
static edge to the handler.
vuexDispatchEdges (callback-synthesizer.ts): the last `/` segment of the key is
the action/mutation name, the preceding segment is the namespace (≈ the module
file). Resolve the name to a function node IN A STORE FILE — the ≥2-signal
store-file gate excludes a same-named `api/` helper (`getInfo`/`login` collide in
practice) — disambiguated by the immediate namespace segment appearing in the
path (handles deep nesting like `d2admin/user/set`), or the same file for a root
local `commit('M')` inside an action. The .vue component is a dispatcher fallback
for top-level setup calls. Surfaces in explore as `dynamic: vuex dispatch`.
Also extracts the canonical Vuex MODULE shape `export default { namespaced,
actions: {…}, mutations: {…} }` (tree-sitter.ts: extractStoreCollectionMethods
off the export_statement, store-file gated) — its object-literal methods were
otherwise never nodes, so d2-admin's actions couldn't be bridged.
Validated 100% precision on three repos — vue-element-admin (55 edges),
vue-admin-template (12), d2-admin (63): 0 non-store targets, 0 namespace
mismatches (54/54 namespaced edges route to the correct module despite 6
colliding `load` actions in d2-admin), 0 on Redux controls (basetool/uwave —
non-string `dispatch()` correctly ignored). Suite green (1613); new
__tests__/vuex-dispatch-synthesizer.test.ts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
8ea32059b6
commit
80a1044d3d
@@ -1066,6 +1066,24 @@ export class TreeSitterExtractor {
|
||||
const parentId = this.nodeStack[this.nodeStack.length - 1];
|
||||
if (parentId) this.emitReExportRefs(node, parentId);
|
||||
}
|
||||
// Vuex MODULE default export — `export default { namespaced, actions: {…},
|
||||
// mutations: {…} }` (the canonical Vuex module shape). Object-literal methods
|
||||
// aren't otherwise extracted, so scan the config's actions/mutations/getters
|
||||
// collections and extract their methods as nodes. Store-file gated (the
|
||||
// ≥2-signal heuristic) so a plain default-exported object is untouched; skip
|
||||
// the subtree afterward (the collection methods are now handled).
|
||||
else if (
|
||||
nodeType === 'export_statement' &&
|
||||
(this.language === 'typescript' || this.language === 'tsx' ||
|
||||
this.language === 'javascript' || this.language === 'jsx') &&
|
||||
this.looksLikeVueStoreFile()
|
||||
) {
|
||||
const exported = getChildByField(node, 'value');
|
||||
if (exported && (exported.type === 'object' || exported.type === 'object_expression')) {
|
||||
this.extractStoreCollectionMethods(exported);
|
||||
skipChildren = true;
|
||||
}
|
||||
}
|
||||
// Check for function calls
|
||||
else if (this.extractor.callTypes.includes(nodeType)) {
|
||||
this.extractCall(node);
|
||||
@@ -2183,6 +2201,23 @@ export class TreeSitterExtractor {
|
||||
return objects;
|
||||
}
|
||||
|
||||
/** Extract the methods of a store-config object's `actions`/`mutations`/`getters`
|
||||
* properties. Used for the canonical Vuex MODULE shape `export default {
|
||||
* namespaced, actions: {…}, mutations: {…} }` — object-literal methods aren't
|
||||
* otherwise extracted, so the actions/mutations would never be nodes. */
|
||||
private extractStoreCollectionMethods(configObj: SyntaxNode): void {
|
||||
for (let j = 0; j < configObj.namedChildCount; j++) {
|
||||
const member = configObj.namedChild(j);
|
||||
if (member?.type !== 'pair') continue;
|
||||
const key = getChildByField(member, 'key');
|
||||
if (!key || !VUE_STORE_COLLECTION_NAMES.has(getNodeText(key, this.source))) continue;
|
||||
const value = getChildByField(member, 'value');
|
||||
if (value && (value.type === 'object' || value.type === 'object_expression')) {
|
||||
this.extractObjectLiteralFunctions(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The SETUP function of a Pinia setup store (`defineStore('id', () => {…})`)
|
||||
* — an arrow/function arg with a block body. Returns null for the options form
|
||||
* (`defineStore({…})`) and for any non-defineStore call. The setup body's local
|
||||
|
||||
Reference in New Issue
Block a user