diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 9ab4e6be..0de79335 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -39,7 +39,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -50,7 +50,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # 鈩癸笍 Command-line programs to run using the OS shell. # 馃摎 https://git.io/JvXDl @@ -64,4 +64,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/ossar-analysis.yml b/.github/workflows/ossar-analysis.yml index 1a772af6..51d0f7ee 100644 --- a/.github/workflows/ossar-analysis.yml +++ b/.github/workflows/ossar-analysis.yml @@ -44,6 +44,6 @@ jobs: # Upload results to the Security tab - name: Upload OSSAR results - uses: github/codeql-action/upload-sarif@v1 + uses: github/codeql-action/upload-sarif@v2 with: sarif_file: ${{ steps.ossar.outputs.sarifFile }} diff --git a/.gitignore b/.gitignore index 0f5bde77..e90c4112 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,18 @@ /.nyc_output -.vscode/ipch +/.vscode/c_cpp_properties.json +/.vscode/ipch +/.vscode/settings.json +/bin /build /coverage /dist /dist-test /emsdk* -/src-expat -/src-graphviz /lib-* /node_modules +/rust +/src-* /tmp /types /vcpkg *.tsbuildinfo -/.vscode/c_cpp_properties.json -/.vscode/settings.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 6dd5ee7f..c37e6507 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -26,6 +26,13 @@ "url": "http://localhost:8000/hw-zstd.html", "webRoot": "${workspaceRoot}" }, + { + "name": "hw-base91.html", + "type": "msedge", + "request": "launch", + "url": "http://localhost:8000/hw-base91.html", + "webRoot": "${workspaceRoot}" + }, { "name": "test-browser", "type": "msedge", @@ -50,9 +57,31 @@ ], "type": "node" }, + { + "name": "sfx-wasm", + "program": "${workspaceFolder}/bin/sfx-wasm.mjs", + "request": "launch", + "args": [ + "./build/cpp/base91/base91lib.wasm" + ], + "skipFiles": [ + "/**" + ], + "type": "node" + }, + { + "name": "cli rollup wasm", + "program": "${workspaceFolder}/output-node/test-wasm.js", + "request": "launch", + "args": [], + "skipFiles": [ + "/**" + ], + "type": "node" + }, { "name": "CLI", - "program": "${workspaceFolder}/bin/cli.js", + "program": "${workspaceFolder}/bin/dot-wasm.mjs", "request": "launch", "args": [ "-K neato", @@ -66,7 +95,7 @@ }, { "name": "CLI Version", - "program": "${workspaceFolder}/bin/cli.js", + "program": "${workspaceFolder}/bin/dot-wasm.mjs", "request": "launch", "args": [ "-v" diff --git a/CMakeLists.txt b/CMakeLists.txt index 77846254..f983232a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,6 @@ SET(EM_FLAGS "-s INVOKE_RUN=0" "-s ALLOW_MEMORY_GROWTH=1" "-s WASM=1" - "-s MODULARIZE" "-s ENVIRONMENT=web" "-s FILESYSTEM=0" # "-s MINIMAL_RUNTIME=1" @@ -21,7 +20,7 @@ SET(EM_FLAGS "-s USE_ES6_IMPORT_META=0" # "-s WASM_BIGINT=1" "--pre-js ${CMAKE_CURRENT_SOURCE_DIR}/cpp/src/pre.js" - # "--post-js ${CMAKE_CURRENT_SOURCE_DIR}/cpp/src/post.js" + "--post-js ${CMAKE_CURRENT_SOURCE_DIR}/cpp/src/post.js" ) IF (CMAKE_BUILD_TYPE STREQUAL "Debug") diff --git a/README.md b/README.md index 41b1b641..123f9910 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,9 @@ Built with: - [Zstandard (zstd)](#zstandard) - [Hello World](#zstandard-hello-world) - [API](#zstandard-api) +- [Base91](#base91) + - [Hello World](#base91-hello-world) + - [API](#base91-api) - [Utilities](#utility) - [Building @hpcc-js/wasm](#building-hpcc-js-wasm) @@ -108,7 +111,7 @@ GraphViz WASM library, see [graphviz.org](https://www.graphviz.org/) for c++ det To call `dot-wasm` without installing: ``` -npx @hpcc-js/wasm [options] fileOrDot +npx -p @hpcc-js/wasm dot-wasm [options] fileOrDot ``` To install the global command `dot-wasm` via NPM: @@ -121,38 +124,35 @@ Usage: Usage: dot-wasm [options] fileOrDot Options: - --version Show version number [boolean] - -K, --layout Set layout engine (circo | dot | fdp | sfdp | neato | osage - | patchwork | twopi). By default, dot is used. - -T, --format Set output language to one of the supported formats (svg, - dot, json, dot_json, xdot_json, plain, plain-ext). By - default, svg is produced. + --version Show version number [boolean] + -K, --layout Set layout engine (circo | dot | fdp | sfdp | neato | osage | patchwo + rk | twopi). By default, dot is used. + -T, --format Set output language to one of the supported formats (svg | dot | json + | dot_json | xdot_json | plain | plain-ext). By default, svg is prod + uced. -n, --neato-no-op Sets no-op flag in neato. - "-n 1" assumes neato nodes have already been positioned and - all nodes have a pos attribute giving the positions. It - then performs an optional adjustment to remove node-node - overlap, depending on the value of the overlap attribute, - computes the edge layouts, depending on the value of the - splines attribute, and emits the graph in the appropriate - format. - "-n 2" Use node positions as specified, with no adjustment - to remove node-node overlaps, and use any edge layouts - already specified by the pos attribute. neato computes an - edge layout for any edge that does not have a pos - attribute. As usual, edge layout is guided by the splines - attribute. - -y, --invert-y By default, the coordinate system used in generic output - formats, such as attributed dot, extended dot, plain and - plain-ext, is the standard cartesian system with the origin - in the lower left corner, and with increasing y coordinates - as points move from bottom to top. If the -y flag is used, - the coordinate system is inverted, so that increasing - values of y correspond to movement from top to bottom. - -h, --help Show help [boolean] + "-n 1" assumes neato nodes have already bee + n positioned and all nodes have a pos attribute giving the positions. + It then performs an optional adjustment to remove node-node overlap, + depending on the value of the overlap attribute, computes the edge l + ayouts, depending on the value of the splines attribute, and emits th + e graph in the appropriate format. + "-n 2" Use node positions as speci + fied, with no adjustment to remove node-node overlaps, and use any ed + ge layouts already specified by the pos attribute. neato computes an + edge layout for any edge that does not have a pos attribute. As usual + , edge layout is guided by the splines attribute. + -y, --invert-y By default, the coordinate system used in generic output formats, suc + h as attributed dot, extended dot, plain and plain-ext, is the standa + rd cartesian system with the origin in the lower left corner, and wit + h increasing y coordinates as points move from bottom to top. If the + -y flag is used, the coordinate system is inverted, so that increasin + g values of y correspond to movement from top to bottom. + -v Echo GraphViz library version + -h, --help Show help [boolean] Examples: - dot-wasm -K neato -T xdot ./input.dot Execute NEATO layout and outputs XDOT - format. + dot-wasm -K neato -T xdot ./input.dot Execute NEATO layout and outputs XDOT format. ``` ### GraphViz Hello World @@ -515,6 +515,122 @@ A note on compressionLevel: The library supports regular compression levels fro --- +## Base91 +_Similar to Base 64, but uses more characters resulting in smaller strings._ + +Base 91 WASM library, similar to Base 64 but uses more characters resulting in smaller strings, see [Base91](https://base91.sourceforge.net/) for more details. + +### Base91 Hello World + +```html + + + + + + Base91 WASM + + + +
+ + + + + +``` + +### Base91 API + +#### Interfaces + +# **Options** 路 [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/trunk/src/base91.ts "Source") + +Options structure for advanced loading. + +```typescript +interface Options { + wasmFolder?: string; + wasmBinary?: ArrayBuffer; +} +``` + +* _wasmFolder_: An optional `string` specifying the location of wasm file. +* _wasmBinary_: An optional "pre-fetched" copy of the wasm binary as returned from `XHR` or `fetch`. + +# **Base91** 路 [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/trunk/src/base91.ts "Source") + +Conceptual interface for TypeScript/JavaScript wrapper API + +```typescript +interface Base91 { + static load(options?: Options): Promise; + version(): string; + + encode(data: Uint8Array): string; + decode(array: string): Uint8Array; +} +``` + +# **Base91.load**(_options_?: **Options**): **Promise\** 路 [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/trunk/src/base91.ts "Source") + +Loads and initializes the Base91 wasm library, returns a Promise to `Base91`: +```typescript +const base91 = await Base91.load(); +...dostuff... +``` +or +```typescript +Base91.load().then(base91 => {...dostuff...}); +``` + +# **base91.version**(): **string** 路 [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/trunk/src/base91.ts "Source") + +* **_returns_**: The Base91 library Version. + +# **base91.encode**(_data_: **Uint8Array**): **string** 路 [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/trunk/src/base91.ts "Source") + +* **_data_**: Raw data to encode. +* **_returns_**: Encoded string. + +Encodes the raw data. + +# **base91.decode**(_str_: **string**): **Uint8Array** 路 [<>](https://github.com/hpcc-systems/hpcc-js-wasm/blob/trunk/src/base91.ts "Source") + +* **_str_**: String to decode. +* **_returns_**: Decoded data. + +Decodes the raw data. + +--- + ## Utility Utility functions unrelated to any specific wasm APIs diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 80122dca..2071017a 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -1,3 +1,4 @@ +ADD_SUBDIRECTORY(base91) ADD_SUBDIRECTORY(expat) ADD_SUBDIRECTORY(graphviz) ADD_SUBDIRECTORY(zstd) diff --git a/cpp/base91/CMakeLists.txt b/cpp/base91/CMakeLists.txt new file mode 100644 index 00000000..9f734e30 --- /dev/null +++ b/cpp/base91/CMakeLists.txt @@ -0,0 +1,43 @@ +PROJECT(base91lib) + +find_package(unofficial-base91 CONFIG REQUIRED) + +# See: https://github.com/emscripten-core/emscripten/blob/main/src/settings.js +SET(EM_FLAGS + ${EM_FLAGS} + "-s EXPORT_NAME='${CMAKE_PROJECT_NAME}'" + "-s EXPORTED_FUNCTIONS=\"[]\"" + "-s EXPORTED_RUNTIME_METHODS=\"[]\"" + "--post-js ${CMAKE_CURRENT_BINARY_DIR}/main_glue.js" +) +STRING(REPLACE ";" " " LINK_FLAGS "${EM_FLAGS}") + +# Generate Glue from IDL file --- +ADD_CUSTOM_COMMAND( + MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/main.idl + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/main_glue.js ${CMAKE_CURRENT_BINARY_DIR}/main_glue.cpp + COMMAND python3 ${CMAKE_BINARY_DIR}/../emsdk/upstream/emscripten/tools/webidl_binder.py ${CMAKE_CURRENT_SOURCE_DIR}/main.idl ${CMAKE_CURRENT_BINARY_DIR}/main_glue +) +SET_PROPERTY(SOURCE main.cpp APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/main_glue.cpp) +# --- --- --- + +INCLUDE_DIRECTORIES( + ${VCPKG_INCLUDE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} +) + +ADD_EXECUTABLE(base91lib + main.cpp +) + +SET_TARGET_PROPERTIES(base91lib PROPERTIES LINK_FLAGS "${LINK_FLAGS} -s ENVIRONMENT=webview") + +TARGET_LINK_LIBRARIES(base91lib + PRIVATE unofficial::base91::base91 +) + +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/base91lib.wasm DESTINATION dist COMPONENT runtime) + +IF (CMAKE_BUILD_TYPE STREQUAL "Debug") + INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/base91lib.wasm.map DESTINATION dist COMPONENT runtime) +ENDIF () \ No newline at end of file diff --git a/cpp/base91/main.cpp b/cpp/base91/main.cpp new file mode 100644 index 00000000..1ae5890c --- /dev/null +++ b/cpp/base91/main.cpp @@ -0,0 +1,59 @@ +#include +#include + +const char *const version = "0.6.0"; + +class CBasE91 +{ +protected: + basE91 m_basE91; + +public: + CBasE91() + { + reset(); + } + + void *malloc(size_t __size) + { + return ::malloc(__size); + } + + void free(void *__ptr) + { + ::free(__ptr); + } + + const char *version() + { + return ::version; + } + + void reset() + { + basE91_init(&m_basE91); + } + + size_t encode(const void *data, size_t dataLen, void *dataOut) + { + return basE91_encode(&m_basE91, data, dataLen, dataOut); + } + + size_t encode_end(void *dataOut) + { + return basE91_encode_end(&m_basE91, dataOut); + } + + size_t decode(const void *data, size_t dataLen, void *dataOut) + { + return basE91_decode(&m_basE91, data, dataLen, dataOut); + } + + size_t decode_end(void *dataOut) + { + return basE91_decode_end(&m_basE91, dataOut); + } +}; + +// Include JS Glue --- +#include "main_glue.cpp" diff --git a/cpp/base91/main.idl b/cpp/base91/main.idl new file mode 100644 index 00000000..974a88f8 --- /dev/null +++ b/cpp/base91/main.idl @@ -0,0 +1,12 @@ +interface CBasE91 +{ + void CBasE91(); + static any malloc(unsigned long size); + static void free(any ptr); + [Const] DOMString version(); + void reset(); + unsigned long encode([Const] any data, unsigned long dataLen, any dataOut); + unsigned long encode_end(any dataOut); + unsigned long decode([Const] any data, unsigned long dataLen, any dataOut); + unsigned long decode_end(any dataOut); +}; diff --git a/cpp/zstd/main.cpp b/cpp/zstd/main.cpp index 447c71a8..907a81a0 100644 --- a/cpp/zstd/main.cpp +++ b/cpp/zstd/main.cpp @@ -1,6 +1,5 @@ -#include #include -#include + #include struct zstd @@ -21,11 +20,6 @@ struct zstd ::free(__ptr); } - static void *memcpy(void *dest, const void *src, size_t n) - { - return ::memcpy(dest, src, n); - } - static size_t compress(void *dst, size_t dstCapacity, const void *src, size_t srcSize, int compressionLevel) { return ZSTD_compress(dst, dstCapacity, src, srcSize, compressionLevel); diff --git a/cpp/zstd/main.idl b/cpp/zstd/main.idl index 788dbd57..0297e903 100644 --- a/cpp/zstd/main.idl +++ b/cpp/zstd/main.idl @@ -4,7 +4,6 @@ interface zstd static any malloc(unsigned long size); static void free(any ptr); - static any memcpy(any dest, [Const] any src, unsigned long n); static unsigned long compress(any dst, unsigned long dstCapacity, [Const] any src, unsigned long srcSize, long compressionLevel); static unsigned long decompress(any dst, unsigned long dstCapacity, [Const] any src, unsigned long compressedSize); diff --git a/hw-base91.html b/hw-base91.html new file mode 100644 index 00000000..66e3d1a7 --- /dev/null +++ b/hw-base91.html @@ -0,0 +1,42 @@ + + + + + + Zstandard WASM + + + +
+ + + + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 4e74692a..0c843ef0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "yargs": "17.6.0" }, "bin": { - "dot-wasm": "bin/cli.js" + "dot-wasm": "bin/dot-wasm.mjs" }, "devDependencies": { "@rollup/plugin-alias": "3.1.9", @@ -23,10 +23,12 @@ "@types/chai": "4.3.3", "@types/emscripten": "1.39.6", "@types/mocha": "9.1.1", - "@typescript-eslint/eslint-plugin": "5.40.1", - "@typescript-eslint/parser": "5.40.1", + "@types/yargs": "^17.0.13", + "@typescript-eslint/eslint-plugin": "5.42.0", + "@typescript-eslint/parser": "5.42.0", "chai": "4.3.6", "eslint": "8.26.0", + "fzstd": "^0.0.4", "karma": "6.4.1", "karma-chai": "0.1.0", "karma-chrome-launcher": "3.1.1", @@ -35,7 +37,8 @@ "karma-spec-reporter": "0.0.34", "local-web-server": "5.2.1", "mocha": "10.1.0", - "node-fetch": "^3.2.10", + "node-base91": "^0.3.4", + "node-fetch": "3.2.10", "npm-run-all": "4.1.5", "rimraf": "3.0.2", "rollup": "2.79.1", @@ -43,7 +46,7 @@ "run-script-os": "1.1.6", "standard-version": "9.5.0", "terser": "5.15.1", - "tslib": "2.4.0", + "tslib": "2.4.1", "typescript": "4.8.4" } }, @@ -539,22 +542,38 @@ } }, "node_modules/@types/semver": { - "version": "7.3.12", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.12.tgz", - "integrity": "sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==", + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "17.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.40.1.tgz", - "integrity": "sha512-FsWboKkWdytGiXT5O1/R9j37YgcjO8MKHSUmWnIEjVaz0krHkplPnYi7mwdb+5+cs0toFNQb0HIrN7zONdIEWg==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.42.0.tgz", + "integrity": "sha512-5TJh2AgL6+wpL8H/GTSjNb4WrjKoR2rqvFxR/DDTqYNk6uXn8BJMEcncLSpMbf/XV1aS0jAjYwn98uvVCiAywQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.40.1", - "@typescript-eslint/type-utils": "5.40.1", - "@typescript-eslint/utils": "5.40.1", + "@typescript-eslint/scope-manager": "5.42.0", + "@typescript-eslint/type-utils": "5.42.0", + "@typescript-eslint/utils": "5.42.0", "debug": "^4.3.4", "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" @@ -577,14 +596,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.1.tgz", - "integrity": "sha512-IK6x55va5w4YvXd4b3VrXQPldV9vQTxi5ov+g4pMANsXPTXOcfjx08CRR1Dfrcc51syPtXHF5bgLlMHYFrvQtg==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.42.0.tgz", + "integrity": "sha512-Ixh9qrOTDRctFg3yIwrLkgf33AHyEIn6lhyf5cCfwwiGtkWhNpVKlEZApi3inGQR/barWnY7qY8FbGKBO7p3JA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.40.1", - "@typescript-eslint/types": "5.40.1", - "@typescript-eslint/typescript-estree": "5.40.1", + "@typescript-eslint/scope-manager": "5.42.0", + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/typescript-estree": "5.42.0", "debug": "^4.3.4" }, "engines": { @@ -604,13 +623,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.40.1.tgz", - "integrity": "sha512-jkn4xsJiUQucI16OLCXrLRXDZ3afKhOIqXs4R3O+M00hdQLKR58WuyXPZZjhKLFCEP2g+TXdBRtLQ33UfAdRUg==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.42.0.tgz", + "integrity": "sha512-l5/3IBHLH0Bv04y+H+zlcLiEMEMjWGaCX6WyHE5Uk2YkSGAMlgdUPsT/ywTSKgu9D1dmmKMYgYZijObfA39Wow==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.40.1", - "@typescript-eslint/visitor-keys": "5.40.1" + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/visitor-keys": "5.42.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -621,13 +640,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.40.1.tgz", - "integrity": "sha512-DLAs+AHQOe6n5LRraXiv27IYPhleF0ldEmx6yBqBgBLaNRKTkffhV1RPsjoJBhVup2zHxfaRtan8/YRBgYhU9Q==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.42.0.tgz", + "integrity": "sha512-HW14TXC45dFVZxnVW8rnUGnvYyRC0E/vxXShFCthcC9VhVTmjqOmtqj6H5rm9Zxv+ORxKA/1aLGD7vmlLsdlOg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.40.1", - "@typescript-eslint/utils": "5.40.1", + "@typescript-eslint/typescript-estree": "5.42.0", + "@typescript-eslint/utils": "5.42.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -648,9 +667,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.40.1.tgz", - "integrity": "sha512-Icg9kiuVJSwdzSQvtdGspOlWNjVDnF3qVIKXdJ103o36yRprdl3Ge5cABQx+csx960nuMF21v8qvO31v9t3OHw==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.42.0.tgz", + "integrity": "sha512-t4lzO9ZOAUcHY6bXQYRuu+3SSYdD9TS8ooApZft4WARt4/f2Cj/YpvbTe8A4GuhT4bNW72goDMOy7SW71mZwGw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -661,13 +680,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.1.tgz", - "integrity": "sha512-5QTP/nW5+60jBcEPfXy/EZL01qrl9GZtbgDZtDPlfW5zj/zjNrdI2B5zMUHmOsfvOr2cWqwVdWjobCiHcedmQA==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.42.0.tgz", + "integrity": "sha512-2O3vSq794x3kZGtV7i4SCWZWCwjEtkWfVqX4m5fbUBomOsEOyd6OAD1qU2lbvV5S8tgy/luJnOYluNyYVeOTTg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.40.1", - "@typescript-eslint/visitor-keys": "5.40.1", + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/visitor-keys": "5.42.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -688,16 +707,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.40.1.tgz", - "integrity": "sha512-a2TAVScoX9fjryNrW6BZRnreDUszxqm9eQ9Esv8n5nXApMW0zeANUYlwh/DED04SC/ifuBvXgZpIK5xeJHQ3aw==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.42.0.tgz", + "integrity": "sha512-JZ++3+h1vbeG1NUECXQZE3hg0kias9kOtcQr3+JVQ3whnjvKuMyktJAAIj6743OeNPnGBmjj7KEmiDL7qsdnCQ==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.40.1", - "@typescript-eslint/types": "5.40.1", - "@typescript-eslint/typescript-estree": "5.40.1", + "@typescript-eslint/scope-manager": "5.42.0", + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/typescript-estree": "5.42.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -714,12 +733,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.1.tgz", - "integrity": "sha512-A2DGmeZ+FMja0geX5rww+DpvILpwo1OsiQs0M+joPWJYsiEFBLsH0y1oFymPNul6Z5okSmHpP4ivkc2N0Cgfkw==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.42.0.tgz", + "integrity": "sha512-QHbu5Hf/2lOEOwy+IUw0GoSCuAzByTAWWrOTKzTzsotiUnWFpuKnXcAhC9YztAf2EElQ0VvIK+pHJUPkM0q7jg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/types": "5.42.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -2966,6 +2985,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/fzstd": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/fzstd/-/fzstd-0.0.4.tgz", + "integrity": "sha512-GNZEyoB2+mGNGhBBdRiPF1WE3xRK5VTOXFNiM8YqUmo5Lo/XeyvLtSSrWLN3NS7JRnwolabqsmE970MiqI69Ug==", + "dev": true + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -5463,6 +5488,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -5484,6 +5515,12 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node_modules/node-base91": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/node-base91/-/node-base91-0.3.4.tgz", + "integrity": "sha512-+eyAj1tayE9k73AWwfpCeS2Gwgs4dFrO8joz3JLt99vOjpr9CCRW7TpmAYqs+kDHI3owKlotZuuz1NbGPvBRqQ==", + "dev": true + }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -7327,9 +7364,9 @@ } }, "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", "dev": true }, "node_modules/tsscmp": { @@ -8215,75 +8252,91 @@ } }, "@types/semver": { - "version": "7.3.12", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.12.tgz", - "integrity": "sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==", + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "@types/yargs": { + "version": "17.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.40.1.tgz", - "integrity": "sha512-FsWboKkWdytGiXT5O1/R9j37YgcjO8MKHSUmWnIEjVaz0krHkplPnYi7mwdb+5+cs0toFNQb0HIrN7zONdIEWg==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.42.0.tgz", + "integrity": "sha512-5TJh2AgL6+wpL8H/GTSjNb4WrjKoR2rqvFxR/DDTqYNk6uXn8BJMEcncLSpMbf/XV1aS0jAjYwn98uvVCiAywQ==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.40.1", - "@typescript-eslint/type-utils": "5.40.1", - "@typescript-eslint/utils": "5.40.1", + "@typescript-eslint/scope-manager": "5.42.0", + "@typescript-eslint/type-utils": "5.42.0", + "@typescript-eslint/utils": "5.42.0", "debug": "^4.3.4", "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" } }, "@typescript-eslint/parser": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.1.tgz", - "integrity": "sha512-IK6x55va5w4YvXd4b3VrXQPldV9vQTxi5ov+g4pMANsXPTXOcfjx08CRR1Dfrcc51syPtXHF5bgLlMHYFrvQtg==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.42.0.tgz", + "integrity": "sha512-Ixh9qrOTDRctFg3yIwrLkgf33AHyEIn6lhyf5cCfwwiGtkWhNpVKlEZApi3inGQR/barWnY7qY8FbGKBO7p3JA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.40.1", - "@typescript-eslint/types": "5.40.1", - "@typescript-eslint/typescript-estree": "5.40.1", + "@typescript-eslint/scope-manager": "5.42.0", + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/typescript-estree": "5.42.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.40.1.tgz", - "integrity": "sha512-jkn4xsJiUQucI16OLCXrLRXDZ3afKhOIqXs4R3O+M00hdQLKR58WuyXPZZjhKLFCEP2g+TXdBRtLQ33UfAdRUg==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.42.0.tgz", + "integrity": "sha512-l5/3IBHLH0Bv04y+H+zlcLiEMEMjWGaCX6WyHE5Uk2YkSGAMlgdUPsT/ywTSKgu9D1dmmKMYgYZijObfA39Wow==", "dev": true, "requires": { - "@typescript-eslint/types": "5.40.1", - "@typescript-eslint/visitor-keys": "5.40.1" + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/visitor-keys": "5.42.0" } }, "@typescript-eslint/type-utils": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.40.1.tgz", - "integrity": "sha512-DLAs+AHQOe6n5LRraXiv27IYPhleF0ldEmx6yBqBgBLaNRKTkffhV1RPsjoJBhVup2zHxfaRtan8/YRBgYhU9Q==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.42.0.tgz", + "integrity": "sha512-HW14TXC45dFVZxnVW8rnUGnvYyRC0E/vxXShFCthcC9VhVTmjqOmtqj6H5rm9Zxv+ORxKA/1aLGD7vmlLsdlOg==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.40.1", - "@typescript-eslint/utils": "5.40.1", + "@typescript-eslint/typescript-estree": "5.42.0", + "@typescript-eslint/utils": "5.42.0", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.40.1.tgz", - "integrity": "sha512-Icg9kiuVJSwdzSQvtdGspOlWNjVDnF3qVIKXdJ103o36yRprdl3Ge5cABQx+csx960nuMF21v8qvO31v9t3OHw==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.42.0.tgz", + "integrity": "sha512-t4lzO9ZOAUcHY6bXQYRuu+3SSYdD9TS8ooApZft4WARt4/f2Cj/YpvbTe8A4GuhT4bNW72goDMOy7SW71mZwGw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.1.tgz", - "integrity": "sha512-5QTP/nW5+60jBcEPfXy/EZL01qrl9GZtbgDZtDPlfW5zj/zjNrdI2B5zMUHmOsfvOr2cWqwVdWjobCiHcedmQA==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.42.0.tgz", + "integrity": "sha512-2O3vSq794x3kZGtV7i4SCWZWCwjEtkWfVqX4m5fbUBomOsEOyd6OAD1qU2lbvV5S8tgy/luJnOYluNyYVeOTTg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.40.1", - "@typescript-eslint/visitor-keys": "5.40.1", + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/visitor-keys": "5.42.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -8292,28 +8345,28 @@ } }, "@typescript-eslint/utils": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.40.1.tgz", - "integrity": "sha512-a2TAVScoX9fjryNrW6BZRnreDUszxqm9eQ9Esv8n5nXApMW0zeANUYlwh/DED04SC/ifuBvXgZpIK5xeJHQ3aw==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.42.0.tgz", + "integrity": "sha512-JZ++3+h1vbeG1NUECXQZE3hg0kias9kOtcQr3+JVQ3whnjvKuMyktJAAIj6743OeNPnGBmjj7KEmiDL7qsdnCQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.40.1", - "@typescript-eslint/types": "5.40.1", - "@typescript-eslint/typescript-estree": "5.40.1", + "@typescript-eslint/scope-manager": "5.42.0", + "@typescript-eslint/types": "5.42.0", + "@typescript-eslint/typescript-estree": "5.42.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" } }, "@typescript-eslint/visitor-keys": { - "version": "5.40.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.1.tgz", - "integrity": "sha512-A2DGmeZ+FMja0geX5rww+DpvILpwo1OsiQs0M+joPWJYsiEFBLsH0y1oFymPNul6Z5okSmHpP4ivkc2N0Cgfkw==", + "version": "5.42.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.42.0.tgz", + "integrity": "sha512-QHbu5Hf/2lOEOwy+IUw0GoSCuAzByTAWWrOTKzTzsotiUnWFpuKnXcAhC9YztAf2EElQ0VvIK+pHJUPkM0q7jg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/types": "5.42.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -10032,6 +10085,12 @@ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true }, + "fzstd": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/fzstd/-/fzstd-0.0.4.tgz", + "integrity": "sha512-GNZEyoB2+mGNGhBBdRiPF1WE3xRK5VTOXFNiM8YqUmo5Lo/XeyvLtSSrWLN3NS7JRnwolabqsmE970MiqI69Ug==", + "dev": true + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -11976,6 +12035,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -11994,6 +12059,12 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node-base91": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/node-base91/-/node-base91-0.3.4.tgz", + "integrity": "sha512-+eyAj1tayE9k73AWwfpCeS2Gwgs4dFrO8joz3JLt99vOjpr9CCRW7TpmAYqs+kDHI3owKlotZuuz1NbGPvBRqQ==", + "dev": true + }, "node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -13369,9 +13440,9 @@ "dev": true }, "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", "dev": true }, "tsscmp": { diff --git a/package.json b/package.json index 51788f39..ab30a4f9 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,22 @@ "import": "./dist/index.es6.js", "default": "./dist/index.js" }, + "expat": { + "import": "./dist/expat.es6.js", + "default": "./dist/expat.js" + }, + "extract": { + "import": "./dist/extract.es6.js", + "default": "./dist/extract.js" + }, + "graphviz": { + "import": "./dist/graphviz.es6.js", + "default": "./dist/graphviz.js" + }, + "zstd": { + "import": "./dist/zstd.es6.js", + "default": "./dist/zstd.js" + }, "default": "./dist/index.js" } }, @@ -36,13 +52,11 @@ "jsdelivr": "dist/index.min.js", "types": "types/index.d.ts", "bin": { - "dot-wasm": "bin/cli.js" + "dot-wasm": "bin/dot-wasm.mjs" }, "files": [ - "bin/cli.js", - "dist/index*.*", - "dist/expat*.*", - "dist/graphviz*.*", + "bin/*.*", + "dist/*.*", "types/*", "src/*.css" ], @@ -58,7 +72,7 @@ "install-vcpkg:win32": "wsl -e ./scripts/cpp-install-vcpkg.sh", "install-build-deps": "run-p install-emsdk install-graphviz install-vcpkg", "uninstall-build-deps": "rimraf ./emsdk ./src-graphviz ./vcpkg ./src-expat ./src-vcpkg", - "clean": "rimraf build coverage dist* lib* tmp types *.tsbuildinfo", + "clean": "rimraf bin build coverage dist* lib* output-* tmp types *.tsbuildinfo", "compile": "tsc", "compile-watch": "npm run compile -- -w", "compile-cpp": "run-script-os", @@ -76,12 +90,13 @@ "dev-start": "ws", "lint": "eslint src/**/*.ts", "lint-fix": "npm run lint -- --fix", - "test-cli": "node ./bin/cli.js -v", + "test-cli": "node ./bin/dot-wasm.mjs -v", + "test-cli-help": "node ./bin/dot-wasm.mjs", "test-bundle": "npx -y esbuild --bundle ./dist/index.js --bundle ./dist/index.es6.js --outdir=tmp", "test-bundle-node": "npx -y esbuild --bundle --platform=node --bundle ./dist/index.node.js ./dist/index.node.es6.mjs --outdir=tmp", "test-chrome": "karma start --single-run --browsers ChromeHeadless karma.conf.js", "test-firefox": "karma start --single-run --browsers Firefox karma.conf.js", - "test-node": "node ./bin/cli.js -v && mocha ./dist-test/index.node.js --reporter spec", + "test-node": "node ./bin/dot-wasm.mjs -v && mocha ./dist-test/index.node.js --reporter spec", "test": "run-s test-bundle test-bundle-node test-chrome test-node", "tag": "run-s standard-version git-push", "purge-jsdelivr": "node ./utils/purge-jsdelivr.js", @@ -100,10 +115,12 @@ "@types/chai": "4.3.3", "@types/emscripten": "1.39.6", "@types/mocha": "9.1.1", - "@typescript-eslint/eslint-plugin": "5.40.1", - "@typescript-eslint/parser": "5.40.1", + "@types/yargs": "^17.0.13", + "@typescript-eslint/eslint-plugin": "5.42.0", + "@typescript-eslint/parser": "5.42.0", "chai": "4.3.6", "eslint": "8.26.0", + "fzstd": "^0.0.4", "karma": "6.4.1", "karma-chai": "0.1.0", "karma-chrome-launcher": "3.1.1", @@ -112,6 +129,7 @@ "karma-spec-reporter": "0.0.34", "local-web-server": "5.2.1", "mocha": "10.1.0", + "node-base91": "^0.3.4", "node-fetch": "3.2.10", "npm-run-all": "4.1.5", "rimraf": "3.0.2", @@ -120,7 +138,7 @@ "run-script-os": "1.1.6", "standard-version": "9.5.0", "terser": "5.15.1", - "tslib": "2.4.0", + "tslib": "2.4.1", "typescript": "4.8.4" }, "repository": { diff --git a/rollup.config.mjs b/rollup.config.mjs index 593efb44..8a9f6478 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -61,6 +61,34 @@ const nodeTpl = (input, cjsOutput, esOutput) => ({ ] }); +const binTpl = (input, esOutput) => ({ + input, + external: id => { + if (id.indexOf("./") !== 0 && id.indexOf("__bin__") < 0) { + console.log(id); + return true; + } + return false; + }, + output: [{ + file: esOutput, + format: "es", + sourcemap: true, + name: pkg.name + }], + plugins: [ + replace({ + preventAssignment: true, + include: ["lib-es6/__bin__/*.mjs"], + delimiters: ["", ""], + values: { + "../index-node": "../dist/index.node.es6.mjs" + } + }), + sourcemaps(), + ] +}); + export default [ browserTpl("lib-es6/index", "dist/index", "dist/index.es6"), nodeTpl("lib-es6/index-node", "dist/index.node", "dist/index.node.es6"), @@ -68,9 +96,13 @@ export default [ browserTpl("lib-es6/graphviz", "dist/graphviz", "dist/graphviz.es6"), browserTpl("lib-es6/expat", "dist/expat", "dist/expat.es6"), browserTpl("lib-es6/zstd", "dist/zstd", "dist/zstd.es6"), + browserTpl("lib-es6/extract", "dist/extract", "dist/extract.es6"), browserTpl("lib-es6/__tests__/index", "dist-test/index", "dist-test/index.es6"), nodeTpl("lib-es6/__tests__/index", "dist-test/index.node", "dist-test/index.node.es6"), + + binTpl("lib-es6/__bin__/dot-wasm", "bin/dot-wasm.mjs"), + binTpl("lib-es6/__bin__/sfx-wasm", "bin/sfx-wasm.mjs"), // { // input: 'lib-es6/test-wasm.js', // output: [{ diff --git a/bin/cli.js b/src/__bin__/dot-wasm.mts similarity index 70% rename from bin/cli.js rename to src/__bin__/dot-wasm.mts index 8eeaa869..f7bbf279 100755 --- a/bin/cli.js +++ b/src/__bin__/dot-wasm.mts @@ -1,12 +1,11 @@ -#!/usr/bin/env node -/* eslint-disable no-undef */ -/* eslint-disable @typescript-eslint/no-var-requires */ +import fs from "fs"; +import { exit } from "process"; +import yargs from "yargs"; +import { hideBin } from 'yargs/helpers' +import { graphviz, graphvizVersion, Ext, Format, Engine } from "../index-node"; -const fs = require("fs"); -const { exit } = require("process"); -const gvMod = require("../dist/index.node.js"); - -const yargs = require("yargs/yargs")(process.argv.slice(2)) +const myYargs = yargs(hideBin(process.argv)) as yargs.Argv<{ vx: boolean, layout: Engine, format: Format, n: string }>; +myYargs .usage("Usage: dot-wasm [options] fileOrDot") .demandCommand(0, 1) .example("dot-wasm -K neato -T xdot ./input.dot", "Execute NEATO layout and outputs XDOT format.") @@ -15,10 +14,10 @@ const yargs = require("yargs/yargs")(process.argv.slice(2)) .describe("K", "Set layout engine (circo | dot | fdp | sfdp | neato | osage | patchwork | twopi). By default, dot is used.") .alias("T", "format") .nargs("T", 1) - .describe("T", "Set output language to one of the supported formats (svg, dot, json, dot_json, xdot_json, plain, plain-ext). By default, svg is produced.") + .describe("T", "Set output language to one of the supported formats (svg | dot | json | dot_json | xdot_json | plain | plain-ext). By default, svg is produced.") .alias("n", "neato-no-op") .nargs("n", 1) - .describe("n", "Sets no-op flag in neato.\n\"-n 1\" assumes neato nodes have already been positioned and all nodes have a pos attribute giving the positions. It then performs an optional adjustment to remove node-node overlap, depending on the value of the overlap attribute, computes the edge layouts, depending on the value of the splines attribute, and emits the graph in the appropriate format.\n\"-n 2\" Use node positions as specified, with no adjustment to remove node-node overlaps, and use any edge layouts already specified by the pos attribute. neato computes an edge layout for any edge that does not have a pos attribute. As usual, edge layout is guided by the splines attribute.") + .describe("n", "Sets no-op flag in neato. \"-n 1\" assumes neato nodes have already been positioned and all nodes have a pos attribute giving the positions. It then performs an optional adjustment to remove node-node overlap, depending on the value of the overlap attribute, computes the edge layouts, depending on the value of the splines attribute, and emits the graph in the appropriate format.\n\"-n 2\" Use node positions as specified, with no adjustment to remove node-node overlaps, and use any edge layouts already specified by the pos attribute. neato computes an edge layout for any edge that does not have a pos attribute. As usual, edge layout is guided by the splines attribute.") .alias("y", "invert-y") .nargs("y", 0) .describe("y", "By default, the coordinate system used in generic output formats, such as attributed dot, extended dot, plain and plain-ext, is the standard cartesian system with the origin in the lower left corner, and with increasing y coordinates as points move from bottom to top. If the -y flag is used, the coordinate system is inverted, so that increasing values of y correspond to movement from top to bottom.") @@ -29,30 +28,30 @@ const yargs = require("yargs/yargs")(process.argv.slice(2)) .epilog("https://github.com/hpcc-systems/hpcc-js-wasm") ; -const argv = yargs.argv; +const argv = await myYargs.argv; try { let dot; - if (fs.existsSync(argv._[0])) { + if (fs.existsSync(argv._[0] as string)) { dot = fs.readFileSync(argv._[0], "utf8"); } else { - dot = argv._[0]; + dot = argv._[0] as string; } if (argv.v) { - gvMod.graphvizVersion().then(version => { + graphvizVersion().then(version => { console.log(`GraphViz version: ${version}`); }).catch(e => { console.error(e.message); exit(1); }) - } else { + } else if (dot) { if (argv.n && argv.layout.trim() !== "neato") { throw new Error("-n option is only supported with -T neato"); } - const ext = { + const ext: Ext = { }; if (argv.n) { ext.nop = parseInt(argv.n); @@ -61,14 +60,16 @@ try { ext.yInvert = true; } - gvMod.graphviz.layout(dot, argv.format?.trim() ?? "svg", argv.layout?.trim() ?? "dot", ext).then(response => { + graphviz.layout(dot, (argv.format?.trim() ?? "svg") as Format, (argv.layout?.trim() ?? "dot") as Engine, ext).then(response => { console.log(response); }).catch(e => { console.error(e.message); exit(1); }); + } else { + throw new Error("'fileOrDot' is required.") } -} catch (e) { - console.error(`Error: ${e.message}\n`); - yargs.showHelp(); +} catch (e: any) { + console.error(`Error: ${e?.message}\n`); + myYargs.showHelp(); } diff --git a/src/__bin__/sfx-wasm.mts b/src/__bin__/sfx-wasm.mts new file mode 100755 index 00000000..e206def4 --- /dev/null +++ b/src/__bin__/sfx-wasm.mts @@ -0,0 +1,44 @@ +import fs from "fs"; +import yargs from "yargs"; +import { hideBin } from 'yargs/helpers' +import { Zstd, Base91, extract } from "../index-node"; + +const myYargs = yargs(hideBin(process.argv)) as yargs.Argv<{}>; +myYargs + .usage("Usage: sfx-wasm [options] filePath") + .demandCommand(0, 1) + .example("sfx-wasm ./input.wasm", "Wrap file in a self extracting JavaScript file.") + .help("h") + .alias("h", "help") + .epilog("https://github.com/hpcc-systems/hpcc-js-wasm") + ; + +const argv = await myYargs.argv; + +try { + const wasmPath = argv._[0] as string; + let wasmContent; + if (fs.existsSync(wasmPath)) { + wasmContent = fs.readFileSync(wasmPath); + } + if (wasmContent) { + const zstd = await Zstd.load(); + const compressed = zstd.compress(new Uint8Array(wasmContent)) + const base91 = await Base91.load(); + const str = base91.encode(compressed); + console.log(`\ +import { extract } from "./extract"; +const blobStr = '${str}'; +export const wasmBinary = extract(blobStr); + `); + const test = extract(str); + if (test.length !== wasmContent.length) { + throw new Error("Oh oh"); + } + } else { + throw new Error("'filePath' is required.") + } +} catch (e: any) { + console.error(`Error: ${e?.message}\n`); + myYargs.showHelp(); +} diff --git a/src/__tests__/base91.ts b/src/__tests__/base91.ts new file mode 100644 index 00000000..39838870 --- /dev/null +++ b/src/__tests__/base91.ts @@ -0,0 +1,37 @@ +import { expect } from "chai"; +import { Base91 } from "../index"; +import { Zstd } from "../index"; + +describe("base91", function () { + it("version", async function () { + const base91 = await Base91.load(); + const v = base91.version(); + expect(v).to.be.a.string; + expect(v).to.not.be.empty; + console.log(v); + }); + + it("simple", async function () { + const base91 = await Base91.load(); + + const data = new Uint8Array(Array.from({ length: 1000 }, (_, i) => i % 256)); + const base91Str = base91.encode(data); + const data2 = await base91.decode(base91Str); + expect(data).to.deep.equal(data2); + }); + + it("compressed", async function () { + const zstd = await Zstd.load(); + const data = new Uint8Array(Array.from({ length: 1000000 }, (_, i) => i % 256)); + const compressed_data = zstd.compress(data); + + const base91 = await Base91.load(); + const base91Str = base91.encode(compressed_data); + console.log(data.byteLength, base91Str.length); + const compressed_data2 = base91.decode(base91Str); + expect(compressed_data).to.deep.equal(compressed_data2); + + const data2 = zstd.decompress(compressed_data2); + expect(data).to.deep.equal(data2); + }); +}); diff --git a/src/__tests__/index.ts b/src/__tests__/index.ts index 39a593f9..4158f497 100644 --- a/src/__tests__/index.ts +++ b/src/__tests__/index.ts @@ -1,6 +1,7 @@ import { wasmFolder } from "../index"; wasmFolder("dist"); +export * from "./base91"; export * from "./expat"; export * from "./graphviz"; export * from "./zstd"; diff --git a/src/__tests__/zstd.ts b/src/__tests__/zstd.ts index cd90b260..aca4fd1d 100644 --- a/src/__tests__/zstd.ts +++ b/src/__tests__/zstd.ts @@ -12,9 +12,8 @@ describe("zstd", function () { it("compress", async function () { const zstd = await Zstd.load(); const data = new Uint8Array(Array.from({ length: 1000 }, (_, i) => i % 256)); - const compressed_data = await zstd.compress(data); - const data2 = await zstd.decompress(compressed_data); + const compressed_data = zstd.compress(data); + const data2 = zstd.decompress(compressed_data); expect(data).to.deep.equal(data2); }); }); - diff --git a/src/base91.ts b/src/base91.ts new file mode 100644 index 00000000..cab20ecc --- /dev/null +++ b/src/base91.ts @@ -0,0 +1,59 @@ +// @ts-ignore +import * as base91lib from "../build/cpp/base91/base91lib"; +import { Options, WasmLibrary } from "./wasm-library"; +import { loadWasm } from "./util"; + +// Ref: http://base91.sourceforge.net/#a5 + +let g_base91: Promise; +export class Base91 extends WasmLibrary { + + private constructor(_module: base91lib) { + super(_module, new _module.CBasE91()); + } + + static load(options?: Options): Promise { + if (!g_base91) { + g_base91 = loadWasm(base91lib, "base91lib", options?.wasmFolder, options?.wasmBinary).then(module => { + return new Base91(module) + }); + } + return g_base91; + } + + version(): string { + return this._exports.version(); + } + + encode(data: Uint8Array): string { + this._exports.reset(); + + const unencoded = this.uint8_heapu8(data); + const encoded = this.malloc_heapu8(unencoded.size + Math.ceil(unencoded.size / 4)); + + encoded.size = this._exports.encode(unencoded.ptr, unencoded.size, encoded.ptr); + let retVal = this.heapu8_string(encoded); + encoded.size = this._exports.encode_end(encoded.ptr); + retVal += this.heapu8_string(encoded); + + this.free_heapu8(encoded); + this.free_heapu8(unencoded); + return retVal; + } + + decode(base91Str: string): Uint8Array { + this._exports.reset(); + + const encoded = this.string_heapu8(base91Str); + const unencoded = this.malloc_heapu8(encoded.size); + + unencoded.size = this._exports.decode(encoded.ptr, encoded.size, unencoded.ptr); + let retVal = this.heapu8_uint8(unencoded); + unencoded.size = this._exports.decode_end(unencoded.ptr); + retVal = new Uint8Array([...retVal, ...this.heapu8_view(unencoded)]); + + this.free_heapu8(unencoded); + this.free_heapu8(encoded); + return retVal; + } +} diff --git a/src/extract.ts b/src/extract.ts new file mode 100644 index 00000000..02b146cf --- /dev/null +++ b/src/extract.ts @@ -0,0 +1,43 @@ +import * as fzstd from 'fzstd'; + + +// See: https://github.com/Equim-chan/base91 +const table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~"'; + +function decode(raw: string): Uint8Array { + const len = raw.length; + const ret = []; + + let b = 0; + let n = 0; + let v = -1; + + for (let i = 0; i < len; i++) { + const p = table.indexOf(raw[i]); + if (p === -1) continue; + if (v < 0) { + v = p; + } else { + v += p * 91; + b |= v << n; + n += (v & 8191) > 88 ? 13 : 14; + do { + ret.push(b & 0xff); + b >>= 8; + n -= 8; + } while (n > 7); + v = -1; + } + } + + if (v > -1) { + ret.push((b | v << n) & 0xff); + } + + return new Uint8Array(ret); +} + +export function extract(raw: string): Uint8Array { + const compressed = decode(raw); + return fzstd.decompress(compressed); +} diff --git a/src/fetch-browser.ts b/src/fetch-browser.ts index 2e94f1e1..c5344938 100644 --- a/src/fetch-browser.ts +++ b/src/fetch-browser.ts @@ -1,13 +1,2 @@ let _scriptDir = (document?.currentScript as any)?.src ?? ""; export const scriptDir = _scriptDir.substring(0, _scriptDir.replace(/[?#].*/, "").lastIndexOf('/') + 1) + "../dist"; - -export async function doFetch(wasmUrl: string): Promise { - return fetch(wasmUrl, { credentials: 'same-origin' } as any).then(response => { - if (!response.ok) { - throw "failed to load wasm binary file at '" + wasmUrl + "'"; - } - return response.arrayBuffer(); - }).catch(e => { - throw e; - }); -} diff --git a/src/index-common.ts b/src/index-common.ts new file mode 100644 index 00000000..6fc087e3 --- /dev/null +++ b/src/index-common.ts @@ -0,0 +1,6 @@ +export { wasmFolder } from "./util"; +export * from "./base91"; +export * from "./expat"; +export * from "./extract"; +export * from "./graphviz"; +export * from "./zstd"; diff --git a/src/index-node.ts b/src/index-node.ts index ee5361f5..f831f85a 100644 --- a/src/index-node.ts +++ b/src/index-node.ts @@ -3,7 +3,4 @@ import { doFetch, scriptDir } from "./fetch-node"; interop.doFetch = doFetch; interop.scriptDir = scriptDir; -export { wasmFolder } from "./util"; -export * from "./expat"; -export * from "./graphviz"; -export * from "./zstd"; +export * from "./index-common"; diff --git a/src/index.ts b/src/index.ts index 7bb2e4e2..6cea5877 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,5 @@ import { interop } from "./util"; -import { doFetch, scriptDir } from "./fetch-browser"; -interop.doFetch = doFetch; +import { scriptDir } from "./fetch-browser"; interop.scriptDir = scriptDir; -export { wasmFolder } from "./util"; -export * from "./expat"; -export * from "./graphviz"; -export * from "./zstd"; +export * from "./index-common"; diff --git a/src/util.ts b/src/util.ts index 7b61744e..28ea01a3 100644 --- a/src/util.ts +++ b/src/util.ts @@ -33,7 +33,7 @@ const g_wasmCache = {} as { [key: string]: Promise }; async function _loadWasm(_wasmLib: any, wasmUrl: string, wasmBinary?: ArrayBuffer): Promise { const wasmLib = _wasmLib.default || _wasmLib; - if (!wasmBinary) { + if (!wasmBinary && interop.doFetch) { wasmBinary = await interop.doFetch(wasmUrl); } return await wasmLib({ diff --git a/src/wasm-library.ts b/src/wasm-library.ts new file mode 100644 index 00000000..97243a5c --- /dev/null +++ b/src/wasm-library.ts @@ -0,0 +1,61 @@ +export interface Options { + wasmFolder?: string; + wasmBinary?: ArrayBuffer; +} + +export type PTR = number; +export interface HeapU8 { + ptr: PTR; + size: number; +} + +export class WasmLibrary { + + protected _module: any; + protected _exports: any; + + protected constructor(_module: any, _export: any) { + this._module = _module; + this._exports = _export; + } + + malloc_heapu8(size: number): HeapU8 { + const ptr: PTR = this._exports.malloc(size); + return { + ptr, + size + }; + } + + free_heapu8(data: HeapU8) { + this._exports.free(data.ptr); + } + + uint8_heapu8(data: Uint8Array): HeapU8 { + const retVal = this.malloc_heapu8(data.byteLength); + this._module.HEAPU8.set(data, retVal.ptr); + return retVal; + } + + heapu8_view(data: HeapU8): Uint8Array { + return this._module.HEAPU8.subarray(data.ptr, data.ptr + data.size); + } + + heapu8_uint8(data: HeapU8): Uint8Array { + return new Uint8Array([...this.heapu8_view(data)]); + } + + string_heapu8(str: string): HeapU8 { + const data = Uint8Array.from(str, x => x.charCodeAt(0)); + return this.uint8_heapu8(data); + } + + heapu8_string(data: HeapU8): string { + const retVal = Array.from({ length: data.size }); + const submodule = this._module.HEAPU8.subarray(data.ptr, data.ptr + data.size); + submodule.forEach((c: number, i: number) => { + retVal[i] = String.fromCharCode(c); + }); + return retVal.join(""); + } +} diff --git a/src/zstd.ts b/src/zstd.ts index 195a9b43..42dad1d5 100644 --- a/src/zstd.ts +++ b/src/zstd.ts @@ -1,22 +1,16 @@ // @ts-ignore import * as zstdlib from "../build/cpp/zstd/zstdlib"; +import { Options, WasmLibrary } from "./wasm-library"; import { loadWasm } from "./util"; // Ref: http://facebook.github.io/zstd/zstd_manual.html - -export interface Options { - wasmFolder?: string; - wasmBinary?: ArrayBuffer; -} +// Ref: https://github.com/facebook/zstd let g_zstd: Promise; -export class Zstd { - protected _module; - protected _exports; +export class Zstd extends WasmLibrary { - private constructor(_module: any) { - this._module = _module; - this._exports = _module.zstd.prototype; + private constructor(_module: zstdlib) { + super(_module, _module.zstd.prototype); } static load(options?: Options): Promise { @@ -33,43 +27,37 @@ export class Zstd { } compress(data: Uint8Array, compressionLevel: number = this.defaultCLevel()): Uint8Array { - const uncompressedSize = data.byteLength; - const uncompressedPtr = this._exports.malloc(uncompressedSize); - this._module.HEAPU8.set(data, uncompressedPtr); + const uncompressed = this.uint8_heapu8(data); const compressedSize = this._exports.compressBound(data.length); - const compressedPtr = this._exports.malloc(compressedSize); - - const actualSize = this._exports.compress(compressedPtr, compressedSize, uncompressedPtr, uncompressedSize, compressionLevel); - if (this._exports.isError(actualSize)) { - console.error(this._exports.getErrorName(actualSize)); + const compressed = this.malloc_heapu8(compressedSize); + compressed.size = this._exports.compress(compressed.ptr, compressedSize, uncompressed.ptr, uncompressed.size, compressionLevel); + if (this._exports.isError(compressed.size)) { + console.error(this._exports.getErrorName(compressed.size)); } + const retVal = this.heapu8_uint8(compressed); - const retVal: Uint8Array = new Uint8Array(this._module.HEAPU8.buffer, compressedPtr, actualSize); - this._exports.free(compressedPtr); - this._exports.free(uncompressedPtr); + this.free_heapu8(compressed); + this.free_heapu8(uncompressed); return retVal; } decompress(array: Uint8Array): Uint8Array { - const compressedSize = array.byteLength; - const compressedPtr = this._exports.malloc(compressedSize); - this._module.HEAPU8.set(array, compressedPtr); - - const uncompressedSize = this._exports.getFrameContentSize(compressedPtr, compressedSize); + const compressed = this.uint8_heapu8(array); + const uncompressedSize = this._exports.getFrameContentSize(compressed.ptr, compressed.size); if (this._exports.isError(uncompressedSize)) { console.error(this._exports.getErrorName(uncompressedSize)); } - const uncompressedPtr = this._exports.malloc(uncompressedSize); - const actualSize = this._exports.decompress(uncompressedPtr, uncompressedSize, compressedPtr, compressedSize); - if (this._exports.isError(actualSize)) { - console.error(this._exports.getErrorName(actualSize)); - } + const uncompressed = this.malloc_heapu8(uncompressedSize); - const retVal = new Uint8Array(this._module.HEAPU8.buffer, uncompressedPtr, actualSize); - this._exports.free(uncompressedPtr); - this._exports.free(compressedPtr); + uncompressed.size = this._exports.decompress(uncompressed.ptr, uncompressedSize, compressed.ptr, compressed.size); + if (this._exports.isError(uncompressed.size)) { + console.error(this._exports.getErrorName(uncompressed.size)); + } + const retVal = this.heapu8_uint8(uncompressed); + this.free_heapu8(uncompressed); + this.free_heapu8(compressed); return retVal; } diff --git a/tsconfig.json b/tsconfig.json index 3e858026..1d780065 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,7 @@ "declarationDir": "./types", "composite": true, "target": "ES2020", - "module": "ES2020", + "module": "ES2022", "moduleResolution": "node", "strict": true, "esModuleInterop": true,