@forge-kit/plugin-source-map-prase 0.0.1 → 0.0.3

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.
Files changed (37) hide show
  1. package/dist/app.js +3 -5
  2. package/dist/node.js +2556 -0
  3. package/package.json +5 -3
  4. package/src/App.less +43 -74
  5. package/src/App.tsx +98 -54
  6. package/src/components/map-input-panel/index.less +71 -79
  7. package/src/components/map-input-panel/index.tsx +65 -69
  8. package/src/components/panel-card/index.less +21 -0
  9. package/src/components/panel-card/index.tsx +6 -8
  10. package/src/components/trace-chain/index.less +126 -125
  11. package/src/components/trace-chain/index.tsx +25 -24
  12. package/src/main.tsx +1 -1
  13. package/src/node/index.ts +6 -0
  14. package/src/{utils/source-map → node/trace/core}/base/registry.ts +14 -11
  15. package/src/{utils/source-map → node/trace/core}/base/types.ts +1 -0
  16. package/src/node/trace/core/domain/chain-slots.ts +33 -0
  17. package/src/{utils/source-map → node/trace/core}/domain/source-content.ts +15 -2
  18. package/src/node/trace/core/domain/trace-resolver.ts +179 -0
  19. package/src/node/trace/core/domain/view-model.ts +57 -0
  20. package/src/node/trace/resolve/context.ts +59 -0
  21. package/src/node/trace/resolve/index.ts +97 -0
  22. package/src/node/trace/resolve/input.ts +35 -0
  23. package/src/node/trace/resolve/snippet-limit.ts +35 -0
  24. package/src/node/trace/resolve/types.ts +37 -0
  25. package/src/node/trace/runner.ts +149 -0
  26. package/src/shared/trace-common.ts +104 -0
  27. package/src/shared/trace-contract.ts +29 -0
  28. package/src/types.ts +19 -0
  29. package/src/utils/trace-ui/index.ts +12 -0
  30. package/src/utils/trace-ui/state.ts +81 -0
  31. package/src/utils/source-map/domain/chain-slots.ts +0 -59
  32. package/src/utils/source-map/domain/trace-resolver.ts +0 -165
  33. package/src/utils/source-map/domain/view-model.ts +0 -20
  34. package/src/utils/source-map/facade/source-map-utils.ts +0 -212
  35. package/src/utils/source-map/index.ts +0 -18
  36. /package/src/{utils/source-map → node/trace/core}/base/constants.ts +0 -0
  37. /package/src/{utils/source-map → node/trace/core}/base/path.ts +0 -0
@@ -1,22 +1,19 @@
1
1
  import * as React from "react";
2
2
  import {Box, Button, Flex, Text, TextField} from "@forge-kit/component";
3
3
  import {PanelCard} from "@/components/panel-card";
4
+ import type {ForgeKitBridge, MapInputConfig} from "@/types";
4
5
  import {noop} from "@/utils";
6
+ import classNames from "classnames";
5
7
  import "./index.less";
6
8
 
7
- interface MapInputConfig {
8
- entryLine: string
9
- entryColumn: string
10
- contextLineRadius: string
11
- }
12
-
13
9
  interface MapInputPanelProps {
10
+ className?: string
14
11
  chainDepth: number
15
12
  entryFileName: string
16
13
  inputConfig: MapInputConfig
17
14
  onInputConfigChange: (next: MapInputConfig) => void
18
15
  onResolve: () => void
19
- onAppendMapFile: (file: File) => void
16
+ onAppendMapFilePath: (filePath: string) => void
20
17
  }
21
18
 
