diff --git a/.eslintrc b/.eslintrc index 924f042..c13def9 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,18 +1,16 @@ { "root": true, "parser": "@typescript-eslint/parser", - "plugins": [ - "@typescript-eslint", - "prettier" - ], + "plugins": ["@typescript-eslint", "prettier", "jsdoc"], "extends": [ "eslint:recommended", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended", + "plugin:jsdoc/recommended", "prettier" ], "rules": { - "no-console": 1, // Means warning + "no-console": 1, // Means warning "prettier/prettier": 2 // Means error } -} \ No newline at end of file +} diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 54d52e2..37c2c0d 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -33,9 +33,10 @@ jobs: - name: Install Node modules run: | npm install - - name: Build project + - name: Build example project and copy docs run: | npm run build + npm run genDocs cd examples/typescript npm install npm run build diff --git a/.gitignore b/.gitignore index 05532d3..b7fac20 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules lib bundle.js +docs esptool-js-*.tgz .vscode/settings.json .parcel-cache diff --git a/examples/typescript/.parcelrc b/examples/typescript/.parcelrc new file mode 100644 index 0000000..853a724 --- /dev/null +++ b/examples/typescript/.parcelrc @@ -0,0 +1,7 @@ +{ + "extends": "@parcel/config-default", + "resolvers": [ + "parcel-resolver-ignore", + "..." + ] + } \ No newline at end of file diff --git a/examples/typescript/README.md b/examples/typescript/README.md index 05a6ecb..4627d85 100644 --- a/examples/typescript/README.md +++ b/examples/typescript/README.md @@ -1,6 +1,8 @@ # Using Esptool-JS in a Typescript environment -This example has example code in `src/index.ts` which is called in the `index.html`. We are using Parcel to do bundle mechanism for the resulting JavaScript for simplicity here. +This example has example code in `src/index.ts` which is called in the `index.html`. We are using Parcel to bundle resulting files for simplicity here. + +**NOTE:** This example is linked to the documentation generated from the source code. You could remove such dependency if necessary by remove `./docs/index.html` from `src/index.html` if you need so. NPM commands used below will generate documentation as well. ## Testing it locally @@ -9,4 +11,13 @@ npm install npm run dev ``` -Then open http://localhost:1234 in Chrome or Edge. The `npm run dev` step will call Parcel which start a local http server serving `index.html` with compiled `index.ts`. \ No newline at end of file +Then open http://localhost:1234 in Chrome or Edge. The `npm run dev` step will call Parcel which start a local http server serving `index.html` with compiled `index.ts`. + +## Generate build to publish + +``` +npm install +npm run build +``` + +Copy the content of `dist` to your static pages service like Github pages. \ No newline at end of file diff --git a/examples/typescript/package.json b/examples/typescript/package.json index 190bf6f..1b17df5 100644 --- a/examples/typescript/package.json +++ b/examples/typescript/package.json @@ -4,15 +4,20 @@ "description": "This an example of using esptool-js with parcel and typescript", "source": "src/index.html", "scripts": { - "dev": "parcel src/index.html", - "build": "npm run clean && parcel build src/index.html --no-optimize --public-url ./", + "genDocs": "cd ../.. && npm run genDocs && mkdir -p examples/typescript/dist && cp -r docs examples/typescript/dist && cd examples/typescript", + "dev": "npm run genDocs && parcel src/index.html", + "build": "npm run clean && npm run genDocs && parcel build src/index.html --no-optimize --public-url ./", "clean": "rimraf dist .parcel-cache", "test": "echo \"Error: no test specified\" && exit 1" }, + "parcelIgnore": [ + "./docs/.+" + ], "author": "", "license": "ISC", "devDependencies": { "parcel": "^2.8.3", + "parcel-resolver-ignore": "^2.1.5", "rimraf": "^4.1.2", "typescript": "^4.9.4" } diff --git a/examples/typescript/src/index.html b/examples/typescript/src/index.html index 6ac92f5..4910600 100644 --- a/examples/typescript/src/index.html +++ b/examples/typescript/src/index.html @@ -20,6 +20,9 @@

A Serial Flasher utility for Espressif chips

+
+ View the API Documentation +

diff --git a/examples/typescript/src/index.ts b/examples/typescript/src/index.ts index 751e399..b5979bb 100644 --- a/examples/typescript/src/index.ts +++ b/examples/typescript/src/index.ts @@ -38,6 +38,16 @@ eraseButton.style.display = "none"; consoleStopButton.style.display = "none"; filesDiv.style.display = "none"; +/** + * The built in Event object. + * @external Event + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Event} + */ + +/** + * File reader handler to read given local file. + * @param {Event} evt File Select event + */ function handleFileSelect(evt) { const file = evt.target.files[0]; @@ -78,10 +88,10 @@ connectButton.onclick = async () => { } as LoaderOptions; esploader = new ESPLoader(flashOptions); - chip = await esploader.main_fn(); + chip = await esploader.main(); // Temporarily broken - // await esploader.flash_id(); + // await esploader.flashId(); } catch (e) { console.error(e); term.writeln(`Error: ${e.message}`); @@ -113,7 +123,7 @@ resetButton.onclick = async () => { eraseButton.onclick = async () => { eraseButton.disabled = true; try { - await esploader.erase_flash(); + await esploader.eraseFlash(); } catch (e) { console.error(e); term.writeln(`Error: ${e.message}`); @@ -166,12 +176,24 @@ addFileButton.onclick = () => { } }; -function removeRow(row) { +/** + * The built in HTMLTableRowElement object. + * @external HTMLTableRowElement + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement} + */ + +/** + * Remove file row from HTML Table + * @param {HTMLTableRowElement} row Table row element to remove + */ +function removeRow(row: HTMLTableRowElement) { const rowIndex = Array.from(table.rows).indexOf(row); table.deleteRow(rowIndex); } -// to be called on disconnect - remove any stale references of older connections if any +/** + * Clean devices variables on chip disconnect. Remove stale references if any. + */ function cleanUp() { device = null; transport = null; @@ -228,7 +250,11 @@ consoleStopButton.onclick = async () => { programDiv.style.display = "initial"; }; -function validate_program_inputs() { +/** + * Validate the provided files images and offset to see if they're valid. + * @returns {string} Program input validation result + */ +function validateProgramInputs() { const offsetArr = []; const rowCount = table.rows.length; let row; @@ -258,7 +284,7 @@ function validate_program_inputs() { programButton.onclick = async () => { const alertMsg = document.getElementById("alertmsg"); - const err = validate_program_inputs(); + const err = validateProgramInputs(); if (err != "success") { alertMsg.innerHTML = "" + err + ""; @@ -301,7 +327,7 @@ programButton.onclick = async () => { }, calculateMD5Hash: (image) => CryptoJS.MD5(CryptoJS.enc.Latin1.parse(image)), } as FlashOptions; - await esploader.write_flash(flashOptions); + await esploader.writeFlash(flashOptions); } catch (e) { console.error(e); term.writeln(`Error: ${e.message}`); diff --git a/package-lock.json b/package-lock.json index 36cf82c..7ca8cab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,12 +23,15 @@ "@typescript-eslint/eslint-plugin": "^5.43.0", "@typescript-eslint/parser": "^5.43.0", "babel-loader": "^9.1.0", + "buffer": "^5.7.1", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", + "eslint-plugin-jsdoc": "^46.4.5", "eslint-plugin-prettier": "^4.2.1", "prettier": "^2.7.1", "rimraf": "^3.0.2", "rollup": "^3.3.0", + "typedoc": "^0.25.2", "typescript": "^4.8.4" } }, @@ -115,9 +118,9 @@ } }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "peer": true, "bin": { @@ -159,9 +162,9 @@ } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "peer": true, "bin": { @@ -390,9 +393,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", - "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==", + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", + "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", "dev": true, "peer": true, "bin": { @@ -453,6 +456,20 @@ "node": ">=6.9.0" } }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.39.4", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.39.4.tgz", + "integrity": "sha512-Jvw915fjqQct445+yron7Dufix9A+m9j1fCJYlCo1FWlRvTxa3pjJelxdSTdaLWcTwRU6vbL+NYjO4YuNIS5Qg==", + "dev": true, + "dependencies": { + "comment-parser": "1.3.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", @@ -557,9 +574,9 @@ } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", @@ -795,12 +812,6 @@ } } }, - "node_modules/@rollup/pluginutils/node_modules/@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", - "dev": true - }, "node_modules/@types/eslint": { "version": "8.4.10", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", @@ -824,9 +835,9 @@ } }, "node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", "dev": true }, "node_modules/@types/json-schema": { @@ -836,9 +847,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "version": "20.4.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", + "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==", "dev": true, "peer": true }, @@ -1054,73 +1065,73 @@ } }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", "dev": true, "peer": true }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", "dev": true, "peer": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", "dev": true, "peer": true }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", "dev": true, "peer": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dev": true, "peer": true, "dependencies": { @@ -1128,9 +1139,9 @@ } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dev": true, "peer": true, "dependencies": { @@ -1138,79 +1149,79 @@ } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", "dev": true, "peer": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", "dev": true, "peer": true, "dependencies": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.11.6", "@xtuc/long": "4.2.2" } }, @@ -1229,9 +1240,9 @@ "peer": true }, "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1241,9 +1252,9 @@ } }, "node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", "dev": true, "peer": true, "peerDependencies": { @@ -1333,6 +1344,12 @@ "node": ">=8" } }, + "node_modules/ansi-sequence-parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", + "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", + "dev": true + }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -1348,6 +1365,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1439,6 +1465,26 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1490,6 +1536,30 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "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" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -1572,6 +1642,15 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "node_modules/comment-parser": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", + "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", + "dev": true, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -1669,9 +1748,9 @@ "peer": true }, "node_modules/enhanced-resolve": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", - "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", "dev": true, "peer": true, "dependencies": { @@ -1683,9 +1762,9 @@ } }, "node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", + "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==", "dev": true, "peer": true }, @@ -1777,6 +1856,41 @@ "eslint": ">=7.0.0" } }, + "node_modules/eslint-plugin-jsdoc": { + "version": "46.4.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.4.5.tgz", + "integrity": "sha512-HjTuxqDYplAQFu29F3MHFCDDBgeqOxPXI6TyBhL0u2rr4XntJ0z3C9PmJvpjFscKdHwkZDN/0l1QCG0QwyRi4g==", + "dev": true, + "dependencies": { + "@es-joy/jsdoccomment": "~0.39.4", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.3.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.5.4", + "spdx-expression-parse": "^3.0.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/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/eslint-plugin-prettier": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", @@ -1975,9 +2089,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -2323,6 +2437,26 @@ "node": ">=8" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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/ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -2374,9 +2508,9 @@ "dev": true }, "node_modules/is-builtin-module": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", - "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", "dev": true, "dependencies": { "builtin-modules": "^3.3.0" @@ -2532,6 +2666,15 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -2577,6 +2720,12 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2630,6 +2779,12 @@ "node": ">=10" } }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, "node_modules/magic-string": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", @@ -2658,14 +2813,26 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" } }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -3122,9 +3289,9 @@ "peer": true }, "node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, "peer": true, "dependencies": { @@ -3141,9 +3308,9 @@ } }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -3156,9 +3323,9 @@ } }, "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==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", "dev": true, "peer": true, "dependencies": { @@ -3186,6 +3353,18 @@ "node": ">=8" } }, + "node_modules/shiki": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.4.tgz", + "integrity": "sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ==", + "dev": true, + "dependencies": { + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -3220,6 +3399,28 @@ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", "dev": true }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "dev": true + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -3279,13 +3480,13 @@ } }, "node_modules/terser": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", - "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", + "version": "5.19.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", + "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", "dev": true, "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -3297,17 +3498,17 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", - "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", "dev": true, "peer": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.14", + "@jridgewell/trace-mapping": "^0.3.17", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "terser": "^5.14.1" + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" }, "engines": { "node": ">= 10.13.0" @@ -3408,6 +3609,51 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typedoc": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.2.tgz", + "integrity": "sha512-286F7BeATBiWe/qC4PCOCKlSTwfnsLbC/4cZ68oGBbvAqb9vV33quEOXx7q176OXotD+JdEerdQ1OZGJ818lnA==", + "dev": true, + "dependencies": { + "lunr": "^2.3.9", + "marked": "^4.3.0", + "minimatch": "^9.0.3", + "shiki": "^0.14.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x" + } + }, + "node_modules/typedoc/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/typedoc/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/typescript": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", @@ -3457,6 +3703,18 @@ "punycode": "^2.1.0" } }, + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, + "node_modules/vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", + "dev": true + }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", @@ -3472,23 +3730,23 @@ } }, "node_modules/webpack": { - "version": "5.75.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", - "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", "dev": true, "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", + "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", @@ -3497,9 +3755,9 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", + "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, @@ -3545,9 +3803,9 @@ } }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -3645,9 +3903,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "peer": true } @@ -3679,9 +3937,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "peer": true } @@ -3863,9 +4121,9 @@ } }, "@babel/parser": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", - "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==", + "version": "7.22.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.7.tgz", + "integrity": "sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==", "dev": true, "peer": true }, @@ -3911,6 +4169,17 @@ "to-fast-properties": "^2.0.0" } }, + "@es-joy/jsdoccomment": { + "version": "0.39.4", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.39.4.tgz", + "integrity": "sha512-Jvw915fjqQct445+yron7Dufix9A+m9j1fCJYlCo1FWlRvTxa3pjJelxdSTdaLWcTwRU6vbL+NYjO4YuNIS5Qg==", + "dev": true, + "requires": { + "comment-parser": "1.3.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + } + }, "@eslint/eslintrc": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", @@ -3986,9 +4255,9 @@ "dev": true }, "@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", "dev": true, "requires": { "@jridgewell/gen-mapping": "^0.3.0", @@ -4135,14 +4404,6 @@ "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^2.3.1" - }, - "dependencies": { - "@types/estree": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", - "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", - "dev": true - } } }, "@types/eslint": { @@ -4168,9 +4429,9 @@ } }, "@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", "dev": true }, "@types/json-schema": { @@ -4180,9 +4441,9 @@ "dev": true }, "@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==", + "version": "20.4.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", + "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==", "dev": true, "peer": true }, @@ -4309,73 +4570,73 @@ } }, "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" } }, "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", "dev": true, "peer": true }, "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", "dev": true, "peer": true }, "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", "dev": true, "peer": true }, "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", "@xtuc/long": "4.2.2" } }, "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", "dev": true, "peer": true }, "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" } }, "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", "dev": true, "peer": true, "requires": { @@ -4383,9 +4644,9 @@ } }, "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", "dev": true, "peer": true, "requires": { @@ -4393,79 +4654,79 @@ } }, "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", "dev": true, "peer": true }, "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" } }, "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" } }, "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" } }, "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", "dev": true, "peer": true, "requires": { - "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/ast": "1.11.6", "@xtuc/long": "4.2.2" } }, @@ -4484,15 +4745,15 @@ "peer": true }, "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true }, "acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", "dev": true, "peer": true, "requires": {} @@ -4559,6 +4820,12 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, + "ansi-sequence-parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", + "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -4568,6 +4835,12 @@ "color-convert": "^2.0.1" } }, + "are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true + }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -4637,6 +4910,12 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4669,6 +4948,16 @@ "update-browserslist-db": "^1.0.9" } }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -4726,6 +5015,12 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "comment-parser": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", + "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", + "dev": true + }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -4803,9 +5098,9 @@ "peer": true }, "enhanced-resolve": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", - "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", "dev": true, "peer": true, "requires": { @@ -4814,9 +5109,9 @@ } }, "es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", + "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==", "dev": true, "peer": true }, @@ -4958,6 +5253,31 @@ "dev": true, "requires": {} }, + "eslint-plugin-jsdoc": { + "version": "46.4.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.4.5.tgz", + "integrity": "sha512-HjTuxqDYplAQFu29F3MHFCDDBgeqOxPXI6TyBhL0u2rr4XntJ0z3C9PmJvpjFscKdHwkZDN/0l1QCG0QwyRi4g==", + "dev": true, + "requires": { + "@es-joy/jsdoccomment": "~0.39.4", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.3.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.5.4", + "spdx-expression-parse": "^3.0.1" + }, + "dependencies": { + "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 + } + } + }, "eslint-plugin-prettier": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", @@ -5012,9 +5332,9 @@ } }, "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "requires": { "estraverse": "^5.1.0" @@ -5287,6 +5607,12 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -5326,9 +5652,9 @@ "dev": true }, "is-builtin-module": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", - "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", "dev": true, "requires": { "builtin-modules": "^3.3.0" @@ -5445,6 +5771,12 @@ "argparse": "^2.0.1" } }, + "jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -5478,6 +5810,12 @@ "dev": true, "peer": true }, + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5519,6 +5857,12 @@ "yallist": "^4.0.0" } }, + "lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true + }, "magic-string": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", @@ -5538,13 +5882,19 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } }, + "marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -5852,9 +6202,9 @@ "peer": true }, "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, "peer": true, "requires": { @@ -5864,18 +6214,18 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" } }, "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", "dev": true, "peer": true, "requires": { @@ -5897,6 +6247,18 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "shiki": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.4.tgz", + "integrity": "sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ==", + "dev": true, + "requires": { + "ansi-sequence-parser": "^1.1.0", + "jsonc-parser": "^3.2.0", + "vscode-oniguruma": "^1.7.0", + "vscode-textmate": "^8.0.0" + } + }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -5925,6 +6287,28 @@ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", "dev": true }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "dev": true + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -5963,29 +6347,29 @@ "peer": true }, "terser": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", - "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", + "version": "5.19.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", + "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", "dev": true, "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" } }, "terser-webpack-plugin": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", - "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", "dev": true, "peer": true, "requires": { - "@jridgewell/trace-mapping": "^0.3.14", + "@jridgewell/trace-mapping": "^0.3.17", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "terser": "^5.14.1" + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" } }, "text-table": { @@ -6046,6 +6430,38 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, + "typedoc": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.2.tgz", + "integrity": "sha512-286F7BeATBiWe/qC4PCOCKlSTwfnsLbC/4cZ68oGBbvAqb9vV33quEOXx7q176OXotD+JdEerdQ1OZGJ818lnA==", + "dev": true, + "requires": { + "lunr": "^2.3.9", + "marked": "^4.3.0", + "minimatch": "^9.0.3", + "shiki": "^0.14.1" + }, + "dependencies": { + "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" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "typescript": { "version": "4.8.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", @@ -6072,6 +6488,18 @@ "punycode": "^2.1.0" } }, + "vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true + }, + "vscode-textmate": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", + "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", + "dev": true + }, "watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", @@ -6084,23 +6512,23 @@ } }, "webpack": { - "version": "5.75.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", - "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", + "version": "5.88.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", + "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", "dev": true, "peer": true, "requires": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", - "acorn-import-assertions": "^1.7.6", + "acorn-import-assertions": "^1.9.0", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.10.0", - "es-module-lexer": "^0.9.0", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", @@ -6109,9 +6537,9 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", + "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", + "terser-webpack-plugin": "^5.3.7", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" } @@ -6133,9 +6561,9 @@ } }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true }, "wrappy": { diff --git a/package.json b/package.json index 5cbd77d..7c6279a 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,9 @@ ], "scripts": { "build": "npm run clean && tsc && rollup --config", - "clean": "rimraf lib bundle.js", + "clean": "rimraf lib bundle.js .parcel-cache", "format": "prettier --write \"src/**/*.ts\"", + "genDocs": "rimraf docs && typedoc", "lint": "eslint . --ext .ts", "lintAndFix": "eslint . --ext .ts --fix", "prepare": "npm run build", @@ -41,12 +42,15 @@ "@typescript-eslint/eslint-plugin": "^5.43.0", "@typescript-eslint/parser": "^5.43.0", "babel-loader": "^9.1.0", + "buffer": "^5.7.1", "eslint": "^8.28.0", "eslint-config-prettier": "^8.5.0", + "eslint-plugin-jsdoc": "^46.4.5", "eslint-plugin-prettier": "^4.2.1", "prettier": "^2.7.1", "rimraf": "^3.0.2", "rollup": "^3.3.0", + "typedoc": "^0.25.2", "typescript": "^4.8.4" } } diff --git a/src/error.ts b/src/error.ts index fe5ec18..e5ed8cf 100644 --- a/src/error.ts +++ b/src/error.ts @@ -1,5 +1,11 @@ +/** + * Represents a Espressif chip error. + */ class ESPError extends Error {} +/** + * Represents a Espressif timeout chip error. + */ class TimeoutError extends ESPError {} export { ESPError, TimeoutError }; diff --git a/src/esploader.ts b/src/esploader.ts index 7ca159c..255d9d1 100644 --- a/src/esploader.ts +++ b/src/esploader.ts @@ -4,29 +4,117 @@ import { Transport, SerialOptions } from "./webserial"; import { ROM } from "./targets/rom"; import { customReset, usbJTAGSerialReset } from "./reset"; +/* global SerialPort */ + +/** + * Options for flashing a device with firmware. + * @interface FlashOptions + */ export interface FlashOptions { + /** + * An array of file objects representing the data to be flashed. + * @type {Array<{ data: string; address: number }>} + */ fileArray: { data: string; address: number }[]; + + /** + * The size of the flash memory to be used. + * @type {string} + */ flashSize: string; + + /** + * The flash mode to be used (e.g., QIO, QOUT, DIO, DOUT). + * @type {string} + */ flashMode: string; + + /** + * The flash frequency to be used (e.g., 40MHz, 80MHz). + * @type {string} + */ flashFreq: string; + + /** + * Flag indicating whether to erase all existing data in the flash memory before flashing. + * @type {boolean} + */ eraseAll: boolean; + + /** + * Flag indicating whether to compress the data before flashing. + * @type {boolean} + */ compress: boolean; + + /** + * A function to report the progress of the flashing operation (optional). + * @type {(fileIndex: number, written: number, total: number) => void} + */ reportProgress?: (fileIndex: number, written: number, total: number) => void; + + /** + * A function to calculate the MD5 hash of the firmware image (optional). + * @type {(image: string) => string} + */ calculateMD5Hash?: (image: string) => string; } +/** + * Options to configure ESPLoader. + * @interface LoaderOptions + */ export interface LoaderOptions { + /** + * The transport mechanism to communicate with the device. + * @type {Transport} + */ transport: Transport; + + /** + * The port to initialize the transport class. + * @type {SerialPort} + */ port?: SerialPort; - baudrate: number; + + /** + * Set of options for SerialPort class. + * @type {Transport} + */ serialOptions?: SerialOptions; + + /** + * The baud rate to be used for communication with the device. + * @type {number} + */ + baudrate: number; + + /** + * An optional terminal interface to interact with the loader during the process. + * @type {IEspLoaderTerminal} + */ terminal?: IEspLoaderTerminal; + + /** + * The baud rate to be used during the initial ROM communication with the device. + * @type {number} + */ romBaudrate: number; + + /** + * Flag indicating whether to enable debug logging for the loader (optional). + * @type {boolean} + */ debugLogging?: boolean; } type FlashReadCallback = ((packet: Uint8Array, progress: number, totalSize: number) => void) | null; +/** + * Return the chip ROM based on the given magic number + * @param {number} magic - magic hex number to select ROM. + * @returns {ROM} The chip ROM class related to given magic hex number. + */ async function magic2Chip(magic: number): Promise { switch (magic) { case 0x00f01d83: { @@ -63,9 +151,26 @@ async function magic2Chip(magic: number): Promise { } } +/** + * A wrapper around your implementation of a terminal by + * implementing the clean, write and writeLine methods + * which are called by the ESPLoader class. + * @interface IEspLoaderTerminal + */ export interface IEspLoaderTerminal { + /** + * Execute a terminal clean command. + */ clean: () => void; + /** + * Write a string of data that include a line terminator. + * @param {string} data - The string to write with line terminator. + */ writeLine: (data: string) => void; + /** + * Write a string of data. + * @param {string} data - The string to write. + */ write: (data: string) => void; } @@ -141,6 +246,14 @@ export class ESPLoader { private romBaudrate = 115200; private debugLogging = false; + /** + * Create a new ESPLoader to perform serial communication + * such as read/write flash memory and registers using a LoaderOptions object. + * @param {LoaderOptions} options - LoaderOptions object argument for ESPLoader. + * ``` + * const myLoader = new ESPLoader({ transport: Transport, baudrate: number, terminal?: IEspLoaderTerminal }); + * ``` + */ constructor(options: LoaderOptions) { this.IS_STUB = false; this.FLASH_WRITE_SIZE = 0x4000; @@ -165,13 +278,18 @@ export class ESPLoader { } this.info("esptool.js"); - this.info("Serial port " + this.transport.get_info()); + this.info("Serial port " + this.transport.getInfo()); } _sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } + /** + * Write to ESP Loader constructor's terminal with or without new line. + * @param {string} str - String to write. + * @param {boolean} withNewline - Add new line at the end ? + */ write(str: string, withNewline = true) { if (this.terminal) { if (withNewline) { @@ -185,36 +303,81 @@ export class ESPLoader { } } + /** + * Write error message to ESP Loader constructor's terminal with or without new line. + * @param {string} str - String to write. + * @param {boolean} withNewline - Add new line at the end ? + */ error(str: string, withNewline = true) { this.write(`Error: ${str}`, withNewline); } + /** + * Write information message to ESP Loader constructor's terminal with or without new line. + * @param {string} str - String to write. + * @param {boolean} withNewline - Add new line at the end ? + */ info(str: string, withNewline = true) { this.write(str, withNewline); } + /** + * Write debug message to ESP Loader constructor's terminal with or without new line. + * @param {string} str - String to write. + * @param {boolean} withNewline - Add new line at the end ? + */ debug(str: string, withNewline = true) { if (this.debugLogging) { this.write(`Debug: ${str}`, withNewline); } } - _short_to_bytearray(i: number) { + /** + * Convert short integer to byte array + * @param {number} i - Number to convert. + * @returns {Uint8Array} Byte array. + */ + _shortToBytearray(i: number) { return new Uint8Array([i & 0xff, (i >> 8) & 0xff]); } - _int_to_bytearray(i: number): Uint8Array { + /** + * Convert an integer to byte array + * @param {number} i - Number to convert. + * @returns {ROM} The chip ROM class related to given magic hex number. + */ + _intToByteArray(i: number): Uint8Array { return new Uint8Array([i & 0xff, (i >> 8) & 0xff, (i >> 16) & 0xff, (i >> 24) & 0xff]); } - _bytearray_to_short(i: number, j: number) { + /** + * Convert a byte array to short integer. + * @param {number} i - Number to convert. + * @param {number} j - Number to convert. + * @returns {number} Return a short integer number. + */ + _byteArrayToShort(i: number, j: number) { return i | (j >> 8); } - _bytearray_to_int(i: number, j: number, k: number, l: number) { + /** + * Convert a byte array to integer. + * @param {number} i - Number to convert. + * @param {number} j - Number to convert. + * @param {number} k - Number to convert. + * @param {number} l - Number to convert. + * @returns {number} Return a integer number. + */ + _byteArrayToInt(i: number, j: number, k: number, l: number) { return i | (j << 8) | (k << 16) | (l << 24); } + /** + * Append a buffer array after another buffer array + * @param {ArrayBuffer} buffer1 - First array buffer. + * @param {ArrayBuffer} buffer2 - magic hex number to select ROM. + * @returns {ArrayBufferLike} Return an array buffer. + */ _appendBuffer(buffer1: ArrayBuffer, buffer2: ArrayBuffer) { const tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); tmp.set(new Uint8Array(buffer1), 0); @@ -222,6 +385,12 @@ export class ESPLoader { return tmp.buffer; } + /** + * Append a buffer array after another buffer array + * @param {Uint8Array} arr1 - First array buffer. + * @param {Uint8Array} arr2 - magic hex number to select ROM. + * @returns {Uint8Array} Return a 8 bit unsigned array. + */ _appendArray(arr1: Uint8Array, arr2: Uint8Array) { const c = new Uint8Array(arr1.length + arr2.length); c.set(arr1, 0); @@ -229,23 +398,36 @@ export class ESPLoader { return c; } + /** + * Convert a unsigned 8 bit integer array to byte string. + * @param {Uint8Array} u8Array - magic hex number to select ROM. + * @returns {string} Return the equivalent string. + */ ui8ToBstr(u8Array: Uint8Array) { - let b_str = ""; + let bStr = ""; for (let i = 0; i < u8Array.length; i++) { - b_str += String.fromCharCode(u8Array[i]); + bStr += String.fromCharCode(u8Array[i]); } - return b_str; + return bStr; } + /** + * Convert a byte string to unsigned 8 bit integer array. + * @param {string} bStr - binary string input + * @returns {Uint8Array} Return a 8 bit unsigned integer array. + */ bstrToUi8(bStr: string) { - const u8_array = new Uint8Array(bStr.length); + const u8Array = new Uint8Array(bStr.length); for (let i = 0; i < bStr.length; i++) { - u8_array[i] = bStr.charCodeAt(i); + u8Array[i] = bStr.charCodeAt(i); } - return u8_array; + return u8Array; } - async flush_input() { + /** + * Flush the serial input by raw read with 200 ms timeout. + */ + async flushInput() { try { await this.transport.rawRead(200); } catch (e) { @@ -253,19 +435,25 @@ export class ESPLoader { } } - async read_packet(op: number | null = null, timeout = 3000): Promise<[number, Uint8Array]> { + /** + * Use the device serial port read function with given timeout to create a valid packet. + * @param {number} op Operation number + * @param {number} timeout timeout number in milliseconds + * @returns {[number, Uint8Array]} valid response packet. + */ + async readPacket(op: number | null = null, timeout = 3000): Promise<[number, Uint8Array]> { // Check up-to next 100 packets for valid response packet for (let i = 0; i < 100; i++) { const p = await this.transport.read(timeout); const resp = p[0]; - const op_ret = p[1]; - const val = this._bytearray_to_int(p[4], p[5], p[6], p[7]); + const opRet = p[1]; + const val = this._byteArrayToInt(p[4], p[5], p[6], p[7]); const data = p.slice(8); if (resp == 1) { - if (op == null || op_ret == op) { + if (op == null || opRet == op) { return [val, data]; } else if (data[0] != 0 && data[1] == this.ROM_INVALID_RECV_MSG) { - await this.flush_input(); + await this.flushInput(); throw new ESPError("unsupported command error"); } } @@ -273,6 +461,15 @@ export class ESPLoader { throw new ESPError("invalid response"); } + /** + * Write a serial command to the chip + * @param {number} op - Operation number + * @param {Uint8Array} data - Unsigned 8 bit array + * @param {number} chk - channel number + * @param {boolean} waitResponse - wait for response ? + * @param {number} timeout - timeout number in milliseconds + * @returns {Promise<[number, Uint8Array]>} Return a number and a 8 bit unsigned integer array. + */ async command( op: number | null = null, data: Uint8Array = new Uint8Array(0), @@ -284,12 +481,12 @@ export class ESPLoader { const pkt = new Uint8Array(8 + data.length); pkt[0] = 0x00; pkt[1] = op; - pkt[2] = this._short_to_bytearray(data.length)[0]; - pkt[3] = this._short_to_bytearray(data.length)[1]; - pkt[4] = this._int_to_bytearray(chk)[0]; - pkt[5] = this._int_to_bytearray(chk)[1]; - pkt[6] = this._int_to_bytearray(chk)[2]; - pkt[7] = this._int_to_bytearray(chk)[3]; + pkt[2] = this._shortToBytearray(data.length)[0]; + pkt[3] = this._shortToBytearray(data.length)[1]; + pkt[4] = this._intToByteArray(chk)[0]; + pkt[5] = this._intToByteArray(chk)[1]; + pkt[6] = this._intToByteArray(chk)[2]; + pkt[7] = this._intToByteArray(chk)[3]; let i; for (i = 0; i < data.length; i++) { @@ -302,30 +499,48 @@ export class ESPLoader { return [0, new Uint8Array(0)]; } - return this.read_packet(op, timeout); + return this.readPacket(op, timeout); } - async read_reg(addr: number, timeout = 3000) { - const pkt = this._int_to_bytearray(addr); + /** + * Read a register from chip. + * @param {number} addr - Register address number + * @param {number} timeout - Timeout in milliseconds (Default: 3000ms) + * @returns {number} - Command number value + */ + async readReg(addr: number, timeout = 3000) { + const pkt = this._intToByteArray(addr); const val = await this.command(this.ESP_READ_REG, pkt, undefined, undefined, timeout); return val[0]; } - async write_reg(addr: number, value: number, mask = 0xffffffff, delay_us = 0, delay_after_us = 0) { - let pkt = this._appendArray(this._int_to_bytearray(addr), this._int_to_bytearray(value)); - pkt = this._appendArray(pkt, this._int_to_bytearray(mask)); - pkt = this._appendArray(pkt, this._int_to_bytearray(delay_us)); - - if (delay_after_us > 0) { - pkt = this._appendArray(pkt, this._int_to_bytearray(this.chip.UART_DATE_REG_ADDR)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); - pkt = this._appendArray(pkt, this._int_to_bytearray(delay_after_us)); - } - - await this.check_command("write target memory", this.ESP_WRITE_REG, pkt); + /** + * Write a number value to register address in chip. + * @param {number} addr - Register address number + * @param {number} value - Number value to write in register + * @param {number} mask - Hex number for mask + * @param {number} delayUs Delay number + * @param {number} delayAfterUs Delay after previous delay + */ + async writeReg(addr: number, value: number, mask = 0xffffffff, delayUs = 0, delayAfterUs = 0) { + let pkt = this._appendArray(this._intToByteArray(addr), this._intToByteArray(value)); + pkt = this._appendArray(pkt, this._intToByteArray(mask)); + pkt = this._appendArray(pkt, this._intToByteArray(delayUs)); + + if (delayAfterUs > 0) { + pkt = this._appendArray(pkt, this._intToByteArray(this.chip.UART_DATE_REG_ADDR)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(delayAfterUs)); + } + + await this.checkCommand("write target memory", this.ESP_WRITE_REG, pkt); } + /** + * Sync chip by sending sync command. + * @returns {[number, Uint8Array]} Command result + */ async sync() { this.debug("Sync"); const cmd = new Uint8Array(36); @@ -347,15 +562,21 @@ export class ESPLoader { } } - async _connect_attempt(mode = "default_reset", esp32r0_delay = false) { - this.debug("_connect_attempt " + mode + " " + esp32r0_delay); + /** + * Attempt to connect to the chip by sending a reset sequence and later a sync command. + * @param {string} mode - Reset mode to use + * @param {boolean} esp32r0Delay - Enable delay for ESP32 R0 + * @returns {string} - Returns 'success' or 'error' message. + */ + async _connectAttempt(mode = "default_reset", esp32r0Delay = false) { + this.debug("_connect_attempt " + mode + " " + esp32r0Delay); if (mode !== "no_reset") { - if (this.transport.get_pid() === this.USB_JTAG_SERIAL_PID) { + if (this.transport.getPid() === this.USB_JTAG_SERIAL_PID) { // Custom reset sequence, which is required when the device // is connecting via its USB-JTAG-Serial peripheral await usbJTAGSerialReset(this.transport); } else { - const strSequence = esp32r0_delay ? "D0|R1|W100|W2000|D1|R0|W50|D0" : "D0|R1|W100|D1|R0|W50|D0"; + const strSequence = esp32r0Delay ? "D0|R1|W100|W2000|D1|R0|W50|D0" : "D0|R1|W100|D1|R0|W50|D0"; await customReset(this.transport, strSequence); } } @@ -374,7 +595,7 @@ export class ESPLoader { } await this._sleep(50); } - this.transport.slip_reader_enabled = true; + this.transport.slipReaderEnabled = true; i = 7; while (i--) { try { @@ -383,7 +604,7 @@ export class ESPLoader { return "success"; } catch (error) { if (error instanceof Error) { - if (esp32r0_delay) { + if (esp32r0Delay) { this.info("_", false); } else { this.info(".", false); @@ -395,17 +616,23 @@ export class ESPLoader { return "error"; } + /** + * Perform a connection to chip. + * @param {string} mode - Reset mode to use. Example: 'default_reset' | 'no_reset' + * @param {number} attempts - Number of connection attempts + * @param {boolean} detecting - Detect the connected chip + */ async connect(mode = "default_reset", attempts = 7, detecting = false) { let i; let resp; this.info("Connecting...", false); await this.transport.connect(this.romBaudrate, this.serialOptions); for (i = 0; i < attempts; i++) { - resp = await this._connect_attempt(mode, false); + resp = await this._connectAttempt(mode, false); if (resp === "success") { break; } - resp = await this._connect_attempt(mode, true); + resp = await this._connectAttempt(mode, true); if (resp === "success") { break; } @@ -416,18 +643,22 @@ export class ESPLoader { this.info("\n\r", false); if (!detecting) { - const chip_magic_value = (await this.read_reg(0x40001000)) >>> 0; - this.debug("Chip Magic " + chip_magic_value.toString(16)); - const chip = await magic2Chip(chip_magic_value); + const chipMagicValue = (await this.readReg(0x40001000)) >>> 0; + this.debug("Chip Magic " + chipMagicValue.toString(16)); + const chip = await magic2Chip(chipMagicValue); if (this.chip === null) { - throw new ESPError(`Unexpected CHIP magic value ${chip_magic_value}. Failed to autodetect chip type.`); + throw new ESPError(`Unexpected CHIP magic value ${chipMagicValue}. Failed to autodetect chip type.`); } else { this.chip = chip as ROM; } } } - async detect_chip(mode = "default_reset") { + /** + * Connect and detect the existing chip. + * @param {string} mode Reset mode to use for connection. + */ + async detectChip(mode = "default_reset") { await this.connect(mode); this.info("Detecting chip type... ", false); if (this.chip != null) { @@ -437,14 +668,23 @@ export class ESPLoader { } } - async check_command( - op_description = "", + /** + * Execute the command and check the command response. + * @param {string} opDescription Command operation description. + * @param {number} op Command operation number + * @param {Uint8Array} data Command value + * @param {number} chk Checksum to use + * @param {number} timeout TImeout number in milliseconds (ms) + * @returns {number} Command result + */ + async checkCommand( + opDescription = "", op: number | null = null, data: Uint8Array = new Uint8Array(0), chk = 0, timeout = 3000, ) { - this.debug("check_command " + op_description); + this.debug("check_command " + opDescription); const resp = await this.command(op, data, chk, undefined, timeout); if (resp[1].length > 4) { return resp[1]; @@ -453,15 +693,27 @@ export class ESPLoader { } } - async mem_begin(size: number, blocks: number, blocksize: number, offset: number) { + /** + * Start downloading an application image to RAM + * @param {number} size Image size number + * @param {number} blocks Number of data blocks + * @param {number} blocksize Size of each data block + * @param {number} offset Image offset number + */ + async memBegin(size: number, blocks: number, blocksize: number, offset: number) { /* XXX: Add check to ensure that STUB is not getting overwritten */ this.debug("mem_begin " + size + " " + blocks + " " + blocksize + " " + offset.toString(16)); - let pkt = this._appendArray(this._int_to_bytearray(size), this._int_to_bytearray(blocks)); - pkt = this._appendArray(pkt, this._int_to_bytearray(blocksize)); - pkt = this._appendArray(pkt, this._int_to_bytearray(offset)); - await this.check_command("enter RAM download mode", this.ESP_MEM_BEGIN, pkt); + let pkt = this._appendArray(this._intToByteArray(size), this._intToByteArray(blocks)); + pkt = this._appendArray(pkt, this._intToByteArray(blocksize)); + pkt = this._appendArray(pkt, this._intToByteArray(offset)); + await this.checkCommand("enter RAM download mode", this.ESP_MEM_BEGIN, pkt); } + /** + * Get the checksum for given unsigned 8-bit array + * @param {Uint8Array} data Unsigned 8-bit integer array + * @returns {number} - Array checksum + */ checksum = function (data: Uint8Array) { let i; let chk = 0xef; @@ -472,28 +724,47 @@ export class ESPLoader { return chk; }; - async mem_block(buffer: Uint8Array, seq: number) { - let pkt = this._appendArray(this._int_to_bytearray(buffer.length), this._int_to_bytearray(seq)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); + /** + * Send a block of image to RAM + * @param {Uint8Array} buffer Unsigned 8-bit array + * @param {number} seq Sequence number + */ + async memBlock(buffer: Uint8Array, seq: number) { + let pkt = this._appendArray(this._intToByteArray(buffer.length), this._intToByteArray(seq)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); pkt = this._appendArray(pkt, buffer); const checksum = this.checksum(buffer); - await this.check_command("write to target RAM", this.ESP_MEM_DATA, pkt, checksum); + await this.checkCommand("write to target RAM", this.ESP_MEM_DATA, pkt, checksum); } - async mem_finish(entrypoint: number) { - const is_entry = entrypoint === 0 ? 1 : 0; - const pkt = this._appendArray(this._int_to_bytearray(is_entry), this._int_to_bytearray(entrypoint)); - await this.check_command("leave RAM download mode", this.ESP_MEM_END, pkt, undefined, 50); // XXX: handle non-stub with diff timeout + /** + * Leave RAM download mode and run application + * @param {number} entrypoint - Entrypoint number + */ + async memFinish(entrypoint: number) { + const isEntry = entrypoint === 0 ? 1 : 0; + const pkt = this._appendArray(this._intToByteArray(isEntry), this._intToByteArray(entrypoint)); + await this.checkCommand("leave RAM download mode", this.ESP_MEM_END, pkt, undefined, 50); // XXX: handle non-stub with diff timeout } - async flash_spi_attach(hspi_arg: number) { - const pkt = this._int_to_bytearray(hspi_arg); - await this.check_command("configure SPI flash pins", this.ESP_SPI_ATTACH, pkt); + /** + * Configure SPI flash pins + * @param {number} hspiArg - Argument for SPI attachment + */ + async flashSpiAttach(hspiArg: number) { + const pkt = this._intToByteArray(hspiArg); + await this.checkCommand("configure SPI flash pins", this.ESP_SPI_ATTACH, pkt); } - timeout_per_mb = function (seconds_per_mb: number, size_bytes: number) { - const result = seconds_per_mb * (size_bytes / 1000000); + /** + * Scale timeouts which are size-specific. + * @param {number} secondsPerMb Seconds per megabytes as number + * @param {number} sizeBytes Size bytes number + * @returns {number} - Scaled timeout for specified size. + */ + timeoutPerMb = function (secondsPerMb: number, sizeBytes: number) { + const result = secondsPerMb * (sizeBytes / 1000000); if (result < 3000) { return 3000; } else { @@ -501,57 +772,68 @@ export class ESPLoader { } }; - async flash_begin(size: number, offset: number) { - const num_blocks = Math.floor((size + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); - const erase_size = this.chip.get_erase_size(offset, size); + /** + * Start downloading to Flash (performs an erase) + * @param {number} size Size to erase + * @param {number} offset Offset to erase + * @returns {number} Number of blocks (of size self.FLASH_WRITE_SIZE) to write. + */ + async flashBegin(size: number, offset: number) { + const numBlocks = Math.floor((size + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); + const eraseSize = this.chip.getEraseSize(offset, size); const d = new Date(); const t1 = d.getTime(); let timeout = 3000; if (this.IS_STUB == false) { - timeout = this.timeout_per_mb(this.ERASE_REGION_TIMEOUT_PER_MB, size); + timeout = this.timeoutPerMb(this.ERASE_REGION_TIMEOUT_PER_MB, size); } - this.debug( - "flash begin " + erase_size + " " + num_blocks + " " + this.FLASH_WRITE_SIZE + " " + offset + " " + size, - ); - let pkt = this._appendArray(this._int_to_bytearray(erase_size), this._int_to_bytearray(num_blocks)); - pkt = this._appendArray(pkt, this._int_to_bytearray(this.FLASH_WRITE_SIZE)); - pkt = this._appendArray(pkt, this._int_to_bytearray(offset)); + this.debug("flash begin " + eraseSize + " " + numBlocks + " " + this.FLASH_WRITE_SIZE + " " + offset + " " + size); + let pkt = this._appendArray(this._intToByteArray(eraseSize), this._intToByteArray(numBlocks)); + pkt = this._appendArray(pkt, this._intToByteArray(this.FLASH_WRITE_SIZE)); + pkt = this._appendArray(pkt, this._intToByteArray(offset)); if (this.IS_STUB == false) { - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); // XXX: Support encrypted + pkt = this._appendArray(pkt, this._intToByteArray(0)); // XXX: Support encrypted } - await this.check_command("enter Flash download mode", this.ESP_FLASH_BEGIN, pkt, undefined, timeout); + await this.checkCommand("enter Flash download mode", this.ESP_FLASH_BEGIN, pkt, undefined, timeout); const t2 = d.getTime(); if (size != 0 && this.IS_STUB == false) { this.info("Took " + (t2 - t1) / 1000 + "." + ((t2 - t1) % 1000) + "s to erase flash block"); } - return num_blocks; + return numBlocks; } - async flash_defl_begin(size: number, compsize: number, offset: number) { - const num_blocks = Math.floor((compsize + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); - const erase_blocks = Math.floor((size + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); + /** + * Start downloading compressed data to Flash (performs an erase) + * @param {number} size Write size + * @param {number} compsize Compressed size + * @param {number} offset Offset for write + * @returns {number} Returns number of blocks (size self.FLASH_WRITE_SIZE) to write. + */ + async flashDeflBegin(size: number, compsize: number, offset: number) { + const numBlocks = Math.floor((compsize + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); + const eraseBlocks = Math.floor((size + this.FLASH_WRITE_SIZE - 1) / this.FLASH_WRITE_SIZE); const d = new Date(); const t1 = d.getTime(); - let write_size, timeout; + let writeSize, timeout; if (this.IS_STUB) { - write_size = size; + writeSize = size; timeout = 3000; } else { - write_size = erase_blocks * this.FLASH_WRITE_SIZE; - timeout = this.timeout_per_mb(this.ERASE_REGION_TIMEOUT_PER_MB, write_size); + writeSize = eraseBlocks * this.FLASH_WRITE_SIZE; + timeout = this.timeoutPerMb(this.ERASE_REGION_TIMEOUT_PER_MB, writeSize); } this.info("Compressed " + size + " bytes to " + compsize + "..."); - let pkt = this._appendArray(this._int_to_bytearray(write_size), this._int_to_bytearray(num_blocks)); - pkt = this._appendArray(pkt, this._int_to_bytearray(this.FLASH_WRITE_SIZE)); - pkt = this._appendArray(pkt, this._int_to_bytearray(offset)); + let pkt = this._appendArray(this._intToByteArray(writeSize), this._intToByteArray(numBlocks)); + pkt = this._appendArray(pkt, this._intToByteArray(this.FLASH_WRITE_SIZE)); + pkt = this._appendArray(pkt, this._intToByteArray(offset)); if ( (this.chip.CHIP_NAME === "ESP32-S2" || @@ -559,37 +841,49 @@ export class ESPLoader { this.chip.CHIP_NAME === "ESP32-C3") && this.IS_STUB === false ) { - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); } - await this.check_command("enter compressed flash mode", this.ESP_FLASH_DEFL_BEGIN, pkt, undefined, timeout); + await this.checkCommand("enter compressed flash mode", this.ESP_FLASH_DEFL_BEGIN, pkt, undefined, timeout); const t2 = d.getTime(); if (size != 0 && this.IS_STUB === false) { this.info("Took " + (t2 - t1) / 1000 + "." + ((t2 - t1) % 1000) + "s to erase flash block"); } - return num_blocks; + return numBlocks; } - async flash_block(data: Uint8Array, seq: number, timeout: number) { - let pkt = this._appendArray(this._int_to_bytearray(data.length), this._int_to_bytearray(seq)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); + /** + * Write block to flash, retry if fail + * @param {Uint8Array} data Unsigned 8-bit array data. + * @param {number} seq Sequence number + * @param {number} timeout Timeout in milliseconds (ms) + */ + async flashBlock(data: Uint8Array, seq: number, timeout: number) { + let pkt = this._appendArray(this._intToByteArray(data.length), this._intToByteArray(seq)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); pkt = this._appendArray(pkt, data); const checksum = this.checksum(data); - await this.check_command("write to target Flash after seq " + seq, this.ESP_FLASH_DATA, pkt, checksum, timeout); + await this.checkCommand("write to target Flash after seq " + seq, this.ESP_FLASH_DATA, pkt, checksum, timeout); } - async flash_defl_block(data: Uint8Array, seq: number, timeout: number) { - let pkt = this._appendArray(this._int_to_bytearray(data.length), this._int_to_bytearray(seq)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); + /** + * Write block to flash, send compressed, retry if fail + * @param {Uint8Array} data Unsigned int 8-bit array data to write + * @param {number} seq Sequence number + * @param {number} timeout Timeout in milliseconds (ms) + */ + async flashDeflBlock(data: Uint8Array, seq: number, timeout: number) { + let pkt = this._appendArray(this._intToByteArray(data.length), this._intToByteArray(seq)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); pkt = this._appendArray(pkt, data); const checksum = this.checksum(data); this.debug("flash_defl_block " + data[0].toString(16) + " " + data[1].toString(16)); - await this.check_command( + await this.checkCommand( "write compressed data to flash after seq " + seq, this.ESP_FLASH_DEFL_DATA, pkt, @@ -598,21 +892,44 @@ export class ESPLoader { ); } - async flash_finish(reboot = false) { + /** + * Leave flash mode and run/reboot + * @param {boolean} reboot Reboot after leaving flash mode ? + */ + async flashFinish(reboot = false) { const val = reboot ? 0 : 1; - const pkt = this._int_to_bytearray(val); + const pkt = this._intToByteArray(val); - await this.check_command("leave Flash mode", this.ESP_FLASH_END, pkt); + await this.checkCommand("leave Flash mode", this.ESP_FLASH_END, pkt); } - async flash_defl_finish(reboot = false) { + /** + * Leave compressed flash mode and run/reboot + * @param {boolean} reboot Reboot after leaving flash mode ? + */ + async flashDeflFinish(reboot = false) { const val = reboot ? 0 : 1; - const pkt = this._int_to_bytearray(val); + const pkt = this._intToByteArray(val); - await this.check_command("leave compressed flash mode", this.ESP_FLASH_DEFL_END, pkt); + await this.checkCommand("leave compressed flash mode", this.ESP_FLASH_DEFL_END, pkt); } - async run_spiflash_command(spiflash_command: number, data: Uint8Array, read_bits: number) { + /** + * Run an arbitrary SPI flash command. + * + * This function uses the "USR_COMMAND" functionality in the ESP + * SPI hardware, rather than the precanned commands supported by + * hardware. So the value of spiflashCommand is an actual command + * byte, sent over the wire. + * + * After writing command byte, writes 'data' to MOSI and then + * reads back 'readBits' of reply on MISO. Result is a number. + * @param {number} spiflashCommand Command to execute in SPI + * @param {Uint8Array} data Data to send + * @param {number} readBits Number of bits to read + * @returns {number} Register SPI_W0_REG value + */ + async runSpiflashCommand(spiflashCommand: number, data: Uint8Array, readBits: number) { // SPI_USR register flags const SPI_USR_COMMAND = 1 << 31; const SPI_USR_MISO = 1 << 28; @@ -626,71 +943,71 @@ export class ESPLoader { const SPI_USR2_REG = base + this.chip.SPI_USR2_OFFS; const SPI_W0_REG = base + this.chip.SPI_W0_OFFS; - let set_data_lengths; + let setDataLengths; if (this.chip.SPI_MOSI_DLEN_OFFS != null) { - set_data_lengths = async (mosi_bits: number, miso_bits: number) => { + setDataLengths = async (mosiBits: number, misoBits: number) => { const SPI_MOSI_DLEN_REG = base + this.chip.SPI_MOSI_DLEN_OFFS; const SPI_MISO_DLEN_REG = base + this.chip.SPI_MISO_DLEN_OFFS; - if (mosi_bits > 0) { - await this.write_reg(SPI_MOSI_DLEN_REG, mosi_bits - 1); + if (mosiBits > 0) { + await this.writeReg(SPI_MOSI_DLEN_REG, mosiBits - 1); } - if (miso_bits > 0) { - await this.write_reg(SPI_MISO_DLEN_REG, miso_bits - 1); + if (misoBits > 0) { + await this.writeReg(SPI_MISO_DLEN_REG, misoBits - 1); } }; } else { - set_data_lengths = async (mosi_bits: number, miso_bits: number) => { + setDataLengths = async (mosiBits: number, misoBits: number) => { const SPI_DATA_LEN_REG = SPI_USR1_REG; const SPI_MOSI_BITLEN_S = 17; const SPI_MISO_BITLEN_S = 8; - const mosi_mask = mosi_bits === 0 ? 0 : mosi_bits - 1; - const miso_mask = miso_bits === 0 ? 0 : miso_bits - 1; - const val = (miso_mask << SPI_MISO_BITLEN_S) | (mosi_mask << SPI_MOSI_BITLEN_S); - await this.write_reg(SPI_DATA_LEN_REG, val); + const mosiMask = mosiBits === 0 ? 0 : mosiBits - 1; + const misoMask = misoBits === 0 ? 0 : misoBits - 1; + const val = (misoMask << SPI_MISO_BITLEN_S) | (mosiMask << SPI_MOSI_BITLEN_S); + await this.writeReg(SPI_DATA_LEN_REG, val); }; } const SPI_CMD_USR = 1 << 18; const SPI_USR2_COMMAND_LEN_SHIFT = 28; - if (read_bits > 32) { + if (readBits > 32) { throw new ESPError("Reading more than 32 bits back from a SPI flash operation is unsupported"); } if (data.length > 64) { throw new ESPError("Writing more than 64 bytes of data with one SPI command is unsupported"); } - const data_bits = data.length * 8; - const old_spi_usr = await this.read_reg(SPI_USR_REG); - const old_spi_usr2 = await this.read_reg(SPI_USR2_REG); + const dataBits = data.length * 8; + const oldSpiUsr = await this.readReg(SPI_USR_REG); + const oldSpiUsr2 = await this.readReg(SPI_USR2_REG); let flags = SPI_USR_COMMAND; let i; - if (read_bits > 0) { + if (readBits > 0) { flags |= SPI_USR_MISO; } - if (data_bits > 0) { + if (dataBits > 0) { flags |= SPI_USR_MOSI; } - await set_data_lengths(data_bits, read_bits); - await this.write_reg(SPI_USR_REG, flags); - let val = (7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflash_command; - await this.write_reg(SPI_USR2_REG, val); - if (data_bits == 0) { - await this.write_reg(SPI_W0_REG, 0); + await setDataLengths(dataBits, readBits); + await this.writeReg(SPI_USR_REG, flags); + let val = (7 << SPI_USR2_COMMAND_LEN_SHIFT) | spiflashCommand; + await this.writeReg(SPI_USR2_REG, val); + if (dataBits == 0) { + await this.writeReg(SPI_W0_REG, 0); } else { if (data.length % 4 != 0) { const padding = new Uint8Array(data.length % 4); data = this._appendArray(data, padding); } - let next_reg = SPI_W0_REG; + let nextReg = SPI_W0_REG; for (i = 0; i < data.length - 4; i += 4) { - val = this._bytearray_to_int(data[i], data[i + 1], data[i + 2], data[i + 3]); - await this.write_reg(next_reg, val); - next_reg += 4; + val = this._byteArrayToInt(data[i], data[i + 1], data[i + 2], data[i + 3]); + await this.writeReg(nextReg, val); + nextReg += 4; } } - await this.write_reg(SPI_CMD_REG, SPI_CMD_USR); + await this.writeReg(SPI_CMD_REG, SPI_CMD_USR); for (i = 0; i < 10; i++) { - val = (await this.read_reg(SPI_CMD_REG)) & SPI_CMD_USR; + val = (await this.readReg(SPI_CMD_REG)) & SPI_CMD_USR; if (val == 0) { break; } @@ -698,23 +1015,31 @@ export class ESPLoader { if (i === 10) { throw new ESPError("SPI command did not complete in time"); } - const stat = await this.read_reg(SPI_W0_REG); - await this.write_reg(SPI_USR_REG, old_spi_usr); - await this.write_reg(SPI_USR2_REG, old_spi_usr2); + const stat = await this.readReg(SPI_W0_REG); + await this.writeReg(SPI_USR_REG, oldSpiUsr); + await this.writeReg(SPI_USR2_REG, oldSpiUsr2); return stat; } - async read_flash_id() { + /** + * Read flash id by executing the SPIFLASH_RDID flash command. + * @returns {Promise} Register SPI_W0_REG value + */ + async readFlashId() { const SPIFLASH_RDID = 0x9f; const pkt = new Uint8Array(0); - return await this.run_spiflash_command(SPIFLASH_RDID, pkt, 24); + return await this.runSpiflashCommand(SPIFLASH_RDID, pkt, 24); } - async erase_flash() { + /** + * Execute the erase flash command + * @returns {Promise} Erase flash command result + */ + async eraseFlash(): Promise { this.info("Erasing flash (this may take a while)..."); let d = new Date(); const t1 = d.getTime(); - const ret = await this.check_command( + const ret = await this.checkCommand( "erase flash", this.ESP_ERASE_FLASH, undefined, @@ -727,17 +1052,28 @@ export class ESPLoader { return ret; } - toHex(buffer: number | Uint8Array) { + /** + * Convert a number or unsigned 8-bit array to hex string + * @param {number | Uint8Array } buffer Data to convert to hex string. + * @returns {string} A hex string + */ + toHex(buffer: number | Uint8Array): string { return Array.prototype.map.call(buffer, (x) => ("00" + x.toString(16)).slice(-2)).join(""); } - async flash_md5sum(addr: number, size: number) { - const timeout = this.timeout_per_mb(this.MD5_TIMEOUT_PER_MB, size); - let pkt = this._appendArray(this._int_to_bytearray(addr), this._int_to_bytearray(size)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0)); - - let res = await this.check_command("calculate md5sum", this.ESP_SPI_FLASH_MD5, pkt, undefined, timeout); + /** + * Calculate the MD5 Checksum command + * @param {number} addr Address number + * @param {number} size Package size + * @returns {string} MD5 Checksum string + */ + async flashMd5sum(addr: number, size: number): Promise { + const timeout = this.timeoutPerMb(this.MD5_TIMEOUT_PER_MB, size); + let pkt = this._appendArray(this._intToByteArray(addr), this._intToByteArray(size)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + pkt = this._appendArray(pkt, this._intToByteArray(0)); + + let res = await this.checkCommand("calculate md5sum", this.ESP_SPI_FLASH_MD5, pkt, undefined, timeout); if (res instanceof Uint8Array && res.length > 16) { res = res.slice(0, 16); } @@ -745,12 +1081,12 @@ export class ESPLoader { return strmd5; } - async read_flash(addr: number, size: number, onPacketReceived: FlashReadCallback = null) { - let pkt = this._appendArray(this._int_to_bytearray(addr), this._int_to_bytearray(size)); - pkt = this._appendArray(pkt, this._int_to_bytearray(0x1000)); - pkt = this._appendArray(pkt, this._int_to_bytearray(1024)); + async readFlash(addr: number, size: number, onPacketReceived: FlashReadCallback = null) { + let pkt = this._appendArray(this._intToByteArray(addr), this._intToByteArray(size)); + pkt = this._appendArray(pkt, this._intToByteArray(0x1000)); + pkt = this._appendArray(pkt, this._intToByteArray(1024)); - const res = await this.check_command("read flash", this.ESP_READ_FLASH, pkt); + const res = await this.checkCommand("read flash", this.ESP_READ_FLASH, pkt); if (res != 0) { throw new ESPError("Failed to read memory: " + res); @@ -763,7 +1099,7 @@ export class ESPLoader { if (packet instanceof Uint8Array) { if (packet.length > 0) { resp = this._appendArray(resp, packet); - await this.transport.write(this._int_to_bytearray(resp.length)); + await this.transport.write(this._intToByteArray(resp.length)); if (onPacketReceived) { onPacketReceived(packet, resp.length, size); @@ -777,16 +1113,20 @@ export class ESPLoader { return resp; } - async run_stub() { + /** + * Upload the flasher ROM bootloader (flasher stub) to the chip. + * @returns {ROM} The Chip ROM + */ + async runStub() { this.info("Uploading stub..."); - let decoded = atob(this.chip.ROM_TEXT); + let decoded = Buffer.from(this.chip.ROM_TEXT).toString("base64"); let chardata = decoded.split("").map(function (x) { return x.charCodeAt(0); }); const text = new Uint8Array(chardata); - decoded = atob(this.chip.ROM_DATA); + decoded = Buffer.from(this.chip.ROM_DATA).toString("base64"); chardata = decoded.split("").map(function (x) { return x.charCodeAt(0); }); @@ -795,23 +1135,23 @@ export class ESPLoader { let blocks = Math.floor((text.length + this.ESP_RAM_BLOCK - 1) / this.ESP_RAM_BLOCK); let i; - await this.mem_begin(text.length, blocks, this.ESP_RAM_BLOCK, this.chip.TEXT_START); + await this.memBegin(text.length, blocks, this.ESP_RAM_BLOCK, this.chip.TEXT_START); for (i = 0; i < blocks; i++) { - const from_offs = i * this.ESP_RAM_BLOCK; - const to_offs = from_offs + this.ESP_RAM_BLOCK; - await this.mem_block(text.slice(from_offs, to_offs), i); + const fromOffs = i * this.ESP_RAM_BLOCK; + const toOffs = fromOffs + this.ESP_RAM_BLOCK; + await this.memBlock(text.slice(fromOffs, toOffs), i); } blocks = Math.floor((data.length + this.ESP_RAM_BLOCK - 1) / this.ESP_RAM_BLOCK); - await this.mem_begin(data.length, blocks, this.ESP_RAM_BLOCK, this.chip.DATA_START); + await this.memBegin(data.length, blocks, this.ESP_RAM_BLOCK, this.chip.DATA_START); for (i = 0; i < blocks; i++) { - const from_offs = i * this.ESP_RAM_BLOCK; - const to_offs = from_offs + this.ESP_RAM_BLOCK; - await this.mem_block(data.slice(from_offs, to_offs), i); + const fromOffs = i * this.ESP_RAM_BLOCK; + const toOffs = fromOffs + this.ESP_RAM_BLOCK; + await this.memBlock(data.slice(fromOffs, toOffs), i); } this.info("Running stub..."); - await this.mem_finish(this.chip.ENTRY); + await this.memFinish(this.chip.ENTRY); // Check up-to next 100 packets to see if stub is running for (let i = 0; i < 100; i++) { @@ -826,10 +1166,13 @@ export class ESPLoader { throw new ESPError("Failed to start stub. Unexpected response"); } - async change_baud() { + /** + * Change the chip baudrate. + */ + async changeBaud() { this.info("Changing baudrate to " + this.baudrate); - const second_arg = this.IS_STUB ? this.transport.baudrate : 0; - const pkt = this._appendArray(this._int_to_bytearray(this.baudrate), this._int_to_bytearray(second_arg)); + const secondArg = this.IS_STUB ? this.transport.baudrate : 0; + const pkt = this._appendArray(this._intToByteArray(this.baudrate), this._intToByteArray(secondArg)); const resp = await this.command(this.ESP_CHANGE_BAUDRATE, pkt); this.debug(resp[0].toString()); this.info("Changed"); @@ -854,39 +1197,54 @@ export class ESPLoader { } } - async main_fn(mode = "default_reset") { - await this.detect_chip(mode); + /** + * Execute the main function of ESPLoader. + * @param {string} mode Reset mode to use + * @returns {ROM} chip ROM + */ + async main(mode = "default_reset") { + await this.detectChip(mode); - const chip = await this.chip.get_chip_description(this); + const chip = await this.chip.getChipDescription(this); this.info("Chip is " + chip); - this.info("Features: " + (await this.chip.get_chip_features(this))); - this.info("Crystal is " + (await this.chip.get_crystal_freq(this)) + "MHz"); - this.info("MAC: " + (await this.chip.read_mac(this))); - await this.chip.read_mac(this); + this.info("Features: " + (await this.chip.getChipFeatures(this))); + this.info("Crystal is " + (await this.chip.getCrystalFreq(this)) + "MHz"); + this.info("MAC: " + (await this.chip.readMac(this))); + await this.chip.readMac(this); - if (typeof this.chip._post_connect != "undefined") { - await this.chip._post_connect(this); + if (typeof this.chip.postConnect != "undefined") { + await this.chip.postConnect(this); } - await this.run_stub(); + await this.runStub(); if (this.romBaudrate !== this.baudrate) { - await this.change_baud(); + await this.changeBaud(); } return chip; } - flash_size_bytes = function (flash_size: string) { - let flash_size_b = -1; - if (flash_size.indexOf("KB") !== -1) { - flash_size_b = parseInt(flash_size.slice(0, flash_size.indexOf("KB"))) * 1024; - } else if (flash_size.indexOf("MB") !== -1) { - flash_size_b = parseInt(flash_size.slice(0, flash_size.indexOf("MB"))) * 1024 * 1024; - } - return flash_size_b; + /** + * Get flash size bytes from flash size string. + * @param {string} flashSize Flash Size string + * @returns {number} Flash size bytes + */ + flashSizeBytes = function (flashSize: string) { + let flashSizeB = -1; + if (flashSize.indexOf("KB") !== -1) { + flashSizeB = parseInt(flashSize.slice(0, flashSize.indexOf("KB"))) * 1024; + } else if (flashSize.indexOf("MB") !== -1) { + flashSizeB = parseInt(flashSize.slice(0, flashSize.indexOf("MB"))) * 1024 * 1024; + } + return flashSizeB; }; - parse_flash_size_arg(flsz: string) { + /** + * Parse a given flash size string to a number + * @param {string} flsz Flash size to request + * @returns {number} Flash size number + */ + parseFlashSizeArg(flsz: string) { if (typeof this.chip.FLASH_SIZES[flsz] === "undefined") { throw new ESPError( "Flash size " + flsz + " is not supported by this chip type. Supported sizes: " + this.chip.FLASH_SIZES, @@ -895,28 +1253,31 @@ export class ESPLoader { return this.chip.FLASH_SIZES[flsz]; } - _update_image_flash_params( - image: string, - address: number, - flash_size: string, - flash_mode: string, - flash_freq: string, - ) { - this.debug("_update_image_flash_params " + flash_size + " " + flash_mode + " " + flash_freq); + /** + * Update the image flash parameters with given arguments. + * @param {string} image binary image as string + * @param {number} address flash address number + * @param {string} flashSize Flash size string + * @param {string} flashMode Flash mode string + * @param {string} flashFreq Flash frequency string + * @returns {string} modified image string + */ + _updateImageFlashParams(image: string, address: number, flashSize: string, flashMode: string, flashFreq: string) { + this.debug("_update_image_flash_params " + flashSize + " " + flashMode + " " + flashFreq); if (image.length < 8) { return image; } if (address != this.chip.BOOTLOADER_FLASH_OFFSET) { return image; } - if (flash_size === "keep" && flash_mode === "keep" && flash_freq === "keep") { + if (flashSize === "keep" && flashMode === "keep" && flashFreq === "keep") { this.info("Not changing the image"); return image; } const magic = parseInt(image[0]); - let a_flash_mode = parseInt(image[2]); - const flash_size_freq = parseInt(image[3]); + let aFlashMode = parseInt(image[2]); + const flashSizeFreq = parseInt(image[3]); if (magic !== this.ESP_IMAGE_MAGIC) { this.info( "Warning: Image file at 0x" + @@ -928,44 +1289,48 @@ export class ESPLoader { /* XXX: Yet to implement actual image verification */ - if (flash_mode !== "keep") { - const flash_modes: { [key: string]: number } = { qio: 0, qout: 1, dio: 2, dout: 3 }; - a_flash_mode = flash_modes[flash_mode]; + if (flashMode !== "keep") { + const flashModes: { [key: string]: number } = { qio: 0, qout: 1, dio: 2, dout: 3 }; + aFlashMode = flashModes[flashMode]; } - let a_flash_freq = flash_size_freq & 0x0f; - if (flash_freq !== "keep") { - const flash_freqs: { [key: string]: number } = { "40m": 0, "26m": 1, "20m": 2, "80m": 0xf }; - a_flash_freq = flash_freqs[flash_freq]; + let aFlashFreq = flashSizeFreq & 0x0f; + if (flashFreq !== "keep") { + const flashFreqs: { [key: string]: number } = { "40m": 0, "26m": 1, "20m": 2, "80m": 0xf }; + aFlashFreq = flashFreqs[flashFreq]; } - let a_flash_size = flash_size_freq & 0xf0; - if (flash_size !== "keep") { - a_flash_size = this.parse_flash_size_arg(flash_size); + let aFlashSize = flashSizeFreq & 0xf0; + if (flashSize !== "keep") { + aFlashSize = this.parseFlashSizeArg(flashSize); } - const flash_params = (a_flash_mode << 8) | (a_flash_freq + a_flash_size); - this.info("Flash params set to " + flash_params.toString(16)); - if (parseInt(image[2]) !== a_flash_mode << 8) { - image = image.substring(0, 2) + (a_flash_mode << 8).toString() + image.substring(2 + 1); + const flashParams = (aFlashMode << 8) | (aFlashFreq + aFlashSize); + this.info("Flash params set to " + flashParams.toString(16)); + if (parseInt(image[2]) !== aFlashMode << 8) { + image = image.substring(0, 2) + (aFlashMode << 8).toString() + image.substring(2 + 1); } - if (parseInt(image[3]) !== a_flash_freq + a_flash_size) { - image = image.substring(0, 3) + (a_flash_freq + a_flash_size).toString() + image.substring(3 + 1); + if (parseInt(image[3]) !== aFlashFreq + aFlashSize) { + image = image.substring(0, 3) + (aFlashFreq + aFlashSize).toString() + image.substring(3 + 1); } return image; } - async write_flash(options: FlashOptions) { + /** + * Write set of file images into given address based on given FlashOptions object. + * @param {FlashOptions} options FlashOptions to configure how and what to write into flash. + */ + async writeFlash(options: FlashOptions) { this.debug("EspLoader program"); if (options.flashSize !== "keep") { - const flash_end = this.flash_size_bytes(options.flashSize); + const flashEnd = this.flashSizeBytes(options.flashSize); for (let i = 0; i < options.fileArray.length; i++) { - if (options.fileArray[i].data.length + options.fileArray[i].address > flash_end) { + if (options.fileArray[i].data.length + options.fileArray[i].address > flashEnd) { throw new ESPError(`File ${i + 1} doesn't fit in the available flash`); } } } if (this.IS_STUB === true && options.eraseAll === true) { - await this.erase_flash(); + await this.eraseFlash(); } let image: string, address: number; for (let i = 0; i < options.fileArray.length; i++) { @@ -979,7 +1344,7 @@ export class ESPLoader { this.debug("Warning: File is empty"); continue; } - image = this._update_image_flash_params(image, address, options.flashSize, options.flashMode, options.flashFreq); + image = this._updateImageFlashParams(image, address, options.flashSize, options.flashMode, options.flashFreq); let calcmd5: string | null = null; if (options.calculateMD5Hash) { calcmd5 = options.calculateMD5Hash(image); @@ -990,12 +1355,12 @@ export class ESPLoader { if (options.compress) { const uncimage = this.bstrToUi8(image); image = this.ui8ToBstr(deflate(uncimage, { level: 9 })); - blocks = await this.flash_defl_begin(uncsize, image.length, address); + blocks = await this.flashDeflBegin(uncsize, image.length, address); } else { - blocks = await this.flash_begin(uncsize, address); + blocks = await this.flashBegin(uncsize, address); } let seq = 0; - let bytes_sent = 0; + let bytesSent = 0; const totalBytes = image.length; if (options.reportProgress) options.reportProgress(i, 0, totalBytes); @@ -1006,15 +1371,15 @@ export class ESPLoader { // Create a decompressor to keep track of the size of uncompressed data // to be written in each chunk. const inflate = new Inflate({ chunkSize: 1 }); - let total_len_uncompressed = 0; + let totalLenUncompressed = 0; inflate.onData = function (chunk: Data): void { - total_len_uncompressed += chunk.byteLength; + totalLenUncompressed += chunk.byteLength; }; while (image.length > 0) { this.debug("Write loop " + address + " " + seq + " " + blocks); this.info( "Writing at 0x" + - (address + total_len_uncompressed).toString(16) + + (address + totalLenUncompressed).toString(16) + "... (" + Math.floor((100 * (seq + 1)) / blocks) + "%)", @@ -1022,32 +1387,32 @@ export class ESPLoader { const block = this.bstrToUi8(image.slice(0, this.FLASH_WRITE_SIZE)); if (options.compress) { - const len_uncompressed_previous = total_len_uncompressed; + const lenUncompressedPrevious = totalLenUncompressed; inflate.push(block, false); - const block_uncompressed = total_len_uncompressed - len_uncompressed_previous; - let block_timeout = 3000; - if (this.timeout_per_mb(this.ERASE_WRITE_TIMEOUT_PER_MB, block_uncompressed) > 3000) { - block_timeout = this.timeout_per_mb(this.ERASE_WRITE_TIMEOUT_PER_MB, block_uncompressed); + const blockUncompressed = totalLenUncompressed - lenUncompressedPrevious; + let blockTimeout = 3000; + if (this.timeoutPerMb(this.ERASE_WRITE_TIMEOUT_PER_MB, blockUncompressed) > 3000) { + blockTimeout = this.timeoutPerMb(this.ERASE_WRITE_TIMEOUT_PER_MB, blockUncompressed); } if (this.IS_STUB === false) { // ROM code writes block to flash before ACKing - timeout = block_timeout; + timeout = blockTimeout; } - await this.flash_defl_block(block, seq, timeout); + await this.flashDeflBlock(block, seq, timeout); if (this.IS_STUB) { // Stub ACKs when block is received, then writes to flash while receiving the block after it - timeout = block_timeout; + timeout = blockTimeout; } } else { throw new ESPError("Yet to handle Non Compressed writes"); } - bytes_sent += block.length; + bytesSent += block.length; image = image.slice(this.FLASH_WRITE_SIZE, image.length); seq++; - if (options.reportProgress) options.reportProgress(i, bytes_sent, totalBytes); + if (options.reportProgress) options.reportProgress(i, bytesSent, totalBytes); } if (this.IS_STUB) { - await this.read_reg(this.CHIP_DETECT_MAGIC_REG_ADDR, timeout); + await this.readReg(this.CHIP_DETECT_MAGIC_REG_ADDR, timeout); } d = new Date(); const t = d.getTime() - t1; @@ -1056,7 +1421,7 @@ export class ESPLoader { "Wrote " + uncsize + " bytes (" + - bytes_sent + + bytesSent + " compressed) at 0x" + address.toString(16) + " in " + @@ -1065,7 +1430,7 @@ export class ESPLoader { ); } if (calcmd5) { - const res = await this.flash_md5sum(address, uncsize); + const res = await this.flashMd5sum(address, uncsize); if (new String(res).valueOf() != new String(calcmd5).valueOf()) { this.info("File md5: " + calcmd5); this.info("Flash md5: " + res); @@ -1078,42 +1443,51 @@ export class ESPLoader { this.info("Leaving..."); if (this.IS_STUB) { - await this.flash_begin(0, 0); + await this.flashBegin(0, 0); if (options.compress) { - await this.flash_defl_finish(); + await this.flashDeflFinish(); } else { - await this.flash_finish(); + await this.flashFinish(); } } } - async flash_id() { + /** + * Read SPI flash manufacturer and device id. + */ + async flashId() { this.debug("flash_id"); - const flashid = await this.read_flash_id(); + const flashid = await this.readFlashId(); this.info("Manufacturer: " + (flashid & 0xff).toString(16)); - const flid_lowbyte = (flashid >> 16) & 0xff; - this.info("Device: " + ((flashid >> 8) & 0xff).toString(16) + flid_lowbyte.toString(16)); - this.info("Detected flash size: " + this.DETECTED_FLASH_SIZES[flid_lowbyte]); + const flidLowbyte = (flashid >> 16) & 0xff; + this.info("Device: " + ((flashid >> 8) & 0xff).toString(16) + flidLowbyte.toString(16)); + this.info("Detected flash size: " + this.DETECTED_FLASH_SIZES[flidLowbyte]); } - async get_flash_size() { + async getFlashSize() { this.debug("flash_id"); - const flashid = await this.read_flash_id(); - const flid_lowbyte = (flashid >> 16) & 0xff; - return this.DETECTED_FLASH_SIZES_NUM[flid_lowbyte]; + const flashid = await this.readFlashId(); + const flidLowbyte = (flashid >> 16) & 0xff; + return this.DETECTED_FLASH_SIZES_NUM[flidLowbyte]; } - async hard_reset() { + /** + * Perform a chip hard reset by setting RTS to LOW and then HIGH. + */ + async hardReset() { await this.transport.setRTS(true); // EN->LOW await this._sleep(100); await this.transport.setRTS(false); } - async soft_reset() { + /** + * Soft reset the device chip. Soft reset with run user code is the closest. + */ + async softReset() { if (!this.IS_STUB) { // "run user code" is as close to a soft reset as we can do - await this.flash_begin(0, 0); - await this.flash_finish(false); + await this.flashBegin(0, 0); + await this.flashFinish(false); } else if (this.chip.CHIP_NAME != "ESP8266") { throw new ESPError("Soft resetting is currently only supported on ESP8266"); } else { diff --git a/src/index.ts b/src/index.ts index 66af3ec..2287878 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,4 @@ export { IEspLoaderTerminal, ESPLoader, FlashOptions, LoaderOptions } from "./esploader"; -export { Transport } from "./webserial"; +export { classicReset, customReset, hardReset, usbJTAGSerialReset, validateCustomResetStringSequence } from "./reset"; +export { ROM } from "./targets/rom"; +export { Transport, SerialOptions } from "./webserial"; diff --git a/src/reset.ts b/src/reset.ts index 850e4d9..267e666 100644 --- a/src/reset.ts +++ b/src/reset.ts @@ -2,10 +2,32 @@ import { Transport } from "./webserial"; const DEFAULT_RESET_DELAY = 50; +/** + * Sleep for ms milliseconds + * @param {number} ms Milliseconds to wait + * @returns {Promise} + */ function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } +/** + * Execute a classic set of commands that will reset the chip. + * + * Commands (e.g. R0) are defined by a code (R) and an argument (0). + * + * The commands are: + * + * D: setDTR - 1=True / 0=False + * + * R: setRTS - 1=True / 0=False + * + * W: Wait (time delay) - positive integer number (miliseconds) + * + * "D0|R1|W100|D1|R0|W50|D0" represents the classic reset strategy + * @param {Transport} transport Transport class to perform serial communication. + * @param {number} resetDelay Delay in milliseconds for reset. + */ export async function classicReset(transport: Transport, resetDelay = DEFAULT_RESET_DELAY) { await transport.setDTR(false); await transport.setRTS(true); @@ -16,6 +38,20 @@ export async function classicReset(transport: Transport, resetDelay = DEFAULT_RE await transport.setDTR(false); } +/** + * Execute a set of commands for USB JTAG serial reset. + * + * Commands (e.g. R0) are defined by a code (R) and an argument (0). + * + * The commands are: + * + * D: setDTR - 1=True / 0=False + * + * R: setRTS - 1=True / 0=False + * + * W: Wait (time delay) - positive integer number (miliseconds) + * @param {Transport} transport Transport class to perform serial communication. + */ export async function usbJTAGSerialReset(transport: Transport) { await transport.setRTS(false); await transport.setDTR(false); @@ -34,6 +70,21 @@ export async function usbJTAGSerialReset(transport: Transport) { await transport.setDTR(false); } +/** + * Execute a set of commands that will hard reset the chip. + * + * Commands (e.g. R0) are defined by a code (R) and an argument (0). + * + * The commands are: + * + * D: setDTR - 1=True / 0=False + * + * R: setRTS - 1=True / 0=False + * + * W: Wait (time delay) - positive integer number (miliseconds) + * @param {Transport} transport Transport class to perform serial communication. + * @param {boolean} usingUsbOtg is it using USB-OTG ? + */ export async function hardReset(transport: Transport, usingUsbOtg = false) { if (usingUsbOtg) { await sleep(200); @@ -51,6 +102,21 @@ type CmdsArgsTypes = { W: number; }; +/** + * Validate a sequence string based on the following format: + * + * Commands (e.g. R0) are defined by a code (R) and an argument (0). + * + * The commands are: + * + * D: setDTR - 1=True / 0=False + * + * R: setRTS - 1=True / 0=False + * + * W: Wait (time delay) - positive integer number (miliseconds) + * @param {string} seqStr Sequence string to validate + * @returns {boolean} Is the sequence string valid ? + */ export function validateCustomResetStringSequence(seqStr: string): boolean { const commands: (keyof CmdsArgsTypes)[] = ["D", "R", "W"]; @@ -94,6 +160,8 @@ export function validateCustomResetStringSequence(seqStr: string): boolean { * W: Wait (time delay) - positive integer number (miliseconds) * * "D0|R1|W100|D1|R0|W50|D0" represents the classic reset strategy + * @param {Transport} transport Transport class to perform serial communication. + * @param {string} sequenceString Custom string sequence for reset strategy */ export async function customReset(transport: Transport, sequenceString: string) { const resetDictionary: { [K in keyof CmdsArgsTypes]: (arg: CmdsArgsTypes[K]) => Promise } = { diff --git a/src/targets/esp32.ts b/src/targets/esp32.ts index a052f82..a1b7593 100644 --- a/src/targets/esp32.ts +++ b/src/targets/esp32.ts @@ -37,30 +37,30 @@ export class ESP32ROM extends ROM { public ROM_DATA = ESP32_STUB.data; public ROM_TEXT = ESP32_STUB.text; - public async read_efuse(loader: ESPLoader, offset: number) { + public async readEfuse(loader: ESPLoader, offset: number): Promise { const addr = this.EFUSE_RD_REG_BASE + 4 * offset; loader.debug("Read efuse " + addr); - return await loader.read_reg(addr); + return await loader.readReg(addr); } - public async get_pkg_version(loader: ESPLoader) { - const word3 = await this.read_efuse(loader, 3); - let pkg_version = (word3 >> 9) & 0x07; - pkg_version += ((word3 >> 2) & 0x1) << 3; - return pkg_version; + public async getPkgVersion(loader: ESPLoader): Promise { + const word3 = await this.readEfuse(loader, 3); + let pkgVersion = (word3 >> 9) & 0x07; + pkgVersion += ((word3 >> 2) & 0x1) << 3; + return pkgVersion; } - public async get_chip_revision(loader: ESPLoader) { - const word3 = await this.read_efuse(loader, 3); - const word5 = await this.read_efuse(loader, 5); - const apb_ctl_date = await loader.read_reg(this.DR_REG_SYSCON_BASE + 0x7c); - - const rev_bit0 = (word3 >> 15) & 0x1; - const rev_bit1 = (word5 >> 20) & 0x1; - const rev_bit2 = (apb_ctl_date >> 31) & 0x1; - if (rev_bit0 != 0) { - if (rev_bit1 != 0) { - if (rev_bit2 != 0) { + public async getChipRevision(loader: ESPLoader): Promise { + const word3 = await this.readEfuse(loader, 3); + const word5 = await this.readEfuse(loader, 5); + const apbCtlDate = await loader.readReg(this.DR_REG_SYSCON_BASE + 0x7c); + + const revBit0 = (word3 >> 15) & 0x1; + const revBit1 = (word5 >> 20) & 0x1; + const revBit2 = (apbCtlDate >> 31) & 0x1; + if (revBit0 != 0) { + if (revBit1 != 0) { + if (revBit2 != 0) { return 3; } else { return 2; @@ -72,8 +72,8 @@ export class ESP32ROM extends ROM { return 0; } - public async get_chip_description(loader: ESPLoader) { - const chip_desc = [ + public async getChipDescription(loader: ESPLoader) { + const chipDesc = [ "ESP32-D0WDQ6", "ESP32-D0WD", "ESP32-D2WD", @@ -82,98 +82,98 @@ export class ESP32ROM extends ROM { "ESP32-PICO-D4", "ESP32-PICO-V3-02", ]; - let chip_name = ""; - const pkg_version = await this.get_pkg_version(loader); - const chip_revision = await this.get_chip_revision(loader); - const rev3 = chip_revision == 3; - const single_core = (await this.read_efuse(loader, 3)) & (1 << 0); + let chipName = ""; + const pkgVersion = await this.getPkgVersion(loader); + const chipRevision = await this.getChipRevision(loader); + const rev3 = chipRevision == 3; + const single_core = (await this.readEfuse(loader, 3)) & (1 << 0); if (single_core != 0) { - chip_desc[0] = "ESP32-S0WDQ6"; - chip_desc[1] = "ESP32-S0WD"; + chipDesc[0] = "ESP32-S0WDQ6"; + chipDesc[1] = "ESP32-S0WD"; } if (rev3) { - chip_desc[5] = "ESP32-PICO-V3"; + chipDesc[5] = "ESP32-PICO-V3"; } - if (pkg_version >= 0 && pkg_version <= 6) { - chip_name = chip_desc[pkg_version]; + if (pkgVersion >= 0 && pkgVersion <= 6) { + chipName = chipDesc[pkgVersion]; } else { - chip_name = "Unknown ESP32"; + chipName = "Unknown ESP32"; } - if (rev3 && (pkg_version === 0 || pkg_version === 1)) { - chip_name += "-V3"; + if (rev3 && (pkgVersion === 0 || pkgVersion === 1)) { + chipName += "-V3"; } - return chip_name + " (revision " + chip_revision + ")"; + return chipName + " (revision " + chipRevision + ")"; } - public async get_chip_features(loader: ESPLoader) { + public async getChipFeatures(loader: ESPLoader) { const features = ["Wi-Fi"]; - const word3 = await this.read_efuse(loader, 3); + const word3 = await this.readEfuse(loader, 3); - const chip_ver_dis_bt = word3 & (1 << 1); - if (chip_ver_dis_bt === 0) { + const chipVerDisBt = word3 & (1 << 1); + if (chipVerDisBt === 0) { features.push(" BT"); } - const chip_ver_dis_app_cpu = word3 & (1 << 0); - if (chip_ver_dis_app_cpu !== 0) { + const chipVerDisAppCpu = word3 & (1 << 0); + if (chipVerDisAppCpu !== 0) { features.push(" Single Core"); } else { features.push(" Dual Core"); } - const chip_cpu_freq_rated = word3 & (1 << 13); - if (chip_cpu_freq_rated !== 0) { - const chip_cpu_freq_low = word3 & (1 << 12); - if (chip_cpu_freq_low !== 0) { + const chipCpuFreqRated = word3 & (1 << 13); + if (chipCpuFreqRated !== 0) { + const chipCpuFreqLow = word3 & (1 << 12); + if (chipCpuFreqLow !== 0) { features.push(" 160MHz"); } else { features.push(" 240MHz"); } } - const pkg_version = await this.get_pkg_version(loader); - if ([2, 4, 5, 6].indexOf(pkg_version) !== -1) { + const pkgVersion = await this.getPkgVersion(loader); + if ([2, 4, 5, 6].indexOf(pkgVersion) !== -1) { features.push(" Embedded Flash"); } - if (pkg_version === 6) { + if (pkgVersion === 6) { features.push(" Embedded PSRAM"); } - const word4 = await this.read_efuse(loader, 4); - const adc_vref = (word4 >> 8) & 0x1f; - if (adc_vref !== 0) { + const word4 = await this.readEfuse(loader, 4); + const adcVref = (word4 >> 8) & 0x1f; + if (adcVref !== 0) { features.push(" VRef calibration in efuse"); } - const blk3_part_res = (word3 >> 14) & 0x1; - if (blk3_part_res !== 0) { + const blk3PartRes = (word3 >> 14) & 0x1; + if (blk3PartRes !== 0) { features.push(" BLK3 partially reserved"); } - const word6 = await this.read_efuse(loader, 6); - const coding_scheme = word6 & 0x3; - const coding_scheme_arr = ["None", "3/4", "Repeat (UNSUPPORTED)", "Invalid"]; - features.push(" Coding Scheme " + coding_scheme_arr[coding_scheme]); + const word6 = await this.readEfuse(loader, 6); + const codingScheme = word6 & 0x3; + const codingSchemeArr = ["None", "3/4", "Repeat (UNSUPPORTED)", "Invalid"]; + features.push(" Coding Scheme " + codingSchemeArr[codingScheme]); return features; } - public async get_crystal_freq(loader: ESPLoader) { - const uart_div = (await loader.read_reg(this.UART_CLKDIV_REG)) & this.UART_CLKDIV_MASK; - const ets_xtal = (loader.transport.baudrate * uart_div) / 1000000 / this.XTAL_CLK_DIVIDER; - let norm_xtal; - if (ets_xtal > 33) { - norm_xtal = 40; + public async getCrystalFreq(loader: ESPLoader) { + const uartDiv = (await loader.readReg(this.UART_CLKDIV_REG)) & this.UART_CLKDIV_MASK; + const etsXtal = (loader.transport.baudrate * uartDiv) / 1000000 / this.XTAL_CLK_DIVIDER; + let normXtal; + if (etsXtal > 33) { + normXtal = 40; } else { - norm_xtal = 26; + normXtal = 26; } - if (Math.abs(norm_xtal - ets_xtal) > 1) { + if (Math.abs(normXtal - etsXtal) > 1) { loader.info("WARNING: Unsupported crystal in use"); } - return norm_xtal; + return normXtal; } public _d2h(d: number) { @@ -181,10 +181,10 @@ export class ESP32ROM extends ROM { return h.length === 1 ? "0" + h : h; } - public async read_mac(loader: ESPLoader) { - let mac0 = await this.read_efuse(loader, 1); + public async readMac(loader: ESPLoader) { + let mac0 = await this.readEfuse(loader, 1); mac0 = mac0 >>> 0; - let mac1 = await this.read_efuse(loader, 2); + let mac1 = await this.readEfuse(loader, 2); mac1 = mac1 >>> 0; const mac = new Uint8Array(6); mac[0] = (mac1 >> 8) & 0xff; diff --git a/src/targets/esp32c3.ts b/src/targets/esp32c3.ts index 0a3bc6c..1f281ef 100644 --- a/src/targets/esp32c3.ts +++ b/src/targets/esp32c3.ts @@ -36,42 +36,42 @@ export class ESP32C3ROM extends ROM { public ROM_DATA = ESP32C3_STUB.data; public ROM_TEXT = ESP32C3_STUB.text; - public async get_pkg_version(loader: ESPLoader) { - const num_word = 3; - const block1_addr = this.EFUSE_BASE + 0x044; - const addr = block1_addr + 4 * num_word; - const word3 = await loader.read_reg(addr); - const pkg_version = (word3 >> 21) & 0x07; - return pkg_version; + public async getPkgVersion(loader: ESPLoader): Promise { + const numWord = 3; + const block1Addr = this.EFUSE_BASE + 0x044; + const addr = block1Addr + 4 * numWord; + const word3 = await loader.readReg(addr); + const pkgVersion = (word3 >> 21) & 0x07; + return pkgVersion; } - public async get_chip_revision(loader: ESPLoader) { - const block1_addr = this.EFUSE_BASE + 0x044; - const num_word = 3; + public async getChipRevision(loader: ESPLoader): Promise { + const block1Addr = this.EFUSE_BASE + 0x044; + const numWord = 3; const pos = 18; - const addr = block1_addr + 4 * num_word; - const ret = ((await loader.read_reg(addr)) & (0x7 << pos)) >> pos; + const addr = block1Addr + 4 * numWord; + const ret = ((await loader.readReg(addr)) & (0x7 << pos)) >> pos; return ret; } - public async get_chip_description(loader: ESPLoader) { + public async getChipDescription(loader: ESPLoader) { let desc: string; - const pkg_ver = await this.get_pkg_version(loader); - if (pkg_ver === 0) { + const pkgVer = await this.getPkgVersion(loader); + if (pkgVer === 0) { desc = "ESP32-C3"; } else { desc = "unknown ESP32-C3"; } - const chip_rev = await this.get_chip_revision(loader); + const chip_rev = await this.getChipRevision(loader); desc += " (revision " + chip_rev + ")"; return desc; } - public async get_chip_features(loader: ESPLoader) { + public async getChipFeatures(loader: ESPLoader) { return ["Wi-Fi"]; } - public async get_crystal_freq(loader: ESPLoader) { + public async getCrystalFreq(loader: ESPLoader) { return 40; } @@ -80,10 +80,10 @@ export class ESP32C3ROM extends ROM { return h.length === 1 ? "0" + h : h; } - public async read_mac(loader: ESPLoader) { - let mac0 = await loader.read_reg(this.MAC_EFUSE_REG); + public async readMac(loader: ESPLoader) { + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; - let mac1 = await loader.read_reg(this.MAC_EFUSE_REG + 4); + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); mac1 = (mac1 >>> 0) & 0x0000ffff; const mac = new Uint8Array(6); mac[0] = (mac1 >> 8) & 0xff; @@ -108,7 +108,7 @@ export class ESP32C3ROM extends ROM { ); } - public get_erase_size(offset: number, size: number) { + public getEraseSize(offset: number, size: number) { return size; } } diff --git a/src/targets/esp32c6.ts b/src/targets/esp32c6.ts index 514a325..8480e15 100644 --- a/src/targets/esp32c6.ts +++ b/src/targets/esp32c6.ts @@ -36,42 +36,42 @@ export class ESP32C6ROM extends ROM { public ROM_DATA = ESP32C6_STUB.data; public ROM_TEXT = ESP32C6_STUB.text; - public async get_pkg_version(loader: ESPLoader) { - const num_word = 3; - const block1_addr = this.EFUSE_BASE + 0x044; - const addr = block1_addr + 4 * num_word; - const word3 = await loader.read_reg(addr); - const pkg_version = (word3 >> 21) & 0x07; - return pkg_version; + public async getPkgVersion(loader: ESPLoader) { + const numWord = 3; + const block1Addr = this.EFUSE_BASE + 0x044; + const addr = block1Addr + 4 * numWord; + const word3 = await loader.readReg(addr); + const pkgVersion = (word3 >> 21) & 0x07; + return pkgVersion; } - public async get_chip_revision(loader: ESPLoader) { - const block1_addr = this.EFUSE_BASE + 0x044; - const num_word = 3; + public async getChipRevision(loader: ESPLoader) { + const block1Addr = this.EFUSE_BASE + 0x044; + const numWord = 3; const pos = 18; - const addr = block1_addr + 4 * num_word; - const ret = ((await loader.read_reg(addr)) & (0x7 << pos)) >> pos; + const addr = block1Addr + 4 * numWord; + const ret = ((await loader.readReg(addr)) & (0x7 << pos)) >> pos; return ret; } - public async get_chip_description(loader: ESPLoader) { + public async getChipDescription(loader: ESPLoader) { let desc: string; - const pkg_ver = await this.get_pkg_version(loader); - if (pkg_ver === 0) { + const pkgVer = await this.getPkgVersion(loader); + if (pkgVer === 0) { desc = "ESP32-C6"; } else { desc = "unknown ESP32-C6"; } - const chip_rev = await this.get_chip_revision(loader); - desc += " (revision " + chip_rev + ")"; + const chipRev = await this.getChipRevision(loader); + desc += " (revision " + chipRev + ")"; return desc; } - public async get_chip_features(loader: ESPLoader) { + public async getChipFeatures(loader: ESPLoader) { return ["Wi-Fi"]; } - public async get_crystal_freq(loader: ESPLoader) { + public async getCrystalFreq(loader: ESPLoader) { return 40; } @@ -80,10 +80,10 @@ export class ESP32C6ROM extends ROM { return h.length === 1 ? "0" + h : h; } - public async read_mac(loader: ESPLoader) { - let mac0 = await loader.read_reg(this.MAC_EFUSE_REG); + public async readMac(loader: ESPLoader) { + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; - let mac1 = await loader.read_reg(this.MAC_EFUSE_REG + 4); + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); mac1 = (mac1 >>> 0) & 0x0000ffff; const mac = new Uint8Array(6); mac[0] = (mac1 >> 8) & 0xff; @@ -108,7 +108,7 @@ export class ESP32C6ROM extends ROM { ); } - public get_erase_size(offset: number, size: number) { + public getEraseSize(offset: number, size: number) { return size; } } diff --git a/src/targets/esp32h2.ts b/src/targets/esp32h2.ts index cb9005e..294d3ab 100644 --- a/src/targets/esp32h2.ts +++ b/src/targets/esp32h2.ts @@ -40,15 +40,15 @@ export class ESP32H2ROM extends ROM { public ROM_DATA = ESP32H2_STUB.data; public ROM_TEXT = ESP32H2_STUB.text; - public async get_chip_description(loader: ESPLoader) { + public async getChipDescription(loader: ESPLoader) { return this.CHIP_NAME; } - public async get_chip_features(loader: ESPLoader) { + public async getChipFeatures(loader: ESPLoader) { return ["BLE", "IEEE802.15.4"]; } - public async get_crystal_freq(loader: ESPLoader) { + public async getCrystalFreq(loader: ESPLoader) { // ESP32H2 XTAL is fixed to 32MHz return 32; } @@ -58,18 +58,18 @@ export class ESP32H2ROM extends ROM { return h.length === 1 ? "0" + h : h; } - public async _post_connect(loader: ESPLoader) { - const buf_no = (await loader.read_reg(this.UARTDEV_BUF_NO)) & 0xff; - loader.debug("In _post_connect " + buf_no); - if (buf_no == this.UARTDEV_BUF_NO_USB) { + public async postConnect(loader: ESPLoader) { + const bufNo = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff; + loader.debug("In _post_connect " + bufNo); + if (bufNo == this.UARTDEV_BUF_NO_USB) { loader.ESP_RAM_BLOCK = this.USB_RAM_BLOCK; } } - public async read_mac(loader: ESPLoader) { - let mac0 = await loader.read_reg(this.MAC_EFUSE_REG); + public async readMac(loader: ESPLoader) { + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; - let mac1 = await loader.read_reg(this.MAC_EFUSE_REG + 4); + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); mac1 = (mac1 >>> 0) & 0x0000ffff; const mac = new Uint8Array(6); mac[0] = (mac1 >> 8) & 0xff; @@ -94,7 +94,7 @@ export class ESP32H2ROM extends ROM { ); } - public get_erase_size(offset: number, size: number) { + public getEraseSize(offset: number, size: number) { return size; } } diff --git a/src/targets/esp32s2.ts b/src/targets/esp32s2.ts index f736e39..1d7f2c4 100644 --- a/src/targets/esp32s2.ts +++ b/src/targets/esp32s2.ts @@ -36,56 +36,56 @@ export class ESP32S2ROM extends ROM { public ROM_DATA = ESP32S2_STUB.data; public ROM_TEXT = ESP32S2_STUB.text; - public async get_pkg_version(loader: ESPLoader) { - const num_word = 3; - const block1_addr = this.EFUSE_BASE + 0x044; - const addr = block1_addr + 4 * num_word; - const word3 = await loader.read_reg(addr); - const pkg_version = (word3 >> 21) & 0x0f; - return pkg_version; + public async getPkgVersion(loader: ESPLoader): Promise { + const numWord = 3; + const block1Addr = this.EFUSE_BASE + 0x044; + const addr = block1Addr + 4 * numWord; + const word3 = await loader.readReg(addr); + const pkgVersion = (word3 >> 21) & 0x0f; + return pkgVersion; } - public async get_chip_description(loader: ESPLoader) { - const chip_desc = ["ESP32-S2", "ESP32-S2FH16", "ESP32-S2FH32"]; - const pkg_ver = await this.get_pkg_version(loader); - if (pkg_ver >= 0 && pkg_ver <= 2) { - return chip_desc[pkg_ver]; + public async getChipDescription(loader: ESPLoader) { + const chipDesc = ["ESP32-S2", "ESP32-S2FH16", "ESP32-S2FH32"]; + const pkgVer = await this.getPkgVersion(loader); + if (pkgVer >= 0 && pkgVer <= 2) { + return chipDesc[pkgVer]; } else { return "unknown ESP32-S2"; } } - public async get_chip_features(loader: ESPLoader) { + public async getChipFeatures(loader: ESPLoader) { const features = ["Wi-Fi"]; - const pkg_ver = await this.get_pkg_version(loader); - if (pkg_ver == 1) { + const pkgVer = await this.getPkgVersion(loader); + if (pkgVer == 1) { features.push("Embedded 2MB Flash"); - } else if (pkg_ver == 2) { + } else if (pkgVer == 2) { features.push("Embedded 4MB Flash"); } - const num_word = 4; - const block2_addr = this.EFUSE_BASE + 0x05c; - const addr = block2_addr + 4 * num_word; - const word4 = await loader.read_reg(addr); - const block2_ver = (word4 >> 4) & 0x07; + const numWord = 4; + const block2Addr = this.EFUSE_BASE + 0x05c; + const addr = block2Addr + 4 * numWord; + const word4 = await loader.readReg(addr); + const block2Ver = (word4 >> 4) & 0x07; - if (block2_ver == 1) { + if (block2Ver == 1) { features.push("ADC and temperature sensor calibration in BLK2 of efuse"); } return features; } - public async get_crystal_freq(loader: ESPLoader) { + public async getCrystalFreq(loader: ESPLoader) { return 40; } public _d2h(d: number) { const h = (+d).toString(16); return h.length === 1 ? "0" + h : h; } - public async read_mac(loader: ESPLoader) { - let mac0 = await loader.read_reg(this.MAC_EFUSE_REG); + public async readMac(loader: ESPLoader) { + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; - let mac1 = await loader.read_reg(this.MAC_EFUSE_REG + 4); + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); mac1 = (mac1 >>> 0) & 0x0000ffff; const mac = new Uint8Array(6); mac[0] = (mac1 >> 8) & 0xff; @@ -110,7 +110,7 @@ export class ESP32S2ROM extends ROM { ); } - public get_erase_size(offset: number, size: number) { + public getEraseSize(offset: number, size: number) { return size; } } diff --git a/src/targets/esp32s3.ts b/src/targets/esp32s3.ts index 6e6b3d6..4749243 100644 --- a/src/targets/esp32s3.ts +++ b/src/targets/esp32s3.ts @@ -40,13 +40,13 @@ export class ESP32S3ROM extends ROM { public ROM_DATA = ESP32S3_STUB.data; public ROM_TEXT = ESP32S3_STUB.text; - public async get_chip_description(loader: ESPLoader) { + public async getChipDescription(loader: ESPLoader) { return "ESP32-S3"; } - public async get_chip_features(loader: ESPLoader) { + public async getChipFeatures(loader: ESPLoader) { return ["Wi-Fi", "BLE"]; } - public async get_crystal_freq(loader: ESPLoader) { + public async getCrystalFreq(loader: ESPLoader) { return 40; } public _d2h(d: number) { @@ -54,18 +54,18 @@ export class ESP32S3ROM extends ROM { return h.length === 1 ? "0" + h : h; } - public async _post_connect(loader: ESPLoader) { - const buf_no = (await loader.read_reg(this.UARTDEV_BUF_NO)) & 0xff; - loader.debug("In _post_connect " + buf_no); - if (buf_no == this.UARTDEV_BUF_NO_USB) { + public async postConnect(loader: ESPLoader) { + const bufNo = (await loader.readReg(this.UARTDEV_BUF_NO)) & 0xff; + loader.debug("In _post_connect " + bufNo); + if (bufNo == this.UARTDEV_BUF_NO_USB) { loader.ESP_RAM_BLOCK = this.USB_RAM_BLOCK; } } - public async read_mac(loader: ESPLoader) { - let mac0 = await loader.read_reg(this.MAC_EFUSE_REG); + public async readMac(loader: ESPLoader) { + let mac0 = await loader.readReg(this.MAC_EFUSE_REG); mac0 = mac0 >>> 0; - let mac1 = await loader.read_reg(this.MAC_EFUSE_REG + 4); + let mac1 = await loader.readReg(this.MAC_EFUSE_REG + 4); mac1 = (mac1 >>> 0) & 0x0000ffff; const mac = new Uint8Array(6); mac[0] = (mac1 >> 8) & 0xff; @@ -90,7 +90,7 @@ export class ESP32S3ROM extends ROM { ); } - public get_erase_size(offset: number, size: number) { + public getEraseSize(offset: number, size: number) { return size; } } diff --git a/src/targets/esp8266.ts b/src/targets/esp8266.ts index 6f3389e..e446118 100644 --- a/src/targets/esp8266.ts +++ b/src/targets/esp8266.ts @@ -42,45 +42,45 @@ export class ESP8266ROM extends ROM { public ROM_DATA = ESP8266_STUB.data; public ROM_TEXT = ESP8266_STUB.text; - public async read_efuse(loader: ESPLoader, offset: number) { + public async readEfuse(loader: ESPLoader, offset: number): Promise { const addr = this.EFUSE_RD_REG_BASE + 4 * offset; loader.debug("Read efuse " + addr); - return await loader.read_reg(addr); + return await loader.readReg(addr); } - public async get_chip_description(loader: ESPLoader) { - const efuse3 = await this.read_efuse(loader, 2); - const efuse0 = await this.read_efuse(loader, 0); + public async getChipDescription(loader: ESPLoader) { + const efuse3 = await this.readEfuse(loader, 2); + const efuse0 = await this.readEfuse(loader, 0); - const is_8285 = ((efuse0 & (1 << 4)) | (efuse3 & (1 << 16))) != 0; // One or the other efuse bit is set for ESP8285 - return is_8285 ? "ESP8285" : "ESP8266EX"; + const is8285 = ((efuse0 & (1 << 4)) | (efuse3 & (1 << 16))) != 0; // One or the other efuse bit is set for ESP8285 + return is8285 ? "ESP8285" : "ESP8266EX"; } - public get_chip_features = async (loader: ESPLoader) => { + public getChipFeatures = async (loader: ESPLoader) => { const features = ["WiFi"]; - if ((await this.get_chip_description(loader)) == "ESP8285") features.push("Embedded Flash"); + if ((await this.getChipDescription(loader)) == "ESP8285") features.push("Embedded Flash"); return features; }; - public async get_crystal_freq(loader: ESPLoader) { - const uart_div = (await loader.read_reg(this.UART_CLKDIV_REG)) & this.UART_CLKDIV_MASK; - const ets_xtal = (loader.transport.baudrate * uart_div) / 1000000 / this.XTAL_CLK_DIVIDER; - let norm_xtal; - if (ets_xtal > 33) { - norm_xtal = 40; + public async getCrystalFreq(loader: ESPLoader) { + const uartDiv = (await loader.readReg(this.UART_CLKDIV_REG)) & this.UART_CLKDIV_MASK; + const etsXtal = (loader.transport.baudrate * uartDiv) / 1000000 / this.XTAL_CLK_DIVIDER; + let normXtal; + if (etsXtal > 33) { + normXtal = 40; } else { - norm_xtal = 26; + normXtal = 26; } - if (Math.abs(norm_xtal - ets_xtal) > 1) { + if (Math.abs(normXtal - etsXtal) > 1) { loader.info( "WARNING: Detected crystal freq " + - ets_xtal + + etsXtal + "MHz is quite different to normalized freq " + - norm_xtal + + normXtal + "MHz. Unsupported crystal in use?", ); } - return norm_xtal; + return normXtal; } public _d2h(d: number) { @@ -88,12 +88,12 @@ export class ESP8266ROM extends ROM { return h.length === 1 ? "0" + h : h; } - public async read_mac(loader: ESPLoader) { - let mac0 = await this.read_efuse(loader, 0); + public async readMac(loader: ESPLoader) { + let mac0 = await this.readEfuse(loader, 0); mac0 = mac0 >>> 0; - let mac1 = await this.read_efuse(loader, 1); + let mac1 = await this.readEfuse(loader, 1); mac1 = mac1 >>> 0; - let mac3 = await this.read_efuse(loader, 3); + let mac3 = await this.readEfuse(loader, 3); mac3 = mac3 >>> 0; const mac = new Uint8Array(6); @@ -132,7 +132,7 @@ export class ESP8266ROM extends ROM { ); } - public get_erase_size(offset: number, size: number) { + public getEraseSize(offset: number, size: number) { return size; } } diff --git a/src/targets/rom.ts b/src/targets/rom.ts index b055ed3..2591b6b 100644 --- a/src/targets/rom.ts +++ b/src/targets/rom.ts @@ -1,25 +1,77 @@ import { ESPLoader } from "../esploader"; +/** + * Represents a chip ROM with basic registers field and abstract functions. + */ export abstract class ROM { - // abstract read_efuse(loader: ESPLoader, offset: number): Promise; //esp32 + /** + * Read ESP32 eFuse. + * @param {ESPLoader} loader - Loader class to communicate with chip. + * @param {number} offset - Offset to start erase. + * @returns {number} The eFuse number. + */ + protected readEfuse?(loader: ESPLoader, offset: number): Promise; - // abstract get_pkg_version(loader: ESPLoader): Promise; // not in esp32s3 + /** + * Get the package version number. + * @param {ESPLoader} loader - Loader class to communicate with chip. + * @returns {number} The package version number. + */ + protected getPkgVersion?(loader: ESPLoader): Promise; - // abstract get_chip_revision(loader: ESPLoader): Promise; esp32 + /** + * Get the chip revision number. + * @param {ESPLoader} loader - Loader class to communicate with chip. + * @returns {number} The chip revision number. + */ + protected getChipRevision?(loader: ESPLoader): Promise; - abstract get_chip_description(loader: ESPLoader): Promise; - - abstract get_chip_features(loader: ESPLoader): Promise; - - abstract get_crystal_freq(loader: ESPLoader): Promise; + /** + * Get the chip description. + * @param {ESPLoader} loader - Loader class to communicate with chip. + * @returns {string} The chip description as string. + */ + abstract getChipDescription(loader: ESPLoader): Promise; + /** + * Get the chip features. + * @param {ESPLoader} loader - Loader class to communicate with chip. + * @returns {string} The chip features as string. + */ + abstract getChipFeatures(loader: ESPLoader): Promise; + /** + * Get the crystal frequency for the chip. + * @param {ESPLoader} loader - Loader class to communicate with chip. + * @returns {string} The crystal frequency as number. + */ + abstract getCrystalFreq(loader: ESPLoader): Promise; + /** + * Convert a number to hex string. + * @param {number} d - Number to convert to hex string. + * @returns {string} The hex string. + */ abstract _d2h(d: number): string; - abstract read_mac(loader: ESPLoader): Promise; + /** + * Get the chip mac address. + * @param {ESPLoader} loader - Loader class to communicate with chip. + * @returns {string} The mac address string. + */ + abstract readMac(loader: ESPLoader): Promise; - _post_connect?(loader: ESPLoader): Promise; + /** + * Function to be executed after chip connection + * @param {ESPLoader} loader - Loader class to communicate with chip. + */ + postConnect?(loader: ESPLoader): Promise; - get_erase_size(offset: number, size: number) { + /** + * Get the chip erase size. + * @param {number} offset - Offset to start erase. + * @param {number} size - Size to erase. + * @returns {number} The erase size of the chip as number. + */ + getEraseSize(offset: number, size: number): number { return size; } diff --git a/src/webserial.ts b/src/webserial.ts index acd5759..f4b16d7 100644 --- a/src/webserial.ts +++ b/src/webserial.ts @@ -1,77 +1,143 @@ +/* global SerialPort, ParityType, FlowControlType */ + +/** + * Options for device serialPort. + * @interface SerialOptions + * + * Note: According to the documentation of the Web Serial API, 'baudRate' is a + * 'required' field as part of serial options. However, we are currently + * maintaining 'baudRate' as a separate parameter outside the options + * dictionary, and it is effectively used in the code. For now, we are + * keeping it optional in the dictionary to avoid conflicts. + */ export interface SerialOptions { - /* - Note: According to the documentation of the Web Serial API, 'baudRate' is a - 'required' field as part of serial options. However, we are currently - maintaining 'baudRate' as a separate parameter outside the options - dictionary, and it is effectively used in the code. For now, we are - keeping it optional in the dictionary to avoid conflicts. - */ + /** + * A positive, non-zero value indicating the baud rate at which serial communication should be established. + * @type {number | undefined} + */ baudRate?: number | undefined; + + /** + * The number of data bits per frame. Either 7 or 8. + * @type {number | undefined} + */ dataBits?: number | undefined; + + /** + * The number of stop bits at the end of a frame. Either 1 or 2. + * @type {number | undefined} + */ stopBits?: number | undefined; + + /** + * The parity mode: none, even or odd + * @type {ParityType | undefined} + */ parity?: ParityType | undefined; + + /** + * A positive, non-zero value indicating the size of the read and write buffers that should be created. + * @type {number | undefined} + */ bufferSize?: number | undefined; + + /** + * The flow control mode: none or hardware. + * @type {FlowControlType | undefined} + */ flowControl?: FlowControlType | undefined; } + +/** + * Wrapper class around Webserial API to communicate with the serial device. + * @param {typeof import("w3c-web-serial").SerialPort} device - Requested device prompted by the browser. + * + * ``` + * const port = await navigator.serial.requestPort(); + * ``` + */ class Transport { - public slip_reader_enabled = false; - public left_over = new Uint8Array(0); + public slipReaderEnabled = false; + public leftOver = new Uint8Array(0); public baudrate = 0; constructor(public device: SerialPort) {} - get_info() { + /** + * Request the serial device vendor ID and Product ID as string. + * @returns {string} Return the device VendorID and ProductID from SerialPortInfo as formatted string. + */ + getInfo() { const info = this.device.getInfo(); return info.usbVendorId && info.usbProductId ? `WebSerial VendorID 0x${info.usbVendorId.toString(16)} ProductID 0x${info.usbProductId.toString(16)}` : ""; } - get_pid() { + /** + * Request the serial device product id from SerialPortInfo. + * @returns {string} Return the product ID. + */ + getPid() { return this.device.getInfo().usbProductId; } - slip_writer(data: Uint8Array) { - let count_esc = 0; + /** + * Format data packet using the Serial Line Internet Protocol (SLIP). + * @param {Uint8Array} data Binary unsigned 8 bit array data to format. + * @returns {Uint8Array} Formatted unsigned 8 bit data array. + */ + slipWriter(data: Uint8Array) { + let countEsc = 0; let i = 0, j = 0; for (i = 0; i < data.length; i++) { if (data[i] === 0xc0 || data[i] === 0xdb) { - count_esc++; + countEsc++; } } - const out_data = new Uint8Array(2 + count_esc + data.length); - out_data[0] = 0xc0; + const outData = new Uint8Array(2 + countEsc + data.length); + outData[0] = 0xc0; j = 1; for (i = 0; i < data.length; i++, j++) { if (data[i] === 0xc0) { - out_data[j++] = 0xdb; - out_data[j] = 0xdc; + outData[j++] = 0xdb; + outData[j] = 0xdc; continue; } if (data[i] === 0xdb) { - out_data[j++] = 0xdb; - out_data[j] = 0xdd; + outData[j++] = 0xdb; + outData[j] = 0xdd; continue; } - out_data[j] = data[i]; + outData[j] = data[i]; } - out_data[j] = 0xc0; - return out_data; + outData[j] = 0xc0; + return outData; } + /** + * Write binary data to device using the WebSerial device writable stream. + * @param {Uint8Array} data 8 bit unsigned data array to write to device. + */ async write(data: Uint8Array) { - const out_data = this.slip_writer(data); + const outData = this.slipWriter(data); if (this.device.writable) { const writer = this.device.writable.getWriter(); - await writer.write(out_data); + await writer.write(outData); writer.releaseLock(); } } + /** + * Concatenate buffer2 to buffer1 and return the resulting ArrayBuffer. + * @param {ArrayBuffer} buffer1 First buffer to concatenate. + * @param {ArrayBuffer} buffer2 Second buffer to concatenate. + * @returns {ArrayBuffer} Result Array buffer. + */ _appendBuffer(buffer1: ArrayBuffer, buffer2: ArrayBuffer) { const tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); tmp.set(new Uint8Array(buffer1), 0); @@ -79,66 +145,76 @@ class Transport { return tmp.buffer; } - /* this function expects complete packet (hence reader reads for atleast 8 bytes. This function is - * stateless and returns the first wellformed packet only after replacing escape sequence */ - slip_reader(data: Uint8Array) { + /** + * Take a data array and return the first well formed packet after + * replacing the escape sequence. Reads at least 8 bytes. + * @param {Uint8Array} data Unsigned 8 bit array from the device read stream. + * @returns {Uint8Array} Formatted packet using SLIP escape sequences. + */ + slipReader(data: Uint8Array) { let i = 0; - let data_start = 0, - data_end = 0; + let dataStart = 0, + dataEnd = 0; let state = "init"; while (i < data.length) { if (state === "init" && data[i] == 0xc0) { - data_start = i + 1; + dataStart = i + 1; state = "valid_data"; i++; continue; } if (state === "valid_data" && data[i] == 0xc0) { - data_end = i - 1; + dataEnd = i - 1; state = "packet_complete"; break; } i++; } if (state !== "packet_complete") { - this.left_over = data; + this.leftOver = data; return new Uint8Array(0); } - this.left_over = data.slice(data_end + 2); - const temp_pkt = new Uint8Array(data_end - data_start + 1); + this.leftOver = data.slice(dataEnd + 2); + const tempPkt = new Uint8Array(dataEnd - dataStart + 1); let j = 0; - for (i = data_start; i <= data_end; i++, j++) { + for (i = dataStart; i <= dataEnd; i++, j++) { if (data[i] === 0xdb && data[i + 1] === 0xdc) { - temp_pkt[j] = 0xc0; + tempPkt[j] = 0xc0; i++; continue; } if (data[i] === 0xdb && data[i + 1] === 0xdd) { - temp_pkt[j] = 0xdb; + tempPkt[j] = 0xdb; i++; continue; } - temp_pkt[j] = data[i]; + tempPkt[j] = data[i]; } - const packet = temp_pkt.slice(0, j); /* Remove unused bytes due to escape seq */ + const packet = tempPkt.slice(0, j); /* Remove unused bytes due to escape seq */ return packet; } - async read(timeout = 0, min_data = 12) { + /** + * Read from serial device using the device ReadableStream. + * @param {number} timeout Read timeout number + * @param {number} minData Minimum packet array length + * @returns {Uint8Array} 8 bit unsigned data array read from device. + */ + async read(timeout = 0, minData = 12) { let t; - let packet = this.left_over; - this.left_over = new Uint8Array(0); - if (this.slip_reader_enabled) { - const val_final = this.slip_reader(packet); - if (val_final.length > 0) { - return val_final; + let packet = this.leftOver; + this.leftOver = new Uint8Array(0); + if (this.slipReaderEnabled) { + const valFinal = this.slipReader(packet); + if (valFinal.length > 0) { + return valFinal; } - packet = this.left_over; - this.left_over = new Uint8Array(0); + packet = this.leftOver; + this.leftOver = new Uint8Array(0); } if (this.device.readable == null) { - return this.left_over; + return this.leftOver; } const reader = this.device.readable.getReader(); @@ -151,32 +227,37 @@ class Transport { do { const { value, done } = await reader.read(); if (done) { - this.left_over = packet; + this.leftOver = packet; throw new Error("Timeout"); } const p = new Uint8Array(this._appendBuffer(packet.buffer, value.buffer)); packet = p; - } while (packet.length < min_data); + } while (packet.length < minData); } finally { if (timeout > 0) { clearTimeout(t); } reader.releaseLock(); } - if (this.slip_reader_enabled) { - return this.slip_reader(packet); + if (this.slipReaderEnabled) { + return this.slipReader(packet); } return packet; } + /** + * Read from serial device without slip formatting. + * @param {number} timeout Read timeout in milliseconds (ms) + * @returns {Uint8Array} 8 bit unsigned data array read from device. + */ async rawRead(timeout = 0) { - if (this.left_over.length != 0) { - const p = this.left_over; - this.left_over = new Uint8Array(0); + if (this.leftOver.length != 0) { + const p = this.leftOver; + this.leftOver = new Uint8Array(0); return p; } if (!this.device.readable) { - return this.left_over; + return this.leftOver; } const reader = this.device.readable.getReader(); let t; @@ -200,6 +281,11 @@ class Transport { } _DTR_state = false; + /** + * Send the RequestToSend (RTS) signal to given state + * # True for EN=LOW, chip in reset and False EN=HIGH, chip out of reset + * @param {boolean} state Boolean state to set the signal + */ async setRTS(state: boolean) { await this.device.setSignals({ requestToSend: state }); // # Work-around for adapters on Windows using the usbser.sys driver: @@ -209,11 +295,21 @@ class Transport { await this.setDTR(this._DTR_state); } + /** + * Send the dataTerminalReady (DTS) signal to given state + * # True for IO0=LOW, chip in reset and False IO0=HIGH + * @param {boolean} state Boolean state to set the signal + */ async setDTR(state: boolean) { this._DTR_state = state; await this.device.setSignals({ dataTerminalReady: state }); } + /** + * Connect to serial device using the Webserial open method. + * @param {number} baud Number baud rate for serial connection. + * @param {typeof import("w3c-web-serial").SerialOptions} serialOptions Serial Options for WebUSB SerialPort class. + */ async connect(baud = 115200, serialOptions: SerialOptions = {}) { await this.device.open({ baudRate: baud, @@ -224,13 +320,17 @@ class Transport { flowControl: serialOptions?.flowControl, }); this.baudrate = baud; - this.left_over = new Uint8Array(0); + this.leftOver = new Uint8Array(0); } async sleep(ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } + /** + * Wait for a given timeout ms for serial device unlock. + * @param {number} timeout Timeout time in milliseconds (ms) to sleep + */ async waitForUnlock(timeout: number) { while ( (this.device.readable && this.device.readable.locked) || @@ -240,6 +340,9 @@ class Transport { } } + /** + * Disconnect from serial device by running SerialPort.close() after streams unlock. + */ async disconnect() { await this.waitForUnlock(400); await this.device.close(); diff --git a/tsconfig.json b/tsconfig.json index ff66898..c6fc028 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,5 +15,9 @@ "resolveJsonModule": true, "strict": true }, + "typedocOptions": { + "entryPoints": ["src/index.ts"], + "out": "docs" + }, "include": ["src/**/*"] }