@eventra_dev/cli-plugin-vue 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Eventra
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.
package/README.md ADDED
@@ -0,0 +1,159 @@
1
+ <p align="center">
2
+ <img src="./assets/eventra-icon-animated.svg" width="120">
3
+ </p>
4
+
5
+ # Eventra CLI Plugin — Vue
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@eventra_dev/cli-plugin-vue"><img alt="npm version" src="https://img.shields.io/npm/v/@eventra_dev/cli-plugin-vue.svg?style=flat-square&color=blue"></a>
9
+ <a href="https://www.npmjs.com/package/@eventra_dev/cli-plugin-vue"><img alt="npm downloads" src="https://img.shields.io/npm/dm/@eventra_dev/cli-plugin-vue.svg?style=flat-square&color=blue"></a>
10
+ <img alt="tests passing" src="https://img.shields.io/badge/tests-15%20passing-brightgreen?style=flat-square&logo=vitest&logoColor=white">
11
+ <img alt="node" src="https://img.shields.io/node/v/@eventra_dev/cli-plugin-vue?style=flat-square&color=darkgreen&logo=node.js&logoColor=white">
12
+ <a href="https://www.typescriptlang.org/"><img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-ready-blue?style=flat-square&logo=typescript&logoColor=white"></a>
13
+ <img alt="license" src="https://img.shields.io/npm/l/@eventra_dev/cli-plugin-vue?style=flat-square&color=lightgrey">
14
+ </p>
15
+
16
+ Official [**Eventra CLI**](https://www.npmjs.com/package/@eventra_dev/eventra-cli) plugin — extracts `track()` calls from Vue Single-File Components (`.vue`), so `eventra sync`/`check`/`watch` understand Vue and Nuxt code the same way they already understand plain TypeScript.
17
+
18
+ ---
19
+
20
+ ## Overview
21
+
22
+ The CLI core is framework-agnostic and only walks `.ts`/`.tsx`/`.js`/`.jsx`. This plugin teaches it `.vue`: it parses each SFC with the real Vue compiler ([`@vue/compiler-sfc`](https://www.npmjs.com/package/@vue/compiler-sfc)) — not a regex — and hands the CLI a single virtual TypeScript module per file, so every existing detection rule (direct SDK calls, function wrappers, cross-file propagation, dynamic-name reporting) applies to Vue code without any Vue-specific case in the core engine.
23
+
24
+ Vue and Nuxt `.vue` files are handled the same way — Nuxt pages/layouts/components are ordinary Vue SFCs. See [Nuxt](#nuxt) below for auto-import composables.
25
+
26
+ ---
27
+
28
+ ## Installation
29
+
30
+ ```bash
31
+ npm install -D @eventra_dev/cli-plugin-vue @eventra_dev/eventra-cli
32
+ # or
33
+ pnpm add -D @eventra_dev/cli-plugin-vue @eventra_dev/eventra-cli
34
+ ```
35
+
36
+ Enable it in `eventra.json`:
37
+
38
+ ```json
39
+ {
40
+ "plugins": ["@eventra_dev/cli-plugin-vue"],
41
+ "sync": {
42
+ "include": ["**/*.{ts,tsx,js,jsx}"],
43
+ "exclude": ["node_modules", "dist", ".next", ".git"]
44
+ }
45
+ }
46
+ ```
47
+
48
+ `sync.include` does **not** need `**/*.vue` added manually — the plugin registers it via `includeGlobs`.
49
+
50
+ ---
51
+
52
+ ## What gets detected
53
+
54
+ ### `<script>` / `<script setup>`
55
+
56
+ Handled exactly like a regular `.ts` file — direct SDK calls, function wrappers, variables, ternaries, cross-file propagation all apply:
57
+
58
+ ```vue
59
+ <script setup lang="ts">
60
+ import { Eventra } from "@eventra_dev/eventra-sdk";
61
+
62
+ const tracker = new Eventra({ apiKey: "YOUR_PROJECT_API_KEY" });
63
+
64
+ tracker.track("checkout.started");
65
+ </script>
66
+ ```
67
+
68
+ `<script>` + `<script setup>` in the same file are merged in source order. `defineProps`/`defineEmits`/`defineExpose`/`defineOptions`/`withDefaults` pass through untouched.
69
+
70
+ ### `<template>` — literal event attributes
71
+
72
+ ```vue
73
+ <template>
74
+ <Button event="checkout.cta" />
75
+ </template>
76
+ ```
77
+
78
+ ### `<template>` — dynamic event attributes
79
+
80
+ ```vue
81
+ <template>
82
+ <Button :event="computedEventName" />
83
+ </template>
84
+ ```
85
+
86
+ The expression is copied as-is into the same module scope as the script. If it resolves to a real script-level constant, the event name is detected normally; otherwise it's reported as a **dynamic occurrence** (same mechanism as `tracker.track(someVariable)` in plain TypeScript) instead of being silently dropped.
87
+
88
+ ### External blocks
89
+
90
+ `<script src="./logic.ts">` and `<template src="./view.html">` are resolved and read from disk.
91
+
92
+ ---
93
+
94
+ ## Nuxt
95
+
96
+ Nuxt pages, layouts, and components are ordinary `.vue` SFCs — parsed identically, no extra configuration needed.
97
+
98
+ Composables auto-imported without an explicit `import` statement (Nuxt's own composables, or your own from `composables/`/`utils/`) resolve correctly **once the project has run `nuxt prepare`/`nuxt dev`** (so `.nuxt/` exists and is wired into `tsconfig.json` — the CLI analyzes the project's real `tsconfig.json`, so Nuxt's generated ambient types are visible to it like any other TypeScript project). This includes the case where a wrapper function that calls `track()` is only reachable via auto-import: the CLI understands the `declare const x: typeof import("./module")["name"]` shape Nuxt/`unplugin-auto-import` generate for these bindings.
99
+
100
+ ---
101
+
102
+ ## Configuration
103
+
104
+ No plugin-specific config — it activates purely by being listed in `eventra.json`'s `plugins` array (see [Installation](#installation)).
105
+
106
+ ---
107
+
108
+ ## Plugin contract
109
+
110
+ ```ts
111
+ export interface CliPluginVue {
112
+ readonly id: string;
113
+ readonly version: string;
114
+ readonly includeGlobs: readonly string[];
115
+ readonly staticSinks?: readonly CliPluginStaticCalleeSink[];
116
+ match(path: string): boolean;
117
+ transform(input: { path: string; source: string }): Promise<{
118
+ modules: Array<{ path: string; content: string }>;
119
+ }>;
120
+ }
121
+ ```
122
+
123
+ No dependency on `@eventra_dev/eventra-cli` — the CLI adapts this shape internally. `.vue` → one virtual `.vue.ts` module (compiled script content, then a function wrapping synthetic calls for every template `event="..."` binding). `staticSinks` describes those synthetic calls; the CLI builds its own sink detector from them. See [`@eventra_dev/eventra-cli`'s plugin docs](https://www.npmjs.com/package/@eventra_dev/eventra-cli#plugin-contract-for-authors) for the full external-plugin contract.
124
+
125
+ ---
126
+
127
+ ## Requirements
128
+
129
+ - Node.js 18+
130
+ - `@eventra_dev/eventra-cli` as the host CLI
131
+
132
+ ---
133
+
134
+ ## Test Coverage
135
+
136
+ **15 unit tests** (vitest), covering:
137
+
138
+ | Area | Covers |
139
+ |---|---|
140
+ | SFC parsing | Script + script-setup merge order, comment safety, `src=` external files |
141
+ | Template — literal | Nested elements, `v-if`/`v-for`, slots, multiple template roots |
142
+ | Template — dynamic | Raw expression passthrough, resolution through the merged script scope |
143
+ | Script-setup macros | `defineProps`/`defineEmits` pass through without special-casing |
144
+ | Virtual module output | Single combined `.vue.ts`, export stub when script/template are empty |
145
+ | Plugin contract | `match()`, `includeGlobs`, `staticSinks`, `transform()` |
146
+
147
+ Also validated end-to-end against real Vue and Nuxt projects (including Nuxt's own generated `.nuxt/` ambient types) as part of `@eventra_dev/eventra-cli`'s test suite.
148
+
149
+ Run locally:
150
+
151
+ ```bash
152
+ pnpm --filter @eventra_dev/cli-plugin-vue test
153
+ ```
154
+
155
+ ---
156
+
157
+ ## License
158
+
159
+ MIT
@@ -0,0 +1,9 @@
1
+ import type { CliPluginVue } from "./types";
2
+ export declare function createCliPluginVue(): CliPluginVue;
3
+ declare const _default: CliPluginVue;
4
+ export default _default;
5
+ export { transformVueSfc } from "./transform";
6
+ export { buildScriptModule, parseVueSfc, scriptVirtualPath } from "./parse-vue-sfc";
7
+ export type { CliPluginStaticCalleeSink, CliPluginTransformInput, CliPluginTransformResult, CliPluginVirtualModule, CliPluginVue, } from "./types";
8
+ export type { ParsedVueSfc, TemplateEventBinding, VueScriptBlock } from "./parse-vue-sfc";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,wBAAgB,kBAAkB,IAAI,YAAY,CAejD;;AAED,wBAAoC;AAEpC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpF,YAAY,EACV,yBAAyB,EACzB,uBAAuB,EACvB,wBAAwB,EACxB,sBAAsB,EACtB,YAAY,GACb,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,YAAY,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.scriptVirtualPath = exports.parseVueSfc = exports.buildScriptModule = exports.transformVueSfc = void 0;
4
+ exports.createCliPluginVue = createCliPluginVue;
5
+ const transform_1 = require("./transform");
6
+ function createCliPluginVue() {
7
+ return {
8
+ id: "vue",
9
+ version: "0.1.0",
10
+ includeGlobs: ["**/*.vue"],
11
+ staticSinks: [
12
+ {
13
+ id: "vue-template-event",
14
+ callee: "__eventra_vue_template_event__",
15
+ eventNameArgumentIndex: 0,
16
+ },
17
+ ],
18
+ match: (path) => path.endsWith(".vue"),
19
+ transform: transform_1.transformVueSfc,
20
+ };
21
+ }
22
+ exports.default = createCliPluginVue();
23
+ var transform_2 = require("./transform");
24
+ Object.defineProperty(exports, "transformVueSfc", { enumerable: true, get: function () { return transform_2.transformVueSfc; } });
25
+ var parse_vue_sfc_1 = require("./parse-vue-sfc");
26
+ Object.defineProperty(exports, "buildScriptModule", { enumerable: true, get: function () { return parse_vue_sfc_1.buildScriptModule; } });
27
+ Object.defineProperty(exports, "parseVueSfc", { enumerable: true, get: function () { return parse_vue_sfc_1.parseVueSfc; } });
28
+ Object.defineProperty(exports, "scriptVirtualPath", { enumerable: true, get: function () { return parse_vue_sfc_1.scriptVirtualPath; } });
@@ -0,0 +1,32 @@
1
+ export interface VueScriptBlock {
2
+ readonly lang: string;
3
+ readonly setup: boolean;
4
+ readonly content: string;
5
+ }
6
+ /** A single `event="..."` binding found on an element in the `<template>`. */
7
+ export interface TemplateEventBinding {
8
+ /** `literal`: the event name is a string constant. `dynamic`: a raw JS/TS expression, copied verbatim. */
9
+ readonly kind: "literal" | "dynamic";
10
+ readonly value: string;
11
+ }
12
+ export interface ParsedVueSfc {
13
+ readonly scripts: readonly VueScriptBlock[];
14
+ readonly templateEvents: readonly TemplateEventBinding[];
15
+ readonly errors: readonly string[];
16
+ }
17
+ /** Parse a Vue SFC via the real `@vue/compiler-sfc` parser (handles comments, `src=`, malformed markup, etc). */
18
+ export declare function parseVueSfc(source: string, filePath: string): ParsedVueSfc;
19
+ /** Map `App.vue` → `App.vue.ts` (single virtual TS module for the compiler). */
20
+ export declare function scriptVirtualPath(vuePath: string): string;
21
+ /**
22
+ * Build one virtual TS module from the parsed SFC: compiled `<script>` +
23
+ * `<script setup>` content, followed by a function wrapping synthetic calls
24
+ * for every template `event="..."` binding. Because everything shares one
25
+ * module scope, a dynamic binding (`:event="expr"`) that references a real
26
+ * top-level script identifier (an imported constant, a `<script setup>`
27
+ * const) resolves through the same checker-based pipeline as any other TS
28
+ * expression; anything that doesn't resolve (e.g. a `v-for` loop variable)
29
+ * is correctly reported as a dynamic occurrence rather than silently dropped.
30
+ */
31
+ export declare function buildScriptModule(parsed: ParsedVueSfc): string;
32
+ //# sourceMappingURL=parse-vue-sfc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-vue-sfc.d.ts","sourceRoot":"","sources":["../src/parse-vue-sfc.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,8EAA8E;AAC9E,MAAM,WAAW,oBAAoB;IACnC,0GAA0G;IAC1G,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,SAAS,cAAc,EAAE,CAAC;IAC5C,QAAQ,CAAC,cAAc,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACzD,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAyDD,iHAAiH;AACjH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAiC1E;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEzD;AAID;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CA+B9D"}
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parseVueSfc = parseVueSfc;
7
+ exports.scriptVirtualPath = scriptVirtualPath;
8
+ exports.buildScriptModule = buildScriptModule;
9
+ const node_fs_1 = __importDefault(require("node:fs"));
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ const compiler_sfc_1 = require("@vue/compiler-sfc");
12
+ const compiler_dom_1 = require("@vue/compiler-dom");
13
+ const compiler_core_1 = require("@vue/compiler-core");
14
+ function readSrcFile(sfcPath, src) {
15
+ const resolved = node_path_1.default.resolve(node_path_1.default.dirname(sfcPath), src);
16
+ try {
17
+ return node_fs_1.default.readFileSync(resolved, "utf8");
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ function collectEventBindings(root, out) {
24
+ function visitChildren(children) {
25
+ for (const child of children) {
26
+ visitNode(child);
27
+ }
28
+ }
29
+ function visitElementProps(props) {
30
+ for (const prop of props) {
31
+ if (prop.type === compiler_core_1.NodeTypes.ATTRIBUTE && prop.name === "event") {
32
+ const value = prop.value?.content?.trim();
33
+ if (value) {
34
+ out.push({ kind: "literal", value });
35
+ }
36
+ continue;
37
+ }
38
+ if (prop.type === compiler_core_1.NodeTypes.DIRECTIVE &&
39
+ prop.name === "bind" &&
40
+ prop.arg?.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION &&
41
+ prop.arg.isStatic &&
42
+ prop.arg.content === "event" &&
43
+ prop.exp?.type === compiler_core_1.NodeTypes.SIMPLE_EXPRESSION) {
44
+ const expr = prop.exp.content.trim();
45
+ if (expr) {
46
+ out.push({ kind: "dynamic", value: expr });
47
+ }
48
+ }
49
+ }
50
+ }
51
+ // `descriptor.template.ast` comes from the parse-only pass (no `transform()`
52
+ // call), so `v-if`/`v-for` elements are still plain `ElementNode`s with the
53
+ // directive attached in `props` — there is no separate IfNode/ForNode to
54
+ // handle here.
55
+ function visitNode(node) {
56
+ if (node.type === compiler_core_1.NodeTypes.ELEMENT) {
57
+ visitElementProps(node.props);
58
+ visitChildren(node.children);
59
+ }
60
+ }
61
+ visitChildren(root.children);
62
+ }
63
+ /** Parse a Vue SFC via the real `@vue/compiler-sfc` parser (handles comments, `src=`, malformed markup, etc). */
64
+ function parseVueSfc(source, filePath) {
65
+ const { descriptor, errors } = (0, compiler_sfc_1.parse)(source, { filename: filePath });
66
+ const scripts = [];
67
+ for (const block of [descriptor.script, descriptor.scriptSetup]) {
68
+ if (!block)
69
+ continue;
70
+ const content = (block.src ? readSrcFile(filePath, block.src) : block.content)?.trim();
71
+ if (!content)
72
+ continue;
73
+ scripts.push({
74
+ lang: (block.lang ?? "js").toLowerCase(),
75
+ setup: Boolean(block.setup),
76
+ content,
77
+ });
78
+ }
79
+ const templateEvents = [];
80
+ const template = descriptor.template;
81
+ if (template) {
82
+ if (template.ast) {
83
+ collectEventBindings(template.ast, templateEvents);
84
+ }
85
+ else if (template.src) {
86
+ const external = readSrcFile(filePath, template.src);
87
+ if (external) {
88
+ collectEventBindings((0, compiler_dom_1.parse)(external), templateEvents);
89
+ }
90
+ }
91
+ }
92
+ return {
93
+ scripts,
94
+ templateEvents,
95
+ errors: errors.map((error) => (error instanceof Error ? error.message : String(error))),
96
+ };
97
+ }
98
+ /** Map `App.vue` → `App.vue.ts` (single virtual TS module for the compiler). */
99
+ function scriptVirtualPath(vuePath) {
100
+ return vuePath.replace(/\.vue$/i, ".vue.ts");
101
+ }
102
+ const TEMPLATE_EVENT_CALLEE = "__eventra_vue_template_event__";
103
+ /**
104
+ * Build one virtual TS module from the parsed SFC: compiled `<script>` +
105
+ * `<script setup>` content, followed by a function wrapping synthetic calls
106
+ * for every template `event="..."` binding. Because everything shares one
107
+ * module scope, a dynamic binding (`:event="expr"`) that references a real
108
+ * top-level script identifier (an imported constant, a `<script setup>`
109
+ * const) resolves through the same checker-based pipeline as any other TS
110
+ * expression; anything that doesn't resolve (e.g. a `v-for` loop variable)
111
+ * is correctly reported as a dynamic occurrence rather than silently dropped.
112
+ */
113
+ function buildScriptModule(parsed) {
114
+ const parts = [];
115
+ if (parsed.scripts.length === 0) {
116
+ parts.push("export {}");
117
+ }
118
+ else {
119
+ for (const block of parsed.scripts) {
120
+ const header = [`// --- vue script${block.setup ? " setup" : ""} ---`];
121
+ if (block.lang !== "ts" && block.lang !== "tsx") {
122
+ header.push("// @ts-nocheck");
123
+ }
124
+ parts.push([...header, block.content].join("\n"));
125
+ }
126
+ }
127
+ if (parsed.templateEvents.length > 0) {
128
+ const lines = [
129
+ "// --- vue template (auto-generated) ---",
130
+ `declare function ${TEMPLATE_EVENT_CALLEE}(name: string): void;`,
131
+ "function __eventraVueTemplate() {",
132
+ ...parsed.templateEvents.map((binding) => binding.kind === "literal"
133
+ ? ` ${TEMPLATE_EVENT_CALLEE}("${escapeString(binding.value)}");`
134
+ : ` ${TEMPLATE_EVENT_CALLEE}(${binding.value});`),
135
+ "}",
136
+ ];
137
+ parts.push(lines.join("\n"));
138
+ }
139
+ return `${parts.join("\n\n")}\n`;
140
+ }
141
+ function escapeString(value) {
142
+ return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
143
+ }
@@ -0,0 +1,3 @@
1
+ import type { CliPluginTransformInput, CliPluginTransformResult } from "./types";
2
+ export declare function transformVueSfc(input: CliPluginTransformInput): Promise<CliPluginTransformResult>;
3
+ //# sourceMappingURL=transform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAEjF,wBAAsB,eAAe,CACnC,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,wBAAwB,CAAC,CAWnC"}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transformVueSfc = transformVueSfc;
4
+ const parse_vue_sfc_1 = require("./parse-vue-sfc");
5
+ async function transformVueSfc(input) {
6
+ const parsed = (0, parse_vue_sfc_1.parseVueSfc)(input.source, input.path);
7
+ return {
8
+ modules: [
9
+ {
10
+ path: (0, parse_vue_sfc_1.scriptVirtualPath)(input.path),
11
+ content: (0, parse_vue_sfc_1.buildScriptModule)(parsed),
12
+ },
13
+ ],
14
+ };
15
+ }
@@ -0,0 +1,33 @@
1
+ /** Input passed to a CLI plugin transform step. */
2
+ export interface CliPluginTransformInput {
3
+ readonly path: string;
4
+ readonly source: string;
5
+ }
6
+ /** Virtual module produced from a source file (e.g. Vue SFC → `.vue.ts`). */
7
+ export interface CliPluginVirtualModule {
8
+ readonly path: string;
9
+ readonly content: string;
10
+ }
11
+ /**
12
+ * Declarative sink: match `CallExpression` by callee identifier and read the
13
+ * event name from a string-literal argument. The CLI converts this to its
14
+ * internal sink detector.
15
+ */
16
+ export interface CliPluginStaticCalleeSink {
17
+ readonly id: string;
18
+ readonly callee: string;
19
+ readonly eventNameArgumentIndex: number;
20
+ }
21
+ export interface CliPluginTransformResult {
22
+ readonly modules: readonly CliPluginVirtualModule[];
23
+ }
24
+ /** Contract for `@eventra_dev/cli-plugin-vue` and compatible CLI plugins. */
25
+ export interface CliPluginVue {
26
+ readonly id: string;
27
+ readonly version: string;
28
+ readonly includeGlobs: readonly string[];
29
+ readonly staticSinks?: readonly CliPluginStaticCalleeSink[];
30
+ match(path: string): boolean;
31
+ transform(input: CliPluginTransformInput): Promise<CliPluginTransformResult>;
32
+ }
33
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,6EAA6E;AAC7E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;CACzC;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,OAAO,EAAE,SAAS,sBAAsB,EAAE,CAAC;CACrD;AAED,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAC5D,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC7B,SAAS,CAAC,KAAK,EAAE,uBAAuB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;CAC9E"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@eventra_dev/cli-plugin-vue",
3
+ "version": "0.2.1",
4
+ "description": "Eventra CLI plugin — extract track() calls from Vue SFC (.vue) files",
5
+ "license": "MIT",
6
+ "type": "commonjs",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md",
18
+ "LICENSE"
19
+ ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/and-1991/eventra-cli-plugin-vue"
23
+ },
24
+ "homepage": "https://eventra.dev",
25
+ "engines": {
26
+ "node": ">=18"
27
+ },
28
+ "scripts": {
29
+ "build": "tsc -p tsconfig.json",
30
+ "clean": "rm -rf dist",
31
+ "test": "vitest run",
32
+ "test:watch": "vitest"
33
+ },
34
+ "dependencies": {
35
+ "@vue/compiler-core": "^3.5.40",
36
+ "@vue/compiler-dom": "^3.5.40",
37
+ "@vue/compiler-sfc": "^3.5.40"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "^20.0.0",
41
+ "typescript": "^5.3.0",
42
+ "vitest": "^4.1.7"
43
+ },
44
+ "keywords": [
45
+ "eventra",
46
+ "eventra-cli",
47
+ "vue",
48
+ "vue3",
49
+ "nuxt",
50
+ "sfc",
51
+ "static-analysis",
52
+ "analytics",
53
+ "plugin"
54
+ ],
55
+ "publishConfig": {
56
+ "access": "public"
57
+ }
58
+ }