@jscad/modeling 3.0.3-alpha.0 → 3.0.4-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/jscad-modeling.es.js +2 -7
  3. package/dist/jscad-modeling.min.js +2 -7
  4. package/package.json +6 -7
  5. package/rollup.config.js +8 -4
  6. package/src/curves/bezier/arcLengthToT.js +1 -1
  7. package/src/curves/bezier/create.js +1 -1
  8. package/src/curves/bezier/index.js +7 -7
  9. package/src/curves/bezier/length.js +1 -1
  10. package/src/curves/bezier/lengths.js +2 -1
  11. package/src/curves/bezier/tangentAt.js +1 -1
  12. package/src/curves/bezier/valueAt.js +1 -1
  13. package/src/curves/index.js +3 -3
  14. package/src/geometries/geom2/applyTransforms.js +3 -1
  15. package/src/geometries/geom2/clone.js +5 -1
  16. package/src/geometries/geom2/create.js +4 -14
  17. package/src/geometries/geom2/fromSides.js +4 -2
  18. package/src/geometries/geom2/index.js +21 -5
  19. package/src/geometries/geom2/isA.js +5 -1
  20. package/src/geometries/geom2/reverse.js +4 -2
  21. package/src/geometries/geom2/toOutlines.js +2 -1
  22. package/src/geometries/geom2/toPoints.js +5 -2
  23. package/src/geometries/geom2/toSides.js +4 -3
  24. package/src/geometries/geom2/toString.js +3 -2
  25. package/src/geometries/geom2/transform.js +4 -2
  26. package/src/geometries/geom2/validate.js +6 -2
  27. package/src/geometries/geom3/clone.js +5 -1
  28. package/src/geometries/geom3/create.js +5 -19
  29. package/src/geometries/geom3/fromVertices.js +13 -1
  30. package/src/geometries/geom3/fromVerticesConvex.js +1 -1
  31. package/src/geometries/geom3/index.d.ts +1 -0
  32. package/src/geometries/geom3/index.js +26 -4
  33. package/src/geometries/geom3/invert.js +5 -1
  34. package/src/geometries/geom3/isA.js +5 -1
  35. package/src/geometries/geom3/isConvex.d.ts +3 -0
  36. package/src/geometries/geom3/isConvex.js +65 -0
  37. package/src/geometries/geom3/isConvex.test.js +44 -0
  38. package/src/geometries/geom3/toPolygons.js +4 -2
  39. package/src/geometries/geom3/toString.js +3 -2
  40. package/src/geometries/geom3/toVertices.js +8 -4
  41. package/src/geometries/geom3/transform.js +5 -2
  42. package/src/geometries/geom3/validate.js +6 -2
  43. package/src/geometries/index.js +9 -7
  44. package/src/geometries/path2/appendArc.js +7 -5
  45. package/src/geometries/path2/appendArc.test.js +11 -15
  46. package/src/geometries/path2/appendBezier.js +6 -4
  47. package/src/geometries/path2/appendPoints.js +4 -2
  48. package/src/geometries/path2/applyTransforms.js +3 -0
  49. package/src/geometries/path2/clone.js +5 -1
  50. package/src/geometries/path2/close.js +5 -1
  51. package/src/geometries/path2/concat.js +3 -2
  52. package/src/geometries/path2/create.js +4 -15
  53. package/src/geometries/path2/equals.js +12 -7
  54. package/src/geometries/path2/fromPoints.js +5 -3
  55. package/src/geometries/path2/index.js +21 -4
  56. package/src/geometries/path2/isA.js +5 -1
  57. package/src/geometries/path2/reverse.js +4 -2
  58. package/src/geometries/path2/toPoints.js +5 -3
  59. package/src/geometries/path2/toString.js +3 -2
  60. package/src/geometries/path2/transform.js +4 -2
  61. package/src/geometries/path2/validate.js +5 -1
  62. package/src/geometries/path3/applyTransforms.js +1 -1
  63. package/src/geometries/path3/close.js +4 -2
  64. package/src/geometries/path3/concat.js +2 -3
  65. package/src/geometries/path3/create.js +4 -20
  66. package/src/geometries/path3/equals.js +4 -2
  67. package/src/geometries/path3/fromVertices.js +2 -3
  68. package/src/geometries/path3/index.js +17 -1
  69. package/src/geometries/path3/isA.js +4 -2
  70. package/src/geometries/path3/reverse.js +2 -3
  71. package/src/geometries/path3/toString.js +2 -3
  72. package/src/geometries/path3/toVertices.js +2 -3
  73. package/src/geometries/path3/transform.js +2 -3
  74. package/src/geometries/path3/validate.js +6 -3
  75. package/src/geometries/poly2/arePointsInside.js +4 -1
  76. package/src/geometries/poly2/clone.js +4 -1
  77. package/src/geometries/poly2/create.js +2 -9
  78. package/src/geometries/poly2/index.js +16 -4
  79. package/src/geometries/poly2/isA.js +5 -1
  80. package/src/geometries/poly2/isConvex.js +5 -1
  81. package/src/geometries/poly2/isSimple.js +5 -1
  82. package/src/geometries/poly2/measureArea.js +4 -1
  83. package/src/geometries/poly2/measureBoundingBox.js +6 -1
  84. package/src/geometries/poly2/reverse.js +4 -1
  85. package/src/geometries/poly2/toPoints.js +6 -1
  86. package/src/geometries/poly2/toString.js +5 -1
  87. package/src/geometries/poly2/transform.js +5 -1
  88. package/src/geometries/poly2/validate.js +6 -2
  89. package/src/geometries/poly3/clone.js +4 -1
  90. package/src/geometries/poly3/create.js +3 -11
  91. package/src/geometries/poly3/fromVerticesAndPlane.js +3 -1
  92. package/src/geometries/poly3/index.js +19 -4
  93. package/src/geometries/poly3/invert.js +4 -1
  94. package/src/geometries/poly3/isA.js +5 -1
  95. package/src/geometries/poly3/isConvex.js +5 -1
  96. package/src/geometries/poly3/measureArea.js +5 -1
  97. package/src/geometries/poly3/measureBoundingBox.js +4 -1
  98. package/src/geometries/poly3/measureBoundingSphere.js +4 -3
  99. package/src/geometries/poly3/measureSignedVolume.js +6 -1
  100. package/src/geometries/poly3/plane.js +6 -0
  101. package/src/geometries/poly3/toString.js +5 -1
  102. package/src/geometries/poly3/toVertices.js +6 -1
  103. package/src/geometries/poly3/transform.js +5 -1
  104. package/src/geometries/poly3/validate.js +6 -2
  105. package/src/geometries/slice/calculatePlane.js +3 -3
  106. package/src/geometries/slice/clone.js +4 -1
  107. package/src/geometries/slice/create.js +5 -10
  108. package/src/geometries/slice/equals.js +5 -1
  109. package/src/geometries/slice/fromGeom2.js +1 -1
  110. package/src/geometries/slice/fromVertices.js +3 -3
  111. package/src/geometries/slice/index.js +19 -4
  112. package/src/geometries/slice/isA.js +5 -1
  113. package/src/geometries/slice/reverse.js +5 -2
  114. package/src/geometries/slice/toEdges.js +5 -3
  115. package/src/geometries/slice/toPolygons.js +5 -1
  116. package/src/geometries/slice/toString.js +5 -1
  117. package/src/geometries/slice/toVertices.js +5 -3
  118. package/src/geometries/slice/transform.js +4 -3
  119. package/src/geometries/slice/validate.js +3 -2
  120. package/src/index.d.ts +1 -0
  121. package/src/index.js +4 -0
  122. package/src/maths/constants.js +11 -7
  123. package/src/maths/index.js +2 -1
  124. package/src/maths/mat4/isOnlyTransformScale.js +1 -1
  125. package/src/operations/booleans/index.js +2 -0
  126. package/src/operations/booleans/intersect.js +0 -1
  127. package/src/operations/booleans/scission.js +0 -1
  128. package/src/operations/booleans/trees/splitLineSegmentByPlane.js +1 -4
  129. package/src/operations/booleans/trees/splitPolygonByPlane.test.js +138 -0
  130. package/src/operations/booleans/unionGeom3.test.js +35 -0
  131. package/src/operations/extrusions/extrudeFromSlices.js +15 -5
  132. package/src/operations/extrusions/extrudeRotate.js +2 -1
  133. package/src/operations/extrusions/extrudeRotate.test.js +34 -0
  134. package/src/operations/extrusions/extrudeWalls.test.js +60 -0
  135. package/src/operations/minkowski/index.d.ts +1 -0
  136. package/src/operations/minkowski/index.js +15 -0
  137. package/src/operations/minkowski/minkowskiSum.d.ts +4 -0
  138. package/src/operations/minkowski/minkowskiSum.js +223 -0
  139. package/src/operations/minkowski/minkowskiSum.test.js +199 -0
  140. package/src/operations/modifiers/reTesselateCoplanarPolygons.js +10 -3
  141. package/src/operations/modifiers/reTesselateCoplanarPolygons.test.js +36 -1
  142. package/src/operations/modifiers/retessellate.js +4 -2
  143. package/src/operations/modifiers/snap.test.js +24 -15
  144. package/src/operations/offsets/offsetGeom3.test.js +5 -7
  145. package/src/primitives/arc.js +2 -2
  146. package/src/primitives/arc.test.js +104 -113
  147. package/src/utils/flatten.js +1 -1
  148. package/src/utils/flatten.test.js +94 -0
