@lukekaalim/act-insight 0.0.2-alpha.6 → 1.1.0
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/CHANGELOG.md +38 -0
- package/InsightApp.ts +364 -169
- package/ScheduleControls.ts +61 -0
- package/TreeViewer.module.css +10 -1
- package/TreeViewer.ts +34 -21
- package/Virtual.ts +64 -0
- package/index.ts +4 -1
- package/lookup.ts +185 -0
- package/package.json +4 -4
- package/utils.ts +59 -47
- package/vite.config.ts +4 -4
- package/CommitViewer.module.css +0 -5
- package/CommitViewer.ts +0 -104
- package/ThreadControls.ts +0 -22
- package/ThreadViewer.module.css +0 -5
- package/ThreadViewer.ts +0 -185
- package/debug.ts +0 -80
- package/devtool_page.ts +0 -0
- package/devtool_panel.ts +0 -0
- package/extension_main.ts +0 -0
- package/insight.test.ts +0 -29
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Component, h, useEffect, useState } from '@lukekaalim/act';
|
|
2
|
+
import { ReconcilerDebugController, ReconcilerDebugEventBus, ScheduleController, ScheduleEventBus } from '@lukekaalim/act-debug';
|
|
3
|
+
import { InsightAppState } from './InsightApp';
|
|
4
|
+
|
|
5
|
+
export type ScheduleControlsProps = {
|
|
6
|
+
controller: ScheduleController,
|
|
7
|
+
bus: ScheduleEventBus,
|
|
8
|
+
|
|
9
|
+
reconciler: ReconcilerDebugController,
|
|
10
|
+
|
|
11
|
+
state: InsightAppState,
|
|
12
|
+
onStateChange?: (newState: InsightAppState) => void,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const ScheduleControls: Component<ScheduleControlsProps> = ({ controller, bus, reconciler, state, onStateChange = () => {} }) => {
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
bus.onInterceptStart = () => {
|
|
18
|
+
onStateChange({ ...state, paused: true });
|
|
19
|
+
//onPauseChange(false)
|
|
20
|
+
}
|
|
21
|
+
bus.onInterceptEnd = () => {
|
|
22
|
+
onStateChange({ ...state, paused: false });
|
|
23
|
+
//onPauseChange(false)
|
|
24
|
+
}
|
|
25
|
+
bus.onAfterCallbackExecute = () => {
|
|
26
|
+
//reconciler.getThread();
|
|
27
|
+
}
|
|
28
|
+
}, [bus, reconciler, state])
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
const onStepClick = () => {
|
|
32
|
+
controller.step();
|
|
33
|
+
}
|
|
34
|
+
const onResumeClick = () => {
|
|
35
|
+
controller.cancelIntercept();
|
|
36
|
+
}
|
|
37
|
+
const onChangeBreakBeforeUpdate = (event: Event) => {
|
|
38
|
+
onStateChange({ ...state, breakOnBeforeUpdate: (event.target as HTMLInputElement).checked });
|
|
39
|
+
}
|
|
40
|
+
const onChangeBreakAfterUpdate = (event: Event) => {
|
|
41
|
+
onStateChange({ ...state, breakOnAfterUpdate: (event.target as HTMLInputElement).checked });
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return h('div', { style: { background: state.paused ? 'red' : 'white', padding: '8px', display: 'flex', gap: '12px' }}, [
|
|
45
|
+
h('div', { style: { display: 'flex', 'flex-direction': 'column' } }, [
|
|
46
|
+
h('label', { style: { 'margin': 'auto 0' } }, [
|
|
47
|
+
h('span', {}, `Break Before Update`),
|
|
48
|
+
h('input', { type: 'checkbox', checked: state.breakOnBeforeUpdate, onChange: onChangeBreakBeforeUpdate }),
|
|
49
|
+
]),
|
|
50
|
+
h('label', { style: { 'margin': 'auto 0' } }, [
|
|
51
|
+
h('span', {}, `Break After Update`),
|
|
52
|
+
h('input', { type: 'checkbox', checked: state.breakOnAfterUpdate, onChange: onChangeBreakAfterUpdate }),
|
|
53
|
+
]),
|
|
54
|
+
]),
|
|
55
|
+
h('button', { onClick: onStepClick, disabled: !state.paused, style: { padding: '8px' } }, 'Step'),
|
|
56
|
+
h('button', { onClick: onResumeClick, disabled: !state.paused, style: { padding: '8px' } }, 'Resume'),
|
|
57
|
+
h('span', {
|
|
58
|
+
style: { border: `2px solid ${state.paused ? 'orange' : 'black'}`, 'border-radius': '8px', padding: '8px' }
|
|
59
|
+
}, state.paused ? `Paused` : `Ready`),
|
|
60
|
+
])
|
|
61
|
+
};
|
package/TreeViewer.module.css
CHANGED
|
@@ -10,10 +10,18 @@
|
|
|
10
10
|
font-family: monospace;
|
|
11
11
|
display: inline;
|
|
12
12
|
|
|
13
|
-
padding:
|
|
13
|
+
padding: 4px;
|
|
14
14
|
border-radius: 8px;
|
|
15
15
|
|
|
16
16
|
margin: 2px;
|
|
17
|
+
|
|
18
|
+
border: 2px solid rgba(255, 255, 255, 0);
|
|
19
|
+
white-space: nowrap;
|
|
20
|
+
}
|
|
21
|
+
.elementName:hover {
|
|
22
|
+
font-weight: bold;
|
|
23
|
+
cursor: pointer;
|
|
24
|
+
border: 2px solid white;
|
|
17
25
|
}
|
|
18
26
|
|
|
19
27
|
.commit {
|
|
@@ -31,6 +39,7 @@
|
|
|
31
39
|
}
|
|
32
40
|
|
|
33
41
|
.commitList {
|
|
42
|
+
flex: 1;
|
|
34
43
|
display: flex;
|
|
35
44
|
flex-direction: column;
|
|
36
45
|
list-style: none;
|
package/TreeViewer.ts
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
import { Component, h, Node } from "@lukekaalim/act";
|
|
2
|
-
import { Commit, CommitID, CommitTree } from "@lukekaalim/act-recon";
|
|
3
2
|
import { hs } from "@lukekaalim/act-web";
|
|
4
|
-
import { getElementName } from "./utils";
|
|
5
3
|
import stringHash from '@sindresorhus/string-hash';
|
|
6
4
|
|
|
7
5
|
import classes from './TreeViewer.module.css';
|
|
8
|
-
import { CommitAttributeTag } from "./AttributeTag";
|
|
6
|
+
//import { CommitAttributeTag } from "./AttributeTag";
|
|
9
7
|
import { CommitReport, TreeReport } from "@lukekaalim/act-debug";
|
|
8
|
+
import { CommitID } from "@lukekaalim/act-recon";
|
|
9
|
+
import { CommitAttributeTag } from './AttributeTag';
|
|
10
10
|
|
|
11
11
|
export type TreeViewerProps = {
|
|
12
|
-
|
|
12
|
+
//commits: Map<CommitID, CommitReport>,
|
|
13
|
+
roots: CommitID[],
|
|
13
14
|
|
|
14
|
-
renderCommit: (
|
|
15
|
+
renderCommit: (commitId: CommitID) => Node,
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export const TreeViewer: Component<TreeViewerProps> = ({
|
|
18
|
-
|
|
19
|
+
//commits,
|
|
20
|
+
roots,
|
|
21
|
+
renderCommit
|
|
19
22
|
}) => {
|
|
20
|
-
const rootCommits =
|
|
21
|
-
.map(root => tree.commits.get(root.id))
|
|
22
|
-
.filter(Boolean) as CommitReport[];
|
|
23
|
+
//const rootCommits = roots.map(root => commits.get(root)).filter(x => !!x)
|
|
23
24
|
|
|
24
25
|
const className = [classes.commitList, classes.top].join(' ')
|
|
25
26
|
|
|
26
|
-
return h('ol', { className },
|
|
27
|
-
h('li', {}, renderCommit(root))));
|
|
27
|
+
return h('ol', { className }, roots.map(root =>
|
|
28
|
+
h('li', { key: root }, renderCommit(root))));
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
export type CommitPreviewProps = {
|
|
31
32
|
commit: CommitReport,
|
|
32
|
-
tree: TreeReport,
|
|
33
33
|
|
|
34
34
|
attributes?: [string, string][],
|
|
35
35
|
|
|
@@ -37,33 +37,46 @@ export type CommitPreviewProps = {
|
|
|
37
37
|
|
|
38
38
|
depth?: number,
|
|
39
39
|
|
|
40
|
-
renderCommit
|
|
40
|
+
renderCommit?: (commit: CommitID) => Node,
|
|
41
41
|
onClick?: () => void,
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
export const CommitPreview: Component<CommitPreviewProps> = ({
|
|
45
|
-
commit,
|
|
45
|
+
commit, depth = 0,
|
|
46
46
|
attributes = [],
|
|
47
47
|
renderCommit,
|
|
48
48
|
color,
|
|
49
49
|
onClick,
|
|
50
50
|
}) => {
|
|
51
|
-
const children = commit.children
|
|
52
|
-
.map(childRef => tree.commits.get(childRef.id)).filter(c => !!c);
|
|
53
|
-
|
|
54
51
|
const background = `hsl(${(depth * 22.3) % 360}deg, 50%, 80%)`;
|
|
55
52
|
const elementBackground = color || `hsl(${stringHash(commit.element.type) % 360}deg, 60%, 80%)`;
|
|
53
|
+
const lineColor = `hsl(${stringHash(commit.id.toString()) % 360}, 100%, 20%)`
|
|
54
|
+
|
|
56
55
|
|
|
56
|
+
return hs('div', { className: classes.commit, style: { position: 'relative' }, id: `commit:${commit.id}` }, [
|
|
57
|
+
commit.children.length > 0 &&
|
|
58
|
+
h('div', { style: {
|
|
59
|
+
position: 'absolute',
|
|
60
|
+
top: '5px',
|
|
61
|
+
height: 'calc(100% - 18px)', width: '1px', background: lineColor, transform: `translate(20px, 0px)`
|
|
62
|
+
} }),
|
|
57
63
|
|
|
58
|
-
|
|
59
|
-
hs('div', { className: [classes.elementBar].join(' ') }, [
|
|
64
|
+
hs('div', { className: [classes.elementBar].join(' '), style: { 'position': 'relative' } }, [
|
|
60
65
|
hs('button', { onClick, className: classes.elementName, style: { background: elementBackground } },
|
|
61
66
|
commit.element.type),
|
|
62
|
-
|
|
67
|
+
h(CommitAttributeTag, { name: 'Id', value: commit.id.toString() }),
|
|
63
68
|
attributes.map(([name, value]) => h(CommitAttributeTag, { name, value }))
|
|
64
69
|
//h(CommitAttributeTag, { name: 'Version', value: commit.version.toString() }),
|
|
65
70
|
]),
|
|
66
|
-
|
|
71
|
+
|
|
72
|
+
!!renderCommit && hs('ol', { className: classes.commitList }, commit.children.map(childId => h('li', { key: childId, style: { position: 'relative' } }, [
|
|
73
|
+
renderCommit(childId),
|
|
74
|
+
h('div', { style: {
|
|
75
|
+
top: 0,
|
|
76
|
+
width: '25px', height: '1px', 'border-top': '2px dotted black', position: 'absolute',
|
|
77
|
+
transform: `translate(-22px, 15px)`
|
|
78
|
+
}})
|
|
79
|
+
]))),
|
|
67
80
|
])
|
|
68
81
|
};
|
|
69
82
|
|
package/Virtual.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Component, h, Node, ReadonlyRef, useEffect, useRef, useState } from "@lukekaalim/act";
|
|
2
|
+
import { debounce } from 'lodash-es';
|
|
3
|
+
|
|
4
|
+
export type VirtualTreeItem = {
|
|
5
|
+
depth: number,
|
|
6
|
+
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type VirtualTreeProps = {
|
|
10
|
+
chunkSize: number,
|
|
11
|
+
chunkCount: number,
|
|
12
|
+
|
|
13
|
+
windowRange: number,
|
|
14
|
+
|
|
15
|
+
renderChunk(index: number): Node,
|
|
16
|
+
|
|
17
|
+
viewportRef?: ReadonlyRef<HTMLElement | null>,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const Virtual1D: Component<VirtualTreeProps> = ({ chunkSize, chunkCount, renderChunk, viewportRef: propViewportRef, windowRange }) => {
|
|
21
|
+
const [start, setStart] = useState(0);
|
|
22
|
+
const [end, setEnd] = useState(0);
|
|
23
|
+
|
|
24
|
+
const localViewportRef = useRef<HTMLElement | null>(null);
|
|
25
|
+
const viewportRef = propViewportRef || localViewportRef;
|
|
26
|
+
|
|
27
|
+
const listRef = useRef<HTMLElement | null>(null);
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (!viewportRef.current)
|
|
31
|
+
return;
|
|
32
|
+
|
|
33
|
+
const viewport = viewportRef.current;
|
|
34
|
+
|
|
35
|
+
const setViewport = () => {
|
|
36
|
+
const rect = viewport.getBoundingClientRect();
|
|
37
|
+
|
|
38
|
+
setStart(Math.floor((viewport.scrollTop) / chunkSize))
|
|
39
|
+
setEnd(Math.ceil((viewport.scrollTop + rect.height) / chunkSize))
|
|
40
|
+
};
|
|
41
|
+
setViewport();
|
|
42
|
+
|
|
43
|
+
viewport.addEventListener('scroll', setViewport)
|
|
44
|
+
return () => {
|
|
45
|
+
viewport.removeEventListener('scroll', setViewport)
|
|
46
|
+
}
|
|
47
|
+
}, [propViewportRef])
|
|
48
|
+
|
|
49
|
+
const renderedIndices = Array
|
|
50
|
+
.from({ length: end - start })
|
|
51
|
+
.map((_, i) => start + i)
|
|
52
|
+
.filter(x => x >= 0 && x < chunkCount);
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
return [
|
|
56
|
+
//h('pre', {}, renderedIndices.join(', ')),
|
|
57
|
+
h('div', { ref: viewportRef, style: { overflow: 'auto', height: '100%' } },
|
|
58
|
+
h('div', { ref: listRef, style: { height: (chunkSize * chunkCount) + 'px', position: 'relative' } },
|
|
59
|
+
renderedIndices.map(index =>
|
|
60
|
+
h('div', { style: { position: 'absolute', top: (index * chunkSize) + 'px', height: chunkSize, padding: '-1', border: '1px dotted black', width: '100%' }},
|
|
61
|
+
renderChunk(index)))
|
|
62
|
+
))
|
|
63
|
+
];
|
|
64
|
+
};
|
package/index.ts
CHANGED
package/lookup.ts
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { CommitReport, DeltaReport, ElementReport, ThreadReport, TreeReport, WorkTaskReport } from "@lukekaalim/act-debug";
|
|
2
|
+
import { CommitID, CommitVersion, WorkThread2 } from "@lukekaalim/act-recon";
|
|
3
|
+
|
|
4
|
+
export class MutableCommitRef {
|
|
5
|
+
element: ElementReport;
|
|
6
|
+
id: CommitID;
|
|
7
|
+
version: CommitVersion;
|
|
8
|
+
distance: number;
|
|
9
|
+
|
|
10
|
+
report: CommitReport;
|
|
11
|
+
|
|
12
|
+
children: MutableCommitRef[] = [];
|
|
13
|
+
parent: null | MutableCommitRef = null;
|
|
14
|
+
|
|
15
|
+
constructor(commit: CommitReport) {
|
|
16
|
+
this.element = commit.element;
|
|
17
|
+
this.id = commit.id;
|
|
18
|
+
this.version = commit.version;
|
|
19
|
+
this.distance = commit.distance;
|
|
20
|
+
|
|
21
|
+
this.report = commit;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
update(commit: CommitReport) {
|
|
25
|
+
this.report = commit;
|
|
26
|
+
this.version = commit.version;
|
|
27
|
+
this.element = commit.element;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
resolve(lookupMap: Map<CommitID, MutableCommitRef>) {
|
|
31
|
+
if (this.report.parent !== null)
|
|
32
|
+
this.linkParent(this.report.parent, lookupMap);
|
|
33
|
+
this.linkChildren(this.report.children, lookupMap);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
linkParent(parent: CommitID, lookupMap: Map<CommitID, MutableCommitRef>) {
|
|
37
|
+
this.parent = lookupMap.get(parent) || null;
|
|
38
|
+
}
|
|
39
|
+
linkChildren(children: CommitID[], lookupMap: Map<CommitID, MutableCommitRef>) {
|
|
40
|
+
this.children = children.map(c => lookupMap.get(c)).filter(x => !!x);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class CommitLookupCache {
|
|
45
|
+
map: Map<CommitID, CommitReport> = new Map();
|
|
46
|
+
roots: Set<CommitID> = new Set();
|
|
47
|
+
|
|
48
|
+
setTree(tree: TreeReport) {
|
|
49
|
+
this.map.clear();
|
|
50
|
+
this.roots.clear();
|
|
51
|
+
|
|
52
|
+
for (const commit of tree.commits) {
|
|
53
|
+
this.map.set(commit.id, commit)
|
|
54
|
+
if (!commit.parent)
|
|
55
|
+
this.roots.add(commit.id);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
ingest(delta: DeltaReport) {
|
|
60
|
+
for (const create of delta.created) {
|
|
61
|
+
this.map.set(create.id, create);
|
|
62
|
+
if (!create.parent)
|
|
63
|
+
this.roots.add(create.id);
|
|
64
|
+
}
|
|
65
|
+
for (const update of delta.updated)
|
|
66
|
+
this.map.set(update.id, update);
|
|
67
|
+
for (const remove of delta.removed) {
|
|
68
|
+
this.map.delete(remove.id);
|
|
69
|
+
this.roots.delete(remove.id);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* A bunch of relevant data for a Tree in the progress of changing
|
|
76
|
+
*/
|
|
77
|
+
export class ThreadLookupCache {
|
|
78
|
+
canon: CommitLookupCache;
|
|
79
|
+
|
|
80
|
+
report: DeltaReport | null = null;
|
|
81
|
+
thread: ThreadReport | null = null;
|
|
82
|
+
|
|
83
|
+
constructor(canon: CommitLookupCache) {
|
|
84
|
+
this.canon = canon;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
roots: Set<CommitID> = new Set();
|
|
88
|
+
|
|
89
|
+
created: Set<CommitID> = new Set();
|
|
90
|
+
updated: Set<CommitID> = new Set();
|
|
91
|
+
removed: Set<CommitID> = new Set();
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* An up to date map of the tree, plus deleted notes in this delta
|
|
95
|
+
*/
|
|
96
|
+
all: Map<CommitID, CommitReport> = new Map();
|
|
97
|
+
|
|
98
|
+
nextTask: WorkTaskReport | null = null;
|
|
99
|
+
prevTask: WorkTaskReport | null = null;
|
|
100
|
+
|
|
101
|
+
allTasks: Map<CommitID, WorkTaskReport> = new Map();
|
|
102
|
+
|
|
103
|
+
targets: Set<CommitID> = new Set();
|
|
104
|
+
visited: Set<CommitID> = new Set();
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Clear the delta cache
|
|
108
|
+
*/
|
|
109
|
+
reset() {
|
|
110
|
+
this.roots = new Set(this.canon.roots)
|
|
111
|
+
this.all = new Map(this.canon.map);
|
|
112
|
+
this.allTasks = new Map();
|
|
113
|
+
|
|
114
|
+
this.nextTask = null;
|
|
115
|
+
this.prevTask = null;
|
|
116
|
+
this.report = null;
|
|
117
|
+
|
|
118
|
+
this.created.clear();
|
|
119
|
+
this.updated.clear();
|
|
120
|
+
this.removed.clear();
|
|
121
|
+
|
|
122
|
+
this.targets.clear();
|
|
123
|
+
this.visited.clear();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
ingestThread(thread: ThreadReport) {
|
|
127
|
+
this.thread = thread;
|
|
128
|
+
|
|
129
|
+
this.nextTask = thread.pendingTasks[thread.pendingTasks.length - 1];
|
|
130
|
+
this.targets = new Set(thread.reasons.map(reason => reason.target));
|
|
131
|
+
this.visited = new Set(thread.visited)
|
|
132
|
+
this.allTasks = new Map(thread.pendingTasks.map(task => [task.id, task]))
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
ingestDelta(delta: DeltaReport) {
|
|
136
|
+
this.report = delta;
|
|
137
|
+
const createdIds = new Set(delta.created.map(c => c.id));
|
|
138
|
+
|
|
139
|
+
for (const commit of delta.created) {
|
|
140
|
+
this.created.add(commit.id)
|
|
141
|
+
|
|
142
|
+
const children = [...new Set(commit.children.filter(c => this.all.has(c) || createdIds.has(c)))]
|
|
143
|
+
this.all.set(commit.id, { ...commit, children });
|
|
144
|
+
|
|
145
|
+
if (!commit.parent)
|
|
146
|
+
this.roots.add(commit.id);
|
|
147
|
+
}
|
|
148
|
+
for (const commit of delta.updated) {
|
|
149
|
+
const existingCommit = this.canon.map.get(commit.id) as CommitReport;
|
|
150
|
+
|
|
151
|
+
const children = [...new Set([
|
|
152
|
+
...commit.children.filter(c => this.all.has(c)),
|
|
153
|
+
...existingCommit.children,
|
|
154
|
+
])]
|
|
155
|
+
const mergedCommitReport = { ...commit, children };
|
|
156
|
+
|
|
157
|
+
this.updated.add(commit.id)
|
|
158
|
+
this.all.set(commit.id, mergedCommitReport)
|
|
159
|
+
}
|
|
160
|
+
for (const commit of delta.removed) {
|
|
161
|
+
this.removed.add(commit.id);
|
|
162
|
+
this.all.set(commit.id, commit);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
getFlat() {
|
|
167
|
+
const pending: CommitReport[] = [...this.roots.values()]
|
|
168
|
+
.map(root => this.all.get(root))
|
|
169
|
+
.filter(x => !!x);
|
|
170
|
+
|
|
171
|
+
const flat: CommitReport[] = [];
|
|
172
|
+
|
|
173
|
+
while (pending.length > 0) {
|
|
174
|
+
const commit = pending.pop() as CommitReport;
|
|
175
|
+
flat.push(commit);
|
|
176
|
+
for (const childId of [...commit.children].reverse()) {
|
|
177
|
+
const child = this.all.get(childId);
|
|
178
|
+
if (child)
|
|
179
|
+
pending.push(child);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return flat;
|
|
184
|
+
}
|
|
185
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lukekaalim/act-insight",
|
|
3
3
|
"main": "index.ts",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "1.1.0",
|
|
5
5
|
"scripts": {},
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@lukekaalim/act": "*",
|
|
8
|
-
"@lukekaalim/act-recon": "3.
|
|
9
|
-
"@lukekaalim/act-web": "
|
|
10
|
-
"@lukekaalim/act-debug": "1.0.
|
|
8
|
+
"@lukekaalim/act-recon": "3.1.0",
|
|
9
|
+
"@lukekaalim/act-web": "5.0.0",
|
|
10
|
+
"@lukekaalim/act-debug": "1.0.1",
|
|
11
11
|
"@sindresorhus/string-hash": "^2.0.0",
|
|
12
12
|
"@types/firefox-webext-browser": "^120.0.4",
|
|
13
13
|
"lodash-es": "^4.17.21"
|
package/utils.ts
CHANGED
|
@@ -1,52 +1,64 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
1
|
+
|
|
2
|
+
import { h, Node } from "@lukekaalim/act";
|
|
3
|
+
import { NodeBuilder, RenderSpace2 } from "@lukekaalim/act-backstage";
|
|
4
|
+
import { createDebugScheduler, DebugReconciler } from "@lukekaalim/act-debug";
|
|
5
|
+
import { createWebNodeBuilder, HTML, render } from "@lukekaalim/act-web";
|
|
6
|
+
import { InsightApp } from "./InsightApp";
|
|
7
|
+
import { Reconciler2 } from "@lukekaalim/act-recon";
|
|
8
|
+
|
|
9
|
+
export type DevOptions = {
|
|
10
|
+
mode?: 'extension' | 'popup' | 'none'
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const renderDEV = (node: Node, builders: NodeBuilder<any, any>[], { mode = 'none' }: DevOptions = {}) => {
|
|
14
|
+
const reconciler = new DebugReconciler();
|
|
15
|
+
const spaces = builders.map(builder => new RenderSpace2(reconciler.tree, builder));
|
|
16
|
+
|
|
17
|
+
reconciler.bus = {
|
|
18
|
+
render(delta) {
|
|
19
|
+
for (const space of spaces)
|
|
20
|
+
space.create(delta);
|
|
21
|
+
for (const space of spaces)
|
|
22
|
+
space.update(delta);
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
switch (mode) {
|
|
26
|
+
case 'popup':
|
|
27
|
+
createDebugPopup(reconciler);
|
|
28
|
+
break;
|
|
29
|
+
default:
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const ref = reconciler.mount(node);
|
|
33
|
+
return {ref, reconciler}
|
|
31
34
|
}
|
|
32
35
|
|
|
33
36
|
|
|
34
|
-
export const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
37
|
+
export const createDebugPopup = async (reconciler: DebugReconciler) => {
|
|
38
|
+
const newWindow = window.open('', "DevTools", "popup");
|
|
39
|
+
if (!newWindow)
|
|
40
|
+
throw new Error(`Unable to make/find new window!`);
|
|
41
|
+
|
|
42
|
+
const body = newWindow.document.body;
|
|
43
|
+
for (const child of [...body.childNodes, ...newWindow.document.head.childNodes])
|
|
44
|
+
child.remove();
|
|
45
|
+
|
|
46
|
+
for (const headElement of [...window.document.head.childNodes])
|
|
47
|
+
if (headElement instanceof HTMLStyleElement)
|
|
48
|
+
newWindow.document.head.appendChild(headElement.cloneNode(true))
|
|
49
|
+
else if (headElement instanceof HTMLLinkElement) {
|
|
50
|
+
const element = headElement.cloneNode(true) as HTMLLinkElement;
|
|
51
|
+
const src = new URL(element.href, document.location.href);
|
|
52
|
+
element.href = src.href;
|
|
53
|
+
newWindow.document.head.appendChild(element)
|
|
47
54
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
55
|
+
|
|
56
|
+
return new Promise<void>(onReady => {
|
|
57
|
+
render(
|
|
58
|
+
h(InsightApp, { controller: reconciler.controller, bus: reconciler.debugBus, document: newWindow.document, onReady }),
|
|
59
|
+
body,
|
|
60
|
+
{ window: newWindow }
|
|
61
|
+
);
|
|
62
|
+
})
|
|
63
|
+
|
|
52
64
|
}
|
package/vite.config.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { defineConfig } from 'vite';
|
|
2
|
-
import webExtension from "vite-plugin-web-extension";
|
|
2
|
+
//import webExtension from "vite-plugin-web-extension";
|
|
3
3
|
|
|
4
4
|
export default defineConfig({
|
|
5
5
|
build: {
|
|
6
6
|
modulePreload: false
|
|
7
7
|
},
|
|
8
|
-
plugins: [webExtension({
|
|
9
|
-
|
|
10
|
-
})],
|
|
8
|
+
//plugins: [webExtension({
|
|
9
|
+
// browser: 'firefox'
|
|
10
|
+
//})],
|
|
11
11
|
});
|