@flighthq/node 0.3.0 → 0.3.1-next.1041.35b950c

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 (60) hide show
  1. package/dist/boundsRectangle.d.ts +3 -3
  2. package/dist/boundsRectangle.d.ts.map +1 -1
  3. package/dist/boundsRectangle.js +63 -11
  4. package/dist/boundsRectangle.js.map +1 -1
  5. package/dist/contract.d.ts +1 -0
  6. package/dist/contract.d.ts.map +1 -1
  7. package/dist/contract.js +1 -0
  8. package/dist/contract.js.map +1 -1
  9. package/dist/enableNodeGuards.d.ts +4 -0
  10. package/dist/enableNodeGuards.d.ts.map +1 -0
  11. package/dist/enableNodeGuards.js +29 -0
  12. package/dist/enableNodeGuards.js.map +1 -0
  13. package/dist/hasAppearance.d.ts +2 -1
  14. package/dist/hasAppearance.d.ts.map +1 -1
  15. package/dist/hasAppearance.js +10 -0
  16. package/dist/hasAppearance.js.map +1 -1
  17. package/dist/hasBoundsRectangle.d.ts.map +1 -1
  18. package/dist/hasBoundsRectangle.js +4 -0
  19. package/dist/hasBoundsRectangle.js.map +1 -1
  20. package/dist/hasTransform3d.d.ts.map +1 -1
  21. package/dist/hasTransform3d.js +11 -4
  22. package/dist/hasTransform3d.js.map +1 -1
  23. package/dist/hierarchy.d.ts +15 -7
  24. package/dist/hierarchy.d.ts.map +1 -1
  25. package/dist/hierarchy.js +46 -25
  26. package/dist/hierarchy.js.map +1 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +1 -1
  30. package/dist/index.js.map +1 -1
  31. package/dist/nodeColorAdjustment.d.ts.map +1 -1
  32. package/dist/nodeColorAdjustment.js +1 -7
  33. package/dist/nodeColorAdjustment.js.map +1 -1
  34. package/dist/nodeOrderList.d.ts.map +1 -1
  35. package/dist/nodeOrderList.js +9 -2
  36. package/dist/nodeOrderList.js.map +1 -1
  37. package/dist/nodeTransform2d.d.ts.map +1 -1
  38. package/dist/nodeTransform2d.js +1 -1
  39. package/dist/nodeTransform2d.js.map +1 -1
  40. package/dist/revision.d.ts +2 -1
  41. package/dist/revision.d.ts.map +1 -1
  42. package/dist/revision.js +9 -4
  43. package/dist/revision.js.map +1 -1
  44. package/dist/stageFit.d.ts.map +1 -1
  45. package/dist/stageFit.js +8 -2
  46. package/dist/stageFit.js.map +1 -1
  47. package/package.json +9 -7
  48. package/src/boundsRectangle.test.ts +320 -7
  49. package/src/enableNodeGuards.test.ts +78 -0
  50. package/src/hasAppearance.test.ts +33 -3
  51. package/src/hasTransform2d.test.ts +6 -0
  52. package/src/hasTransform3d.test.ts +40 -8
  53. package/src/hierarchy.test.ts +223 -3
  54. package/src/node.test.ts +11 -1
  55. package/src/nodeColorAdjustment.test.ts +11 -0
  56. package/src/nodeOrderList.test.ts +84 -18
  57. package/src/nodeTransform2d.test.ts +45 -0
  58. package/src/revision.test.ts +26 -0
  59. package/src/stageFit.test.ts +56 -1
  60. package/src/traversal.test.ts +32 -2
@@ -1,6 +1,7 @@
1
1
  import { createNode, getNodeRuntime } from '@flighthq/node/contract';
2
2
  import type { Node, NodeRuntime } from '@flighthq/types/contract';
3
3
 
