@design-core/core 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (254) hide show
  1. package/.eslintrc.json +14 -7
  2. package/.github/workflows/DesignCoreQA.yml +3 -1
  3. package/README.md +11 -4
  4. package/TODO.md +19 -0
  5. package/core/core/core.js +49 -42
  6. package/core/designCore.js +61 -2
  7. package/core/dimensions/alignedDimension.js +142 -0
  8. package/core/dimensions/angularDimension.js +550 -0
  9. package/core/dimensions/baseCircularDimension.js +244 -0
  10. package/core/dimensions/baseDimension.js +558 -0
  11. package/core/dimensions/baseLinearDimension.js +371 -0
  12. package/core/dimensions/diametricDimension.js +82 -0
  13. package/core/dimensions/dimension.js +298 -0
  14. package/core/dimensions/linearDimension.js +29 -0
  15. package/core/dimensions/radialDimension.js +78 -0
  16. package/core/dimensions/rotatedDimension.js +167 -0
  17. package/core/entities/arc.js +314 -60
  18. package/core/entities/arctext.js +642 -0
  19. package/core/entities/basePolyline.js +553 -94
  20. package/core/entities/circle.js +181 -54
  21. package/core/entities/entity.js +154 -74
  22. package/core/entities/hatch.js +807 -0
  23. package/core/entities/insert.js +200 -39
  24. package/core/entities/line.js +196 -134
  25. package/core/entities/lwpolyline.js +21 -44
  26. package/core/entities/point.js +194 -29
  27. package/core/entities/polyline.js +54 -7
  28. package/core/entities/rectangle.js +43 -13
  29. package/core/entities/solid.js +43 -6
  30. package/core/entities/text.js +324 -181
  31. package/core/lib/boundingBox.js +73 -13
  32. package/core/lib/canvas.js +256 -65
  33. package/core/lib/clipboard.js +198 -0
  34. package/core/lib/colour.js +144 -0
  35. package/core/lib/colours.js +367 -301
  36. package/core/lib/commandLine.js +16 -28
  37. package/core/lib/commandManager.js +115 -58
  38. package/core/lib/constants.js +23 -0
  39. package/core/lib/dxf/dxf.js +249 -34
  40. package/core/lib/dxf/dxfFile.js +23 -38
  41. package/core/lib/dxf/dxfIterator.js +17 -5
  42. package/core/lib/dxf/dxfRead.js +23 -7
  43. package/core/lib/dxf/dxfWrite.js +39 -129
  44. package/core/lib/dxf/handleManager.js +97 -0
  45. package/core/lib/dxf/sections/blocks.js +16 -2
  46. package/core/lib/dxf/sections/entities.js +17 -3
  47. package/core/lib/dxf/sections/header.js +10 -1
  48. package/core/lib/dxf/sections/objects.js +36 -0
  49. package/core/lib/dxf/sections/section.js +43 -5
  50. package/core/lib/dxf/sections/tables.js +17 -3
  51. package/core/lib/entityManager.js +178 -0
  52. package/core/lib/fileio.js +14 -4
  53. package/core/lib/headers.js +229 -0
  54. package/core/lib/input.js +46 -0
  55. package/core/lib/inputManager.js +199 -194
  56. package/core/lib/intersect.js +341 -468
  57. package/core/lib/logging.js +25 -1
  58. package/core/lib/matrix.js +6 -8
  59. package/core/lib/mouse.js +24 -79
  60. package/core/lib/patterns.js +690 -0
  61. package/core/lib/promptOptions.js +133 -0
  62. package/core/lib/scene.js +71 -174
  63. package/core/lib/selectionManager.js +74 -48
  64. package/core/lib/selectionWindow.js +24 -10
  65. package/core/lib/settings.js +18 -11
  66. package/core/lib/snapping.js +129 -21
  67. package/core/lib/stateManager.js +288 -0
  68. package/core/lib/strings.js +57 -5
  69. package/core/lib/utils.js +95 -11
  70. package/core/objects/dictionary.js +43 -0
  71. package/core/objects/dictionaryManager.js +80 -0
  72. package/core/properties/dimType.js +117 -0
  73. package/core/properties/flags.js +66 -0
  74. package/core/properties/property.js +26 -0
  75. package/core/properties/propertyManager.js +65 -19
  76. package/core/tables/appId.js +31 -0
  77. package/core/tables/appIdManager.js +44 -0
  78. package/core/tables/block.js +323 -0
  79. package/core/tables/blockManager.js +48 -0
  80. package/core/tables/blockRecord.js +29 -0
  81. package/core/tables/blockRecordManager.js +37 -0
  82. package/core/tables/dimStyle.js +627 -0
  83. package/core/tables/dimStyleManager.js +187 -0
  84. package/core/tables/endblk.js +28 -0
  85. package/core/tables/layer.js +219 -0
  86. package/core/tables/layerManager.js +47 -0
  87. package/core/tables/ltype.js +85 -0
  88. package/core/tables/ltypeManager.js +65 -0
  89. package/core/tables/style.js +145 -0
  90. package/core/tables/styleManager.js +55 -0
  91. package/core/tables/styleManagerBase.js +110 -0
  92. package/core/tables/tableManagerBase.js +354 -0
  93. package/core/tables/ucs.js +28 -0
  94. package/core/tables/ucsManager.js +44 -0
  95. package/core/tables/view.js +28 -0
  96. package/core/tables/viewManager.js +44 -0
  97. package/core/tables/vport.js +70 -0
  98. package/core/tables/vportManager.js +65 -0
  99. package/core/tools/chamfer.js +343 -0
  100. package/core/tools/chamferFilletBase.js +162 -0
  101. package/core/tools/copy.js +68 -40
  102. package/core/tools/copybase.js +65 -0
  103. package/core/tools/copyclip.js +59 -0
  104. package/core/tools/cornerEntity.js +138 -0
  105. package/core/tools/cutclip.js +72 -0
  106. package/core/tools/distance.js +37 -9
  107. package/core/tools/erase.js +43 -13
  108. package/core/tools/explode.js +117 -0
  109. package/core/tools/extend.js +71 -32
  110. package/core/tools/fillet.js +336 -0
  111. package/core/tools/identify.js +33 -6
  112. package/core/tools/matchProp.js +106 -0
  113. package/core/tools/mirror.js +141 -0
  114. package/core/tools/move.js +65 -32
  115. package/core/tools/offset.js +321 -0
  116. package/core/tools/pan.js +54 -0
  117. package/core/tools/pasteclip.js +93 -0
  118. package/core/tools/purge.js +90 -0
  119. package/core/tools/rotate.js +105 -70
  120. package/core/tools/scale.js +166 -0
  121. package/core/tools/tool.js +14 -4
  122. package/core/tools/trim.js +71 -32
  123. package/core/tools/zoom.js +152 -0
  124. package/package.json +3 -305
  125. package/test/dimensions/alignedDimension.test.js +211 -0
  126. package/test/dimensions/angularDimension.test.js +243 -0
  127. package/test/dimensions/baseDimension.test.js +239 -0
  128. package/test/dimensions/diametricDimension.test.js +203 -0
  129. package/test/dimensions/dimension.test.js +102 -0
  130. package/test/dimensions/radialDimension.test.js +203 -0
  131. package/test/dimensions/rotatedDimension.test.js +224 -0
  132. package/test/entities/arc.test.js +463 -41
  133. package/test/entities/arctext.test.js +329 -0
  134. package/test/entities/basePolyline.test.js +459 -10
  135. package/test/entities/circle.test.js +312 -7
  136. package/test/entities/entity.test.js +28 -9
  137. package/test/entities/hatch.test.js +606 -0
  138. package/test/entities/insert.test.js +90 -0
  139. package/test/entities/line.test.js +182 -6
  140. package/test/entities/point.test.js +375 -37
  141. package/test/entities/solid.test.js +156 -0
  142. package/test/entities/text.test.js +533 -7
  143. package/test/integration/exportIntegration.reference.dxf +1706 -0
  144. package/test/integration/exportIntegration.test.js +186 -0
  145. package/test/integration/importExportIntegration.test.js +126 -0
  146. package/test/integration/intersectionIntegration.test.js +880 -0
  147. package/test/integration/userInputIntegration.reference.dxf +1410 -0
  148. package/test/integration/userInputIntegration.test.js +269 -0
  149. package/test/lib/boundingBox.test.js +26 -2
  150. package/test/lib/canvas.test.js +613 -5
  151. package/test/lib/clipboard.test.js +70 -0
  152. package/test/lib/colour.test.js +114 -0
  153. package/test/lib/colours.test.js +63 -18
  154. package/test/lib/commandLine.test.js +159 -22
  155. package/test/lib/commandManager.test.js +4 -4
  156. package/test/lib/constants.test.js +9 -0
  157. package/test/lib/dxf/dxfFile.test.js +6 -2
  158. package/test/lib/dxf/dxfIterator.test.js +1 -1
  159. package/test/lib/dxf/dxfWrite.test.js +173 -0
  160. package/test/lib/dxf/handleManager.test.js +137 -0
  161. package/test/lib/dxf/sections/blocks.test.js +5 -5
  162. package/test/lib/dxf/sections/entities.test.js +4 -4
  163. package/test/lib/dxf/sections/header.test.js +18 -4
  164. package/test/lib/dxf/sections/objects.test.js +132 -0
  165. package/test/lib/dxf/sections/section.test.js +29 -29
  166. package/test/lib/dxf/sections/tables.test.js +3 -3
  167. package/test/lib/entityManager.test.js +163 -0
  168. package/test/lib/headers.test.js +233 -0
  169. package/test/lib/inputManager.test.js +1144 -5
  170. package/test/lib/intersect.test.js +454 -331
  171. package/test/lib/logging.test.js +1 -1
  172. package/test/lib/matrix.test.js +1 -1
  173. package/test/lib/mouse.test.js +327 -4
  174. package/test/lib/patterns.test.js +105 -0
  175. package/test/lib/promptOptions.test.js +179 -0
  176. package/test/lib/scene.test.js +16 -52
  177. package/test/lib/selectionManager.test.js +17 -5
  178. package/test/lib/settings.test.js +111 -5
  179. package/test/lib/snapping.test.js +142 -4
  180. package/test/lib/stateManager.test.js +155 -0
  181. package/test/lib/utils.test.js +81 -1
  182. package/test/objects/dictionary.test.js +81 -0
  183. package/test/objects/dictionaryManager.test.js +34 -0
  184. package/test/properties/dimType.test.js +62 -0
  185. package/test/properties/flags.test.js +164 -0
  186. package/test/properties/property.test.js +13 -0
  187. package/test/properties/propertyManager.test.js +10 -11
  188. package/test/tables/appId.test.js +46 -0
  189. package/test/tables/appIdManager.test.js +72 -0
  190. package/test/tables/block.test.js +157 -0
  191. package/test/tables/blockManager.test.js +52 -0
  192. package/test/tables/blockRecord.test.js +39 -0
  193. package/test/tables/blockRecordManager.test.js +60 -0
  194. package/test/tables/dimstyle.test.js +72 -0
  195. package/test/tables/endblk.test.js +30 -0
  196. package/test/tables/layer.test.js +95 -0
  197. package/test/tables/layerManager.test.js +172 -0
  198. package/test/{styles → tables}/ltype.test.js +7 -7
  199. package/test/{styles → tables}/ltypeManager.test.js +2 -2
  200. package/test/tables/style.test.js +44 -0
  201. package/test/tables/stylemanagerbase.test.js +220 -0
  202. package/test/tables/tableManagerBase.test.js +194 -0
  203. package/test/tables/ucs.test.js +37 -0
  204. package/test/tables/ucsManager.test.js +48 -0
  205. package/test/tables/view.test.js +37 -0
  206. package/test/tables/viewManager.test.js +48 -0
  207. package/test/tables/vport.test.js +117 -0
  208. package/test/tables/vportManager.test.js +54 -0
  209. package/test/test-helpers/test-helpers.js +66 -0
  210. package/test/tools/chamfer.test.js +970 -0
  211. package/test/tools/chamferFilletBase.test.js +446 -0
  212. package/test/tools/copy.test.js +22 -14
  213. package/test/tools/copybase.test.js +93 -0
  214. package/test/tools/copyclip.test.js +92 -0
  215. package/test/tools/cornerEntity.test.js +201 -0
  216. package/test/tools/cutclip.test.js +94 -0
  217. package/test/tools/distance.test.js +140 -18
  218. package/test/tools/erase.test.js +12 -12
  219. package/test/tools/explode.test.js +45 -0
  220. package/test/tools/extend.test.js +326 -44
  221. package/test/tools/fillet.test.js +831 -0
  222. package/test/tools/identify.test.js +115 -16
  223. package/test/tools/matchProp.test.js +84 -0
  224. package/test/tools/mirror.test.js +475 -0
  225. package/test/tools/move.test.js +75 -19
  226. package/test/tools/offset.test.js +748 -0
  227. package/test/tools/pan.test.js +72 -0
  228. package/test/tools/pasteclip.test.js +100 -0
  229. package/test/tools/purge.test.js +89 -0
  230. package/test/tools/rotate.test.js +89 -23
  231. package/test/tools/scale.test.js +529 -0
  232. package/test/tools/trim.test.js +419 -84
  233. package/test/tools/zoom.test.js +504 -0
  234. package/core/entities/alignedDimension.js +0 -279
  235. package/core/entities/angularDimension.js +0 -194
  236. package/core/entities/baseDimension.js +0 -227
  237. package/core/entities/block.js +0 -247
  238. package/core/entities/diametricDimension.js +0 -133
  239. package/core/entities/dimension.js +0 -202
  240. package/core/entities/radialDimension.js +0 -126
  241. package/core/styles/dimStyle.js +0 -719
  242. package/core/styles/dimStyleManager.js +0 -47
  243. package/core/styles/layer.js +0 -133
  244. package/core/styles/layerManager.js +0 -40
  245. package/core/styles/ltype.js +0 -86
  246. package/core/styles/ltypeManager.js +0 -50
  247. package/core/styles/style.js +0 -158
  248. package/core/styles/styleManager.js +0 -43
  249. package/core/styles/styleManagerBase.js +0 -299
  250. package/test/entities/block.test.js +0 -22
  251. package/test/styles/dimstyle.test.js +0 -19
  252. package/test/styles/layerManager.test.js +0 -150
  253. package/test/styles/style.test.js +0 -33
  254. package/test/styles/stylemanagerbase.test.js +0 -219
