@flanksource/clicky-ui 0.1.0 → 0.2.1
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/README.md +29 -2
- package/dist/api-explorer.d.ts +5 -0
- package/dist/api-explorer.d.ts.map +1 -0
- package/dist/api-explorer.js +25 -0
- package/dist/api-explorer.js.map +1 -0
- package/dist/clicky.d.ts +2 -0
- package/dist/clicky.d.ts.map +1 -0
- package/dist/clicky.js +5 -0
- package/dist/clicky.js.map +1 -0
- package/dist/components/DatePicker.d.ts +18 -0
- package/dist/components/DatePicker.d.ts.map +1 -0
- package/dist/components/DatePicker.js +63 -0
- package/dist/components/DatePicker.js.map +1 -0
- package/dist/components/DateTimePicker.d.ts +18 -0
- package/dist/components/DateTimePicker.d.ts.map +1 -0
- package/dist/components/DateTimePicker.js +84 -0
- package/dist/components/DateTimePicker.js.map +1 -0
- package/dist/components/FilterBar.d.ts +180 -0
- package/dist/components/FilterBar.d.ts.map +1 -0
- package/dist/components/FilterBar.js +1685 -0
- package/dist/components/FilterBar.js.map +1 -0
- package/dist/components/MultiSelect.d.ts +19 -0
- package/dist/components/MultiSelect.d.ts.map +1 -0
- package/dist/components/MultiSelect.js +143 -0
- package/dist/components/MultiSelect.js.map +1 -0
- package/dist/components/RangeSlider.d.ts +16 -0
- package/dist/components/RangeSlider.d.ts.map +1 -0
- package/dist/components/RangeSlider.js +92 -0
- package/dist/components/RangeSlider.js.map +1 -0
- package/dist/components/button.d.ts +21 -0
- package/dist/components/button.d.ts.map +1 -0
- package/dist/components/button.js +126 -0
- package/dist/components/button.js.map +1 -0
- package/dist/components/density-switcher.d.ts +7 -0
- package/dist/components/density-switcher.d.ts.map +1 -0
- package/dist/components/density-switcher.js +32 -0
- package/dist/components/density-switcher.js.map +1 -0
- package/dist/components/icon-menu-picker.d.ts +22 -0
- package/dist/components/icon-menu-picker.d.ts.map +1 -0
- package/dist/components/icon-menu-picker.js +181 -0
- package/dist/components/icon-menu-picker.js.map +1 -0
- package/dist/components/select.d.ts +15 -0
- package/dist/components/select.d.ts.map +1 -0
- package/dist/components/select.js +39 -0
- package/dist/components/select.js.map +1 -0
- package/dist/components/theme-switcher.d.ts +7 -0
- package/dist/components/theme-switcher.d.ts.map +1 -0
- package/dist/components/theme-switcher.js +42 -0
- package/dist/components/theme-switcher.js.map +1 -0
- package/dist/components.d.ts +14 -0
- package/dist/components.d.ts.map +1 -0
- package/dist/components.js +31 -0
- package/dist/components.js.map +1 -0
- package/dist/data/AnsiHtml.d.ts +7 -0
- package/dist/data/AnsiHtml.d.ts.map +1 -0
- package/dist/data/AnsiHtml.js +71 -0
- package/dist/data/AnsiHtml.js.map +1 -0
- package/dist/data/Avatar.d.ts +32 -0
- package/dist/data/Avatar.d.ts.map +1 -0
- package/dist/data/Avatar.js +201 -0
- package/dist/data/Avatar.js.map +1 -0
- package/dist/data/AvatarBadge.d.ts +26 -0
- package/dist/data/AvatarBadge.d.ts.map +1 -0
- package/dist/data/AvatarBadge.js +104 -0
- package/dist/data/AvatarBadge.js.map +1 -0
- package/dist/data/Badge.d.ts +44 -0
- package/dist/data/Badge.d.ts.map +1 -0
- package/dist/data/Badge.js +667 -0
- package/dist/data/Badge.js.map +1 -0
- package/dist/data/Clicky.d.ts +147 -0
- package/dist/data/Clicky.d.ts.map +1 -0
- package/dist/data/Clicky.fixtures.d.ts +3 -0
- package/dist/data/Clicky.fixtures.d.ts.map +1 -0
- package/dist/data/Clicky.js +1960 -0
- package/dist/data/Clicky.js.map +1 -0
- package/dist/data/DataTable.d.ts +95 -0
- package/dist/data/DataTable.d.ts.map +1 -0
- package/dist/data/DataTable.js +1464 -0
- package/dist/data/DataTable.js.map +1 -0
- package/dist/data/FilterPill.d.ts +29 -0
- package/dist/data/FilterPill.d.ts.map +1 -0
- package/dist/data/FilterPill.js +153 -0
- package/dist/data/FilterPill.js.map +1 -0
- package/dist/data/Gauge.d.ts +15 -0
- package/dist/data/Gauge.d.ts.map +1 -0
- package/dist/data/Gauge.js +63 -0
- package/dist/data/Gauge.js.map +1 -0
- package/dist/data/Icon.d.ts +53 -0
- package/dist/data/Icon.d.ts.map +1 -0
- package/dist/data/Icon.js +115 -0
- package/dist/data/Icon.js.map +1 -0
- package/dist/data/JsonView.d.ts +8 -0
- package/dist/data/JsonView.d.ts.map +1 -0
- package/dist/data/JsonView.js +74 -0
- package/dist/data/JsonView.js.map +1 -0
- package/dist/data/KeyValueList.d.ts +17 -0
- package/dist/data/KeyValueList.d.ts.map +1 -0
- package/dist/data/KeyValueList.js +33 -0
- package/dist/data/KeyValueList.js.map +1 -0
- package/dist/data/LogViewer.d.ts +10 -0
- package/dist/data/LogViewer.d.ts.map +1 -0
- package/dist/data/LogViewer.js +46 -0
- package/dist/data/LogViewer.js.map +1 -0
- package/dist/data/LogsTable.d.ts +27 -0
- package/dist/data/LogsTable.d.ts.map +1 -0
- package/dist/data/LogsTable.js +580 -0
- package/dist/data/LogsTable.js.map +1 -0
- package/dist/data/Markdown.d.ts +6 -0
- package/dist/data/Markdown.d.ts.map +1 -0
- package/dist/data/Markdown.js +59 -0
- package/dist/data/Markdown.js.map +1 -0
- package/dist/data/MatrixTable.d.ts +22 -0
- package/dist/data/MatrixTable.d.ts.map +1 -0
- package/dist/data/MatrixTable.js +164 -0
- package/dist/data/MatrixTable.js.map +1 -0
- package/dist/data/MethodBadge.d.ts +6 -0
- package/dist/data/MethodBadge.d.ts.map +1 -0
- package/dist/data/MethodBadge.js +18 -0
- package/dist/data/MethodBadge.js.map +1 -0
- package/dist/data/ProgressBar.d.ts +13 -0
- package/dist/data/ProgressBar.d.ts.map +1 -0
- package/dist/data/ProgressBar.js +34 -0
- package/dist/data/ProgressBar.js.map +1 -0
- package/dist/data/SortableHeader.d.ts +12 -0
- package/dist/data/SortableHeader.d.ts.map +1 -0
- package/dist/data/SortableHeader.js +33 -0
- package/dist/data/SortableHeader.js.map +1 -0
- package/dist/data/TabButton.d.ts +12 -0
- package/dist/data/TabButton.d.ts.map +1 -0
- package/dist/data/TabButton.js +45 -0
- package/dist/data/TabButton.js.map +1 -0
- package/dist/data/Tree.d.ts +35 -0
- package/dist/data/Tree.d.ts.map +1 -0
- package/dist/data/Tree.js +236 -0
- package/dist/data/Tree.js.map +1 -0
- package/dist/data/TreeGroupHeader.d.ts +11 -0
- package/dist/data/TreeGroupHeader.d.ts.map +1 -0
- package/dist/data/TreeGroupHeader.js +41 -0
- package/dist/data/TreeGroupHeader.js.map +1 -0
- package/dist/data/TreeNode.d.ts +43 -0
- package/dist/data/TreeNode.d.ts.map +1 -0
- package/dist/data/TreeNode.js +100 -0
- package/dist/data/TreeNode.js.map +1 -0
- package/dist/data/cells/StatusDot.d.ts +11 -0
- package/dist/data/cells/StatusDot.d.ts.map +1 -0
- package/dist/data/cells/StatusDot.js +38 -0
- package/dist/data/cells/StatusDot.js.map +1 -0
- package/dist/data/cells/TagList.d.ts +59 -0
- package/dist/data/cells/TagList.d.ts.map +1 -0
- package/dist/data/cells/TagList.js +257 -0
- package/dist/data/cells/TagList.js.map +1 -0
- package/dist/data/cells/Timestamp.d.ts +46 -0
- package/dist/data/cells/Timestamp.d.ts.map +1 -0
- package/dist/data/cells/Timestamp.js +146 -0
- package/dist/data/cells/Timestamp.js.map +1 -0
- package/dist/data/cells/status-mapping.d.ts +8 -0
- package/dist/data/cells/status-mapping.d.ts.map +1 -0
- package/dist/data/cells/status-mapping.js +44 -0
- package/dist/data/cells/status-mapping.js.map +1 -0
- package/dist/data/code-highlight.d.ts +12 -0
- package/dist/data/code-highlight.d.ts.map +1 -0
- package/dist/data/code-highlight.js +28 -0
- package/dist/data/code-highlight.js.map +1 -0
- package/dist/data/diagnostics/DiagnosticsDetailPanel.d.ts +9 -0
- package/dist/data/diagnostics/DiagnosticsDetailPanel.d.ts.map +1 -0
- package/dist/data/diagnostics/DiagnosticsDetailPanel.js +445 -0
- package/dist/data/diagnostics/DiagnosticsDetailPanel.js.map +1 -0
- package/dist/data/diagnostics/DiagnosticsTree.d.ts +9 -0
- package/dist/data/diagnostics/DiagnosticsTree.d.ts.map +1 -0
- package/dist/data/diagnostics/DiagnosticsTree.js +78 -0
- package/dist/data/diagnostics/DiagnosticsTree.js.map +1 -0
- package/dist/data/diagnostics/ErrorDetails.d.ts +20 -0
- package/dist/data/diagnostics/ErrorDetails.d.ts.map +1 -0
- package/dist/data/diagnostics/ErrorDetails.js +157 -0
- package/dist/data/diagnostics/ErrorDetails.js.map +1 -0
- package/dist/data/diagnostics/GoroutineCard.d.ts +10 -0
- package/dist/data/diagnostics/GoroutineCard.d.ts.map +1 -0
- package/dist/data/diagnostics/GoroutineCard.js +75 -0
- package/dist/data/diagnostics/GoroutineCard.js.map +1 -0
- package/dist/data/diagnostics/JvmStackTrace.d.ts +11 -0
- package/dist/data/diagnostics/JvmStackTrace.d.ts.map +1 -0
- package/dist/data/diagnostics/JvmStackTrace.js +26 -0
- package/dist/data/diagnostics/JvmStackTrace.js.map +1 -0
- package/dist/data/diagnostics/RenderedStackTrace.d.ts +18 -0
- package/dist/data/diagnostics/RenderedStackTrace.d.ts.map +1 -0
- package/dist/data/diagnostics/RenderedStackTrace.js +235 -0
- package/dist/data/diagnostics/RenderedStackTrace.js.map +1 -0
- package/dist/data/diagnostics/ThreadCard.d.ts +10 -0
- package/dist/data/diagnostics/ThreadCard.d.ts.map +1 -0
- package/dist/data/diagnostics/ThreadCard.js +78 -0
- package/dist/data/diagnostics/ThreadCard.js.map +1 -0
- package/dist/data/diagnostics/error-diagnostics.d.ts +26 -0
- package/dist/data/diagnostics/error-diagnostics.d.ts.map +1 -0
- package/dist/data/diagnostics/error-diagnostics.js +108 -0
- package/dist/data/diagnostics/error-diagnostics.js.map +1 -0
- package/dist/data/diagnostics/fixtures.d.ts +3 -0
- package/dist/data/diagnostics/fixtures.d.ts.map +1 -0
- package/dist/data/diagnostics/jvm-stacktrace.d.ts +34 -0
- package/dist/data/diagnostics/jvm-stacktrace.d.ts.map +1 -0
- package/dist/data/diagnostics/jvm-stacktrace.js +190 -0
- package/dist/data/diagnostics/jvm-stacktrace.js.map +1 -0
- package/dist/data/diagnostics/stacktrace-parse.d.ts +11 -0
- package/dist/data/diagnostics/stacktrace-parse.d.ts.map +1 -0
- package/dist/data/diagnostics/stacktrace-parse.js +87 -0
- package/dist/data/diagnostics/stacktrace-parse.js.map +1 -0
- package/dist/data/diagnostics/stacktrace.d.ts +38 -0
- package/dist/data/diagnostics/stacktrace.d.ts.map +1 -0
- package/dist/data/diagnostics/stacktrace.js +119 -0
- package/dist/data/diagnostics/stacktrace.js.map +1 -0
- package/dist/data/diagnostics/types.d.ts +30 -0
- package/dist/data/diagnostics/types.d.ts.map +1 -0
- package/dist/data/diagnostics/utils.d.ts +8 -0
- package/dist/data/diagnostics/utils.d.ts.map +1 -0
- package/dist/data/diagnostics/utils.js +59 -0
- package/dist/data/diagnostics/utils.js.map +1 -0
- package/dist/data/har/HarPanel.d.ts +9 -0
- package/dist/data/har/HarPanel.d.ts.map +1 -0
- package/dist/data/har/HarPanel.js +175 -0
- package/dist/data/har/HarPanel.js.map +1 -0
- package/dist/data/har/fixtures.d.ts +3 -0
- package/dist/data/har/fixtures.d.ts.map +1 -0
- package/dist/data/har/types.d.ts +47 -0
- package/dist/data/har/types.d.ts.map +1 -0
- package/dist/data.d.ts +39 -0
- package/dist/data.d.ts.map +1 -0
- package/dist/data.js +109 -0
- package/dist/data.js.map +1 -0
- package/dist/hooks/use-density.d.ts +22 -0
- package/dist/hooks/use-density.d.ts.map +1 -0
- package/dist/hooks/use-density.js +54 -0
- package/dist/hooks/use-density.js.map +1 -0
- package/dist/hooks/use-history-route.d.ts +6 -0
- package/dist/hooks/use-history-route.d.ts.map +1 -0
- package/dist/hooks/use-history-route.js +31 -0
- package/dist/hooks/use-history-route.js.map +1 -0
- package/dist/hooks/use-sort.d.ts +17 -0
- package/dist/hooks/use-sort.d.ts.map +1 -0
- package/dist/hooks/use-sort.js +42 -0
- package/dist/hooks/use-sort.js.map +1 -0
- package/dist/hooks/use-theme.d.ts +17 -0
- package/dist/hooks/use-theme.d.ts.map +1 -0
- package/dist/hooks/use-theme.js +68 -0
- package/dist/hooks/use-theme.js.map +1 -0
- package/dist/hooks.d.ts +5 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +14 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +193 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/Section.d.ts +23 -0
- package/dist/layout/Section.d.ts.map +1 -0
- package/dist/layout/Section.js +73 -0
- package/dist/layout/Section.js.map +1 -0
- package/dist/layout/SplitPane.d.ts +13 -0
- package/dist/layout/SplitPane.d.ts.map +1 -0
- package/dist/layout/SplitPane.js +72 -0
- package/dist/layout/SplitPane.js.map +1 -0
- package/dist/lib/palette.d.ts +4 -0
- package/dist/lib/palette.d.ts.map +1 -0
- package/dist/lib/palette.js +35 -0
- package/dist/lib/palette.js.map +1 -0
- package/dist/lib/size.d.ts +6 -0
- package/dist/lib/size.d.ts.map +1 -0
- package/dist/lib/size.js +14 -0
- package/dist/lib/size.js.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +9 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/overlay/HoverCard.d.ts +13 -0
- package/dist/overlay/HoverCard.d.ts.map +1 -0
- package/dist/overlay/HoverCard.js +170 -0
- package/dist/overlay/HoverCard.js.map +1 -0
- package/dist/overlay/Modal.d.ts +17 -0
- package/dist/overlay/Modal.d.ts.map +1 -0
- package/dist/overlay/Modal.js +91 -0
- package/dist/overlay/Modal.js.map +1 -0
- package/dist/rpc/AcceptPicker.d.ts +52 -0
- package/dist/rpc/AcceptPicker.d.ts.map +1 -0
- package/dist/rpc/AcceptPicker.js +126 -0
- package/dist/rpc/AcceptPicker.js.map +1 -0
- package/dist/rpc/ApiExplorer.d.ts +11 -0
- package/dist/rpc/ApiExplorer.d.ts.map +1 -0
- package/dist/rpc/ApiExplorer.js +37 -0
- package/dist/rpc/ApiExplorer.js.map +1 -0
- package/dist/rpc/CommandForm.d.ts +15 -0
- package/dist/rpc/CommandForm.d.ts.map +1 -0
- package/dist/rpc/CommandForm.js +356 -0
- package/dist/rpc/CommandForm.js.map +1 -0
- package/dist/rpc/CommandOutput.d.ts +11 -0
- package/dist/rpc/CommandOutput.d.ts.map +1 -0
- package/dist/rpc/CommandOutput.js +195 -0
- package/dist/rpc/CommandOutput.js.map +1 -0
- package/dist/rpc/EndpointList.d.ts +18 -0
- package/dist/rpc/EndpointList.d.ts.map +1 -0
- package/dist/rpc/EndpointList.js +56 -0
- package/dist/rpc/EndpointList.js.map +1 -0
- package/dist/rpc/EntityExplorerApp.d.ts +15 -0
- package/dist/rpc/EntityExplorerApp.d.ts.map +1 -0
- package/dist/rpc/EntityExplorerApp.js +282 -0
- package/dist/rpc/EntityExplorerApp.js.map +1 -0
- package/dist/rpc/ExecutionResult.d.ts +14 -0
- package/dist/rpc/ExecutionResult.d.ts.map +1 -0
- package/dist/rpc/ExecutionResult.js +51 -0
- package/dist/rpc/ExecutionResult.js.map +1 -0
- package/dist/rpc/FilterForm.d.ts +22 -0
- package/dist/rpc/FilterForm.d.ts.map +1 -0
- package/dist/rpc/FilterForm.js +392 -0
- package/dist/rpc/FilterForm.js.map +1 -0
- package/dist/rpc/InlineError.d.ts +7 -0
- package/dist/rpc/InlineError.d.ts.map +1 -0
- package/dist/rpc/InlineError.js +54 -0
- package/dist/rpc/InlineError.js.map +1 -0
- package/dist/rpc/OperationActionDialog.d.ts +12 -0
- package/dist/rpc/OperationActionDialog.d.ts.map +1 -0
- package/dist/rpc/OperationActionDialog.js +105 -0
- package/dist/rpc/OperationActionDialog.js.map +1 -0
- package/dist/rpc/OperationCatalog.d.ts +21 -0
- package/dist/rpc/OperationCatalog.d.ts.map +1 -0
- package/dist/rpc/OperationCatalog.js +339 -0
- package/dist/rpc/OperationCatalog.js.map +1 -0
- package/dist/rpc/OperationCommandPage.d.ts +22 -0
- package/dist/rpc/OperationCommandPage.d.ts.map +1 -0
- package/dist/rpc/OperationCommandPage.js +484 -0
- package/dist/rpc/OperationCommandPage.js.map +1 -0
- package/dist/rpc/OperationEntityPage.d.ts +23 -0
- package/dist/rpc/OperationEntityPage.d.ts.map +1 -0
- package/dist/rpc/OperationEntityPage.js +218 -0
- package/dist/rpc/OperationEntityPage.js.map +1 -0
- package/dist/rpc/classify.d.ts +8 -0
- package/dist/rpc/classify.d.ts.map +1 -0
- package/dist/rpc/classify.js +76 -0
- package/dist/rpc/classify.js.map +1 -0
- package/dist/rpc/clickyMetadata.d.ts +12 -0
- package/dist/rpc/clickyMetadata.d.ts.map +1 -0
- package/dist/rpc/clickyMetadata.js +71 -0
- package/dist/rpc/clickyMetadata.js.map +1 -0
- package/dist/rpc/formMetadata.d.ts +27 -0
- package/dist/rpc/formMetadata.d.ts.map +1 -0
- package/dist/rpc/formMetadata.js +250 -0
- package/dist/rpc/formMetadata.js.map +1 -0
- package/dist/rpc/types.d.ts +109 -0
- package/dist/rpc/types.d.ts.map +1 -0
- package/dist/rpc/types.js +8 -0
- package/dist/rpc/types.js.map +1 -0
- package/dist/rpc/useOperations.d.ts +346 -0
- package/dist/rpc/useOperations.d.ts.map +1 -0
- package/dist/rpc/useOperations.js +31 -0
- package/dist/rpc/useOperations.js.map +1 -0
- package/dist/rpc.d.ts +14 -0
- package/dist/rpc.d.ts.map +1 -0
- package/dist/rpc.js +37 -0
- package/dist/rpc.js.map +1 -0
- package/dist/styles.css +2 -0
- package/dist/styles.d.ts +1 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +2 -0
- package/dist/styles.js.map +1 -0
- package/dist/tailwind-preset.d.ts +4 -0
- package/dist/tailwind-preset.d.ts.map +1 -0
- package/dist/tailwind-preset.js +69 -0
- package/dist/tailwind-preset.js.map +1 -0
- package/dist/utils.d.ts +4 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +12 -0
- package/dist/utils.js.map +1 -0
- package/package.json +83 -40
- package/dist/index.d.mts +0 -834
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs +0 -2918
- package/dist/index.mjs.map +0 -1
- package/dist/tailwind-preset.d.mts +0 -7
- package/dist/tailwind-preset.d.mts.map +0 -1
- package/dist/tailwind-preset.mjs +0 -64
- package/dist/tailwind-preset.mjs.map +0 -1
- package/src/styles/tokens.css +0 -78
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RenderedStackTrace.js","sources":["../../../src/data/diagnostics/RenderedStackTrace.tsx"],"sourcesContent":["import { useEffect, useMemo, useState } from \"react\";\nimport {\n parseJavaStackTrace,\n type ParsedStackFrame,\n type ParsedStackTrace,\n} from \"./stacktrace-parse\";\nimport { highlightCode, loadShikiTransformers } from \"../code-highlight\";\nimport { Icon } from \"../Icon\";\n\n// SourceResolver matches the Go clicky.SourceResolver interface: given a\n// frame, return surrounding source lines so the renderer can display inline\n// context. Failures must be silent (return undefined) so a missing class\n// never blocks the rest of the trace.\nexport type StackTraceSourceResolver = (\n frame: ParsedStackFrame,\n contextLines: number,\n) =>\n | {\n lines: string[];\n startLine: number;\n language?: string;\n }\n | undefined;\n\nexport interface StackTraceProps {\n // Either a raw Java stack-trace string OR a pre-parsed ParsedStackTrace\n // (e.g. one received from a Go backend that already ran the parser there).\n input: string | ParsedStackTrace;\n language?: \"java\";\n resolver?: StackTraceSourceResolver;\n contextLines?: number;\n hideRuntimeOnly?: boolean;\n include?: string[];\n exclude?: string[];\n className?: string;\n}\n\n// StackTrace is the React counterpart to Go's clicky.StackTrace builder. Pass\n// a raw exception dump and it parses + renders frames; pass a SourceResolver\n// to get inline source context (±N lines) under each frame, with the focal\n// line highlighted.\nexport function StackTrace({\n input,\n language = \"java\",\n resolver,\n contextLines = 3,\n hideRuntimeOnly = false,\n include,\n exclude,\n className,\n}: StackTraceProps) {\n const parsed = useMemo<ParsedStackTrace>(() => {\n if (typeof input === \"string\") {\n return parseJavaStackTrace(input);\n }\n return input;\n }, [input, language]);\n\n const enrichedFrames = useMemo<ParsedStackFrame[]>(() => {\n if (!resolver) return parsed.frames;\n return parsed.frames.map((frame): ParsedStackFrame => {\n if (frame.sourceLines && frame.sourceLines.length > 0) return frame;\n const resolved = resolver(frame, contextLines);\n if (!resolved) return frame;\n const next: ParsedStackFrame = {\n ...frame,\n sourceLines: resolved.lines,\n sourceStartLine: resolved.startLine,\n };\n if (resolved.language !== undefined) next.sourceLanguage = resolved.language;\n return next;\n });\n }, [parsed.frames, resolver, contextLines]);\n\n const visibleFrames = useMemo(() => {\n return enrichedFrames.filter((frame) => {\n if (hideRuntimeOnly && frame.runtime) return false;\n if (exclude && exclude.some((p) => frame.class?.startsWith(p))) return false;\n if (include && include.length > 0) {\n return include.some((p) => frame.class?.startsWith(p));\n }\n return true;\n });\n }, [enrichedFrames, hideRuntimeOnly, include, exclude]);\n\n if (visibleFrames.length === 0 && !parsed.exceptionClass) return null;\n\n const hasFilteredFrames = visibleFrames.length !== enrichedFrames.length;\n\n return (\n <div\n className={[\n \"overflow-hidden rounded-md border border-border bg-background text-foreground\",\n className,\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n {(parsed.exceptionClass || parsed.message) && (\n <div className=\"border-b border-border bg-red-500/5 px-3 py-2\">\n <div className=\"flex min-w-0 items-start gap-2\">\n <Icon\n name=\"codicon:error\"\n className=\"mt-0.5 shrink-0 text-sm text-red-600 dark:text-red-400\"\n />\n <div className=\"min-w-0 flex-1\">\n {parsed.exceptionClass && (\n <div className=\"break-all font-mono text-xs font-semibold text-red-700 dark:text-red-300\">\n {parsed.exceptionClass}\n </div>\n )}\n {parsed.message && (\n <div className=\"mt-0.5 whitespace-pre-wrap break-words text-xs text-foreground\">\n {parsed.message}\n </div>\n )}\n </div>\n </div>\n </div>\n )}\n {parsed.causedBy.length > 0 && (\n <div className=\"space-y-1 border-b border-border bg-orange-500/5 px-3 py-2\">\n {parsed.causedBy.map((cause, i) => (\n <div\n key={i}\n className=\"flex min-w-0 items-start gap-2 font-mono text-[11px] text-orange-700 dark:text-orange-300\"\n >\n <Icon name=\"codicon:debug-stackframe-dot\" className=\"mt-0.5 shrink-0 text-xs\" />\n <span className=\"shrink-0 opacity-75\">Caused by</span>\n <span className=\"min-w-0 break-all\">{cause}</span>\n </div>\n ))}\n </div>\n )}\n <div className=\"divide-y divide-border/60\">\n {visibleFrames.map((frame, idx) => (\n <FrameWithSource key={`${frame.functionName}-${idx}`} frame={frame} index={idx} />\n ))}\n </div>\n {hasFilteredFrames && (\n <div className=\"border-t border-border bg-muted/30 px-3 py-1.5 text-[11px] text-muted-foreground\">\n Showing {visibleFrames.length} of {enrichedFrames.length} frames\n </div>\n )}\n </div>\n );\n}\n\nfunction FrameWithSource({ frame, index }: { frame: ParsedStackFrame; index: number }) {\n const hasSource = frame.sourceLines && frame.sourceLines.length > 0;\n\n return (\n <div className={hasSource ? \"bg-amber-500/[0.03]\" : undefined}>\n <StackFrameRow frame={frame} index={index} />\n {hasSource ? <SourceWindow frame={frame} /> : null}\n </div>\n );\n}\n\nfunction StackFrameRow({ frame, index }: { frame: ParsedStackFrame; index: number }) {\n const iconName = frame.nativeMethod\n ? \"codicon:chip\"\n : frame.runtime\n ? \"codicon:debug-step-over\"\n : \"codicon:symbol-method\";\n const className = frame.class;\n const methodName = frame.displayName || frame.method || frame.functionName;\n\n return (\n <div\n className={[\n \"grid grid-cols-[2rem_minmax(0,1fr)] gap-2 px-3 py-1.5 text-xs\",\n frame.runtime ? \"text-muted-foreground\" : \"text-foreground\",\n ].join(\" \")}\n >\n <div className=\"flex items-start justify-end gap-1 pt-0.5 font-mono text-[10px] text-muted-foreground\">\n <span>{index + 1}</span>\n <Icon name={iconName} className=\"mt-px shrink-0 text-[11px]\" />\n </div>\n <div className=\"min-w-0\">\n <div className=\"flex min-w-0 flex-wrap items-baseline gap-x-2 gap-y-0.5\">\n <span className=\"min-w-0 break-all font-mono font-semibold leading-4\">{methodName}</span>\n {className && (\n <span className=\"min-w-0 break-all font-mono text-[11px] text-muted-foreground\">\n {className}\n </span>\n )}\n {frame.location && (\n <span className=\"rounded border border-border bg-muted/40 px-1.5 py-px font-mono text-[10px] text-muted-foreground\">\n {frame.location}\n </span>\n )}\n </div>\n </div>\n </div>\n );\n}\n\n// Picks the language-appropriate inline comment prefix for the\n// `[!code error]` marker that Shiki's transformerNotationErrorLevel\n// recognises (https://shiki.style/packages/transformers#transformernotationerrorlevel).\n// We deliberately stick to single-line markers — block comments would\n// confuse the transformer's per-line scan.\nfunction inlineCommentPrefix(language: string): string {\n switch (language) {\n case \"python\":\n case \"py\":\n case \"bash\":\n case \"sh\":\n case \"shell\":\n case \"ruby\":\n case \"rb\":\n case \"yaml\":\n case \"yml\":\n case \"toml\":\n return \"#\";\n default:\n // Java, Go, TS/JS, C/C++, C#, Rust, Kotlin, Swift, Scala, Groovy…\n return \"//\";\n }\n}\n\nfunction buildAnnotatedSource(\n lines: string[],\n startLine: number,\n focalLine: number,\n language: string,\n): string {\n const focalIdx = focalLine - startLine;\n if (focalIdx < 0 || focalIdx >= lines.length) {\n return lines.join(\"\\n\");\n }\n const prefix = inlineCommentPrefix(language);\n return lines\n .map((src, i) => (i === focalIdx ? `${src} ${prefix} [!code error]` : src))\n .join(\"\\n\");\n}\n\nfunction SourceWindow({ frame }: { frame: ParsedStackFrame }) {\n const start = frame.sourceStartLine ?? 0;\n const focal = frame.line ?? -1;\n const lines = frame.sourceLines ?? [];\n const lineNumbers = frame.sourceLineNumbers;\n const language = frame.sourceLanguage ?? \"java\";\n\n const rows = useMemo(\n () =>\n lines.map((src, i) => ({\n source: src,\n lineNumber: lineNumbers?.[i] ?? start + i,\n })),\n [lineNumbers, lines, start],\n );\n\n const hasExplicitLineNumbers = lineNumbers != null && lineNumbers.length > 0;\n\n const annotatedSource = useMemo(\n () => buildAnnotatedSource(lines, start, focal, language),\n [lines, start, focal, language],\n );\n\n const [html, setHtml] = useState<string | null>(null);\n\n useEffect(() => {\n if (!annotatedSource || hasExplicitLineNumbers) {\n setHtml(null);\n return;\n }\n let cancelled = false;\n loadShikiTransformers()\n .then(({ transformerNotationErrorLevel }) =>\n highlightCode(annotatedSource, {\n lang: language,\n transformers: [transformerNotationErrorLevel()],\n }),\n )\n .then((out) => {\n if (!cancelled) setHtml(out);\n });\n return () => {\n cancelled = true;\n };\n }, [annotatedSource, hasExplicitLineNumbers, language]);\n\n // CSS-counter-driven line-number gutter: the wrapping <div> seeds a\n // counter that each rendered `.line` increments. `--shiki-start` lets\n // us start counting from the absolute frame line number rather than 1.\n // Without `start` we'd need a server-rendered `<ol start=\"...\">` which\n // would fight Shiki's own `<span class=\"line\">` markup.\n const counterStart = start - 1;\n\n if (!html || hasExplicitLineNumbers) {\n return <SourceRows rows={rows} focal={focal} />;\n }\n\n return (\n <div\n className=\"stacktrace-source ml-6 overflow-x-auto rounded border border-border/50 bg-muted/30 p-2 text-[11px] leading-relaxed\"\n style={{ [\"--shiki-start\" as string]: counterStart }}\n dangerouslySetInnerHTML={{ __html: html }}\n />\n );\n}\n\nfunction SourceRows({\n rows,\n focal,\n}: {\n rows: Array<{ source: string; lineNumber: number }>;\n focal: number;\n}) {\n return (\n <div className=\"mx-3 mb-2 ml-12 overflow-x-auto rounded border border-border/60 bg-muted/30 py-1 font-mono text-[11px] leading-relaxed\">\n {rows.map((row, i) => {\n const isFocal = row.lineNumber === focal;\n return (\n <div\n key={`${row.lineNumber}-${i}`}\n className={[\n \"grid min-w-max grid-cols-[3.5rem_minmax(24rem,1fr)] gap-3 px-2\",\n isFocal\n ? \"bg-red-500/10 font-semibold text-red-800 dark:text-red-300\"\n : \"text-foreground\",\n ].join(\" \")}\n >\n <span className=\"select-none text-right text-muted-foreground\">\n {isFocal ? \">\" : \"\"}\n {row.lineNumber}\n </span>\n <code className=\"whitespace-pre\">{row.source || \" \"}</code>\n </div>\n );\n })}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ParsedThread } from './jvm-stacktrace';
|
|
2
|
+
export declare function threadStateBadge(state: string): string;
|
|
3
|
+
export declare function threadStateDot(state: string): string;
|
|
4
|
+
export type ThreadCardProps = {
|
|
5
|
+
thread: ParsedThread;
|
|
6
|
+
search: string;
|
|
7
|
+
hideRuntimeOnly: boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare function ThreadCard({ thread, search, hideRuntimeOnly }: ThreadCardProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
//# sourceMappingURL=ThreadCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThreadCard.d.ts","sourceRoot":"","sources":["../../../src/data/diagnostics/ThreadCard.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAgBtD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAgBpD;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,wBAAgB,UAAU,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,EAAE,eAAe,2CAqC9E"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
+
import { JvmStackTrace } from "./JvmStackTrace.js";
|
|
3
|
+
function threadStateBadge(state) {
|
|
4
|
+
switch (state) {
|
|
5
|
+
case "runnable":
|
|
6
|
+
return "bg-green-50 text-green-700 dark:bg-green-500/20 dark:text-green-300";
|
|
7
|
+
case "blocked":
|
|
8
|
+
return "bg-red-50 text-red-700 dark:bg-red-500/20 dark:text-red-300";
|
|
9
|
+
case "waiting":
|
|
10
|
+
case "timed_waiting":
|
|
11
|
+
return "bg-blue-50 text-blue-700 dark:bg-blue-500/20 dark:text-blue-300";
|
|
12
|
+
case "new":
|
|
13
|
+
return "bg-amber-50 text-amber-700 dark:bg-amber-500/20 dark:text-amber-300";
|
|
14
|
+
case "terminated":
|
|
15
|
+
return "bg-muted text-muted-foreground";
|
|
16
|
+
default:
|
|
17
|
+
return "bg-muted text-muted-foreground";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function threadStateDot(state) {
|
|
21
|
+
switch (state) {
|
|
22
|
+
case "runnable":
|
|
23
|
+
return "bg-green-500";
|
|
24
|
+
case "blocked":
|
|
25
|
+
return "bg-red-500";
|
|
26
|
+
case "waiting":
|
|
27
|
+
case "timed_waiting":
|
|
28
|
+
return "bg-blue-500";
|
|
29
|
+
case "new":
|
|
30
|
+
return "bg-amber-500";
|
|
31
|
+
case "terminated":
|
|
32
|
+
return "bg-muted-foreground/40";
|
|
33
|
+
default:
|
|
34
|
+
return "bg-muted-foreground/40";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function ThreadCard({ thread, search, hideRuntimeOnly }) {
|
|
38
|
+
const frames = hideRuntimeOnly ? thread.frames.filter((f) => f.kind !== "frame" || !f.runtime) : thread.frames;
|
|
39
|
+
const defaultOpen = thread.state === "runnable" || thread.state === "blocked" || !!search;
|
|
40
|
+
return /* @__PURE__ */ jsxs("details", { className: "border-0 bg-transparent", open: defaultOpen, children: [
|
|
41
|
+
/* @__PURE__ */ jsx("summary", { className: "cursor-pointer list-none px-0 py-1", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
42
|
+
/* @__PURE__ */ jsxs("span", { className: "font-mono text-xs font-semibold text-foreground", children: [
|
|
43
|
+
"#",
|
|
44
|
+
thread.id
|
|
45
|
+
] }),
|
|
46
|
+
/* @__PURE__ */ jsx("span", { className: "truncate font-mono text-xs text-foreground", children: thread.name }),
|
|
47
|
+
/* @__PURE__ */ jsxs(
|
|
48
|
+
"span",
|
|
49
|
+
{
|
|
50
|
+
className: `inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] ${threadStateBadge(
|
|
51
|
+
thread.state
|
|
52
|
+
)}`,
|
|
53
|
+
children: [
|
|
54
|
+
/* @__PURE__ */ jsx("span", { className: `h-2 w-2 rounded-full ${threadStateDot(thread.state)}` }),
|
|
55
|
+
thread.rawState || thread.state
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
),
|
|
59
|
+
thread.daemon && /* @__PURE__ */ jsx("span", { className: "rounded-full bg-muted px-1.5 py-0.5 text-[10px] text-muted-foreground", children: "daemon" }),
|
|
60
|
+
/* @__PURE__ */ jsxs("span", { className: "text-[11px] text-muted-foreground", children: [
|
|
61
|
+
frames.length,
|
|
62
|
+
"f"
|
|
63
|
+
] }),
|
|
64
|
+
thread.userFrameCount > 0 && /* @__PURE__ */ jsxs("span", { className: "text-[11px] text-muted-foreground", children: [
|
|
65
|
+
thread.userFrameCount,
|
|
66
|
+
"u"
|
|
67
|
+
] }),
|
|
68
|
+
thread.topFunction && /* @__PURE__ */ jsx("span", { className: "truncate text-[11px] text-muted-foreground", children: thread.topFunction })
|
|
69
|
+
] }) }),
|
|
70
|
+
/* @__PURE__ */ jsx(JvmStackTrace, { frames, className: "space-y-0.5 py-1 pl-3" })
|
|
71
|
+
] });
|
|
72
|
+
}
|
|
73
|
+
export {
|
|
74
|
+
ThreadCard,
|
|
75
|
+
threadStateBadge,
|
|
76
|
+
threadStateDot
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=ThreadCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThreadCard.js","sources":["../../../src/data/diagnostics/ThreadCard.tsx"],"sourcesContent":["import { JvmStackTrace } from \"./JvmStackTrace\";\nimport type { ParsedThread } from \"./jvm-stacktrace\";\n\nexport function threadStateBadge(state: string): string {\n switch (state) {\n case \"runnable\":\n return \"bg-green-50 text-green-700 dark:bg-green-500/20 dark:text-green-300\";\n case \"blocked\":\n return \"bg-red-50 text-red-700 dark:bg-red-500/20 dark:text-red-300\";\n case \"waiting\":\n case \"timed_waiting\":\n return \"bg-blue-50 text-blue-700 dark:bg-blue-500/20 dark:text-blue-300\";\n case \"new\":\n return \"bg-amber-50 text-amber-700 dark:bg-amber-500/20 dark:text-amber-300\";\n case \"terminated\":\n return \"bg-muted text-muted-foreground\";\n default:\n return \"bg-muted text-muted-foreground\";\n }\n}\n\nexport function threadStateDot(state: string): string {\n switch (state) {\n case \"runnable\":\n return \"bg-green-500\";\n case \"blocked\":\n return \"bg-red-500\";\n case \"waiting\":\n case \"timed_waiting\":\n return \"bg-blue-500\";\n case \"new\":\n return \"bg-amber-500\";\n case \"terminated\":\n return \"bg-muted-foreground/40\";\n default:\n return \"bg-muted-foreground/40\";\n }\n}\n\nexport type ThreadCardProps = {\n thread: ParsedThread;\n search: string;\n hideRuntimeOnly: boolean;\n};\n\nexport function ThreadCard({ thread, search, hideRuntimeOnly }: ThreadCardProps) {\n const frames = hideRuntimeOnly\n ? thread.frames.filter((f) => f.kind !== \"frame\" || !f.runtime)\n : thread.frames;\n const defaultOpen = thread.state === \"runnable\" || thread.state === \"blocked\" || !!search;\n\n return (\n <details className=\"border-0 bg-transparent\" open={defaultOpen}>\n <summary className=\"cursor-pointer list-none px-0 py-1\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <span className=\"font-mono text-xs font-semibold text-foreground\">#{thread.id}</span>\n <span className=\"truncate font-mono text-xs text-foreground\">{thread.name}</span>\n <span\n className={`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[11px] ${threadStateBadge(\n thread.state,\n )}`}\n >\n <span className={`h-2 w-2 rounded-full ${threadStateDot(thread.state)}`} />\n {thread.rawState || thread.state}\n </span>\n {thread.daemon && (\n <span className=\"rounded-full bg-muted px-1.5 py-0.5 text-[10px] text-muted-foreground\">\n daemon\n </span>\n )}\n <span className=\"text-[11px] text-muted-foreground\">{frames.length}f</span>\n {thread.userFrameCount > 0 && (\n <span className=\"text-[11px] text-muted-foreground\">{thread.userFrameCount}u</span>\n )}\n {thread.topFunction && (\n <span className=\"truncate text-[11px] text-muted-foreground\">{thread.topFunction}</span>\n )}\n </div>\n </summary>\n <JvmStackTrace frames={frames} className=\"space-y-0.5 py-1 pl-3\" />\n </details>\n );\n}\n"],"names":[],"mappings":";;AAGO,SAAS,iBAAiB,OAAuB;AACtD,UAAQ,OAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EAAA;AAEb;AAEO,SAAS,eAAe,OAAuB;AACpD,UAAQ,OAAA;AAAA,IACN,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EAAA;AAEb;AAQO,SAAS,WAAW,EAAE,QAAQ,QAAQ,mBAAoC;AAC/E,QAAM,SAAS,kBACX,OAAO,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,WAAW,CAAC,EAAE,OAAO,IAC5D,OAAO;AACX,QAAM,cAAc,OAAO,UAAU,cAAc,OAAO,UAAU,aAAa,CAAC,CAAC;AAEnF,SACE,qBAAC,WAAA,EAAQ,WAAU,2BAA0B,MAAM,aACjD,UAAA;AAAA,IAAA,oBAAC,aAAQ,WAAU,sCACjB,UAAA,qBAAC,OAAA,EAAI,WAAU,qCACb,UAAA;AAAA,MAAA,qBAAC,QAAA,EAAK,WAAU,mDAAkD,UAAA;AAAA,QAAA;AAAA,QAAE,OAAO;AAAA,MAAA,GAAG;AAAA,MAC9E,oBAAC,QAAA,EAAK,WAAU,8CAA8C,iBAAO,MAAK;AAAA,MAC1E;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,WAAW,uEAAuE;AAAA,YAChF,OAAO;AAAA,UAAA,CACR;AAAA,UAED,UAAA;AAAA,YAAA,oBAAC,UAAK,WAAW,wBAAwB,eAAe,OAAO,KAAK,CAAC,IAAI;AAAA,YACxE,OAAO,YAAY,OAAO;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAE5B,OAAO,UACN,oBAAC,QAAA,EAAK,WAAU,yEAAwE,UAAA,UAExF;AAAA,MAEF,qBAAC,QAAA,EAAK,WAAU,qCAAqC,UAAA;AAAA,QAAA,OAAO;AAAA,QAAO;AAAA,MAAA,GAAC;AAAA,MACnE,OAAO,iBAAiB,KACvB,qBAAC,QAAA,EAAK,WAAU,qCAAqC,UAAA;AAAA,QAAA,OAAO;AAAA,QAAe;AAAA,MAAA,GAAC;AAAA,MAE7E,OAAO,eACN,oBAAC,UAAK,WAAU,8CAA8C,iBAAO,YAAA,CAAY;AAAA,IAAA,EAAA,CAErF,EAAA,CACF;AAAA,IACA,oBAAC,eAAA,EAAc,QAAgB,WAAU,wBAAA,CAAwB;AAAA,EAAA,GACnE;AAEJ;"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type ErrorDiagnostics = {
|
|
2
|
+
message: string;
|
|
3
|
+
trace?: string;
|
|
4
|
+
time?: string;
|
|
5
|
+
stacktrace?: string;
|
|
6
|
+
context: Array<[string, string]>;
|
|
7
|
+
raw?: unknown;
|
|
8
|
+
};
|
|
9
|
+
export type ParsedErrorStackTrace = {
|
|
10
|
+
headline?: string;
|
|
11
|
+
frames: ErrorStackFrame[];
|
|
12
|
+
unparsed: string[];
|
|
13
|
+
raw: string;
|
|
14
|
+
};
|
|
15
|
+
export type ErrorStackFrame = {
|
|
16
|
+
raw: string;
|
|
17
|
+
file: string;
|
|
18
|
+
line: number;
|
|
19
|
+
functionName?: string;
|
|
20
|
+
};
|
|
21
|
+
export declare function normalizeErrorDiagnostics(value: unknown, fallback?: string | null): ErrorDiagnostics | null;
|
|
22
|
+
export declare function parseDiagnosticsStackTrace(stacktrace: string): ParsedErrorStackTrace;
|
|
23
|
+
export declare function parseInlineJsonContextValue(value: string): unknown | null;
|
|
24
|
+
export declare function compactStackPath(file: string): string;
|
|
25
|
+
export declare function isApplicationStackFrame(file: string): boolean;
|
|
26
|
+
//# sourceMappingURL=error-diagnostics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-diagnostics.d.ts","sourceRoot":"","sources":["../../../src/data/diagnostics/error-diagnostics.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACjC,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,OAAO,EACd,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GACvB,gBAAgB,GAAG,IAAI,CA0BzB;AAED,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,qBAAqB,CA4BpF;AAED,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAQzE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,UAM5C;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,WAKnD"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
function normalizeErrorDiagnostics(value, fallback) {
|
|
2
|
+
if (!value) return null;
|
|
3
|
+
if (typeof value === "string") {
|
|
4
|
+
return value.trim() ? { message: value, context: [] } : null;
|
|
5
|
+
}
|
|
6
|
+
const record = objectRecord(value);
|
|
7
|
+
if (!record) return null;
|
|
8
|
+
const nested = objectRecord(record.error) ?? objectRecord(record.diagnostics);
|
|
9
|
+
if (nested && nested !== record) {
|
|
10
|
+
return normalizeErrorDiagnostics(nested, fallback);
|
|
11
|
+
}
|
|
12
|
+
const message = firstString(record, ["error", "message", "msg", "reason", "detail", "details"]) ?? fallback;
|
|
13
|
+
const trace = firstString(record, ["trace", "trace_id", "traceId", "traceID"]);
|
|
14
|
+
const stacktrace = firstString(record, ["stacktrace", "stack_trace", "stackTrace", "stack"]);
|
|
15
|
+
const time = firstString(record, ["time", "timestamp", "created_at"]);
|
|
16
|
+
const context = contextEntries(record.context);
|
|
17
|
+
if (!message && !trace && !stacktrace && context.length === 0) return null;
|
|
18
|
+
return {
|
|
19
|
+
message: message ?? "Action failed",
|
|
20
|
+
context,
|
|
21
|
+
raw: value,
|
|
22
|
+
...trace !== void 0 ? { trace } : {},
|
|
23
|
+
...time !== void 0 ? { time } : {},
|
|
24
|
+
...stacktrace !== void 0 ? { stacktrace } : {}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function parseDiagnosticsStackTrace(stacktrace) {
|
|
28
|
+
const lines = stacktrace.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
29
|
+
const frames = [];
|
|
30
|
+
const unparsed = [];
|
|
31
|
+
let headline;
|
|
32
|
+
for (const line of lines) {
|
|
33
|
+
const frame = parseStackTraceFrame(line);
|
|
34
|
+
if (frame) {
|
|
35
|
+
frames.push(frame);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (!headline && !line.startsWith("--- at ")) {
|
|
39
|
+
headline = line;
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
unparsed.push(line);
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
frames,
|
|
46
|
+
unparsed,
|
|
47
|
+
raw: stacktrace,
|
|
48
|
+
...headline !== void 0 ? { headline } : {}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function parseInlineJsonContextValue(value) {
|
|
52
|
+
const trimmed = value.trim();
|
|
53
|
+
if (!trimmed || !/^[{[]/.test(trimmed)) return null;
|
|
54
|
+
try {
|
|
55
|
+
return JSON.parse(trimmed);
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function compactStackPath(file) {
|
|
61
|
+
return file.replace(/^github\.com\/flanksource\/incident-commander\//, "").replace(/^github\.com\/flanksource\//, "flanksource/").replace(/^.*\/go\/pkg\/mod\//, "pkg/mod/").replace(/^.*\/incident-commander\//, "");
|
|
62
|
+
}
|
|
63
|
+
function isApplicationStackFrame(file) {
|
|
64
|
+
return file.includes("github.com/flanksource/incident-commander/") || file.includes("/incident-commander/");
|
|
65
|
+
}
|
|
66
|
+
function parseStackTraceFrame(line) {
|
|
67
|
+
var _a;
|
|
68
|
+
const match = line.match(/^--- at (.+):(\d+)(?:\s+(.+))?$/);
|
|
69
|
+
if (!match) return null;
|
|
70
|
+
return {
|
|
71
|
+
raw: line,
|
|
72
|
+
file: match[1] ?? "",
|
|
73
|
+
line: Number(match[2] ?? 0),
|
|
74
|
+
...((_a = match[3]) == null ? void 0 : _a.trim()) ? { functionName: match[3].trim() } : {}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function objectRecord(value) {
|
|
78
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
function firstString(record, keys) {
|
|
82
|
+
for (const key of keys) {
|
|
83
|
+
const value = record[key];
|
|
84
|
+
if (typeof value === "string" && value.trim()) return value;
|
|
85
|
+
}
|
|
86
|
+
return void 0;
|
|
87
|
+
}
|
|
88
|
+
function contextEntries(value) {
|
|
89
|
+
const record = objectRecord(value);
|
|
90
|
+
if (!record) return [];
|
|
91
|
+
return Object.entries(record).filter(
|
|
92
|
+
([, entryValue]) => entryValue !== void 0 && entryValue !== null && entryValue !== ""
|
|
93
|
+
).map(([key, entryValue]) => [key, stringifyValue(entryValue)]);
|
|
94
|
+
}
|
|
95
|
+
function stringifyValue(value) {
|
|
96
|
+
if (value === null || value === void 0 || value === "") return "-";
|
|
97
|
+
if (typeof value === "string") return value;
|
|
98
|
+
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
99
|
+
return JSON.stringify(value);
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
compactStackPath,
|
|
103
|
+
isApplicationStackFrame,
|
|
104
|
+
normalizeErrorDiagnostics,
|
|
105
|
+
parseDiagnosticsStackTrace,
|
|
106
|
+
parseInlineJsonContextValue
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=error-diagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-diagnostics.js","sources":["../../../src/data/diagnostics/error-diagnostics.ts"],"sourcesContent":["// Normalize ad-hoc error payloads (oops JSON, plain strings, nested objects)\n// into the shape ErrorDetails consumes. Mirrors what `samber/oops` emits\n// from `OopsError.MarshalJSON()` on the Go side.\n\nexport type ErrorDiagnostics = {\n message: string;\n trace?: string;\n time?: string;\n stacktrace?: string;\n context: Array<[string, string]>;\n raw?: unknown;\n};\n\nexport type ParsedErrorStackTrace = {\n headline?: string;\n frames: ErrorStackFrame[];\n unparsed: string[];\n raw: string;\n};\n\nexport type ErrorStackFrame = {\n raw: string;\n file: string;\n line: number;\n functionName?: string;\n};\n\nexport function normalizeErrorDiagnostics(\n value: unknown,\n fallback?: string | null,\n): ErrorDiagnostics | null {\n if (!value) return null;\n if (typeof value === \"string\") {\n return value.trim() ? { message: value, context: [] } : null;\n }\n const record = objectRecord(value);\n if (!record) return null;\n const nested = objectRecord(record.error) ?? objectRecord(record.diagnostics);\n if (nested && nested !== record) {\n return normalizeErrorDiagnostics(nested, fallback);\n }\n const message =\n firstString(record, [\"error\", \"message\", \"msg\", \"reason\", \"detail\", \"details\"]) ?? fallback;\n const trace = firstString(record, [\"trace\", \"trace_id\", \"traceId\", \"traceID\"]);\n const stacktrace = firstString(record, [\"stacktrace\", \"stack_trace\", \"stackTrace\", \"stack\"]);\n const time = firstString(record, [\"time\", \"timestamp\", \"created_at\"]);\n const context = contextEntries(record.context);\n if (!message && !trace && !stacktrace && context.length === 0) return null;\n return {\n message: message ?? \"Action failed\",\n context,\n raw: value,\n ...(trace !== undefined ? { trace } : {}),\n ...(time !== undefined ? { time } : {}),\n ...(stacktrace !== undefined ? { stacktrace } : {}),\n };\n}\n\nexport function parseDiagnosticsStackTrace(stacktrace: string): ParsedErrorStackTrace {\n const lines = stacktrace\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter(Boolean);\n const frames: ErrorStackFrame[] = [];\n const unparsed: string[] = [];\n let headline: string | undefined;\n\n for (const line of lines) {\n const frame = parseStackTraceFrame(line);\n if (frame) {\n frames.push(frame);\n continue;\n }\n if (!headline && !line.startsWith(\"--- at \")) {\n headline = line;\n continue;\n }\n unparsed.push(line);\n }\n\n return {\n frames,\n unparsed,\n raw: stacktrace,\n ...(headline !== undefined ? { headline } : {}),\n };\n}\n\nexport function parseInlineJsonContextValue(value: string): unknown | null {\n const trimmed = value.trim();\n if (!trimmed || !/^[{[]/.test(trimmed)) return null;\n try {\n return JSON.parse(trimmed);\n } catch {\n return null;\n }\n}\n\nexport function compactStackPath(file: string) {\n return file\n .replace(/^github\\.com\\/flanksource\\/incident-commander\\//, \"\")\n .replace(/^github\\.com\\/flanksource\\//, \"flanksource/\")\n .replace(/^.*\\/go\\/pkg\\/mod\\//, \"pkg/mod/\")\n .replace(/^.*\\/incident-commander\\//, \"\");\n}\n\nexport function isApplicationStackFrame(file: string) {\n return (\n file.includes(\"github.com/flanksource/incident-commander/\") ||\n file.includes(\"/incident-commander/\")\n );\n}\n\nfunction parseStackTraceFrame(line: string): ErrorStackFrame | null {\n const match = line.match(/^--- at (.+):(\\d+)(?:\\s+(.+))?$/);\n if (!match) return null;\n return {\n raw: line,\n file: match[1] ?? \"\",\n line: Number(match[2] ?? 0),\n ...(match[3]?.trim() ? { functionName: match[3]!.trim() } : {}),\n };\n}\n\nfunction objectRecord(value: unknown): Record<string, unknown> | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return null;\n return value as Record<string, unknown>;\n}\n\nfunction firstString(record: Record<string, unknown>, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = record[key];\n if (typeof value === \"string\" && value.trim()) return value;\n }\n return undefined;\n}\n\nfunction contextEntries(value: unknown): Array<[string, string]> {\n const record = objectRecord(value);\n if (!record) return [];\n return Object.entries(record)\n .filter(\n ([, entryValue]) => entryValue !== undefined && entryValue !== null && entryValue !== \"\",\n )\n .map(([key, entryValue]) => [key, stringifyValue(entryValue)]);\n}\n\nfunction stringifyValue(value: unknown): string {\n if (value === null || value === undefined || value === \"\") return \"-\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n return JSON.stringify(value);\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../../src/data/diagnostics/fixtures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAyB3C,eAAO,MAAM,iBAAiB,EAAE,WA+C/B,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface ParsedThreadFrame {
|
|
2
|
+
functionName: string;
|
|
3
|
+
displayName: string;
|
|
4
|
+
file?: string;
|
|
5
|
+
line?: number;
|
|
6
|
+
location?: string;
|
|
7
|
+
kind: "frame" | "locked" | "waiting_on" | "waiting_to_lock" | "parking";
|
|
8
|
+
runtime: boolean;
|
|
9
|
+
nativeMethod: boolean;
|
|
10
|
+
annotationText?: string;
|
|
11
|
+
class?: string;
|
|
12
|
+
method?: string;
|
|
13
|
+
sourceLines?: string[];
|
|
14
|
+
sourceLineNumbers?: number[];
|
|
15
|
+
sourceStartLine?: number;
|
|
16
|
+
sourceLanguage?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ParsedThread {
|
|
19
|
+
id: number;
|
|
20
|
+
nid?: string;
|
|
21
|
+
name: string;
|
|
22
|
+
state: string;
|
|
23
|
+
rawState: string;
|
|
24
|
+
priority?: number;
|
|
25
|
+
daemon?: boolean;
|
|
26
|
+
frames: ParsedThreadFrame[];
|
|
27
|
+
raw: string;
|
|
28
|
+
userFrameCount: number;
|
|
29
|
+
topFunction?: string;
|
|
30
|
+
searchText: string;
|
|
31
|
+
}
|
|
32
|
+
export declare function parseJvmThreadDump(text: string): ParsedThread[];
|
|
33
|
+
export declare function countThreadsByState(threads: ParsedThread[]): Map<string, number>;
|
|
34
|
+
//# sourceMappingURL=jvm-stacktrace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jvm-stacktrace.d.ts","sourceRoot":"","sources":["../../../src/data/diagnostics/jvm-stacktrace.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,YAAY,GAAG,iBAAiB,GAAG,SAAS,CAAC;IACxE,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IAKxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAIhB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AASD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CAa/D;AA4JD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAIhF"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
const headerRe = /^"(?<name>[^"]*)"(?<rest>.*)$/;
|
|
2
|
+
const stateRe = /^\s*java\.lang\.Thread\.State:\s+(?<state>[A-Z_]+)(?:\s+\((?<sub>[^)]+)\))?/;
|
|
3
|
+
const frameRe = /^\s*at\s+(?<fn>[^\s(]+)\((?<src>[^)]+)\)\s*$/;
|
|
4
|
+
const srcLineRe = /^(?<file>[^:]+):(?<line>\d+)$/;
|
|
5
|
+
const annotationRe = /^\s*-\s+(?<kind>locked|waiting on|waiting to lock|parking to wait for)\b(?<rest>.*)$/;
|
|
6
|
+
function parseJvmThreadDump(text) {
|
|
7
|
+
const trimmed = text.trim();
|
|
8
|
+
if (!trimmed) return [];
|
|
9
|
+
const blocks = splitIntoThreadBlocks(trimmed);
|
|
10
|
+
const threads = [];
|
|
11
|
+
for (const block of blocks) {
|
|
12
|
+
const parsed = parseThreadBlock(block);
|
|
13
|
+
if (parsed) threads.push(parsed);
|
|
14
|
+
}
|
|
15
|
+
return threads;
|
|
16
|
+
}
|
|
17
|
+
function splitIntoThreadBlocks(text) {
|
|
18
|
+
const out = [];
|
|
19
|
+
let current = [];
|
|
20
|
+
const lines = text.split("\n");
|
|
21
|
+
for (const raw of lines) {
|
|
22
|
+
const line = raw.replace(/\r$/, "");
|
|
23
|
+
if (line.startsWith('"') && current.length > 0) {
|
|
24
|
+
out.push(current.join("\n"));
|
|
25
|
+
current = [line];
|
|
26
|
+
} else {
|
|
27
|
+
current.push(line);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (current.length > 0) out.push(current.join("\n"));
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
function parseThreadBlock(block) {
|
|
34
|
+
var _a, _b, _c, _d;
|
|
35
|
+
const lines = block.split("\n");
|
|
36
|
+
const header = ((_a = lines[0]) == null ? void 0 : _a.trim()) ?? "";
|
|
37
|
+
const headerMatch = headerRe.exec(header);
|
|
38
|
+
if (!(headerMatch == null ? void 0 : headerMatch.groups)) return null;
|
|
39
|
+
const name = headerMatch.groups.name;
|
|
40
|
+
if (!name) return null;
|
|
41
|
+
const rest = headerMatch.groups.rest ?? "";
|
|
42
|
+
const idMatch = /#(\d+)\b/.exec(rest);
|
|
43
|
+
const prioMatch = /\bprio=(\d+)/.exec(rest);
|
|
44
|
+
const nidMatch = /\bnid=(0x[0-9a-f]+)/i.exec(rest);
|
|
45
|
+
const daemon = /\bdaemon\b/.test(rest);
|
|
46
|
+
const headerStateTrail = extractHeaderStateTrail(rest);
|
|
47
|
+
let rawState = headerStateTrail ?? "";
|
|
48
|
+
let state = normalizeJvmState(rawState);
|
|
49
|
+
const frames = [];
|
|
50
|
+
for (let i = 1; i < lines.length; i++) {
|
|
51
|
+
const line = lines[i];
|
|
52
|
+
if (line == null) continue;
|
|
53
|
+
if (!line.trim()) continue;
|
|
54
|
+
const stateMatch = stateRe.exec(line);
|
|
55
|
+
if (stateMatch == null ? void 0 : stateMatch.groups) {
|
|
56
|
+
const primary = stateMatch.groups.state;
|
|
57
|
+
if (!primary) continue;
|
|
58
|
+
const sub = stateMatch.groups.sub;
|
|
59
|
+
rawState = sub ? `${primary} (${sub})` : primary;
|
|
60
|
+
state = normalizeJvmState(primary);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const frameMatch = frameRe.exec(line);
|
|
64
|
+
if (frameMatch == null ? void 0 : frameMatch.groups) {
|
|
65
|
+
const functionName = frameMatch.groups.fn;
|
|
66
|
+
const src = frameMatch.groups.src;
|
|
67
|
+
if (!functionName || !src) continue;
|
|
68
|
+
const frame = {
|
|
69
|
+
functionName,
|
|
70
|
+
displayName: sanitizeJvmFunctionName(functionName),
|
|
71
|
+
kind: "frame",
|
|
72
|
+
runtime: isJvmRuntimeFrame(functionName),
|
|
73
|
+
nativeMethod: src === "Native Method"
|
|
74
|
+
};
|
|
75
|
+
const srcMatch = srcLineRe.exec(src);
|
|
76
|
+
if (((_b = srcMatch == null ? void 0 : srcMatch.groups) == null ? void 0 : _b.file) && srcMatch.groups.line) {
|
|
77
|
+
frame.file = srcMatch.groups.file;
|
|
78
|
+
frame.line = Number(srcMatch.groups.line);
|
|
79
|
+
frame.location = `${frame.file}:${frame.line}`;
|
|
80
|
+
} else if (src === "Native Method") {
|
|
81
|
+
frame.location = "Native Method";
|
|
82
|
+
} else {
|
|
83
|
+
frame.location = src;
|
|
84
|
+
}
|
|
85
|
+
frames.push(frame);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const annoMatch = annotationRe.exec(line);
|
|
89
|
+
if ((_c = annoMatch == null ? void 0 : annoMatch.groups) == null ? void 0 : _c.kind) {
|
|
90
|
+
const annotationKind = annoMatch.groups.kind;
|
|
91
|
+
const kind = mapAnnotationKind(annotationKind);
|
|
92
|
+
frames.push({
|
|
93
|
+
functionName: annotationKind,
|
|
94
|
+
displayName: annotationKind,
|
|
95
|
+
kind,
|
|
96
|
+
runtime: false,
|
|
97
|
+
nativeMethod: false,
|
|
98
|
+
annotationText: (annoMatch.groups.rest ?? "").trim()
|
|
99
|
+
});
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const userFrameCount = frames.filter((f) => f.kind === "frame" && !f.runtime).length;
|
|
104
|
+
const topFunction = (_d = frames.find((f) => f.kind === "frame")) == null ? void 0 : _d.functionName;
|
|
105
|
+
const searchText = [
|
|
106
|
+
header,
|
|
107
|
+
...frames.map((f) => `${f.functionName} ${f.location ?? ""} ${f.annotationText ?? ""}`)
|
|
108
|
+
].join("\n").toLowerCase();
|
|
109
|
+
return {
|
|
110
|
+
id: idMatch ? Number(idMatch[1]) : deriveSyntheticId(name, rest),
|
|
111
|
+
name,
|
|
112
|
+
state: state || "unknown",
|
|
113
|
+
rawState: rawState || "",
|
|
114
|
+
daemon,
|
|
115
|
+
frames,
|
|
116
|
+
raw: block,
|
|
117
|
+
userFrameCount,
|
|
118
|
+
searchText,
|
|
119
|
+
...(nidMatch == null ? void 0 : nidMatch[1]) !== void 0 ? { nid: nidMatch[1] } : {},
|
|
120
|
+
...(prioMatch == null ? void 0 : prioMatch[1]) !== void 0 ? { priority: Number(prioMatch[1]) } : {},
|
|
121
|
+
...topFunction !== void 0 ? { topFunction } : {}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function extractHeaderStateTrail(rest) {
|
|
125
|
+
var _a, _b;
|
|
126
|
+
const tail = rest.match(/nid=0x[0-9a-f]+\s+(?<desc>[^[]+?)(?:\s+\[0x[0-9a-f]+\])?\s*$/i);
|
|
127
|
+
return (_b = (_a = tail == null ? void 0 : tail.groups) == null ? void 0 : _a.desc) == null ? void 0 : _b.trim();
|
|
128
|
+
}
|
|
129
|
+
function deriveSyntheticId(name, rest) {
|
|
130
|
+
const tid = /\btid=(0x[0-9a-f]+)/i.exec(rest);
|
|
131
|
+
if (tid == null ? void 0 : tid[1]) {
|
|
132
|
+
const hex = tid[1].slice(2);
|
|
133
|
+
const n = Number.parseInt(hex.slice(-8), 16);
|
|
134
|
+
if (Number.isFinite(n)) return n;
|
|
135
|
+
}
|
|
136
|
+
let h = 0;
|
|
137
|
+
for (let i = 0; i < name.length; i++) h = h * 31 + name.charCodeAt(i) | 0;
|
|
138
|
+
return Math.abs(h);
|
|
139
|
+
}
|
|
140
|
+
function mapAnnotationKind(kind) {
|
|
141
|
+
switch (kind) {
|
|
142
|
+
case "locked":
|
|
143
|
+
return "locked";
|
|
144
|
+
case "waiting on":
|
|
145
|
+
return "waiting_on";
|
|
146
|
+
case "waiting to lock":
|
|
147
|
+
return "waiting_to_lock";
|
|
148
|
+
case "parking to wait for":
|
|
149
|
+
return "parking";
|
|
150
|
+
default:
|
|
151
|
+
return "frame";
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function countThreadsByState(threads) {
|
|
155
|
+
const counts = /* @__PURE__ */ new Map();
|
|
156
|
+
for (const t of threads) counts.set(t.state, (counts.get(t.state) ?? 0) + 1);
|
|
157
|
+
return counts;
|
|
158
|
+
}
|
|
159
|
+
function normalizeJvmState(value) {
|
|
160
|
+
if (!value) return "";
|
|
161
|
+
const upper = value.trim().toUpperCase();
|
|
162
|
+
if (upper.startsWith("RUNNABLE")) return "runnable";
|
|
163
|
+
if (upper.startsWith("TIMED_WAITING")) return "timed_waiting";
|
|
164
|
+
if (upper.startsWith("WAITING")) return "waiting";
|
|
165
|
+
if (upper.startsWith("BLOCKED")) return "blocked";
|
|
166
|
+
if (upper.startsWith("NEW")) return "new";
|
|
167
|
+
if (upper.startsWith("TERMINATED")) return "terminated";
|
|
168
|
+
const lower = value.trim().toLowerCase();
|
|
169
|
+
if (lower.includes("runnable")) return "runnable";
|
|
170
|
+
if (lower.includes("waiting on condition") || lower.includes("sleeping")) return "timed_waiting";
|
|
171
|
+
if (lower.includes("waiting")) return "waiting";
|
|
172
|
+
if (lower.includes("blocked")) return "blocked";
|
|
173
|
+
return lower.split(/\s+/)[0] ?? "";
|
|
174
|
+
}
|
|
175
|
+
const runtimePrefixes = ["java.", "javax.", "sun.", "jdk.", "com.sun.", "oracle.jrockit."];
|
|
176
|
+
function isJvmRuntimeFrame(functionName) {
|
|
177
|
+
return runtimePrefixes.some((p) => functionName.startsWith(p));
|
|
178
|
+
}
|
|
179
|
+
function sanitizeJvmFunctionName(functionName) {
|
|
180
|
+
const parts = functionName.split(".");
|
|
181
|
+
if (parts.length < 2) return functionName;
|
|
182
|
+
const method = parts[parts.length - 1];
|
|
183
|
+
const cls = parts[parts.length - 2];
|
|
184
|
+
return `${cls}.${method}`;
|
|
185
|
+
}
|
|
186
|
+
export {
|
|
187
|
+
countThreadsByState,
|
|
188
|
+
parseJvmThreadDump
|
|
189
|
+
};
|
|
190
|
+
//# sourceMappingURL=jvm-stacktrace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jvm-stacktrace.js","sources":["../../../src/data/diagnostics/jvm-stacktrace.ts"],"sourcesContent":["export interface ParsedThreadFrame {\n functionName: string;\n displayName: string;\n file?: string;\n line?: number;\n location?: string;\n kind: \"frame\" | \"locked\" | \"waiting_on\" | \"waiting_to_lock\" | \"parking\";\n runtime: boolean;\n nativeMethod: boolean;\n annotationText?: string;\n // Optional fully-qualified class name (e.g. \"com.example.admin.pas.Foo\").\n // Lets renderers filter or group by package without re-splitting\n // functionName. Populated by parseJavaStackTrace; left undefined by the\n // thread-dump parser since its frames are raw \"fn(src)\" pairs.\n class?: string;\n method?: string;\n // Optional source-context window populated by clicky.SourceResolver\n // (or its TS equivalent). sourceLines[line - sourceStartLine] is the focal\n // line. Empty/undefined when no resolver was attached.\n sourceLines?: string[];\n sourceLineNumbers?: number[];\n sourceStartLine?: number;\n sourceLanguage?: string;\n}\n\nexport interface ParsedThread {\n id: number;\n nid?: string;\n name: string;\n state: string;\n rawState: string;\n priority?: number;\n daemon?: boolean;\n frames: ParsedThreadFrame[];\n raw: string;\n userFrameCount: number;\n topFunction?: string;\n searchText: string;\n}\n\nconst headerRe = /^\"(?<name>[^\"]*)\"(?<rest>.*)$/;\nconst stateRe = /^\\s*java\\.lang\\.Thread\\.State:\\s+(?<state>[A-Z_]+)(?:\\s+\\((?<sub>[^)]+)\\))?/;\nconst frameRe = /^\\s*at\\s+(?<fn>[^\\s(]+)\\((?<src>[^)]+)\\)\\s*$/;\nconst srcLineRe = /^(?<file>[^:]+):(?<line>\\d+)$/;\nconst annotationRe =\n /^\\s*-\\s+(?<kind>locked|waiting on|waiting to lock|parking to wait for)\\b(?<rest>.*)$/;\n\nexport function parseJvmThreadDump(text: string): ParsedThread[] {\n const trimmed = text.trim();\n if (!trimmed) return [];\n\n // Split on blank lines OR on a new `\"...\"` header that follows immediately.\n const blocks = splitIntoThreadBlocks(trimmed);\n const threads: ParsedThread[] = [];\n\n for (const block of blocks) {\n const parsed = parseThreadBlock(block);\n if (parsed) threads.push(parsed);\n }\n return threads;\n}\n\nfunction splitIntoThreadBlocks(text: string): string[] {\n const out: string[] = [];\n let current: string[] = [];\n const lines = text.split(\"\\n\");\n for (const raw of lines) {\n const line = raw.replace(/\\r$/, \"\");\n if (line.startsWith('\"') && current.length > 0) {\n out.push(current.join(\"\\n\"));\n current = [line];\n } else {\n current.push(line);\n }\n }\n if (current.length > 0) out.push(current.join(\"\\n\"));\n return out;\n}\n\nfunction parseThreadBlock(block: string): ParsedThread | null {\n const lines = block.split(\"\\n\");\n const header = lines[0]?.trim() ?? \"\";\n const headerMatch = headerRe.exec(header);\n if (!headerMatch?.groups) return null;\n\n const name = headerMatch.groups.name;\n if (!name) return null;\n const rest = headerMatch.groups.rest ?? \"\";\n const idMatch = /#(\\d+)\\b/.exec(rest);\n const prioMatch = /\\bprio=(\\d+)/.exec(rest);\n const nidMatch = /\\bnid=(0x[0-9a-f]+)/i.exec(rest);\n const daemon = /\\bdaemon\\b/.test(rest);\n const headerStateTrail = extractHeaderStateTrail(rest);\n\n let rawState = headerStateTrail ?? \"\";\n let state = normalizeJvmState(rawState);\n const frames: ParsedThreadFrame[] = [];\n\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i];\n if (line == null) continue;\n if (!line.trim()) continue;\n\n const stateMatch = stateRe.exec(line);\n if (stateMatch?.groups) {\n const primary = stateMatch.groups.state;\n if (!primary) continue;\n const sub = stateMatch.groups.sub;\n rawState = sub ? `${primary} (${sub})` : primary;\n state = normalizeJvmState(primary);\n continue;\n }\n\n const frameMatch = frameRe.exec(line);\n if (frameMatch?.groups) {\n const functionName = frameMatch.groups.fn;\n const src = frameMatch.groups.src;\n if (!functionName || !src) continue;\n const frame: ParsedThreadFrame = {\n functionName,\n displayName: sanitizeJvmFunctionName(functionName),\n kind: \"frame\",\n runtime: isJvmRuntimeFrame(functionName),\n nativeMethod: src === \"Native Method\",\n };\n const srcMatch = srcLineRe.exec(src);\n if (srcMatch?.groups?.file && srcMatch.groups.line) {\n frame.file = srcMatch.groups.file;\n frame.line = Number(srcMatch.groups.line);\n frame.location = `${frame.file}:${frame.line}`;\n } else if (src === \"Native Method\") {\n frame.location = \"Native Method\";\n } else {\n frame.location = src;\n }\n frames.push(frame);\n continue;\n }\n\n const annoMatch = annotationRe.exec(line);\n if (annoMatch?.groups?.kind) {\n const annotationKind = annoMatch.groups.kind;\n const kind = mapAnnotationKind(annotationKind);\n frames.push({\n functionName: annotationKind,\n displayName: annotationKind,\n kind,\n runtime: false,\n nativeMethod: false,\n annotationText: (annoMatch.groups.rest ?? \"\").trim(),\n });\n continue;\n }\n }\n\n const userFrameCount = frames.filter((f) => f.kind === \"frame\" && !f.runtime).length;\n const topFunction = frames.find((f) => f.kind === \"frame\")?.functionName;\n const searchText = [\n header,\n ...frames.map((f) => `${f.functionName} ${f.location ?? \"\"} ${f.annotationText ?? \"\"}`),\n ]\n .join(\"\\n\")\n .toLowerCase();\n\n return {\n id: idMatch ? Number(idMatch[1]) : deriveSyntheticId(name, rest),\n name,\n state: state || \"unknown\",\n rawState: rawState || \"\",\n daemon,\n frames,\n raw: block,\n userFrameCount,\n searchText,\n ...(nidMatch?.[1] !== undefined ? { nid: nidMatch[1] } : {}),\n ...(prioMatch?.[1] !== undefined ? { priority: Number(prioMatch[1]) } : {}),\n ...(topFunction !== undefined ? { topFunction } : {}),\n };\n}\n\nfunction extractHeaderStateTrail(rest: string): string | undefined {\n // Example header tails: \"... nid=0x1903 waiting on condition [0x...]\"\n // Capture the descriptor between nid=... and the trailing [address].\n const tail = rest.match(/nid=0x[0-9a-f]+\\s+(?<desc>[^[]+?)(?:\\s+\\[0x[0-9a-f]+\\])?\\s*$/i);\n return tail?.groups?.desc?.trim();\n}\n\nfunction deriveSyntheticId(name: string, rest: string): number {\n const tid = /\\btid=(0x[0-9a-f]+)/i.exec(rest);\n if (tid?.[1]) {\n // stable non-negative int derived from tid hex suffix\n const hex = tid[1].slice(2);\n const n = Number.parseInt(hex.slice(-8), 16);\n if (Number.isFinite(n)) return n;\n }\n // Fallback: hash of name\n let h = 0;\n for (let i = 0; i < name.length; i++) h = (h * 31 + name.charCodeAt(i)) | 0;\n return Math.abs(h);\n}\n\nfunction mapAnnotationKind(kind: string): ParsedThreadFrame[\"kind\"] {\n switch (kind) {\n case \"locked\":\n return \"locked\";\n case \"waiting on\":\n return \"waiting_on\";\n case \"waiting to lock\":\n return \"waiting_to_lock\";\n case \"parking to wait for\":\n return \"parking\";\n default:\n return \"frame\";\n }\n}\n\nexport function countThreadsByState(threads: ParsedThread[]): Map<string, number> {\n const counts = new Map<string, number>();\n for (const t of threads) counts.set(t.state, (counts.get(t.state) ?? 0) + 1);\n return counts;\n}\n\nfunction normalizeJvmState(value: string): string {\n if (!value) return \"\";\n const upper = value.trim().toUpperCase();\n if (upper.startsWith(\"RUNNABLE\")) return \"runnable\";\n if (upper.startsWith(\"TIMED_WAITING\")) return \"timed_waiting\";\n if (upper.startsWith(\"WAITING\")) return \"waiting\";\n if (upper.startsWith(\"BLOCKED\")) return \"blocked\";\n if (upper.startsWith(\"NEW\")) return \"new\";\n if (upper.startsWith(\"TERMINATED\")) return \"terminated\";\n // Header fragments like \"waiting on condition\", \"runnable\", \"sleeping\"\n const lower = value.trim().toLowerCase();\n if (lower.includes(\"runnable\")) return \"runnable\";\n if (lower.includes(\"waiting on condition\") || lower.includes(\"sleeping\")) return \"timed_waiting\";\n if (lower.includes(\"waiting\")) return \"waiting\";\n if (lower.includes(\"blocked\")) return \"blocked\";\n return lower.split(/\\s+/)[0] ?? \"\";\n}\n\nconst runtimePrefixes = [\"java.\", \"javax.\", \"sun.\", \"jdk.\", \"com.sun.\", \"or\" + \"acle.jrockit.\"];\nfunction isJvmRuntimeFrame(functionName: string): boolean {\n return runtimePrefixes.some((p) => functionName.startsWith(p));\n}\n\nfunction sanitizeJvmFunctionName(functionName: string): string {\n // e.g. \"com.example.App$Inner.method\" → \"App$Inner.method\"\n const parts = functionName.split(\".\");\n if (parts.length < 2) return functionName;\n const method = parts[parts.length - 1];\n const cls = parts[parts.length - 2];\n return `${cls}.${method}`;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ParsedThreadFrame } from './jvm-stacktrace';
|
|
2
|
+
export type ParsedStackFrame = ParsedThreadFrame;
|
|
3
|
+
export interface ParsedStackTrace {
|
|
4
|
+
exceptionClass?: string;
|
|
5
|
+
message?: string;
|
|
6
|
+
causedBy: string[];
|
|
7
|
+
frames: ParsedStackFrame[];
|
|
8
|
+
language: "java";
|
|
9
|
+
}
|
|
10
|
+
export declare function parseJavaStackTrace(input: string): ParsedStackTrace;
|
|
11
|
+
//# sourceMappingURL=stacktrace-parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stacktrace-parse.d.ts","sourceRoot":"","sources":["../../../src/data/diagnostics/stacktrace-parse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAI1D,MAAM,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAYD,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CA8CnE"}
|