@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/next.d.mts +4 -0
- package/dist/next.d.ts +4 -0
- package/dist/next.js +127 -3
- package/dist/next.mjs +127 -3
- package/dist/react.js +225 -6
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +225 -6
- package/dist/react.mjs.map +1 -1
- package/package.json +1 -1
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
|
|
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 (
|
|
1544
|
-
styleEl.textContent = text.replace(
|
|
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 (
|
|
1551
|
-
s.cssText = s.cssText.replace(
|
|
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}`);
|