@@ -0,0 +1,137 @@
1
+ import { HandleManager } from '../../../core/lib/dxf/handleManager.js';
2
+
3
+ test('Test HandleManager.constructor', () => {
4
+ const handle = new HandleManager();
5
+ expect(handle.counter).toBe(10);
6
+ expect(handle.usedHandles.size).toBe(0);
7
+ });
8
+
9
+ test('Test HandleManager.next', () => {
10
+ const handle = new HandleManager();
11
+ expect(handle.next()).toBe('A');
12
+ expect(handle.next()).toBe('B');
13
+ expect(handle.next()).toBe('C');
14
+ expect(handle.counter).toBe(13);
15
+ // each allocated handle is tracked in usedHandles
16
+ expect(handle.usedHandles.has('A')).toBe(true);
17
+ expect(handle.usedHandles.has('B')).toBe(true);
18
+ expect(handle.usedHandles.has('C')).toBe(true);
19
+ });
20
+
21
+ test('Test HandleManager.format', () => {
22
+ const handle = new HandleManager();
23
+ expect(handle.format(0)).toBe('0');
24
+ expect(handle.format(10)).toBe('A');
25
+ expect(handle.format(15)).toBe('F');
26
+ expect(handle.format(16)).toBe('10');
27
+ expect(handle.format(255)).toBe('FF');
28
+ });
29
+
30
+ test('Test HandleManager.reset', () => {
31
+ const handle = new HandleManager();
32
+ handle.next();
33
+ handle.next();
34
+ expect(handle.counter).toBe(12);
35
+ handle.reset();
36
+ expect(handle.counter).toBe(10);
37
+ // usedHandles must also be cleared
38
+ expect(handle.usedHandles.size).toBe(0);
39
+ });
40
+
41
+ test('Test HandleManager.handseed getter', () => {
42
+ const handle = new HandleManager();
43
+ expect(handle.handseed).toBe('A');
44
+ handle.next();
45
+ expect(handle.handseed).toBe('B');
46
+ });
47
+
48
+ test('Test HandleManager.handseed setter', () => {
49
+ const handle = new HandleManager();
50
+ handle.handseed = 'FF';
51
+ expect(handle.counter).toBe(255);
52
+ expect(handle.next()).toBe('FF');
53
+ expect(handle.next()).toBe('100');
54
+ });
55
+
56
+ test('Test HandleManager.handseed setter directly assigns counter, even below current value', () => {
57
+ const handle = new HandleManager();
58
+ // Advance the counter, then set handseed to a lower value.
59
+ // The setter performs a direct assignment with no lower-bound guard.
60
+ handle.next(); // counter → 11
61
+ handle.next(); // counter → 12
62
+ handle.handseed = '5'; // parseInt('5', 16) = 5
63
+ expect(handle.counter).toBe(5);
64
+ });
65
+
66
+ test('Test HandleManager.checkHandle coerces numeric handle to string', () => {
67
+ const handle = new HandleManager();
68
+ handle.checkHandle(255);
69
+ // String(255) = '255', which is valid hex (0x255 = 597)
70
+ expect(handle.usedHandles.has('255')).toBe(true);
71
+ expect(handle.counter).toBe(598);
72
+ });
73
+
74
+ test('Test HandleManager.checkHandle advances counter when handle >= counter', () => {
75
+ const handle = new HandleManager();
76
+ // counter starts at 10 (0xA); register 0x1F (31) — above counter
77
+ handle.checkHandle('1F');
78
+ expect(handle.usedHandles.has('1F')).toBe(true);
79
+ expect(handle.counter).toBe(32); // 0x1F + 1
80
+ });
81
+
82
+ test('Test HandleManager.checkHandle does not advance counter when handle < counter', () => {
83
+ const handle = new HandleManager();
84
+ handle.next(); // counter → 11 (0xB), 'A' allocated
85
+ const counterBefore = handle.counter;
86
+ // Register a handle lower than current counter
87
+ handle.checkHandle('5');
88
+ expect(handle.usedHandles.has('5')).toBe(true);
89
+ expect(handle.counter).toBe(counterBefore); // counter unchanged
90
+ });
91
+
92
+ test('Test HandleManager.checkHandle ignores undefined and null', () => {
93
+ const handle = new HandleManager();
94
+ const counterBefore = handle.counter;
95
+ handle.checkHandle(undefined);
96
+ handle.checkHandle(null);
97
+ expect(handle.counter).toBe(counterBefore);
98
+ expect(handle.usedHandles.size).toBe(0);
99
+ });
100
+
101
+ test('Test HandleManager.checkHandle ignores invalid hex strings', () => {
102
+ const handle = new HandleManager();
103
+ const counterBefore = handle.counter;
104
+ handle.checkHandle('XYZ');
105
+ handle.checkHandle('');
106
+ expect(handle.counter).toBe(counterBefore);
107
+ expect(handle.usedHandles.size).toBe(0);
108
+ });
109
+
110
+ test('Test HandleManager.releaseHandle removes handle from usedHandles', () => {
111
+ const handle = new HandleManager();
112
+ const h = handle.next(); // allocates 'A'
113
+ expect(handle.usedHandles.has('A')).toBe(true);
114
+ handle.releaseHandle(h);
115
+ expect(handle.usedHandles.has('A')).toBe(false);
116
+ });
117
+
118
+ test('Test HandleManager.releaseHandle ignores undefined and null', () => {
119
+ const handle = new HandleManager();
120
+ handle.next();
121
+ const sizeBefore = handle.usedHandles.size;
122
+ handle.releaseHandle(undefined);
123
+ handle.releaseHandle(null);
124
+ expect(handle.usedHandles.size).toBe(sizeBefore);
125
+ });
126
+
127
+ test('Test HandleManager.releaseHandle allows handle to be re-registered without duplicate error', () => {
128
+ const handle = new HandleManager();
129
+ const h = handle.next(); // allocates 'A'
130
+ handle.releaseHandle(h);
131
+ // After release the handle is gone, so checkHandle should re-register it cleanly
132
+ handle.checkHandle(h);
133
+ // The handle should be back in usedHandles with no duplicate detection
134
+ expect(handle.usedHandles.has('A')).toBe(true);
135
+ // Only one entry — no duplication
136
+ expect(handle.usedHandles.size).toBe(1);
137
+ });
@@ -1,8 +1,8 @@
1
- import {Blocks} from '../../../../core/lib/dxf/sections/blocks.js';
2
- import {DxfIterator} from '../../../../core/lib/dxf/dxfIterator.js';
1
+ import { Blocks } from '../../../../core/lib/dxf/sections/blocks.js';
2
+ import { DxfIterator } from '../../../../core/lib/dxf/dxfIterator.js';
3
3
 
