From c59130c754c7119bc0ef9937a8b96b309c95f36d Mon Sep 17 00:00:00 2001 From: Emmett Lalish Date: Thu, 27 Oct 2022 10:01:08 -0700 Subject: [PATCH] Adding NodeJS tests for WASM module (#262) * modularize wasm and add mocha tests * add npm tests to CI * fix mv command * revert to build directory * added rest of example tests * fixed three.js test * update web examples for module --- .github/workflows/manifold.yml | 3 + .gitignore | 1 + bindings/wasm/CMakeLists.txt | 9 +- bindings/wasm/examples/editor.js | 12 +- bindings/wasm/examples/examples.js | 734 +++++----- bindings/wasm/examples/model-viewer.html | 70 +- bindings/wasm/examples/three.html | 95 +- bindings/wasm/examples/worker.js | 82 +- bindings/wasm/package-lock.json | 1705 ++++++++++++++++++++++ bindings/wasm/package.json | 14 +- bindings/wasm/test/test.js | 152 ++ 11 files changed, 2376 insertions(+), 501 deletions(-) create mode 100644 bindings/wasm/package-lock.json create mode 100644 bindings/wasm/test/test.js diff --git a/.github/workflows/manifold.yml b/.github/workflows/manifold.yml index 26701d0f3..d61324f63 100644 --- a/.github/workflows/manifold.yml +++ b/.github/workflows/manifold.yml @@ -97,6 +97,9 @@ jobs: run: | cd build/test node ./manifold_test.js + cd ../bindings/wasm + npm install + npm test - name: Upload WASM files uses: actions/upload-artifact@v3 with: diff --git a/.gitignore b/.gitignore index cec57bc9f..5a82a9f33 100644 --- a/.gitignore +++ b/.gitignore @@ -108,5 +108,6 @@ Temporary Items build buildWASM docs/html +node_modules/ __pycache__ .vscode/c_cpp_properties.json \ No newline at end of file diff --git a/bindings/wasm/CMakeLists.txt b/bindings/wasm/CMakeLists.txt index f994c89a5..b076abdb0 100644 --- a/bindings/wasm/CMakeLists.txt +++ b/bindings/wasm/CMakeLists.txt @@ -21,12 +21,11 @@ set_source_files_properties(bindings.cpp OBJECT_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bindings.js) target_link_libraries(manifoldjs manifold sdf) target_compile_options(manifoldjs PRIVATE ${MANIFOLD_FLAGS} -fexceptions) -target_link_options(manifoldjs PUBLIC --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/bindings.js --bind -s ALLOW_TABLE_GROWTH=1 - -sEXPORTED_RUNTIME_METHODS=addFunction,removeFunction) +target_link_options(manifoldjs PUBLIC --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/bindings.js --bind -sALLOW_TABLE_GROWTH=1 + -sEXPORTED_RUNTIME_METHODS=addFunction,removeFunction -sMODULARIZE=1) target_compile_features(manifoldjs PUBLIC cxx_std_14) set_target_properties(manifoldjs PROPERTIES OUTPUT_NAME "manifold") -file(GLOB_RECURSE WEB_FILES CONFIGURE_DEPENDS *.html *.ts) -file(COPY ${WEB_FILES} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) -set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${WEB_FILES}) +file(COPY examples;test;. DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS examples;test) diff --git a/bindings/wasm/examples/editor.js b/bindings/wasm/examples/editor.js index 49615f39f..bed517118 100644 --- a/bindings/wasm/examples/editor.js +++ b/bindings/wasm/examples/editor.js @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +const exampleFunctions = examples.functionBodies; + let editor = undefined; // File UI ------------------------------------------------------------ @@ -53,7 +55,7 @@ function nthKey(n) { function saveCurrent() { if (editor) { const currentName = currentElement.textContent; - if (!examples.get(currentName)) { + if (!exampleFunctions.get(currentName)) { setScript(currentName, editor.getValue()); } } @@ -69,8 +71,8 @@ function switchTo(scriptName) { switching = true; currentElement.textContent = scriptName; setScript('currentName', scriptName); - const code = examples.get(scriptName) ?? getScript(scriptName) ?? ''; - isExample = examples.get(scriptName) != null; + const code = exampleFunctions.get(scriptName) ?? getScript(scriptName) ?? ''; + isExample = exampleFunctions.get(scriptName) != null; editor.setValue(code); } } @@ -103,7 +105,7 @@ function addIcon(button) { function uniqueName(name) { let num = 1; let newName = name; - while (getScript(newName) != null || examples.get(newName) != null) { + while (getScript(newName) != null || exampleFunctions.get(newName) != null) { newName = name + ' ' + num++; } return newName; @@ -214,7 +216,7 @@ require(['vs/editor/editor.main'], async function () { const w = await monaco.languages.typescript.getTypeScriptWorker(); tsWorker = await w(editor.getModel().uri); - for (const [name] of examples) { + for (const [name] of exampleFunctions) { const button = createDropdownItem(name); dropdown.appendChild(button.parentElement); } diff --git a/bindings/wasm/examples/examples.js b/bindings/wasm/examples/examples.js index 99e099f87..e3f9e8fe7 100644 --- a/bindings/wasm/examples/examples.js +++ b/bindings/wasm/examples/examples.js @@ -12,411 +12,415 @@ // See the License for the specific language governing permissions and // limitations under the License. -const exampleFunctions = { - Intro: function () { - // Write code in JavaScript or TypeScript and this editor will show the API docs. - // Type e.g. "box." to see the Manifold API. - // Type "Module." to see the static API - these functions can also be used bare. - // Use console.log() to print output (lower-right). - // This editor defines Z as up and units of mm. - - const box = cube([100, 100, 100], true); - const ball = sphere(60, 100); - // You must name your final output "result". - const result = box.subtract(ball); - - // All changes are automatically saved and restored between sessions. - // This app is purely local - there is no server communication. - // This means it will work equally well offline once loaded. - // To share your code with another browser/device, simply copy the text to a file. - return result; - }, - - TetrahedronPuzzle: function () { - // A tetrahedron cut into two identical halves that can screw together as a - // puzzle. This only outputs one of the halves. This demonstrates how - // redundant points along a polygon can be used to make twisted extrusions - // smoother. Based on the screw puzzle by George Hart: - // https://www.thingiverse.com/thing:186372 - - const edgeLength = 50;// Length of each edge of the overall tetrahedron. - const gap = 0.2;// Spacing between the two halves to allow sliding. - const nDivisions = 50;// Number of divisions (both ways) in the screw surface. - - const scale = edgeLength / (2 * Math.sqrt(2)); - - const tet = tetrahedron().scale(scale); - - const box = []; - box.push([2, -2], [2, 2]); - for (let i = 0; i <= nDivisions; ++i) { - box.push([gap / (2 * scale), 2 - i * 4 / nDivisions]); - } +(function (exports) { + + exports.functions = { + Intro: function () { + // Write code in JavaScript or TypeScript and this editor will show the API docs. + // Type e.g. "box." to see the Manifold API. + // Type "Module." to see the static API - these functions can also be used bare. + // Use console.log() to print output (lower-right). + // This editor defines Z as up and units of mm. + + const box = cube([100, 100, 100], true); + const ball = sphere(60, 100); + // You must name your final output "result". + const result = box.subtract(ball); + + // All changes are automatically saved and restored between sessions. + // This app is purely local - there is no server communication. + // This means it will work equally well offline once loaded. + // To share your code with another browser/device, simply copy the text to a file. + return result; + }, - const screw = extrude(box, 2, nDivisions, 270) - .rotate([0, 0, -45]) - .translate([0, 0, -1]) - .scale(scale); + TetrahedronPuzzle: function () { + // A tetrahedron cut into two identical halves that can screw together as a + // puzzle. This only outputs one of the halves. This demonstrates how + // redundant points along a polygon can be used to make twisted extrusions + // smoother. Based on the screw puzzle by George Hart: + // https://www.thingiverse.com/thing:186372 - const result = tet.intersect(screw); - return result; - }, + const edgeLength = 50;// Length of each edge of the overall tetrahedron. + const gap = 0.2;// Spacing between the two halves to allow sliding. + const nDivisions = 50;// Number of divisions (both ways) in the screw surface. - RoundedFrame: function () { - // Demonstrates how at 90-degree intersections, the sphere and cylinder facets - // match up perfectly, for any choice of global resolution parameters. + const scale = edgeLength / (2 * Math.sqrt(2)); - function roundedFrame(edgeLength, radius, circularSegments = 0) { - const edge = cylinder(edgeLength, radius, -1, circularSegments); - const corner = sphere(radius, circularSegments); + const tet = tetrahedron().scale(scale); - let edge1 = union(corner, edge); - edge1 = edge1.rotate([-90, 0, 0]).translate([-edgeLength / 2, -edgeLength / 2, 0]); + const box = []; + box.push([2, -2], [2, 2]); + for (let i = 0; i <= nDivisions; ++i) { + box.push([gap / (2 * scale), 2 - i * 4 / nDivisions]); + } - let edge2 = edge1.rotate([0, 0, 180]); - edge2 = union(edge2, edge1); - edge2 = union(edge2, edge.translate([-edgeLength / 2, -edgeLength / 2, 0])); + const screw = extrude(box, 2, nDivisions, 270) + .rotate([0, 0, -45]) + .translate([0, 0, -1]) + .scale(scale); - let edge4 = edge2.rotate([0, 0, 90]); - edge4 = union(edge4, edge2); + const result = tet.intersect(screw); + return result; + }, - let frame = edge4.translate([0, 0, -edgeLength / 2]); - frame = union(frame, frame.rotate([180, 0, 0])); + RoundedFrame: function () { + // Demonstrates how at 90-degree intersections, the sphere and cylinder facets + // match up perfectly, for any choice of global resolution parameters. - return frame; - } + function roundedFrame(edgeLength, radius, circularSegments = 0) { + const edge = cylinder(edgeLength, radius, -1, circularSegments); + const corner = sphere(radius, circularSegments); - setMinCircularAngle(3); - setMinCircularEdgeLength(0.5); - const result = roundedFrame(100, 10); - return result; - }, - - Heart: function () { - // Smooth, complex manifolds can be created using the warp() function. This - // example recreates the Exploitable Heart by Emmett Lalish: - // https://www.thingiverse.com/thing:6190 - - const func = (v) => { - const x2 = v[0] * v[0]; - const y2 = v[1] * v[1]; - const z = v[2]; - const z2 = z * z; - const a = x2 + 9 / 4 * y2 + z2; - const b = z * z2 * (x2 + 9 / 80 * y2); - const a2 = a * a; - const a3 = a * a2; - - const step = (r) => { - const r2 = r * r; - const r4 = r2 * r2; - // Taubin's function: https://mathworld.wolfram.com/HeartSurface.html - const f = a3 * r4 * r2 - b * r4 * r - 3 * a2 * r4 + 3 * a * r2 - 1; - // Derivative - const df = 6 * a3 * r4 * r - 5 * b * r4 - 12 * a2 * r2 * r + 6 * a * r; - return f / df; - }; - // Newton's method for root finding - let r = 1.5; - let dr = 1; - while (Math.abs(dr) > 0.0001) { - dr = step(r); - r -= dr; - } - // Update radius - v[0] *= r; - v[1] *= r; - v[2] *= r; - }; - - const ball = sphere(1, 200); - const heart = ball.warp(func); - const box = heart.boundingBox(); - const result = heart.scale(100 / (box.max[0] - box.min[0])); - return result; - }, - - Scallop: function () { - // A smoothed manifold demonstrating selective edge sharpening with smooth() - // and refine(), see more details at: - // https://elalish.blogspot.com/2022/03/smoothing-triangle-meshes.html - - const height = 10; - const radius = 30; - const offset = 20; - const wiggles = 12; - const sharpness = 0.8; - const n = 50; - - const scallop = { - vertPos: [], - triVerts: [] - }; - scallop.vertPos.push([-offset, 0, height], [-offset, 0, -height]); - const sharpenedEdges = []; - - const delta = 3.14159 / wiggles; - for (let i = 0; i < 2 * wiggles; ++i) { - const theta = (i - wiggles) * delta; - const amp = 0.5 * height * Math.max(Math.cos(0.8 * theta), 0); - - scallop.vertPos.push([radius * Math.cos(theta), - radius * Math.sin(theta), - amp * (i % 2 == 0 ? 1 : -1)]); - let j = i + 1; - if (j == 2 * wiggles) j = 0; - - const smoothness = 1 - sharpness * Math.cos((theta + delta / 2) / 2); - let halfedge = 3 * scallop.triVerts.length + 1; - sharpenedEdges.push({ halfedge, smoothness }); - scallop.triVerts.push([0, 2 + i, 2 + j]); - - halfedge = 3 * scallop.triVerts.length + 1; - sharpenedEdges.push({ halfedge, smoothness }); - scallop.triVerts.push([1, 2 + j, 2 + i]); - } + let edge1 = union(corner, edge); + edge1 = edge1.rotate([-90, 0, 0]).translate([-edgeLength / 2, -edgeLength / 2, 0]); - const result = smooth(scallop, sharpenedEdges).refine(n); - return result; - }, - - TorusKnot: function () { - // Creates a classic torus knot, defined as a string wrapping periodically - // around the surface of an imaginary donut. If p and q have a common factor - // then you will get multiple separate, interwoven knots. This is an example of - // using the warp() method, thus avoiding any direct handling of triangles. - - // @param p The number of times the thread passes through the donut hole. - // @param q The number of times the thread circles the donut. - // @param majorRadius Radius of the interior of the imaginary donut. - // @param minorRadius Radius of the small cross-section of the imaginary donut. - // @param threadRadius Radius of the small cross-section of the actual object. - // @param circularSegments Number of linear segments making up the threadRadius - // circle. Default is getCircularSegments(threadRadius). - // @param linearSegments Number of segments along the length of the knot. - // Default makes roughly square facets. - - function torusKnot(p, q, majorRadius, minorRadius, - threadRadius, circularSegments = 0, - linearSegments = 0) { - function gcd(a, b) { - return b == 0 ? a : gcd(b, a % b); - } + let edge2 = edge1.rotate([0, 0, 180]); + edge2 = union(edge2, edge1); + edge2 = union(edge2, edge.translate([-edgeLength / 2, -edgeLength / 2, 0])); + + let edge4 = edge2.rotate([0, 0, 90]); + edge4 = union(edge4, edge2); - const kLoops = gcd(p, q); - p /= kLoops; - q /= kLoops; - const n = circularSegments > 2 ? circularSegments : - getCircularSegments(threadRadius); - const m = linearSegments > 2 ? linearSegments : - n * q * majorRadius / threadRadius; - - const circle = []; - const dPhi = 2 * 3.14159 / n; - const offset = 2; - for (let i = 0; i < n; ++i) { - circle.push([Math.cos(dPhi * i) + offset, Math.sin(dPhi * i)]); + let frame = edge4.translate([0, 0, -edgeLength / 2]); + frame = union(frame, frame.rotate([180, 0, 0])); + + return frame; } - const point = new THREE.Vector3(); - const axis = new THREE.Vector3(); + setMinCircularAngle(3); + setMinCircularEdgeLength(0.5); + const result = roundedFrame(100, 10); + return result; + }, + + Heart: function () { + // Smooth, complex manifolds can be created using the warp() function. This + // example recreates the Exploitable Heart by Emmett Lalish: + // https://www.thingiverse.com/thing:6190 const func = (v) => { - const psi = q * Math.atan2(v[0], v[1]); - const theta = psi * p / q; - const x1 = Math.sqrt(v[0] * v[0] + v[1] * v[1]); - const phi = Math.atan2(x1 - offset, v[2]); - point.set(Math.cos(phi), 0, Math.sin(phi)).multiplyScalar(threadRadius); - const r = majorRadius + minorRadius * Math.cos(theta); - point.applyAxisAngle(axis.set(1, 0, 0), -Math.atan2(p * minorRadius, q * r)); - point.x += minorRadius; - point.applyAxisAngle(axis.set(0, 1, 0), theta); - point.x += majorRadius; - point.applyAxisAngle(axis.set(0, 0, 1), psi); - v[0] = point.x; - v[1] = point.y; - v[2] = point.z; + const x2 = v[0] * v[0]; + const y2 = v[1] * v[1]; + const z = v[2]; + const z2 = z * z; + const a = x2 + 9 / 4 * y2 + z2; + const b = z * z2 * (x2 + 9 / 80 * y2); + const a2 = a * a; + const a3 = a * a2; + + const step = (r) => { + const r2 = r * r; + const r4 = r2 * r2; + // Taubin's function: https://mathworld.wolfram.com/HeartSurface.html + const f = a3 * r4 * r2 - b * r4 * r - 3 * a2 * r4 + 3 * a * r2 - 1; + // Derivative + const df = 6 * a3 * r4 * r - 5 * b * r4 - 12 * a2 * r2 * r + 6 * a * r; + return f / df; + }; + // Newton's method for root finding + let r = 1.5; + let dr = 1; + while (Math.abs(dr) > 0.0001) { + dr = step(r); + r -= dr; + } + // Update radius + v[0] *= r; + v[1] *= r; + v[2] *= r; + }; + + const ball = sphere(1, 200); + const heart = ball.warp(func); + const box = heart.boundingBox(); + const result = heart.scale(100 / (box.max[0] - box.min[0])); + return result; + }, + + Scallop: function () { + // A smoothed manifold demonstrating selective edge sharpening with smooth() + // and refine(), see more details at: + // https://elalish.blogspot.com/2022/03/smoothing-triangle-meshes.html + + const height = 10; + const radius = 30; + const offset = 20; + const wiggles = 12; + const sharpness = 0.8; + const n = 50; + + const scallop = { + vertPos: [], + triVerts: [] + }; + scallop.vertPos.push([-offset, 0, height], [-offset, 0, -height]); + const sharpenedEdges = []; + + const delta = 3.14159 / wiggles; + for (let i = 0; i < 2 * wiggles; ++i) { + const theta = (i - wiggles) * delta; + const amp = 0.5 * height * Math.max(Math.cos(0.8 * theta), 0); + + scallop.vertPos.push([radius * Math.cos(theta), + radius * Math.sin(theta), + amp * (i % 2 == 0 ? 1 : -1)]); + let j = i + 1; + if (j == 2 * wiggles) j = 0; + + const smoothness = 1 - sharpness * Math.cos((theta + delta / 2) / 2); + let halfedge = 3 * scallop.triVerts.length + 1; + sharpenedEdges.push({ halfedge, smoothness }); + scallop.triVerts.push([0, 2 + i, 2 + j]); + + halfedge = 3 * scallop.triVerts.length + 1; + sharpenedEdges.push({ halfedge, smoothness }); + scallop.triVerts.push([1, 2 + j, 2 + i]); } - let knot = revolve(circle, m).warp(func); + const result = smooth(scallop, sharpenedEdges).refine(n); + return result; + }, + + TorusKnot: function () { + // Creates a classic torus knot, defined as a string wrapping periodically + // around the surface of an imaginary donut. If p and q have a common factor + // then you will get multiple separate, interwoven knots. This is an example of + // using the warp() method, thus avoiding any direct handling of triangles. + + // @param p The number of times the thread passes through the donut hole. + // @param q The number of times the thread circles the donut. + // @param majorRadius Radius of the interior of the imaginary donut. + // @param minorRadius Radius of the small cross-section of the imaginary donut. + // @param threadRadius Radius of the small cross-section of the actual object. + // @param circularSegments Number of linear segments making up the threadRadius + // circle. Default is getCircularSegments(threadRadius). + // @param linearSegments Number of segments along the length of the knot. + // Default makes roughly square facets. + + function torusKnot(p, q, majorRadius, minorRadius, + threadRadius, circularSegments = 0, + linearSegments = 0) { + function gcd(a, b) { + return b == 0 ? a : gcd(b, a % b); + } + + const kLoops = gcd(p, q); + p /= kLoops; + q /= kLoops; + const n = circularSegments > 2 ? circularSegments : + getCircularSegments(threadRadius); + const m = linearSegments > 2 ? linearSegments : + n * q * majorRadius / threadRadius; + + const circle = []; + const dPhi = 2 * 3.14159 / n; + const offset = 2; + for (let i = 0; i < n; ++i) { + circle.push([Math.cos(dPhi * i) + offset, Math.sin(dPhi * i)]); + } + + const point = new THREE.Vector3(); + const axis = new THREE.Vector3(); + + const func = (v) => { + const psi = q * Math.atan2(v[0], v[1]); + const theta = psi * p / q; + const x1 = Math.sqrt(v[0] * v[0] + v[1] * v[1]); + const phi = Math.atan2(x1 - offset, v[2]); + point.set(Math.cos(phi), 0, Math.sin(phi)).multiplyScalar(threadRadius); + const r = majorRadius + minorRadius * Math.cos(theta); + point.applyAxisAngle(axis.set(1, 0, 0), -Math.atan2(p * minorRadius, q * r)); + point.x += minorRadius; + point.applyAxisAngle(axis.set(0, 1, 0), theta); + point.x += majorRadius; + point.applyAxisAngle(axis.set(0, 0, 1), psi); + v[0] = point.x; + v[1] = point.y; + v[2] = point.z; + } + + let knot = revolve(circle, m).warp(func); - if (kLoops > 1) { - const knots = [] - for (let k = 0; k < kLoops; ++k) { - knots.push(knot.rotate([0, 0, 360 * (k / kLoops) * (q / p)])); + if (kLoops > 1) { + const knots = [] + for (let k = 0; k < kLoops; ++k) { + knots.push(knot.rotate([0, 0, 360 * (k / kLoops) * (q / p)])); + } + knot = compose(knots); } - knot = compose(knots); + + return knot; } - return knot; - } + // This recreates Matlab Knot by Emmett Lalish: + // https://www.thingiverse.com/thing:7080 - // This recreates Matlab Knot by Emmett Lalish: - // https://www.thingiverse.com/thing:7080 + const result = torusKnot(1, 3, 25, 10, 3.75); + return result; + }, - const result = torusKnot(1, 3, 25, 10, 3.75); - return result; - }, + MengerSponge: function () { + // This example demonstrates how symbolic perturbation correctly creates + // holes even though the subtracted objects are exactly coplanar. - MengerSponge: function () { - // This example demonstrates how symbolic perturbation correctly creates - // holes even though the subtracted objects are exactly coplanar. + function vec2add(a, b) { + return [a[0] + b[0], a[1] + b[1]]; + } - function vec2add(a, b) { - return [a[0] + b[0], a[1] + b[1]]; - } + function fractal(holes, hole, w, position, depth, maxDepth) { + w /= 3; + holes.push( + hole.scale([w, w, 1.0]).translate([position[0], position[1], 0.0])); + if (depth == maxDepth) return; + const offsets = [ + [-w, -w], [-w, 0.0], [-w, w], [0.0, w], [w, w], [w, 0.0], [w, -w], [0.0, -w] + ]; + for (let offset of offsets) + fractal(holes, hole, w, vec2add(position, offset), depth + 1, maxDepth); + } - function fractal(holes, hole, w, position, depth, maxDepth) { - w /= 3; - holes.push( - hole.scale([w, w, 1.0]).translate([position[0], position[1], 0.0])); - if (depth == maxDepth) return; - const offsets = [ - [-w, -w], [-w, 0.0], [-w, w], [0.0, w], [w, w], [w, 0.0], [w, -w], [0.0, -w] - ]; - for (let offset of offsets) - fractal(holes, hole, w, vec2add(position, offset), depth + 1, maxDepth); - } + function mengerSponge(n) { + let result = cube([1, 1, 1], true); + const holes = []; + fractal(holes, result, 1.0, [0.0, 0.0], 1, n); - function mengerSponge(n) { - let result = cube([1, 1, 1], true); - const holes = []; - fractal(holes, result, 1.0, [0.0, 0.0], 1, n); + const hole = compose(holes); - const hole = compose(holes); + result = difference(result, hole); + result = difference(result, hole.rotate([90, 0, 0])); + result = difference(result, hole.rotate([0, 90, 0])); - result = difference(result, hole); - result = difference(result, hole.rotate([90, 0, 0])); - result = difference(result, hole.rotate([0, 90, 0])); + return result; + } + const result = mengerSponge(3).scale(100); return result; - } + }, + + StretchyBracelet: function () { + // Recreates Stretchy Bracelet by Emmett Lalish: + // https://www.thingiverse.com/thing:13505 + + function base( + width, radius, decorRadius, twistRadius, + nDecor, innerRadius, outerRadius, cut, + nCut, nDivision) { + function rotate(v, theta) { + return [ + v[0] * Math.cos(theta) - v[1] * Math.sin(theta), + v[0] * Math.sin(theta) + v[1] * Math.cos(theta) + ]; + } - const result = mengerSponge(3).scale(100); - return result; - }, - - StretchyBracelet: function () { - // Recreates Stretchy Bracelet by Emmett Lalish: - // https://www.thingiverse.com/thing:13505 - - function base( - width, radius, decorRadius, twistRadius, - nDecor, innerRadius, outerRadius, cut, - nCut, nDivision) { - function rotate(v, theta) { - return [ - v[0] * Math.cos(theta) - v[1] * Math.sin(theta), - v[0] * Math.sin(theta) + v[1] * Math.cos(theta) - ]; + let b = cylinder(width, radius + twistRadius / 2); + const circle = []; + const dPhiDeg = 180 / nDivision; + for (let i = 0; i < 2 * nDivision; ++i) { + circle.push([ + decorRadius * Math.cos(dPhiDeg * i * Math.PI / 180) + twistRadius, + decorRadius * Math.sin(dPhiDeg * i * Math.PI / 180) + ]); + } + let decor = + extrude(circle, width, nDivision, 180).scale([1, 0.5, 1]).translate([ + 0, radius, 0 + ]); + for (let i = 0; i < nDecor; i++) + b = b.add(decor.rotate([0, 0, (360.0 / nDecor) * i])); + const stretch = []; + const dPhiRad = 2 * Math.PI / nCut; + + const p0 = [outerRadius, 0]; + const p1 = [innerRadius, -cut]; + const p2 = [innerRadius, cut]; + for (let i = 0; i < nCut; ++i) { + stretch.push(rotate(p0, dPhiRad * i)); + stretch.push(rotate(p1, dPhiRad * i)); + stretch.push(rotate(p2, dPhiRad * i)); + stretch.push(rotate(p0, dPhiRad * i)); + } + b = intersection(extrude(stretch, width), b); + return b; } - let b = cylinder(width, radius + twistRadius / 2); - const circle = []; - const dPhiDeg = 180 / nDivision; - for (let i = 0; i < 2 * nDivision; ++i) { - circle.push([ - decorRadius * Math.cos(dPhiDeg * i * Math.PI / 180) + twistRadius, - decorRadius * Math.sin(dPhiDeg * i * Math.PI / 180) - ]); + function stretchyBracelet( + radius = 30, height = 8, width = 15, + thickness = 0.4, nDecor = 20, nCut = 27, + nDivision = 30) { + const twistRadius = Math.PI * radius / nDecor; + const decorRadius = twistRadius * 1.5; + const outerRadius = radius + (decorRadius + twistRadius) * 0.5; + const innerRadius = outerRadius - height; + const cut = 0.5 * (Math.PI * 2 * innerRadius / nCut - thickness); + const adjThickness = 0.5 * thickness * height / cut; + + return difference( + base( + width, radius, decorRadius, twistRadius, nDecor, + innerRadius + thickness, outerRadius + adjThickness, + cut - adjThickness, nCut, nDivision), + base( + width, radius - thickness, decorRadius, twistRadius, nDecor, + innerRadius, outerRadius + 3 * adjThickness, cut, nCut, nDivision)); } - let decor = - extrude(circle, width, nDivision, 180).scale([1, 0.5, 1]).translate([ - 0, radius, 0 - ]); - for (let i = 0; i < nDecor; i++) - b = b.add(decor.rotate([0, 0, (360.0 / nDecor) * i])); - const stretch = []; - const dPhiRad = 2 * Math.PI / nCut; - - const p0 = [outerRadius, 0]; - const p1 = [innerRadius, -cut]; - const p2 = [innerRadius, cut]; - for (let i = 0; i < nCut; ++i) { - stretch.push(rotate(p0, dPhiRad * i)); - stretch.push(rotate(p1, dPhiRad * i)); - stretch.push(rotate(p2, dPhiRad * i)); - stretch.push(rotate(p0, dPhiRad * i)); + + const result = stretchyBracelet(); + return result; + }, + + GyroidModule: function () { + // Recreates Modular Gyroid Puzzle by Emmett Lalish: + // https://www.thingiverse.com/thing:25477. This sample demonstrates the use + // of a Signed Distance Function (SDF) to create smooth, complex manifolds. + + const size = 20; + const n = 20; + const pi = 3.14159; + + function gyroid(p) { + const x = p[0] - pi / 4; + const y = p[1] - pi / 4; + const z = p[2] - pi / 4; + return Math.cos(x) * Math.sin(y) + + Math.cos(y) * Math.sin(z) + + Math.cos(z) * Math.sin(x); } - b = intersection(extrude(stretch, width), b); - return b; - } - function stretchyBracelet( - radius = 30, height = 8, width = 15, - thickness = 0.4, nDecor = 20, nCut = 27, - nDivision = 30) { - const twistRadius = Math.PI * radius / nDecor; - const decorRadius = twistRadius * 1.5; - const outerRadius = radius + (decorRadius + twistRadius) * 0.5; - const innerRadius = outerRadius - height; - const cut = 0.5 * (Math.PI * 2 * innerRadius / nCut - thickness); - const adjThickness = 0.5 * thickness * height / cut; - - return difference( - base( - width, radius, decorRadius, twistRadius, nDecor, - innerRadius + thickness, outerRadius + adjThickness, - cut - adjThickness, nCut, nDivision), - base( - width, radius - thickness, decorRadius, twistRadius, nDecor, - innerRadius, outerRadius + 3 * adjThickness, cut, nCut, nDivision)); - } + function gyroidOffset(level) { + const period = 2 * pi; + const box = { + min: [-period, -period, -period], + max: [period, period, period] + }; + return levelSet(gyroid, box, period / n, level).scale(size / period); + }; - const result = stretchyBracelet(); - return result; - }, - - GyroidModule: function () { - // Recreates Modular Gyroid Puzzle by Emmett Lalish: - // https://www.thingiverse.com/thing:25477. This sample demonstrates the use - // of a Signed Distance Function (SDF) to create smooth, complex manifolds. - - const size = 20; - const n = 20; - const pi = 3.14159; - - function gyroid(p) { - const x = p[0] - pi / 4; - const y = p[1] - pi / 4; - const z = p[2] - pi / 4; - return Math.cos(x) * Math.sin(y) - + Math.cos(y) * Math.sin(z) - + Math.cos(z) * Math.sin(x); + function rhombicDodecahedron() { + const box = cube([1, 1, 2], true).scale(size * Math.sqrt(2)); + const result = box.rotate([90, 45, 0]).intersect(box.rotate([90, 45, 90])); + return result.intersect(box.rotate([0, 0, 45])); + } + + let result = rhombicDodecahedron().intersect(gyroidOffset(-0.4)) + result = result.subtract(gyroidOffset(0.4)); + result = result.rotate([-45, 0, 90]).translate([0, 0, size / Math.sqrt(2)]); + return result; } + }; - function gyroidOffset(level) { - const period = 2 * pi; - const box = { - min: [-period, -period, -period], - max: [period, period, period] - }; - return levelSet(gyroid, box, period / n, level).scale(size / period); - }; + exports.functionBodies = new Map(); - function rhombicDodecahedron() { - const box = cube([1, 1, 2], true).scale(size * Math.sqrt(2)); - const result = box.rotate([90, 45, 0]).intersect(box.rotate([90, 45, 90])); - return result.intersect(box.rotate([0, 0, 45])); - } + for (const [func, code] of Object.entries(exports.functions)) { + const whole = code.toString(); + const lines = whole.split('\n'); + lines.splice(0, 1);// remove first line + lines.splice(-2, 2);// remove last two lines + // remove first six leading spaces + const body = '\n' + lines.map(l => l.slice(6)).join('\n'); + + const name = func.replace(/([a-z])([A-Z])/g, '$1 $2');// Add spaces between words + exports.functionBodies.set(name, body); + }; - let result = rhombicDodecahedron().intersect(gyroidOffset(-0.4)) - result = result.subtract(gyroidOffset(0.4)); - result = result.rotate([-45, 0, 90]).translate([0, 0, size / Math.sqrt(2)]); - return result; - } -}; - -const examples = new Map(); - -for (const [func, code] of Object.entries(exampleFunctions)) { - const whole = code.toString(); - const lines = whole.split('\n'); - lines.splice(0, 1);// remove first line - lines.splice(-2, 2);// remove last two lines - // remove first four leading spaces - const body = '\n' + lines.map(l => l.slice(4)).join('\n'); - - const name = func.replace(/([a-z])([A-Z])/g, '$1 $2');// Add spaces between words - examples.set(name, body); -}; +})(typeof exports == "undefined" ? this['examples'] = {} : exports); \ No newline at end of file diff --git a/bindings/wasm/examples/model-viewer.html b/bindings/wasm/examples/model-viewer.html index 1d8abf043..9ae7b9bbe 100644 --- a/bindings/wasm/examples/model-viewer.html +++ b/bindings/wasm/examples/model-viewer.html @@ -48,39 +48,41 @@ + + - - \ No newline at end of file diff --git a/bindings/wasm/examples/three.html b/bindings/wasm/examples/three.html index d961b3591..d42b100bb 100644 --- a/bindings/wasm/examples/three.html +++ b/bindings/wasm/examples/three.html @@ -49,59 +49,59 @@ + - \ No newline at end of file diff --git a/bindings/wasm/examples/worker.js b/bindings/wasm/examples/worker.js index 7a7c3dd33..eac6e4df0 100644 --- a/bindings/wasm/examples/worker.js +++ b/bindings/wasm/examples/worker.js @@ -12,6 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +const threePath = 'https://cdn.jsdelivr.net/npm/three@0.144.0/'; +importScripts('manifold.js', threePath + 'build/three.js', threePath + 'examples/js/exporters/GLTFExporter.js'); + // manifold member functions that returns a new manifold const memberFunctions = [ 'add', 'subtract', 'intersect', 'refine', 'transform', 'translate', 'rotate', @@ -28,52 +31,49 @@ const utils = [ ]; const exposedFunctions = constructors.concat(utils); -var Module = { - onRuntimeInitialized: function () { - Module.setup(); - // Setup memory management, such that users don't have to care about - // calling `delete` manually. - // Note that this only fixes memory leak across different runs: the memory - // will only be freed when the compilation finishes. - - let manifoldRegistry = []; - for (const name of memberFunctions) { - const originalFn = Module.Manifold.prototype[name]; - Module.Manifold.prototype["_" + name] = originalFn; - Module.Manifold.prototype[name] = function (...args) { - const result = this["_" + name](...args); - manifoldRegistry.push(result); - return result; - } +let wasm; +Module().then(function (tmp) { + wasm = tmp; + wasm.setup(); + // Setup memory management, such that users don't have to care about + // calling `delete` manually. + // Note that this only fixes memory leak across different runs: the memory + // will only be freed when the compilation finishes. + + let manifoldRegistry = []; + for (const name of memberFunctions) { + const originalFn = wasm.Manifold.prototype[name]; + wasm.Manifold.prototype["_" + name] = originalFn; + wasm.Manifold.prototype[name] = function (...args) { + const result = this["_" + name](...args); + manifoldRegistry.push(result); + return result; } + } - for (const name of constructors) { - const originalFn = Module[name]; - Module[name] = function (...args) { - const result = originalFn(...args); - manifoldRegistry.push(result); - return result; - } + for (const name of constructors) { + const originalFn = wasm[name]; + wasm[name] = function (...args) { + const result = originalFn(...args); + manifoldRegistry.push(result); + return result; } + } - Module.cleanup = function () { - for (const obj of manifoldRegistry) { - // decompose result is an array of manifolds - if (obj instanceof Array) - for (const elem of obj) - elem.delete(); - else - obj.delete(); - } - manifoldRegistry = []; + wasm.cleanup = function () { + for (const obj of manifoldRegistry) { + // decompose result is an array of manifolds + if (obj instanceof Array) + for (const elem of obj) + elem.delete(); + else + obj.delete(); } - - postMessage(null); + manifoldRegistry = []; } -}; -const threePath = 'https://cdn.jsdelivr.net/npm/three@0.144.0/'; -importScripts('manifold.js', threePath + 'build/three.js', threePath + 'examples/js/exporters/GLTFExporter.js'); + postMessage(null); +}); const oldLog = console.log; console.log = function (...args) { @@ -93,12 +93,12 @@ onmessage = (e) => { const content = e.data + '\nexportGLB(result);\n'; try { const f = new Function(...exposedFunctions, content); - f(...exposedFunctions.map(name => Module[name])); + f(...exposedFunctions.map(name => wasm[name])); } catch (error) { console.log(error.toString()); postMessage({ objectURL: null }); } finally { - Module.cleanup(); + wasm.cleanup(); } } diff --git a/bindings/wasm/package-lock.json b/bindings/wasm/package-lock.json new file mode 100644 index 000000000..3dea0cd1a --- /dev/null +++ b/bindings/wasm/package-lock.json @@ -0,0 +1,1705 @@ +{ + "name": "manifold-3d", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "manifold-3d", + "version": "1.0.0", + "license": "Apache-2.0", + "devDependencies": { + "chai": "*", + "mocha": "*" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", + "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loupe": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", + "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz", + "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==", + "dev": true, + "dependencies": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chai": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", + "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "dev": true + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + } + }, + "loupe": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", + "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "dev": true, + "requires": { + "get-func-name": "^2.0.0" + } + }, + "minimatch": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", + "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "mocha": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.1.0.tgz", + "integrity": "sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg==", + "dev": true, + "requires": { + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.4", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "5.0.1", + "ms": "2.1.3", + "nanoid": "3.3.3", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "workerpool": "6.2.1", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "nanoid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", + "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "workerpool": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", + "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/bindings/wasm/package.json b/bindings/wasm/package.json index 6f91d4c2f..28c8e2e70 100644 --- a/bindings/wasm/package.json +++ b/bindings/wasm/package.json @@ -6,7 +6,9 @@ "files": [ "manifold.js", "manifold.wasm", - "manifold.d.ts" + "manifold.d.ts", + "examples/examples.js", + "test/test.js" ], "typings": "manifold.d.ts", "types": "manifold.d.ts", @@ -32,5 +34,13 @@ "bugs": { "url": "https://github.com/elalish/manifold/issues" }, - "homepage": "https://github.com/elalish/manifold#readme" + "homepage": "https://github.com/elalish/manifold#readme", + "scripts": { + "test": "mocha -u tdd -t 30000" + }, + "devDependencies": { + "chai": "*", + "mocha": "*", + "three": "^0.146.0" + } } \ No newline at end of file diff --git a/bindings/wasm/test/test.js b/bindings/wasm/test/test.js new file mode 100644 index 000000000..f959daadd --- /dev/null +++ b/bindings/wasm/test/test.js @@ -0,0 +1,152 @@ +// Copyright 2022 The Manifold Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +const expect = require('chai').expect; +const wasm = require('../manifold.js'); +const examples = require('../examples/examples'); +const THREE = require('three'); + +// manifold member functions that returns a new manifold +const memberFunctions = [ + 'add', 'subtract', 'intersect', 'refine', 'transform', 'translate', 'rotate', + 'scale', 'asOriginal', 'decompose' +]; +// top level functions that constructs a new manifold +const constructors = [ + 'cube', 'cylinder', 'sphere', 'tetrahedron', 'extrude', 'revolve', 'union', + 'difference', 'intersection', 'compose', 'levelSet', 'smooth' +]; +const utils = [ + 'setMinCircularAngle', 'setMinCircularEdgeLength', 'setCircularSegments', + 'getCircularSegments' +]; +const exposedFunctions = constructors.concat(utils); + +wasm().then(function (Module) { + Module.setup(); + // Setup memory management, such that users don't have to care about + // calling `delete` manually. + // Note that this only fixes memory leak across different runs: the memory + // will only be freed when the compilation finishes. + + let manifoldRegistry = []; + for (const name of memberFunctions) { + const originalFn = Module.Manifold.prototype[name]; + Module.Manifold.prototype["_" + name] = originalFn; + Module.Manifold.prototype[name] = function (...args) { + const result = this["_" + name](...args); + manifoldRegistry.push(result); + return result; + } + } + + for (const name of constructors) { + const originalFn = Module[name]; + Module[name] = function (...args) { + const result = originalFn(...args); + manifoldRegistry.push(result); + return result; + } + } + + Module.cleanup = function () { + for (const obj of manifoldRegistry) { + // decompose result is an array of manifolds + if (obj instanceof Array) + for (const elem of obj) + elem.delete(); + else + obj.delete(); + } + manifoldRegistry = []; + } + + function runExample(name) { + try { + const content = examples.functionBodies.get(name) + '\nreturn result;\n';; + const f = new Function(...exposedFunctions, 'THREE', content); + const manifold = f(...exposedFunctions.map(name => Module[name]), THREE); + const prop = manifold.getProperties(); + const genus = manifold.genus(); + return { ...prop, genus }; + } finally { + Module.cleanup(); + } + } + + suite('Examples', () => { + test('Intro', () => { + const result = runExample('Intro'); + expect(result.genus).to.equal(5, 'Genus'); + expect(result.volume).to.be.closeTo(203164, 1, 'Volume'); + expect(result.surfaceArea).to.be.closeTo(62046, 1, 'Surface Area'); + }); + + test('Tetrahedron Puzzle', () => { + const result = runExample('Tetrahedron Puzzle'); + expect(result.genus).to.equal(0, 'Genus'); + expect(result.volume).to.be.closeTo(7297, 1, 'Volume'); + expect(result.surfaceArea).to.be.closeTo(3303, 1, 'Surface Area'); + }); + + test('Rounded Frame', () => { + const result = runExample('Rounded Frame'); + expect(result.genus).to.equal(5, 'Genus'); + expect(result.volume).to.be.closeTo(353706, 1, 'Volume'); + expect(result.surfaceArea).to.be.closeTo(68454, 1, 'Surface Area'); + }); + + test('Heart', () => { + const result = runExample('Heart'); + expect(result.genus).to.equal(0, 'Genus'); + expect(result.volume).to.be.closeTo(282743, 1, 'Volume'); + expect(result.surfaceArea).to.be.closeTo(22187, 1, 'Surface Area'); + }); + + test('Scallop', () => { + const result = runExample('Scallop'); + expect(result.genus).to.equal(0, 'Genus'); + expect(result.volume).to.be.closeTo(41284, 1, 'Volume'); + expect(result.surfaceArea).to.be.closeTo(7810, 1, 'Surface Area'); + }); + + test('Torus Knot', () => { + const result = runExample('Torus Knot'); + expect(result.genus).to.equal(1, 'Genus'); + expect(result.volume).to.be.closeTo(20960, 1, 'Volume'); + expect(result.surfaceArea).to.be.closeTo(11202, 1, 'Surface Area'); + }); + + test('Menger Sponge', () => { + const result = runExample('Menger Sponge'); + expect(result.genus).to.equal(1409, 'Genus'); + expect(result.volume).to.be.closeTo(406457, 1, 'Volume'); + expect(result.surfaceArea).to.be.closeTo(247590, 1, 'Surface Area'); + }); + + test('Stretchy Bracelet', () => { + const result = runExample('Stretchy Bracelet'); + expect(result.genus).to.equal(1, 'Genus'); + expect(result.volume).to.be.closeTo(3992, 1, 'Volume'); + expect(result.surfaceArea).to.be.closeTo(22267, 1, 'Surface Area'); + }); + + test('Gyroid Module', () => { + const result = runExample('Gyroid Module'); + expect(result.genus).to.equal(15, 'Genus'); + expect(result.volume).to.be.closeTo(4167, 1, 'Volume'); + expect(result.surfaceArea).to.be.closeTo(5642, 1, 'Surface Area'); + }); + }); +});