@immense/vue-pom-generator 1.0.66 → 1.0.67

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.
Files changed (53) hide show
  1. package/AGENTS.md +21 -0
  2. package/README.md +1 -0
  3. package/RELEASE_NOTES.md +78 -11
  4. package/class-generation/index.ts +16 -5
  5. package/dist/class-generation/index.d.ts.map +1 -1
  6. package/dist/compiler-metadata-utils.d.ts.map +1 -1
  7. package/dist/index.cjs +257 -78
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.mjs +257 -78
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/manifest-generator.d.ts +2 -0
  14. package/dist/manifest-generator.d.ts.map +1 -1
  15. package/dist/metadata-collector.d.ts +2 -0
  16. package/dist/metadata-collector.d.ts.map +1 -1
  17. package/dist/plugin/create-vue-pom-generator-plugins.d.ts.map +1 -1
  18. package/dist/plugin/internal/build-plugin.d.ts.map +1 -0
  19. package/dist/plugin/internal/dev-plugin.d.ts.map +1 -0
  20. package/dist/plugin/internal/virtual-modules.d.ts.map +1 -0
  21. package/dist/plugin/{support-plugins.d.ts → internal-plugins.d.ts} +14 -3
  22. package/dist/plugin/internal-plugins.d.ts.map +1 -0
  23. package/dist/plugin/runtime/annotator/client.d.ts +67 -0
  24. package/dist/plugin/runtime/annotator/client.d.ts.map +1 -0
  25. package/dist/plugin/runtime/annotator/format.d.ts +13 -0
  26. package/dist/plugin/runtime/annotator/format.d.ts.map +1 -0
  27. package/dist/plugin/runtime/annotator/plugin.d.ts +12 -0
  28. package/dist/plugin/runtime/annotator/plugin.d.ts.map +1 -0
  29. package/dist/plugin/runtime/annotator/styles.d.ts +3 -0
  30. package/dist/plugin/runtime/annotator/styles.d.ts.map +1 -0
  31. package/dist/plugin/runtime/annotator/vue-detector.d.ts +12 -0
  32. package/dist/plugin/runtime/annotator/vue-detector.d.ts.map +1 -0
  33. package/dist/plugin/types.d.ts +58 -3
  34. package/dist/plugin/types.d.ts.map +1 -1
  35. package/dist/plugin/vue-plugin.d.ts +4 -0
  36. package/dist/plugin/vue-plugin.d.ts.map +1 -1
  37. package/dist/transform.d.ts +4 -0
  38. package/dist/transform.d.ts.map +1 -1
  39. package/dist/utils.d.ts +19 -0
  40. package/dist/utils.d.ts.map +1 -1
  41. package/package.json +3 -1
  42. package/plugin/runtime/annotator/client.ts +1005 -0
  43. package/plugin/runtime/annotator/format.ts +76 -0
  44. package/plugin/runtime/annotator/plugin.ts +109 -0
  45. package/plugin/runtime/annotator/styles.ts +379 -0
  46. package/plugin/runtime/annotator/vue-detector.ts +216 -0
  47. package/dist/plugin/support/build-plugin.d.ts.map +0 -1
  48. package/dist/plugin/support/dev-plugin.d.ts.map +0 -1
  49. package/dist/plugin/support/virtual-modules.d.ts.map +0 -1
  50. package/dist/plugin/support-plugins.d.ts.map +0 -1
  51. /package/dist/plugin/{support → internal}/build-plugin.d.ts +0 -0
  52. /package/dist/plugin/{support → internal}/dev-plugin.d.ts +0 -0
  53. /package/dist/plugin/{support → internal}/virtual-modules.d.ts +0 -0