4
4
  const blockData =
5
- `2
5
+ `2
6
6
  BLOCKS
7
7
  0
8
8
  BLOCK
@@ -91,7 +91,7 @@ test('Test blocks.read', () => {
91
91
  test('Test blocks.addTable', () => {
92
92
  // block without data
93
93
  const blockEntity = {};
94
- const blockCount = blocks.blocks.length;
94
+ const itemCount = blocks.blocks.length;
95
95
  blocks.addBlock(blockEntity);
96
- expect(blocks.blocks.length).toBe(blockCount);
96
+ expect(blocks.blocks.length).toBe(itemCount);
97
97
  });
@@ -1,8 +1,8 @@
1
- import {Entities} from '../../../../core/lib/dxf/sections/entities.js';
2
- import {DxfIterator} from '../../../../core/lib/dxf/dxfIterator.js';
1
+ import { Entities } from '../../../../core/lib/dxf/sections/entities.js';
2
+ import { DxfIterator } from '../../../../core/lib/dxf/dxfIterator.js';
3
3
 
4
4
  const entityData =
5
- `0
5
+ `0
6
6
  ENTITIES
7
7
  0
8
8
  CIRCLE
@@ -119,7 +119,7 @@ test('Test Entities.read', () => {
119
119
 
120
120
  test('Test Entities.addEntity', () => {
121
121
  // entity without points
122
- const circleEntity = {'0': 'CIRCLE', '40': 100, '8': '0'};
122
+ const circleEntity = { '0': 'CIRCLE', '40': 100, '8': '0' };
123
123
 
124
124
  expect(() => {
125
125
  entities.addEntity(circleEntity);
@@ -1,8 +1,8 @@
1
- import {Header} from '../../../../core/lib/dxf/sections/header.js';
2
- import {DxfIterator} from '../../../../core/lib/dxf/dxfIterator.js';
1
+ import { Header } from '../../../../core/lib/dxf/sections/header.js';
2
+ import { DxfIterator } from '../../../../core/lib/dxf/dxfIterator.js';
3
3
 
4
4
  const headerData =
5
- `2
5
+ `2
6
6
  HEADER
7
7
  9
8
8
  $ACADVER
@@ -32,7 +32,15 @@ $EXTMAX
32
32
  300
33
33
  30
34
34
  0.0
35
+ 9
36
+ $TEXTSTYLE
37
+ 7
38
+ Standard
35
39
  9
40
+ $CLAYER
41
+ 8
42
+ 0
43
+ 0
36
44
  ENDSEC
37
45
  0
38
46
  EOF`;
@@ -43,7 +51,7 @@ const header = new Header();
43
51
  header.read(iterator);
44
52
 
45
53
  test('Test Header.read', () => {
46
- expect(Object.keys(header)).toHaveLength(5);
54
+ expect(Object.keys(header)).toHaveLength(6);
47
55
  // check the entity type
48
56
  expect(header).toHaveProperty('$ACADVER');
49
57
  expect(header['$ACADVER']).toHaveProperty('1', 'AC1009');
@@ -59,4 +67,10 @@ test('Test Header.read', () => {
59
67
  expect(header['$EXTMIN'].points[0]).toHaveProperty('x', 100);
60
68
  expect(header['$EXTMIN'].points[0]).toHaveProperty('y', 100);
61
69
  expect(header['$EXTMIN'].points[0]).toHaveProperty('z', 100);
70
+
71
+ expect(header).toHaveProperty('$TEXTSTYLE');
72
+ expect(header['$TEXTSTYLE']).toHaveProperty('7', 'Standard');
73
+
74
+ expect(header).toHaveProperty('$CLAYER');
75
+ expect(header['$CLAYER']).toHaveProperty('8', '0');
62
76
  });
@@ -0,0 +1,132 @@
1
+ import { Objects } from '../../../../core/lib/dxf/sections/objects.js';
2
+ import { DxfIterator } from '../../../../core/lib/dxf/dxfIterator.js';
3
+
4
+ const objectData =
5
+ `0
6
+ OBJECTS
7
+ 0
8
+ DICTIONARY
9
+ 5
10
+ 27
11
+ 100
12
+ AcDbDictionary
13
+ 281
14
+ 1
15
+ 3
16
+ ACAD_GROUP
17
+ 350
18
+ 26
19
+ 0
20
+ DICTIONARY
21
+ 5
22
+ 26
23
+ 100
24
+ AcDbDictionary
25
+ 281
26
+ 1
27
+ 0
28
+ ENDSEC
29
+ 0
30
+ EOF`;
31
+
32
+ const iterator = new DxfIterator();
33
+ iterator.loadFile(objectData);
34
+ const objects = new Objects();
35
+
36
+ test('Test Objects.read', () => {
37
+ const readObjects = objects.read(iterator);
38
+
39
+ expect(readObjects).toHaveLength(2);
40
+
41
+ const rootDictionary = readObjects[0];
42
+ const groupDictionary = readObjects[1];
43
+
44
+ // check the object types
45
+ expect(rootDictionary).toHaveProperty('0', 'DICTIONARY');
46
+ expect(groupDictionary).toHaveProperty('0', 'DICTIONARY');
47
+
48
+ // check handles
49
+ expect(rootDictionary).toHaveProperty('5', '27');
50
+ expect(groupDictionary).toHaveProperty('5', '26');
51
+
52
+ // check AcDbDictionary subclass marker
53
+ expect(rootDictionary).toHaveProperty('100', 'AcDbDictionary');
54
+ expect(groupDictionary).toHaveProperty('100', 'AcDbDictionary');
55
+
56
+ // check duplicate record cloning
57
+ expect(rootDictionary).toHaveProperty('281', 1);
58
+ expect(groupDictionary).toHaveProperty('281', 1);
59
+
60
+ // check root dictionary entries
61
+ expect(rootDictionary).toHaveProperty('3', 'ACAD_GROUP');
62
+ expect(rootDictionary).toHaveProperty('350', '26');
63
+ });
64
+
65
+ test('Test Objects.read with multiple entries', () => {
66
+ const multiEntryData =
67
+ `0
68
+ OBJECTS
69
+ 0
70
+ DICTIONARY
71
+ 5
72
+ C
73
+ 100
74
+ AcDbDictionary
75
+ 281
76
+ 1
77
+ 3
78
+ ACAD_GROUP
79
+ 350
80
+ D
81
+ 3
82
+ ACAD_LAYOUT
83
+ 350
84
+ 1A
85
+ 3
86
+ ACAD_PLOTSTYLENAME
87
+ 350
88
+ E
89
+ 0
90
+ DICTIONARY
91
+ 5
92
+ D
93
+ 100
94
+ AcDbDictionary
95
+ 281
96
+ 1
97
+ 0
98
+ ENDSEC
99
+ 0
100
+ EOF`;
101
+
102
+ const iter = new DxfIterator();
103
+ iter.loadFile(multiEntryData);
104
+ const obj = new Objects();
105
+ const result = obj.read(iter);
106
+
107
+ expect(result).toHaveLength(2);
108
+
109
+ const rootDict = result[0];
110
+
111
+ // multiple group code 3 values should be arrayed
112
+ expect(rootDict[3]).toEqual(['ACAD_GROUP', 'ACAD_LAYOUT', 'ACAD_PLOTSTYLENAME']);
113
+ // multiple group code 350 values should be arrayed
114
+ expect(rootDict[350]).toEqual(['D', '1A', 'E']);
115
+ });
116
+
117
+ test('Test Objects.read with empty section', () => {
118
+ const emptyData =
119
+ `0
120
+ OBJECTS
121
+ 0
122
+ ENDSEC
123
+ 0
124
+ EOF`;
125
+
126
+ const iter = new DxfIterator();
127
+ iter.loadFile(emptyData);
128
+ const obj = new Objects();
129
+ const result = obj.read(iter);
130
+
131
+ expect(result).toHaveLength(0);
132
+ });
@@ -1,5 +1,5 @@
1
- import {Section} from '../../../../core/lib/dxf/sections/section.js';
2
- import {DxfIterator} from '../../../../core/lib/dxf/dxfIterator.js';
1
+ import { Section } from '../../../../core/lib/dxf/sections/section.js';
2
+ import { DxfIterator } from '../../../../core/lib/dxf/dxfIterator.js';
3
3
 
4
4
  const section = new Section();
5
5
 
@@ -29,7 +29,7 @@ test('Test Section.parseValue', () => {
29
29
 
30
30
  test('Test Section.parseChild', () => {
31
31
  const string =
32
- `0
32
+ `0
33
33
  CIRCLE
34
34
  8
35
35
  0
@@ -69,7 +69,7 @@ EOF`;
69
69
 
70
70
  test('Test Section.parsePoint', () => {
71
71
  const string =
72
- `10
72
+ `10
73
73
  500.0
74
74
  20
75
75
  500.0
@@ -125,69 +125,69 @@ test('Test Section.parseBoolean', () => {
125
125
 
126
126
  test('Test Section.getGroupValue', () => {
127
127
  // 0-9: String
128
- expect(section.getGroupValue({'code': '1', 'value': '1'})).toBe('1');
128
+ expect(section.getGroupValue({ 'code': '1', 'value': '1' })).toBe('1');
129
129
  // 10-39: Double precision 3D point value
130
130
  // 40-59: Double precision floating-point value
131
- expect(section.getGroupValue({'code': '10', 'value': ' 100.0'})).toBe(100.0);
131
+ expect(section.getGroupValue({ 'code': '10', 'value': ' 100.0' })).toBe(100.0);
132
132
  // 60-79: 16-bit integer value
133
133
  // 90-99: 32-bit integer value
134
- expect(section.getGroupValue({'code': '60', 'value': ' 100.0'})).toBe(100);
134
+ expect(section.getGroupValue({ 'code': '60', 'value': ' 100.0' })).toBe(100);
135
135
  // 100: String (255-character maximum; less for Unicode strings)
136
136
  // 102: String (255-character maximum; less for Unicode strings)
137
137
  // 105: String representing hexadecimal (hex) handle value
138
- expect(section.getGroupValue({'code': '100', 'value': 'aabbccdd'})).toBe('aabbccdd');
138
+ expect(section.getGroupValue({ 'code': '100', 'value': 'aabbccdd' })).toBe('aabbccdd');
139
139
  // 110-119: Double precision floating-point value
140
140
  // 120-129: Double precision floating-point value
141
141
  // 130-139: Double precision floating-point value
142
142
  // 140-149: Double precision scalar floating-point value
143
- expect(section.getGroupValue({'code': '110', 'value': ' 100.0'})).toBe(100.0);
143
+ expect(section.getGroupValue({ 'code': '110', 'value': ' 100.0' })).toBe(100.0);
144
144
  // 160-169: 64-bit integer value
145
145
  // 170-179: 16-bit integer value
146
- expect(section.getGroupValue({'code': '160', 'value': ' 100.0'})).toBe(100);
146
+ expect(section.getGroupValue({ 'code': '160', 'value': ' 100.0' })).toBe(100);
147
147
  // 210-239: Double-precision floating-point value
148
- expect(section.getGroupValue({'code': '210', 'value': ' 100.0'})).toBe(100.0);
148
+ expect(section.getGroupValue({ 'code': '210', 'value': ' 100.0' })).toBe(100.0);
149
149
  // 270-279: 16-bit integer value
150
150
  // 280-289: 16-bit integer value
151
- expect(section.getGroupValue({'code': '270', 'value': ' 100.0'})).toBe(100);
151
+ expect(section.getGroupValue({ 'code': '270', 'value': ' 100.0' })).toBe(100);
152
152
  // 290-299: Boolean flag value
153
- expect(section.getGroupValue({'code': '290', 'value': ' 0'})).toBe(false);
154
- expect(section.getGroupValue({'code': '299', 'value': ' 1'})).toBe(true);
153
+ expect(section.getGroupValue({ 'code': '290', 'value': ' 0' })).toBe(false);
154
+ expect(section.getGroupValue({ 'code': '299', 'value': ' 1' })).toBe(true);
155
155
  // 300-309: Arbitrary text string
156
156
  // 330-369: String representing hex object IDs
157
- expect(section.getGroupValue({'code': '300', 'value': 'aabbccdd'})).toBe('aabbccdd');
157
+ expect(section.getGroupValue({ 'code': '300', 'value': 'aabbccdd' })).toBe('aabbccdd');
158
158
  // 370-379: 16-bit integer value
159
159
  // 380-389: 16-bit integer value
160
- expect(section.getGroupValue({'code': '370', 'value': ' 100.0'})).toBe(100);
160
+ expect(section.getGroupValue({ 'code': '370', 'value': ' 100.0' })).toBe(100);
161
161
  // 390-399: String representing hex handle value
162
- expect(section.getGroupValue({'code': '390', 'value': 'aabbccdd'})).toBe('aabbccdd');
162
+ expect(section.getGroupValue({ 'code': '390', 'value': 'aabbccdd' })).toBe('aabbccdd');
163
163
  // 400-409: 16-bit integer value
164
- expect(section.getGroupValue({'code': '400', 'value': ' 100.0'})).toBe(100);
164
+ expect(section.getGroupValue({ 'code': '400', 'value': ' 100.0' })).toBe(100);
165
165
  // 410-419: String
166
- expect(section.getGroupValue({'code': '410', 'value': 'aabbccdd'})).toBe('aabbccdd');
166
+ expect(section.getGroupValue({ 'code': '410', 'value': 'aabbccdd' })).toBe('aabbccdd');
167
167
  // 420-429: 32-bit integer value
168
- expect(section.getGroupValue({'code': '420', 'value': ' 100.0'})).toBe(100);
168
+ expect(section.getGroupValue({ 'code': '420', 'value': ' 100.0' })).toBe(100);
169
169
  // 430-439: String
170
- expect(section.getGroupValue({'code': '340', 'value': 'aabbccdd'})).toBe('aabbccdd');
170
+ expect(section.getGroupValue({ 'code': '340', 'value': 'aabbccdd' })).toBe('aabbccdd');
171
171
  // 440-449: 32-bit integer value
172
172
  // 450-459: Long
173
- expect(section.getGroupValue({'code': '440', 'value': ' 100.0'})).toBe(100);
173
+ expect(section.getGroupValue({ 'code': '440', 'value': ' 100.0' })).toBe(100);
174
174
  // 460-469: Double-precision floating-point value
175
- expect(section.getGroupValue({'code': '460', 'value': ' 100.0'})).toBe(100.0);
175
+ expect(section.getGroupValue({ 'code': '460', 'value': ' 100.0' })).toBe(100.0);
176
176
  // 470-479: String
177
177
  // 480-481: String representing hex handle value
178
- expect(section.getGroupValue({'code': '470', 'value': 'aabbccdd'})).toBe('aabbccdd');
178
+ expect(section.getGroupValue({ 'code': '470', 'value': 'aabbccdd' })).toBe('aabbccdd');
179
179
  // 999: Comment (string)
180
- expect(section.getGroupValue({'code': '999', 'value': 'comment'})).toBe('comment');
180
+ expect(section.getGroupValue({ 'code': '999', 'value': 'comment' })).toBe('comment');
181
181
  // 1000-1009: String (same limits as indicated with 0-9 code range)
182
- expect(section.getGroupValue({'code': '1000', 'value': 'aabbccdd'})).toBe('aabbccdd');
182
+ expect(section.getGroupValue({ 'code': '1000', 'value': 'aabbccdd' })).toBe('aabbccdd');
183
183
  // 1010-1059: Double-precision floating-point value
184
- expect(section.getGroupValue({'code': '1010', 'value': ' 100.0'})).toBe(100.0);
184
+ expect(section.getGroupValue({ 'code': '1010', 'value': ' 100.0' })).toBe(100.0);
185
185
  // 1060-1070: 16-bit integer value
186
186
  // 1071: 32-bit: integer value
187
- expect(section.getGroupValue({'code': '1060', 'value': ' 100.0'})).toBe(100);
187
+ expect(section.getGroupValue({ 'code': '1060', 'value': ' 100.0' })).toBe(100);
188
188
 
189
189
  // test for throw on invalid group code
190
190
  expect(() => {
191
- section.getGroupValue({'code': 'error', 'value': 'error'}); ;
191
+ section.getGroupValue({ 'code': 'error', 'value': 'error' }); ;
192
192
  }).toThrow();
193
193
  });
@@ -1,8 +1,8 @@
1
- import {Tables} from '../../../../core/lib/dxf/sections/tables.js';
2
- import {DxfIterator} from '../../../../core/lib/dxf/dxfIterator.js';
1
+ import { Tables } from '../../../../core/lib/dxf/sections/tables.js';
2
+ import { DxfIterator } from '../../../../core/lib/dxf/dxfIterator.js';
3
3
 
4
4
  const tableData =
5
- `0
5
+ `0
6
6
  TABLES
7
7
  0
8
8
  TABLE
@@ -0,0 +1,163 @@
1
+ import { Core } from '../../core/core/core.js';
2
+ import { DesignCore } from '../../core/designCore.js';
3
+ import { Line } from '../../core/entities/line.js';
4
+ import { Circle } from '../../core/entities/circle.js';
5
+ import { Point } from '../../core/entities/point.js';
6
+
7
+ // initialise core (also activates DesignCore facade)
8
+ new Core();
9
+
10
+ describe('EntityManager', () => {
11
+ beforeEach(() => {
12
+ // reset scene entities before each test
13
+ DesignCore.Scene.clear();
14
+ });
15
+
16
+ test('create adds a new entity with current layer', () => {
17
+ const mgr = DesignCore.Scene.entities;
18
+ const p1 = new Point(0, 0);
19
+ const p2 = new Point(10, 0);
20
+
21
+ mgr.create('Line', { points: [p1, p2] });
22
+
23
+ expect(mgr.count()).toBe(1);
24
+ const ent = mgr.get(0);
25
+ expect(ent).toBeInstanceOf(Line);
26
+ expect(ent.layer).toBe(DesignCore.LayerManager.getCstyle());
27
+ });
28
+
29
+ test('add/get/count manage entities correctly', () => {
30
+ const mgr = DesignCore.Scene.entities;
31
+ const line = new Line({ points: [new Point(0, 0), new Point(1, 1)] });
32
+ expect(mgr.count()).toBe(0);
33
+ mgr.add(line);
34
+ expect(mgr.count()).toBe(1);
35
+ expect(mgr.get(0)).toBe(line);
36
+ });
37
+
38
+ test('replace swaps entity at index', () => {
39
+ const mgr = DesignCore.Scene.entities;
40
+ const line = new Line({ points: [new Point(0, 0), new Point(1, 1)] });
41
+ const circle = new Circle({ points: [new Point(5, 5)], radius: 2 });
42
+ mgr.add(line);
43
+ expect(mgr.get(0)).toBeInstanceOf(Line);
44
+ mgr.replace(0, circle);
45
+ expect(mgr.get(0)).toBe(circle);
46
+ expect(mgr.get(0)).toBeInstanceOf(Circle);
47
+ });
48
+
49
+ test('remove deletes entity at index', () => {
50
+ const mgr = DesignCore.Scene.entities;
51
+ const l1 = new Line({ points: [new Point(0, 0), new Point(1, 0)] });
52
+ const l2 = new Line({ points: [new Point(0, 1), new Point(1, 1)] });
53
+ mgr.add(l1);
54
+ mgr.add(l2);
55
+ expect(mgr.count()).toBe(2);
56
+ mgr.remove(0);
57
+ expect(mgr.count()).toBe(1);
58
+ expect(mgr.get(0)).toBe(l2);
59
+ });
60
+
61
+ test('remove releases the entity handle from HandleManager', () => {
62
+ const mgr = DesignCore.Scene.entities;
63
+ const line = new Line({ points: [new Point(0, 0), new Point(1, 0)] });
64
+ mgr.add(line);
65
+ const handle = line.handle;
66
+ expect(DesignCore.HandleManager.usedHandles.has(handle)).toBe(true);
67
+ mgr.remove(0);
68
+ expect(DesignCore.HandleManager.usedHandles.has(handle)).toBe(false);
69
+ });
70
+
71
+ test('remove then re-add (undo) does not produce a duplicate handle', () => {
72
+ const mgr = DesignCore.Scene.entities;
73
+ const line = new Line({ points: [new Point(0, 0), new Point(1, 0)] });
74
+ mgr.add(line);
75
+ const handle = line.handle;
76
+ const sizeAfterAdd = DesignCore.HandleManager.usedHandles.size;
77
+
78
+ mgr.remove(0);
79
+ // After remove the handle must be released
80
+ expect(DesignCore.HandleManager.usedHandles.has(handle)).toBe(false);
81
+ expect(DesignCore.HandleManager.usedHandles.size).toBe(sizeAfterAdd - 1);
82
+
83
+ // Re-add the same entity (simulates undo of a delete)
84
+ mgr.add(line);
85
+ expect(line.handle).toBe(handle);
86
+ expect(DesignCore.HandleManager.usedHandles.has(handle)).toBe(true);
87
+ // Size must return to what it was after the first add, not grow by one.
88
+ // If checkHandle silently re-inserted without the prior releaseHandle, the
89
+ // Set would still show size = sizeAfterAdd (Sets deduplicate), but the
90
+ // error log would fire. Tracking size across remove → re-add catches the
91
+ // case where releaseHandle was not called and size never shrank.
92
+ expect(DesignCore.HandleManager.usedHandles.size).toBe(sizeAfterAdd);
93
+ });
94
+
95
+
96
+ test('indexOf - test correct index is returned', () => {
97
+ const mgr = DesignCore.Scene.entities;
98
+ // Add two lines with the same data
99
+ const l1 = new Line({ points: [new Point(0, 0), new Point(10, 0)] });
100
+ const l2 = new Line({ points: [new Point(0, 0), new Point(10, 0)] });
101
+ mgr.add(l1);
102
+ mgr.add(l2);
103
+ expect(mgr.count()).toBe(2);
104
+ expect(mgr.indexOf(l1)).toBe(0);
105
+ expect(mgr.indexOf(l2)).toBe(1);
106
+ });
107
+
108
+ test('find returns indices matching type and property', () => {
109
+ const mgr = DesignCore.Scene.entities;
110
+ const l1 = new Line({ points: [new Point(0, 0), new Point(1, 0)], lineWidth: 5 });
111
+ const l2 = new Line({ points: [new Point(0, 1), new Point(1, 1)], lineWidth: 2 });
112
+ mgr.add(l1);
113
+ mgr.add(l2);
114
+
115
+ const found = mgr.find('Line', 'lineWidth', 5);
116
+ expect(found).toEqual([0]);
117
+
118
+ const anyFound = mgr.find('ANY', 'lineWidth', 2);
119
+ expect(anyFound).toEqual([1]);
120
+ });
121
+
122
+ test('findClosest returns index of nearest selectable entity', () => {
123
+ const mgr = DesignCore.Scene.entities;
124
+ // two horizontal lines at y=0 and y=10
125
+ const l1 = new Line({ points: [new Point(0, 0), new Point(100, 0)] });
126
+ const l2 = new Line({ points: [new Point(0, 10), new Point(100, 10)] });
127
+ mgr.add(l1);
128
+ mgr.add(l2);
129
+
130
+ // point closer to y=10 line
131
+ const p = new Point(50, 9.9);
132
+ const idx = mgr.findClosest(p);
133
+ expect(idx).toBe(1);
134
+ });
135
+
136
+ test('update applies setProperty for existing keys only', () => {
137
+ const mgr = DesignCore.Scene.entities;
138
+ const l = new Line({ points: [new Point(0, 0), new Point(1, 1)] });
139
+ mgr.add(l);
140
+
141
+ const newP1 = new Point(2, 2);
142
+ const newP2 = new Point(3, 3);
143
+ mgr.update(0, { points: [newP1, newP2], nonExistent: 123 });
144
+
145
+ expect(mgr.get(0).points[0].x).toBe(2);
146
+ expect(mgr.get(0).points[0].y).toBe(2);
147
+ expect(mgr.get(0).points[1].x).toBe(3);
148
+ expect(mgr.get(0).points[1].y).toBe(3);
149
+ // nonExistent should be ignored
150
+ expect(mgr.get(0).nonExistent).toBeUndefined();
151
+ });
152
+
153
+ test('count and clear reflect entity storage size', () => {
154
+ const mgr = DesignCore.Scene.entities;
155
+ mgr.add(new Line({ points: [new Point(0, 0), new Point(1, 0)] }));
156
+ mgr.add(new Line({ points: [new Point(0, 1), new Point(1, 1)] }));
157
+ expect(mgr.count()).toBe(2);
158
+ mgr.clear();
159
+ expect(mgr.count()).toBe(0);
160
+ });
161
+ });
162
+
163
+