@chrisdudek/yg 5.3.0 → 5.4.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/dist/bin.js +1985 -397
- package/dist/structure.d.ts +7 -0
- package/dist/structure.js +10 -5
- package/dist/templates/portal/js/bootstrap.js +206 -0
- package/dist/templates/portal/js/consumer.js +128 -0
- package/dist/templates/portal/js/dispatch.js +181 -0
- package/dist/templates/portal/js/export.js +151 -0
- package/dist/templates/portal/js/glossary.js +72 -0
- package/dist/templates/portal/js/namespace.js +60 -0
- package/dist/templates/portal/js/palette-overlay.js +176 -0
- package/dist/templates/portal/js/palette.js +133 -0
- package/dist/templates/portal/js/router.js +169 -0
- package/dist/templates/portal/js/shell.js +264 -0
- package/dist/templates/portal/js/state-model.js +142 -0
- package/dist/templates/portal/js/tree.js +190 -0
- package/dist/templates/portal/js/views/coverage-view.js +247 -0
- package/dist/templates/portal/js/views/flows-view.js +204 -0
- package/dist/templates/portal/js/views/overview-view.js +167 -0
- package/dist/templates/portal/js/views/panel-aspect.js +141 -0
- package/dist/templates/portal/js/views/panel-view.js +314 -0
- package/dist/templates/portal/js/views/relations-matrix.js +185 -0
- package/dist/templates/portal/js/views/relations-view.js +185 -0
- package/dist/templates/portal/js/views/rulebook-view.js +174 -0
- package/dist/templates/portal/js/views/start-view.js +287 -0
- package/dist/templates/portal/js/views/suppressions-view.js +187 -0
- package/dist/templates/portal/js/views/tree-view.js +68 -0
- package/dist/templates/portal/js/views/types-view.js +154 -0
- package/dist/templates/portal/vendor/d3-hierarchy.js +350 -0
- package/package.json +5 -2
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* V6 Type Model — the architecture vocabulary as CAPABILITY DISCOVERY.
|
|
3
|
+
*
|
|
4
|
+
* "What Yggdrasil can enforce here, and how", seen live on your repo (§3.5/§3a V6). Every node
|
|
5
|
+
* TYPE the architecture defines, as a card: its description, whether it classifies files or is
|
|
6
|
+
* organizational, its strict / log flags, its live node-count, what it may nest under (parents),
|
|
7
|
+
* what it may depend on (the allowed-relations matrix row), and the rules it carries by default.
|
|
8
|
+
*
|
|
9
|
+
* This surface renders no verdict state — it is the architecture's grammar, not a pass/fail of
|
|
10
|
+
* any code — so it deliberately paints no green: the relation hues are relation TYPES, never a
|
|
11
|
+
* verdict, and a node-count is a fact, not an approval. The honest-state model still owns every
|
|
12
|
+
* verdict color elsewhere; this view simply never claims one.
|
|
13
|
+
*
|
|
14
|
+
* Transitions (§3a V6): a default-rule chip → V5 (that rule in the rulebook); "nodes of this
|
|
15
|
+
* type" → V3 (the structure tree). Browser globals only; reads the resolved PortalData; no Node.
|
|
16
|
+
*/
|
|
17
|
+
(function () {
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
var Yg = (window.YgPortal = window.YgPortal || {});
|
|
21
|
+
var dom = Yg.dom;
|
|
22
|
+
Yg.views = Yg.views || {};
|
|
23
|
+
|
|
24
|
+
// Relation type → a stable, colorblind-safe hue (a relation TYPE marker, never a verdict state).
|
|
25
|
+
var REL_COLOR = {
|
|
26
|
+
calls: '#0d74ce',
|
|
27
|
+
uses: '#208368',
|
|
28
|
+
extends: '#9a6700',
|
|
29
|
+
implements: '#8e4ec6',
|
|
30
|
+
emits: '#d6409f',
|
|
31
|
+
listens: '#d6409f',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
/** The "may depend on" line: each allowed relation type with its permitted target types. */
|
|
35
|
+
function dependsOn(allowed) {
|
|
36
|
+
var wrap = dom.el('div', 'ty-rels');
|
|
37
|
+
var any = false;
|
|
38
|
+
for (var rel in allowed) {
|
|
39
|
+
if (!Object.prototype.hasOwnProperty.call(allowed, rel)) continue;
|
|
40
|
+
var targets = (allowed[rel] || []).filter(function (t) {
|
|
41
|
+
return t !== 'deny' && t !== 'default';
|
|
42
|
+
});
|
|
43
|
+
if (!targets.length) continue;
|
|
44
|
+
any = true;
|
|
45
|
+
var group = dom.el('span', 'ty-relgroup');
|
|
46
|
+
var label = dom.el('b', 'ty-reltype');
|
|
47
|
+
label.style.color = REL_COLOR[rel] || 'var(--text-secondary)';
|
|
48
|
+
label.textContent = rel;
|
|
49
|
+
group.appendChild(label);
|
|
50
|
+
group.appendChild(dom.el('span', 'ty-reltargets', ' ' + targets.join(' · ')));
|
|
51
|
+
wrap.appendChild(group);
|
|
52
|
+
}
|
|
53
|
+
if (!any) wrap.appendChild(dom.el('span', 'ty-rel-none', '— structural parent only (no code dependency permitted)'));
|
|
54
|
+
return wrap;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** The default-rules line: each rule a clickable chip routing to its detail in V5. */
|
|
58
|
+
function defaultRules(aspects, nav) {
|
|
59
|
+
if (!aspects || !aspects.length) return dom.el('span', 'ty-rel-none', '—');
|
|
60
|
+
var wrap = dom.el('span', 'ty-asps');
|
|
61
|
+
for (var i = 0; i < aspects.length; i += 1) {
|
|
62
|
+
var chip = dom.el('button', 'ty-asp mono');
|
|
63
|
+
chip.type = 'button';
|
|
64
|
+
chip.textContent = aspects[i];
|
|
65
|
+
chip.addEventListener(
|
|
66
|
+
'click',
|
|
67
|
+
(function (id) {
|
|
68
|
+
return function () {
|
|
69
|
+
nav({ view: 'rulebook', aspect: id });
|
|
70
|
+
};
|
|
71
|
+
})(aspects[i]),
|
|
72
|
+
);
|
|
73
|
+
wrap.appendChild(chip);
|
|
74
|
+
}
|
|
75
|
+
return wrap;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function typeCard(type, nav) {
|
|
79
|
+
var card = dom.el('div', 'ty-card');
|
|
80
|
+
|
|
81
|
+
var head = dom.el('div', 'ty-head');
|
|
82
|
+
head.appendChild(dom.el('b', 'mono ty-name', type.id));
|
|
83
|
+
var classifying = (type.parents && type.parents.length >= 0) && hasRelationsOrAspects(type);
|
|
84
|
+
head.appendChild(dom.el('span', 'ty-badge ' + (type.nodeCount >= 0 && classifying ? 'ty-badge-cls' : 'ty-badge-org'), classifying ? 'classifying' : 'organizational'));
|
|
85
|
+
if (type.strict) head.appendChild(dom.el('span', 'ty-badge ty-badge-strict', 'strict'));
|
|
86
|
+
if (type.logRequired) head.appendChild(dom.el('span', 'ty-badge ty-badge-log', 'log'));
|
|
87
|
+
|
|
88
|
+
var count = dom.el('button', 'ty-count');
|
|
89
|
+
count.type = 'button';
|
|
90
|
+
count.textContent = type.nodeCount + (type.nodeCount === 1 ? ' node' : ' nodes');
|
|
91
|
+
count.addEventListener('click', function () {
|
|
92
|
+
nav({ view: 'tree', type: type.id });
|
|
93
|
+
});
|
|
94
|
+
head.appendChild(count);
|
|
95
|
+
card.appendChild(head);
|
|
96
|
+
|
|
97
|
+
if (type.description) card.appendChild(dom.el('div', 'ty-desc', type.description));
|
|
98
|
+
|
|
99
|
+
var kv = dom.el('dl', 'ty-kv');
|
|
100
|
+
kv.appendChild(dom.el('dt', null, 'nests under'));
|
|
101
|
+
var parents = dom.el('dd', 'mono', (type.parents && type.parents.length) ? type.parents.join(' · ') : '— (top level)');
|
|
102
|
+
kv.appendChild(parents);
|
|
103
|
+
|
|
104
|
+
kv.appendChild(dom.el('dt', null, 'may depend on'));
|
|
105
|
+
var dd = dom.el('dd');
|
|
106
|
+
dd.appendChild(dependsOn(type.allowedRelations || {}));
|
|
107
|
+
kv.appendChild(dd);
|
|
108
|
+
|
|
109
|
+
kv.appendChild(dom.el('dt', null, 'default rules'));
|
|
110
|
+
var ddR = dom.el('dd');
|
|
111
|
+
ddR.appendChild(defaultRules(type.defaultAspects, nav));
|
|
112
|
+
kv.appendChild(ddR);
|
|
113
|
+
card.appendChild(kv);
|
|
114
|
+
|
|
115
|
+
return card;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** A type that defines relations or default aspects classifies files; otherwise organizational. */
|
|
119
|
+
function hasRelationsOrAspects(type) {
|
|
120
|
+
var rels = type.allowedRelations || {};
|
|
121
|
+
for (var rel in rels) {
|
|
122
|
+
if (!Object.prototype.hasOwnProperty.call(rels, rel)) continue;
|
|
123
|
+
var targets = (rels[rel] || []).filter(function (t) {
|
|
124
|
+
return t !== 'deny' && t !== 'default';
|
|
125
|
+
});
|
|
126
|
+
if (targets.length) return true;
|
|
127
|
+
}
|
|
128
|
+
return (type.defaultAspects && type.defaultAspects.length > 0) || type.strict === true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function summary(types) {
|
|
132
|
+
var strict = 0;
|
|
133
|
+
var logged = 0;
|
|
134
|
+
for (var i = 0; i < types.length; i += 1) {
|
|
135
|
+
if (types[i].strict) strict += 1;
|
|
136
|
+
if (types[i].logRequired) logged += 1;
|
|
137
|
+
}
|
|
138
|
+
return types.length + ' types · ' + strict + ' strict (every matching file must be captured) · ' + logged + ' log-gated (changes must record a reason)';
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
Yg.views.types = function (stage, route, data, ctx) {
|
|
142
|
+
var nav = ctx && ctx.navigate ? ctx.navigate : function () {};
|
|
143
|
+
var types = (data.types || []).slice();
|
|
144
|
+
|
|
145
|
+
stage.appendChild(dom.el('p', 'view-lead', 'Every kind of component the architecture defines — what it may depend on, and the rules it carries by default. This is what is possible and how, seen live on your repo. It is the grammar, not a verdict: nothing here is green or red.'));
|
|
146
|
+
stage.appendChild(dom.el('div', 'rb-sub', summary(types)));
|
|
147
|
+
|
|
148
|
+
var grid = dom.el('div', 'ty-grid');
|
|
149
|
+
for (var i = 0; i < types.length; i += 1) {
|
|
150
|
+
grid.appendChild(typeCard(types[i], nav));
|
|
151
|
+
}
|
|
152
|
+
stage.appendChild(grid);
|
|
153
|
+
};
|
|
154
|
+
})();
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* d3-hierarchy (vendored subset) — ISC License, Copyright 2010-2021 Mike Bostock.
|
|
3
|
+
* https://github.com/d3/d3-hierarchy
|
|
4
|
+
*
|
|
5
|
+
* Vendored into the Yggdrasil portal as a committed, offline static asset: no runtime
|
|
6
|
+
* npm dependency, no CDN, no network. This is the layout MATH only — hierarchy() builds
|
|
7
|
+
* a node tree from data, and tree() runs the Reingold-Tilford / Buchheim tidy-tree
|
|
8
|
+
* algorithm to assign (x, y) coordinates. All drawing is the portal's own code; this lib
|
|
9
|
+
* supplies coordinates and nothing else. It performs no I/O of any kind.
|
|
10
|
+
*
|
|
11
|
+
* Exposed as the global `d3` (a minimal namespace with `hierarchy` and `tree`), the same
|
|
12
|
+
* surface the portal bootstrap consumes, so swapping in the full upstream package later is
|
|
13
|
+
* a drop-in. Pared to the functions the portal uses; semantics match upstream d3-hierarchy.
|
|
14
|
+
*/
|
|
15
|
+
(function (global) {
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
// ── hierarchy ────────────────────────────────────────────────────────────────
|
|
19
|
+
function Node(data) {
|
|
20
|
+
this.data = data;
|
|
21
|
+
this.depth = 0;
|
|
22
|
+
this.height = 0;
|
|
23
|
+
this.parent = null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
Node.prototype = {
|
|
27
|
+
constructor: Node,
|
|
28
|
+
each: function (callback) {
|
|
29
|
+
let index = -1;
|
|
30
|
+
for (const node of this) callback(node, ++index, this);
|
|
31
|
+
return this;
|
|
32
|
+
},
|
|
33
|
+
eachBefore: function (callback) {
|
|
34
|
+
const nodes = [this];
|
|
35
|
+
let node;
|
|
36
|
+
let index = -1;
|
|
37
|
+
while ((node = nodes.pop())) {
|
|
38
|
+
callback(node, ++index, this);
|
|
39
|
+
const children = node.children;
|
|
40
|
+
if (children) for (let i = children.length - 1; i >= 0; --i) nodes.push(children[i]);
|
|
41
|
+
}
|
|
42
|
+
return this;
|
|
43
|
+
},
|
|
44
|
+
descendants: function () {
|
|
45
|
+
const out = [];
|
|
46
|
+
this.each((n) => out.push(n));
|
|
47
|
+
return out;
|
|
48
|
+
},
|
|
49
|
+
links: function () {
|
|
50
|
+
const root = this;
|
|
51
|
+
const links = [];
|
|
52
|
+
root.each((node) => {
|
|
53
|
+
if (node !== root) links.push({ source: node.parent, target: node });
|
|
54
|
+
});
|
|
55
|
+
return links;
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
Node.prototype[Symbol.iterator] = function* () {
|
|
60
|
+
let node = this;
|
|
61
|
+
let current = [node];
|
|
62
|
+
let next = [];
|
|
63
|
+
do {
|
|
64
|
+
next = [];
|
|
65
|
+
for (node of current) {
|
|
66
|
+
yield node;
|
|
67
|
+
const children = node.children;
|
|
68
|
+
if (children) for (const child of children) next.push(child);
|
|
69
|
+
}
|
|
70
|
+
current = next;
|
|
71
|
+
} while (next.length);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
function computeHeight(node) {
|
|
75
|
+
let height = 0;
|
|
76
|
+
do {
|
|
77
|
+
node.height = height;
|
|
78
|
+
node = node.parent;
|
|
79
|
+
} while (node && node.height < ++height);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function hierarchy(data, children) {
|
|
83
|
+
if (data instanceof Map) {
|
|
84
|
+
data = [undefined, data];
|
|
85
|
+
if (children === undefined) children = mapChildren;
|
|
86
|
+
} else if (children === undefined) {
|
|
87
|
+
children = objectChildren;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const root = new Node(data);
|
|
91
|
+
const nodes = [root];
|
|
92
|
+
let node;
|
|
93
|
+
let child;
|
|
94
|
+
let childs;
|
|
95
|
+
let i;
|
|
96
|
+
let n;
|
|
97
|
+
|
|
98
|
+
while ((node = nodes.pop())) {
|
|
99
|
+
if ((childs = children(node.data)) && (n = (childs = Array.from(childs)).length)) {
|
|
100
|
+
node.children = childs;
|
|
101
|
+
for (i = n - 1; i >= 0; --i) {
|
|
102
|
+
nodes.push((child = childs[i] = new Node(childs[i])));
|
|
103
|
+
child.parent = node;
|
|
104
|
+
child.depth = node.depth + 1;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return root.eachBefore(computeHeight);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function objectChildren(d) {
|
|
113
|
+
return d.children;
|
|
114
|
+
}
|
|
115
|
+
function mapChildren(d) {
|
|
116
|
+
return Array.isArray(d) ? d[1] : null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ── tree (tidy tree — Buchheim/Walker) ─────────────────────────────────────────
|
|
120
|
+
function defaultSeparation(a, b) {
|
|
121
|
+
return a.parent === b.parent ? 1 : 2;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function nextLeft(v) {
|
|
125
|
+
const children = v.children;
|
|
126
|
+
return children ? children[0] : v.t;
|
|
127
|
+
}
|
|
128
|
+
function nextRight(v) {
|
|
129
|
+
const children = v.children;
|
|
130
|
+
return children ? children[children.length - 1] : v.t;
|
|
131
|
+
}
|
|
132
|
+
function moveSubtree(wm, wp, shift) {
|
|
133
|
+
const change = shift / (wp.i - wm.i);
|
|
134
|
+
wp.c -= change;
|
|
135
|
+
wp.s += shift;
|
|
136
|
+
wm.c += change;
|
|
137
|
+
wp.z += shift;
|
|
138
|
+
wp.m += shift;
|
|
139
|
+
}
|
|
140
|
+
function executeShifts(v) {
|
|
141
|
+
let shift = 0;
|
|
142
|
+
let change = 0;
|
|
143
|
+
const children = v.children;
|
|
144
|
+
let i = children.length;
|
|
145
|
+
let w;
|
|
146
|
+
while (--i >= 0) {
|
|
147
|
+
w = children[i];
|
|
148
|
+
w.z += shift;
|
|
149
|
+
w.m += shift;
|
|
150
|
+
shift += w.s + (change += w.c);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function nextAncestor(vim, v, ancestor) {
|
|
154
|
+
return vim.a.parent === v.parent ? vim.a : ancestor;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function TreeNode(node, i) {
|
|
158
|
+
this._ = node;
|
|
159
|
+
this.parent = null;
|
|
160
|
+
this.children = null;
|
|
161
|
+
this.A = null; // default ancestor
|
|
162
|
+
this.a = this; // ancestor
|
|
163
|
+
this.z = 0; // prelim
|
|
164
|
+
this.m = 0; // mod
|
|
165
|
+
this.c = 0; // change
|
|
166
|
+
this.s = 0; // shift
|
|
167
|
+
this.t = null; // thread
|
|
168
|
+
this.i = i; // number
|
|
169
|
+
}
|
|
170
|
+
TreeNode.prototype = Object.create(Node.prototype);
|
|
171
|
+
|
|
172
|
+
function treeRoot(root) {
|
|
173
|
+
const tree = new TreeNode(root, 0);
|
|
174
|
+
let node;
|
|
175
|
+
const nodes = [tree];
|
|
176
|
+
let child;
|
|
177
|
+
let children;
|
|
178
|
+
let i;
|
|
179
|
+
let n;
|
|
180
|
+
|
|
181
|
+
while ((node = nodes.pop())) {
|
|
182
|
+
if ((children = node._.children)) {
|
|
183
|
+
node.children = new Array((n = children.length));
|
|
184
|
+
for (i = n - 1; i >= 0; --i) {
|
|
185
|
+
nodes.push((child = node.children[i] = new TreeNode(children[i], i)));
|
|
186
|
+
child.parent = node;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
(tree.parent = new TreeNode(null, 0)).children = [tree];
|
|
192
|
+
return tree;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function tree() {
|
|
196
|
+
let separation = defaultSeparation;
|
|
197
|
+
let dx = 1;
|
|
198
|
+
let dy = 1;
|
|
199
|
+
let nodeSize = null;
|
|
200
|
+
|
|
201
|
+
function layout(root) {
|
|
202
|
+
const t = treeRoot(root);
|
|
203
|
+
|
|
204
|
+
t.eachAfter(firstWalk);
|
|
205
|
+
t.parent.m = -t.z;
|
|
206
|
+
t.eachBefore(secondWalk);
|
|
207
|
+
|
|
208
|
+
if (nodeSize) root.eachBefore(sizeNode);
|
|
209
|
+
else {
|
|
210
|
+
let left = root;
|
|
211
|
+
let right = root;
|
|
212
|
+
let bottom = root;
|
|
213
|
+
root.eachBefore((node) => {
|
|
214
|
+
if (node.x < left.x) left = node;
|
|
215
|
+
if (node.x > right.x) right = node;
|
|
216
|
+
if (node.depth > bottom.depth) bottom = node;
|
|
217
|
+
});
|
|
218
|
+
const s = left === right ? 1 : separation(left, right) / 2;
|
|
219
|
+
const tx = s - left.x;
|
|
220
|
+
const kx = dx / (right.x + s + tx);
|
|
221
|
+
const ky = dy / (bottom.depth || 1);
|
|
222
|
+
root.eachBefore((node) => {
|
|
223
|
+
node.x = (node.x + tx) * kx;
|
|
224
|
+
node.y = node.depth * ky;
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return root;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function firstWalk(v) {
|
|
232
|
+
const children = v.children;
|
|
233
|
+
const siblings = v.parent.children;
|
|
234
|
+
const w = v.i ? siblings[v.i - 1] : null;
|
|
235
|
+
if (children) {
|
|
236
|
+
executeShifts(v);
|
|
237
|
+
const midpoint = (children[0].z + children[children.length - 1].z) / 2;
|
|
238
|
+
if (w) {
|
|
239
|
+
v.z = w.z + separation(v._, w._);
|
|
240
|
+
v.m = v.z - midpoint;
|
|
241
|
+
} else {
|
|
242
|
+
v.z = midpoint;
|
|
243
|
+
}
|
|
244
|
+
} else if (w) {
|
|
245
|
+
v.z = w.z + separation(v._, w._);
|
|
246
|
+
}
|
|
247
|
+
v.parent.A = apportion(v, w, v.parent.A || siblings[0]);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function secondWalk(v) {
|
|
251
|
+
v._.x = v.z + v.parent.m;
|
|
252
|
+
v.m += v.parent.m;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function apportion(v, w, ancestor) {
|
|
256
|
+
if (w) {
|
|
257
|
+
let vip = v;
|
|
258
|
+
let vop = v;
|
|
259
|
+
let vim = w;
|
|
260
|
+
let vom = vip.parent.children[0];
|
|
261
|
+
let sip = vip.m;
|
|
262
|
+
let sop = vop.m;
|
|
263
|
+
let sim = vim.m;
|
|
264
|
+
let som = vom.m;
|
|
265
|
+
let shift;
|
|
266
|
+
while (((vim = nextRight(vim)), (vip = nextLeft(vip)), vim && vip)) {
|
|
267
|
+
vom = nextLeft(vom);
|
|
268
|
+
vop = nextRight(vop);
|
|
269
|
+
vop.a = v;
|
|
270
|
+
shift = vim.z + sim - vip.z - sip + separation(vim._, vip._);
|
|
271
|
+
if (shift > 0) {
|
|
272
|
+
moveSubtree(nextAncestor(vim, v, ancestor), v, shift);
|
|
273
|
+
sip += shift;
|
|
274
|
+
sop += shift;
|
|
275
|
+
}
|
|
276
|
+
sim += vim.m;
|
|
277
|
+
sip += vip.m;
|
|
278
|
+
som += vom.m;
|
|
279
|
+
sop += vop.m;
|
|
280
|
+
}
|
|
281
|
+
if (vim && !nextRight(vop)) {
|
|
282
|
+
vop.t = vim;
|
|
283
|
+
vop.m += sim - sop;
|
|
284
|
+
}
|
|
285
|
+
if (vip && !nextLeft(vom)) {
|
|
286
|
+
vom.t = vip;
|
|
287
|
+
vom.m += sip - som;
|
|
288
|
+
ancestor = v;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return ancestor;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function sizeNode(node) {
|
|
295
|
+
node.x *= dx;
|
|
296
|
+
node.y = node.depth * dy;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
layout.separation = function (x) {
|
|
300
|
+
if (arguments.length) {
|
|
301
|
+
separation = x;
|
|
302
|
+
return layout;
|
|
303
|
+
}
|
|
304
|
+
return separation;
|
|
305
|
+
};
|
|
306
|
+
layout.size = function (x) {
|
|
307
|
+
if (arguments.length) {
|
|
308
|
+
nodeSize = false;
|
|
309
|
+
dx = +x[0];
|
|
310
|
+
dy = +x[1];
|
|
311
|
+
return layout;
|
|
312
|
+
}
|
|
313
|
+
return nodeSize ? null : [dx, dy];
|
|
314
|
+
};
|
|
315
|
+
layout.nodeSize = function (x) {
|
|
316
|
+
if (arguments.length) {
|
|
317
|
+
nodeSize = true;
|
|
318
|
+
dx = +x[0];
|
|
319
|
+
dy = +x[1];
|
|
320
|
+
return layout;
|
|
321
|
+
}
|
|
322
|
+
return nodeSize ? [dx, dy] : null;
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
return layout;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// eachAfter is needed by the tree layout; add it to the prototype.
|
|
329
|
+
Node.prototype.eachAfter = function (callback) {
|
|
330
|
+
const nodes = [this];
|
|
331
|
+
const next = [];
|
|
332
|
+
let node;
|
|
333
|
+
let index = -1;
|
|
334
|
+
while ((node = nodes.pop())) {
|
|
335
|
+
next.push(node);
|
|
336
|
+
const children = node.children;
|
|
337
|
+
if (children) for (let i = 0, n = children.length; i < n; ++i) nodes.push(children[i]);
|
|
338
|
+
}
|
|
339
|
+
while ((node = next.pop())) callback(node, ++index, this);
|
|
340
|
+
return this;
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
const d3 = { hierarchy: hierarchy, tree: tree };
|
|
344
|
+
|
|
345
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
346
|
+
module.exports = d3;
|
|
347
|
+
} else {
|
|
348
|
+
global.d3 = Object.assign(global.d3 || {}, d3);
|
|
349
|
+
}
|
|
350
|
+
})(typeof globalThis !== 'undefined' ? globalThis : this);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrisdudek/yg",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.1",
|
|
4
4
|
"description": "Architecture rules your AI coding agent can't ignore. It gets the rules for a file before it edits, and every change is checked — by a free local script or an LLM reviewer — before it moves on. Works with Claude Code, Cursor, Copilot, Codex, Cline.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,10 +22,12 @@
|
|
|
22
22
|
"test:watch": "vitest",
|
|
23
23
|
"test:external": "vitest run --config vitest.external.config.ts",
|
|
24
24
|
"test:coverage": "vitest run --coverage",
|
|
25
|
+
"test:e2e:portal": "playwright test",
|
|
25
26
|
"lint": "eslint src/",
|
|
26
27
|
"lint:fix": "eslint src/ --fix",
|
|
27
28
|
"format": "prettier --write \"src/**/*.ts\"",
|
|
28
|
-
"typecheck": "tsc -p tsconfig.check.json"
|
|
29
|
+
"typecheck": "tsc -p tsconfig.check.json",
|
|
30
|
+
"typecheck:e2e": "tsc -p tests/portal-e2e/tsconfig.json"
|
|
29
31
|
},
|
|
30
32
|
"keywords": [
|
|
31
33
|
"yggdrasil",
|
|
@@ -82,6 +84,7 @@
|
|
|
82
84
|
},
|
|
83
85
|
"devDependencies": {
|
|
84
86
|
"@eslint/js": "^10.0.1",
|
|
87
|
+
"@playwright/test": "^1.61.1",
|
|
85
88
|
"@tree-sitter-grammars/tree-sitter-kotlin": "^1.1.0",
|
|
86
89
|
"@tree-sitter-grammars/tree-sitter-toml": "^0.7.0",
|
|
87
90
|
"@tree-sitter-grammars/tree-sitter-yaml": "^0.7.1",
|