@@ -13,205 +13,196 @@ test('arc (defaults)', (t) => {
13
13
  const obs = path2.toPoints(geometry)
14
14
 
15
15
  t.notThrows(() => path2.validate(geometry))
16
- t.is(obs.length, 33)
16
+ t.is(obs.length, 32)
17
17
  })
18
18
 
19
19
  test('arc (options)', (t) => {
20
20
  // test center
21
21
  let exp = [
22
22
  [3, 2],
23
- [2.9324722294043557, 2.361241666187153],
24
- [2.739008917220659, 2.6736956436465573],
25
- [2.4457383557765384, 2.8951632913550625],
26
- [2.092268359463302, 2.9957341762950342],
27
- [1.7263370099279172, 2.961825643172819],
28
- [1.3973653636207437, 2.7980172272802397],
29
- [1.1497828642703858, 2.526432162877356],
30
- [1.017026900316098, 2.1837495178165702],
31
- [1.017026900316098, 1.8162504821834298],
32
- [1.149782864270386, 1.4735678371226442],
33
- [1.3973653636207435, 1.2019827727197605],
34
- [1.726337009927917, 1.0381743568271808],
35
- [2.0922683594633016, 1.0042658237049653],
36
- [2.4457383557765384, 1.1048367086449378],
37
- [2.739008917220659, 1.326304356353443],
38
- [2.9324722294043557, 1.6387583338128469]
23
+ [2.923879532511287, 2.3826834323650896],
24
+ [2.7071067811865475, 2.7071067811865475],
25
+ [2.3826834323650896, 2.923879532511287],
26
+ [2, 3],
27
+ [1.6173165676349104, 2.923879532511287],
28
+ [1.2928932188134525, 2.7071067811865475],
29
+ [1.0761204674887133, 2.38268343236509],
30
+ [1, 2],
31
+ [1.076120467488713, 1.6173165676349104],
32
+ [1.2928932188134523, 1.2928932188134525],
33
+ [1.6173165676349097, 1.0761204674887135],
34
+ [2, 1],
35
+ [2.38268343236509, 1.0761204674887135],
36
+ [2.7071067811865475, 1.2928932188134523],
37
+ [2.9238795325112865, 1.6173165676349095]
39
38
  ]
40
39
  let geometry = arc({ center: [2, 2], segments: 16 })
41
40
  let obs = path2.toPoints(geometry)
42
41
 
43
42
  t.notThrows(() => path2.validate(geometry))
44
- t.is(obs.length, 17)
43
+ t.is(obs.length, 16)
45
44
  t.true(comparePoints(obs, exp))
46
45
 
47
46
  // test radius
48
47
  exp = [
49
48
  [2, 0],
50
- [1.8649444588087116, 0.7224833323743058],
51
- [1.4780178344413182, 1.3473912872931144],
52
- [0.8914767115530766, 1.7903265827101247],
53
- [0.18453671892660403, 1.991468352590069],
54
- [-0.5473259801441658, 1.923651286345638],
55
- [-1.2052692727585126, 1.5960344545604792],
56
- [-1.7004342714592284, 1.0528643257547114],
57
- [-1.9659461993678036, 0.36749903563314074],
58
- [-1.9659461993678036, -0.36749903563314024],
59
- [-1.7004342714592282, -1.0528643257547117],
60
- [-1.205269272758513, -1.596034454560479],
61
- [-0.5473259801441662, -1.923651286345638],
62
- [0.1845367189266031, -1.9914683525900692],
63
- [0.8914767115530771, -1.7903265827101245],
64
- [1.4780178344413184, -1.3473912872931142],
65
- [1.8649444588087116, -0.7224833323743061]
49
+ [1.8477590650225735, 0.7653668647301796],
50
+ [1.4142135623730951, 1.414213562373095],
51
+ [0.7653668647301797, 1.8477590650225735],
52
+ [0, 2],
53
+ [-0.7653668647301795, 1.8477590650225735],
54
+ [-1.414213562373095, 1.4142135623730951],
55
+ [-1.8477590650225735, 0.7653668647301798],
56
+ [-2, 0],
57
+ [-1.8477590650225737, -0.7653668647301793],
58
+ [-1.4142135623730954, -1.414213562373095],
59
+ [-0.7653668647301807, -1.847759065022573],
60
+ [0, -2],
61
+ [0.76536686473018, -1.8477590650225733],
62
+ [1.4142135623730947, -1.4142135623730954],
63
+ [1.847759065022573, -0.7653668647301808]
66
64
  ]
67
65
  geometry = arc({ radius: 2, segments: 16 })
68
66
  obs = path2.toPoints(geometry)
69
67
 
70
68
  t.notThrows(() => path2.validate(geometry))
71
- t.is(obs.length, 17)
69
+ t.is(obs.length, 16)
72
70
  t.true(comparePoints(obs, exp))
73
71
 
74
72
  // test startAngle
75
73
  exp = [
76
- [6.123233995736766e-17, 1],
77
- [-0.3546048870425357, 0.9350162426854148],
78
- [-0.6631226582407953, 0.748510748171101],
79
- [-0.8854560256532098, 0.4647231720437687],
80
- [-0.992708874098054, 0.12053668025532308],
81
- [-0.970941817426052, -0.23931566428755788],
82
- [-0.8229838658936566, -0.5680647467311556],
83
- [-0.5680647467311559, -0.8229838658936564],
84
- [-0.23931566428755774, -0.970941817426052],
85
- [0.1205366802553232, -0.992708874098054],
86
- [0.4647231720437688, -0.8854560256532098],
87
- [0.7485107481711007, -0.6631226582407955],
88
- [0.9350162426854147, -0.35460488704253595],
89
- [1, -2.4492935982947064e-16]
74
+ [0, 1],
75
+ [-0.3826834323650897, 0.9238795325112867],
76
+ [-0.7071067811865475, 0.7071067811865476],
77
+ [-0.9238795325112867, 0.3826834323650899],
78
+ [-1, 0],
79
+ [-0.9238795325112868, -0.38268343236508967],
80
+ [-0.7071067811865477, -0.7071067811865475],
81
+ [-0.38268343236509034, -0.9238795325112865],
82
+ [0, -1],
83
+ [0.38268343236509, -0.9238795325112866],
84
+ [0.7071067811865474, -0.7071067811865477],
85
+ [0.9238795325112865, -0.3826834323650904],
86
+ [1, 0]
90
87
  ]
91
88
  geometry = arc({ startAngle: TAU / 4, segments: 16 })
92
89
  obs = path2.toPoints(geometry)
93
90
 
94
91
  t.notThrows(() => path2.validate(geometry))
95
- t.is(obs.length, 14)
92
+ t.is(obs.length, 13)
96
93
  t.true(comparePoints(obs, exp))
97
94
 
98
95
  // test endAngle
99
96
  exp = [
100
97
  [1, 0],
101
- [0.9510565162951535, 0.3090169943749474],
102
- [0.8090169943749475, 0.5877852522924731],
103
- [0.5877852522924731, 0.8090169943749475],
104
- [0.30901699437494745, 0.9510565162951535],
105
- [6.123233995736766e-17, 1]
98
+ [0.9238795325112867, 0.3826834323650898],
99
+ [0.7071067811865476, 0.7071067811865475],
100
+ [0.38268343236508984, 0.9238795325112867],
101
+ [0, 1]
106
102
  ]
107
103
  geometry = arc({ endAngle: TAU / 4, segments: 16 })
108
104
  obs = path2.toPoints(geometry)
109
105
 
110
106
  t.notThrows(() => path2.validate(geometry))
111
- t.is(obs.length, 6)
107
+ t.is(obs.length, 5)
112
108
  t.true(comparePoints(obs, exp))
113
109
 
114
110
  // test makeTangent
115
111
  exp = [
116
112
  [1, 0],
117
- [0.9957341762950345, 0.09226835946330199],
118
- [0.8999557329057603, 0.43598128263728936],
119
- [0.6896020498551045, 0.7241885202318785],
120
- [0.391453692861967, 0.9201978082699006],
121
- [0.04346855052920052, 0.9990547958520045],
122
- [-0.31005066355011174, 0.9507200355689026],
123
- [-0.6240966815770753, 0.781347126470996],
124
- [-0.858687650595474, 0.5124992865505523],
125
- [-0.9839573055048071, 0.1784040945262181],
126
- [-0.9839573055048071, -0.1784040945262183],
127
- [-0.8586876505954741, -0.5124992865505521],
128
- [-0.6240966815770755, -0.7813471264709959],
129
- [-0.3100506635501122, -0.9507200355689025],
130
- [0.04346855052920005, -0.9990547958520045],
131
- [0.39145369286196696, -0.9201978082699006],
132
- [0.6896020498551043, -0.7241885202318787],
133
- [0.8999557329057604, -0.435981282637289],
134
- [0.9957341762950345, -0.09226835946330197]
113
+ [0.9951847266721969, 0.0980171403295606],
114
+ [0.8876396204028539, 0.46053871095824],
115
+ [0.6531728429537769, 0.7572088465064846],
116
+ [0.325310292162263, 0.9456073253805213],
117
+ [-0.04906767432741801, 0.9987954562051724],
118
+ [-0.416429560097637, 0.9091679830905225],
119
+ [-0.7242470829514668, 0.689540544737067],
120
+ [-0.9285060804732155, 0.3713171939518377],
121
+ [-1, 0],
122
+ [-0.9285060804732156, -0.37131719395183743],
123
+ [-0.724247082951467, -0.6895405447370668],
124
+ [-0.4164295600976372, -0.9091679830905224],
125
+ [-0.04906767432741803, -0.9987954562051724],
126
+ [0.3253102921622629, -0.9456073253805213],
127
+ [0.6531728429537768, -0.7572088465064846],
128
+ [0.8876396204028539, -0.46053871095823995],
129
+ [0.9951847266721969, -0.0980171403295605]
135
130
  ]
136
131
  geometry = arc({ makeTangent: true, segments: 16 })
137
132
  obs = path2.toPoints(geometry)
138
133
 
139
134
  t.notThrows(() => path2.validate(geometry))
140
- t.is(obs.length, 19)
135
+ t.is(obs.length, 18)
141
136
  t.true(comparePoints(obs, exp))
142
137
 
143
138
  // test segments
144
139
  exp = [
145
140
  [1, 0],
146
- [0.766044443118978, 0.6427876096865393],
147
- [0.17364817766693041, 0.984807753012208],
148
- [-0.4999999999999998, 0.8660254037844387],
149
- [-0.9396926207859083, 0.3420201433256689],
150
- [-0.9396926207859084, -0.34202014332566866],
151
- [-0.5000000000000004, -0.8660254037844385],
152
- [0.17364817766692997, -0.9848077530122081],
153
- [0.7660444431189778, -0.6427876096865396]
141
+ [0.7071067811865476, 0.7071067811865475],
142
+ [0, 1],
143
+ [-0.7071067811865475, 0.7071067811865476],
144
+ [-1, 0],
145
+ [-0.7071067811865477, -0.7071067811865475],
146
+ [0, -1],
147
+ [0.7071067811865474, -0.7071067811865477]
154
148
  ]
155
149
  geometry = arc({ segments: 8 })
156
150
  obs = path2.toPoints(geometry)
157
151
 
158
152
  t.notThrows(() => path2.validate(geometry))
159
- t.is(obs.length, 9)
153
+ t.is(obs.length, 8)
160
154
  t.true(comparePoints(obs, exp))
161
155
  })
