@impakers/debug 1.4.6 → 1.4.7

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/dist/react.mjs CHANGED
@@ -1535,23 +1535,59 @@ function findNearestComponentSource(element, maxAncestors = 10) {
1535
1535
  }
1536
1536
 
1537
1537
  // src/utils/capture-element.ts
1538
- var UNSUPPORTED_COLOR_RE = /oklab|oklch|color-mix/i;
1539
- var COLOR_DECLARATION_RE = /[^{};\n]+:\s*[^;{}]*(?:oklab|oklch|color-mix|lch|lab)\([^)]*(?:\([^)]*\))*[^)]*\)[^;{}]*/gi;
1538
+ var UNSUPPORTED_RE = /oklab|oklch|color-mix/i;
1540
1539
  function sanitizeUnsupportedColors(clonedDoc) {
1540
+ try {
1541
+ for (let i = 0; i < clonedDoc.styleSheets.length; i++) {
1542
+ try {
1543
+ const sheet = clonedDoc.styleSheets[i];
1544
+ const rules = sheet.cssRules || sheet.rules;
1545
+ if (!rules) continue;
1546
+ sanitizeCSSRules(sheet, rules);
1547
+ } catch {
1548
+ }
1549
+ }
1550
+ } catch {
1551
+ }
1541
1552
  clonedDoc.querySelectorAll("style").forEach((styleEl) => {
1542
1553
  const text = styleEl.textContent || "";
1543
- if (UNSUPPORTED_COLOR_RE.test(text)) {
1544
- styleEl.textContent = text.replace(COLOR_DECLARATION_RE, "");
1554
+ if (UNSUPPORTED_RE.test(text)) {
1555
+ styleEl.textContent = text.replace(
1556
+ /[^{};\n]+:\s*[^;{}]*(?:oklab|oklch|color-mix|lch|lab)\([^)]*(?:\([^)]*\))*[^)]*\)[^;{}]*/gi,
1557
+ ""
1558
+ );
1545
1559
  }
1546
1560
  });
1547
1561
  clonedDoc.querySelectorAll("*").forEach((el) => {
1548
1562
  const s = el.style;
1549
1563
  if (!s?.cssText) return;
1550
- if (UNSUPPORTED_COLOR_RE.test(s.cssText)) {
1551
- s.cssText = s.cssText.replace(COLOR_DECLARATION_RE, "");
1564
+ if (UNSUPPORTED_RE.test(s.cssText)) {
1565
+ s.cssText = s.cssText.replace(
1566
+ /[^;]*(?:oklab|oklch|color-mix|lch|lab)\([^)]*(?:\([^)]*\))*[^)]*\)[^;]*/gi,
1567
+ ""
1568
+ );
1552
1569
  }
1553
1570
  });
1554
1571
  }