22
19
  interface MapInputFieldProps {
@@ -45,25 +42,27 @@ const MapInputField: React.FC<MapInputFieldProps> = (props) => {
45
42
 
46
43
  export const MapInputPanel: React.FC<MapInputPanelProps> = (props) => {
47
44
  const {
45
+ className,
48
46
  chainDepth,
49
47
  entryFileName,
50
48
  inputConfig,
51
49
  onInputConfigChange,
52
50
  onResolve,
53
- onAppendMapFile,
51
+ onAppendMapFilePath,
54
52
  } = props
55
53
 
56
- const openFilePicker = () => {
57
- const fileInput = document.createElement("input")
58
- fileInput.type = "file"
59
- fileInput.accept = ".map,application/json"
60
- fileInput.onchange = () => {
61
- const file = fileInput.files?.[0]
62
- if (file) {
63
- onAppendMapFile(file)
64
- }
65
- }
66
- fileInput.click()
54
+ const openFilePicker = async () => {
55
+ const openFileDialog = (window as Window & {forgeKit?: ForgeKitBridge}).forgeKit?.openFileDialog
56
+ if (!openFileDialog) return
57
+
58
+ const selected = await openFileDialog({
59
+ multiple: true,
60
+ filters: [{name: "Source Map", extensions: ["map", "json"]}],
61
+ })
62
+ const paths = Array.isArray(selected) ? selected : (selected ? [selected] : [])
63
+ paths.forEach((filePath) => {
64
+ if (typeof filePath === "string") onAppendMapFilePath(filePath)
65
+ })
67
66
  }
68
67
 
69
68
  const handleInputConfigChange = (field: keyof MapInputConfig, value: string) => {
@@ -71,58 +70,55 @@ export const MapInputPanel: React.FC<MapInputPanelProps> = (props) => {
71
70
  }
72
71
 
73
72
  return (
74
- <PanelCard
75
- title="MAP INPUT"
76
- cardClassName="input-panel-card"
77
- contentClassName="input-panel-content"
78
- contentProps={{direction: "column", gap: "3"}}
79
- >
80
- <Box className="input-summary-grid">
81
- <Box className="input-summary-item">
82
- <Text className="input-summary-label">入口 Map</Text>
83
- <Text className="input-summary-value">{entryFileName || "-"}</Text>
84
- </Box>
85
- <Box className="input-summary-item">
86
- <Text className="input-summary-label">链路层数</Text>
87
- <Text className="input-summary-value">{`${chainDepth} 层`}</Text>
88
- </Box>
89
- </Box>
73
+ <PanelCard title="MAP INPUT" className={classNames("input-panel-card", className)}>
74
+ <Flex className="input-panel-content" direction='column' gap="3">
75
+ <Box className="input-summary-grid">
76
+ <Box className="input-summary-item">
77
+ <Text className="input-summary-label">入口 Map</Text>
78
+ <Text className="input-summary-value">{entryFileName || "-"}</Text>
79
+ </Box>
80
+ <Box className="input-summary-item">
81
+ <Text className="input-summary-label">链路层数</Text>
82
+ <Text className="input-summary-value">{`${chainDepth} 层`}</Text>
83
+ </Box>
84
+ </Box>
90
85
 
91
- <Box className="input-hints">
92
- <Text className="input-hints-title">使用说明</Text>
93
- <Text className="input-hints-item">1. 按解析链路顺序添加 map 文件。</Text>
94
- <Text className="input-hints-item">2. 入口 Map 会自动取第一层的 output file。</Text>
95
- <Text className="input-hints-item">3. TRACE CHAIN 支持拖动序号来切换 map 顺序。</Text>
96
- </Box>
86
+ <Box className="input-hints">
87
+ <Text className="input-hints-title">使用说明</Text>
88
+ <Text className="input-hints-item">1. 按解析链路顺序添加 map 文件。</Text>
89
+ <Text className="input-hints-item">2. 入口 Map 会自动取第一层的 output file。</Text>
90
+ <Text className="input-hints-item">3. TRACE CHAIN 支持拖动序号来切换 map 顺序。</Text>
91
+ </Box>
97
92
 
98
- <Box className="input-footer">
99
- <Flex gap="2" className="entry-row" align="end" wrap="wrap">
100
- <MapInputField
101
- title="入口行号"
102
- min={1}
103
- value={inputConfig.entryLine}
104
- onChange={(value) => handleInputConfigChange("entryLine", value)}
105
- />
106
- <MapInputField
107
- title="入口列号"
108
- min={0}
109
- value={inputConfig.entryColumn}
110
- onChange={(value) => handleInputConfigChange("entryColumn", value)}
111
- />
112
- <MapInputField
113
- title="上下文行数"
114
- min={0}
115
- value={inputConfig.contextLineRadius}
116
- onChange={(value) => handleInputConfigChange("contextLineRadius", value)}
117
- />
118
- </Flex>
119
- <Flex className="entry-actions" direction="column" justify="center" align="center" gap="2">
120
- <Flex className="entry-action-row" gap="2" wrap="wrap" justify="center" align="center">
121
- <Button size="2" radius="large" onClick={onResolve}>解析链路</Button>
122
- <Button size="2" radius="large" variant="outline" onClick={openFilePicker}>添加 map 文件</Button>
123
- </Flex>
124
- </Flex>
125
- </Box>
93
+ <Box className="input-footer">
94
+ <Flex gap="2" className="entry-row" align="end" wrap="wrap">
95
+ <MapInputField
96
+ title="入口行号"
97
+ min={1}
98
+ value={inputConfig.entryLine}
99
+ onChange={(value) => handleInputConfigChange("entryLine", value)}
100
+ />
101
+ <MapInputField
102
+ title="入口列号"
103
+ min={0}
104
+ value={inputConfig.entryColumn}
105
+ onChange={(value) => handleInputConfigChange("entryColumn", value)}
106
+ />
107
+ <MapInputField
108
+ title="上下文行数"
109
+ min={0}
110
+ value={inputConfig.contextLineRadius}
111
+ onChange={(value) => handleInputConfigChange("contextLineRadius", value)}
112
+ />
113
+ </Flex>
114
+ <Flex className="entry-actions" direction="column" justify="center" align="center" gap="2">
115
+ <Flex className="entry-action-row" gap="2" wrap="wrap" justify="center" align="center">
116
+ <Button size="2" radius="large" onClick={onResolve}>解析链路</Button>
117
+ <Button size="2" radius="large" variant="outline" onClick={openFilePicker}>添加 map 文件</Button>
118
+ </Flex>
119
+ </Flex>
120
+ </Box>
121
+ </Flex>
126
122
  </PanelCard>
127
123
  )
128
124
  }
@@ -0,0 +1,21 @@
1
+ .panel-card {
2
+ display: flex !important;
3
+
4
+ .panel-shell {
5
+ overflow: hidden;
6
+ flex: 1;
7
+
8
+ .panel-title {
9
+ display: block;
10
+ padding: 0 0 var(--space-3);
11
+ margin-bottom: var(--space-3);
12
+ border-bottom: solid 1px var(--gray-5);
13
+ font-size: 12px;
14
+ letter-spacing: 0.1em;
15
+ color: var(--gray-11);
16
+ text-transform: uppercase;
17
+ }
18
+ }
19
+
20
+ }
21
+
@@ -1,24 +1,22 @@
1
1
  import * as React from "react";
2
2
  import {Card, Flex, Text} from "@forge-kit/component";
3
+ import classNames from 'classnames'
4
+ import './index.less'
3
5
 
4
6
  interface PanelCardProps {
5
7
  title: string
6
- cardClassName: string
7
- contentClassName: string
8
- contentProps?: Omit<React.ComponentProps<typeof Flex>, "className" | "children">
8
+ className?: string
9
9
  children?: React.ReactNode
10
10
  }
11
11
 
12
12
  export const PanelCard: React.FC<PanelCardProps> = (props) => {
13
- const {title, cardClassName, contentClassName, contentProps, children} = props
13
+ const {title, className, children} = props
14
14
 
15
15
  return (
16
- <Card className={cardClassName}>
16
+ <Card className={classNames('panel-card', className)} >
17
17
  <Flex className="panel-shell" direction="column">
18
18
  <Text className="panel-title">{title}</Text>
19
- <Flex className={contentClassName} {...contentProps}>
20
- {children}
21
- </Flex>
19
+ <>{children}</>
22
20
  </Flex>
23
21
  </Card>
24
22
  )
@@ -1,128 +1,129 @@
1
- .trace-chain-root {
2
- flex: 1;
3
- min-height: 0;
4
- height: 100%;
5
- overflow: auto;
6
- padding: 4px;
7
- -webkit-app-region: no-drag;
8
-
9
- .trace-chain-item {
10
- margin-bottom: 10px;
11
-
12
- &[data-dragging="true"] {
13
- opacity: 0.85;
1
+ .trace-panel-card {
2
+ .trace-panel-content {
3
+ flex: 1;
4
+ overflow: auto;
5
+
6
+ .trace-chain-root {
7
+ flex: 1;
8
+ min-height: 0;
9
+ height: 100%;
10
+ overflow: auto;
11
+ padding: 4px;
12
+
13
+ .trace-chain-empty {
14
+ min-height: 180px;
15
+ border: 1px dashed var(--gray-6);
16
+ border-radius: var(--radius-3);
17
+ color: var(--gray-11);
18
+ font-size: 13px;
19
+ }
20
+
21
+ .trace-chain-item {
22
+ margin-bottom: 10px;
23
+
24
+ &[data-dragging="true"] {
25
+ opacity: 0.85;
26
+ }
27
+
28
+ .trace-chain-node {
29
+ padding: 10px;
30
+ border-radius: var(--radius-3);
31
+ border: 1px solid var(--gray-6);
32
+ background: linear-gradient(160deg, color-mix(in srgb, var(--gray-3) 90%, transparent), color-mix(in srgb, var(--gray-2) 90%, transparent));
33
+
34
+ .trace-chain-drag-handle {
35
+ min-width: 46px;
36
+ height: 24px;
37
+ border-radius: 999px;
38
+ border: 1px solid var(--gray-7);
39
+ background: var(--gray-4);
40
+ color: var(--gray-12);
41
+ font-size: 12px;
42
+ font-weight: 600;
43
+ user-select: none;
44
+ cursor: grab;
45
+
46
+ &:active {
47
+ cursor: grabbing;
48
+ }
49
+ }
50
+
51
+ .trace-chain-content {
52
+ overflow: hidden;
53
+ width: 100%;
54
+
55
+ .trace-chain-header {
56
+ width: 100%;
57
+
58
+ .trace-chain-main-title {
59
+ display: block;
60
+ font-size: 13px;
61
+ font-weight: 700;
62
+ color: var(--gray-12);
63
+ line-height: 1.35;
64
+ word-break: break-all;
65
+ user-select: text;
66
+ cursor: text;
67
+ }
68
+ }
69
+
70
+ .trace-chain-row {
71
+ display: grid;
72
+ grid-template-columns: 34px minmax(0, 1fr);
73
+ gap: 6px;
74
+ padding: 2px 0;
75
+
76
+ &[data-row-type="output"] {
77
+ margin-top: 2px;
78
+ padding-top: 8px;
79
+ border-top: 1px dashed color-mix(in srgb, var(--gray-6) 78%, transparent);
80
+ }
81
+
82
+ .trace-chain-label {
83
+ min-width: 30px;
84
+ font-size: 12px;
85
+ color: var(--gray-10);
86
+ user-select: none;
87
+ margin-top: 1px;
88
+ }
89
+
90
+ .trace-chain-detail {
91
+ min-width: 0;
92
+
93
+ .trace-chain-file {
94
+ font-size: 13px;
95
+ font-weight: 600;
96
+ color: var(--gray-12);
97
+ white-space: normal;
98
+ overflow-wrap: anywhere;
99
+ word-break: break-all;
100
+ user-select: text;
101
+ cursor: text;
102
+ }
103
+
104
+ .trace-chain-position {
105
+ font-size: 12px;
106
+ color: var(--gray-11);
107
+ white-space: normal;
108
+ overflow-wrap: anywhere;
109
+ user-select: text;
110
+ cursor: text;
111
+ }
112
+ }
113
+ }
114
+
115
+ .trace-chain-error {
116
+ font-size: 12px;
117
+ color: #ff7b7b;
118
+ }
119
+
120
+ .trace-chain-pending {
121
+ font-size: 12px;
122
+ color: var(--gray-10);
123
+ }
124
+ }
125
+ }
126
+ }
14
127
  }
15
128
  }
16
-
17
- .trace-chain-empty {
18
- min-height: 180px;
19
- border: 1px dashed var(--gray-6);
20
- border-radius: var(--radius-3);
21
- color: var(--gray-11);
22
- font-size: 13px;
23
- }
24
-
25
- .trace-chain-node {
26
- padding: 10px;
27
- border-radius: var(--radius-3);
28
- border: 1px solid var(--gray-6);
29
- background:
30
- linear-gradient(160deg, color-mix(in srgb, var(--gray-3) 90%, transparent), color-mix(in srgb, var(--gray-2) 90%, transparent));
31
- }
32
-
33
- .trace-chain-drag-handle {
34
- min-width: 46px;
35
- height: 24px;
36
- border-radius: 999px;
37
- border: 1px solid var(--gray-7);
38
- background: var(--gray-4);
39
- color: var(--gray-12);
40
- font-size: 12px;
41
- font-weight: 600;
42
- user-select: none;
43
- cursor: grab;
44
-
45
- &:active {
46
- cursor: grabbing;
47
- }
48
- }
49
-
50
- .trace-chain-content {
51
- overflow: hidden;
52
- width: 100%;
53
- }
54
-
55
- .trace-chain-main-title {
56
- display: block;
57
- font-size: 13px;
58
- font-weight: 700;
59
- color: var(--gray-12);
60
- line-height: 1.35;
61
- word-break: break-all;
62
- user-select: text;
63
- cursor: text;
64
- }
65
-
66
- .trace-chain-header {
67
- width: 100%;
68
- }
69
-
70
- .trace-chain-row {
71
- display: grid;
72
- grid-template-columns: 34px minmax(0, 1fr);
73
- gap: 6px;
74
- padding: 2px 0;
75
- }
76
-
77
- .trace-chain-row[data-row-type="output"] {
78
- margin-top: 2px;
79
- padding-top: 8px;
80
- border-top: 1px dashed color-mix(in srgb, var(--gray-6) 78%, transparent);
81
- }
82
-
83
- .trace-chain-label {
84
- min-width: 30px;
85
- font-size: 12px;
86
- color: var(--gray-10);
87
- user-select: none;
88
- margin-top: 1px;
89
- }
90
-
91
- .trace-chain-detail {
92
- min-width: 0;
93
- }
94
-
95
- .trace-chain-output-head {
96
- }
97
-
98
- .trace-chain-file {
99
- font-size: 13px;
100
- font-weight: 600;
101
- color: var(--gray-12);
102
- white-space: normal;
103
- overflow-wrap: anywhere;
104
- word-break: break-all;
105
- user-select: text;
106
- cursor: text;
107
- }
108
-
109
- .trace-chain-position {
110
- font-size: 12px;
111
- color: var(--gray-11);
112
- white-space: normal;
113
- overflow-wrap: anywhere;
114
- user-select: text;
115
- cursor: text;
116
- }
117
-
118
- .trace-chain-error {
119
- font-size: 12px;
120
- color: #ff7b7b;
121
- }
122
-
123
- .trace-chain-pending {
124
- font-size: 12px;
125
- color: var(--gray-10);
126
- }
127
-
128
129
  }
@@ -3,7 +3,9 @@ import {Box, Button, Flex, Text} from "@forge-kit/component";
3
3
  import {DndContext, PointerSensor, closestCenter, useSensor, useSensors, type DragEndEvent} from "@dnd-kit/core";
4
4
  import {SortableContext, arrayMove, useSortable, verticalListSortingStrategy} from "@dnd-kit/sortable";
5
5
  import {CSS} from "@dnd-kit/utilities";
6
+ import {PanelCard} from "@/components/panel-card";
6
7
  import "./index.less";
8
+ import classNames from "classnames";
7
9
 
8
10
  interface TraceChainNode {
9
11
  fileName: string
@@ -73,7 +75,8 @@ const SortableTraceChainItem: React.FC<SortableTraceChainItemProps> = (props) =>
73
75
  return (
74
76
  <Box ref={setNodeRef} style={style} className="trace-chain-item" data-dragging={isDragging ? "true" : "false"}>
75
77
  <Flex className="trace-chain-node" gap="2">
76
- <Flex className="trace-chain-drag-handle" align="center" justify="center" {...attributes} {...listeners}>#{index + 1}</Flex>
78
+ <Flex className="trace-chain-drag-handle" align="center"
79
+ justify="center" {...attributes} {...listeners}>#{index + 1}</Flex>
77
80
  <Flex className="trace-chain-content" direction="column" gap="2">
78
81
  <Flex className="trace-chain-header" justify="between" align="start" gap="2">
79
82
  <Text className="trace-chain-main-title">{slot.mapFileName || "(未命名 map 文件)"}</Text>
@@ -113,14 +116,6 @@ export const TraceChain: React.FC<TraceChainProps> = (props) => {
113
116
  const {slots = [], data = [], onReorder, onDelete, className} = props
114
117
  const sensors = useSensors(useSensor(PointerSensor, {activationConstraint: {distance: 6}}))
115
118
 
116
- if (slots.length === 0) {
117
- return (
118
- <Box className={className || "trace-chain-root"}>
119
- <Flex className="trace-chain-empty" align="center" justify="center">暂无解析链路,上传 map 并点击“解析链路”。</Flex>
120
- </Box>
121
- )
122
- }
123
-
124
119
  const handleDragEnd = (event: DragEndEvent) => {
125
120
  const {active, over} = event
126
121
  if (!over || active.id === over.id) return
@@ -132,20 +127,26 @@ export const TraceChain: React.FC<TraceChainProps> = (props) => {
132
127
  }
133
128
 
134
129
  return (
135
- <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
136
- <SortableContext items={slots.map((item) => item.id)} strategy={verticalListSortingStrategy}>
137
- <Box className={className || "trace-chain-root"}>
138
- {slots.map((slot, index) => (
139
- <SortableTraceChainItem
140
- key={slot.id}
141
- slot={slot}
142
- hop={data[index]}
143
- index={index}
144
- onDelete={onDelete}
145
- />
146
- ))}
147
- </Box>
148
- </SortableContext>
149
- </DndContext>
130
+ <PanelCard title="TRACE CHAIN" className={classNames('trace-panel-card', className)}>
131
+ <Flex className="trace-panel-content">
132
+ {Boolean(!slots.length) && (
133
+ <Box className="trace-chain-root">
134
+ <Flex className="trace-chain-empty" align="center" justify="center">暂无解析链路,上传 map 并点击“解析链路”。</Flex>
135
+ </Box>
136
+ )}
137
+ {Boolean(slots.length) && (
138
+ <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
139
+ <SortableContext items={slots.map((item) => item.id)} strategy={verticalListSortingStrategy}>
140
+ <Box className="trace-chain-root">
141
+ {slots.map((slot, index) => {
142
+ return <SortableTraceChainItem key={slot.id} slot={slot} hop={data[index]}
143
+ index={index} onDelete={onDelete}/>
144
+ })}
145
+ </Box>
146
+ </SortableContext>
147
+ </DndContext>
148
+ )}
149
+ </Flex>
150
+ </PanelCard>
150
151
  )
151
152
  }
package/src/main.tsx CHANGED
@@ -1,6 +1,6 @@
1
1
  import {StrictMode} from 'react'
2
2
  import ReactDOM from "react-dom/client";
3
- import {definePlugin} from '@forge-kit/types'
3
+ import {definePlugin} from '@forge-kit/helper'
4
4
  import {App} from '@/App.tsx'
5
5
 
6
6
  let rootInstance: ReturnType<typeof ReactDOM.createRoot> | null = null;
@@ -0,0 +1,6 @@
1
+ import {defineInvokeMethod, registerInvokeMethod} from "@forge-kit/node-sdk";
2
+ import {getSourceSnippet, profileResolveTracePhases, resolveTrace} from "./trace/resolve";
3
+
4
+ const invokeMethod = defineInvokeMethod({resolveTrace, getSourceSnippet, profileResolveTracePhases})
5
+
6
+ registerInvokeMethod(invokeMethod)
@@ -1,19 +1,23 @@
1
1
  import type {SourceMapRecord, SourceMapRegistry} from "./types";
2
2
  import {getBaseName, normalizePath} from "./path";
3
3
 
4
- export const registerSourceMap = (registry: SourceMapRegistry, key: string, sourceMapRecord: SourceMapRecord) => {
4
+ interface RegisterSourceMapInput {
5
+ registry: SourceMapRegistry
6
+ key: string
7
+ sourceMapRecord: SourceMapRecord
8
+ }
9
+
10
+ export const registerSourceMap = (input: RegisterSourceMapInput) => {
11
+ const {registry, key, sourceMapRecord} = input
5
12
  const normalized = normalizePath(key)
13
+
6
14
  if (!normalized) return registry
7
15
 
8
- const nextRegistry: SourceMapRegistry = {
9
- ...registry,
10
- [normalized]: sourceMapRecord,
11
- }
16
+ const nextRegistry: SourceMapRegistry = {...registry, [normalized]: sourceMapRecord}
12
17
 
13
18
  const baseName = getBaseName(normalized)
14
- if (!nextRegistry[baseName]) {
15
- nextRegistry[baseName] = sourceMapRecord
16
- }
19
+
20
+ if (!nextRegistry[baseName]) nextRegistry[baseName] = sourceMapRecord
17
21
 
18
22
  return nextRegistry
19
23
  }
@@ -21,9 +25,8 @@ export const registerSourceMap = (registry: SourceMapRegistry, key: string, sour
21
25
  export const listSourceMapRecords = (sourceMaps: SourceMapRegistry): SourceMapRecord[] => {
22
26
  const map = new Map<string, SourceMapRecord>()
23
27
  Object.values(sourceMaps).forEach((record) => {
24
- if (!map.has(record.mapFileName)) {
25
- map.set(record.mapFileName, record)
26
- }
28
+ if (map.has(record.mapFileName)) return
29
+ map.set(record.mapFileName, record)
27
30
  })
28
31
  return Array.from(map.values())
29
32
  }
@@ -30,6 +30,7 @@ export interface ResolvedSourceMeta {
30
30
  export interface ChainMapSlot {
31
31
  id: string
32
32
  mapFileName: string
33
+ mapFilePath?: string
33
34
  sourceMapRecord?: SourceMapRecord
34
35
  error?: string
35
36
  }
@@ -0,0 +1,33 @@
1
+ import {normalizePath, stripMapExt} from "../base/path";
2
+ import {registerSourceMap} from "../base/registry";
3
+ import type {ChainMapSlot, SourceMapRegistry} from "../base/types";
4
+
5
+ export const buildRegistryFromChainSlots = (slots: ChainMapSlot[]) => {
6
+ let registry: SourceMapRegistry = {}
7
+ const orderedMapFileNames: string[] = []
8
+
9
+ slots.forEach((slot) => {
10
+ const {sourceMapRecord: record} = slot
11
+ if (!record) return
12
+
13
+ orderedMapFileNames.push(record.mapFileName)
14
+ registry = registerSourceMap({registry, key: record.mapFileName, sourceMapRecord: record})
15
+ registry = registerSourceMap({registry, key: stripMapExt(record.mapFileName), sourceMapRecord: record})
16
+
17
+ if (record.rawSourceMap.file) {
18
+ registry = registerSourceMap({registry, key: record.rawSourceMap.file, sourceMapRecord: record})
19
+ }
20
+ })
21
+
22
+ return {registry, orderedMapFileNames}
23
+ }
24
+
25
+ export const getAutoEntryFileNameFromSlots = (slots: ChainMapSlot[]) => {
26
+ const firstValidSlot = slots.find((slot) => slot.sourceMapRecord)
27
+ if (!firstValidSlot?.sourceMapRecord) return ""
28
+
29
+ const mappedFile = firstValidSlot.sourceMapRecord.rawSourceMap.file
30
+ if (mappedFile) return normalizePath(mappedFile)
31
+
32
+ return stripMapExt(firstValidSlot.sourceMapRecord.mapFileName)
33
+ }