162
156
 
163
157
  test('arc (rotations)', (t) => {
164
158
  let exp = [
165
- [6.123233995736766e-17, 1],
166
- [-0.30901699437494734, 0.9510565162951536],
167
- [-0.587785252292473, 0.8090169943749475],
168
- [-0.8090169943749473, 0.5877852522924732],
169
- [-0.9510565162951535, 0.3090169943749475],
170
- [-1, 1.2246467991473532e-16]
159
+ [0, 1],
160
+ [-0.3826834323650897, 0.9238795325112867],
161
+ [-0.7071067811865475, 0.7071067811865476],
162
+ [-0.9238795325112867, 0.3826834323650899],
163
+ [-1, 0]
171
164
  ]
172
165
  let geometry = arc({ startAngle: TAU / 4, endAngle: TAU / 2, segments: 16 })
173
166
  let obs = path2.toPoints(geometry)
174
167
 
175
168
  t.notThrows(() => path2.validate(geometry))
176
- t.is(obs.length, 6)
169
+ t.is(obs.length, 5)
177
170
  t.true(comparePoints(obs, exp))
178
171
 
179
172
  exp = [
180
- [-1, 1.2246467991473532e-16],
181
- [-0.9396926207859084, -0.34202014332566866],
182
- [-0.7660444431189781, -0.6427876096865393],
183
- [-0.5000000000000004, -0.8660254037844385],
184
- [-0.17364817766693033, -0.984807753012208],
185
- [0.17364817766692997, -0.9848077530122081],
186
- [0.49999999999999933, -0.866025403784439],
187
- [0.7660444431189778, -0.6427876096865396],
188
- [0.9396926207859084, -0.3420201433256686],
189
- [1, -2.4492935982947064e-16]
173
+ [-1, 0],
174
+ [-0.9238795325112868, -0.38268343236508967],
175
+ [-0.7071067811865477, -0.7071067811865475],
176
+ [-0.38268343236509034, -0.9238795325112865],
177
+ [0, -1],
178
+ [0.38268343236509, -0.9238795325112866],
179
+ [0.7071067811865474, -0.7071067811865477],
180
+ [0.9238795325112865, -0.3826834323650904],
181
+ [1, 0]
190
182
  ]
191
183
  geometry = arc({ startAngle: TAU / 2, endAngle: TAU, segments: 16 })
192
184
  obs = path2.toPoints(geometry)
193
185
 
194
186
  t.notThrows(() => path2.validate(geometry))
195
- t.is(obs.length, 10)
187
+ t.is(obs.length, 9)
196
188
  t.true(comparePoints(obs, exp))
197
189
 
198
190
  exp = [
199
- [-1.8369701987210297e-16, -1],
200
- [0.34202014332566816, -0.9396926207859085],
201
- [0.6427876096865393, -0.7660444431189781],
202
- [0.8660254037844384, -0.5000000000000004],
203
- [0.984807753012208, -0.1736481776669304],
204
- [0.9848077530122081, 0.17364817766692991],
205
- [0.866025403784439, 0.4999999999999993],
206
- [0.6427876096865396, 0.7660444431189778],
207
- [0.34202014332566866, 0.9396926207859084],
208
- [3.061616997868383e-16, 1]
191
+ [0, -1],
192
+ [0.38268343236509, -0.9238795325112866],
193
+ [0.7071067811865474, -0.7071067811865477],
194
+ [0.9238795325112865, -0.3826834323650904],
195
+ [1, 0],
196
+ [0.9238795325112867, 0.38268343236508995],
197
+ [0.7071067811865477, 0.7071067811865474],
198
+ [0.38268343236509045, 0.9238795325112865],
199
+ [0, 1]
209
200
  ]
210
201
  geometry = arc({ startAngle: TAU * 0.75, endAngle: TAU / 4, segments: 16 })
211
202
  obs = path2.toPoints(geometry)
212
203
 
213
204
  t.notThrows(() => path2.validate(geometry))
214
- t.is(obs.length, 10)
205
+ t.is(obs.length, 9)
215
206
  t.true(comparePoints(obs, exp))
216
207
 
217
208
  exp = [[-1.8369701987210297e-16, -1]]
@@ -5,4 +5,4 @@
5
5
  * @returns {Array} a flat list of arguments
6
6
  * @alias module:modeling/utils.flatten
7
7
  */
8
- export const flatten = (arr) => arr.reduce((acc, val) => Array.isArray(val) ? acc.concat(flatten(val)) : acc.concat(val), [])
8
+ export const flatten = (arr) => arr.flat(Infinity)
@@ -0,0 +1,94 @@
1
+ import test from 'ava'
2
+
3
+ import { flatten } from './index.js'
4
+
5
+ test('flatten: test an empty array returns empty.', (t) => {
6
+ t.deepEqual(flatten([]), [])
7
+ })
8
+
9
+ test('flatten: test a flat array is unchanged.', (t) => {
10
+ t.deepEqual(flatten([1, 2, 3]), [1, 2, 3])
11
+ })
12
+
13
+ test('flatten: test single level nesting is flattened.', (t) => {
14
+ t.deepEqual(flatten([1, [2, 3], 4]), [1, 2, 3, 4])
15
+ t.deepEqual(flatten([[1, 2], [3, 4]]), [1, 2, 3, 4])
16
+ t.deepEqual(flatten([[1], [2], [3]]), [1, 2, 3])
17
+ })
18
+
19
+ test('flatten: test deep nesting is flattened.', (t) => {
20
+ t.deepEqual(flatten([1, [2, [3, [4]]]]), [1, 2, 3, 4])
21
+ t.deepEqual(flatten([[[[1]]]]), [1])
22
+ t.deepEqual(flatten([1, [2, [3, [4, [5]]]]]), [1, 2, 3, 4, 5])
23
+ })
24
+
25
+ test('flatten: test mixed nesting depths are flattened.', (t) => {
26
+ t.deepEqual(flatten([1, [2, 3], [[4, 5]], [[[6]]]]), [1, 2, 3, 4, 5, 6])
27
+ })
28
+
29
+ test('flatten: test empty nested arrays are removed.', (t) => {
30
+ t.deepEqual(flatten([[]]), [])
31
+ t.deepEqual(flatten([[], []]), [])
32
+ t.deepEqual(flatten([1, [], 2]), [1, 2])
33
+ t.deepEqual(flatten([[], [1], []]), [1])
34
+ })
35
+
36
+ test('flatten: test single element arrays are flattened.', (t) => {
37
+ t.deepEqual(flatten([1]), [1])
38
+ t.deepEqual(flatten([[1]]), [1])
39
+ t.deepEqual(flatten([[[1]]]), [1])
40
+ })
41
+
42
+ test('flatten: test element order is preserved.', (t) => {
43
+ t.deepEqual(flatten([1, [2, 3], 4, [5, 6]]), [1, 2, 3, 4, 5, 6])
44
+ t.deepEqual(flatten([[1, 2], 3, [4, [5, 6]]]), [1, 2, 3, 4, 5, 6])
45
+ })
46
+
47
+ test('flatten: test object references are preserved.', (t) => {
48
+ const obj1 = { id: 1 }
49
+ const obj2 = { id: 2 }
50
+ const obj3 = { id: 3 }
51
+ const result = flatten([obj1, [obj2, obj3]])
52
+ t.is(result[0], obj1)
53
+ t.is(result[1], obj2)
54
+ t.is(result[2], obj3)
55
+ })
56
+
57
+ test('flatten: test various types are preserved.', (t) => {
58
+ const obj = { a: 1 }
59
+ const fn = () => {}
60
+ t.deepEqual(flatten([1, 'string', null, undefined, true]), [1, 'string', null, undefined, true])
61
+
62
+ const result = flatten([obj, [fn]])
63
+ t.is(result[0], obj)
64
+ t.is(result[1], fn)
65
+ })
66
+
67
+ test('flatten: test large flat array is unchanged.', (t) => {
68
+ const large = []
69
+ for (let i = 0; i < 1000; i++) {
70
+ large.push(i)
71
+ }
72
+ const result = flatten(large)
73
+ t.is(result.length, 1000)
74
+ t.is(result[0], 0)
75
+ t.is(result[999], 999)
76
+ })
77
+
78
+ test('flatten: test large nested array is flattened.', (t) => {
79
+ const nested = []
80
+ for (let i = 0; i < 100; i++) {
81
+ nested.push([i * 10, i * 10 + 1, i * 10 + 2])
82
+ }
83
+ const result = flatten(nested)
84
+ t.is(result.length, 300)
85
+ t.is(result[0], 0)
86
+ t.is(result[3], 10)
87
+ })
88
+
89
+ test('flatten: test input array is not modified.', (t) => {
90
+ const input = [1, [2, 3], 4]
91
+ const inputCopy = JSON.stringify(input)
92
+ flatten(input)
93
+ t.is(JSON.stringify(input), inputCopy)
94
+ })