4
+ import { addNodeChild } from './hierarchy';
4
5
  import {
5
6
  computeNodeWorldTransformRevision,
6
7
  getNodeAppearanceRevision,
@@ -41,6 +42,7 @@ describe('computeNodeWorldTransformRevision', () => {
41
42
  computeNodeWorldTransformRevision(runtime);
42
43
  expect(runtime.worldTransformUsingLocalTransformId).toBe(3);
43
44
  expect(runtime.worldTransformUsingParentTransformId).toBe(0);
45
+ expect(runtime.worldTransformId).not.toBe(0);
44
46
  });
45
47
 
46
48
  it('incorporates parent worldTransformId when provided', () => {
@@ -51,6 +53,17 @@ describe('computeNodeWorldTransformRevision', () => {
51
53
  computeNodeWorldTransformRevision(runtime, parentRuntime);
52
54
  expect(runtime.worldTransformUsingParentTransformId).toBe(7);
53
55
  });
56
+
57
+ it('assigns the next monotonic world revision on every recompute', () => {
58
+ const runtime = getEntityRuntime(node);
59
+ computeNodeWorldTransformRevision(runtime);
60
+ const first = runtime.worldTransformId;
61
+
62
+ computeNodeWorldTransformRevision(runtime);
63
+
64
+ const next = (first + 1) >>> 0;
65
+ expect(runtime.worldTransformId).toBe(next === 0 ? 1 : next);
66
+ });
54
67
  });
55
68
 
56
69
  describe('getNodeAppearanceRevision', () => {
@@ -246,6 +259,19 @@ describe('invalidateNodeWorldBounds', () => {
246
259
  expect(runtime.worldBoundsUsingWorldTransformId).toBe(-1);
247
260
  expect(runtime.worldBoundsUsingLocalBoundsId).toBe(-1);
248
261
  });
262
+
263
+ it('invalidates every ancestor whose aggregate includes the target', () => {
264
+ const parent = createTestNode();
265
+ addNodeChild(parent, node);
266
+ const parentRuntime = getEntityRuntime(parent);
267
+ parentRuntime.worldBoundsUsingWorldTransformId = 1;
268
+ parentRuntime.worldBoundsUsingLocalBoundsId = 1;
269
+
270
+ invalidateNodeWorldBounds(node);
271
+
272
+ expect(parentRuntime.worldBoundsUsingWorldTransformId).toBe(-1);
273
+ expect(parentRuntime.worldBoundsUsingLocalBoundsId).toBe(-1);
274
+ });
249
275
  });
250
276
 
251
277
  type TestNode = Node;
@@ -18,10 +18,12 @@ import {
18
18
 
19
19
  const TestNodeKind = 'TestNode';
20
20
 
21
- function makeNodeWithBounds(width: number, height: number) {
21
+ function makeNodeWithBounds(width: number, height: number, x = 0, y = 0) {
22
22
  const node = createNode(TestNodeKind);
23
23
  const runtime = getNodeRuntime(node) as unknown as HasBoundsRectangleRuntime;
24
24
  runtime.computeLocalBoundsRectangle = (out) => {
25
+ out.x = x;
26
+ out.y = y;
25
27
  out.width = width;
26
28
  out.height = height;
27
29
  };
@@ -137,6 +139,18 @@ describe('computeScene2DFitTransform', () => {
137
139
  expect(m.d).toBe(1);
138
140
  });
139
141
 
142
+ it('sets identity when only the content width is zero', () => {
143
+ const m = createMatrix(2, 3, 4, 5, 6, 7);
144
+ computeScene2DFitTransform(m, fit({ root: makeNodeWithBounds(0, 50), scaleMode: 'exactfit' }), 800, 600);
145
+ expect(m).toMatchObject({ a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 });
146
+ });
147
+
148
+ it('sets identity when only the content height is zero', () => {
149
+ const m = createMatrix(2, 3, 4, 5, 6, 7);
150
+ computeScene2DFitTransform(m, fit({ root: makeNodeWithBounds(100, 0), scaleMode: 'exactfit' }), 800, 600);
151
+ expect(m).toMatchObject({ a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 });
152
+ });
153
+
140
154
  it('noscale with topleft: identity scale at origin', () => {
141
155
  const m = createMatrix();
142
156
  computeScene2DFitTransform(
@@ -226,4 +240,45 @@ describe('computeScene2DFitTransform', () => {
226
240
  expect(m.b).toBe(0);
227
241
  expect(m.c).toBe(0);
228
242
  });
243
+
244
+ it('maps a nonzero content-bounds origin to the selected alignment', () => {
245
+ const m = createMatrix();
246
+ computeScene2DFitTransform(
247
+ m,
248
+ fit({ align: 'topleft', root: makeNodeWithBounds(100, 50, 10, -20), scaleMode: 'exactfit' }),
249
+ 200,
250
+ 100,
251
+ );
252
+
253
+ expect(m.a).toBe(2);
254
+ expect(m.d).toBe(2);
255
+ expect(m.tx).toBe(-20);
256
+ expect(m.ty).toBe(40);
257
+ });
258
+
259
+ it('uses scaled width before subtracting a nonzero origin on a centered horizontal axis', () => {
260
+ const m = createMatrix();
261
+ computeScene2DFitTransform(
262
+ m,
263
+ fit({ align: 'top', root: makeNodeWithBounds(100, 50, 10, -20), scaleMode: 'exactfit' }),
264
+ 200,
265
+ 100,
266
+ );
267
+
268
+ expect(m.tx).toBe(-20);
269
+ expect(m.ty).toBe(40);
270
+ });
271
+
272
+ it('uses scaled height before subtracting a nonzero origin on a centered vertical axis', () => {
273
+ const m = createMatrix();
274
+ computeScene2DFitTransform(
275
+ m,
276
+ fit({ align: 'left', root: makeNodeWithBounds(100, 50, 10, -20), scaleMode: 'exactfit' }),
277
+ 200,
278
+ 100,
279
+ );
280
+
281
+ expect(m.tx).toBe(-20);
282
+ expect(m.ty).toBe(40);
283
+ });
229
284
  });
@@ -1,8 +1,8 @@
1
- import type { Node, NodeTraits } from '@flighthq/types/contract';
1
+ import type { Node, NodeRuntime, NodeTraits } from '@flighthq/types/contract';
2
2
  import { NodeKind } from '@flighthq/types/contract';
3
3
 
4
4
  import { addNodeChild } from './hierarchy';
5
- import { createNode } from './node';
5
+ import { createNode, getNodeRuntime } from './node';
6
6
  import {
7
7
  findNode,
8
8
  findNodeByName,
@@ -190,6 +190,18 @@ describe('getNodeNextSibling', () => {
190
190
  it('returns the next sibling', () => {
191
191
  expect(getNodeNextSibling(childA)).toBe(childB);
192
192
  });
193
+
194
+ it('returns null for a stale parent whose child list is absent', () => {
195
+ (getNodeRuntime(root) as NodeRuntime).children = null;
196
+
197
+ expect(getNodeNextSibling(childA)).toBeNull();
198
+ });
199
+
200
+ it('returns null for a stale parent whose nonempty child list omits the source', () => {
201
+ (getNodeRuntime(root) as NodeRuntime).children = [childB];
202
+
203
+ expect(getNodeNextSibling(childA)).toBeNull();
204
+ });
193
205
  });
194
206
 
195
207
  describe('getNodePreviousSibling', () => {
@@ -204,6 +216,12 @@ describe('getNodePreviousSibling', () => {
204
216
  it('returns the previous sibling', () => {
205
217
  expect(getNodePreviousSibling(childB)).toBe(childA);
206
218
  });
219
+
220
+ it('returns null for a stale parent whose child list is absent', () => {
221
+ (getNodeRuntime(root) as NodeRuntime).children = null;
222
+
223
+ expect(getNodePreviousSibling(childB)).toBeNull();
224
+ });
207
225
  });
208
226
 
209
227
  describe('walkNodeDescendants', () => {
@@ -242,4 +260,16 @@ describe('walkNodeDescendants', () => {
242
260
  expect(visited).not.toContain(grandchild);
243
261
  expect(visited).not.toContain(childB);
244
262
  });
263
+
264
+ it('propagates an early stop from a nested descendant', () => {
265
+ const visited: Node<NodeTraits>[] = [];
266
+
267
+ const result = walkNodeDescendants(root, (node) => {
268
+ visited.push(node);
269
+ return node !== grandchild;
270
+ });
271
+
272
+ expect(result).toBe(false);
273
+ expect(visited).toEqual([childA, grandchild]);
274
+ });
245
275
  });