1572
+ function sanitizeCSSRules(sheet, rules) {
1573
+ for (let j = rules.length - 1; j >= 0; j--) {
1574
+ const rule = rules[j];
1575
+ if ("cssRules" in rule && rule.cssRules) {
1576
+ sanitizeCSSRules(sheet, rule.cssRules);
1577
+ continue;
1578
+ }
1579
+ if (rule instanceof CSSStyleRule) {
1580
+ const style = rule.style;
1581
+ for (let k = style.length - 1; k >= 0; k--) {
1582
+ const prop = style[k];
1583
+ const val = style.getPropertyValue(prop);
1584
+ if (UNSUPPORTED_RE.test(val)) {
1585
+ style.setProperty(prop, "transparent");
1586
+ }
1587
+ }
1588
+ }
1589
+ }
1590
+ }
1555
1591
  async function captureElement(el, options = {}) {
1556
1592
  const { quality = 0.7, maxScale = 2 } = options;
1557
1593
  const html2canvas = (await import("html2canvas")).default;
@@ -1804,6 +1840,151 @@ function collectMetadata(getUser) {
1804
1840
  return metadata;
1805
1841
  }
1806
1842
 
1843
+ // src/core/debug-targets.ts
1844
+ var NEXT_ROUTE_MANIFEST_URL = "/_next/static/chunks/impakers-debug-route-manifest.json";
1845
+ var manifestPromise = null;
1846
+ var manifestFailed = false;
1847
+ function normalizePathname(pathname) {
1848
+ if (!pathname || pathname === "/") return "/";
1849
+ return pathname.endsWith("/") ? pathname.slice(0, -1) || "/" : pathname;
1850
+ }
1851
+ function splitPathname(pathname) {
1852
+ const normalized = normalizePathname(pathname);
1853
+ if (normalized === "/") return [];
1854
+ return normalized.slice(1).split("/").map((segment) => decodeURIComponent(segment)).filter(Boolean);
1855
+ }
1856
+ function isDynamicSegment(segment) {
1857
+ return /^\[[^\]]+\]$/.test(segment);
1858
+ }
1859
+ function isCatchAllSegment(segment) {
1860
+ return /^\[\.\.\.[^\]]+\]$/.test(segment);
1861
+ }
1862
+ function isOptionalCatchAllSegment(segment) {
1863
+ return /^\[\[\.\.\.[^\]]+\]\]$/.test(segment);
1864
+ }
1865
+ function scoreRouteMatch(routeSegments, pathnameSegments) {
1866
+ let routeIndex = 0;
1867
+ let pathIndex = 0;
1868
+ let score = 0;
1869
+ while (routeIndex < routeSegments.length) {
1870
+ const routeSegment = routeSegments[routeIndex];
1871
+ if (isOptionalCatchAllSegment(routeSegment)) {
1872
+ score += 1;
1873
+ pathIndex = pathnameSegments.length;
1874
+ routeIndex += 1;
1875
+ break;
1876
+ }
1877
+ if (isCatchAllSegment(routeSegment)) {
1878
+ if (pathIndex >= pathnameSegments.length) return null;
1879
+ score += 2;
1880
+ pathIndex = pathnameSegments.length;
1881
+ routeIndex += 1;
1882
+ break;
1883
+ }
1884
+ const pathSegment = pathnameSegments[pathIndex];
1885
+ if (pathSegment === void 0) return null;
1886
+ if (isDynamicSegment(routeSegment)) {
1887
+ score += 5;
1888
+ routeIndex += 1;
1889
+ pathIndex += 1;
1890
+ continue;
1891
+ }
1892
+ if (routeSegment !== pathSegment) return null;
1893
+ score += 20;
1894
+ routeIndex += 1;
1895
+ pathIndex += 1;
1896
+ }
1897
+ if (routeIndex !== routeSegments.length) return null;
1898
+ if (pathIndex !== pathnameSegments.length) return null;
1899
+ return score;
1900
+ }
1901
+ async function loadNextRouteManifest() {
1902
+ if (manifestFailed) return null;
1903
+ if (manifestPromise) return manifestPromise;
1904
+ manifestPromise = (async () => {
1905
+ try {
1906
+ const res = await fetch(NEXT_ROUTE_MANIFEST_URL, { cache: "force-cache" });
1907
+ if (!res.ok) {
1908
+ manifestFailed = true;
1909
+ return null;
1910
+ }
1911
+ const json = await res.json();
1912
+ if (!json || typeof json !== "object" || !Array.isArray(json.entries)) {
1913
+ manifestFailed = true;
1914
+ return null;
1915
+ }
1916
+ return json;
1917
+ } catch {
1918
+ manifestFailed = true;
1919
+ return null;
1920
+ }
1921
+ })();
1922
+ return manifestPromise;
1923
+ }
1924
+ function buildRouteTargets(entry) {
1925
+ const pageTarget = entry.files.find((file) => file.kind === "page");
1926
+ const layoutTargets = entry.files.filter((file) => file.kind === "layout");
1927
+ const targets = [];
1928
+ if (pageTarget) {
1929
+ targets.push({
1930
+ kind: "route-page",
1931
+ file: pageTarget.file,
1932
+ label: "Current page route",
1933
+ confidence: 1,
1934
+ reason: "matched-current-url"
1935
+ });
1936
+ }
1937
+ layoutTargets.forEach((layout, index) => {
1938
+ targets.push({
1939
+ kind: "route-layout",
1940
+ file: layout.file,
1941
+ label: index === layoutTargets.length - 1 ? "Nearest layout" : "Ancestor layout",
1942
+ confidence: Math.max(0.7, 0.95 - index * 0.08),
1943
+ reason: "matched-layout-chain"
1944
+ });
1945
+ });
1946
+ return targets;
1947
+ }
1948
+ async function getRouteDebugTargets(pathname) {
1949
+ if (typeof window === "undefined") return null;
1950
+ const currentPathname = pathname ?? window.location.pathname;
1951
+ const manifest = await loadNextRouteManifest();
1952
+ if (!manifest) return null;
1953
+ const pathnameSegments = splitPathname(currentPathname);
1954
+ let bestEntry = null;
1955
+ let bestScore = -1;
1956
+ for (const entry of manifest.entries) {
1957
+ const score = scoreRouteMatch(entry.segments, pathnameSegments);
1958
+ if (score === null) continue;
1959
+ if (score > bestScore) {
1960
+ bestScore = score;
1961
+ bestEntry = entry;
1962
+ }
1963
+ }
1964
+ if (!bestEntry) return null;
1965
+ return {
1966
+ targets: buildRouteTargets(bestEntry),
1967
+ context: {
1968
+ pathname: normalizePathname(currentPathname),
1969
+ matchedRoute: bestEntry.route,
1970
+ source: "next-route-manifest"
1971
+ }
1972
+ };
1973
+ }
1974
+ function mergeDebugTargets(...groups) {
1975
+ const merged = [];
1976
+ const seen = /* @__PURE__ */ new Set();
1977
+ groups.forEach((group) => {
1978
+ group?.forEach((target) => {
1979
+ const key = `${target.kind}:${target.file}:${target.line ?? ""}:${target.column ?? ""}`;
1980
+ if (seen.has(key)) return;
1981
+ seen.add(key);
1982
+ merged.push(target);
1983
+ });
1984
+ });
1985
+ return merged.sort((a, b) => b.confidence - a.confidence);
1986
+ }
1987
+
1807
1988
  // src/core/api.ts
