@deltarobotics/uhd-viewer 0.0.0-stage → 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/CHANGELOG.md +74 -0
- package/LICENSE +202 -0
- package/NOTICE +22 -0
- package/README.md +168 -2
- package/bin/serve.d.mts +62 -0
- package/bin/serve.mjs +257 -0
- package/bin/uhd-viewer.mjs +75 -0
- package/dist/app/assets/KodeMono-Bold-DdIivhPN.woff2 +0 -0
- package/dist/app/assets/KodeMono-Medium-CVnTuv5A.ttf +0 -0
- package/dist/app/assets/KodeMono-Regular-Bdr_-rJX.woff2 +0 -0
- package/dist/app/assets/KodeMono-SemiBold-JAfn5Dpm.ttf +0 -0
- package/dist/app/assets/index-CEJyT8hF.css +2 -0
- package/dist/app/assets/index-DWZ-48wc.js +3853 -0
- package/dist/app/index.html +16 -0
- package/dist/components/components.css +6372 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +26609 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/types/uhd-viewer/src/api.d.ts +286 -0
- package/dist/components/types/uhd-viewer/src/cad/CadView.d.ts +52 -0
- package/dist/components/types/uhd-viewer/src/cad/ModelView.d.ts +30 -0
- package/dist/components/types/uhd-viewer/src/cad/explode.d.ts +110 -0
- package/dist/components/types/uhd-viewer/src/cad/explodeSample.d.ts +25 -0
- package/dist/components/types/uhd-viewer/src/cad/findings.d.ts +41 -0
- package/dist/components/types/uhd-viewer/src/cad/labels.d.ts +76 -0
- package/dist/components/types/uhd-viewer/src/cad/model.d.ts +132 -0
- package/dist/components/types/uhd-viewer/src/cad/row.d.ts +15 -0
- package/dist/components/types/uhd-viewer/src/cad/scene.d.ts +95 -0
- package/dist/components/types/uhd-viewer/src/cad/scope.d.ts +89 -0
- package/dist/components/types/uhd-viewer/src/canvas/Canvas.d.ts +90 -0
- package/dist/components/types/uhd-viewer/src/canvas/Icon.d.ts +5 -0
- package/dist/components/types/uhd-viewer/src/canvas/LinkEdge.d.ts +40 -0
- package/dist/components/types/uhd-viewer/src/canvas/Port.d.ts +18 -0
- package/dist/components/types/uhd-viewer/src/canvas/actions.d.ts +5 -0
- package/dist/components/types/uhd-viewer/src/canvas/geometry.d.ts +72 -0
- package/dist/components/types/uhd-viewer/src/canvas/interaction.d.ts +162 -0
- package/dist/components/types/uhd-viewer/src/canvas/nodes.d.ts +43 -0
- package/dist/components/types/uhd-viewer/src/canvas/reveal.d.ts +55 -0
- package/dist/components/types/uhd-viewer/src/canvas/rightDrag.d.ts +51 -0
- package/dist/components/types/uhd-viewer/src/canvas/routing.d.ts +28 -0
- package/dist/components/types/uhd-viewer/src/chrome/ArtifactCards.d.ts +30 -0
- package/dist/components/types/uhd-viewer/src/chrome/Artifacts.d.ts +44 -0
- package/dist/components/types/uhd-viewer/src/chrome/BoardInspector.d.ts +53 -0
- package/dist/components/types/uhd-viewer/src/chrome/Chrome.d.ts +126 -0
- package/dist/components/types/uhd-viewer/src/chrome/Evidence.d.ts +20 -0
- package/dist/components/types/uhd-viewer/src/chrome/InterfaceCards.d.ts +66 -0
- package/dist/components/types/uhd-viewer/src/chrome/PairView.d.ts +37 -0
- package/dist/components/types/uhd-viewer/src/chrome/Sections.d.ts +128 -0
- package/dist/components/types/uhd-viewer/src/components.d.ts +60 -0
- package/dist/components/types/uhd-viewer/src/host/channel.d.ts +49 -0
- package/dist/components/types/uhd-viewer/src/host/context.d.ts +29 -0
- package/dist/components/types/uhd-viewer/src/host/protocol.d.ts +22 -0
- package/dist/components/types/uhd-viewer/src/host/targets.d.ts +101 -0
- package/dist/components/types/uhd-viewer/src/layout/board-layout.d.ts +69 -0
- package/dist/components/types/uhd-viewer/src/layout/card-body.d.ts +64 -0
- package/dist/components/types/uhd-viewer/src/layout/layout.d.ts +94 -0
- package/dist/components/types/uhd-viewer/src/layout/module-layout.d.ts +32 -0
- package/dist/components/types/uhd-viewer/src/layout/router.d.ts +55 -0
- package/dist/components/types/uhd-viewer/src/layout/taps.d.ts +20 -0
- package/dist/components/types/uhd-viewer/src/model/artifacts.d.ts +129 -0
- package/dist/components/types/uhd-viewer/src/model/classification.d.ts +41 -0
- package/dist/components/types/uhd-viewer/src/model/diagnostics.d.ts +27 -0
- package/dist/components/types/uhd-viewer/src/model/evidence.d.ts +63 -0
- package/dist/components/types/uhd-viewer/src/model/from-uhd.d.ts +58 -0
- package/dist/components/types/uhd-viewer/src/model/hierarchy.d.ts +173 -0
- package/dist/components/types/uhd-viewer/src/model/isolate.d.ts +33 -0
- package/dist/components/types/uhd-viewer/src/model/level.d.ts +7 -0
- package/dist/components/types/uhd-viewer/src/model/nets.d.ts +53 -0
- package/dist/components/types/uhd-viewer/src/model/outputs.d.ts +79 -0
- package/dist/components/types/uhd-viewer/src/model/slots.d.ts +184 -0
- package/dist/components/types/uhd-viewer/src/model/types.d.ts +213 -0
- package/dist/components/types/uhd-viewer/src/options.d.ts +27 -0
- package/dist/components/types/uhd-viewer/src/source/source.d.ts +109 -0
- package/dist/components/types/uhd-viewer/src/source/tolerant.d.ts +45 -0
- package/dist/components/types/uhd-viewer/src/theme/ThemeProvider.d.ts +33 -0
- package/dist/components/types/uhd-viewer/src/theme/adapters.d.ts +28 -0
- package/dist/components/types/uhd-viewer/src/theme/resolve.d.ts +19 -0
- package/dist/components/types/uhd-viewer/src/theme/themes.d.ts +67 -0
- package/dist/components/types/uhd-viewer/src/theme/tokens.d.ts +175 -0
- package/dist/components/types/uhd-viewer/src/ui/Inspector.d.ts +45 -0
- package/dist/components/types/uhd-viewer/src/ui/Legend.d.ts +59 -0
- package/dist/components/types/uhd-viewer/src/ui/ScrollArea.d.ts +16 -0
- package/dist/components/types/uhd-viewer/src/ui/Toolbar.d.ts +49 -0
- package/dist/components/types/uhd-viewer/src/ui/Tooltips.d.ts +3 -0
- package/dist/components/types/uhd-viewer/src/ui/cx.d.ts +2 -0
- package/dist/components/types/uhd-viewer/src/ui/legendFit.d.ts +55 -0
- package/dist/components/types/uhd-viewer/src/viewer/controller.d.ts +219 -0
- package/dist/components/types/uhd-viewer/src/viewer/details.d.ts +81 -0
- package/dist/components/types/uhd-viewer/src/viewer/hierarchy.d.ts +82 -0
- package/dist/components/types/uhd-viewer/src/viewer/mount.d.ts +12 -0
- package/dist/components/types/uhd-viewer/src/viewer/views.d.ts +187 -0
- package/dist/headless/index.d.ts +71 -0
- package/dist/headless/index.js +7425 -0
- package/dist/headless/index.js.map +1 -0
- package/dist/lib/api.d.ts +252 -0
- package/dist/lib/uhd-viewer.css +3 -0
- package/dist/lib/uhd-viewer.d.ts +4 -0
- package/dist/lib/uhd-viewer.js +97787 -0
- package/package.json +110 -4
- package/src/styles/fonts/OFL.txt +93 -0
- package/src/styles/tailwind-theme.css +48 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The hierarchy panel's model (PB-1042): the whole module tree of a system,
|
|
3
|
+
* every level at once (the root, its sub-modules, their parts and harnesses),
|
|
4
|
+
* with what each row shows (an icon by kind, the host's part mark, the worst
|
|
5
|
+
* finding here or below), the filter, the rows on screen, the keyboard, and
|
|
6
|
+
* how a row maps to the diagram's level and selection. Pure functions, so they
|
|
7
|
+
* test without a page; viewer/hierarchy.tsx draws them.
|
|
8
|
+
*/
|
|
9
|
+
import type { ModuleDef } from "@deltarobotics/uhd";
|
|
10
|
+
import type { ModuleLookup } from "@deltarobotics/uhd";
|
|
11
|
+
import type { UhdBundleDiagnostic } from "@deltarobotics/uhd";
|
|
12
|
+
import type { NodeMark } from "../api";
|
|
13
|
+
import type { ScopedDiagnostic } from "./diagnostics";
|
|
14
|
+
import { type LevelSelection } from "../host/targets";
|
|
15
|
+
/** What a row is: the same kinds as a host's own module tree. */
|
|
16
|
+
export type HierarchyKind = "system" | "assembly" | "group" | "part" | "board" | "enclosure" | "structure" | "harness" | "fasteners";
|
|
17
|
+
export type Severity = "error" | "warning" | "info";
|
|
18
|
+
export interface Findings {
|
|
19
|
+
error: number;
|
|
20
|
+
warning: number;
|
|
21
|
+
info: number;
|
|
22
|
+
}
|
|
23
|
+
export interface HierarchyNode {
|
|
24
|
+
/** Instance path from the root ("" is the root). */
|
|
25
|
+
path: string;
|
|
26
|
+
/** The parent's path; undefined for the root. */
|
|
27
|
+
parent?: string;
|
|
28
|
+
label: string;
|
|
29
|
+
defId: string;
|
|
30
|
+
/** The definition's own name, when the instance is named otherwise ("FB upper" is a "Resistor 1 MΩ"). */
|
|
31
|
+
defName?: string;
|
|
32
|
+
kind: HierarchyKind;
|
|
33
|
+
/** A Lucide icon name for the kind. */
|
|
34
|
+
icon: string;
|
|
35
|
+
depth: number;
|
|
36
|
+
quantity?: number;
|
|
37
|
+
/** The host's mark for the definition (a part's status), as the diagram's dot shows it. */
|
|
38
|
+
mark?: NodeMark;
|
|
39
|
+
/** The bundle names the definition and does not hold it: drawn as a placeholder. */
|
|
40
|
+
missing?: boolean;
|
|
41
|
+
/** Findings on this module itself. */
|
|
42
|
+
findings: Findings;
|
|
43
|
+
/** The worst finding here or below. */
|
|
44
|
+
worst?: Severity;
|
|
45
|
+
/** The module has a level of its own (a module with children; not a harness). */
|
|
46
|
+
drillable: boolean;
|
|
47
|
+
/** A row of the panel's own that only holds others (`WIRING_PATH`): no module, nothing to select. */
|
|
48
|
+
group?: boolean;
|
|
49
|
+
/** In the wiring group: the module it belongs to ("Front-right arm"), since four "Prop nut" rows read alike. */
|
|
50
|
+
where?: string;
|
|
51
|
+
children: HierarchyNode[];
|
|
52
|
+
}
|
|
53
|
+
/** Icons by kind (Lucide names), matching a host tree's: a board, a package, a chip, a plug. */
|
|
54
|
+
export declare const KIND_ICON: Record<HierarchyKind, string>;
|
|
55
|
+
/** What a kind is called (tooltips, the accessible description). */
|
|
56
|
+
export declare const KIND_LABEL: Record<HierarchyKind, string>;
|
|
57
|
+
/** A module that stands for a part nobody has chosen yet (the host marks it with a ring). */
|
|
58
|
+
export declare const BLANK_ICON = "circle-dashed";
|
|
59
|
+
/** What kind of module a definition is, from what the bundle says (its UHD kind, nets, children, categories). */
|
|
60
|
+
export declare function kindOf(def: ModuleDef | undefined, isRoot: boolean): HierarchyKind;
|
|
61
|
+
export interface HierarchyOptions {
|
|
62
|
+
/** The host's marks by definition id (`ViewerOptions.nodeMarks`). */
|
|
63
|
+
marks?: Record<string, NodeMark>;
|
|
64
|
+
/** The viewer's own checks (systemDiagnostics). */
|
|
65
|
+
diagnostics?: readonly ScopedDiagnostic[];
|
|
66
|
+
/** The producer's and the host's findings. */
|
|
67
|
+
hostDiagnostics?: readonly UhdBundleDiagnostic[];
|
|
68
|
+
/** Whether the definition is a placeholder for one the bundle lacks. */
|
|
69
|
+
isMissing?: (def: ModuleDef) => boolean;
|
|
70
|
+
}
|
|
71
|
+
/** The module tree from the root: `[root]`. A definition that names itself further down stops there. */
|
|
72
|
+
export declare function buildHierarchy(root: ModuleDef, lookup: ModuleLookup, options?: HierarchyOptions): HierarchyNode[];
|
|
73
|
+
/** The module a canonical ref names: `board/u2:pin_14` → `board/u2`, `link:a/b/l1` → `a/b`, `:sda` on a scope → the scope. */
|
|
74
|
+
export declare function modulePart(ref: string, scope: string): string;
|
|
75
|
+
export declare function walkHierarchy(nodes: readonly HierarchyNode[]): Generator<HierarchyNode>;
|
|
76
|
+
/** Every node by path. */
|
|
77
|
+
export declare const hierarchyIndex: (nodes: readonly HierarchyNode[]) => Map<string, HierarchyNode>;
|
|
78
|
+
/** The paths above `path`, root first ("" for the root itself has none). */
|
|
79
|
+
export declare function ancestorsOf(path: string): string[];
|
|
80
|
+
/**
|
|
81
|
+
* The tree reduced to the rows that match `text` (every word, in the label,
|
|
82
|
+
* the definition's name, the instance path, the definition id or the kind;
|
|
83
|
+
* case-insensitive), with
|
|
84
|
+
* the modules that lead to them. A matching module keeps its own children.
|
|
85
|
+
* Returns the reduced tree and the paths to show open.
|
|
86
|
+
*/
|
|
87
|
+
export declare function filterHierarchy(nodes: readonly HierarchyNode[], text: string): {
|
|
88
|
+
nodes: HierarchyNode[];
|
|
89
|
+
expanded: Set<string>;
|
|
90
|
+
matches: Set<string>;
|
|
91
|
+
};
|
|
92
|
+
/** One row on screen. */
|
|
93
|
+
export interface HierarchyRow {
|
|
94
|
+
node: HierarchyNode;
|
|
95
|
+
/** 1-based, as `aria-level` takes it. */
|
|
96
|
+
level: number;
|
|
97
|
+
/** Has rows below it (open or not). */
|
|
98
|
+
branch: boolean;
|
|
99
|
+
open: boolean;
|
|
100
|
+
/** 1-based place among its siblings, and how many there are (`aria-posinset`, `aria-setsize`). */
|
|
101
|
+
pos: number;
|
|
102
|
+
size: number;
|
|
103
|
+
}
|
|
104
|
+
/** The rows on screen: every node whose ancestors are all open. */
|
|
105
|
+
export declare function visibleRows(nodes: readonly HierarchyNode[], expanded: ReadonlySet<string>): HierarchyRow[];
|
|
106
|
+
/** What a key does on the tree: where the focus goes, what opens or closes, and what is asked of the viewer. */
|
|
107
|
+
export interface TreeKeyResult {
|
|
108
|
+
focus: string;
|
|
109
|
+
expanded: Set<string>;
|
|
110
|
+
action?: "select" | "drill";
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The tree's keyboard (WAI-ARIA tree pattern): Up and Down move, Home and End
|
|
114
|
+
* go to the first and last row; Right opens a closed module, or moves to its
|
|
115
|
+
* first child; Left closes an open one, or moves to its parent; Enter and
|
|
116
|
+
* Space select the row (Enter on the row already selected drills into it,
|
|
117
|
+
* when it has a level of its own); `*` opens every sibling. Undefined: the key
|
|
118
|
+
* is not the tree's.
|
|
119
|
+
*/
|
|
120
|
+
export declare function treeKey(rows: readonly HierarchyRow[], focus: string, key: string, expanded: ReadonlySet<string>, selected?: string): TreeKeyResult | undefined;
|
|
121
|
+
/** The module path the diagram has selected, from its level and selection; undefined for none, a link or a net. */
|
|
122
|
+
export declare function selectedPath(drill: readonly string[], selection: LevelSelection): string | undefined;
|
|
123
|
+
/**
|
|
124
|
+
* Where a click on a row takes the diagram: the level that holds the module,
|
|
125
|
+
* with it selected (the current level, when the module is drawn there; the
|
|
126
|
+
* root row is the top level with nothing selected).
|
|
127
|
+
*/
|
|
128
|
+
export declare function rowTarget(root: ModuleDef, lookup: ModuleLookup, path: string, current: {
|
|
129
|
+
drill: string[];
|
|
130
|
+
expanded: ReadonlySet<string>;
|
|
131
|
+
}): {
|
|
132
|
+
drill: string[];
|
|
133
|
+
selection: LevelSelection;
|
|
134
|
+
};
|
|
135
|
+
/** Where drilling into a row takes the diagram: its own level, nothing selected. */
|
|
136
|
+
export declare function drillInto(node: HierarchyNode): {
|
|
137
|
+
drill: string[];
|
|
138
|
+
selection: LevelSelection;
|
|
139
|
+
};
|
|
140
|
+
/** The paths to open so that `path` shows: its ancestors. */
|
|
141
|
+
export declare function revealPaths(expanded: ReadonlySet<string>, path: string | undefined): Set<string>;
|
|
142
|
+
/** What the panel keeps per tab: open or folded to its rail, its width, the open modules. */
|
|
143
|
+
export interface HierarchyPanelState {
|
|
144
|
+
open: boolean;
|
|
145
|
+
width: number;
|
|
146
|
+
expanded: string[];
|
|
147
|
+
}
|
|
148
|
+
export declare const HIERARCHY_WIDTH: {
|
|
149
|
+
readonly min: 180;
|
|
150
|
+
readonly max: 520;
|
|
151
|
+
readonly default: 280;
|
|
152
|
+
};
|
|
153
|
+
/** A kept state, checked; anything malformed falls back to the default. */
|
|
154
|
+
export declare function panelState(v: unknown, fallbackOpen?: boolean): HierarchyPanelState;
|
|
155
|
+
export declare const clampWidth: (w: number, room?: number) => number;
|
|
156
|
+
/** The row "Harnesses & links" that holds the harnesses, cables and fastener stacks: not a module of the system. */
|
|
157
|
+
export declare const WIRING_PATH = "#wiring";
|
|
158
|
+
/**
|
|
159
|
+
* The tree as the panel shows it: the system's structure first, and the
|
|
160
|
+
* harnesses and links (harnesses, cables and fastener stacks) folded into one
|
|
161
|
+
* group row at the bottom, `WIRING_PATH`. With `level` (the instance path of
|
|
162
|
+
* the level on screen, "" for the root), the group holds only that level's own
|
|
163
|
+
* harnesses, not those of the modules inside it: they show once that module is
|
|
164
|
+
* the level. Without `level`, every harness, wherever it sits, each with the
|
|
165
|
+
* module it belongs to. Harnesses never show in the structure. Without any for
|
|
166
|
+
* the group, the structure alone.
|
|
167
|
+
*/
|
|
168
|
+
export declare function groupWiring(nodes: readonly HierarchyNode[], level?: string): HierarchyNode[];
|
|
169
|
+
/** The marks the tree shows, once each, in the order of their tones: a legend (the first sentence of a mark's label names it). */
|
|
170
|
+
export declare function markLegend(nodes: readonly HierarchyNode[]): {
|
|
171
|
+
tone: NodeMark["tone"];
|
|
172
|
+
label: string;
|
|
173
|
+
}[];
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Isolating a legend entry (a signal type, a domain, a DRC state): the links
|
|
3
|
+
* of that kind stay, with the interfaces and modules they touch; everything
|
|
4
|
+
* else on the level fades. Pure functions of the level's view model, so the
|
|
5
|
+
* result follows the model as it rebuilds and the drill level as it changes.
|
|
6
|
+
*/
|
|
7
|
+
import { type Classification } from "./classification";
|
|
8
|
+
import type { ViewLink, ViewModel } from "./types";
|
|
9
|
+
/** What stays at full strength while some legend entries are isolated. */
|
|
10
|
+
export interface Isolation {
|
|
11
|
+
/** View link ids (`ViewLink.id`: each drawn line). */
|
|
12
|
+
links: Set<string>;
|
|
13
|
+
/** Node ids: the ends of those links, the nets of that kind, and the containers that hold either. */
|
|
14
|
+
nodes: Set<string>;
|
|
15
|
+
/** Ports as `node|port`: the ends of those links, and ports of that kind on a node that stays. */
|
|
16
|
+
ports: Set<string>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The legend entries a link belongs to: its own and, by signal type or
|
|
20
|
+
* domain, those of what it carries (a cable with power and a UART is in both;
|
|
21
|
+
* by DRC state a link has one state, its own).
|
|
22
|
+
*/
|
|
23
|
+
export declare function linkKeys(link: ViewLink, mode: Classification): Set<string>;
|
|
24
|
+
/** Every legend entry the level has something of: its links (and what they carry) and its nets. */
|
|
25
|
+
export declare function presentKeys(vm: ViewModel, mode: Classification): Set<string>;
|
|
26
|
+
/** What stays when `keys` are isolated on the level; null when nothing is isolated. */
|
|
27
|
+
export declare function isolate(vm: ViewModel, mode: Classification, keys: ReadonlySet<string>): Isolation | null;
|
|
28
|
+
/**
|
|
29
|
+
* A click on a legend entry: it becomes the one isolated; a click on the only
|
|
30
|
+
* one isolated shows everything again. With `add` (a modifier key) it joins
|
|
31
|
+
* or leaves the ones held.
|
|
32
|
+
*/
|
|
33
|
+
export declare function toggleIsolated(current: ReadonlySet<string>, key: string, add?: boolean): Set<string>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ViewNode } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* The modules a level draws: its nodes less what is not a module of its own
|
|
4
|
+
* (the drilled-into module's boundary ports, a board's net junctions and
|
|
5
|
+
* their taps). A level with none is empty, whatever ports it shows.
|
|
6
|
+
*/
|
|
7
|
+
export declare function levelModules(nodes: readonly ViewNode[]): ViewNode[];
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Board nets in the view model (PB-823; UHD docs/boards-and-nets.md).
|
|
3
|
+
*
|
|
4
|
+
* A net is a `Net` interface on the board itself (protocol `net`, not
|
|
5
|
+
* exposed), joined to each pin on it by a stored membership link. Drawing a
|
|
6
|
+
* line per membership would draw a star of N lines per net, most of them to
|
|
7
|
+
* the same component; drawing every pair would be worse. Instead:
|
|
8
|
+
*
|
|
9
|
+
* - each net is a junction node (`:<net>`; `board:<net>` when the board is
|
|
10
|
+
* expanded in place);
|
|
11
|
+
* - each component on the net gets one port for it, named for the net, and
|
|
12
|
+
* one grouped line to the junction whose children are its pins on the net;
|
|
13
|
+
* - a ground net (a ground pin on it and no supply pin) is drawn as ground
|
|
14
|
+
* symbols at its members, like any ground link, unless GND wires are on;
|
|
15
|
+
* - the functional links UHD derives over the nets (an I2C bus, a supply to
|
|
16
|
+
* its loads) are listed by name, and their state is carried by the grouped
|
|
17
|
+
* lines they run over, so a `bus_incomplete` or `harness_wiring` finding
|
|
18
|
+
* on one turns those lines red, as it does for a cable's lanes.
|
|
19
|
+
*/
|
|
20
|
+
import type { ModuleDef } from "@deltarobotics/uhd";
|
|
21
|
+
import type { LinkResult, ModuleLookup } from "@deltarobotics/uhd";
|
|
22
|
+
import type { ViewDerived, ViewLink, ViewNode, ViewPort } from "./types";
|
|
23
|
+
/** Node id of a net: the canonical path of the net interface (`:<net>`, or `board:<net>` inside an expanded board). */
|
|
24
|
+
export declare const netNodeId: (prefix: string, net: string) => string;
|
|
25
|
+
/** Port id on a component for its connection to a net. */
|
|
26
|
+
export declare const netPortId: (net: string) => string;
|
|
27
|
+
/**
|
|
28
|
+
* Label of a grouped membership line: the pin's name, or the distinct names
|
|
29
|
+
* of several ("VDD/VDDIO"), or the first and how many others ("IOVDD +3").
|
|
30
|
+
*/
|
|
31
|
+
export declare function pinsLabel(names: string[]): string;
|
|
32
|
+
export interface LevelNets {
|
|
33
|
+
/** Junction nodes (ground nets left out unless `grounds`). */
|
|
34
|
+
nodes: ViewNode[];
|
|
35
|
+
/** One grouped line per component and net. */
|
|
36
|
+
links: ViewLink[];
|
|
37
|
+
/** Ports to add to the component nodes, by node id. */
|
|
38
|
+
ports: Map<string, ViewPort[]>;
|
|
39
|
+
derived: ViewDerived[];
|
|
40
|
+
/** Membership link id (prefixed) → grouped line id. */
|
|
41
|
+
owners: Map<string, string>;
|
|
42
|
+
/** Derived link id (prefixed) → grouped line ids it runs over. */
|
|
43
|
+
derivedOwners: Map<string, string[]>;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The nets of `def` drawn at a level (`prefix` "" for the level module itself,
|
|
47
|
+
* `<child>/` for a board expanded in place). `results` are the module's stored
|
|
48
|
+
* link results, `derived` the links UHD derives from them.
|
|
49
|
+
*/
|
|
50
|
+
export declare function levelNets(def: ModuleDef, results: LinkResult[], derived: LinkResult[], lookup: ModuleLookup, prefix: string, opts: {
|
|
51
|
+
grounds: boolean;
|
|
52
|
+
parent?: string;
|
|
53
|
+
}): LevelNets;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standard outputs (PB-823): the files a capability provider exports for a
|
|
3
|
+
* custom module, which the viewer reads as ordinary artifacts. It finds them
|
|
4
|
+
* by their fixed file names (protoboard-cli docs/specs/tool-integrations.md
|
|
5
|
+
* §8) and never by the tool that wrote them:
|
|
6
|
+
*
|
|
7
|
+
* circuit board.glb, board.manifest.json, bom.csv, pnp.csv, netlist.json,
|
|
8
|
+
* and the drawings schematic.svg, pcb-top.svg, pcb-bottom.svg
|
|
9
|
+
* cad body.glb, body.manifest.json, and print/cut exports (.stl, .3mf, .dxf)
|
|
10
|
+
*
|
|
11
|
+
* PCB drawings are in board millimetres: one SVG user unit is 1 mm, the top
|
|
12
|
+
* view draws board (x, y) at (x, −y), and the bottom view, seen from below,
|
|
13
|
+
* at (−x, −y), with (x, y) as in pnp.csv and the geometry manifest. That is
|
|
14
|
+
* what lets the viewer mark a component on them from its pick-and-place row.
|
|
15
|
+
* A drawing whose viewBox does not hold the placed components is shown
|
|
16
|
+
* without marks.
|
|
17
|
+
*/
|
|
18
|
+
import type { ArtifactDef, ModuleDef } from "@deltarobotics/uhd";
|
|
19
|
+
import type { GeometryManifest } from "@deltarobotics/uhd";
|
|
20
|
+
import type { ModuleLookup } from "@deltarobotics/uhd";
|
|
21
|
+
export interface CircuitOutputs {
|
|
22
|
+
glb?: ArtifactDef;
|
|
23
|
+
manifest?: ArtifactDef;
|
|
24
|
+
bom?: ArtifactDef;
|
|
25
|
+
pnp?: ArtifactDef;
|
|
26
|
+
netlist?: ArtifactDef;
|
|
27
|
+
schematic?: ArtifactDef;
|
|
28
|
+
top?: ArtifactDef;
|
|
29
|
+
bottom?: ArtifactDef;
|
|
30
|
+
}
|
|
31
|
+
export interface CadOutputs {
|
|
32
|
+
glb?: ArtifactDef;
|
|
33
|
+
manifest?: ArtifactDef;
|
|
34
|
+
/** Manufacturing exports: STL, 3MF, DXF. */
|
|
35
|
+
exports: ArtifactDef[];
|
|
36
|
+
}
|
|
37
|
+
/** A module's circuit standard outputs, by file name; undefined when it has none of them. */
|
|
38
|
+
export declare function circuitOutputs(def: ModuleDef | undefined): CircuitOutputs | undefined;
|
|
39
|
+
/** A module's cad standard outputs, by file name; undefined when it has none of them. */
|
|
40
|
+
export declare function cadOutputs(def: ModuleDef | undefined): CadOutputs | undefined;
|
|
41
|
+
/** Standard output drawings are views of the board, not pictures of the part: never its thumbnail. */
|
|
42
|
+
export declare const isBoardDrawing: (a: ArtifactDef) => boolean;
|
|
43
|
+
/** RFC 4180 CSV with a header row, as rows of named fields. */
|
|
44
|
+
export declare function parseCsv(text: string): Record<string, string>[];
|
|
45
|
+
export interface PnpRow {
|
|
46
|
+
instance: string;
|
|
47
|
+
x: number;
|
|
48
|
+
y: number;
|
|
49
|
+
rotation: number;
|
|
50
|
+
side: "top" | "bottom";
|
|
51
|
+
}
|
|
52
|
+
/** Pick-and-place rows (`instance`, `x_mm`, `y_mm`, `rotation_deg`, `side`); rows that do not parse are left out. */
|
|
53
|
+
export declare function parsePnp(text: string): PnpRow[];
|
|
54
|
+
/** Where a component sits on the board: a rectangle in board millimetres. */
|
|
55
|
+
export interface Footprint {
|
|
56
|
+
instance: string;
|
|
57
|
+
side: "top" | "bottom";
|
|
58
|
+
/** Centre (board mm). */
|
|
59
|
+
x: number;
|
|
60
|
+
y: number;
|
|
61
|
+
/** Size along board x and y, after rotation. */
|
|
62
|
+
w: number;
|
|
63
|
+
h: number;
|
|
64
|
+
/** Where the size came from: the part's package facts, or the manifest feature's area. */
|
|
65
|
+
size: "package" | "manifest" | "unknown";
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Every placed component's rectangle: its pick-and-place position, sized by
|
|
69
|
+
* the part's package (length × width, turned by the row's rotation), else by
|
|
70
|
+
* the manifest feature named by its instance path (a square of its area),
|
|
71
|
+
* else a 1 mm square.
|
|
72
|
+
*/
|
|
73
|
+
export declare function footprints(board: ModuleDef, lookup: ModuleLookup, pnp: PnpRow[], manifest?: GeometryManifest): Footprint[];
|
|
74
|
+
/** Board millimetres → drawing units for one side (the convention above). */
|
|
75
|
+
export declare const toDrawing: (side: "top" | "bottom", x: number, y: number) => [number, number];
|
|
76
|
+
/** Whether a drawing's viewBox holds every component placed on its side (else its marks would be wrong). */
|
|
77
|
+
export declare function drawingFits(viewBox: [number, number, number, number], side: "top" | "bottom", fps: Footprint[]): boolean;
|
|
78
|
+
/** The component under a point of a drawing, smallest first (a resistor under a chip's corner wins). */
|
|
79
|
+
export declare function footprintAt(side: "top" | "bottom", fps: Footprint[], dx: number, dy: number, slack?: number): Footprint | undefined;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A module's interfaces as the inspector's slot cards (PB-1042, design A with
|
|
3
|
+
* expandable cards, 2026-10-21): what each interface is (its kind, protocol,
|
|
4
|
+
* role and pins), what it is linked to and through which harness, and, for
|
|
5
|
+
* the card opened, its pin mapping, its stated parameters, its links and the
|
|
6
|
+
* links derived over them with their state, its findings, its notes and
|
|
7
|
+
* assumptions, and the sources it cites. Plain data from the view model and
|
|
8
|
+
* the definitions; nothing here draws.
|
|
9
|
+
*/
|
|
10
|
+
import type { InterfaceDef, ModuleDef } from "@deltarobotics/uhd";
|
|
11
|
+
import type { ViewModel, ViewNode, ViewPort } from "./types";
|
|
12
|
+
export type SlotKind = "power" | "signal" | "mechanical";
|
|
13
|
+
/** A link's state in the inspector's words: a stored link is configured, a derived one compatible. */
|
|
14
|
+
export type SlotState = "configured" | "compatible" | "warning" | "incompatible" | "unconfigured";
|
|
15
|
+
/** One pin or slot of the interface, the leaf it binds, and what it meets on the other side. */
|
|
16
|
+
export interface SlotPin {
|
|
17
|
+
/** The pin or slot as the board names it ("RX2", "BAT+"). */
|
|
18
|
+
pin: string;
|
|
19
|
+
/** The leaf interface it binds on this module ("uart2_rx"), when it is not the pin itself. */
|
|
20
|
+
leaf?: string;
|
|
21
|
+
/** `←` into this module, `→` out of it, `—` a shared return (ground), `↔` both or not known. */
|
|
22
|
+
dir: "←" | "→" | "—" | "↔";
|
|
23
|
+
/** The pin it meets on the other side, and that module's name. */
|
|
24
|
+
other?: string;
|
|
25
|
+
otherModule?: string;
|
|
26
|
+
}
|
|
27
|
+
export interface SlotParam {
|
|
28
|
+
label: string;
|
|
29
|
+
value: string;
|
|
30
|
+
}
|
|
31
|
+
export interface SlotLink {
|
|
32
|
+
/** The link's id as its module declares it ("rx_pads"), or a derived link's name. */
|
|
33
|
+
label: string;
|
|
34
|
+
/** Its name as declared ("Receiver wires on the FC"). */
|
|
35
|
+
name?: string;
|
|
36
|
+
/** What to select in the viewer for it: a canonical id on the level shown. */
|
|
37
|
+
select: string;
|
|
38
|
+
/** The harness or cable it runs through. */
|
|
39
|
+
via?: string;
|
|
40
|
+
state: SlotState;
|
|
41
|
+
/** A link UHD derives over this one (through a cable's conductors, over a net). */
|
|
42
|
+
derived?: boolean;
|
|
43
|
+
/** The finding messages the viewer's checks put on it. */
|
|
44
|
+
diagnostics: string[];
|
|
45
|
+
}
|
|
46
|
+
export interface SlotFinding {
|
|
47
|
+
/** The host's key for it, when the host gave the finding (its Locate). */
|
|
48
|
+
key?: string;
|
|
49
|
+
code: string;
|
|
50
|
+
message: string;
|
|
51
|
+
severity: "error" | "warning" | "info";
|
|
52
|
+
}
|
|
53
|
+
export interface SlotNote {
|
|
54
|
+
/** What the trait is ("Usage note", "Assumption", "Data gap"). */
|
|
55
|
+
label: string;
|
|
56
|
+
text: string;
|
|
57
|
+
/** An `assumption` trait, or a relation stated as assumed: marked as such. */
|
|
58
|
+
assumption?: boolean;
|
|
59
|
+
}
|
|
60
|
+
export interface SlotSource {
|
|
61
|
+
label: string;
|
|
62
|
+
url: string;
|
|
63
|
+
}
|
|
64
|
+
export interface InterfaceSlot {
|
|
65
|
+
/** The port's id on the module. */
|
|
66
|
+
id: string;
|
|
67
|
+
name: string;
|
|
68
|
+
kind: SlotKind;
|
|
69
|
+
/** "UART · CRSF", "Power in", "USB". */
|
|
70
|
+
protocol?: string;
|
|
71
|
+
/** "host", "sink", "source", "device". */
|
|
72
|
+
role?: string;
|
|
73
|
+
/** Its pins, as chips. */
|
|
74
|
+
pins: string[];
|
|
75
|
+
/** The modules it is linked to, each with the harness the link runs through. */
|
|
76
|
+
linked: {
|
|
77
|
+
module: string;
|
|
78
|
+
via?: string;
|
|
79
|
+
}[];
|
|
80
|
+
/** Linked to nothing, and not part of an interface that is. */
|
|
81
|
+
open: boolean;
|
|
82
|
+
/** Linked through another interface of the module that binds it (an exported pad inside a linked pad group). */
|
|
83
|
+
usedBy?: string;
|
|
84
|
+
/** Exported to the boundary of the module it is in, by that name: linked from outside, not open. */
|
|
85
|
+
exportedAs?: string;
|
|
86
|
+
/** A pin bound into another interface of the module (a UART's RX inside its pad group), by that one's name: not on the outline, not linked on its own. */
|
|
87
|
+
partOf?: string;
|
|
88
|
+
/** The worst state of its links. */
|
|
89
|
+
state?: SlotState;
|
|
90
|
+
pinMap: SlotPin[];
|
|
91
|
+
params: SlotParam[];
|
|
92
|
+
links: SlotLink[];
|
|
93
|
+
findings: SlotFinding[];
|
|
94
|
+
notes: SlotNote[];
|
|
95
|
+
sources: SlotSource[];
|
|
96
|
+
/** Canonical refs of the interface and its links, for findings and Locate (`stack:rx_fc_pads`, `rx_pads`). */
|
|
97
|
+
refs: string[];
|
|
98
|
+
/** A card for several alike interfaces (Motor pads ×4): their ids. */
|
|
99
|
+
members?: string[];
|
|
100
|
+
/** What such a card is linked to, said once ("4 arms" via "Motor phase leads"). */
|
|
101
|
+
together?: {
|
|
102
|
+
module: string;
|
|
103
|
+
via?: string;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/** A finding the host knows about, with the canonical ids it is about (links as the viewer selects them, interfaces as `path:id`). */
|
|
107
|
+
export interface HostFinding {
|
|
108
|
+
key: string;
|
|
109
|
+
code: string;
|
|
110
|
+
message: string;
|
|
111
|
+
severity: "error" | "warning" | "info";
|
|
112
|
+
refs: string[];
|
|
113
|
+
}
|
|
114
|
+
export interface SlotOptions {
|
|
115
|
+
/** Definitions by id: the module's own, its children's (leaves bound by its pad groups) and the other ends'. */
|
|
116
|
+
lookup: (id: string) => ModuleDef | undefined;
|
|
117
|
+
/** The level the view model is of, from the root (canonical ids are joined to it). */
|
|
118
|
+
drill?: string[];
|
|
119
|
+
/** Names as written in the model, by node id on the level (the view model's labels are upper case). */
|
|
120
|
+
names?: Map<string, string>;
|
|
121
|
+
/** Link names as declared, by link id on the level. */
|
|
122
|
+
linkNames?: Map<string, string>;
|
|
123
|
+
/** Findings of the host (with their keys) or of the viewer's own checks. */
|
|
124
|
+
findings?: HostFinding[];
|
|
125
|
+
}
|
|
126
|
+
/** "max_current" → "Max current", "rx_fc_pads" → "RX FC pads". */
|
|
127
|
+
export declare function humanize(id: string): string;
|
|
128
|
+
/** "BATTERY LEAD" → "Battery lead": a label the view model upper-cased, back in sentence case. */
|
|
129
|
+
export declare function sentence(label: string): string;
|
|
130
|
+
/** A parameter with its unit: "5 V", "6–30 V", "2–6" (dimensionless). */
|
|
131
|
+
export declare function paramValue(p: {
|
|
132
|
+
value?: number;
|
|
133
|
+
unit?: string;
|
|
134
|
+
range?: [number, number];
|
|
135
|
+
}): string | undefined;
|
|
136
|
+
/** An interface by id: the module's own, an export's child interface, or a leaf of a child (one or two levels down). */
|
|
137
|
+
export declare function findInterface(def: ModuleDef | undefined, id: string, lookup: SlotOptions["lookup"], depth?: number): InterfaceDef | undefined;
|
|
138
|
+
/** Which way a pin faces, from its leaf's roles, else from its name. */
|
|
139
|
+
export declare function direction(leaf: InterfaceDef | undefined, name: string): SlotPin["dir"];
|
|
140
|
+
/** Power (red), signal (blue) or mechanical (grey): the slot glyph's colour. */
|
|
141
|
+
export declare function slotKind(port: ViewPort, leaves: (InterfaceDef | undefined)[], lanes: string[]): SlotKind;
|
|
142
|
+
/** "dolphinrc.com · …e-165929bb5a.pdf": where a source is, short. */
|
|
143
|
+
export declare function sourceLabel(url: string): string;
|
|
144
|
+
/** Every interface of the node as a slot card, linked ones first, then open ones, then those used through another. */
|
|
145
|
+
export declare function interfaceSlots(node: ViewNode, vm: ViewModel, opts: SlotOptions): InterfaceSlot[];
|
|
146
|
+
/**
|
|
147
|
+
* Interfaces that differ only by a number (Motor 1 pads … Motor 4 pads), alike in kind, protocol and state of
|
|
148
|
+
* linking, as one card: "Motor pads ×4", its pins and its links those of every member. Three or more.
|
|
149
|
+
*/
|
|
150
|
+
export declare function groupSlots(slots: InterfaceSlot[]): InterfaceSlot[];
|
|
151
|
+
/** The Interfaces section's header: "6 linked · 1 open", counting each interface of a grouped card. */
|
|
152
|
+
export declare function slotSummary(slots: InterfaceSlot[]): {
|
|
153
|
+
total: number;
|
|
154
|
+
linked: number;
|
|
155
|
+
open: number;
|
|
156
|
+
used: number;
|
|
157
|
+
text: string;
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* The viewer's own findings as host findings: UHD's checks of the level and
|
|
161
|
+
* the bundle producer's, each with the canonical ids it is about (links
|
|
162
|
+
* without their `link:` prefix, re-based onto the root).
|
|
163
|
+
*/
|
|
164
|
+
export declare function checkFindings(checks: {
|
|
165
|
+
id: string;
|
|
166
|
+
rule: string;
|
|
167
|
+
severity: "error" | "warning" | "info";
|
|
168
|
+
message: string;
|
|
169
|
+
refs: string[];
|
|
170
|
+
scope?: string;
|
|
171
|
+
}[], producer?: {
|
|
172
|
+
code: string;
|
|
173
|
+
severity: "error" | "warning" | "info";
|
|
174
|
+
message: string;
|
|
175
|
+
entity?: {
|
|
176
|
+
kind: string;
|
|
177
|
+
id: string;
|
|
178
|
+
};
|
|
179
|
+
}[]): HostFinding[];
|
|
180
|
+
/** Names as written, by node id on a level (the view model's labels are upper case), and its links' names by id. */
|
|
181
|
+
export declare function levelNames(vm: ViewModel, level: ModuleDef | undefined, lookup: (id: string) => ModuleDef | undefined): {
|
|
182
|
+
names: Map<string, string>;
|
|
183
|
+
linkNames: Map<string, string>;
|
|
184
|
+
};
|