@@ -0,0 +1,76 @@
1
+ export type OutputDetail = "standard" | "forensic";
2
+
3
+ export interface FormattedAnnotation {
4
+ comment: string;
5
+ targetLabel: string;
6
+ source?: string;
7
+ component?: string;
8
+ uiText?: string;
9
+ locator?: string;
10
+ domHint?: string;
11
+ }
12
+
13
+ function normalizeInlineText(value: string | undefined): string | undefined {
14
+ const normalized = value?.replace(/\s+/g, " ").trim();
15
+ return normalized || undefined;
16
+ }
17
+
18
+ export function formatAnnotations(
19
+ annotations: FormattedAnnotation[],
20
+ detail: OutputDetail,
21
+ pageUrl: string,
22
+ ): string {
23
+ const shortUrl = pageUrl.replace(/^https?:\/\//, "");
24
+ const lines: string[] = [];
25
+
26
+ lines.push(`## Feedback — ${shortUrl}`);
27
+ lines.push(`- **URL:** ${pageUrl}`);
28
+ if (detail === "forensic" && typeof window !== "undefined") {
29
+ lines.push(`- **Viewport:** ${window.innerWidth}x${window.innerHeight}`);
30
+ }
31
+ lines.push("");
32
+
33
+ for (let i = 0; i < annotations.length; i += 1) {
34
+ const annotation = annotations[i]!;
35
+ const title = normalizeInlineText(annotation.comment) || annotation.targetLabel;
36
+ lines.push(`### ${i + 1}. ${title}`);
37
+ lines.push(`- **Source:** ${annotation.source || "Unable to find component file path."}`);
38
+
39
+ if (annotation.component) {
40
+ lines.push(`- **Component:** ${annotation.component}`);
41
+ }
42
+
43
+ lines.push(`- **Target:** \`${annotation.targetLabel}\``);
44
+
45
+ const uiText = normalizeInlineText(annotation.uiText);
46
+ if (uiText) {
47
+ lines.push(`- **UI text:** \`${uiText}\``);
48
+ }
49
+
50
+ const locator = normalizeInlineText(annotation.locator);
51
+ if (locator) {
52
+ lines.push(`- **Locator:** ${locator}`);
53
+ }
54
+
55
+ if (detail === "forensic") {
56
+ const domHint = normalizeInlineText(annotation.domHint);
57
+ if (domHint) {
58
+ lines.push(`- **DOM hint:** \`${domHint}\``);
59
+ }
60
+ }
61
+
62
+ lines.push("");
63
+ }
64
+
65
+ return lines.join("\n");
66
+ }
67
+
68
+ export function formatSingleAnnotationPreview(
69
+ annotation: FormattedAnnotation,
70
+ detail: OutputDetail,
71
+ pageUrl: string,
72
+ ): string {
73
+ const formatted = formatAnnotations([annotation], detail, pageUrl);
74
+ const headingIndex = formatted.indexOf("### 1.");
75
+ return headingIndex >= 0 ? formatted.slice(headingIndex).trim() : formatted.trim();
76
+ }
@@ -0,0 +1,109 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ import type { HtmlTagDescriptor, Plugin } from "vite";
6
+
7
+ import type { OutputDetail } from "./format";
8
+
9
+ export interface ResolvedAnnotatorUiOptions {
10
+ enabled: boolean;
11
+ sourceAttribute: string;
12
+ metadataAttributePrefix: string;
13
+ outputDetail: OutputDetail;
14
+ copyToClipboard: boolean;
15
+ showComponentTree: boolean;
16
+ }
17
+
18
+ const ANNOTATOR_CLIENT_VIRTUAL_ID = "virtual:vue-pom-generator/annotator-client";
19
+ const ANNOTATOR_CLIENT_RESOLVED_ID = `\0${ANNOTATOR_CLIENT_VIRTUAL_ID}`;
20
+ const DEFAULT_ENTRY_SUFFIXES = [
21
+ "/src/main.ts",
22
+ "/src/main.js",
23
+ "/src/main.mts",
24
+ "/src/main.tsx",
25
+ "/src/main.jsx",
26
+ ];
27
+
28
+ function toFsImportPath(filePath: string): string {
29
+ return `/@fs/${filePath.replace(/\\/g, "/")}`;
30
+ }
31
+
32
+ function resolveAnnotatorClientPath(): string {
33
+ const candidates = [
34
+ fileURLToPath(new URL("./client.ts", import.meta.url)),
35
+ fileURLToPath(new URL("../plugin/runtime/annotator/client.ts", import.meta.url)),
36
+ ];
37
+
38
+ const resolved = candidates.find(candidate => fs.existsSync(candidate));
39
+ if (!resolved) {
40
+ throw new Error("[vue-pom-generator] Unable to locate annotator client source.");
41
+ }
42
+ return path.resolve(resolved);
43
+ }
44
+
45
+ export function createAnnotatorUiPlugin(options: ResolvedAnnotatorUiOptions): Plugin {
46
+ const clientPath = resolveAnnotatorClientPath();
47
+ const clientImportPath = toFsImportPath(clientPath);
48
+ const clientOptions = JSON.stringify({
49
+ sourceAttribute: options.sourceAttribute,
50
+ metadataAttributePrefix: options.metadataAttributePrefix,
51
+ outputDetail: options.outputDetail,
52
+ copyToClipboard: options.copyToClipboard,
53
+ showComponentTree: options.showComponentTree,
54
+ });
55
+
56
+ return {
57
+ name: "vue-pom-generator:annotator-ui",
58
+ apply: "serve",
59
+ resolveId(id) {
60
+ if (id === ANNOTATOR_CLIENT_VIRTUAL_ID) {
61
+ return ANNOTATOR_CLIENT_RESOLVED_ID;
62
+ }
63
+ },
64
+ load(id) {
65
+ if (id !== ANNOTATOR_CLIENT_RESOLVED_ID) {
66
+ return null;
67
+ }
68
+
69
+ return [
70
+ `import { mountAnnotatorClient } from ${JSON.stringify(clientImportPath)};`,
71
+ `mountAnnotatorClient(${clientOptions});`,
72
+ "",
73
+ ].join("\n");
74
+ },
75
+ transform(code, id) {
76
+ if (!options.enabled) {
77
+ return null;
78
+ }
79
+
80
+ const normalizedId = id.replace(/\\/g, "/");
81
+ if (!DEFAULT_ENTRY_SUFFIXES.some(suffix => normalizedId.endsWith(suffix))) {
82
+ return null;
83
+ }
84
+
85
+ if (code.includes(ANNOTATOR_CLIENT_VIRTUAL_ID)) {
86
+ return null;
87
+ }
88
+
89
+ return {
90
+ code: `import ${JSON.stringify(ANNOTATOR_CLIENT_VIRTUAL_ID)};\n${code}`,
91
+ map: null,
92
+ };
93
+ },
94
+ transformIndexHtml() {
95
+ if (!options.enabled) {
96
+ return undefined;
97
+ }
98
+
99
+ const tag: HtmlTagDescriptor = {
100
+ tag: "script",
101
+ attrs: { type: "module" },
102
+ children: `import ${JSON.stringify(ANNOTATOR_CLIENT_VIRTUAL_ID)};`,
103
+ injectTo: "body",
104
+ };
105
+
106
+ return [tag];
107
+ },
108
+ };
109
+ }
@@ -0,0 +1,379 @@
1
+ export const ANNOTATOR_ROOT_ATTR = "data-vpg-annotator-root";
2
+
3
+ export const ANNOTATOR_STYLES = `
4
+ [${ANNOTATOR_ROOT_ATTR}] {
5
+ --vpg-annotator-accent: #4f46e5;
6
+ --vpg-annotator-accent-strong: #4338ca;
7
+ --vpg-annotator-bg: rgba(15, 23, 42, 0.96);
8
+ --vpg-annotator-bg-soft: rgba(30, 41, 59, 0.96);
9
+ --vpg-annotator-border: rgba(148, 163, 184, 0.28);
10
+ --vpg-annotator-text: #e2e8f0;
11
+ --vpg-annotator-text-soft: #94a3b8;
12
+ --vpg-annotator-shadow: 0 16px 40px rgba(15, 23, 42, 0.26);
13
+ --vpg-annotator-radius: 0px;
14
+ --vpg-annotator-edge-offset: 20px;
15
+ color: var(--vpg-annotator-text);
16
+ font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
17
+ }
18
+
19
+ [${ANNOTATOR_ROOT_ATTR}],
20
+ [${ANNOTATOR_ROOT_ATTR}] *,
21
+ [${ANNOTATOR_ROOT_ATTR}] *::before,
22
+ [${ANNOTATOR_ROOT_ATTR}] *::after {
23
+ box-sizing: border-box;
24
+ }
25
+
26
+ .vpg-annotator-layer {
27
+ position: fixed;
28
+ inset: 0;
29
+ pointer-events: none;
30
+ }
31
+
32
+ .vpg-annotator-layer--markers {
33
+ z-index: 2147483646;
34
+ }
35
+
36
+ .vpg-annotator-layer--panels {
37
+ z-index: 2147483647;
38
+ }
39
+
40
+ .vpg-annotator-toolbar,
41
+ .vpg-annotator-panel,
42
+ .vpg-annotator-input,
43
+ .vpg-annotator-settings,
44
+ .vpg-annotator-toast {
45
+ background: var(--vpg-annotator-bg);
46
+ border: 1px solid var(--vpg-annotator-border);
47
+ box-shadow: var(--vpg-annotator-shadow);
48
+ backdrop-filter: blur(18px);
49
+ }
50
+
51
+ .vpg-annotator-toolbar {
52
+ position: fixed;
53
+ right: var(--vpg-annotator-edge-offset);
54
+ bottom: var(--vpg-annotator-edge-offset);
55
+ z-index: 2147483647;
56
+ display: flex;
57
+ gap: 8px;
58
+ align-items: center;
59
+ padding: 8px;
60
+ border-radius: var(--vpg-annotator-radius);
61
+ user-select: none;
62
+ }
63
+
64
+ .vpg-annotator-toolbar-handle,
65
+ .vpg-annotator-btn {
66
+ appearance: none;
67
+ display: inline-flex;
68
+ align-items: center;
69
+ justify-content: center;
70
+ min-width: 32px;
71
+ min-height: 32px;
72
+ padding: 7px 10px;
73
+ border: 1px solid var(--vpg-annotator-border);
74
+ border-radius: var(--vpg-annotator-radius);
75
+ background: var(--vpg-annotator-bg-soft);
76
+ color: var(--vpg-annotator-text);
77
+ font-size: 12px;
78
+ font-weight: 600;
79
+ line-height: 1;
80
+ }
81
+
82
+ .vpg-annotator-toolbar-handle {
83
+ padding: 0;
84
+ cursor: grab;
85
+ touch-action: none;
86
+ }
87
+
88
+ .vpg-annotator-toolbar--dragging,
89
+ .vpg-annotator-toolbar--dragging * {
90
+ cursor: grabbing !important;
91
+ }
92
+
93
+ .vpg-annotator-btn {
94
+ cursor: pointer;
95
+ }
96
+
97
+ .vpg-annotator-btn--icon {
98
+ width: 32px;
99
+ padding: 0;
100
+ }
101
+
102
+ .vpg-annotator-btn:hover,
103
+ .vpg-annotator-toolbar-handle:hover {
104
+ border-color: rgba(99, 102, 241, 0.45);
105
+ }
106
+
107
+ .vpg-annotator-btn:disabled {
108
+ opacity: 0.45;
109
+ cursor: not-allowed;
110
+ }
111
+
112
+ .vpg-annotator-btn--primary,
113
+ .vpg-annotator-btn[aria-pressed="true"] {
114
+ background: var(--vpg-annotator-accent);
115
+ border-color: var(--vpg-annotator-accent);
116
+ color: white;
117
+ }
118
+
119
+ .vpg-annotator-icon {
120
+ width: 16px;
121
+ height: 16px;
122
+ display: inline-flex;
123
+ align-items: center;
124
+ justify-content: center;
125
+ }
126
+
127
+ .vpg-annotator-icon svg {
128
+ width: 100%;
129
+ height: 100%;
130
+ display: block;
131
+ fill: none;
132
+ stroke: currentColor;
133
+ stroke-width: 1.5;
134
+ stroke-linecap: round;
135
+ stroke-linejoin: round;
136
+ }
137
+
138
+ .vpg-annotator-count {
139
+ padding-left: 4px;
140
+ white-space: nowrap;
141
+ }
142
+
143
+ .vpg-annotator-panel,
144
+ .vpg-annotator-input,
145
+ .vpg-annotator-settings {
146
+ position: fixed;
147
+ z-index: 2147483647;
148
+ min-width: 300px;
149
+ max-width: min(560px, calc(100vw - 24px));
150
+ border-radius: var(--vpg-annotator-radius);
151
+ overflow: visible;
152
+ pointer-events: auto;
153
+ visibility: hidden;
154
+ }
155
+
156
+ .vpg-annotator-settings {
157
+ min-width: 260px;
158
+ max-width: min(320px, calc(100vw - 24px));
159
+ }
160
+
161
+ .vpg-annotator-arrow {
162
+ position: absolute;
163
+ z-index: 0;
164
+ width: 14px;
165
+ height: 14px;
166
+ background: var(--vpg-annotator-bg);
167
+ border: 1px solid var(--vpg-annotator-border);
168
+ transform: rotate(45deg);
169
+ }
170
+
171
+ .vpg-annotator-panel[data-placement^="top"] .vpg-annotator-arrow,
172
+ .vpg-annotator-input[data-placement^="top"] .vpg-annotator-arrow,
173
+ .vpg-annotator-settings[data-placement^="top"] .vpg-annotator-arrow {
174
+ border-top: none;
175
+ border-left: none;
176
+ }
177
+
178
+ .vpg-annotator-panel[data-placement^="bottom"] .vpg-annotator-arrow,
179
+ .vpg-annotator-input[data-placement^="bottom"] .vpg-annotator-arrow,
180
+ .vpg-annotator-settings[data-placement^="bottom"] .vpg-annotator-arrow {
181
+ border-right: none;
182
+ border-bottom: none;
183
+ }
184
+
185
+ .vpg-annotator-panel[data-placement^="left"] .vpg-annotator-arrow,
186
+ .vpg-annotator-input[data-placement^="left"] .vpg-annotator-arrow,
187
+ .vpg-annotator-settings[data-placement^="left"] .vpg-annotator-arrow {
188
+ border-left: none;
189
+ border-bottom: none;
190
+ }
191
+
192
+ .vpg-annotator-panel[data-placement^="right"] .vpg-annotator-arrow,
193
+ .vpg-annotator-input[data-placement^="right"] .vpg-annotator-arrow,
194
+ .vpg-annotator-settings[data-placement^="right"] .vpg-annotator-arrow {
195
+ border-top: none;
196
+ border-right: none;
197
+ }
198
+
199
+ .vpg-annotator-panel-body,
200
+ .vpg-annotator-input-body,
201
+ .vpg-annotator-settings-body {
202
+ position: relative;
203
+ z-index: 1;
204
+ padding: 14px;
205
+ }
206
+
207
+ .vpg-annotator-heading {
208
+ margin: 0 0 6px;
209
+ font-size: 13px;
210
+ font-weight: 700;
211
+ }
212
+
213
+ .vpg-annotator-subtle {
214
+ margin: 0;
215
+ font-size: 12px;
216
+ color: var(--vpg-annotator-text-soft);
217
+ }
218
+
219
+ .vpg-annotator-textarea,
220
+ .vpg-annotator-comment,
221
+ .vpg-annotator-select {
222
+ width: 100%;
223
+ border: 1px solid var(--vpg-annotator-border);
224
+ border-radius: var(--vpg-annotator-radius);
225
+ background: rgba(15, 23, 42, 0.72);
226
+ color: var(--vpg-annotator-text);
227
+ }
228
+
229
+ .vpg-annotator-textarea,
230
+ .vpg-annotator-comment {
231
+ padding: 10px 12px;
232
+ font-size: 12px;
233
+ line-height: 1.55;
234
+ }
235
+
236
+ .vpg-annotator-textarea {
237
+ min-height: 220px;
238
+ margin-top: 12px;
239
+ resize: vertical;
240
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
241
+ }
242
+
243
+ .vpg-annotator-comment {
244
+ min-height: 92px;
245
+ resize: vertical;
246
+ font-family: inherit;
247
+ }
248
+
249
+ .vpg-annotator-input-meta {
250
+ min-height: 160px;
251
+ margin-bottom: 10px;
252
+ }
253
+
254
+ .vpg-annotator-row {
255
+ display: flex;
256
+ align-items: center;
257
+ justify-content: space-between;
258
+ gap: 12px;
259
+ margin-top: 12px;
260
+ }
261
+
262
+ .vpg-annotator-actions {
263
+ display: flex;
264
+ gap: 8px;
265
+ justify-content: flex-end;
266
+ margin-top: 12px;
267
+ }
268
+
269
+ .vpg-annotator-field {
270
+ display: grid;
271
+ gap: 6px;
272
+ margin-top: 12px;
273
+ }
274
+
275
+ .vpg-annotator-shortcuts {
276
+ display: grid;
277
+ gap: 8px;
278
+ }
279
+
280
+ .vpg-annotator-shortcut-row {
281
+ display: flex;
282
+ align-items: center;
283
+ justify-content: space-between;
284
+ gap: 12px;
285
+ }
286
+
287
+ .vpg-annotator-label {
288
+ font-size: 12px;
289
+ font-weight: 600;
290
+ color: var(--vpg-annotator-text-soft);
291
+ }
292
+
293
+ .vpg-annotator-select,
294
+ .vpg-annotator-checkbox {
295
+ accent-color: var(--vpg-annotator-accent);
296
+ }
297
+
298
+ .vpg-annotator-select {
299
+ padding: 8px 10px;
300
+ }
301
+
302
+ .vpg-annotator-kbd {
303
+ min-width: 32px;
304
+ padding: 4px 8px;
305
+ border: 1px solid var(--vpg-annotator-border);
306
+ border-radius: var(--vpg-annotator-radius);
307
+ background: rgba(15, 23, 42, 0.72);
308
+ color: var(--vpg-annotator-text);
309
+ font: inherit;
310
+ font-size: 11px;
311
+ font-weight: 700;
312
+ line-height: 1;
313
+ text-align: center;
314
+ }
315
+
316
+ .vpg-annotator-highlight {
317
+ position: fixed;
318
+ z-index: 2147483646;
319
+ pointer-events: none;
320
+ border: 2px solid var(--vpg-annotator-accent);
321
+ border-radius: var(--vpg-annotator-radius);
322
+ background: rgba(79, 70, 229, 0.08);
323
+ box-shadow: inset 0 0 0 1px rgba(255,255,255,0.08);
324
+ }
325
+
326
+ .vpg-annotator-highlight-label {
327
+ position: absolute;
328
+ left: 0;
329
+ top: -30px;
330
+ max-width: min(520px, calc(100vw - 24px));
331
+ overflow: hidden;
332
+ text-overflow: ellipsis;
333
+ white-space: nowrap;
334
+ border-radius: var(--vpg-annotator-radius);
335
+ background: var(--vpg-annotator-accent);
336
+ color: white;
337
+ padding: 5px 10px;
338
+ font-size: 12px;
339
+ font-weight: 700;
340
+ }
341
+
342
+ .vpg-annotator-shield {
343
+ position: fixed;
344
+ inset: 0;
345
+ z-index: 2147483645;
346
+ background: transparent;
347
+ }
348
+
349
+ .vpg-annotator-marker {
350
+ position: absolute;
351
+ z-index: 2147483646;
352
+ display: flex;
353
+ align-items: center;
354
+ justify-content: center;
355
+ width: 24px;
356
+ height: 24px;
357
+ pointer-events: auto;
358
+ border: none;
359
+ border-radius: var(--vpg-annotator-radius);
360
+ background: var(--vpg-annotator-accent);
361
+ color: white;
362
+ font-size: 12px;
363
+ font-weight: 700;
364
+ cursor: pointer;
365
+ box-shadow: 0 8px 20px rgba(15, 23, 42, 0.28);
366
+ }
367
+
368
+ .vpg-annotator-toast {
369
+ position: fixed;
370
+ right: 24px;
371
+ bottom: 86px;
372
+ z-index: 2147483647;
373
+ padding: 8px 12px;
374
+ border-radius: var(--vpg-annotator-radius);
375
+ color: var(--vpg-annotator-text);
376
+ font-size: 12px;
377
+ font-weight: 600;
378
+ }
379
+ `;