1808
1989
  function getToken() {
1809
1990
  const token = loadToken();
@@ -3371,6 +3552,23 @@ function detectSourceFileCandidates(element) {
3371
3552
  }
3372
3553
  return [];
3373
3554
  }
3555
+ function buildComponentDebugTarget(resolvedSource, componentName) {
3556
+ const match = resolvedSource.match(/^(.+):(\d+)(?::(\d+))?$/);
3557
+ if (!match) return null;
3558
+ const [, file, lineStr, columnStr] = match;
3559
+ const line = Number.parseInt(lineStr, 10);
3560
+ const column = columnStr ? Number.parseInt(columnStr, 10) : void 0;
3561
+ if (!file || Number.isNaN(line)) return null;
3562
+ return {
3563
+ kind: "component",
3564
+ file,
3565
+ line,
3566
+ column,
3567
+ label: componentName || "Resolved component source",
3568
+ confidence: 0.98,
3569
+ reason: "resolved-from-source-map"
3570
+ };
3571
+ }
3374
3572
  var STORAGE_PREFIX = "impakers-debug-markers-";
3375
3573
  function getRouteKey() {
3376
3574
  return STORAGE_PREFIX + window.location.pathname;
@@ -3692,7 +3890,28 @@ function DebugWidget({ endpoint, getUser, onHide }) {
3692
3890
  } catch {
3693
3891
  }
3694
3892
  }
3893
+ const routeMatch = await getRouteDebugTargets(window.location.pathname);
3894
+ const componentTarget = resolvedSource && !resolvedSource.includes("/chunks/") ? buildComponentDebugTarget(resolvedSource, resolvedName) : null;
3895
+ const debugTargets = mergeDebugTargets(
3896
+ componentTarget ? [componentTarget] : void 0,
3897
+ routeMatch?.targets
3898
+ );
3899
+ if (debugTargets.length > 0) {
3900
+ metadata.debugTargets = debugTargets;
3901
+ }
3902
+ if (routeMatch?.context) {
3903
+ metadata.routeDebug = routeMatch.context;
3904
+ }
3695
3905
  const descriptionParts = [comment];
3906
+ if (debugTargets.length > 0) {
3907
+ descriptionParts.push(
3908
+ "\n\n---\n**\uB514\uBC84\uAE45 \uD0C0\uAC9F \uD30C\uC77C**:",
3909
+ ...debugTargets.map((target) => {
3910
+ const suffix = target.line ? `:${target.line}${typeof target.column === "number" ? `:${target.column}` : ""}` : "";
3911
+ return `- [${target.kind}] \`${target.file}${suffix}\` (${target.reason})`;
3912
+ })
3913
+ );
3914
+ }
3696
3915
  const elementInfo = [];
3697
3916
  if (pendingAnnotation.element) {
3698
3917
  elementInfo.push(`**\uC120\uD0DD\uB41C \uC694\uC18C**: ${pendingAnnotation.element}`);