web-remarq 0.2.5 → 0.3.0

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.
@@ -217,12 +217,54 @@ var WebRemarq = (() => {
217
217
  return result;
218
218
  }
219
219
 
220
+ // src/core/source-detect.ts
221
+ function detectRemarqPlugin(el) {
222
+ const source = el.getAttribute("data-remarq-source");
223
+ if (!source) return { source: null, component: null };
224
+ return {
225
+ source,
226
+ component: el.getAttribute("data-remarq-component")
227
+ };
228
+ }
229
+ function detectExternalSource(el) {
230
+ var _a;
231
+ const source = (_a = el.dataset.source) != null ? _a : el.getAttribute("data-locator");
232
+ if (!source) return { source: null, component: null };
233
+ return { source, component: null };
234
+ }
235
+ function detectReactFiber(el) {
236
+ var _a, _b, _c, _d;
237
+ const key = Object.keys(el).find((k) => k.startsWith("__reactFiber$"));
238
+ if (!key) return { source: null, component: null };
239
+ let current = el[key];
240
+ let depth = 0;
241
+ while (current && depth < 15) {
242
+ const debugSource = current._debugSource;
243
+ if (debugSource == null ? void 0 : debugSource.fileName) {
244
+ const source = `${debugSource.fileName}:${(_a = debugSource.lineNumber) != null ? _a : 0}:${(_b = debugSource.columnNumber) != null ? _b : 0}`;
245
+ const fiberType = current.type;
246
+ const component = typeof fiberType === "object" && fiberType ? (_d = (_c = fiberType.displayName) != null ? _c : fiberType.name) != null ? _d : null : null;
247
+ return { source, component };
248
+ }
249
+ current = current.return;
250
+ depth++;
251
+ }
252
+ return { source: null, component: null };
253
+ }
254
+ function detectSource(el) {
255
+ const external = detectExternalSource(el);
256
+ if (external.source) return external;
257
+ const fiber = detectReactFiber(el);
258
+ if (fiber.source) return fiber;
259
+ return { source: null, component: null };
260
+ }
261
+
220
262
  // src/core/fingerprint.ts
221
263
  var TEXT_MAX_LENGTH = 50;
222
264
  function createFingerprint(el, options2) {
223
265
  var _a, _b, _c, _d, _e, _f, _g;
224
266
  const dataAttr = (_a = options2 == null ? void 0 : options2.dataAttribute) != null ? _a : "data-annotate";
225
- return {
267
+ return __spreadValues({
226
268
  dataAnnotate: (_b = el.getAttribute(dataAttr)) != null ? _b : null,
227
269
  dataTestId: (_e = (_d = (_c = el.getAttribute("data-testid")) != null ? _c : el.getAttribute("data-test")) != null ? _d : el.getAttribute("data-cy")) != null ? _e : null,
228
270
  id: getStableId(el),
@@ -239,6 +281,24 @@ var WebRemarq = (() => {
239
281
  parentAnchor: findParentAnchor(el, dataAttr),
240
282
  rawClasses: Array.from(el.classList),
241
283
  cssModules: decomposeCSSModules(Array.from(el.classList))
284
+ }, resolveSourceFields(el));
285
+ }
286
+ function resolveSourceFields(el) {
287
+ const plugin = detectRemarqPlugin(el);
288
+ if (plugin.source) {
289
+ return {
290
+ sourceLocation: plugin.source,
291
+ componentName: plugin.component,
292
+ detectedSource: null,
293
+ detectedComponent: null
294
+ };
295
+ }
296
+ const detected = detectSource(el);
297
+ return {
298
+ sourceLocation: null,
299
+ componentName: null,
300
+ detectedSource: detected.source,
301
+ detectedComponent: detected.component
242
302
  };
243
303
  }
244
304
  function getStableId(el) {
@@ -424,6 +484,88 @@ var WebRemarq = (() => {
424
484
  return bestScore >= MATCH_THRESHOLD ? bestEl : null;
425
485
  }
426
486
 
487
+ // src/core/agent-export.ts
488
+ function parseSourceLocation(raw) {
489
+ const parts = raw.split(":");
490
+ if (parts.length < 2) return null;
491
+ const column = parseInt(parts.pop(), 10);
492
+ const line = parseInt(parts.pop(), 10);
493
+ const file = parts.join(":");
494
+ if (!file || isNaN(line)) return null;
495
+ return { file, line, column: isNaN(column) ? 0 : column };
496
+ }
497
+ function resolveSource(fp) {
498
+ var _a, _b;
499
+ if (fp.sourceLocation) {
500
+ const parsed = parseSourceLocation(fp.sourceLocation);
501
+ if (parsed) return __spreadProps(__spreadValues({}, parsed), { component: (_a = fp.componentName) != null ? _a : null });
502
+ }
503
+ if (fp.detectedSource) {
504
+ const parsed = parseSourceLocation(fp.detectedSource);
505
+ if (parsed) return __spreadProps(__spreadValues({}, parsed), { component: (_b = fp.detectedComponent) != null ? _b : null });
506
+ }
507
+ return null;
508
+ }
509
+ var TEMPLATE_GLOB = "*.{tsx,jsx,vue,svelte,html}";
510
+ var CSS_MODULE_GLOB = "*.module.{css,scss,less}";
511
+ var COMPONENT_GLOB = "*.{tsx,jsx,vue,ts,js}";
512
+ function buildSearchHints(fp) {
513
+ var _a, _b;
514
+ const grepQueries = [];
515
+ if (fp.dataAnnotate) {
516
+ grepQueries.push({ query: `data-annotate="${fp.dataAnnotate}"`, glob: TEMPLATE_GLOB, confidence: "high" });
517
+ }
518
+ if (fp.dataTestId) {
519
+ grepQueries.push({ query: `data-testid="${fp.dataTestId}"`, glob: TEMPLATE_GLOB, confidence: "high" });
520
+ }
521
+ if (fp.id) {
522
+ grepQueries.push({ query: `id="${fp.id}"`, glob: TEMPLATE_GLOB, confidence: "high" });
523
+ }
524
+ if (fp.ariaLabel) {
525
+ grepQueries.push({ query: `aria-label="${fp.ariaLabel}"`, glob: TEMPLATE_GLOB, confidence: "high" });
526
+ }
527
+ if (fp.textContent) {
528
+ grepQueries.push({ query: `"${fp.textContent}"`, glob: TEMPLATE_GLOB, confidence: "medium" });
529
+ }
530
+ if (fp.role) {
531
+ grepQueries.push({ query: `role="${fp.role}"`, glob: TEMPLATE_GLOB, confidence: "medium" });
532
+ }
533
+ if ((_a = fp.cssModules) == null ? void 0 : _a.length) {
534
+ for (const mod of fp.cssModules) {
535
+ grepQueries.push({ query: `.${mod.localName}`, glob: CSS_MODULE_GLOB, confidence: "medium" });
536
+ grepQueries.push({ query: `styles.${mod.localName}`, glob: COMPONENT_GLOB, confidence: "medium" });
537
+ }
538
+ }
539
+ if (fp.stableClasses.length) {
540
+ for (const cls of fp.stableClasses.slice(0, 3)) {
541
+ grepQueries.push({ query: `"${cls}"`, glob: TEMPLATE_GLOB, confidence: "low" });
542
+ }
543
+ }
544
+ return {
545
+ grepQueries,
546
+ domContext: fp.domPath,
547
+ tagName: fp.tagName,
548
+ classes: (_b = fp.rawClasses) != null ? _b : fp.stableClasses
549
+ };
550
+ }
551
+ function generateAgentExport(annotations, viewportBucket) {
552
+ const agentAnnotations = annotations.map((ann) => ({
553
+ id: ann.id,
554
+ route: ann.route,
555
+ comment: ann.comment,
556
+ status: ann.status,
557
+ timestamp: ann.timestamp,
558
+ source: resolveSource(ann.fingerprint),
559
+ searchHints: buildSearchHints(ann.fingerprint)
560
+ }));
561
+ return {
562
+ version: 1,
563
+ format: "agent",
564
+ viewportBucket,
565
+ annotations: agentAnnotations
566
+ };
567
+ }
568
+
427
569
  // src/ui/styles.ts
428
570
  var STYLES_ID = "data-remarq-styles";
429
571
  var CSS = `
@@ -1978,6 +2120,22 @@ var WebRemarq = (() => {
1978
2120
  console.warn("[web-remarq] Clipboard write failed");
1979
2121
  });
1980
2122
  }
2123
+ function exportAgent() {
2124
+ const anns = storage.getAll();
2125
+ if (!anns.length) return;
2126
+ const data = generateAgentExport(anns, toBucket(window.innerWidth));
2127
+ const json = JSON.stringify(data, null, 2);
2128
+ downloadFile(json, `remarq-agent-${Date.now()}.json`, "application/json");
2129
+ }
2130
+ function copyAgentToClipboard() {
2131
+ const anns = storage.getAll();
2132
+ if (!anns.length) return;
2133
+ const data = generateAgentExport(anns, toBucket(window.innerWidth));
2134
+ const json = JSON.stringify(data, null, 2);
2135
+ navigator.clipboard.writeText(json).catch(() => {
2136
+ console.warn("[web-remarq] Clipboard write failed");
2137
+ });
2138
+ }
1981
2139
  function setupMutationObserver() {
1982
2140
  mutationObserver = new MutationObserver((mutations) => {
1983
2141
  for (const m of mutations) {
@@ -2083,10 +2241,12 @@ var WebRemarq = (() => {
2083
2241
  },
2084
2242
  export(format) {
2085
2243
  if (format === "md") exportMarkdown();
2086
- else exportJSON();
2244
+ else if (format === "json") exportJSON();
2245
+ else exportAgent();
2087
2246
  },
2088
- copy() {
2089
- copyToClipboard();
2247
+ copy(format) {
2248
+ if (format === "agent") copyAgentToClipboard();
2249
+ else copyToClipboard();
2090
2250
  },
2091
2251
  async import(file) {
2092
2252
  const text = await file.text();