@flanksource/clicky-ui 0.3.13 → 0.3.15

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.
@@ -24,7 +24,6 @@ function countStackByState(stack) {
24
24
  return /* @__PURE__ */ new Map();
25
25
  }
26
26
  const headerRe = /^goroutine\s+(\d+)\s+\[(.+?)\]:$/;
27
- const fileRe = /^\s*(.+?):(\d+)(?:\s+\+0x[0-9a-f]+)?$/i;
28
27
  const goSrcPrefixRe = /^\/usr\/local\/go[\d.]+\/src\//;
29
28
  const goWorkspacePrefixRe = /^.*?\/go\/src\//;
30
29
  const goPkgModPrefixRe = /^.*?\/go\/pkg\/mod\//;
@@ -48,11 +47,11 @@ function parseGoroutineDump(text) {
48
47
  if (line == null) continue;
49
48
  const trimmedLine = line.trim();
50
49
  if (!trimmedLine) continue;
51
- const fileMatch = fileRe.exec(trimmedLine);
50
+ const fileLocation = parseGoroutineFileLocation(trimmedLine);
52
51
  const previousFrame = frames[frames.length - 1];
53
- if (fileMatch && previousFrame && !previousFrame.file) {
54
- previousFrame.file = fileMatch[1] ?? "";
55
- previousFrame.line = Number(fileMatch[2] ?? 0);
52
+ if (fileLocation && previousFrame && !previousFrame.file) {
53
+ previousFrame.file = fileLocation.file;
54
+ previousFrame.line = fileLocation.line;
56
55
  continue;
57
56
  }
58
57
  const kind = trimmedLine.startsWith("created by ") ? "created_by" : "frame";
@@ -98,6 +97,37 @@ function normalizeState(value) {
98
97
  function isRuntimeFrame(functionName) {
99
98
  return functionName.startsWith("runtime.") || functionName.startsWith("runtime/") || functionName.startsWith("internal/") || functionName.startsWith("runtime/internal/") || functionName.startsWith("syscall.") || functionName.startsWith("reflect.");
100
99
  }
100
+ function parseGoroutineFileLocation(value) {
101
+ const separator = value.lastIndexOf(":");
102
+ if (separator <= 0) return void 0;
103
+ let index = separator + 1;
104
+ const lineStart = index;
105
+ while (index < value.length && isAsciiDigit(value[index] ?? "")) index++;
106
+ if (index === lineStart) return void 0;
107
+ const lineEnd = index;
108
+ if (index < value.length) {
109
+ const whitespaceStart = index;
110
+ while (index < value.length && (value[index] ?? "").trim() === "") index++;
111
+ if (index === whitespaceStart || value.slice(index, index + 3).toLowerCase() !== "+0x") {
112
+ return void 0;
113
+ }
114
+ index += 3;
115
+ const offsetStart = index;
116
+ while (index < value.length && isAsciiHexDigit(value[index] ?? "")) index++;
117
+ if (index === offsetStart || index !== value.length) return void 0;
118
+ }
119
+ return {
120
+ file: value.slice(0, separator),
121
+ line: Number(value.slice(lineStart, lineEnd))
122
+ };
123
+ }
124
+ function isAsciiDigit(value) {
125
+ return value >= "0" && value <= "9";
126
+ }
127
+ function isAsciiHexDigit(value) {
128
+ const lower = value.toLowerCase();
129
+ return isAsciiDigit(value) || lower >= "a" && lower <= "f";
130
+ }
101
131
  function splitGoroutineBlocks(text) {
102
132
  const blocks = [];
103
133
  let lines = [];
@@ -1 +1 @@
1
- {"version":3,"file":"stacktrace.cjs","sources":["../../../src/data/diagnostics/stacktrace.ts"],"sourcesContent":["import { parseJvmThreadDump, countThreadsByState, type ParsedThread } from \"./jvm-stacktrace\";\n\nexport type DumpFormat = \"go\" | \"jvm\" | \"unknown\";\n\nexport type ParsedStack =\n | { format: \"go\"; goroutines: ParsedGoroutine[] }\n | { format: \"jvm\"; threads: ParsedThread[] }\n | { format: \"unknown\"; goroutines: []; threads: [] };\n\nexport function detectDumpFormat(text: string): DumpFormat {\n const trimmed = text.trim();\n if (!trimmed) return \"unknown\";\n // JVM header: `\"name\" ... prio=` OR `\"name\" ... tid=`\n if (/^\"[^\"]*\"[^\\n]*\\b(prio=|tid=|nid=)/m.test(trimmed)) return \"jvm\";\n // Go header: `goroutine N [state]:`\n if (/^goroutine\\s+\\d+\\s+\\[[^\\]]+\\]:/m.test(trimmed)) return \"go\";\n return \"unknown\";\n}\n\nexport function parseStackDump(text: string): ParsedStack {\n const format = detectDumpFormat(text);\n if (format === \"jvm\") {\n return { format: \"jvm\", threads: parseJvmThreadDump(text) };\n }\n if (format === \"go\") {\n return { format: \"go\", goroutines: parseGoroutineDump(text) };\n }\n return { format: \"unknown\", goroutines: [], threads: [] };\n}\n\nexport function countStackByState(stack: ParsedStack): Map<string, number> {\n if (stack.format === \"jvm\") return countThreadsByState(stack.threads);\n if (stack.format === \"go\") return countGoroutinesByState(stack.goroutines);\n return new Map();\n}\n\nexport interface ParsedGoroutineFrame {\n functionName: string;\n displayName: string;\n file?: string;\n location?: string;\n line?: number;\n kind: \"frame\" | \"created_by\";\n runtime: boolean;\n}\n\nexport interface ParsedGoroutine {\n id: number;\n state: string;\n rawState: string;\n frames: ParsedGoroutineFrame[];\n raw: string;\n userFrameCount: number;\n topFunction?: string;\n searchText: string;\n}\n\nconst headerRe = /^goroutine\\s+(\\d+)\\s+\\[(.+?)\\]:$/;\nconst fileRe = /^\\s*(.+?):(\\d+)(?:\\s+\\+0x[0-9a-f]+)?$/i;\nconst goSrcPrefixRe = /^\\/usr\\/local\\/go[\\d.]+\\/src\\//;\nconst goWorkspacePrefixRe = /^.*?\\/go\\/src\\//;\nconst goPkgModPrefixRe = /^.*?\\/go\\/pkg\\/mod\\//;\n\nexport function parseGoroutineDump(text: string): ParsedGoroutine[] {\n const trimmed = text.trim();\n if (!trimmed) return [];\n\n const blocks = splitGoroutineBlocks(trimmed);\n const goroutines: ParsedGoroutine[] = [];\n\n for (const block of blocks) {\n const lines = block.split(\"\\n\").map((line) => line.replace(/\\r$/, \"\"));\n const header = lines[0]?.trim();\n const match = headerRe.exec(header || \"\");\n if (!match) continue;\n\n const id = Number(match[1] ?? 0);\n const rawState = match[2] ?? \"\";\n const state = normalizeState(rawState);\n const frames: ParsedGoroutineFrame[] = [];\n\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n if (line == null) continue;\n const trimmedLine = line.trim();\n if (!trimmedLine) continue;\n\n const fileMatch = fileRe.exec(trimmedLine);\n const previousFrame = frames[frames.length - 1];\n if (fileMatch && previousFrame && !previousFrame.file) {\n previousFrame.file = fileMatch[1] ?? \"\";\n previousFrame.line = Number(fileMatch[2] ?? 0);\n continue;\n }\n\n const kind = trimmedLine.startsWith(\"created by \") ? \"created_by\" : \"frame\";\n const functionName =\n kind === \"created_by\" ? trimmedLine.slice(\"created by \".length) : trimmedLine;\n frames.push({\n functionName,\n displayName: sanitizeFunctionName(functionName),\n kind,\n runtime: isRuntimeFrame(functionName),\n });\n }\n\n for (const frame of frames) {\n if (frame.file) {\n frame.file = normalizeFilePath(frame.file);\n frame.location = `${frame.file}${frame.line ? `:${frame.line}` : \"\"}`;\n }\n }\n\n const topFunction = frames.find((frame) => frame.kind === \"frame\")?.functionName;\n\n goroutines.push({\n id,\n state,\n rawState,\n frames,\n raw: block,\n userFrameCount: frames.filter((frame) => !frame.runtime && frame.kind === \"frame\").length,\n searchText: `${header}\\n${frames\n .map((frame) => `${frame.functionName} ${frame.file || \"\"}`)\n .join(\"\\n\")}`.toLowerCase(),\n ...(topFunction !== undefined ? { topFunction } : {}),\n });\n }\n\n return goroutines;\n}\n\nexport function countGoroutinesByState(goroutines: ParsedGoroutine[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const goroutine of goroutines) {\n counts.set(goroutine.state, (counts.get(goroutine.state) || 0) + 1);\n }\n return counts;\n}\n\nfunction normalizeState(value: string): string {\n return (value.split(\",\")[0] ?? \"\").trim().toLowerCase();\n}\n\nfunction isRuntimeFrame(functionName: string): boolean {\n return (\n functionName.startsWith(\"runtime.\") ||\n functionName.startsWith(\"runtime/\") ||\n functionName.startsWith(\"internal/\") ||\n functionName.startsWith(\"runtime/internal/\") ||\n functionName.startsWith(\"syscall.\") ||\n functionName.startsWith(\"reflect.\")\n );\n}\n\nfunction splitGoroutineBlocks(text: string): string[] {\n const blocks: string[] = [];\n let lines: string[] = [];\n for (const line of text.split(\"\\n\")) {\n if (line.trim()) {\n lines.push(line);\n } else if (lines.length > 0) {\n blocks.push(lines.join(\"\\n\"));\n lines = [];\n }\n }\n if (lines.length > 0) blocks.push(lines.join(\"\\n\"));\n return blocks;\n}\n\nfunction sanitizeFunctionName(functionName: string): string {\n let name = functionName.trim();\n const paren = name.indexOf(\"(\");\n if (paren !== -1) name = name.slice(0, paren);\n return stripPackageQualifier(name);\n}\n\nfunction stripPackageQualifier(name: string): string {\n return name.replace(/^((?:[^./\\s]+\\/)+)([^./\\s]+)\\./, \"$2.\");\n}\n\nfunction normalizeFilePath(path: string): string {\n return path\n .replace(goSrcPrefixRe, \"\")\n .replace(goWorkspacePrefixRe, \"\")\n .replace(goPkgModPrefixRe, \"\");\n}\n"],"names":["parseJvmThreadDump","countThreadsByState"],"mappings":"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"}
1
+ {"version":3,"file":"stacktrace.cjs","sources":["../../../src/data/diagnostics/stacktrace.ts"],"sourcesContent":["import { parseJvmThreadDump, countThreadsByState, type ParsedThread } from \"./jvm-stacktrace\";\n\nexport type DumpFormat = \"go\" | \"jvm\" | \"unknown\";\n\nexport type ParsedStack =\n | { format: \"go\"; goroutines: ParsedGoroutine[] }\n | { format: \"jvm\"; threads: ParsedThread[] }\n | { format: \"unknown\"; goroutines: []; threads: [] };\n\nexport function detectDumpFormat(text: string): DumpFormat {\n const trimmed = text.trim();\n if (!trimmed) return \"unknown\";\n // JVM header: `\"name\" ... prio=` OR `\"name\" ... tid=`\n if (/^\"[^\"]*\"[^\\n]*\\b(prio=|tid=|nid=)/m.test(trimmed)) return \"jvm\";\n // Go header: `goroutine N [state]:`\n if (/^goroutine\\s+\\d+\\s+\\[[^\\]]+\\]:/m.test(trimmed)) return \"go\";\n return \"unknown\";\n}\n\nexport function parseStackDump(text: string): ParsedStack {\n const format = detectDumpFormat(text);\n if (format === \"jvm\") {\n return { format: \"jvm\", threads: parseJvmThreadDump(text) };\n }\n if (format === \"go\") {\n return { format: \"go\", goroutines: parseGoroutineDump(text) };\n }\n return { format: \"unknown\", goroutines: [], threads: [] };\n}\n\nexport function countStackByState(stack: ParsedStack): Map<string, number> {\n if (stack.format === \"jvm\") return countThreadsByState(stack.threads);\n if (stack.format === \"go\") return countGoroutinesByState(stack.goroutines);\n return new Map();\n}\n\nexport interface ParsedGoroutineFrame {\n functionName: string;\n displayName: string;\n file?: string;\n location?: string;\n line?: number;\n kind: \"frame\" | \"created_by\";\n runtime: boolean;\n}\n\nexport interface ParsedGoroutine {\n id: number;\n state: string;\n rawState: string;\n frames: ParsedGoroutineFrame[];\n raw: string;\n userFrameCount: number;\n topFunction?: string;\n searchText: string;\n}\n\nconst headerRe = /^goroutine\\s+(\\d+)\\s+\\[(.+?)\\]:$/;\nconst goSrcPrefixRe = /^\\/usr\\/local\\/go[\\d.]+\\/src\\//;\nconst goWorkspacePrefixRe = /^.*?\\/go\\/src\\//;\nconst goPkgModPrefixRe = /^.*?\\/go\\/pkg\\/mod\\//;\n\nexport function parseGoroutineDump(text: string): ParsedGoroutine[] {\n const trimmed = text.trim();\n if (!trimmed) return [];\n\n const blocks = splitGoroutineBlocks(trimmed);\n const goroutines: ParsedGoroutine[] = [];\n\n for (const block of blocks) {\n const lines = block.split(\"\\n\").map((line) => line.replace(/\\r$/, \"\"));\n const header = lines[0]?.trim();\n const match = headerRe.exec(header || \"\");\n if (!match) continue;\n\n const id = Number(match[1] ?? 0);\n const rawState = match[2] ?? \"\";\n const state = normalizeState(rawState);\n const frames: ParsedGoroutineFrame[] = [];\n\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n if (line == null) continue;\n const trimmedLine = line.trim();\n if (!trimmedLine) continue;\n\n const fileLocation = parseGoroutineFileLocation(trimmedLine);\n const previousFrame = frames[frames.length - 1];\n if (fileLocation && previousFrame && !previousFrame.file) {\n previousFrame.file = fileLocation.file;\n previousFrame.line = fileLocation.line;\n continue;\n }\n\n const kind = trimmedLine.startsWith(\"created by \") ? \"created_by\" : \"frame\";\n const functionName =\n kind === \"created_by\" ? trimmedLine.slice(\"created by \".length) : trimmedLine;\n frames.push({\n functionName,\n displayName: sanitizeFunctionName(functionName),\n kind,\n runtime: isRuntimeFrame(functionName),\n });\n }\n\n for (const frame of frames) {\n if (frame.file) {\n frame.file = normalizeFilePath(frame.file);\n frame.location = `${frame.file}${frame.line ? `:${frame.line}` : \"\"}`;\n }\n }\n\n const topFunction = frames.find((frame) => frame.kind === \"frame\")?.functionName;\n\n goroutines.push({\n id,\n state,\n rawState,\n frames,\n raw: block,\n userFrameCount: frames.filter((frame) => !frame.runtime && frame.kind === \"frame\").length,\n searchText: `${header}\\n${frames\n .map((frame) => `${frame.functionName} ${frame.file || \"\"}`)\n .join(\"\\n\")}`.toLowerCase(),\n ...(topFunction !== undefined ? { topFunction } : {}),\n });\n }\n\n return goroutines;\n}\n\nexport function countGoroutinesByState(goroutines: ParsedGoroutine[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const goroutine of goroutines) {\n counts.set(goroutine.state, (counts.get(goroutine.state) || 0) + 1);\n }\n return counts;\n}\n\nfunction normalizeState(value: string): string {\n return (value.split(\",\")[0] ?? \"\").trim().toLowerCase();\n}\n\nfunction isRuntimeFrame(functionName: string): boolean {\n return (\n functionName.startsWith(\"runtime.\") ||\n functionName.startsWith(\"runtime/\") ||\n functionName.startsWith(\"internal/\") ||\n functionName.startsWith(\"runtime/internal/\") ||\n functionName.startsWith(\"syscall.\") ||\n functionName.startsWith(\"reflect.\")\n );\n}\n\nfunction parseGoroutineFileLocation(value: string): { file: string; line: number } | undefined {\n const separator = value.lastIndexOf(\":\");\n if (separator <= 0) return undefined;\n\n let index = separator + 1;\n const lineStart = index;\n while (index < value.length && isAsciiDigit(value[index] ?? \"\")) index++;\n if (index === lineStart) return undefined;\n\n const lineEnd = index;\n if (index < value.length) {\n const whitespaceStart = index;\n while (index < value.length && (value[index] ?? \"\").trim() === \"\") index++;\n if (index === whitespaceStart || value.slice(index, index + 3).toLowerCase() !== \"+0x\") {\n return undefined;\n }\n\n index += 3;\n const offsetStart = index;\n while (index < value.length && isAsciiHexDigit(value[index] ?? \"\")) index++;\n if (index === offsetStart || index !== value.length) return undefined;\n }\n\n return {\n file: value.slice(0, separator),\n line: Number(value.slice(lineStart, lineEnd)),\n };\n}\n\nfunction isAsciiDigit(value: string): boolean {\n return value >= \"0\" && value <= \"9\";\n}\n\nfunction isAsciiHexDigit(value: string): boolean {\n const lower = value.toLowerCase();\n return isAsciiDigit(value) || (lower >= \"a\" && lower <= \"f\");\n}\n\nfunction splitGoroutineBlocks(text: string): string[] {\n const blocks: string[] = [];\n let lines: string[] = [];\n for (const line of text.split(\"\\n\")) {\n if (line.trim()) {\n lines.push(line);\n } else if (lines.length > 0) {\n blocks.push(lines.join(\"\\n\"));\n lines = [];\n }\n }\n if (lines.length > 0) blocks.push(lines.join(\"\\n\"));\n return blocks;\n}\n\nfunction sanitizeFunctionName(functionName: string): string {\n let name = functionName.trim();\n const paren = name.indexOf(\"(\");\n if (paren !== -1) name = name.slice(0, paren);\n return stripPackageQualifier(name);\n}\n\nfunction stripPackageQualifier(name: string): string {\n return name.replace(/^((?:[^./\\s]+\\/)+)([^./\\s]+)\\./, \"$2.\");\n}\n\nfunction normalizeFilePath(path: string): string {\n return path\n .replace(goSrcPrefixRe, \"\")\n .replace(goWorkspacePrefixRe, \"\")\n .replace(goPkgModPrefixRe, \"\");\n}\n"],"names":["parseJvmThreadDump","countThreadsByState"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"stacktrace.d.ts","sourceRoot":"","sources":["../../../src/data/diagnostics/stacktrace.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2C,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAE9F,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,KAAK,GAAG,SAAS,CAAC;AAElD,MAAM,MAAM,WAAW,GACnB;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,eAAe,EAAE,CAAA;CAAE,GAC/C;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,YAAY,EAAE,CAAA;CAAE,GAC1C;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,EAAE,CAAC;IAAC,OAAO,EAAE,EAAE,CAAA;CAAE,CAAC;AAEvD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAQzD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CASxD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAIzE;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,GAAG,YAAY,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAQD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,EAAE,CAmElE;AAED,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,eAAe,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAMzF"}
1
+ {"version":3,"file":"stacktrace.d.ts","sourceRoot":"","sources":["../../../src/data/diagnostics/stacktrace.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2C,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAE9F,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,KAAK,GAAG,SAAS,CAAC;AAElD,MAAM,MAAM,WAAW,GACnB;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,eAAe,EAAE,CAAA;CAAE,GAC/C;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,YAAY,EAAE,CAAA;CAAE,GAC1C;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,EAAE,CAAC;IAAC,OAAO,EAAE,EAAE,CAAA;CAAE,CAAC;AAEvD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAQzD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CASxD;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAIzE;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,GAAG,YAAY,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,oBAAoB,EAAE,CAAC;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAOD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,EAAE,CAmElE;AAED,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,eAAe,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAMzF"}
@@ -22,7 +22,6 @@ function countStackByState(stack) {
22
22
  return /* @__PURE__ */ new Map();
23
23
  }
24
24
  const headerRe = /^goroutine\s+(\d+)\s+\[(.+?)\]:$/;
25
- const fileRe = /^\s*(.+?):(\d+)(?:\s+\+0x[0-9a-f]+)?$/i;
26
25
  const goSrcPrefixRe = /^\/usr\/local\/go[\d.]+\/src\//;
27
26
  const goWorkspacePrefixRe = /^.*?\/go\/src\//;
28
27
  const goPkgModPrefixRe = /^.*?\/go\/pkg\/mod\//;
@@ -46,11 +45,11 @@ function parseGoroutineDump(text) {
46
45
  if (line == null) continue;
47
46
  const trimmedLine = line.trim();
48
47
  if (!trimmedLine) continue;
49
- const fileMatch = fileRe.exec(trimmedLine);
48
+ const fileLocation = parseGoroutineFileLocation(trimmedLine);
50
49
  const previousFrame = frames[frames.length - 1];
51
- if (fileMatch && previousFrame && !previousFrame.file) {
52
- previousFrame.file = fileMatch[1] ?? "";
53
- previousFrame.line = Number(fileMatch[2] ?? 0);
50
+ if (fileLocation && previousFrame && !previousFrame.file) {
51
+ previousFrame.file = fileLocation.file;
52
+ previousFrame.line = fileLocation.line;
54
53
  continue;
55
54
  }
56
55
  const kind = trimmedLine.startsWith("created by ") ? "created_by" : "frame";
@@ -96,6 +95,37 @@ function normalizeState(value) {
96
95
  function isRuntimeFrame(functionName) {
97
96
  return functionName.startsWith("runtime.") || functionName.startsWith("runtime/") || functionName.startsWith("internal/") || functionName.startsWith("runtime/internal/") || functionName.startsWith("syscall.") || functionName.startsWith("reflect.");
98
97
  }
98
+ function parseGoroutineFileLocation(value) {
99
+ const separator = value.lastIndexOf(":");
100
+ if (separator <= 0) return void 0;
101
+ let index = separator + 1;
102
+ const lineStart = index;
103
+ while (index < value.length && isAsciiDigit(value[index] ?? "")) index++;
104
+ if (index === lineStart) return void 0;
105
+ const lineEnd = index;
106
+ if (index < value.length) {
107
+ const whitespaceStart = index;
108
+ while (index < value.length && (value[index] ?? "").trim() === "") index++;
109
+ if (index === whitespaceStart || value.slice(index, index + 3).toLowerCase() !== "+0x") {
110
+ return void 0;
111
+ }
112
+ index += 3;
113
+ const offsetStart = index;
114
+ while (index < value.length && isAsciiHexDigit(value[index] ?? "")) index++;
115
+ if (index === offsetStart || index !== value.length) return void 0;
116
+ }
117
+ return {
118
+ file: value.slice(0, separator),
119
+ line: Number(value.slice(lineStart, lineEnd))
120
+ };
121
+ }
122
+ function isAsciiDigit(value) {
123
+ return value >= "0" && value <= "9";
124
+ }
125
+ function isAsciiHexDigit(value) {
126
+ const lower = value.toLowerCase();
127
+ return isAsciiDigit(value) || lower >= "a" && lower <= "f";
128
+ }
99
129
  function splitGoroutineBlocks(text) {
100
130
  const blocks = [];
101
131
  let lines = [];
@@ -1 +1 @@
1
- {"version":3,"file":"stacktrace.js","sources":["../../../src/data/diagnostics/stacktrace.ts"],"sourcesContent":["import { parseJvmThreadDump, countThreadsByState, type ParsedThread } from \"./jvm-stacktrace\";\n\nexport type DumpFormat = \"go\" | \"jvm\" | \"unknown\";\n\nexport type ParsedStack =\n | { format: \"go\"; goroutines: ParsedGoroutine[] }\n | { format: \"jvm\"; threads: ParsedThread[] }\n | { format: \"unknown\"; goroutines: []; threads: [] };\n\nexport function detectDumpFormat(text: string): DumpFormat {\n const trimmed = text.trim();\n if (!trimmed) return \"unknown\";\n // JVM header: `\"name\" ... prio=` OR `\"name\" ... tid=`\n if (/^\"[^\"]*\"[^\\n]*\\b(prio=|tid=|nid=)/m.test(trimmed)) return \"jvm\";\n // Go header: `goroutine N [state]:`\n if (/^goroutine\\s+\\d+\\s+\\[[^\\]]+\\]:/m.test(trimmed)) return \"go\";\n return \"unknown\";\n}\n\nexport function parseStackDump(text: string): ParsedStack {\n const format = detectDumpFormat(text);\n if (format === \"jvm\") {\n return { format: \"jvm\", threads: parseJvmThreadDump(text) };\n }\n if (format === \"go\") {\n return { format: \"go\", goroutines: parseGoroutineDump(text) };\n }\n return { format: \"unknown\", goroutines: [], threads: [] };\n}\n\nexport function countStackByState(stack: ParsedStack): Map<string, number> {\n if (stack.format === \"jvm\") return countThreadsByState(stack.threads);\n if (stack.format === \"go\") return countGoroutinesByState(stack.goroutines);\n return new Map();\n}\n\nexport interface ParsedGoroutineFrame {\n functionName: string;\n displayName: string;\n file?: string;\n location?: string;\n line?: number;\n kind: \"frame\" | \"created_by\";\n runtime: boolean;\n}\n\nexport interface ParsedGoroutine {\n id: number;\n state: string;\n rawState: string;\n frames: ParsedGoroutineFrame[];\n raw: string;\n userFrameCount: number;\n topFunction?: string;\n searchText: string;\n}\n\nconst headerRe = /^goroutine\\s+(\\d+)\\s+\\[(.+?)\\]:$/;\nconst fileRe = /^\\s*(.+?):(\\d+)(?:\\s+\\+0x[0-9a-f]+)?$/i;\nconst goSrcPrefixRe = /^\\/usr\\/local\\/go[\\d.]+\\/src\\//;\nconst goWorkspacePrefixRe = /^.*?\\/go\\/src\\//;\nconst goPkgModPrefixRe = /^.*?\\/go\\/pkg\\/mod\\//;\n\nexport function parseGoroutineDump(text: string): ParsedGoroutine[] {\n const trimmed = text.trim();\n if (!trimmed) return [];\n\n const blocks = splitGoroutineBlocks(trimmed);\n const goroutines: ParsedGoroutine[] = [];\n\n for (const block of blocks) {\n const lines = block.split(\"\\n\").map((line) => line.replace(/\\r$/, \"\"));\n const header = lines[0]?.trim();\n const match = headerRe.exec(header || \"\");\n if (!match) continue;\n\n const id = Number(match[1] ?? 0);\n const rawState = match[2] ?? \"\";\n const state = normalizeState(rawState);\n const frames: ParsedGoroutineFrame[] = [];\n\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n if (line == null) continue;\n const trimmedLine = line.trim();\n if (!trimmedLine) continue;\n\n const fileMatch = fileRe.exec(trimmedLine);\n const previousFrame = frames[frames.length - 1];\n if (fileMatch && previousFrame && !previousFrame.file) {\n previousFrame.file = fileMatch[1] ?? \"\";\n previousFrame.line = Number(fileMatch[2] ?? 0);\n continue;\n }\n\n const kind = trimmedLine.startsWith(\"created by \") ? \"created_by\" : \"frame\";\n const functionName =\n kind === \"created_by\" ? trimmedLine.slice(\"created by \".length) : trimmedLine;\n frames.push({\n functionName,\n displayName: sanitizeFunctionName(functionName),\n kind,\n runtime: isRuntimeFrame(functionName),\n });\n }\n\n for (const frame of frames) {\n if (frame.file) {\n frame.file = normalizeFilePath(frame.file);\n frame.location = `${frame.file}${frame.line ? `:${frame.line}` : \"\"}`;\n }\n }\n\n const topFunction = frames.find((frame) => frame.kind === \"frame\")?.functionName;\n\n goroutines.push({\n id,\n state,\n rawState,\n frames,\n raw: block,\n userFrameCount: frames.filter((frame) => !frame.runtime && frame.kind === \"frame\").length,\n searchText: `${header}\\n${frames\n .map((frame) => `${frame.functionName} ${frame.file || \"\"}`)\n .join(\"\\n\")}`.toLowerCase(),\n ...(topFunction !== undefined ? { topFunction } : {}),\n });\n }\n\n return goroutines;\n}\n\nexport function countGoroutinesByState(goroutines: ParsedGoroutine[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const goroutine of goroutines) {\n counts.set(goroutine.state, (counts.get(goroutine.state) || 0) + 1);\n }\n return counts;\n}\n\nfunction normalizeState(value: string): string {\n return (value.split(\",\")[0] ?? \"\").trim().toLowerCase();\n}\n\nfunction isRuntimeFrame(functionName: string): boolean {\n return (\n functionName.startsWith(\"runtime.\") ||\n functionName.startsWith(\"runtime/\") ||\n functionName.startsWith(\"internal/\") ||\n functionName.startsWith(\"runtime/internal/\") ||\n functionName.startsWith(\"syscall.\") ||\n functionName.startsWith(\"reflect.\")\n );\n}\n\nfunction splitGoroutineBlocks(text: string): string[] {\n const blocks: string[] = [];\n let lines: string[] = [];\n for (const line of text.split(\"\\n\")) {\n if (line.trim()) {\n lines.push(line);\n } else if (lines.length > 0) {\n blocks.push(lines.join(\"\\n\"));\n lines = [];\n }\n }\n if (lines.length > 0) blocks.push(lines.join(\"\\n\"));\n return blocks;\n}\n\nfunction sanitizeFunctionName(functionName: string): string {\n let name = functionName.trim();\n const paren = name.indexOf(\"(\");\n if (paren !== -1) name = name.slice(0, paren);\n return stripPackageQualifier(name);\n}\n\nfunction stripPackageQualifier(name: string): string {\n return name.replace(/^((?:[^./\\s]+\\/)+)([^./\\s]+)\\./, \"$2.\");\n}\n\nfunction normalizeFilePath(path: string): string {\n return path\n .replace(goSrcPrefixRe, \"\")\n .replace(goWorkspacePrefixRe, \"\")\n .replace(goPkgModPrefixRe, \"\");\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stacktrace.js","sources":["../../../src/data/diagnostics/stacktrace.ts"],"sourcesContent":["import { parseJvmThreadDump, countThreadsByState, type ParsedThread } from \"./jvm-stacktrace\";\n\nexport type DumpFormat = \"go\" | \"jvm\" | \"unknown\";\n\nexport type ParsedStack =\n | { format: \"go\"; goroutines: ParsedGoroutine[] }\n | { format: \"jvm\"; threads: ParsedThread[] }\n | { format: \"unknown\"; goroutines: []; threads: [] };\n\nexport function detectDumpFormat(text: string): DumpFormat {\n const trimmed = text.trim();\n if (!trimmed) return \"unknown\";\n // JVM header: `\"name\" ... prio=` OR `\"name\" ... tid=`\n if (/^\"[^\"]*\"[^\\n]*\\b(prio=|tid=|nid=)/m.test(trimmed)) return \"jvm\";\n // Go header: `goroutine N [state]:`\n if (/^goroutine\\s+\\d+\\s+\\[[^\\]]+\\]:/m.test(trimmed)) return \"go\";\n return \"unknown\";\n}\n\nexport function parseStackDump(text: string): ParsedStack {\n const format = detectDumpFormat(text);\n if (format === \"jvm\") {\n return { format: \"jvm\", threads: parseJvmThreadDump(text) };\n }\n if (format === \"go\") {\n return { format: \"go\", goroutines: parseGoroutineDump(text) };\n }\n return { format: \"unknown\", goroutines: [], threads: [] };\n}\n\nexport function countStackByState(stack: ParsedStack): Map<string, number> {\n if (stack.format === \"jvm\") return countThreadsByState(stack.threads);\n if (stack.format === \"go\") return countGoroutinesByState(stack.goroutines);\n return new Map();\n}\n\nexport interface ParsedGoroutineFrame {\n functionName: string;\n displayName: string;\n file?: string;\n location?: string;\n line?: number;\n kind: \"frame\" | \"created_by\";\n runtime: boolean;\n}\n\nexport interface ParsedGoroutine {\n id: number;\n state: string;\n rawState: string;\n frames: ParsedGoroutineFrame[];\n raw: string;\n userFrameCount: number;\n topFunction?: string;\n searchText: string;\n}\n\nconst headerRe = /^goroutine\\s+(\\d+)\\s+\\[(.+?)\\]:$/;\nconst goSrcPrefixRe = /^\\/usr\\/local\\/go[\\d.]+\\/src\\//;\nconst goWorkspacePrefixRe = /^.*?\\/go\\/src\\//;\nconst goPkgModPrefixRe = /^.*?\\/go\\/pkg\\/mod\\//;\n\nexport function parseGoroutineDump(text: string): ParsedGoroutine[] {\n const trimmed = text.trim();\n if (!trimmed) return [];\n\n const blocks = splitGoroutineBlocks(trimmed);\n const goroutines: ParsedGoroutine[] = [];\n\n for (const block of blocks) {\n const lines = block.split(\"\\n\").map((line) => line.replace(/\\r$/, \"\"));\n const header = lines[0]?.trim();\n const match = headerRe.exec(header || \"\");\n if (!match) continue;\n\n const id = Number(match[1] ?? 0);\n const rawState = match[2] ?? \"\";\n const state = normalizeState(rawState);\n const frames: ParsedGoroutineFrame[] = [];\n\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n if (line == null) continue;\n const trimmedLine = line.trim();\n if (!trimmedLine) continue;\n\n const fileLocation = parseGoroutineFileLocation(trimmedLine);\n const previousFrame = frames[frames.length - 1];\n if (fileLocation && previousFrame && !previousFrame.file) {\n previousFrame.file = fileLocation.file;\n previousFrame.line = fileLocation.line;\n continue;\n }\n\n const kind = trimmedLine.startsWith(\"created by \") ? \"created_by\" : \"frame\";\n const functionName =\n kind === \"created_by\" ? trimmedLine.slice(\"created by \".length) : trimmedLine;\n frames.push({\n functionName,\n displayName: sanitizeFunctionName(functionName),\n kind,\n runtime: isRuntimeFrame(functionName),\n });\n }\n\n for (const frame of frames) {\n if (frame.file) {\n frame.file = normalizeFilePath(frame.file);\n frame.location = `${frame.file}${frame.line ? `:${frame.line}` : \"\"}`;\n }\n }\n\n const topFunction = frames.find((frame) => frame.kind === \"frame\")?.functionName;\n\n goroutines.push({\n id,\n state,\n rawState,\n frames,\n raw: block,\n userFrameCount: frames.filter((frame) => !frame.runtime && frame.kind === \"frame\").length,\n searchText: `${header}\\n${frames\n .map((frame) => `${frame.functionName} ${frame.file || \"\"}`)\n .join(\"\\n\")}`.toLowerCase(),\n ...(topFunction !== undefined ? { topFunction } : {}),\n });\n }\n\n return goroutines;\n}\n\nexport function countGoroutinesByState(goroutines: ParsedGoroutine[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const goroutine of goroutines) {\n counts.set(goroutine.state, (counts.get(goroutine.state) || 0) + 1);\n }\n return counts;\n}\n\nfunction normalizeState(value: string): string {\n return (value.split(\",\")[0] ?? \"\").trim().toLowerCase();\n}\n\nfunction isRuntimeFrame(functionName: string): boolean {\n return (\n functionName.startsWith(\"runtime.\") ||\n functionName.startsWith(\"runtime/\") ||\n functionName.startsWith(\"internal/\") ||\n functionName.startsWith(\"runtime/internal/\") ||\n functionName.startsWith(\"syscall.\") ||\n functionName.startsWith(\"reflect.\")\n );\n}\n\nfunction parseGoroutineFileLocation(value: string): { file: string; line: number } | undefined {\n const separator = value.lastIndexOf(\":\");\n if (separator <= 0) return undefined;\n\n let index = separator + 1;\n const lineStart = index;\n while (index < value.length && isAsciiDigit(value[index] ?? \"\")) index++;\n if (index === lineStart) return undefined;\n\n const lineEnd = index;\n if (index < value.length) {\n const whitespaceStart = index;\n while (index < value.length && (value[index] ?? \"\").trim() === \"\") index++;\n if (index === whitespaceStart || value.slice(index, index + 3).toLowerCase() !== \"+0x\") {\n return undefined;\n }\n\n index += 3;\n const offsetStart = index;\n while (index < value.length && isAsciiHexDigit(value[index] ?? \"\")) index++;\n if (index === offsetStart || index !== value.length) return undefined;\n }\n\n return {\n file: value.slice(0, separator),\n line: Number(value.slice(lineStart, lineEnd)),\n };\n}\n\nfunction isAsciiDigit(value: string): boolean {\n return value >= \"0\" && value <= \"9\";\n}\n\nfunction isAsciiHexDigit(value: string): boolean {\n const lower = value.toLowerCase();\n return isAsciiDigit(value) || (lower >= \"a\" && lower <= \"f\");\n}\n\nfunction splitGoroutineBlocks(text: string): string[] {\n const blocks: string[] = [];\n let lines: string[] = [];\n for (const line of text.split(\"\\n\")) {\n if (line.trim()) {\n lines.push(line);\n } else if (lines.length > 0) {\n blocks.push(lines.join(\"\\n\"));\n lines = [];\n }\n }\n if (lines.length > 0) blocks.push(lines.join(\"\\n\"));\n return blocks;\n}\n\nfunction sanitizeFunctionName(functionName: string): string {\n let name = functionName.trim();\n const paren = name.indexOf(\"(\");\n if (paren !== -1) name = name.slice(0, paren);\n return stripPackageQualifier(name);\n}\n\nfunction stripPackageQualifier(name: string): string {\n return name.replace(/^((?:[^./\\s]+\\/)+)([^./\\s]+)\\./, \"$2.\");\n}\n\nfunction normalizeFilePath(path: string): string {\n return path\n .replace(goSrcPrefixRe, \"\")\n .replace(goWorkspacePrefixRe, \"\")\n .replace(goPkgModPrefixRe, \"\");\n}\n"],"names":[],"mappings":"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"}
@@ -15,9 +15,9 @@ function detectMode() {
15
15
  }
16
16
  function getVersionInfo() {
17
17
  return {
18
- commit: read(() => "0eb4c401", ""),
19
- tag: read(() => "clicky-ui@0.3.12", ""),
20
- date: read(() => "2026-07-16T18:21:17.612Z", ""),
18
+ commit: read(() => "df3338f6", ""),
19
+ tag: read(() => "clicky-ui@0.3.14", ""),
20
+ date: read(() => "2026-07-22T13:34:38.142Z", ""),
21
21
  dirty: read(() => true, false),
22
22
  mode: detectMode()
23
23
  };
@@ -13,9 +13,9 @@ function detectMode() {
13
13
  }
14
14
  function getVersionInfo() {
15
15
  return {
16
- commit: read(() => "0eb4c401", ""),
17
- tag: read(() => "clicky-ui@0.3.12", ""),
18
- date: read(() => "2026-07-16T18:20:59.418Z", ""),
16
+ commit: read(() => "df3338f6", ""),
17
+ tag: read(() => "clicky-ui@0.3.14", ""),
18
+ date: read(() => "2026-07-22T13:34:19.117Z", ""),
19
19
  dirty: read(() => true, false),
20
20
  mode: detectMode()
21
21
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flanksource/clicky-ui",
3
- "version": "0.3.13",
3
+ "version": "0.3.15",
4
4
  "description": "Flanksource Clicky UI — React component library built on shadcn/ui with light/dark and density theming.",
5
5
  "homepage": "https://github.com/flanksource/clicky-ui#readme",
6
6
  "bugs": "https://github.com/flanksource/clicky-ui/issues",